⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mpc52xx_psc_spi.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
{	struct mpc52xx_cdm __iomem *cdm;	struct mpc52xx_gpio __iomem *gpio;	struct mpc52xx_psc __iomem *psc = mps->psc;	u32 ul;	u32 mclken_div;	int ret = 0;#if defined(CONFIG_PPC_MERGE)	cdm = mpc52xx_find_and_map("mpc5200-cdm");	gpio = mpc52xx_find_and_map("mpc5200-gpio");#else	cdm = ioremap(MPC52xx_PA(MPC52xx_CDM_OFFSET), MPC52xx_CDM_SIZE);	gpio = ioremap(MPC52xx_PA(MPC52xx_GPIO_OFFSET), MPC52xx_GPIO_SIZE);#endif	if (!cdm || !gpio) {		printk(KERN_ERR "Error mapping CDM/GPIO\n");		ret = -EFAULT;		goto unmap_regs;	}	/* default sysclk is 512MHz */	mclken_div = 0x8000 |		(((mps->sysclk ? mps->sysclk : 512000000) / MCLK) & 0x1FF);	switch (psc_id) {	case 1:		ul = in_be32(&gpio->port_config);		ul &= 0xFFFFFFF8;		ul |= 0x00000006;		out_be32(&gpio->port_config, ul);		out_be16(&cdm->mclken_div_psc1, mclken_div);		ul = in_be32(&cdm->clk_enables);		ul |= 0x00000020;		out_be32(&cdm->clk_enables, ul);		break;	case 2:		ul = in_be32(&gpio->port_config);		ul &= 0xFFFFFF8F;		ul |= 0x00000060;		out_be32(&gpio->port_config, ul);		out_be16(&cdm->mclken_div_psc2, mclken_div);		ul = in_be32(&cdm->clk_enables);		ul |= 0x00000040;		out_be32(&cdm->clk_enables, ul);		break;	case 3:		ul = in_be32(&gpio->port_config);		ul &= 0xFFFFF0FF;		ul |= 0x00000600;		out_be32(&gpio->port_config, ul);		out_be16(&cdm->mclken_div_psc3, mclken_div);		ul = in_be32(&cdm->clk_enables);		ul |= 0x00000080;		out_be32(&cdm->clk_enables, ul);		break;	case 6:		ul = in_be32(&gpio->port_config);		ul &= 0xFF8FFFFF;		ul |= 0x00700000;		out_be32(&gpio->port_config, ul);		out_be16(&cdm->mclken_div_psc6, mclken_div);		ul = in_be32(&cdm->clk_enables);		ul |= 0x00000010;		out_be32(&cdm->clk_enables, ul);		break;	default:		ret = -EINVAL;		goto unmap_regs;	}	/* Reset the PSC into a known state */	out_8(&psc->command, MPC52xx_PSC_RST_RX);	out_8(&psc->command, MPC52xx_PSC_RST_TX);	out_8(&psc->command, MPC52xx_PSC_TX_DISABLE | MPC52xx_PSC_RX_DISABLE);	/* Disable interrupts, interrupts are based on alarm level */	out_be16(&psc->mpc52xx_psc_imr, 0);	out_8(&psc->command, MPC52xx_PSC_SEL_MODE_REG_1);	out_8(&psc->rfcntl, 0);	out_8(&psc->mode, MPC52xx_PSC_MODE_FFULL);	/* Configure 8bit codec mode as a SPI master and use EOF flags */	/* SICR_SIM_CODEC8|SICR_GENCLK|SICR_SPI|SICR_MSTR|SICR_USEEOF */	out_be32(&psc->sicr, 0x0180C800);	out_be16(&psc->ccr, 0x070F); /* by default SPI Clk 1MHz */	/* Set 2ms DTL delay */	out_8(&psc->ctur, 0x00);	out_8(&psc->ctlr, 0x84);	mps->bits_per_word = 8;unmap_regs:	if (cdm)		iounmap(cdm);	if (gpio)		iounmap(gpio);	return ret;}static irqreturn_t mpc52xx_psc_spi_isr(int irq, void *dev_id){	struct mpc52xx_psc_spi *mps = (struct mpc52xx_psc_spi *)dev_id;	struct mpc52xx_psc __iomem *psc = mps->psc;	/* disable interrupt and wake up the work queue */	if (in_be16(&psc->mpc52xx_psc_isr) & MPC52xx_PSC_IMR_RXRDY) {		out_be16(&psc->mpc52xx_psc_imr, 0);		complete(&mps->done);		return IRQ_HANDLED;	}	return IRQ_NONE;}/* bus_num is used only for the case dev->platform_data == NULL */static int __init mpc52xx_psc_spi_do_probe(struct device *dev, u32 regaddr,				u32 size, unsigned int irq, s16 bus_num){	struct fsl_spi_platform_data *pdata = dev->platform_data;	struct mpc52xx_psc_spi *mps;	struct spi_master *master;	int ret;	master = spi_alloc_master(dev, sizeof *mps);	if (master == NULL)		return -ENOMEM;	dev_set_drvdata(dev, master);	mps = spi_master_get_devdata(master);	mps->irq = irq;	if (pdata == NULL) {		dev_warn(dev, "probe called without platform data, no "				"(de)activate_cs function will be called\n");		mps->activate_cs = NULL;		mps->deactivate_cs = NULL;		mps->sysclk = 0;		master->bus_num = bus_num;		master->num_chipselect = 255;	} else {		mps->activate_cs = pdata->activate_cs;		mps->deactivate_cs = pdata->deactivate_cs;		mps->sysclk = pdata->sysclk;		master->bus_num = pdata->bus_num;		master->num_chipselect = pdata->max_chipselect;	}	master->setup = mpc52xx_psc_spi_setup;	master->transfer = mpc52xx_psc_spi_transfer;	master->cleanup = mpc52xx_psc_spi_cleanup;	mps->psc = ioremap(regaddr, size);	if (!mps->psc) {		dev_err(dev, "could not ioremap I/O port range\n");		ret = -EFAULT;		goto free_master;	}	ret = request_irq(mps->irq, mpc52xx_psc_spi_isr, 0, "mpc52xx-psc-spi",				mps);	if (ret)		goto free_master;	ret = mpc52xx_psc_spi_port_config(master->bus_num, mps);	if (ret < 0)		goto free_irq;	spin_lock_init(&mps->lock);	init_completion(&mps->done);	INIT_WORK(&mps->work, mpc52xx_psc_spi_work);	INIT_LIST_HEAD(&mps->queue);	mps->workqueue = create_singlethread_workqueue(		master->dev.parent->bus_id);	if (mps->workqueue == NULL) {		ret = -EBUSY;		goto free_irq;	}	ret = spi_register_master(master);	if (ret < 0)		goto unreg_master;	return ret;unreg_master:	destroy_workqueue(mps->workqueue);free_irq:	free_irq(mps->irq, mps);free_master:	if (mps->psc)		iounmap(mps->psc);	spi_master_put(master);	return ret;}static int __exit mpc52xx_psc_spi_do_remove(struct device *dev){	struct spi_master *master = dev_get_drvdata(dev);	struct mpc52xx_psc_spi *mps = spi_master_get_devdata(master);	flush_workqueue(mps->workqueue);	destroy_workqueue(mps->workqueue);	spi_unregister_master(master);	free_irq(mps->irq, mps);	if (mps->psc)		iounmap(mps->psc);	return 0;}#if !defined(CONFIG_PPC_MERGE)static int __init mpc52xx_psc_spi_probe(struct platform_device *dev){	switch(dev->id) {	case 1:	case 2:	case 3:	case 6:		return mpc52xx_psc_spi_do_probe(&dev->dev,			MPC52xx_PA(MPC52xx_PSCx_OFFSET(dev->id)),			MPC52xx_PSC_SIZE, platform_get_irq(dev, 0), dev->id);	default:		return -EINVAL;	}}static int __exit mpc52xx_psc_spi_remove(struct platform_device *dev){	return mpc52xx_psc_spi_do_remove(&dev->dev);}static struct platform_driver mpc52xx_psc_spi_platform_driver = {	.remove = __exit_p(mpc52xx_psc_spi_remove),	.driver = {		.name = "mpc52xx-psc-spi",		.owner = THIS_MODULE,	},};static int __init mpc52xx_psc_spi_init(void){	return platform_driver_probe(&mpc52xx_psc_spi_platform_driver,			mpc52xx_psc_spi_probe);}module_init(mpc52xx_psc_spi_init);static void __exit mpc52xx_psc_spi_exit(void){	platform_driver_unregister(&mpc52xx_psc_spi_platform_driver);}module_exit(mpc52xx_psc_spi_exit);#else	/* defined(CONFIG_PPC_MERGE) */static int __init mpc52xx_psc_spi_of_probe(struct of_device *op,	const struct of_device_id *match){	const u32 *regaddr_p;	u64 regaddr64, size64;	s16 id = -1;	regaddr_p = of_get_address(op->node, 0, &size64, NULL);	if (!regaddr_p) {		printk(KERN_ERR "Invalid PSC address\n");		return -EINVAL;	}	regaddr64 = of_translate_address(op->node, regaddr_p);	/* get PSC id (1..6, used by port_config) */	if (op->dev.platform_data == NULL) {		const u32 *psc_nump;		psc_nump = of_get_property(op->node, "cell-index", NULL);		if (!psc_nump || *psc_nump > 5) {			printk(KERN_ERR "mpc52xx_psc_spi: Device node %s has invalid "					"cell-index property\n", op->node->full_name);			return -EINVAL;		}		id = *psc_nump + 1;	}	return mpc52xx_psc_spi_do_probe(&op->dev, (u32)regaddr64, (u32)size64,					irq_of_parse_and_map(op->node, 0), id);}static int __exit mpc52xx_psc_spi_of_remove(struct of_device *op){	return mpc52xx_psc_spi_do_remove(&op->dev);}static struct of_device_id mpc52xx_psc_spi_of_match[] = {	{ .type = "spi", .compatible = "mpc5200-psc-spi", },	{},};MODULE_DEVICE_TABLE(of, mpc52xx_psc_spi_of_match);static struct of_platform_driver mpc52xx_psc_spi_of_driver = {	.owner = THIS_MODULE,	.name = "mpc52xx-psc-spi",	.match_table = mpc52xx_psc_spi_of_match,	.probe = mpc52xx_psc_spi_of_probe,	.remove = __exit_p(mpc52xx_psc_spi_of_remove),	.driver = {		.name = "mpc52xx-psc-spi",		.owner = THIS_MODULE,	},};static int __init mpc52xx_psc_spi_init(void){	return of_register_platform_driver(&mpc52xx_psc_spi_of_driver);}module_init(mpc52xx_psc_spi_init);static void __exit mpc52xx_psc_spi_exit(void){	of_unregister_platform_driver(&mpc52xx_psc_spi_of_driver);}module_exit(mpc52xx_psc_spi_exit);#endif	/* defined(CONFIG_PPC_MERGE) */MODULE_AUTHOR("Dragos Carp");MODULE_DESCRIPTION("MPC52xx PSC SPI Driver");MODULE_LICENSE("GPL");

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -