From: Anton Vorontsov <avorontsov@ru.mvista.com>
To: Grant Likely <grant.likely@secretlab.ca>
Cc: linuxppc-dev@ozlabs.org, Gary Jennejohn <garyj@denx.de>,
Guennadi Liakhovetski <g.liakhovetski@gmx.de>
Subject: [PATCH 1/4] [SPI] spi_mpc83xx: convert to the OF platform driver
Date: Wed, 21 May 2008 19:41:37 +0400 [thread overview]
Message-ID: <20080521154137.GA4566@polina.dev.rtsoft.ru> (raw)
In-Reply-To: <20080521154103.GA32577@polina.dev.rtsoft.ru>
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@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@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
next prev parent reply other threads:[~2008-05-21 15:41 UTC|newest]
Thread overview: 24+ messages / expand[flat|nested] mbox.gz Atom feed top
2008-05-21 15:41 [RFC/DRAFT] SPI OF bindings, MMC-over-SPI, chip-selects and so on Anton Vorontsov
2008-05-21 15:41 ` Anton Vorontsov [this message]
2008-05-21 16:50 ` [PATCH 1/4] [SPI] spi_mpc83xx: convert to the OF platform driver Grant Likely
2008-05-21 17:05 ` Anton Vorontsov
2008-05-21 17:17 ` Grant Likely
2008-05-21 15:41 ` [PATCH 2/4] [OF] spi_of: add support for dedicated SPI constructors Anton Vorontsov
2008-05-21 15:56 ` Guennadi Liakhovetski
2008-05-21 16:10 ` Anton Vorontsov
2008-05-21 16:24 ` Guennadi Liakhovetski
2008-05-21 16:48 ` Anton Vorontsov
2008-05-21 17:05 ` Grant Likely
2008-05-21 17:51 ` Guennadi Liakhovetski
2008-05-21 19:06 ` Grant Likely
2008-05-21 19:20 ` Guennadi Liakhovetski
2008-05-21 19:53 ` Grant Likely
2008-05-21 20:00 ` Guennadi Liakhovetski
2008-05-21 20:07 ` Grant Likely
2008-05-21 17:30 ` Grant Likely
2008-05-21 15:41 ` [PATCH 3/4] [OF] MMC-over-SPI OF constructor Anton Vorontsov
2008-05-21 15:41 ` [PATCH 4/4] [POWERPC] 86xx: mpc8610_hpcd: support for MMC-over-SPI and PIXIS' GPIOs Anton Vorontsov
2008-05-21 15:54 ` [RFC/DRAFT] SPI OF bindings, MMC-over-SPI, chip-selects and so on Guennadi Liakhovetski
2008-05-21 16:01 ` Anton Vorontsov
2008-05-21 16:51 ` Grant Likely
2008-05-21 17:32 ` Grant Likely
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20080521154137.GA4566@polina.dev.rtsoft.ru \
--to=avorontsov@ru.mvista.com \
--cc=g.liakhovetski@gmx.de \
--cc=garyj@denx.de \
--cc=grant.likely@secretlab.ca \
--cc=linuxppc-dev@ozlabs.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).