Merge branch 'topic/hda' into for-linus
[pandora-kernel.git] / drivers / spi / spi_mpc83xx.c
index 44a2b46..f4573a9 100644 (file)
@@ -14,6 +14,8 @@
 #include <linux/init.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/err.h>
 #include <linux/completion.h>
 #include <linux/interrupt.h>
 #include <linux/delay.h>
 #include <linux/spi/spi_bitbang.h>
 #include <linux/platform_device.h>
 #include <linux/fsl_devices.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/gpio.h>
+#include <linux/of_gpio.h>
+#include <linux/of_spi.h>
 
+#include <sysdev/fsl_soc.h>
 #include <asm/irq.h>
 #include <asm/io.h>
 
@@ -79,7 +87,7 @@ struct mpc83xx_spi {
        u32(*get_tx) (struct mpc83xx_spi *);
 
        unsigned int count;
-       int irq;
+       unsigned int irq;
 
        unsigned nsecs;         /* (clock cycle time)/2 */
 
@@ -89,9 +97,6 @@ struct mpc83xx_spi {
 
        bool qe_mode;
 
-       void (*activate_cs) (u8 cs, u8 polarity);
-       void (*deactivate_cs) (u8 cs, u8 polarity);
-
        u8 busy;
 
        struct workqueue_struct *workqueue;
@@ -123,6 +128,7 @@ static inline u32 mpc83xx_spi_read_reg(__be32 __iomem * reg)
 }
 
 #define MPC83XX_SPI_RX_BUF(type)                                         \
+static                                                                   \
 void mpc83xx_spi_rx_buf_##type(u32 data, struct mpc83xx_spi *mpc83xx_spi) \
 {                                                                        \
        type * rx = mpc83xx_spi->rx;                                      \
@@ -131,6 +137,7 @@ void mpc83xx_spi_rx_buf_##type(u32 data, struct mpc83xx_spi *mpc83xx_spi) \
 }
 
 #define MPC83XX_SPI_TX_BUF(type)                               \
+static                                                         \
 u32 mpc83xx_spi_tx_buf_##type(struct mpc83xx_spi *mpc83xx_spi) \
 {                                                              \
        u32 data;                                               \
@@ -151,15 +158,14 @@ MPC83XX_SPI_TX_BUF(u32)
 
 static void mpc83xx_spi_chipselect(struct spi_device *spi, int value)
 {
-       struct mpc83xx_spi *mpc83xx_spi;
-       u8 pol = spi->mode & SPI_CS_HIGH ? 1 : 0;
+       struct mpc83xx_spi *mpc83xx_spi = spi_master_get_devdata(spi->master);
+       struct fsl_spi_platform_data *pdata = spi->dev.parent->platform_data;
+       bool pol = spi->mode & SPI_CS_HIGH;
        struct spi_mpc83xx_cs   *cs = spi->controller_state;
 
-       mpc83xx_spi = spi_master_get_devdata(spi->master);
-
        if (value == BITBANG_CS_INACTIVE) {
-               if (mpc83xx_spi->deactivate_cs)
-                       mpc83xx_spi->deactivate_cs(spi->chip_select, pol);
+               if (pdata->cs_control)
+                       pdata->cs_control(spi, !pol);
        }
 
        if (value == BITBANG_CS_ACTIVE) {
@@ -172,7 +178,7 @@ static void mpc83xx_spi_chipselect(struct spi_device *spi, int value)
 
                if (cs->hw_mode != regval) {
                        unsigned long flags;
-                       void *tmp_ptr = &mpc83xx_spi->base->mode;
+                       __be32 __iomem *mode = &mpc83xx_spi->base->mode;
 
                        regval = cs->hw_mode;
                        /* Turn off IRQs locally to minimize time that
@@ -180,12 +186,12 @@ static void mpc83xx_spi_chipselect(struct spi_device *spi, int value)
                         */
                        local_irq_save(flags);
                        /* Turn off SPI unit prior changing mode */
-                       mpc83xx_spi_write_reg(tmp_ptr, regval & ~SPMODE_ENABLE);
-                       mpc83xx_spi_write_reg(tmp_ptr, regval);
+                       mpc83xx_spi_write_reg(mode, regval & ~SPMODE_ENABLE);
+                       mpc83xx_spi_write_reg(mode, regval);
                        local_irq_restore(flags);
                }
-               if (mpc83xx_spi->activate_cs)
-                       mpc83xx_spi->activate_cs(spi->chip_select, pol);
+               if (pdata->cs_control)
+                       pdata->cs_control(spi, pol);
        }
 }
 
@@ -284,7 +290,7 @@ int mpc83xx_spi_setup_transfer(struct spi_device *spi, struct spi_transfer *t)
        regval =  mpc83xx_spi_read_reg(&mpc83xx_spi->base->mode);
        if (cs->hw_mode != regval) {
                unsigned long flags;
-               void *tmp_ptr = &mpc83xx_spi->base->mode;
+               __be32 __iomem *mode = &mpc83xx_spi->base->mode;
 
                regval = cs->hw_mode;
                /* Turn off IRQs locally to minimize time
@@ -292,8 +298,8 @@ int mpc83xx_spi_setup_transfer(struct spi_device *spi, struct spi_transfer *t)
                 */
                local_irq_save(flags);
                /* Turn off SPI unit prior changing mode */
-               mpc83xx_spi_write_reg(tmp_ptr, regval & ~SPMODE_ENABLE);
-               mpc83xx_spi_write_reg(tmp_ptr, regval);
+               mpc83xx_spi_write_reg(mode, regval & ~SPMODE_ENABLE);
+               mpc83xx_spi_write_reg(mode, regval);
                local_irq_restore(flags);
        }
        return 0;
@@ -483,7 +489,7 @@ static int mpc83xx_spi_setup(struct spi_device *spi)
        return 0;
 }
 
-irqreturn_t mpc83xx_spi_irq(s32 irq, void *context_data)
+static irqreturn_t mpc83xx_spi_irq(s32 irq, void *context_data)
 {
        struct mpc83xx_spi *mpc83xx_spi = context_data;
        u32 event;
@@ -545,43 +551,28 @@ static void mpc83xx_spi_cleanup(struct spi_device *spi)
        kfree(spi->controller_state);
 }
 
-static int __init mpc83xx_spi_probe(struct platform_device *dev)
+static struct spi_master * __devinit
+mpc83xx_spi_probe(struct device *dev, struct resource *mem, unsigned int irq)
 {
+       struct fsl_spi_platform_data *pdata = dev->platform_data;
        struct spi_master *master;
        struct mpc83xx_spi *mpc83xx_spi;
-       struct fsl_spi_platform_data *pdata;
-       struct resource *r;
        u32 regval;
        int ret = 0;
 
-       /* Get resources(memory, IRQ) associated with the device */
-       master = spi_alloc_master(&dev->dev, sizeof(struct mpc83xx_spi));
-
+       master = spi_alloc_master(dev, sizeof(struct mpc83xx_spi));
        if (master == NULL) {
                ret = -ENOMEM;
                goto err;
        }
 
-       platform_set_drvdata(dev, master);
-       pdata = dev->dev.platform_data;
+       dev_set_drvdata(dev, master);
 
-       if (pdata == NULL) {
-               ret = -ENODEV;
-               goto free_master;
-       }
-
-       r = platform_get_resource(dev, IORESOURCE_MEM, 0);
-       if (r == NULL) {
-               ret = -ENODEV;
-               goto free_master;
-       }
        master->setup = mpc83xx_spi_setup;
        master->transfer = mpc83xx_spi_transfer;
        master->cleanup = mpc83xx_spi_cleanup;
 
        mpc83xx_spi = spi_master_get_devdata(master);
-       mpc83xx_spi->activate_cs = pdata->activate_cs;
-       mpc83xx_spi->deactivate_cs = pdata->deactivate_cs;
        mpc83xx_spi->qe_mode = pdata->qe_mode;
        mpc83xx_spi->get_rx = mpc83xx_spi_rx_buf_u8;
        mpc83xx_spi->get_tx = mpc83xx_spi_tx_buf_u8;
@@ -596,18 +587,13 @@ static int __init mpc83xx_spi_probe(struct platform_device *dev)
 
        init_completion(&mpc83xx_spi->done);
 
-       mpc83xx_spi->base = ioremap(r->start, r->end - r->start + 1);
+       mpc83xx_spi->base = ioremap(mem->start, mem->end - mem->start + 1);
        if (mpc83xx_spi->base == NULL) {
                ret = -ENOMEM;
                goto put_master;
        }
 
-       mpc83xx_spi->irq = platform_get_irq(dev, 0);
-
-       if (mpc83xx_spi->irq < 0) {
-               ret = -ENXIO;
-               goto unmap_io;
-       }
+       mpc83xx_spi->irq = irq;
 
        /* Register for SPI Interrupt */
        ret = request_irq(mpc83xx_spi->irq, mpc83xx_spi_irq,
@@ -649,9 +635,9 @@ static int __init mpc83xx_spi_probe(struct platform_device *dev)
 
        printk(KERN_INFO
               "%s: MPC83xx SPI Controller driver at 0x%p (irq = %d)\n",
-              dev_name(&dev->dev), mpc83xx_spi->base, mpc83xx_spi->irq);
+              dev_name(dev), mpc83xx_spi->base, mpc83xx_spi->irq);
 
-       return ret;
+       return master;
 
 unreg_master:
        destroy_workqueue(mpc83xx_spi->workqueue);
@@ -661,18 +647,16 @@ unmap_io:
        iounmap(mpc83xx_spi->base);
 put_master:
        spi_master_put(master);
-free_master:
-       kfree(master);
 err:
-       return ret;
+       return ERR_PTR(ret);
 }
 
-static int __exit mpc83xx_spi_remove(struct platform_device *dev)
+static int __devexit mpc83xx_spi_remove(struct device *dev)
 {
        struct mpc83xx_spi *mpc83xx_spi;
        struct spi_master *master;
 
-       master = platform_get_drvdata(dev);
+       master = dev_get_drvdata(dev);
        mpc83xx_spi = spi_master_get_devdata(master);
 
        flush_workqueue(mpc83xx_spi->workqueue);
@@ -685,23 +669,293 @@ static int __exit mpc83xx_spi_remove(struct platform_device *dev)
        return 0;
 }
 
+struct mpc83xx_spi_probe_info {
+       struct fsl_spi_platform_data pdata;
+       int *gpios;
+       bool *alow_flags;
+};
+
+static struct mpc83xx_spi_probe_info *
+to_of_pinfo(struct fsl_spi_platform_data *pdata)
+{
+       return container_of(pdata, struct mpc83xx_spi_probe_info, pdata);
+}
+
+static void mpc83xx_spi_cs_control(struct spi_device *spi, bool on)
+{
+       struct device *dev = spi->dev.parent;
+       struct mpc83xx_spi_probe_info *pinfo = to_of_pinfo(dev->platform_data);
+       u16 cs = spi->chip_select;
+       int gpio = pinfo->gpios[cs];
+       bool alow = pinfo->alow_flags[cs];
+
+       gpio_set_value(gpio, on ^ alow);
+}
+
+static int of_mpc83xx_spi_get_chipselects(struct device *dev)
+{
+       struct device_node *np = dev_archdata_get_node(&dev->archdata);
+       struct fsl_spi_platform_data *pdata = dev->platform_data;
+       struct mpc83xx_spi_probe_info *pinfo = to_of_pinfo(pdata);
+       unsigned int ngpios;
+       int i = 0;
+       int ret;
+
+       ngpios = of_gpio_count(np);
+       if (!ngpios) {
+               /*
+                * SPI w/o chip-select line. One SPI device is still permitted
+                * though.
+                */
+               pdata->max_chipselect = 1;
+               return 0;
+       }
+
+       pinfo->gpios = kmalloc(ngpios * sizeof(pinfo->gpios), GFP_KERNEL);
+       if (!pinfo->gpios)
+               return -ENOMEM;
+       memset(pinfo->gpios, -1, ngpios * sizeof(pinfo->gpios));
+
+       pinfo->alow_flags = kzalloc(ngpios * sizeof(pinfo->alow_flags),
+                                   GFP_KERNEL);
+       if (!pinfo->alow_flags) {
+               ret = -ENOMEM;
+               goto err_alloc_flags;
+       }
+
+       for (; i < ngpios; i++) {
+               int gpio;
+               enum of_gpio_flags flags;
+
+               gpio = of_get_gpio_flags(np, i, &flags);
+               if (!gpio_is_valid(gpio)) {
+                       dev_err(dev, "invalid gpio #%d: %d\n", i, gpio);
+                       goto err_loop;
+               }
+
+               ret = gpio_request(gpio, dev_name(dev));
+               if (ret) {
+                       dev_err(dev, "can't request gpio #%d: %d\n", i, ret);
+                       goto err_loop;
+               }
+
+               pinfo->gpios[i] = gpio;
+               pinfo->alow_flags[i] = flags & OF_GPIO_ACTIVE_LOW;
+
+               ret = gpio_direction_output(pinfo->gpios[i],
+                                           pinfo->alow_flags[i]);
+               if (ret) {
+                       dev_err(dev, "can't set output direction for gpio "
+                               "#%d: %d\n", i, ret);
+                       goto err_loop;
+               }
+       }
+
+       pdata->max_chipselect = ngpios;
+       pdata->cs_control = mpc83xx_spi_cs_control;
+
+       return 0;
+
+err_loop:
+       while (i >= 0) {
+               if (gpio_is_valid(pinfo->gpios[i]))
+                       gpio_free(pinfo->gpios[i]);
+               i--;
+       }
+
+       kfree(pinfo->alow_flags);
+       pinfo->alow_flags = NULL;
+err_alloc_flags:
+       kfree(pinfo->gpios);
+       pinfo->gpios = NULL;
+       return ret;
+}
+
+static int of_mpc83xx_spi_free_chipselects(struct device *dev)
+{
+       struct fsl_spi_platform_data *pdata = dev->platform_data;
+       struct mpc83xx_spi_probe_info *pinfo = to_of_pinfo(pdata);
+       int i;
+
+       if (!pinfo->gpios)
+               return 0;
+
+       for (i = 0; i < pdata->max_chipselect; i++) {
+               if (gpio_is_valid(pinfo->gpios[i]))
+                       gpio_free(pinfo->gpios[i]);
+       }
+
+       kfree(pinfo->gpios);
+       kfree(pinfo->alow_flags);
+       return 0;
+}
+
+static int __devinit of_mpc83xx_spi_probe(struct of_device *ofdev,
+                                         const struct of_device_id *ofid)
+{
+       struct device *dev = &ofdev->dev;
+       struct device_node *np = ofdev->node;
+       struct mpc83xx_spi_probe_info *pinfo;
+       struct fsl_spi_platform_data *pdata;
+       struct spi_master *master;
+       struct resource mem;
+       struct resource irq;
+       const void *prop;
+       int ret = -ENOMEM;
+
+       pinfo = kzalloc(sizeof(*pinfo), GFP_KERNEL);
+       if (!pinfo)
+               return -ENOMEM;
+
+       pdata = &pinfo->pdata;
+       dev->platform_data = pdata;
+
+       /* Allocate bus num dynamically. */
+       pdata->bus_num = -1;
+
+       /* SPI controller is either clocked from QE or SoC clock. */
+       pdata->sysclk = get_brgfreq();
+       if (pdata->sysclk == -1) {
+               pdata->sysclk = fsl_get_sys_freq();
+               if (pdata->sysclk == -1) {
+                       ret = -ENODEV;
+                       goto err_clk;
+               }
+       }
+
+       prop = of_get_property(np, "mode", NULL);
+       if (prop && !strcmp(prop, "cpu-qe"))
+               pdata->qe_mode = 1;
+
+       ret = of_mpc83xx_spi_get_chipselects(dev);
+       if (ret)
+               goto err;
+
+       ret = of_address_to_resource(np, 0, &mem);
+       if (ret)
+               goto err;
+
+       ret = of_irq_to_resource(np, 0, &irq);
+       if (!ret) {
+               ret = -EINVAL;
+               goto err;
+       }
+
+       master = mpc83xx_spi_probe(dev, &mem, irq.start);
+       if (IS_ERR(master)) {
+               ret = PTR_ERR(master);
+               goto err;
+       }
+
+       of_register_spi_devices(master, np);
+
+       return 0;
+
+err:
+       of_mpc83xx_spi_free_chipselects(dev);
+err_clk:
+       kfree(pinfo);
+       return ret;
+}
+
+static int __devexit of_mpc83xx_spi_remove(struct of_device *ofdev)
+{
+       int ret;
+
+       ret = mpc83xx_spi_remove(&ofdev->dev);
+       if (ret)
+               return ret;
+       of_mpc83xx_spi_free_chipselects(&ofdev->dev);
+       return 0;
+}
+
+static const struct of_device_id of_mpc83xx_spi_match[] = {
+       { .compatible = "fsl,spi" },
+       {},
+};
+MODULE_DEVICE_TABLE(of, of_mpc83xx_spi_match);
+
+static struct of_platform_driver of_mpc83xx_spi_driver = {
+       .name           = "mpc83xx_spi",
+       .match_table    = of_mpc83xx_spi_match,
+       .probe          = of_mpc83xx_spi_probe,
+       .remove         = __devexit_p(of_mpc83xx_spi_remove),
+};
+
+#ifdef CONFIG_MPC832x_RDB
+/*
+ *                             XXX XXX XXX
+ * This is "legacy" platform driver, was used by the MPC8323E-RDB boards
+ * only. The driver should go away soon, since newer MPC8323E-RDB's device
+ * tree can work with OpenFirmware driver. But for now we support old trees
+ * as well.
+ */
+static int __devinit plat_mpc83xx_spi_probe(struct platform_device *pdev)
+{
+       struct resource *mem;
+       unsigned int irq;
+       struct spi_master *master;
+
+       if (!pdev->dev.platform_data)
+               return -EINVAL;
+
+       mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!mem)
+               return -EINVAL;
+
+       irq = platform_get_irq(pdev, 0);
+       if (!irq)
+               return -EINVAL;
+
+       master = mpc83xx_spi_probe(&pdev->dev, mem, irq);
+       if (IS_ERR(master))
+               return PTR_ERR(master);
+       return 0;
+}
+
+static int __devexit plat_mpc83xx_spi_remove(struct platform_device *pdev)
+{
+       return mpc83xx_spi_remove(&pdev->dev);
+}
+
 MODULE_ALIAS("platform:mpc83xx_spi");
 static struct platform_driver mpc83xx_spi_driver = {
-       .remove = __exit_p(mpc83xx_spi_remove),
+       .probe = plat_mpc83xx_spi_probe,
+       .remove = __exit_p(plat_mpc83xx_spi_remove),
        .driver = {
                .name = "mpc83xx_spi",
                .owner = THIS_MODULE,
        },
 };
 
+static bool legacy_driver_failed;
+
+static void __init legacy_driver_register(void)
+{
+       legacy_driver_failed = platform_driver_register(&mpc83xx_spi_driver);
+}
+
+static void __exit legacy_driver_unregister(void)
+{
+       if (legacy_driver_failed)
+               return;
+       platform_driver_unregister(&mpc83xx_spi_driver);
+}
+#else
+static void __init legacy_driver_register(void) {}
+static void __exit legacy_driver_unregister(void) {}
+#endif /* CONFIG_MPC832x_RDB */
+
 static int __init mpc83xx_spi_init(void)
 {
-       return platform_driver_probe(&mpc83xx_spi_driver, mpc83xx_spi_probe);
+       legacy_driver_register();
+       return of_register_platform_driver(&of_mpc83xx_spi_driver);
 }
 
 static void __exit mpc83xx_spi_exit(void)
 {
-       platform_driver_unregister(&mpc83xx_spi_driver);
+       of_unregister_platform_driver(&of_mpc83xx_spi_driver);
+       legacy_driver_unregister();
 }
 
 module_init(mpc83xx_spi_init);