summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/devicetree/bindings/spi/spi-bus.txt3
-rw-r--r--Documentation/devicetree/bindings/spi/spi-gpio.txt29
-rw-r--r--Documentation/devicetree/bindings/spi/spi-sc18is602.txt23
-rw-r--r--Documentation/devicetree/bindings/spi/spi_pl022.txt22
-rw-r--r--Documentation/spi/spi-sc18is60236
-rw-r--r--arch/arm/mach-u300/core.c3
-rw-r--r--drivers/spi/Kconfig6
-rw-r--r--drivers/spi/Makefile1
-rw-r--r--drivers/spi/spi-altera.c4
-rw-r--r--drivers/spi/spi-gpio.c131
-rw-r--r--drivers/spi/spi-mpc512x-psc.c3
-rw-r--r--drivers/spi/spi-mpc52xx-psc.c3
-rw-r--r--drivers/spi/spi-mpc52xx.c9
-rw-r--r--drivers/spi/spi-omap2-mcspi.c321
-rw-r--r--drivers/spi/spi-orion.c209
-rw-r--r--drivers/spi/spi-pl022.c196
-rw-r--r--drivers/spi/spi-s3c24xx.c1
-rw-r--r--drivers/spi/spi-s3c64xx.c11
-rw-r--r--drivers/spi/spi-sc18is602.c364
-rw-r--r--drivers/spi/spi-sh-hspi.c5
-rw-r--r--drivers/spi/spi-stmp.c6
-rw-r--r--drivers/spi/spi-tegra.c4
-rw-r--r--drivers/spi/spi-tle62x0.c13
-rw-r--r--drivers/spi/spi-topcliff-pch.c2
-rw-r--r--include/linux/amba/pl022.h2
-rw-r--r--include/linux/platform_data/sc18is602.h19
26 files changed, 1059 insertions, 367 deletions
diff --git a/Documentation/devicetree/bindings/spi/spi-bus.txt b/Documentation/devicetree/bindings/spi/spi-bus.txt
index e782add2e45..d2c33d0f533 100644
--- a/Documentation/devicetree/bindings/spi/spi-bus.txt
+++ b/Documentation/devicetree/bindings/spi/spi-bus.txt
@@ -21,6 +21,9 @@ assumption that board specific platform code will be used to manage
chip selects. Individual drivers can define additional properties to
support describing the chip select layout.
+Optional property:
+- num-cs : total number of chipselects
+
SPI slave nodes must be children of the SPI master node and can
contain the following properties.
- reg - (required) chip select address of device.
diff --git a/Documentation/devicetree/bindings/spi/spi-gpio.txt b/Documentation/devicetree/bindings/spi/spi-gpio.txt
new file mode 100644
index 00000000000..8a824be1575
--- /dev/null
+++ b/Documentation/devicetree/bindings/spi/spi-gpio.txt
@@ -0,0 +1,29 @@
+SPI-GPIO devicetree bindings
+
+Required properties:
+
+ - compatible: should be set to "spi-gpio"
+ - #address-cells: should be set to <0x1>
+ - ranges
+ - gpio-sck: GPIO spec for the SCK line to use
+ - gpio-miso: GPIO spec for the MISO line to use
+ - gpio-mosi: GPIO spec for the MOSI line to use
+ - cs-gpios: GPIOs to use for chipselect lines
+ - num-chipselects: number of chipselect lines
+
+Example:
+
+ spi {
+ compatible = "spi-gpio";
+ #address-cells = <0x1>;
+ ranges;
+
+ gpio-sck = <&gpio 95 0>;
+ gpio-miso = <&gpio 98 0>;
+ gpio-mosi = <&gpio 97 0>;
+ cs-gpios = <&gpio 125 0>;
+ num-chipselects = <1>;
+
+ /* clients */
+ };
+
diff --git a/Documentation/devicetree/bindings/spi/spi-sc18is602.txt b/Documentation/devicetree/bindings/spi/spi-sc18is602.txt
new file mode 100644
index 00000000000..02f9033270a
--- /dev/null
+++ b/Documentation/devicetree/bindings/spi/spi-sc18is602.txt
@@ -0,0 +1,23 @@
+NXP SC18IS602/SCIS603
+
+Required properties:
+ - compatible : Should be one of
+ "nxp,sc18is602"
+ "nxp,sc18is602b"
+ "nxp,sc18is603"
+ - reg: I2C bus address
+
+Optional properties:
+ - clock-frequency : external oscillator clock frequency. If not
+ specified, the SC18IS602 default frequency (7372000) will be used.
+
+The clock-frequency property is relevant and needed only if the chip has an
+external oscillator (SC18IS603).
+
+Example:
+
+ sc18is603@28 {
+ compatible = "nxp,sc18is603";
+ reg = <0x28>;
+ clock-frequency = <14744000>;
+ }
diff --git a/Documentation/devicetree/bindings/spi/spi_pl022.txt b/Documentation/devicetree/bindings/spi/spi_pl022.txt
index 306ec3ff3c0..f158fd31cfd 100644
--- a/Documentation/devicetree/bindings/spi/spi_pl022.txt
+++ b/Documentation/devicetree/bindings/spi/spi_pl022.txt
@@ -6,7 +6,29 @@ Required properties:
- interrupts : Should contain SPI controller interrupt
Optional properties:
+- num-cs : total number of chipselects
- cs-gpios : should specify GPIOs used for chipselects.
The gpios will be referred to as reg = <index> in the SPI child nodes.
If unspecified, a single SPI device without a chip select can be used.
+- pl022,autosuspend-delay : delay in ms following transfer completion before
+ the runtime power management system suspends the
+ device. A setting of 0 indicates no delay and the
+ device will be suspended immediately
+- pl022,rt : indicates the controller should run the message pump with realtime
+ priority to minimise the transfer latency on the bus (boolean)
+
+
+SPI slave nodes must be children of the SPI master node and can
+contain the following properties.
+
+- pl022,interface : interface type:
+ 0: SPI
+ 1: Texas Instruments Synchronous Serial Frame Format
+ 2: Microwire (Half Duplex)
+- pl022,com-mode : polling, interrupt or dma
+- pl022,rx-level-trig : Rx FIFO watermark level
+- pl022,tx-level-trig : Tx FIFO watermark level
+- pl022,ctrl-len : Microwire interface: Control length
+- pl022,wait-state : Microwire interface: Wait state
+- pl022,duplex : Microwire interface: Full/Half duplex
diff --git a/Documentation/spi/spi-sc18is602 b/Documentation/spi/spi-sc18is602
new file mode 100644
index 00000000000..a45702865a3
--- /dev/null
+++ b/Documentation/spi/spi-sc18is602
@@ -0,0 +1,36 @@
+Kernel driver spi-sc18is602
+===========================
+
+Supported chips:
+ * NXP SI18IS602/602B/603
+ Datasheet: http://www.nxp.com/documents/data_sheet/SC18IS602_602B_603.pdf
+
+Author:
+ Guenter Roeck <linux@roeck-us.net>
+
+
+Description
+-----------
+
+This driver provides connects a NXP SC18IS602/603 I2C-bus to SPI bridge to the
+kernel's SPI core subsystem.
+
+The driver does not probe for supported chips, since the SI18IS602/603 does not
+support Chip ID registers. You will have to instantiate the devices explicitly.
+Please see Documentation/i2c/instantiating-devices for details.
+
+
+Usage Notes
+-----------
+
+This driver requires the I2C adapter driver to support raw I2C messages. I2C
+adapter drivers which can only handle the SMBus protocol are not supported.
+
+The maximum SPI message size supported by SC18IS602/603 is 200 bytes. Attempts
+to initiate longer transfers will fail with -EINVAL. EEPROM read operations and
+similar large accesses have to be split into multiple chunks of no more than
+200 bytes per SPI message (128 bytes of data per message is recommended). This
+means that programs such as "cp" or "od", which automatically use large block
+sizes to access a device, can not be used directly to read data from EEPROM.
+Programs such as dd, where the block size can be specified, should be used
+instead.
diff --git a/arch/arm/mach-u300/core.c b/arch/arm/mach-u300/core.c
index 03acf1883ec..281292ebac2 100644
--- a/arch/arm/mach-u300/core.c
+++ b/arch/arm/mach-u300/core.c
@@ -1605,9 +1605,6 @@ static struct u300_mux_hog u300_mux_hogs[] = {
.dev = &uart0_device.dev,
},
{
- .dev = &pl022_device.dev,
- },
- {
.dev = &mmcsd_device.dev,
},
};
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index 5f84b5563c2..920bb4d22d4 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -325,6 +325,12 @@ config SPI_S3C64XX
help
SPI driver for Samsung S3C64XX and newer SoCs.
+config SPI_SC18IS602
+ tristate "NXP SC18IS602/602B/603 I2C to SPI bridge"
+ depends on I2C
+ help
+ SPI driver for NXP SC18IS602/602B/603 I2C to SPI bridge.
+
config SPI_SH_MSIOF
tristate "SuperH MSIOF SPI controller"
depends on SUPERH && HAVE_CLK
diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
index 3920dcf4c74..7559c984db7 100644
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
@@ -51,6 +51,7 @@ obj-$(CONFIG_SPI_S3C24XX) += spi-s3c24xx-hw.o
spi-s3c24xx-hw-y := spi-s3c24xx.o
spi-s3c24xx-hw-$(CONFIG_SPI_S3C24XX_FIQ) += spi-s3c24xx-fiq.o
obj-$(CONFIG_SPI_S3C64XX) += spi-s3c64xx.o
+obj-$(CONFIG_SPI_SC18IS602) += spi-sc18is602.o
obj-$(CONFIG_SPI_SH) += spi-sh.o
obj-$(CONFIG_SPI_SH_HSPI) += spi-sh-hspi.o
obj-$(CONFIG_SPI_SH_MSIOF) += spi-sh-msiof.o
diff --git a/drivers/spi/spi-altera.c b/drivers/spi/spi-altera.c
index c00d00e96ee..f1fec2a19d1 100644
--- a/drivers/spi/spi-altera.c
+++ b/drivers/spi/spi-altera.c
@@ -307,8 +307,6 @@ static const struct of_device_id altera_spi_match[] = {
{},
};
MODULE_DEVICE_TABLE(of, altera_spi_match);
-#else /* CONFIG_OF */
-#define altera_spi_match NULL
#endif /* CONFIG_OF */
static struct platform_driver altera_spi_driver = {
@@ -318,7 +316,7 @@ static struct platform_driver altera_spi_driver = {
.name = DRV_NAME,
.owner = THIS_MODULE,
.pm = NULL,
- .of_match_table = altera_spi_match,
+ .of_match_table = of_match_ptr(altera_spi_match),
},
};
module_platform_driver(altera_spi_driver);
diff --git a/drivers/spi/spi-gpio.c b/drivers/spi/spi-gpio.c
index 0b56cfc71fa..a2b50c516b3 100644
--- a/drivers/spi/spi-gpio.c
+++ b/drivers/spi/spi-gpio.c
@@ -22,6 +22,8 @@
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/gpio.h>
+#include <linux/of_device.h>
+#include <linux/of_gpio.h>
#include <linux/spi/spi.h>
#include <linux/spi/spi_bitbang.h>
@@ -46,6 +48,7 @@ struct spi_gpio {
struct spi_bitbang bitbang;
struct spi_gpio_platform_data pdata;
struct platform_device *pdev;
+ int cs_gpios[0];
};
/*----------------------------------------------------------------------*/
@@ -89,15 +92,21 @@ struct spi_gpio {
/*----------------------------------------------------------------------*/
-static inline const struct spi_gpio_platform_data * __pure
-spi_to_pdata(const struct spi_device *spi)
+static inline struct spi_gpio * __pure
+spi_to_spi_gpio(const struct spi_device *spi)
{
const struct spi_bitbang *bang;
- const struct spi_gpio *spi_gpio;
+ struct spi_gpio *spi_gpio;
bang = spi_master_get_devdata(spi->master);
spi_gpio = container_of(bang, struct spi_gpio, bitbang);
- return &spi_gpio->pdata;
+ return spi_gpio;
+}
+
+static inline struct spi_gpio_platform_data * __pure
+spi_to_pdata(const struct spi_device *spi)
+{
+ return &spi_to_spi_gpio(spi)->pdata;
}
/* this is #defined to avoid unused-variable warnings when inlining */
@@ -210,7 +219,8 @@ static u32 spi_gpio_spec_txrx_word_mode3(struct spi_device *spi,
static void spi_gpio_chipselect(struct spi_device *spi, int is_active)
{
- unsigned long cs = (unsigned long) spi->controller_data;
+ struct spi_gpio *spi_gpio = spi_to_spi_gpio(spi);
+ unsigned int cs = spi_gpio->cs_gpios[spi->chip_select];
/* set initial clock polarity */
if (is_active)
@@ -224,12 +234,27 @@ static void spi_gpio_chipselect(struct spi_device *spi, int is_active)
static int spi_gpio_setup(struct spi_device *spi)
{
- unsigned long cs = (unsigned long) spi->controller_data;
- int status = 0;
+ unsigned int cs;
+ int status = 0;
+ struct spi_gpio *spi_gpio = spi_to_spi_gpio(spi);
+ struct device_node *np = spi->master->dev.of_node;
if (spi->bits_per_word > 32)
return -EINVAL;
+ if (np) {
+ /*
+ * In DT environments, the CS GPIOs have already been
+ * initialized from the "cs-gpios" property of the node.
+ */
+ cs = spi_gpio->cs_gpios[spi->chip_select];
+ } else {
+ /*
+ * ... otherwise, take it from spi->controller_data
+ */
+ cs = (unsigned int) spi->controller_data;
+ }
+
if (!spi->controller_state) {
if (cs != SPI_GPIO_NO_CHIPSELECT) {
status = gpio_request(cs, dev_name(&spi->dev));
@@ -239,8 +264,12 @@ static int spi_gpio_setup(struct spi_device *spi)
!(spi->mode & SPI_CS_HIGH));
}
}
- if (!status)
+ if (!status) {
status = spi_bitbang_setup(spi);
+ /* in case it was initialized from static board data */
+ spi_gpio->cs_gpios[spi->chip_select] = cs;
+ }
+
if (status) {
if (!spi->controller_state && cs != SPI_GPIO_NO_CHIPSELECT)
gpio_free(cs);
@@ -250,7 +279,8 @@ static int spi_gpio_setup(struct spi_device *spi)
static void spi_gpio_cleanup(struct spi_device *spi)
{
- unsigned long cs = (unsigned long) spi->controller_data;
+ struct spi_gpio *spi_gpio = spi_to_spi_gpio(spi);
+ unsigned int cs = spi_gpio->cs_gpios[spi->chip_select];
if (cs != SPI_GPIO_NO_CHIPSELECT)
gpio_free(cs);
@@ -313,6 +343,55 @@ done:
return value;
}
+#ifdef CONFIG_OF
+static struct of_device_id spi_gpio_dt_ids[] = {
+ { .compatible = "spi-gpio" },
+ {}
+};
+MODULE_DEVICE_TABLE(of, spi_gpio_dt_ids);
+
+static int spi_gpio_probe_dt(struct platform_device *pdev)
+{
+ int ret;
+ u32 tmp;
+ struct spi_gpio_platform_data *pdata;
+ struct device_node *np = pdev->dev.of_node;
+ const struct of_device_id *of_id =
+ of_match_device(spi_gpio_dt_ids, &pdev->dev);
+
+ if (!of_id)
+ return 0;
+
+ pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
+ if (!pdata)
+ return -ENOMEM;
+
+ pdata->sck = of_get_named_gpio(np, "gpio-sck", 0);
+ pdata->miso = of_get_named_gpio(np, "gpio-miso", 0);
+ pdata->mosi = of_get_named_gpio(np, "gpio-mosi", 0);
+
+ ret = of_property_read_u32(np, "num-chipselects", &tmp);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "num-chipselects property not found\n");
+ goto error_free;
+ }
+
+ pdata->num_chipselect = tmp;
+ pdev->dev.platform_data = pdata;
+
+ return 1;
+
+error_free:
+ devm_kfree(&pdev->dev, pdata);
+ return ret;
+}
+#else
+static inline int spi_gpio_probe_dt(struct platform_device *pdev)
+{
+ return 0;
+}
+#endif
+
static int __devinit spi_gpio_probe(struct platform_device *pdev)
{
int status;
@@ -320,6 +399,13 @@ static int __devinit spi_gpio_probe(struct platform_device *pdev)
struct spi_gpio *spi_gpio;
struct spi_gpio_platform_data *pdata;
u16 master_flags = 0;
+ bool use_of = 0;
+
+ status = spi_gpio_probe_dt(pdev);
+ if (status < 0)
+ return status;
+ if (status > 0)
+ use_of = 1;
pdata = pdev->dev.platform_data;
#ifdef GENERIC_BITBANG
@@ -331,7 +417,8 @@ static int __devinit spi_gpio_probe(struct platform_device *pdev)
if (status < 0)
return status;
- master = spi_alloc_master(&pdev->dev, sizeof *spi_gpio);
+ master = spi_alloc_master(&pdev->dev, sizeof(*spi_gpio) +
+ (sizeof(int) * SPI_N_CHIPSEL));
if (!master) {
status = -ENOMEM;
goto gpio_free;
@@ -348,6 +435,23 @@ static int __devinit spi_gpio_probe(struct platform_device *pdev)
master->num_chipselect = SPI_N_CHIPSEL;
master->setup = spi_gpio_setup;
master->cleanup = spi_gpio_cleanup;
+#ifdef CONFIG_OF
+ master->dev.of_node = pdev->dev.of_node;
+
+ if (use_of) {
+ int i;
+ struct device_node *np = pdev->dev.of_node;
+
+ /*
+ * In DT environments, take the CS GPIO from the "cs-gpios"
+ * property of the node.
+ */
+
+ for (i = 0; i < SPI_N_CHIPSEL; i++)
+ spi_gpio->cs_gpios[i] =
+ of_get_named_gpio(np, "cs-gpios", i);
+ }
+#endif
spi_gpio->bitbang.master = spi_master_get(master);
spi_gpio->bitbang.chipselect = spi_gpio_chipselect;
@@ -408,8 +512,11 @@ static int __devexit spi_gpio_remove(struct platform_device *pdev)
MODULE_ALIAS("platform:" DRIVER_NAME);
static struct platform_driver spi_gpio_driver = {
- .driver.name = DRIVER_NAME,
- .driver.owner = THIS_MODULE,
+ .driver = {
+ .name = DRIVER_NAME,
+ .owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(spi_gpio_dt_ids),
+ },
.probe = spi_gpio_probe,
.remove = __devexit_p(spi_gpio_remove),
};
diff --git a/drivers/spi/spi-mpc512x-psc.c b/drivers/spi/spi-mpc512x-psc.c
index 4c63f772780..0a1e39e94d0 100644
--- a/drivers/spi/spi-mpc512x-psc.c
+++ b/drivers/spi/spi-mpc512x-psc.c
@@ -494,7 +494,7 @@ free_master:
static int __devexit mpc512x_psc_spi_do_remove(struct device *dev)
{
- struct spi_master *master = dev_get_drvdata(dev);
+ struct spi_master *master = spi_master_get(dev_get_drvdata(dev));
struct mpc512x_psc_spi *mps = spi_master_get_devdata(master);
flush_workqueue(mps->workqueue);
@@ -503,6 +503,7 @@ static int __devexit mpc512x_psc_spi_do_remove(struct device *dev)
free_irq(mps->irq, mps);
if (mps->psc)
iounmap(mps->psc);
+ spi_master_put(master);
return 0;
}
diff --git a/drivers/spi/spi-mpc52xx-psc.c b/drivers/spi/spi-mpc52xx-psc.c
index 66047156d90..bd47d262d53 100644
--- a/drivers/spi/spi-mpc52xx-psc.c
+++ b/drivers/spi/spi-mpc52xx-psc.c
@@ -481,7 +481,7 @@ static int __devinit mpc52xx_psc_spi_of_probe(struct platform_device *op)
static int __devexit mpc52xx_psc_spi_of_remove(struct platform_device *op)
{
- struct spi_master *master = dev_get_drvdata(&op->dev);
+ struct spi_master *master = spi_master_get(dev_get_drvdata(&op->dev));
struct mpc52xx_psc_spi *mps = spi_master_get_devdata(master);
flush_workqueue(mps->workqueue);
@@ -490,6 +490,7 @@ static int __devexit mpc52xx_psc_spi_of_remove(struct platform_device *op)
free_irq(mps->irq, mps);
if (mps->psc)
iounmap(mps->psc);
+ spi_master_put(master);
return 0;
}
diff --git a/drivers/spi/spi-mpc52xx.c b/drivers/spi/spi-mpc52xx.c
index cb3a3830b0a..04541065021 100644
--- a/drivers/spi/spi-mpc52xx.c
+++ b/drivers/spi/spi-mpc52xx.c
@@ -454,7 +454,7 @@ static int __devinit mpc52xx_spi_probe(struct platform_device *op)
GFP_KERNEL);
if (!ms->gpio_cs) {
rc = -ENOMEM;
- goto err_alloc;
+ goto err_alloc_gpio;
}
for (i = 0; i < ms->gpio_cs_count; i++) {
@@ -514,12 +514,13 @@ static int __devinit mpc52xx_spi_probe(struct platform_device *op)
err_register:
dev_err(&ms->master->dev, "initialization failed\n");
- spi_master_put(master);
err_gpio:
while (i-- > 0)
gpio_free(ms->gpio_cs[i]);
kfree(ms->gpio_cs);
+ err_alloc_gpio:
+ spi_master_put(master);
err_alloc:
err_init:
iounmap(regs);
@@ -528,7 +529,7 @@ static int __devinit mpc52xx_spi_probe(struct platform_device *op)
static int __devexit mpc52xx_spi_remove(struct platform_device *op)
{
- struct spi_master *master = dev_get_drvdata(&op->dev);
+ struct spi_master *master = spi_master_get(dev_get_drvdata(&op->dev));
struct mpc52xx_spi *ms = spi_master_get_devdata(master);
int i;
@@ -540,8 +541,8 @@ static int __devexit mpc52xx_spi_remove(struct platform_device *op)
kfree(ms->gpio_cs);
spi_unregister_master(master);
- spi_master_put(master);
iounmap(ms->regs);
+ spi_master_put(master);
return 0;
}
diff --git a/drivers/spi/spi-omap2-mcspi.c b/drivers/spi/spi-omap2-mcspi.c
index b2fb141da37..06684d995d3 100644
--- a/drivers/spi/spi-omap2-mcspi.c
+++ b/drivers/spi/spi-omap2-mcspi.c
@@ -38,6 +38,8 @@
#include <linux/pm_runtime.h>
#include <linux/of.h>
#include <linux/of_device.h>
+#include <linux/pinctrl/consumer.h>
+#include <linux/err.h>
#include <linux/spi/spi.h>
@@ -140,13 +142,6 @@ struct omap2_mcspi_cs {
u32 chconf0;
};
-#define MOD_REG_BIT(val, mask, set) do { \
- if (set) \
- val |= mask; \
- else \
- val &= ~mask; \
-} while (0)
-
static inline void mcspi_write_reg(struct spi_master *master,
int idx, u32 val)
{
@@ -205,7 +200,11 @@ static void omap2_mcspi_set_dma_req(const struct spi_device *spi,
else
rw = OMAP2_MCSPI_CHCONF_DMAW;
- MOD_REG_BIT(l, rw, enable);
+ if (enable)
+ l |= rw;
+ else
+ l &= ~rw;
+
mcspi_write_chconf0(spi, l);
}
@@ -224,7 +223,11 @@ static void omap2_mcspi_force_cs(struct spi_device *spi, int cs_active)
u32 l;
l = mcspi_cached_chconf0(spi);
- MOD_REG_BIT(l, OMAP2_MCSPI_CHCONF_FORCE, cs_active);
+ if (cs_active)
+ l |= OMAP2_MCSPI_CHCONF_FORCE;
+ else
+ l &= ~OMAP2_MCSPI_CHCONF_FORCE;
+
mcspi_write_chconf0(spi, l);
}
@@ -239,9 +242,8 @@ static void omap2_mcspi_set_master_mode(struct spi_master *master)
* to single-channel master mode
*/
l = mcspi_read_reg(master, OMAP2_MCSPI_MODULCTRL);
- MOD_REG_BIT(l, OMAP2_MCSPI_MODULCTRL_STEST, 0);
- MOD_REG_BIT(l, OMAP2_MCSPI_MODULCTRL_MS, 0);
- MOD_REG_BIT(l, OMAP2_MCSPI_MODULCTRL_SINGLE, 1);
+ l &= ~(OMAP2_MCSPI_MODULCTRL_STEST | OMAP2_MCSPI_MODULCTRL_MS);
+ l |= OMAP2_MCSPI_MODULCTRL_SINGLE;
mcspi_write_reg(master, OMAP2_MCSPI_MODULCTRL, l);
ctx->modulctrl = l;
@@ -260,16 +262,6 @@ static void omap2_mcspi_restore_ctx(struct omap2_mcspi *mcspi)
list_for_each_entry(cs, &ctx->cs, node)
__raw_writel(cs->chconf0, cs->base + OMAP2_MCSPI_CHCONF0);
}
-static void omap2_mcspi_disable_clocks(struct omap2_mcspi *mcspi)
-{
- pm_runtime_mark_last_busy(mcspi->dev);
- pm_runtime_put_autosuspend(mcspi->dev);
-}
-
-static int omap2_mcspi_enable_clocks(struct omap2_mcspi *mcspi)
-{
- return pm_runtime_get_sync(mcspi->dev);
-}
static int omap2_prepare_transfer(struct spi_master *master)
{
@@ -325,49 +317,27 @@ static void omap2_mcspi_tx_callback(void *data)
omap2_mcspi_set_dma_req(spi, 0, 0);
}
-static unsigned
-omap2_mcspi_txrx_dma(struct spi_device *spi, struct spi_transfer *xfer)
+static void omap2_mcspi_tx_dma(struct spi_device *spi,
+ struct spi_transfer *xfer,
+ struct dma_slave_config cfg)
{
struct omap2_mcspi *mcspi;
- struct omap2_mcspi_cs *cs = spi->controller_state;
struct omap2_mcspi_dma *mcspi_dma;
unsigned int count;
- int word_len, element_count;
- int elements = 0;
- u32 l;
u8 * rx;
const u8 * tx;
void __iomem *chstat_reg;
- struct dma_slave_config cfg;
- enum dma_slave_buswidth width;
- unsigned es;
+ struct omap2_mcspi_cs *cs = spi->controller_state;
mcspi = spi_master_get_devdata(spi->master);
mcspi_dma = &mcspi->dma_channels[spi->chip_select];
- l = mcspi_cached_chconf0(spi);
+ count = xfer->len;
+ rx = xfer->rx_buf;
+ tx = xfer->tx_buf;
chstat_reg = cs->base + OMAP2_MCSPI_CHSTAT0;
- if (cs->word_len <= 8) {
- width = DMA_SLAVE_BUSWIDTH_1_BYTE;
- es = 1;
- } else if (cs->word_len <= 16) {
- width = DMA_SLAVE_BUSWIDTH_2_BYTES;
- es = 2;
- } else {
- width = DMA_SLAVE_BUSWIDTH_4_BYTES;
- es = 4;
- }
-
- memset(&cfg, 0, sizeof(cfg));
- cfg.src_addr = cs->phys + OMAP2_MCSPI_RX0;
- cfg.dst_addr = cs->phys + OMAP2_MCSPI_TX0;
- cfg.src_addr_width = width;
- cfg.dst_addr_width = width;
- cfg.src_maxburst = 1;
- cfg.dst_maxburst = 1;
-
- if (xfer->tx_buf && mcspi_dma->dma_tx) {
+ if (mcspi_dma->dma_tx) {
struct dma_async_tx_descriptor *tx;
struct scatterlist sg;
@@ -378,7 +348,7 @@ omap2_mcspi_txrx_dma(struct spi_device *spi, struct spi_transfer *xfer)
sg_dma_len(&sg) = xfer->len;
tx = dmaengine_prep_slave_sg(mcspi_dma->dma_tx, &sg, 1,
- DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+ DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
if (tx) {
tx->callback = omap2_mcspi_tx_callback;
tx->callback_param = spi;
@@ -387,8 +357,50 @@ omap2_mcspi_txrx_dma(struct spi_device *spi, struct spi_transfer *xfer)
/* FIXME: fall back to PIO? */
}
}
+ dma_async_issue_pending(mcspi_dma->dma_tx);
+ omap2_mcspi_set_dma_req(spi, 0, 1);
+
+ wait_for_completion(&mcspi_dma->dma_tx_completion);
+ dma_unmap_single(mcspi->dev, xfer->tx_dma, count,
+ DMA_TO_DEVICE);
+
+ /* for TX_ONLY mode, be sure all words have shifted out */
+ if (rx == NULL) {
+ if (mcspi_wait_for_reg_bit(chstat_reg,
+ OMAP2_MCSPI_CHSTAT_TXS) < 0)
+ dev_err(&spi->dev, "TXS timed out\n");
+ else if (mcspi_wait_for_reg_bit(chstat_reg,
+ OMAP2_MCSPI_CHSTAT_EOT) < 0)
+ dev_err(&spi->dev, "EOT timed out\n");
+ }
+}
+
+static unsigned
+omap2_mcspi_rx_dma(struct spi_device *spi, struct spi_transfer *xfer,
+ struct dma_slave_config cfg,
+ unsigned es)
+{
+ struct omap2_mcspi *mcspi;
+ struct omap2_mcspi_dma *mcspi_dma;
+ unsigned int count;
+ u32 l;
+ int elements = 0;
+ int word_len, element_count;
+ struct omap2_mcspi_cs *cs = spi->controller_state;
+ mcspi = spi_master_get_devdata(spi->master);
+ mcspi_dma = &mcspi->dma_channels[spi->chip_select];
+ count = xfer->len;
+ word_len = cs->word_len;
+ l = mcspi_cached_chconf0(spi);
- if (xfer->rx_buf && mcspi_dma->dma_rx) {
+ if (word_len <= 8)
+ element_count = count;
+ else if (word_len <= 16)
+ element_count = count >> 1;
+ else /* word_len <= 32 */
+ element_count = count >> 2;
+
+ if (mcspi_dma->dma_rx) {
struct dma_async_tx_descriptor *tx;
struct scatterlist sg;
size_t len = xfer->len - es;
@@ -403,108 +415,120 @@ omap2_mcspi_txrx_dma(struct spi_device *spi, struct spi_transfer *xfer)
sg_dma_len(&sg) = len;
tx = dmaengine_prep_slave_sg(mcspi_dma->dma_rx, &sg, 1,
- DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+ DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT |
+ DMA_CTRL_ACK);
if (tx) {
tx->callback = omap2_mcspi_rx_callback;
tx->callback_param = spi;
dmaengine_submit(tx);
} else {
- /* FIXME: fall back to PIO? */
- }
- }
-
- count = xfer->len;
- word_len = cs->word_len;
-
- rx = xfer->rx_buf;
- tx = xfer->tx_buf;
-
- if (word_len <= 8) {
- element_count = count;
- } else if (word_len <= 16) {
- element_count = count >> 1;
- } else /* word_len <= 32 */ {
- element_count = count >> 2;
- }
-
- if (tx != NULL) {
- dma_async_issue_pending(mcspi_dma->dma_tx);
- omap2_mcspi_set_dma_req(spi, 0, 1);
- }
-
- if (rx != NULL) {
- dma_async_issue_pending(mcspi_dma->dma_rx);
- omap2_mcspi_set_dma_req(spi, 1, 1);
- }
-
- if (tx != NULL) {
- wait_for_completion(&mcspi_dma->dma_tx_completion);
- dma_unmap_single(mcspi->dev, xfer->tx_dma, count,
- DMA_TO_DEVICE);
-
- /* for TX_ONLY mode, be sure all words have shifted out */
- if (rx == NULL) {
- if (mcspi_wait_for_reg_bit(chstat_reg,
- OMAP2_MCSPI_CHSTAT_TXS) < 0)
- dev_err(&spi->dev, "TXS timed out\n");
- else if (mcspi_wait_for_reg_bit(chstat_reg,
- OMAP2_MCSPI_CHSTAT_EOT) < 0)
- dev_err(&spi->dev, "EOT timed out\n");
+ /* FIXME: fall back to PIO? */
}
}
- if (rx != NULL) {
- wait_for_completion(&mcspi_dma->dma_rx_completion);
- dma_unmap_single(mcspi->dev, xfer->rx_dma, count,
- DMA_FROM_DEVICE);
- omap2_mcspi_set_enable(spi, 0);
+ dma_async_issue_pending(mcspi_dma->dma_rx);
+ omap2_mcspi_set_dma_req(spi, 1, 1);
- elements = element_count - 1;
+ wait_for_completion(&mcspi_dma->dma_rx_completion);
+ dma_unmap_single(mcspi->dev, xfer->rx_dma, count,
+ DMA_FROM_DEVICE);
+ omap2_mcspi_set_enable(spi, 0);
- if (l & OMAP2_MCSPI_CHCONF_TURBO) {
- elements--;
+ elements = element_count - 1;
- if (likely(mcspi_read_cs_reg(spi, OMAP2_MCSPI_CHSTAT0)
- & OMAP2_MCSPI_CHSTAT_RXS)) {
- u32 w;
-
- w = mcspi_read_cs_reg(spi, OMAP2_MCSPI_RX0);
- if (word_len <= 8)
- ((u8 *)xfer->rx_buf)[elements++] = w;
- else if (word_len <= 16)
- ((u16 *)xfer->rx_buf)[elements++] = w;
- else /* word_len <= 32 */
- ((u32 *)xfer->rx_buf)[elements++] = w;
- } else {
- dev_err(&spi->dev,
- "DMA RX penultimate word empty");
- count -= (word_len <= 8) ? 2 :
- (word_len <= 16) ? 4 :
- /* word_len <= 32 */ 8;
- omap2_mcspi_set_enable(spi, 1);
- return count;
- }
- }
+ if (l & OMAP2_MCSPI_CHCONF_TURBO) {
+ elements--;
if (likely(mcspi_read_cs_reg(spi, OMAP2_MCSPI_CHSTAT0)
- & OMAP2_MCSPI_CHSTAT_RXS)) {
+ & OMAP2_MCSPI_CHSTAT_RXS)) {
u32 w;
w = mcspi_read_cs_reg(spi, OMAP2_MCSPI_RX0);
if (word_len <= 8)
- ((u8 *)xfer->rx_buf)[elements] = w;
+ ((u8 *)xfer->rx_buf)[elements++] = w;
else if (word_len <= 16)
- ((u16 *)xfer->rx_buf)[elements] = w;
+ ((u16 *)xfer->rx_buf)[elements++] = w;
else /* word_len <= 32 */
- ((u32 *)xfer->rx_buf)[elements] = w;
+ ((u32 *)xfer->rx_buf)[elements++] = w;
} else {
- dev_err(&spi->dev, "DMA RX last word empty");
- count -= (word_len <= 8) ? 1 :
- (word_len <= 16) ? 2 :
- /* word_len <= 32 */ 4;
+ dev_err(&spi->dev, "DMA RX penultimate word empty");
+ count -= (word_len <= 8) ? 2 :
+ (word_len <= 16) ? 4 :
+ /* word_len <= 32 */ 8;
+ omap2_mcspi_set_enable(spi, 1);
+ return count;
}
- omap2_mcspi_set_enable(spi, 1);
}
+ if (likely(mcspi_read_cs_reg(spi, OMAP2_MCSPI_CHSTAT0)
+ & OMAP2_MCSPI_CHSTAT_RXS)) {
+ u32 w;
+
+ w = mcspi_read_cs_reg(spi, OMAP2_MCSPI_RX0);
+ if (word_len <= 8)
+ ((u8 *)xfer->rx_buf)[elements] = w;
+ else if (word_len <= 16)
+ ((u16 *)xfer->rx_buf)[elements] = w;
+ else /* word_len <= 32 */
+ ((u32 *)xfer->rx_buf)[elements] = w;
+ } else {
+ dev_err(&spi->dev, "DMA RX last word empty");
+ count -= (word_len <= 8) ? 1 :
+ (word_len <= 16) ? 2 :
+ /* word_len <= 32 */ 4;
+ }
+ omap2_mcspi_set_enable(spi, 1);
+ return count;
+}
+
+static unsigned
+omap2_mcspi_txrx_dma(struct spi_device *spi, struct spi_transfer *xfer)
+{
+ struct omap2_mcspi *mcspi;
+ struct omap2_mcspi_cs *cs = spi->controller_state;
+ struct omap2_mcspi_dma *mcspi_dma;
+ unsigned int count;
+ u32 l;
+ u8 *rx;
+ const u8 *tx;
+ struct dma_slave_config cfg;
+ enum dma_slave_buswidth width;
+ unsigned es;
+
+ mcspi = spi_master_get_devdata(spi->master);
+ mcspi_dma = &mcspi->dma_channels[spi->chip_select];
+ l = mcspi_cached_chconf0(spi);
+
+
+ if (cs->word_len <= 8) {
+ width = DMA_SLAVE_BUSWIDTH_1_BYTE;
+ es = 1;
+ } else if (cs->word_len <= 16) {
+ width = DMA_SLAVE_BUSWIDTH_2_BYTES;
+ es = 2;
+ } else {
+ width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+ es = 4;
+ }
+
+ memset(&cfg, 0, sizeof(cfg));
+ cfg.src_addr = cs->phys + OMAP2_MCSPI_RX0;
+ cfg.dst_addr = cs->phys + OMAP2_MCSPI_TX0;
+ cfg.src_addr_width = width;
+ cfg.dst_addr_width = width;
+ cfg.src_maxburst = 1;
+ cfg.dst_maxburst = 1;
+
+ rx = xfer->rx_buf;
+ tx = xfer->tx_buf;
+
+ count = xfer->len;
+
+ if (tx != NULL)
+ omap2_mcspi_tx_dma(spi, xfer, cfg);
+
+ if (rx != NULL)
+ return omap2_mcspi_rx_dma(spi, xfer, cfg, es);
+
return count;
}
@@ -848,12 +872,13 @@ static int omap2_mcspi_setup(struct spi_device *spi)
return ret;
}
- ret = omap2_mcspi_enable_clocks(mcspi);
+ ret = pm_runtime_get_sync(mcspi->dev);
if (ret < 0)
return ret;
ret = omap2_mcspi_setup_transfer(spi, NULL);
- omap2_mcspi_disable_clocks(mcspi);
+ pm_runtime_mark_last_busy(mcspi->dev);
+ pm_runtime_put_autosuspend(mcspi->dev);
return ret;
}
@@ -1067,7 +1092,7 @@ static int __devinit omap2_mcspi_master_setup(struct omap2_mcspi *mcspi)
struct omap2_mcspi_regs *ctx = &mcspi->ctx;
int ret = 0;
- ret = omap2_mcspi_enable_clocks(mcspi);
+ ret = pm_runtime_get_sync(mcspi->dev);
if (ret < 0)
return ret;
@@ -1076,7 +1101,8 @@ static int __devinit omap2_mcspi_master_setup(struct omap2_mcspi *mcspi)
ctx->wakeupenable = OMAP2_MCSPI_WAKEUPENABLE_WKEN;
omap2_mcspi_set_master_mode(master);
- omap2_mcspi_disable_clocks(mcspi);
+ pm_runtime_mark_last_busy(mcspi->dev);
+ pm_runtime_put_autosuspend(mcspi->dev);
return 0;
}
@@ -1124,6 +1150,7 @@ static int __devinit omap2_mcspi_probe(struct platform_device *pdev)
static int bus_num = 1;
struct device_node *node = pdev->dev.of_node;
const struct of_device_id *match;
+ struct pinctrl *pinctrl;
master = spi_alloc_master(&pdev->dev, sizeof *mcspi);
if (master == NULL) {
@@ -1219,6 +1246,11 @@ static int __devinit omap2_mcspi_probe(struct platform_device *pdev)
if (status < 0)
goto dma_chnl_free;
+ pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
+ if (IS_ERR(pinctrl))
+ dev_warn(&pdev->dev,
+ "pins are not configured from the driver\n");
+
pm_runtime_use_autosuspend(&pdev->dev);
pm_runtime_set_autosuspend_delay(&pdev->dev, SPI_AUTOSUSPEND_TIMEOUT);
pm_runtime_enable(&pdev->dev);
@@ -1238,7 +1270,6 @@ dma_chnl_free:
kfree(mcspi->dma_channels);
free_master:
spi_master_put(master);
- platform_set_drvdata(pdev, NULL);
return status;
}
@@ -1252,12 +1283,11 @@ static int __devexit omap2_mcspi_remove(struct platform_device *pdev)
mcspi = spi_master_get_devdata(master);
dma_channels = mcspi->dma_channels;
- omap2_mcspi_disable_clocks(mcspi);
+ pm_runtime_put_sync(mcspi->dev);
pm_runtime_disable(&pdev->dev);
spi_unregister_master(master);
kfree(dma_channels);
- platform_set_drvdata(pdev, NULL);
return 0;
}
@@ -1278,20 +1308,21 @@ static int omap2_mcspi_resume(struct device *dev)
struct omap2_mcspi_regs *ctx = &mcspi->ctx;
struct omap2_mcspi_cs *cs;
- omap2_mcspi_enable_clocks(mcspi);
+ pm_runtime_get_sync(mcspi->dev);
list_for_each_entry(cs, &ctx->cs, node) {
if ((cs->chconf0 & OMAP2_MCSPI_CHCONF_FORCE) == 0) {
/*
* We need to toggle CS state for OMAP take this
* change in account.
*/
- MOD_REG_BIT(cs->chconf0, OMAP2_MCSPI_CHCONF_FORCE, 1);
+ cs->chconf0 |= OMAP2_MCSPI_CHCONF_FORCE;
__raw_writel(cs->chconf0, cs->base + OMAP2_MCSPI_CHCONF0);
- MOD_REG_BIT(cs->chconf0, OMAP2_MCSPI_CHCONF_FORCE, 0);
+ cs->chconf0 &= ~OMAP2_MCSPI_CHCONF_FORCE;
__raw_writel(cs->chconf0, cs->base + OMAP2_MCSPI_CHCONF0);
}
}
- omap2_mcspi_disable_clocks(mcspi);
+ pm_runtime_mark_last_busy(mcspi->dev);
+ pm_runtime_put_autosuspend(mcspi->dev);
return 0;
}
#else
diff --git a/drivers/spi/spi-orion.c b/drivers/spi/spi-orion.c
index 9b0caddce50..b17c09cf0a0 100644
--- a/drivers/spi/spi-orion.c
+++ b/drivers/spi/spi-orion.c
@@ -36,12 +36,6 @@
#define ORION_SPI_CLK_PRESCALE_MASK 0x1F
struct orion_spi {
- struct work_struct work;
-
- /* Lock access to transfer list. */
- spinlock_t lock;
-
- struct list_head msg_queue;
struct spi_master *master;
void __iomem *base;
unsigned int max_speed;
@@ -49,8 +43,6 @@ struct orion_spi {
struct clk *clk;
};
-static struct workqueue_struct *orion_spi_wq;
-
static inline void __iomem *spi_reg(struct orion_spi *orion_spi, u32 reg)
{
return orion_spi->base + reg;
@@ -277,73 +269,78 @@ out:
}
-static void orion_spi_work(struct work_struct *work)
+static int orion_spi_transfer_one_message(struct spi_master *master,
+ struct spi_message *m)
{
- struct orion_spi *orion_spi =
- container_of(work, struct orion_spi, work);
-
- spin_lock_irq(&orion_spi->lock);
- while (!list_empty(&orion_spi->msg_queue)) {
- struct spi_message *m;
- struct spi_device *spi;
- struct spi_transfer *t = NULL;
- int par_override = 0;
- int status = 0;
- int cs_active = 0;
-
- m = container_of(orion_spi->msg_queue.next, struct spi_message,
- queue);
+ struct orion_spi *orion_spi = spi_master_get_devdata(master);
+ struct spi_device *spi = m->spi;
+ struct spi_transfer *t = NULL;
+ int par_override = 0;
+ int status = 0;
+ int cs_active = 0;
- list_del_init(&m->queue);
- spin_unlock_irq(&orion_spi->lock);
+ /* Load defaults */
+ status = orion_spi_setup_transfer(spi, NULL);
- spi = m->spi;
+ if (status < 0)
+ goto msg_done;
- /* Load defaults */
- status = orion_spi_setup_transfer(spi, NULL);
+ list_for_each_entry(t, &m->transfers, transfer_list) {
+ /* make sure buffer length is even when working in 16
+ * bit mode*/
+ if ((t->bits_per_word == 16) && (t->len & 1)) {
+ dev_err(&spi->dev,
+ "message rejected : "
+ "odd data length %d while in 16 bit mode\n",
+ t->len);
+ status = -EIO;
+ goto msg_done;
+ }
- if (status < 0)
+ if (t->speed_hz && t->speed_hz < orion_spi->min_speed) {
+ dev_err(&spi->dev,
+ "message rejected : "
+ "device min speed (%d Hz) exceeds "
+ "required transfer speed (%d Hz)\n",
+ orion_spi->min_speed, t->speed_hz);
+ status = -EIO;
goto msg_done;
+ }
- list_for_each_entry(t, &m->transfers, transfer_list) {
- if (par_override || t->speed_hz || t->bits_per_word) {
- par_override = 1;
- status = orion_spi_setup_transfer(spi, t);
- if (status < 0)
- break;
- if (!t->speed_hz && !t->bits_per_word)
- par_override = 0;
- }
-
- if (!cs_active) {
- orion_spi_set_cs(orion_spi, 1);
- cs_active = 1;
- }
-
- if (t->len)
- m->actual_length +=
- orion_spi_write_read(spi, t);
-
- if (t->delay_usecs)
- udelay(t->delay_usecs);
-
- if (t->cs_change) {
- orion_spi_set_cs(orion_spi, 0);
- cs_active = 0;
- }
+ if (par_override || t->speed_hz || t->bits_per_word) {
+ par_override = 1;
+ status = orion_spi_setup_transfer(spi, t);
+ if (status < 0)
+ break;
+ if (!t->speed_hz && !t->bits_per_word)
+ par_override = 0;
}
-msg_done:
- if (cs_active)
- orion_spi_set_cs(orion_spi, 0);
+ if (!cs_active) {
+ orion_spi_set_cs(orion_spi, 1);
+ cs_active = 1;
+ }
- m->status = status;
- m->complete(m->context);
+ if (t->len)
+ m->actual_length += orion_spi_write_read(spi, t);
- spin_lock_irq(&orion_spi->lock);
+ if (t->delay_usecs)
+ udelay(t->delay_usecs);
+
+ if (t->cs_change) {
+ orion_spi_set_cs(orion_spi, 0);
+ cs_active = 0;
+ }
}
- spin_unlock_irq(&orion_spi->lock);
+msg_done:
+ if (cs_active)
+ orion_spi_set_cs(orion_spi, 0);
+
+ m->status = status;
+ spi_finalize_current_message(master);
+
+ return 0;
}
static int __init orion_spi_reset(struct orion_spi *orion_spi)
@@ -376,75 +373,6 @@ static int orion_spi_setup(struct spi_device *spi)
return 0;
}
-static int orion_spi_transfer(struct spi_device *spi, struct spi_message *m)
-{
- struct orion_spi *orion_spi;
- struct spi_transfer *t = NULL;
- unsigned long flags;
-
- m->actual_length = 0;
- m->status = 0;
-
- /* reject invalid messages and transfers */
- if (list_empty(&m->transfers) || !m->complete)
- return -EINVAL;
-
- orion_spi = spi_master_get_devdata(spi->master);
-
- list_for_each_entry(t, &m->transfers, transfer_list) {
- unsigned int bits_per_word = spi->bits_per_word;
-
- if (t->tx_buf == NULL && t->rx_buf == NULL && t->len) {
- dev_err(&spi->dev,
- "message rejected : "
- "invalid transfer data buffers\n");
- goto msg_rejected;
- }
-
- if (t->bits_per_word)
- bits_per_word = t->bits_per_word;
-
- if ((bits_per_word != 8) && (bits_per_word != 16)) {
- dev_err(&spi->dev,
- "message rejected : "
- "invalid transfer bits_per_word (%d bits)\n",
- bits_per_word);
- goto msg_rejected;
- }
- /*make sure buffer length is even when working in 16 bit mode*/
- if ((t->bits_per_word == 16) && (t->len & 1)) {
- dev_err(&spi->dev,
- "message rejected : "
- "odd data length (%d) while in 16 bit mode\n",
- t->len);
- goto msg_rejected;
- }
-
- if (t->speed_hz && t->speed_hz < orion_spi->min_speed) {
- dev_err(&spi->dev,
- "message rejected : "
- "device min speed (%d Hz) exceeds "
- "required transfer speed (%d Hz)\n",
- orion_spi->min_speed, t->speed_hz);
- goto msg_rejected;
- }
- }
-
-
- spin_lock_irqsave(&orion_spi->lock, flags);
- list_add_tail(&m->queue, &orion_spi->msg_queue);
- queue_work(orion_spi_wq, &orion_spi->work);
- spin_unlock_irqrestore(&orion_spi->lock, flags);
-
- return 0;
-msg_rejected:
- /* Message rejected and not queued */
- m->status = -EINVAL;
- if (m->complete)
- m->complete(m->context);
- return -EINVAL;
-}
-
static int __init orion_spi_probe(struct platform_device *pdev)
{
struct spi_master *master;
@@ -474,7 +402,7 @@ static int __init orion_spi_probe(struct platform_device *pdev)
master->mode_bits = 0;
master->setup = orion_spi_setup;
- master->transfer = orion_spi_transfer;
+ master->transfer_one_message = orion_spi_transfer_one_message;
master->num_chipselect = ORION_NUM_CHIPSELECTS;
dev_set_drvdata(&pdev->dev, master);
@@ -507,11 +435,6 @@ static int __init orion_spi_probe(struct platform_device *pdev)
}
spi->base = ioremap(r->start, SZ_1K);
- INIT_WORK(&spi->work, orion_spi_work);
-
- spin_lock_init(&spi->lock);
- INIT_LIST_HEAD(&spi->msg_queue);
-
if (orion_spi_reset(spi) < 0)
goto out_rel_mem;
@@ -536,14 +459,12 @@ out:
static int __exit orion_spi_remove(struct platform_device *pdev)
{
struct spi_master *master;
- struct orion_spi *spi;
struct resource *r;
+ struct orion_spi *spi;
master = dev_get_drvdata(&pdev->dev);
spi = spi_master_get_devdata(master);
- cancel_work_sync(&spi->work);
-
clk_disable_unprepare(spi->clk);
clk_put(spi->clk);
@@ -574,21 +495,13 @@ static struct platform_driver orion_spi_driver = {
static int __init orion_spi_init(void)
{
- orion_spi_wq = create_singlethread_workqueue(
- orion_spi_driver.driver.name);
- if (orion_spi_wq == NULL)
- return -ENOMEM;
-
return platform_driver_probe(&orion_spi_driver, orion_spi_probe);
}
module_init(orion_spi_init);
static void __exit orion_spi_exit(void)
{
- flush_workqueue(orion_spi_wq);
platform_driver_unregister(&orion_spi_driver);
-
- destroy_workqueue(orion_spi_wq);
}
module_exit(orion_spi_exit);
diff --git a/drivers/spi/spi-pl022.c b/drivers/spi/spi-pl022.c
index 6abbe23c39b..f8568b43660 100644
--- a/drivers/spi/spi-pl022.c
+++ b/drivers/spi/spi-pl022.c
@@ -40,6 +40,9 @@
#include <linux/dma-mapping.h>
#include <linux/scatterlist.h>
#include <linux/pm_runtime.h>
+#include <linux/gpio.h>
+#include <linux/of_gpio.h>
+#include <linux/pinctrl/consumer.h>
/*
* This macro is used to define some register default values.
@@ -356,6 +359,8 @@ struct vendor_data {
* @sgt_rx: scattertable for the RX transfer
* @sgt_tx: scattertable for the TX transfer
* @dummypage: a dummy page used for driving data on the bus with DMA
+ * @cur_cs: current chip select (gpio)
+ * @chipselects: list of chipselects (gpios)
*/
struct pl022 {
struct amba_device *adev;
@@ -363,6 +368,10 @@ struct pl022 {
resource_size_t phybase;
void __iomem *virtbase;
struct clk *clk;
+ /* Two optional pin states - default & sleep */
+ struct pinctrl *pinctrl;
+ struct pinctrl_state *pins_default;
+ struct pinctrl_state *pins_sleep;
struct spi_master *master;
struct pl022_ssp_controller *master_info;
/* Message per-transfer pump */
@@ -389,6 +398,8 @@ struct pl022 {
char *dummypage;
bool dma_running;
#endif
+ int cur_cs;
+ int *chipselects;
};
/**
@@ -433,6 +444,14 @@ static void null_cs_control(u32 command)
pr_debug("pl022: dummy chip select control, CS=0x%x\n", command);
}
+static void pl022_cs_control(struct pl022 *pl022, u32 command)
+{
+ if (gpio_is_valid(pl022->cur_cs))
+ gpio_set_value(pl022->cur_cs, command);
+ else
+ pl022->cur_chip->cs_control(command);
+}
+
/**
* giveback - current spi_message is over, schedule next message and call
* callback of this message. Assumes that caller already
@@ -479,7 +498,7 @@ static void giveback(struct pl022 *pl022)
if (next_msg && next_msg->spi != pl022->cur_msg->spi)
next_msg = NULL;
if (!next_msg || pl022->cur_msg->state == STATE_ERROR)
- pl022->cur_chip->cs_control(SSP_CHIP_DESELECT);
+ pl022_cs_control(pl022, SSP_CHIP_DESELECT);
else
pl022->next_msg_cs_active = true;
@@ -818,8 +837,7 @@ static void dma_callback(void *data)
/* Update total bytes transferred */
msg->actual_length += pl022->cur_transfer->len;
if (pl022->cur_transfer->cs_change)
- pl022->cur_chip->
- cs_control(SSP_CHIP_DESELECT);
+ pl022_cs_control(pl022, SSP_CHIP_DESELECT);
/* Move to next transfer */
msg->state = next_transfer(pl022);
@@ -1252,8 +1270,7 @@ static irqreturn_t pl022_interrupt_handler(int irq, void *dev_id)
/* Update total bytes transferred */
msg->actual_length += pl022->cur_transfer->len;
if (pl022->cur_transfer->cs_change)
- pl022->cur_chip->
- cs_control(SSP_CHIP_DESELECT);
+ pl022_cs_control(pl022, SSP_CHIP_DESELECT);
/* Move to next transfer */
msg->state = next_transfer(pl022);
tasklet_schedule(&pl022->pump_transfers);
@@ -1338,7 +1355,7 @@ static void pump_transfers(unsigned long data)
/* Reselect chip select only if cs_change was requested */
if (previous->cs_change)
- pl022->cur_chip->cs_control(SSP_CHIP_SELECT);
+ pl022_cs_control(pl022, SSP_CHIP_SELECT);
} else {
/* STATE_START */
message->state = STATE_RUNNING;
@@ -1377,7 +1394,7 @@ static void do_interrupt_dma_transfer(struct pl022 *pl022)
/* Enable target chip, if not already active */
if (!pl022->next_msg_cs_active)
- pl022->cur_chip->cs_control(SSP_CHIP_SELECT);
+ pl022_cs_control(pl022, SSP_CHIP_SELECT);
if (set_up_next_transfer(pl022, pl022->cur_transfer)) {
/* Error path */
@@ -1429,12 +1446,12 @@ static void do_polling_transfer(struct pl022 *pl022)
if (previous->delay_usecs)
udelay(previous->delay_usecs);
if (previous->cs_change)
- pl022->cur_chip->cs_control(SSP_CHIP_SELECT);
+ pl022_cs_control(pl022, SSP_CHIP_SELECT);
} else {
/* STATE_START */
message->state = STATE_RUNNING;
if (!pl022->next_msg_cs_active)
- pl022->cur_chip->cs_control(SSP_CHIP_SELECT);
+ pl022_cs_control(pl022, SSP_CHIP_SELECT);
}
/* Configuration Changing Per Transfer */
@@ -1466,7 +1483,7 @@ static void do_polling_transfer(struct pl022 *pl022)
/* Update total byte transferred */
message->actual_length += pl022->cur_transfer->len;
if (pl022->cur_transfer->cs_change)
- pl022->cur_chip->cs_control(SSP_CHIP_DESELECT);
+ pl022_cs_control(pl022, SSP_CHIP_DESELECT);
/* Move to next transfer */
message->state = next_transfer(pl022);
}
@@ -1495,6 +1512,7 @@ static int pl022_transfer_one_message(struct spi_master *master,
/* Setup the SPI using the per chip configuration */
pl022->cur_chip = spi_get_ctldata(msg->spi);
+ pl022->cur_cs = pl022->chipselects[msg->spi->chip_select];
restore_state(pl022);
flush(pl022);
@@ -1766,12 +1784,14 @@ static const struct pl022_config_chip pl022_default_chip_info = {
static int pl022_setup(struct spi_device *spi)
{
struct pl022_config_chip const *chip_info;
+ struct pl022_config_chip chip_info_dt;
struct chip_data *chip;
struct ssp_clock_params clk_freq = { .cpsdvsr = 0, .scr = 0};
int status = 0;
struct pl022 *pl022 = spi_master_get_devdata(spi->master);
unsigned int bits = spi->bits_per_word;
u32 tmp;
+ struct device_node *np = spi->dev.of_node;
if (!spi->max_speed_hz)
return -EINVAL;
@@ -1794,10 +1814,32 @@ static int pl022_setup(struct spi_device *spi)
chip_info = spi->controller_data;
if (chip_info == NULL) {
- chip_info = &pl022_default_chip_info;
- /* spi_board_info.controller_data not is supplied */
- dev_dbg(&spi->dev,
- "using default controller_data settings\n");
+ if (np) {
+ chip_info_dt = pl022_default_chip_info;
+
+ chip_info_dt.hierarchy = SSP_MASTER;
+ of_property_read_u32(np, "pl022,interface",
+ &chip_info_dt.iface);
+ of_property_read_u32(np, "pl022,com-mode",
+ &chip_info_dt.com_mode);
+ of_property_read_u32(np, "pl022,rx-level-trig",
+ &chip_info_dt.rx_lev_trig);
+ of_property_read_u32(np, "pl022,tx-level-trig",
+ &chip_info_dt.tx_lev_trig);
+ of_property_read_u32(np, "pl022,ctrl-len",
+ &chip_info_dt.ctrl_len);
+ of_property_read_u32(np, "pl022,wait-state",
+ &chip_info_dt.wait_state);
+ of_property_read_u32(np, "pl022,duplex",
+ &chip_info_dt.duplex);
+
+ chip_info = &chip_info_dt;
+ } else {
+ chip_info = &pl022_default_chip_info;
+ /* spi_board_info.controller_data not is supplied */
+ dev_dbg(&spi->dev,
+ "using default controller_data settings\n");
+ }
} else
dev_dbg(&spi->dev,
"using user supplied controller_data settings\n");
@@ -1840,8 +1882,9 @@ static int pl022_setup(struct spi_device *spi)
chip->xfer_type = chip_info->com_mode;
if (!chip_info->cs_control) {
chip->cs_control = null_cs_control;
- dev_warn(&spi->dev,
- "chip select function is NULL for this chip\n");
+ if (!gpio_is_valid(pl022->chipselects[spi->chip_select]))
+ dev_warn(&spi->dev,
+ "invalid chip select\n");
} else
chip->cs_control = chip_info->cs_control;
@@ -1986,6 +2029,34 @@ static void pl022_cleanup(struct spi_device *spi)
kfree(chip);
}
+static struct pl022_ssp_controller *
+pl022_platform_data_dt_get(struct device *dev)
+{
+ struct device_node *np = dev->of_node;
+ struct pl022_ssp_controller *pd;
+ u32 tmp;
+
+ if (!np) {
+ dev_err(dev, "no dt node defined\n");
+ return NULL;
+ }
+
+ pd = devm_kzalloc(dev, sizeof(struct pl022_ssp_controller), GFP_KERNEL);
+ if (!pd) {
+ dev_err(dev, "cannot allocate platform data memory\n");
+ return NULL;
+ }
+
+ pd->bus_id = -1;
+ of_property_read_u32(np, "num-cs", &tmp);
+ pd->num_chipselect = tmp;
+ of_property_read_u32(np, "pl022,autosuspend-delay",
+ &pd->autosuspend_delay);
+ pd->rt = of_property_read_bool(np, "pl022,rt");
+
+ return pd;
+}
+
static int __devinit
pl022_probe(struct amba_device *adev, const struct amba_id *id)
{
@@ -1993,12 +2064,24 @@ pl022_probe(struct amba_device *adev, const struct amba_id *id)
struct pl022_ssp_controller *platform_info = adev->dev.platform_data;
struct spi_master *master;
struct pl022 *pl022 = NULL; /*Data for this driver */
- int status = 0;
+ struct device_node *np = adev->dev.of_node;
+ int status = 0, i, num_cs;
dev_info(&adev->dev,
"ARM PL022 driver, device ID: 0x%08x\n", adev->periphid);
- if (platform_info == NULL) {
- dev_err(&adev->dev, "probe - no platform data supplied\n");
+ if (!platform_info && IS_ENABLED(CONFIG_OF))
+ platform_info = pl022_platform_data_dt_get(dev);
+
+ if (!platform_info) {
+ dev_err(dev, "probe: no platform data defined\n");
+ status = -ENODEV;
+ goto err_no_pdata;
+ }
+
+ if (platform_info->num_chipselect) {
+ num_cs = platform_info->num_chipselect;
+ } else {
+ dev_err(dev, "probe: no chip select defined\n");
status = -ENODEV;
goto err_no_pdata;
}
@@ -2016,19 +2099,71 @@ pl022_probe(struct amba_device *adev, const struct amba_id *id)
pl022->master_info = platform_info;
pl022->adev = adev;
pl022->vendor = id->data;
+ pl022->chipselects = devm_kzalloc(dev, num_cs * sizeof(int),
+ GFP_KERNEL);
+
+ pl022->pinctrl = devm_pinctrl_get(dev);
+ if (IS_ERR(pl022->pinctrl)) {
+ status = PTR_ERR(pl022->pinctrl);
+ goto err_no_pinctrl;
+ }
+
+ pl022->pins_default = pinctrl_lookup_state(pl022->pinctrl,
+ PINCTRL_STATE_DEFAULT);
+ /* enable pins to be muxed in and configured */
+ if (!IS_ERR(pl022->pins_default)) {
+ status = pinctrl_select_state(pl022->pinctrl,
+ pl022->pins_default);
+ if (status)
+ dev_err(dev, "could not set default pins\n");
+ } else
+ dev_err(dev, "could not get default pinstate\n");
+
+ pl022->pins_sleep = pinctrl_lookup_state(pl022->pinctrl,
+ PINCTRL_STATE_SLEEP);
+ if (IS_ERR(pl022->pins_sleep))
+ dev_dbg(dev, "could not get sleep pinstate\n");
/*
* Bus Number Which has been Assigned to this SSP controller
* on this board
*/
master->bus_num = platform_info->bus_id;
- master->num_chipselect = platform_info->num_chipselect;
+ master->num_chipselect = num_cs;
master->cleanup = pl022_cleanup;
master->setup = pl022_setup;
master->prepare_transfer_hardware = pl022_prepare_transfer_hardware;
master->transfer_one_message = pl022_transfer_one_message;
master->unprepare_transfer_hardware = pl022_unprepare_transfer_hardware;
master->rt = platform_info->rt;
+ master->dev.of_node = dev->of_node;
+
+ if (platform_info->num_chipselect && platform_info->chipselects) {
+ for (i = 0; i < num_cs; i++)
+ pl022->chipselects[i] = platform_info->chipselects[i];
+ } else if (IS_ENABLED(CONFIG_OF)) {
+ for (i = 0; i < num_cs; i++) {
+ int cs_gpio = of_get_named_gpio(np, "cs-gpios", i);
+
+ if (cs_gpio == -EPROBE_DEFER) {
+ status = -EPROBE_DEFER;
+ goto err_no_gpio;
+ }
+
+ pl022->chipselects[i] = cs_gpio;
+
+ if (gpio_is_valid(cs_gpio)) {
+ if (gpio_request(cs_gpio, "ssp-pl022"))
+ dev_err(&adev->dev,
+ "could not request %d gpio\n",
+ cs_gpio);
+ else if (gpio_direction_output(cs_gpio, 1))
+ dev_err(&adev->dev,
+ "could set gpio %d as output\n",
+ cs_gpio);
+ }
+ }
+ }
/*
* Supports mode 0-3, loopback, and active low CS. Transfers are
@@ -2137,6 +2272,8 @@ pl022_probe(struct amba_device *adev, const struct amba_id *id)
err_no_ioremap:
amba_release_regions(adev);
err_no_ioregion:
+ err_no_gpio:
+ err_no_pinctrl:
spi_master_put(master);
err_no_master:
err_no_pdata:
@@ -2170,7 +2307,6 @@ pl022_remove(struct amba_device *adev)
amba_release_regions(adev);
tasklet_disable(&pl022->pump_transfers);
spi_unregister_master(pl022->master);
- spi_master_put(pl022->master);
amba_set_drvdata(adev, NULL);
return 0;
}
@@ -2211,15 +2347,33 @@ static int pl022_resume(struct device *dev)
static int pl022_runtime_suspend(struct device *dev)
{
struct pl022 *pl022 = dev_get_drvdata(dev);
+ int status = 0;
clk_disable(pl022->clk);
+ /* Optionally let pins go into sleep states */
+ if (!IS_ERR(pl022->pins_sleep)) {
+ status = pinctrl_select_state(pl022->pinctrl,
+ pl022->pins_sleep);
+ if (status)
+ dev_err(dev, "could not set pins to sleep state\n");
+ }
+
return 0;
}
static int pl022_runtime_resume(struct device *dev)
{
struct pl022 *pl022 = dev_get_drvdata(dev);
+ int status = 0;
+
+ /* Optionaly enable pins to be muxed in and configured */
+ if (!IS_ERR(pl022->pins_default)) {
+ status = pinctrl_select_state(pl022->pinctrl,
+ pl022->pins_default);
+ if (status)
+ dev_err(dev, "could not set default pins\n");
+ }
clk_enable(pl022->clk);
diff --git a/drivers/spi/spi-s3c24xx.c b/drivers/spi/spi-s3c24xx.c
index 8ee7d790ce4..a2a080b7f42 100644
--- a/drivers/spi/spi-s3c24xx.c
+++ b/drivers/spi/spi-s3c24xx.c
@@ -611,6 +611,7 @@ static int __devinit s3c24xx_spi_probe(struct platform_device *pdev)
if (!pdata->set_cs) {
if (pdata->pin_cs < 0) {
dev_err(&pdev->dev, "No chipselect pin\n");
+ err = -EINVAL;
goto err_register;
}
diff --git a/drivers/spi/spi-s3c64xx.c b/drivers/spi/spi-s3c64xx.c
index d1c8441f638..a2062b231a6 100644
--- a/drivers/spi/spi-s3c64xx.c
+++ b/drivers/spi/spi-s3c64xx.c
@@ -976,7 +976,8 @@ err_msgq:
spi_set_ctldata(spi, NULL);
err_gpio_req:
- kfree(cs);
+ if (spi->dev.of_node)
+ kfree(cs);
return err;
}
@@ -1409,7 +1410,7 @@ static int s3c64xx_spi_remove(struct platform_device *pdev)
#ifdef CONFIG_PM
static int s3c64xx_spi_suspend(struct device *dev)
{
- struct spi_master *master = spi_master_get(dev_get_drvdata(dev));
+ struct spi_master *master = dev_get_drvdata(dev);
struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(master);
spi_master_suspend(master);
@@ -1428,7 +1429,7 @@ static int s3c64xx_spi_suspend(struct device *dev)
static int s3c64xx_spi_resume(struct device *dev)
{
- struct spi_master *master = spi_master_get(dev_get_drvdata(dev));
+ struct spi_master *master = dev_get_drvdata(dev);
struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(master);
struct s3c64xx_spi_info *sci = sdd->cntrlr_info;
@@ -1452,7 +1453,7 @@ static int s3c64xx_spi_resume(struct device *dev)
#ifdef CONFIG_PM_RUNTIME
static int s3c64xx_spi_runtime_suspend(struct device *dev)
{
- struct spi_master *master = spi_master_get(dev_get_drvdata(dev));
+ struct spi_master *master = dev_get_drvdata(dev);
struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(master);
clk_disable(sdd->clk);
@@ -1463,7 +1464,7 @@ static int s3c64xx_spi_runtime_suspend(struct device *dev)
static int s3c64xx_spi_runtime_resume(struct device *dev)
{
- struct spi_master *master = spi_master_get(dev_get_drvdata(dev));
+ struct spi_master *master = dev_get_drvdata(dev);
struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(master);
clk_enable(sdd->src_clk);
diff --git a/drivers/spi/spi-sc18is602.c b/drivers/spi/spi-sc18is602.c
new file mode 100644
index 00000000000..9eda21d739c
--- /dev/null
+++ b/drivers/spi/spi-sc18is602.c
@@ -0,0 +1,364 @@
+/*
+ * NXP SC18IS602/603 SPI driver
+ *
+ * Copyright (C) Guenter Roeck <linux@roeck-us.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/kernel.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/spi/spi.h>
+#include <linux/i2c.h>
+#include <linux/delay.h>
+#include <linux/pm_runtime.h>
+#include <linux/of.h>
+#include <linux/platform_data/sc18is602.h>
+
+enum chips { sc18is602, sc18is602b, sc18is603 };
+
+#define SC18IS602_BUFSIZ 200
+#define SC18IS602_CLOCK 7372000
+
+#define SC18IS602_MODE_CPHA BIT(2)
+#define SC18IS602_MODE_CPOL BIT(3)
+#define SC18IS602_MODE_LSB_FIRST BIT(5)
+#define SC18IS602_MODE_CLOCK_DIV_4 0x0
+#define SC18IS602_MODE_CLOCK_DIV_16 0x1
+#define SC18IS602_MODE_CLOCK_DIV_64 0x2
+#define SC18IS602_MODE_CLOCK_DIV_128 0x3
+
+struct sc18is602 {
+ struct spi_master *master;
+ struct device *dev;
+ u8 ctrl;
+ u32 freq;
+ u32 speed;
+
+ /* I2C data */
+ struct i2c_client *client;
+ enum chips id;
+ u8 buffer[SC18IS602_BUFSIZ + 1];
+ int tlen; /* Data queued for tx in buffer */
+ int rindex; /* Receive data index in buffer */
+};
+
+static int sc18is602_wait_ready(struct sc18is602 *hw, int len)
+{
+ int i, err;
+ int usecs = 1000000 * len / hw->speed + 1;
+ u8 dummy[1];
+
+ for (i = 0; i < 10; i++) {
+ err = i2c_master_recv(hw->client, dummy, 1);
+ if (err >= 0)
+ return 0;
+ usleep_range(usecs, usecs * 2);
+ }
+ return -ETIMEDOUT;
+}
+
+static int sc18is602_txrx(struct sc18is602 *hw, struct spi_message *msg,
+ struct spi_transfer *t, bool do_transfer)
+{
+ unsigned int len = t->len;
+ int ret;
+
+ if (hw->tlen == 0) {
+ /* First byte (I2C command) is chip select */
+ hw->buffer[0] = 1 << msg->spi->chip_select;
+ hw->tlen = 1;
+ hw->rindex = 0;
+ }
+ /*
+ * We can not immediately send data to the chip, since each I2C message
+ * resembles a full SPI message (from CS active to CS inactive).
+ * Enqueue messages up to the first read or until do_transfer is true.
+ */
+ if (t->tx_buf) {
+ memcpy(&hw->buffer[hw->tlen], t->tx_buf, len);
+ hw->tlen += len;
+ if (t->rx_buf)
+ do_transfer = true;
+ else
+ hw->rindex = hw->tlen - 1;
+ } else if (t->rx_buf) {
+ /*
+ * For receive-only transfers we still need to perform a dummy
+ * write to receive data from the SPI chip.
+ * Read data starts at the end of transmit data (minus 1 to
+ * account for CS).
+ */
+ hw->rindex = hw->tlen - 1;
+ memset(&hw->buffer[hw->tlen], 0, len);
+ hw->tlen += len;
+ do_transfer = true;
+ }
+
+ if (do_transfer && hw->tlen > 1) {
+ ret = sc18is602_wait_ready(hw, SC18IS602_BUFSIZ);
+ if (ret < 0)
+ return ret;
+ ret = i2c_master_send(hw->client, hw->buffer, hw->tlen);
+ if (ret < 0)
+ return ret;
+ if (ret != hw->tlen)
+ return -EIO;
+
+ if (t->rx_buf) {
+ int rlen = hw->rindex + len;
+
+ ret = sc18is602_wait_ready(hw, hw->tlen);
+ if (ret < 0)
+ return ret;
+ ret = i2c_master_recv(hw->client, hw->buffer, rlen);
+ if (ret < 0)
+ return ret;
+ if (ret != rlen)
+ return -EIO;
+ memcpy(t->rx_buf, &hw->buffer[hw->rindex], len);
+ }
+ hw->tlen = 0;
+ }
+ return len;
+}
+
+static int sc18is602_setup_transfer(struct sc18is602 *hw, u32 hz, u8 mode)
+{
+ u8 ctrl = 0;
+ int ret;
+
+ if (mode & SPI_CPHA)
+ ctrl |= SC18IS602_MODE_CPHA;
+ if (mode & SPI_CPOL)
+ ctrl |= SC18IS602_MODE_CPOL;
+ if (mode & SPI_LSB_FIRST)
+ ctrl |= SC18IS602_MODE_LSB_FIRST;
+
+ /* Find the closest clock speed */
+ if (hz >= hw->freq / 4) {
+ ctrl |= SC18IS602_MODE_CLOCK_DIV_4;
+ hw->speed = hw->freq / 4;
+ } else if (hz >= hw->freq / 16) {
+ ctrl |= SC18IS602_MODE_CLOCK_DIV_16;
+ hw->speed = hw->freq / 16;
+ } else if (hz >= hw->freq / 64) {
+ ctrl |= SC18IS602_MODE_CLOCK_DIV_64;
+ hw->speed = hw->freq / 64;
+ } else {
+ ctrl |= SC18IS602_MODE_CLOCK_DIV_128;
+ hw->speed = hw->freq / 128;
+ }
+
+ /*
+ * Don't do anything if the control value did not change. The initial
+ * value of 0xff for hw->ctrl ensures that the correct mode will be set
+ * with the first call to this function.
+ */
+ if (ctrl == hw->ctrl)
+ return 0;
+
+ ret = i2c_smbus_write_byte_data(hw->client, 0xf0, ctrl);
+ if (ret < 0)
+ return ret;
+
+ hw->ctrl = ctrl;
+
+ return 0;
+}
+
+static int sc18is602_check_transfer(struct spi_device *spi,
+ struct spi_transfer *t, int tlen)
+{
+ int bpw;
+ uint32_t hz;
+
+ if (t && t->len + tlen > SC18IS602_BUFSIZ)
+ return -EINVAL;
+
+ bpw = spi->bits_per_word;
+ if (t && t->bits_per_word)
+ bpw = t->bits_per_word;
+ if (bpw != 8)
+ return -EINVAL;
+
+ hz = spi->max_speed_hz;
+ if (t && t->speed_hz)
+ hz = t->speed_hz;
+ if (hz == 0)
+ return -EINVAL;
+
+ return 0;
+}
+
+static int sc18is602_transfer_one(struct spi_master *master,
+ struct spi_message *m)
+{
+ struct sc18is602 *hw = spi_master_get_devdata(master);
+ struct spi_device *spi = m->spi;
+ struct spi_transfer *t;
+ int status = 0;
+
+ /* SC18IS602 does not support CS2 */
+ if (hw->id == sc18is602 && spi->chip_select == 2) {
+ status = -ENXIO;
+ goto error;
+ }
+
+ hw->tlen = 0;
+ list_for_each_entry(t, &m->transfers, transfer_list) {
+ u32 hz = t->speed_hz ? : spi->max_speed_hz;
+ bool do_transfer;
+
+ status = sc18is602_check_transfer(spi, t, hw->tlen);
+ if (status < 0)
+ break;
+
+ status = sc18is602_setup_transfer(hw, hz, spi->mode);
+ if (status < 0)
+ break;
+
+ do_transfer = t->cs_change || list_is_last(&t->transfer_list,
+ &m->transfers);
+
+ if (t->len) {
+ status = sc18is602_txrx(hw, m, t, do_transfer);
+ if (status < 0)
+ break;
+ m->actual_length += status;
+ }
+ status = 0;
+
+ if (t->delay_usecs)
+ udelay(t->delay_usecs);
+ }
+error:
+ m->status = status;
+ spi_finalize_current_message(master);
+
+ return status;
+}
+
+static int sc18is602_setup(struct spi_device *spi)
+{
+ if (!spi->bits_per_word)
+ spi->bits_per_word = 8;
+
+ if (spi->mode & ~(SPI_CPHA | SPI_CPOL | SPI_LSB_FIRST))
+ return -EINVAL;
+
+ return sc18is602_check_transfer(spi, NULL, 0);
+}
+
+static int sc18is602_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct device *dev = &client->dev;
+ struct device_node *np = dev->of_node;
+ struct sc18is602_platform_data *pdata = dev_get_platdata(dev);
+ struct sc18is602 *hw;
+ struct spi_master *master;
+ int error;
+
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C |
+ I2C_FUNC_SMBUS_WRITE_BYTE_DATA))
+ return -EINVAL;
+
+ master = spi_alloc_master(dev, sizeof(struct sc18is602));
+ if (!master)
+ return -ENOMEM;
+
+ hw = spi_master_get_devdata(master);
+ i2c_set_clientdata(client, hw);
+
+ hw->master = master;
+ hw->client = client;
+ hw->dev = dev;
+ hw->ctrl = 0xff;
+
+ hw->id = id->driver_data;
+
+ switch (hw->id) {
+ case sc18is602:
+ case sc18is602b:
+ master->num_chipselect = 4;
+ hw->freq = SC18IS602_CLOCK;
+ break;
+ case sc18is603:
+ master->num_chipselect = 2;
+ if (pdata) {
+ hw->freq = pdata->clock_frequency;
+ } else {
+ const __be32 *val;
+ int len;
+
+ val = of_get_property(np, "clock-frequency", &len);
+ if (val && len >= sizeof(__be32))
+ hw->freq = be32_to_cpup(val);
+ }
+ if (!hw->freq)
+ hw->freq = SC18IS602_CLOCK;
+ break;
+ }
+ master->bus_num = client->adapter->nr;
+ master->mode_bits = SPI_CPHA | SPI_CPOL | SPI_LSB_FIRST;
+ master->setup = sc18is602_setup;
+ master->transfer_one_message = sc18is602_transfer_one;
+ master->dev.of_node = np;
+
+ error = spi_register_master(master);
+ if (error)
+ goto error_reg;
+
+ return 0;
+
+error_reg:
+ spi_master_put(master);
+ return error;
+}
+
+static int sc18is602_remove(struct i2c_client *client)
+{
+ struct sc18is602 *hw = i2c_get_clientdata(client);
+ struct spi_master *master = hw->master;
+
+ spi_unregister_master(master);
+
+ return 0;
+}
+
+static const struct i2c_device_id sc18is602_id[] = {
+ { "sc18is602", sc18is602 },
+ { "sc18is602b", sc18is602b },
+ { "sc18is603", sc18is603 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, sc18is602_id);
+
+static struct i2c_driver sc18is602_driver = {
+ .driver = {
+ .name = "sc18is602",
+ },
+ .probe = sc18is602_probe,
+ .remove = sc18is602_remove,
+ .id_table = sc18is602_id,
+};
+
+module_i2c_driver(sc18is602_driver);
+
+MODULE_DESCRIPTION("SC18IC602/603 SPI Master Driver");
+MODULE_AUTHOR("Guenter Roeck");
+MODULE_LICENSE("GPL");
diff --git a/drivers/spi/spi-sh-hspi.c b/drivers/spi/spi-sh-hspi.c
index 934138c7b3d..796c077ef43 100644
--- a/drivers/spi/spi-sh-hspi.c
+++ b/drivers/spi/spi-sh-hspi.c
@@ -283,7 +283,7 @@ static int __devinit hspi_probe(struct platform_device *pdev)
ret = spi_register_master(master);
if (ret < 0) {
dev_err(&pdev->dev, "spi_register_master error.\n");
- goto error2;
+ goto error1;
}
pm_runtime_enable(&pdev->dev);
@@ -292,8 +292,6 @@ static int __devinit hspi_probe(struct platform_device *pdev)
return 0;
- error2:
- devm_iounmap(hspi->dev, hspi->addr);
error1:
clk_put(clk);
error0:
@@ -310,7 +308,6 @@ static int __devexit hspi_remove(struct platform_device *pdev)
clk_put(hspi->clk);
spi_unregister_master(hspi->master);
- devm_iounmap(hspi->dev, hspi->addr);
return 0;
}
diff --git a/drivers/spi/spi-stmp.c b/drivers/spi/spi-stmp.c
index 58e38528532..911e904b3c8 100644
--- a/drivers/spi/spi-stmp.c
+++ b/drivers/spi/spi-stmp.c
@@ -594,9 +594,7 @@ static int __devexit stmp_spi_remove(struct platform_device *dev)
struct stmp_spi *ss;
struct spi_master *master;
- master = platform_get_drvdata(dev);
- if (master == NULL)
- goto out0;
+ master = spi_master_get(platform_get_drvdata(dev));
ss = spi_master_get_devdata(master);
spi_unregister_master(master);
@@ -609,8 +607,6 @@ static int __devexit stmp_spi_remove(struct platform_device *dev)
destroy_workqueue(ss->workqueue);
iounmap(ss->regs);
spi_master_put(master);
- platform_set_drvdata(dev, NULL);
-out0:
return 0;
}
diff --git a/drivers/spi/spi-tegra.c b/drivers/spi/spi-tegra.c
index ef52c1c6f5c..e28445d8d27 100644
--- a/drivers/spi/spi-tegra.c
+++ b/drivers/spi/spi-tegra.c
@@ -652,7 +652,7 @@ static int __devexit spi_tegra_remove(struct platform_device *pdev)
struct spi_tegra_data *tspi;
struct resource *r;
- master = dev_get_drvdata(&pdev->dev);
+ master = spi_master_get(dev_get_drvdata(&pdev->dev));
tspi = spi_master_get_devdata(master);
spi_unregister_master(master);
@@ -668,6 +668,8 @@ static int __devexit spi_tegra_remove(struct platform_device *pdev)
clk_put(tspi->clk);
iounmap(tspi->base);
+ spi_master_put(master);
+
r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
release_mem_region(r->start, resource_size(r));
diff --git a/drivers/spi/spi-tle62x0.c b/drivers/spi/spi-tle62x0.c
index 0ce5c12aab5..24421024dea 100644
--- a/drivers/spi/spi-tle62x0.c
+++ b/drivers/spi/spi-tle62x0.c
@@ -316,18 +316,7 @@ static struct spi_driver tle62x0_driver = {
.remove = __devexit_p(tle62x0_remove),
};
-static __init int tle62x0_init(void)
-{
- return spi_register_driver(&tle62x0_driver);
-}
-
-static __exit void tle62x0_exit(void)
-{
- spi_unregister_driver(&tle62x0_driver);
-}
-
-module_init(tle62x0_init);
-module_exit(tle62x0_exit);
+module_spi_driver(tle62x0_driver);
MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");
MODULE_DESCRIPTION("TLE62x0 SPI driver");
diff --git a/drivers/spi/spi-topcliff-pch.c b/drivers/spi/spi-topcliff-pch.c
index cd56dcf4632..159dafd2f90 100644
--- a/drivers/spi/spi-topcliff-pch.c
+++ b/drivers/spi/spi-topcliff-pch.c
@@ -1536,8 +1536,6 @@ static int __devexit pch_spi_pd_remove(struct platform_device *plat_dev)
pci_iounmap(board_dat->pdev, data->io_remap_addr);
spi_unregister_master(data->master);
- spi_master_put(data->master);
- platform_set_drvdata(plat_dev, NULL);
return 0;
}
diff --git a/include/linux/amba/pl022.h b/include/linux/amba/pl022.h
index fe1d7b283cb..854b7294f6c 100644
--- a/include/linux/amba/pl022.h
+++ b/include/linux/amba/pl022.h
@@ -244,6 +244,7 @@ struct dma_chan;
* indicates no delay and the device will be suspended immediately.
* @rt: indicates the controller should run the message pump with realtime
* priority to minimise the transfer latency on the bus.
+ * @chipselects: list of <num_chipselects> chip select gpios
*/
struct pl022_ssp_controller {
u16 bus_id;
@@ -254,6 +255,7 @@ struct pl022_ssp_controller {
void *dma_tx_param;
int autosuspend_delay;
bool rt;
+ int *chipselects;
};
/**
diff --git a/include/linux/platform_data/sc18is602.h b/include/linux/platform_data/sc18is602.h
new file mode 100644
index 00000000000..997b0663415
--- /dev/null
+++ b/include/linux/platform_data/sc18is602.h
@@ -0,0 +1,19 @@
+/*
+ * Platform data for NXP SC18IS602/603
+ *
+ * Copyright (C) 2012 Guenter Roeck <linux@roeck-us.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * For further information, see the Documentation/spi/sc18is602 file.
+ */
+
+/**
+ * struct sc18is602_platform_data - sc18is602 info
+ * @clock_frequency SC18IS603 oscillator frequency
+ */
+struct sc18is602_platform_data {
+ u32 clock_frequency;
+};