📄 mpc52xx_psc_spi.c
字号:
{ 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 + -