> + cs->speed_hz);
> + oldcdm = in_8(&hw->regs->cdm);
> + if (oldcdm != cdm)
> + out_8(&hw->regs->cdm, cdm);
> + /* write new configration */
> + out_8(&hw->regs->mode, mode);
> +
> + spi_ppc4xx_gpio(hw, spi->chip_select, cspol);
> +
> + break;
> + }
> +}
> +
> +static irqreturn_t spi_ppc4xx_int(int irq, void *dev_id)
> +{
> + struct ppc4xx_spi *hw;
> + u8 status;
> + u8 data;
> + unsigned int count;
> +
> + hw = dev_id;
> +
> + if (irq != hw->irqnum) {
> + printk(KERN_WARNING
> + "spi_ppc4xx_int : "
> + "Received wrong int %d. Waiting for %dn", irq,
> + hw->irqnum);
> + return IRQ_NONE;
> + }
> +
> + status = in_8(&hw->regs->sr);
> +
> + /* should never happen but check anyway */
> + if (status & SPI_PPC4XX_SR_BSY) {
> + dev_dbg(hw->dev, "got interrupt but spi still busy?n");
> + complete(&hw->done);
> + return IRQ_HANDLED;
> + }
> +
> + count = hw->count;
> + hw->count++;
> +
> + if (status & SPI_PPC4XX_SR_RBR) {
> + /* Data Ready */
> + data = in_8(&hw->regs->rxd);
> + if (hw->rx)
> + hw->rx[count] = data;
> + }
> +
> + count++;
> +
> + if (count < hw->len) {
> + data = hw->tx ? hw->tx[count] : 0;
> + out_8(&hw->regs->txd, data);
> + out_8(&hw->regs->cr, SPI_PPC4XX_CR_STR);
> + } else {
> + complete(&hw->done);
> + }
> +
> + return IRQ_HANDLED;
> +}
> +
> +static void spi_ppc4xx_cleanup(struct spi_device *spi)
> +{
> + kfree(spi->controller_state);
> +}
> +
> +static void spi_ppc4xx_enable(struct ppc4xx_spi *hw)
> +{
> + unsigned long pfc1;
> + uint osrh, tsrh;
> +
> + mtdcr(SDR0_CFGADDR, SDR0_PFC1);
> + pfc1 = mfdcr(SDR0_CFGDATA);
> + /* need to clear bit 14 to enable SPC */
> + pfc1 &= ~(1 << 17);
> + mtdcr(SDR0_CFGADDR, SDR0_PFC1);
> + mtdcr(SDR0_CFGDATA, pfc1);
> +
> + /* enable SPCDO */
> + osrh = in_be32((void *)((u32)hw->gpio0 + GPIOx_OSRH));
> + tsrh = in_be32((void *)((u32)hw->gpio0 + GPIOx_TSRH));
> + /* need to set bits 14:15 in OSRH to 0x01 */
> + osrh &= ~(0x03 << 16);
> + osrh |= (0x01 << 16);
> + out_be32((void *)((u32)hw->gpio0 + GPIOx_OSRH), osrh);
> +
> + /* need to set bits 14:15 in TSRH to 0x01 */
> + tsrh &= ~(0x03 << 16);
> + tsrh |= (0x01 << 16);
> + out_be32((void *)((u32)hw->gpio0 + GPIOx_TSRH), tsrh);
> +}
> +
> +#ifdef CONFIG_PPC_OF
> +static int __init spi_ppc4xx_of_probe(struct of_device *op,
> + const struct of_device_id *match)
> +{
> + struct ppc4xx_spi *hw;
> + struct spi_master *master;
> + struct spi_bitbang *bbp;
> + struct resource resource;
> + struct device_node *np = op->node;
> + struct device *dev = &op->dev;
> + struct device_node *gpionp;
> + const u32 *regaddr;
> + u64 addr64, size64;
> + int ret;
> + const unsigned int *clk;
> +
> + master = spi_alloc_master(dev, sizeof(*hw));
> + if (master == NULL)
> + return -ENOMEM;
> + dev_set_drvdata(dev, master);
> + hw = spi_master_get_devdata(master);
> + memset(hw, 0, sizeof(*hw));
> +
> + hw->master = spi_master_get(master);
> + hw->dev = dev;
> +
> + init_completion(&hw->done);
> +
> + /* setup the state for the bitbang driver */
> + bbp = &hw->bitbang;
> + bbp->master = hw->master;
> + bbp->setup_transfer = spi_ppc4xx_setupxfer;
> + bbp->chipselect = spi_ppc4xx_chipsel;
> + bbp->txrx_bufs = spi_ppc4xx_txrx;
> + bbp->use_dma = 0;
> + bbp->master->setup = spi_ppc4xx_setup;
> + bbp->master->cleanup = spi_ppc4xx_cleanup;
> + /* only one SPI controller */
> + bbp->master->bus_num = 0;
> + if (bbp->master->num_chipselect == 0)
> + bbp->master->num_chipselect = GPIO_TOTPINS;
> +
> + dev_dbg(dev, "bitbang at %pn", bbp);
> +
> + /* get the clock for the OPB */
> + gpionp = of_find_compatible_node(NULL, NULL, "ibm,opb");
> + if (gpionp == NULL) {
> + dev_warn(dev, "OPB: cannot find noden");
> + ret = -ENODEV;
> + goto free_master;
> + }
> + /* get the clock (Hz) for the OPB */
> + clk = of_get_property(gpionp, "clock-frequency", NULL);
> + if (clk == NULL) {
> + dev_warn(dev, "OPB: no clock-frequency property setn");
> + of_node_put(gpionp);
> + ret = -ENODEV;
> + goto free_master;
> + }
> + hw->opb_freq = *clk;
> + hw->opb_freq >>= 2;
> + of_node_put(gpionp);
> +
> + ret = of_address_to_resource(np, 0, &resource);
> + if (ret) {
> + printk(KERN_ERR "Error while parsing device node resourcen");
> + goto free_master;
> + }
> + hw->mapbase = resource.start;
> + hw->mapsize = resource.end - resource.start + 1;
> +
> + /* sanity check */
> + if (hw->mapsize < sizeof(struct spi_ppc4xx_regs)) {
> + dev_warn(dev, "too small to map registersn");
> + /* XXXX */
> + ret = -EINVAL;
> + goto free_master;
> + }
> +
> + hw->irqnum = irq_of_parse_and_map(np, 0);
> + ret = request_irq(hw->irqnum, spi_ppc4xx_int,
> + IRQF_DISABLED, "spi_ppc4xx_of", (void *)hw);
> + if (ret) {
> + dev_warn(dev, "unable to allocate interruptn");
> + goto free_master;
> + }
> +
> + if (!request_mem_region(hw->mapbase, hw->mapsize, DRIVER_NAME)) {
> + dev_warn(dev, "resource unavailablen");
> + ret = -EBUSY;
> + goto request_mem_error;
> + }
> +
> + hw->regs = ioremap(hw->mapbase, sizeof(struct spi_ppc4xx_regs));
> +
> + if (!hw->regs) {
> + dev_warn(dev, "unable to memory map registersn");
> + ret = -ENXIO;
> + goto map_io_error;
> + }
> +
> + /* since there's no GPIO driver we have to do it ourselves */
> + /* find the entry for GPIO0 */
> + gpionp = of_find_compatible_node(NULL, NULL, "ibm,gpio");
> + if (gpionp == NULL) {
> + dev_warn(dev, "unable to find node for GPIO0n");
> + ret = -ENODEV;
> + goto unmap_regs;
> + }
> + regaddr = of_get_address(gpionp, 0, &size64, NULL);
> + if (regaddr == NULL) {
> + dev_warn(dev, "unable to get address for GPIO0n");
> + of_node_put(gpionp);
> + ret = -ENODEV;
> + goto unmap_regs;
> + }
> + addr64 = of_translate_address(gpionp, regaddr);
> +
> + hw->gpio0 = ioremap(addr64, size64);
> + if (!hw->gpio0) {
> + dev_warn(dev, "unable to memory map gpio0n");
> + of_node_put(gpionp);
> + ret = -ENOMEM;
> + goto unmap_regs;
> + }
> + gpio0np = gpionp;
> +
> + /* find the entry for GPIO1 */
> + /* note that this will of_node_put gpio0np! */
> + gpionp = of_find_compatible_node(gpio0np, NULL, "ibm,gpio");
> + if (gpionp == NULL) {
> + dev_warn(dev, "unable to find node for GPIO1n");
> + ret = -ENODEV;
> + goto unmap_gpio0;
> + }
> + regaddr = of_get_address(gpionp, 0, &size64, NULL);
> + if (regaddr == NULL) {
> + dev_warn(dev, "unable to get address for GPIO1n");
> + of_node_put(gpionp);
> + ret = -ENODEV;
> + goto unmap_gpio0;
> + }
> + addr64 = of_translate_address(gpionp, regaddr);
> +
> + /* possibly needed for CS */
> + hw->gpio1 = ioremap(addr64, size64);
> + if (!hw->gpio1) {
> + dev_warn(dev, "unable to memory map gpio1n");
> + of_node_put(gpionp);
> + ret = -ENOMEM;
> + goto unmap_gpio0;
> + }
> + of_node_put(gpionp);
> +
> + spi_ppc4xx_enable(hw);
> +
> + /* register our spi controller */
> + ret = spi_bitbang_start(bbp);
> + if (ret) {
> + dev_err(dev, "Failed to register SPI mastern");
> + goto unmap_gpio0;
> + }
> +
> + printk(KERN_INFO "SPI: SPI_PPC4XX OF SPI drivern");
> +
> + return 0;
> +
> +unmap_gpio0:
> + iounmap(hw->gpio0);
> +unmap_regs:
> + iounmap(hw->regs);
> +map_io_error:
> + release_mem_region(hw->mapbase, hw->mapsize);
> +request_mem_error:
> + free_irq(hw->irqnum, hw);
> +free_master:
> + dev_set_drvdata(dev, NULL);
> + spi_master_put(master);
> +
> + dev_err(dev, "initialization failedn");
> + return ret;
> +}
> +
> +static int __exit spi_ppc4xx_of_remove(struct of_device *op)
> +{
> + struct spi_master *master = dev_get_drvdata(&op->dev);
> + struct ppc4xx_spi *hw;
> +
> + hw = spi_master_get_devdata(master);
> + spi_bitbang_stop(&hw->bitbang);
> + spi_unregister_master(hw->master);
> + dev_set_drvdata(&op->dev, NULL);
> + release_mem_region(hw->mapbase, hw->mapsize);
> + free_irq(hw->irqnum, hw);
> + iounmap(hw->regs);
> + iounmap(hw->gpio0);
> + iounmap(hw->gpio1);
> +
> + return 0;
> +}
> +
> +static struct of_device_id spi_ppc4xx_of_match[] = {
> + { .type = "spi", .compatible = "ibm,spi", },
> + {},
> +};
> +
> +MODULE_DEVICE_TABLE(of, spi_ppc4xx_of_match);
> +
> +static struct of_platform_driver spi_ppc4xx_of_driver = {
> + .owner = THIS_MODULE,
> + .name = DRIVER_NAME,
> + .match_table = spi_ppc4xx_of_match,
> + .probe = spi_ppc4xx_of_probe,
> + .remove = __exit_p(spi_ppc4xx_of_remove),
> + .driver = {
> + .name = DRIVER_NAME,
> + .owner = THIS_MODULE,
> + },
> +};
> +
> +static int __init spi_ppc4xx_init(void)
> +{
> + return of_register_platform_driver(&spi_ppc4xx_of_driver);
> +}
> +
> +static void __exit spi_ppc4xx_exit(void)
> +{
> + of_unregister_platform_driver(&spi_ppc4xx_of_driver);
> +}
> +
> +#else /* not OF-type probe */
> +
> +static int __devinit spi_ppc4xx_probe(struct platform_device *pdev)
> +{
> + struct ppc4xx_spi *hw;
> + struct spi_master *master;
> + struct spi_bitbang *bbp;
> + struct device *dev = &pdev->dev;
> + struct resource *mem_io, *irqres;
> + int ret = -ENODEV;
> +
> + master = spi_alloc_master(dev, sizeof(*hw));
> + if (master == NULL)
> + return -ENOMEM;
> +
> + dev_set_drvdata(dev, master);
> + hw = spi_master_get_devdata(master);
> + memset(hw, 0, sizeof(*hw));
> +
> + hw->master = spi_master_get(master);
> + hw->dev = dev;
> +
> + platform_set_drvdata(pdev, hw);
> + init_completion(&hw->done);
> +
> + /* setup the state for the bitbang driver */
> + bbp = &hw->bitbang;
> + bbp->master = hw->master;
> + bbp->setup_transfer = spi_ppc4xx_setupxfer;
> + bbp->chipselect = spi_ppc4xx_chipsel;
> + bbp->txrx_bufs = spi_ppc4xx_txrx;
> + bbp->use_dma = 0;
> + bbp->master->setup = spi_ppc4xx_setup;
> + bbp->master->cleanup = spi_ppc4xx_cleanup;
> + /* only one SPI controller */
> + bbp->master->bus_num = 0;
> + if (bbp->master->num_chipselect == 0)
> + bbp->master->num_chipselect = GPIO_TOTPINS;
> +
> + dev_dbg(dev, "bitbang at %pn", bbp);
> +
> + /* get the clock (Hz) for the OPB. Set in sequoia_setup_arch() */
> + hw->opb_freq = ocp_sys_info.opb_bus_freq >> 2;
> +
> + /* needed to set SCPD0 */
> + hw->gpio0 = ioremap(GPIO0_BASE, GPIOx_SIZE);
> + if (hw->gpio0 == NULL) {
> + printk(KERN_ERR DRIVER_NAME " unable to ioremap GPIO0n");
> + ret = -ENOMEM;
> + goto free_master;
> + }
> + /* possibly needed for CS */
> + hw->gpio1 = ioremap(GPIO1_BASE, GPIOx_SIZE);
> + if (hw->gpio1 == NULL) {
> + printk(KERN_ERR DRIVER_NAME " unable to ioremap GPIO1n");
> + iounmap(hw->gpio0);
> + ret = -ENOMEM;
> + goto free_master;
> + }
> +
> + mem_io = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> + irqres = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
> +
> + if ((!mem_io) | (!irqres))
> + goto out_err;
> + /* save value for release_mem_region use */
> + hw->mapbase = mem_io->start;
> + hw->mapsize = mem_io->end - mem_io->start + 1;
> + /* sanity check */
> + if (hw->mapsize < sizeof(struct spi_ppc4xx_regs)) {
> + dev_warn(dev, "too small to map registersn");
> + /* XXXX */
> + ret = -EINVAL;
> + goto out_err;
> + }
> +
> + hw->irqnum = irqres->start;
> + ret = request_irq(hw->irqnum, spi_ppc4xx_int,
> + IRQF_DISABLED, "spi_ppc4xx", (void *)hw);
> + if (ret)
> + goto out_err;
> +
> + if (!request_mem_region(hw->mapbase, hw->mapsize, DRIVER_NAME)) {
> + printk(KERN_ERR DRIVER_NAME " - resource unavailablen");
> + ret = -EBUSY;
> + goto request_mem_error;
> + }
> +
> + hw->regs = ioremap(hw->mapbase, sizeof(struct spi_ppc4xx_regs));
> +
> + if (!hw->regs) {
> + printk(KERN_ERR DRIVER_NAME " - failed to map spi regsn");
> + ret = -ENXIO;
> + goto map_io_error;
> + }
> +
> + spi_ppc4xx_enable(hw);
> +
> + /* register our spi controller */
> + ret = spi_bitbang_start(bbp);
> + if (ret) {
> + dev_err(dev, "Failed to register SPI mastern");
> + goto map_io_error;
> + }
> +
> + return 0;
> +
> +map_io_error:
> + release_mem_region(hw->mapbase, hw->mapsize);
> +request_mem_error:
> + free_irq(hw->irqnum, hw);
> +out_err:
> + iounmap(hw->gpio0);
> + iounmap(hw->gpio1);
> +free_master:
> + platform_set_drvdata(pdev, NULL);
> + dev_set_drvdata(dev, NULL);
> + spi_master_put(master);
> +
> + printk(KERN_ERR "SPI: SPI_PPC4XX SPI init FAILED !!!n");
> + return ret;
> +}
> +
> +static int __devexit spi_ppc4xx_remove(struct platform_device *dev)
> +{
> + struct ppc4xx_spi *hw;
> +
> + hw = platform_get_drvdata(dev);
> + spi_bitbang_stop(&hw->bitbang);
> + spi_unregister_master(hw->master);
> + dev_set_drvdata(&dev->dev, NULL);
> + platform_set_drvdata(dev, NULL);
> + release_mem_region(hw->mapbase, hw->mapsize);
> + free_irq(hw->irqnum, hw);
> + iounmap(hw->regs);
> + iounmap(hw->gpio0);
> + iounmap(hw->gpio1);
> +
> + return 0;
> +}
> +
> +static struct platform_driver spi_ppc4xx_platform_driver = {
> + .probe = spi_ppc4xx_probe,
> + .remove = __exit_p(spi_ppc4xx_remove),
> + .driver = {
> + .name = "spi_ppc4xx",
> + .owner = THIS_MODULE,
> + },
> +};
> +
> +static int __init spi_ppc4xx_init(void)
> +{
> + printk(KERN_INFO "SPI: SPI_PPC4XX SPI drivern");
> + return platform_driver_register(&spi_ppc4xx_platform_driver);
> +}
> +
> +static void __exit spi_ppc4xx_exit(void)
> +{
> + platform_driver_unregister(&spi_ppc4xx_platform_driver);
> +}
> +#endif /* CONFIG_PPC_OF */
> +
> +module_init(spi_ppc4xx_init);
> +module_exit(spi_ppc4xx_exit);
> +
> +MODULE_LICENSE("GPL");
> --
> Gary Jennejohn
> *********************************************************************
> DENX Software Engineering GmbH, MD: Wolfgang Denk & Detlev Zundel
> HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
> Phone: +49-8142-66989-0 Fax: +49-8142-66989-80 Email:
office@denx.de
> *********************************************************************
> _______________________________________________
> Kernel-mentors mailing list
>
Kernel-mentors@selenic.com
>
http://selenic.com/mailman/listinfo/kernel-mentors
>
>
>
>
>
>