[PATCH 1/4] [SPI] spi_mpc83xx: convert to the OF platform driver
Anton Vorontsov
avorontsov at ru.mvista.com
Thu May 22 01:41:37 EST 2008
This patch converts the driver to speak OF directly. FSL SPI controllers
do not use internal chip-select machines, so boards must use GPIOs for
these purposes.
Signed-off-by: Anton Vorontsov <avorontsov at ru.mvista.com>
---
Documentation/powerpc/booting-without-of.txt | 1 +
drivers/spi/Kconfig | 3 +-
drivers/spi/spi_mpc83xx.c | 279 +++++++++++++++++---------
3 files changed, 184 insertions(+), 99 deletions(-)
diff --git a/Documentation/powerpc/booting-without-of.txt b/Documentation/powerpc/booting-without-of.txt
index 8545f82..011bf5e 100644
--- a/Documentation/powerpc/booting-without-of.txt
+++ b/Documentation/powerpc/booting-without-of.txt
@@ -1607,6 +1607,7 @@ platforms are moved over to use the flattened-device-tree model.
controller you have.
- interrupt-parent : the phandle for the interrupt controller that
services interrupts for this device.
+ - gpios : (optional) may specify GPIOs used for SPI chip-selects
Example:
spi at 4c0 {
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index 3f0dcae..4c9afeb 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -129,7 +129,8 @@ config SPI_MPC52xx_PSC
config SPI_MPC83xx
tristate "Freescale MPC8xxx SPI controller"
- depends on SPI_MASTER && FSL_SOC && EXPERIMENTAL
+ depends on SPI_MASTER && OF_GPIO && FSL_SOC && EXPERIMENTAL
+ select SPI_MASTER_OF
help
This enables using the Freescale MPC8xxx SPI controllers in master
mode.
diff --git a/drivers/spi/spi_mpc83xx.c b/drivers/spi/spi_mpc83xx.c
index 6832da6..7ae4096 100644
--- a/drivers/spi/spi_mpc83xx.c
+++ b/drivers/spi/spi_mpc83xx.c
@@ -21,11 +21,14 @@
#include <linux/device.h>
#include <linux/spi/spi.h>
#include <linux/spi/spi_bitbang.h>
-#include <linux/platform_device.h>
-#include <linux/fsl_devices.h>
+#include <linux/spi/spi_of.h>
+#include <linux/of_platform.h>
+#include <linux/gpio.h>
+#include <linux/of_gpio.h>
#include <asm/irq.h>
#include <asm/io.h>
+#include <sysdev/fsl_soc.h>
/* SPI Controller registers */
struct mpc83xx_spi_reg {
@@ -66,6 +69,11 @@ struct mpc83xx_spi_reg {
#define SPIM_NE 0x00000200 /* Not empty */
#define SPIM_NF 0x00000100 /* Not full */
+enum spi83xx_mode {
+ CPU_MODE = 0,
+ CPU_QE_MODE,
+};
+
/* SPI Controller driver's private data. */
struct mpc83xx_spi {
struct mpc83xx_spi_reg __iomem *base;
@@ -80,6 +88,7 @@ struct mpc83xx_spi {
unsigned int count;
int irq;
+ unsigned int *gpios;
unsigned nsecs; /* (clock cycle time)/2 */
@@ -87,10 +96,7 @@ struct mpc83xx_spi {
u32 rx_shift; /* RX data reg shift when in qe mode */
u32 tx_shift; /* TX data reg shift when in qe mode */
- bool qe_mode;
-
- void (*activate_cs) (u8 cs, u8 polarity);
- void (*deactivate_cs) (u8 cs, u8 polarity);
+ enum spi83xx_mode mode;
u8 busy;
@@ -151,16 +157,13 @@ 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 spi_mpc83xx_cs *cs = spi->controller_state;
+ unsigned int cs_gpio = mpc83xx_spi->gpios[spi->chip_select];
- 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 (value == BITBANG_CS_INACTIVE && gpio_is_valid(cs_gpio))
+ gpio_set_value(cs_gpio, !pol);
if (value == BITBANG_CS_ACTIVE) {
u32 regval = mpc83xx_spi_read_reg(&mpc83xx_spi->base->mode);
@@ -184,8 +187,8 @@ static void mpc83xx_spi_chipselect(struct spi_device *spi, int value)
mpc83xx_spi_write_reg(tmp_ptr, regval);
local_irq_restore(flags);
}
- if (mpc83xx_spi->activate_cs)
- mpc83xx_spi->activate_cs(spi->chip_select, pol);
+ if (gpio_is_valid(cs_gpio))
+ gpio_set_value(cs_gpio, pol);
}
}
@@ -225,14 +228,14 @@ int mpc83xx_spi_setup_transfer(struct spi_device *spi, struct spi_transfer *t)
if (bits_per_word <= 8) {
cs->get_rx = mpc83xx_spi_rx_buf_u8;
cs->get_tx = mpc83xx_spi_tx_buf_u8;
- if (mpc83xx_spi->qe_mode) {
+ if (mpc83xx_spi->mode == CPU_QE_MODE) {
cs->rx_shift = 16;
cs->tx_shift = 24;
}
} else if (bits_per_word <= 16) {
cs->get_rx = mpc83xx_spi_rx_buf_u16;
cs->get_tx = mpc83xx_spi_tx_buf_u16;
- if (mpc83xx_spi->qe_mode) {
+ if (mpc83xx_spi->mode == CPU_QE_MODE) {
cs->rx_shift = 16;
cs->tx_shift = 16;
}
@@ -242,7 +245,7 @@ int mpc83xx_spi_setup_transfer(struct spi_device *spi, struct spi_transfer *t)
} else
return -EINVAL;
- if (mpc83xx_spi->qe_mode && spi->mode & SPI_LSB_FIRST) {
+ if (mpc83xx_spi->mode == CPU_QE_MODE && spi->mode & SPI_LSB_FIRST) {
cs->tx_shift = 0;
if (bits_per_word <= 8)
cs->rx_shift = 8;
@@ -536,92 +539,152 @@ static void mpc83xx_spi_cleanup(struct spi_device *spi)
kfree(spi->controller_state);
}
-static int __init mpc83xx_spi_probe(struct platform_device *dev)
+static unsigned int of_num_children(struct device_node *parent)
+{
+ unsigned int count = 0;
+ struct device_node *child = NULL;
+
+ for_each_child_of_node(parent, child)
+ count++;
+
+ return count;
+}
+
+static void __devinit mpc83xx_spi_hwinit(struct mpc83xx_spi *mpc83xx_spi)
{
+ u32 regval;
+
+ /* SPI controller initializations */
+ mpc83xx_spi_write_reg(&mpc83xx_spi->base->mode, 0);
+ mpc83xx_spi_write_reg(&mpc83xx_spi->base->mask, 0);
+ mpc83xx_spi_write_reg(&mpc83xx_spi->base->command, 0);
+ mpc83xx_spi_write_reg(&mpc83xx_spi->base->event, 0xffffffff);
+
+ /* Enable SPI interface */
+ regval = SPMODE_INIT_VAL | SPMODE_ENABLE;
+ if (mpc83xx_spi->mode == CPU_QE_MODE)
+ regval |= SPMODE_OP;
+
+ mpc83xx_spi_write_reg(&mpc83xx_spi->base->mode, regval);
+}
+
+static int __devinit mpc83xx_spi_probe(struct of_device *ofdev,
+ const struct of_device_id *match)
+{
+ struct device *dev = &ofdev->dev;
+ struct device_node *np = ofdev->node;
struct spi_master *master;
struct mpc83xx_spi *mpc83xx_spi;
- struct fsl_spi_platform_data *pdata;
- struct resource *r;
- u32 regval;
int ret = 0;
+ int size;
+ const char *mode;
+ const u32 *bus_num;
+ int i = 0;
+
+ master = spi_alloc_master(dev, sizeof(struct mpc83xx_spi));
+ if (!master)
+ return -ENOMEM;
+ dev_set_drvdata(dev, master);
+ mpc83xx_spi = spi_master_get_devdata(master);
- /* Get resources(memory, IRQ) associated with the device */
- master = spi_alloc_master(&dev->dev, sizeof(struct mpc83xx_spi));
+ master->setup = mpc83xx_spi_setup;
+ master->transfer = mpc83xx_spi_transfer;
+ master->cleanup = mpc83xx_spi_cleanup;
+ mpc83xx_spi->get_rx = mpc83xx_spi_rx_buf_u8;
+ mpc83xx_spi->get_tx = mpc83xx_spi_tx_buf_u8;
- if (master == NULL) {
+ bus_num = of_get_property(np, "reg", &size);
+ if (!bus_num || size < sizeof(*bus_num)) {
+ dev_err(dev, "unable to get reg property from OF\n");
+ ret = -EINVAL;
+ goto err_bus_num;
+ }
+ master->bus_num = *bus_num;
+
+ master->num_chipselect = of_num_children(np);
+ mpc83xx_spi->gpios = kmalloc(
+ sizeof(mpc83xx_spi->gpios[0]) * master->num_chipselect,
+ GFP_KERNEL);
+ if (!mpc83xx_spi->gpios) {
ret = -ENOMEM;
- goto err;
+ goto err_alloc_gpios;
}
- platform_set_drvdata(dev, master);
- pdata = dev->dev.platform_data;
+ if (master->num_chipselect == 1) {
+ /* no retval check, CS isn't mandatory for single device */
+ mpc83xx_spi->gpios[0] = of_get_gpio(np, 0);
+ i++;
+ }
- if (pdata == NULL) {
- ret = -ENODEV;
- goto free_master;
+ for (; i < master->num_chipselect; i++) {
+ mpc83xx_spi->gpios[i] = of_get_gpio(np, i);
+ if (!gpio_is_valid(mpc83xx_spi->gpios[i])) {
+ dev_err(dev, "chipselect %d without GPIO\n", i);
+ goto err_of_get_gpio;
+ }
}
- r = platform_get_resource(dev, IORESOURCE_MEM, 0);
- if (r == NULL) {
- ret = -ENODEV;
- goto free_master;
+ for (i = 0; i < master->num_chipselect; i++) {
+ int gpio = mpc83xx_spi->gpios[i];
+
+ if (!gpio_is_valid(gpio))
+ continue;
+
+ ret = gpio_request(gpio, dev->bus_id);
+ if (ret)
+ goto err_gpio_request;
+
+ ret = gpio_direction_output(gpio, 0);
+ if (ret)
+ goto err_gpio_dir;
}
- 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;
- mpc83xx_spi->spibrg = pdata->sysclk;
+#ifdef CONFIG_QUICC_ENGINE
+ mpc83xx_spi->spibrg = get_brgfreq();
+#endif
+ if (!mpc83xx_spi->spibrg || mpc83xx_spi->spibrg == -1) {
+ mpc83xx_spi->spibrg = fsl_get_sys_freq();
+ if (!mpc83xx_spi->spibrg || mpc83xx_spi->spibrg == -1) {
+ dev_err(dev, "unable to get frequency from OF\n");
+ goto err_sysclk;
+ }
+ }
+
+ mode = of_get_property(np, "mode", NULL);
+ if (mode && !strcmp(mode, "cpu-qe"))
+ mpc83xx_spi->mode = CPU_QE_MODE;
mpc83xx_spi->rx_shift = 0;
mpc83xx_spi->tx_shift = 0;
- if (mpc83xx_spi->qe_mode) {
+ if (mpc83xx_spi->mode == CPU_QE_MODE) {
mpc83xx_spi->rx_shift = 16;
mpc83xx_spi->tx_shift = 24;
}
init_completion(&mpc83xx_spi->done);
- mpc83xx_spi->base = ioremap(r->start, r->end - r->start + 1);
- if (mpc83xx_spi->base == NULL) {
+ mpc83xx_spi->base = of_iomap(np, 0);
+ if (!mpc83xx_spi->base) {
+ dev_err(dev, "unable to get memory from OF\n");
ret = -ENOMEM;
- goto put_master;
+ goto err_iomap;
}
- mpc83xx_spi->irq = platform_get_irq(dev, 0);
-
- if (mpc83xx_spi->irq < 0) {
+ mpc83xx_spi->irq = irq_of_parse_and_map(np, 0);
+ if (mpc83xx_spi->irq == NO_IRQ) {
+ dev_err(dev, "unable to get IRQ from OF\n");
ret = -ENXIO;
- goto unmap_io;
+ goto err_irq_parse;
}
/* Register for SPI Interrupt */
ret = request_irq(mpc83xx_spi->irq, mpc83xx_spi_irq,
0, "mpc83xx_spi", mpc83xx_spi);
+ if (ret != 0) {
+ dev_err(dev, "unable to request IRQ\n");
+ goto err_irq_request;
+ }
- if (ret != 0)
- goto unmap_io;
-
- master->bus_num = pdata->bus_num;
- master->num_chipselect = pdata->max_chipselect;
-
- /* SPI controller initializations */
- mpc83xx_spi_write_reg(&mpc83xx_spi->base->mode, 0);
- mpc83xx_spi_write_reg(&mpc83xx_spi->base->mask, 0);
- mpc83xx_spi_write_reg(&mpc83xx_spi->base->command, 0);
- mpc83xx_spi_write_reg(&mpc83xx_spi->base->event, 0xffffffff);
-
- /* Enable SPI interface */
- regval = pdata->initial_spmode | SPMODE_INIT_VAL | SPMODE_ENABLE;
- if (pdata->qe_mode)
- regval |= SPMODE_OP;
-
- mpc83xx_spi_write_reg(&mpc83xx_spi->base->mode, regval);
spin_lock_init(&mpc83xx_spi->lock);
init_completion(&mpc83xx_spi->done);
INIT_WORK(&mpc83xx_spi->work, mpc83xx_spi_work);
@@ -629,42 +692,53 @@ static int __init mpc83xx_spi_probe(struct platform_device *dev)
mpc83xx_spi->workqueue = create_singlethread_workqueue(
master->dev.parent->bus_id);
- if (mpc83xx_spi->workqueue == NULL) {
+ if (!mpc83xx_spi->workqueue) {
ret = -EBUSY;
- goto free_irq;
+ goto err_wqueue;
}
+ mpc83xx_spi_hwinit(mpc83xx_spi);
+
ret = spi_register_master(master);
if (ret < 0)
- goto unreg_master;
+ goto err_spi_reg;
+
+ spi_of_register_devices(master, np);
printk(KERN_INFO
"%s: MPC83xx SPI Controller driver at 0x%p (irq = %d)\n",
- dev->dev.bus_id, mpc83xx_spi->base, mpc83xx_spi->irq);
+ dev->bus_id, mpc83xx_spi->base, mpc83xx_spi->irq);
return ret;
-unreg_master:
+err_spi_reg:
destroy_workqueue(mpc83xx_spi->workqueue);
-free_irq:
+err_wqueue:
free_irq(mpc83xx_spi->irq, mpc83xx_spi);
-unmap_io:
+err_irq_request:
+ irq_dispose_mapping(mpc83xx_spi->irq);
+err_irq_parse:
iounmap(mpc83xx_spi->base);
-put_master:
+err_iomap:
+err_sysclk:
+err_gpio_dir:
+ i++;
+err_gpio_request:
+ while (--i >= 0)
+ gpio_free(mpc83xx_spi->gpios[i]);
+err_of_get_gpio:
+ kfree(mpc83xx_spi->gpios);
+err_alloc_gpios:
+err_bus_num:
spi_master_put(master);
-free_master:
- kfree(master);
-err:
return ret;
}
-static int __exit mpc83xx_spi_remove(struct platform_device *dev)
+static int __devexit mpc83xx_spi_remove(struct of_device *ofdev)
{
- struct mpc83xx_spi *mpc83xx_spi;
- struct spi_master *master;
-
- master = platform_get_drvdata(dev);
- mpc83xx_spi = spi_master_get_devdata(master);
+ struct spi_master *master = dev_get_drvdata(&ofdev->dev);
+ struct mpc83xx_spi *mpc83xx_spi = spi_master_get_devdata(master);
+ int i = master->num_chipselect;
flush_workqueue(mpc83xx_spi->workqueue);
destroy_workqueue(mpc83xx_spi->workqueue);
@@ -673,29 +747,38 @@ static int __exit mpc83xx_spi_remove(struct platform_device *dev)
free_irq(mpc83xx_spi->irq, mpc83xx_spi);
iounmap(mpc83xx_spi->base);
+ while (--i >= 0)
+ gpio_free(mpc83xx_spi->gpios[i]);
+
return 0;
}
-MODULE_ALIAS("platform:mpc83xx_spi");
-static struct platform_driver mpc83xx_spi_driver = {
- .remove = __exit_p(mpc83xx_spi_remove),
- .driver = {
- .name = "mpc83xx_spi",
- .owner = THIS_MODULE,
+static const struct of_device_id mpc83xx_spi_match[] = {
+ { .compatible = "fsl,spi", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, mpc83xx_spi_match);
+
+static struct of_platform_driver mpc83xx_spi_driver = {
+ .match_table = mpc83xx_spi_match,
+ .probe = mpc83xx_spi_probe,
+ .remove = __devexit_p(mpc83xx_spi_remove),
+ .driver = {
+ .name = "mpc83xx_spi",
+ .owner = THIS_MODULE,
},
};
static int __init mpc83xx_spi_init(void)
{
- return platform_driver_probe(&mpc83xx_spi_driver, mpc83xx_spi_probe);
+ return of_register_platform_driver(&mpc83xx_spi_driver);
}
+module_init(mpc83xx_spi_init);
static void __exit mpc83xx_spi_exit(void)
{
- platform_driver_unregister(&mpc83xx_spi_driver);
+ of_unregister_platform_driver(&mpc83xx_spi_driver);
}
-
-module_init(mpc83xx_spi_init);
module_exit(mpc83xx_spi_exit);
MODULE_AUTHOR("Kumar Gala");
--
1.5.5.1
More information about the Linuxppc-dev
mailing list