All of lore.kernel.org
 help / color / mirror / Atom feed
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

  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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.