summaryrefslogtreecommitdiffstats
path: root/drivers/spi
diff options
context:
space:
mode:
authorArnd Bergmann <arnd@arndb.de>2012-10-04 22:57:00 +0200
committerArnd Bergmann <arnd@arndb.de>2012-10-04 22:57:51 +0200
commitc37d6154c0b9163c27e53cc1d0be3867b4abd760 (patch)
tree7a24522c56d1cb284dff1d3c225bbdaba0901bb5 /drivers/spi
parente7a570ff7dff9af6e54ff5e580a61ec7652137a0 (diff)
parent8a1ab3155c2ac7fbe5f2038d6e26efeb607a1498 (diff)
Merge branch 'disintegrate-asm-generic' of git://git.infradead.org/users/dhowells/linux-headers into asm-generic
Patches from David Howells <dhowells@redhat.com>: This is to complete part of the UAPI disintegration for which the preparatory patches were pulled recently. Note that there are some fixup patches which are at the base of the branch aimed at you, plus all arches get the asm-generic branch merged in too. * 'disintegrate-asm-generic' of git://git.infradead.org/users/dhowells/linux-headers: UAPI: (Scripted) Disintegrate include/asm-generic UAPI: Fix conditional header installation handling (notably kvm_para.h on m68k) c6x: remove c6x signal.h UAPI: Split compound conditionals containing __KERNEL__ in Arm64 UAPI: Fix the guards on various asm/unistd.h files Signed-off-by: Arnd Bergmann <arnd@arndb.de>
Diffstat (limited to 'drivers/spi')
-rw-r--r--drivers/spi/Kconfig15
-rw-r--r--drivers/spi/Makefile3
-rw-r--r--drivers/spi/spi-altera.c4
-rw-r--r--drivers/spi/spi-au1550.c2
-rw-r--r--drivers/spi/spi-bfin-sport.c2
-rw-r--r--drivers/spi/spi-davinci.c2
-rw-r--r--drivers/spi/spi-ep93xx.c4
-rw-r--r--drivers/spi/spi-gpio.c131
-rw-r--r--drivers/spi/spi-imx.c10
-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-mxs.c674
-rw-r--r--drivers/spi/spi-nuc900.c2
-rw-r--r--drivers/spi/spi-oc-tiny.c2
-rw-r--r--drivers/spi/spi-omap-uwire.c5
-rw-r--r--drivers/spi/spi-omap2-mcspi.c325
-rw-r--r--drivers/spi/spi-orion.c209
-rw-r--r--drivers/spi/spi-pl022.c251
-rw-r--r--drivers/spi/spi-ppc4xx.c4
-rw-r--r--drivers/spi/spi-s3c24xx.c1
-rw-r--r--drivers/spi/spi-s3c64xx.c20
-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.c700
-rw-r--r--drivers/spi/spi-tle62x0.c13
-rw-r--r--drivers/spi/spi-topcliff-pch.c4
28 files changed, 1661 insertions, 1112 deletions
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index 5f84b5563c2..ecc31a1f73f 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
@@ -364,11 +370,12 @@ config SPI_STMP3XXX
help
SPI driver for Freescale STMP37xx/378x SoC SSP interface
-config SPI_TEGRA
- tristate "Nvidia Tegra SPI controller"
- depends on ARCH_TEGRA && (TEGRA_SYSTEM_DMA || TEGRA20_APB_DMA)
+config SPI_MXS
+ tristate "Freescale MXS SPI controller"
+ depends on ARCH_MXS
+ select STMP_DEVICE
help
- SPI driver for NVidia Tegra SoCs
+ SPI driver for Freescale MXS devices.
config SPI_TI_SSP
tristate "TI Sequencer Serial Port - SPI Support"
diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
index 3920dcf4c74..22fd3a7251b 100644
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
@@ -36,6 +36,7 @@ obj-$(CONFIG_SPI_LM70_LLP) += spi-lm70llp.o
obj-$(CONFIG_SPI_MPC512x_PSC) += spi-mpc512x-psc.o
obj-$(CONFIG_SPI_MPC52xx_PSC) += spi-mpc52xx-psc.o
obj-$(CONFIG_SPI_MPC52xx) += spi-mpc52xx.o
+obj-$(CONFIG_SPI_MXS) += spi-mxs.o
obj-$(CONFIG_SPI_NUC900) += spi-nuc900.o
obj-$(CONFIG_SPI_OC_TINY) += spi-oc-tiny.o
obj-$(CONFIG_SPI_OMAP_UWIRE) += spi-omap-uwire.o
@@ -51,13 +52,13 @@ 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
obj-$(CONFIG_SPI_SH_SCI) += spi-sh-sci.o
obj-$(CONFIG_SPI_SIRF) += spi-sirf.o
obj-$(CONFIG_SPI_STMP3XXX) += spi-stmp.o
-obj-$(CONFIG_SPI_TEGRA) += spi-tegra.o
obj-$(CONFIG_SPI_TI_SSP) += spi-ti-ssp.o
obj-$(CONFIG_SPI_TLE62X0) += spi-tle62x0.o
obj-$(CONFIG_SPI_TOPCLIFF_PCH) += spi-topcliff-pch.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-au1550.c b/drivers/spi/spi-au1550.c
index 5784c879961..4de66d1cfe5 100644
--- a/drivers/spi/spi-au1550.c
+++ b/drivers/spi/spi-au1550.c
@@ -475,7 +475,7 @@ static irqreturn_t au1550_spi_dma_irq_callback(struct au1550_spi *hw)
/*
* due to an spi error we consider transfer as done,
* so mask all events until before next transfer start
- * and stop the possibly running dma immediatelly
+ * and stop the possibly running dma immediately
*/
au1550_spi_mask_ack_all(hw);
au1xxx_dbdma_stop(hw->dma_rx_ch);
diff --git a/drivers/spi/spi-bfin-sport.c b/drivers/spi/spi-bfin-sport.c
index 1fe51198a62..6555ecd0730 100644
--- a/drivers/spi/spi-bfin-sport.c
+++ b/drivers/spi/spi-bfin-sport.c
@@ -467,7 +467,7 @@ bfin_sport_spi_pump_transfers(unsigned long data)
dev_dbg(drv_data->dev, "IO write error!\n");
drv_data->state = ERROR_STATE;
} else {
- /* Update total byte transfered */
+ /* Update total byte transferred */
message->actual_length += transfer->len;
/* Move to next transfer of this msg */
drv_data->state = bfin_sport_spi_next_transfer(drv_data);
diff --git a/drivers/spi/spi-davinci.c b/drivers/spi/spi-davinci.c
index 9b2901feaf7..3afe2f4f5b8 100644
--- a/drivers/spi/spi-davinci.c
+++ b/drivers/spi/spi-davinci.c
@@ -30,7 +30,7 @@
#include <linux/spi/spi_bitbang.h>
#include <linux/slab.h>
-#include <mach/spi.h>
+#include <linux/platform_data/spi-davinci.h>
#include <mach/edma.h>
#define SPI_NO_RESOURCE ((resource_size_t)-1)
diff --git a/drivers/spi/spi-ep93xx.c b/drivers/spi/spi-ep93xx.c
index f97f1d24880..3a219599612 100644
--- a/drivers/spi/spi-ep93xx.c
+++ b/drivers/spi/spi-ep93xx.c
@@ -31,8 +31,8 @@
#include <linux/scatterlist.h>
#include <linux/spi/spi.h>
-#include <mach/dma.h>
-#include <mach/ep93xx_spi.h>
+#include <linux/platform_data/dma-ep93xx.h>
+#include <linux/platform_data/spi-ep93xx.h>
#define SSPCR0 0x0000
#define SSPCR0_MODE_SHIFT 6
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-imx.c b/drivers/spi/spi-imx.c
index e834ff8c018..c9a0d8467de 100644
--- a/drivers/spi/spi-imx.c
+++ b/drivers/spi/spi-imx.c
@@ -39,7 +39,7 @@
#include <linux/of_gpio.h>
#include <linux/pinctrl/consumer.h>
-#include <mach/spi.h>
+#include <linux/platform_data/spi-imx.h>
#define DRIVER_NAME "spi_imx"
@@ -97,7 +97,7 @@ struct spi_imx_data {
const void *tx_buf;
unsigned int txfifo; /* number of words pushed in tx FIFO */
- struct spi_imx_devtype_data *devtype_data;
+ const struct spi_imx_devtype_data *devtype_data;
int chipselect[0];
};
@@ -197,6 +197,7 @@ static unsigned int spi_imx_clkdiv_2(unsigned int fin,
#define MX51_ECSPI_CONFIG_SCLKPOL(cs) (1 << ((cs) + 4))
#define MX51_ECSPI_CONFIG_SBBCTRL(cs) (1 << ((cs) + 8))
#define MX51_ECSPI_CONFIG_SSBPOL(cs) (1 << ((cs) + 12))
+#define MX51_ECSPI_CONFIG_SCLKCTL(cs) (1 << ((cs) + 20))
#define MX51_ECSPI_INT 0x10
#define MX51_ECSPI_INT_TEEN (1 << 0)
@@ -287,9 +288,10 @@ static int __maybe_unused mx51_ecspi_config(struct spi_imx_data *spi_imx,
if (config->mode & SPI_CPHA)
cfg |= MX51_ECSPI_CONFIG_SCLKPHA(config->cs);
- if (config->mode & SPI_CPOL)
+ if (config->mode & SPI_CPOL) {
cfg |= MX51_ECSPI_CONFIG_SCLKPOL(config->cs);
-
+ cfg |= MX51_ECSPI_CONFIG_SCLKCTL(config->cs);
+ }
if (config->mode & SPI_CS_HIGH)
cfg |= MX51_ECSPI_CONFIG_SSBPOL(config->cs);
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-mxs.c b/drivers/spi/spi-mxs.c
new file mode 100644
index 00000000000..edf1360ab09
--- /dev/null
+++ b/drivers/spi/spi-mxs.c
@@ -0,0 +1,674 @@
+/*
+ * Freescale MXS SPI master driver
+ *
+ * Copyright 2012 DENX Software Engineering, GmbH.
+ * Copyright 2012 Freescale Semiconductor, Inc.
+ * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
+ *
+ * Rework and transition to new API by:
+ * Marek Vasut <marex@denx.de>
+ *
+ * Based on previous attempt by:
+ * Fabio Estevam <fabio.estevam@freescale.com>
+ *
+ * Based on code from U-Boot bootloader by:
+ * Marek Vasut <marex@denx.de>
+ *
+ * Based on spi-stmp.c, which is:
+ * Author: Dmitry Pervushin <dimka@embeddedalley.com>
+ *
+ * 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.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_gpio.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/dma-mapping.h>
+#include <linux/dmaengine.h>
+#include <linux/highmem.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/completion.h>
+#include <linux/gpio.h>
+#include <linux/regulator/consumer.h>
+#include <linux/module.h>
+#include <linux/pinctrl/consumer.h>
+#include <linux/stmp_device.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/mxs-spi.h>
+
+#define DRIVER_NAME "mxs-spi"
+
+/* Use 10S timeout for very long transfers, it should suffice. */
+#define SSP_TIMEOUT 10000
+
+#define SG_MAXLEN 0xff00
+
+struct mxs_spi {
+ struct mxs_ssp ssp;
+ struct completion c;
+};
+
+static int mxs_spi_setup_transfer(struct spi_device *dev,
+ struct spi_transfer *t)
+{
+ struct mxs_spi *spi = spi_master_get_devdata(dev->master);
+ struct mxs_ssp *ssp = &spi->ssp;
+ uint8_t bits_per_word;
+ uint32_t hz = 0;
+
+ bits_per_word = dev->bits_per_word;
+ if (t && t->bits_per_word)
+ bits_per_word = t->bits_per_word;
+
+ if (bits_per_word != 8) {
+ dev_err(&dev->dev, "%s, unsupported bits_per_word=%d\n",
+ __func__, bits_per_word);
+ return -EINVAL;
+ }
+
+ hz = dev->max_speed_hz;
+ if (t && t->speed_hz)
+ hz = min(hz, t->speed_hz);
+ if (hz == 0) {
+ dev_err(&dev->dev, "Cannot continue with zero clock\n");
+ return -EINVAL;
+ }
+
+ mxs_ssp_set_clk_rate(ssp, hz);
+
+ writel(BF_SSP_CTRL1_SSP_MODE(BV_SSP_CTRL1_SSP_MODE__SPI) |
+ BF_SSP_CTRL1_WORD_LENGTH
+ (BV_SSP_CTRL1_WORD_LENGTH__EIGHT_BITS) |
+ ((dev->mode & SPI_CPOL) ? BM_SSP_CTRL1_POLARITY : 0) |
+ ((dev->mode & SPI_CPHA) ? BM_SSP_CTRL1_PHASE : 0),
+ ssp->base + HW_SSP_CTRL1(ssp));
+
+ writel(0x0, ssp->base + HW_SSP_CMD0);
+ writel(0x0, ssp->base + HW_SSP_CMD1);
+
+ return 0;
+}
+
+static int mxs_spi_setup(struct spi_device *dev)
+{
+ int err = 0;
+
+ if (!dev->bits_per_word)
+ dev->bits_per_word = 8;
+
+ if (dev->mode & ~(SPI_CPOL | SPI_CPHA))
+ return -EINVAL;
+
+ err = mxs_spi_setup_transfer(dev, NULL);
+ if (err) {
+ dev_err(&dev->dev,
+ "Failed to setup transfer, error = %d\n", err);
+ }
+
+ return err;
+}
+
+static uint32_t mxs_spi_cs_to_reg(unsigned cs)
+{
+ uint32_t select = 0;
+
+ /*
+ * i.MX28 Datasheet: 17.10.1: HW_SSP_CTRL0
+ *
+ * The bits BM_SSP_CTRL0_WAIT_FOR_CMD and BM_SSP_CTRL0_WAIT_FOR_IRQ
+ * in HW_SSP_CTRL0 register do have multiple usage, please refer to
+ * the datasheet for further details. In SPI mode, they are used to
+ * toggle the chip-select lines (nCS pins).
+ */
+ if (cs & 1)
+ select |= BM_SSP_CTRL0_WAIT_FOR_CMD;
+ if (cs & 2)
+ select |= BM_SSP_CTRL0_WAIT_FOR_IRQ;
+
+ return select;
+}
+
+static void mxs_spi_set_cs(struct mxs_spi *spi, unsigned cs)
+{
+ const uint32_t mask =
+ BM_SSP_CTRL0_WAIT_FOR_CMD | BM_SSP_CTRL0_WAIT_FOR_IRQ;
+ uint32_t select;
+ struct mxs_ssp *ssp = &spi->ssp;
+
+ writel(mask, ssp->base + HW_SSP_CTRL0 + STMP_OFFSET_REG_CLR);
+ select = mxs_spi_cs_to_reg(cs);
+ writel(select, ssp->base + HW_SSP_CTRL0 + STMP_OFFSET_REG_SET);
+}
+
+static inline void mxs_spi_enable(struct mxs_spi *spi)
+{
+ struct mxs_ssp *ssp = &spi->ssp;
+
+ writel(BM_SSP_CTRL0_LOCK_CS,
+ ssp->base + HW_SSP_CTRL0 + STMP_OFFSET_REG_SET);
+ writel(BM_SSP_CTRL0_IGNORE_CRC,
+ ssp->base + HW_SSP_CTRL0 + STMP_OFFSET_REG_CLR);
+}
+
+static inline void mxs_spi_disable(struct mxs_spi *spi)
+{
+ struct mxs_ssp *ssp = &spi->ssp;
+
+ writel(BM_SSP_CTRL0_LOCK_CS,
+ ssp->base + HW_SSP_CTRL0 + STMP_OFFSET_REG_CLR);
+ writel(BM_SSP_CTRL0_IGNORE_CRC,
+ ssp->base + HW_SSP_CTRL0 + STMP_OFFSET_REG_SET);
+}
+
+static int mxs_ssp_wait(struct mxs_spi *spi, int offset, int mask, bool set)
+{
+ const unsigned long timeout = jiffies + msecs_to_jiffies(SSP_TIMEOUT);
+ struct mxs_ssp *ssp = &spi->ssp;
+ uint32_t reg;
+
+ do {
+ reg = readl_relaxed(ssp->base + offset);
+
+ if (!set)
+ reg = ~reg;
+
+ reg &= mask;
+
+ if (reg == mask)
+ return 0;
+ } while (time_before(jiffies, timeout));
+
+ return -ETIMEDOUT;
+}
+
+static void mxs_ssp_dma_irq_callback(void *param)
+{
+ struct mxs_spi *spi = param;
+ complete(&spi->c);
+}
+
+static irqreturn_t mxs_ssp_irq_handler(int irq, void *dev_id)
+{
+ struct mxs_ssp *ssp = dev_id;
+ dev_err(ssp->dev, "%s[%i] CTRL1=%08x STATUS=%08x\n",
+ __func__, __LINE__,
+ readl(ssp->base + HW_SSP_CTRL1(ssp)),
+ readl(ssp->base + HW_SSP_STATUS(ssp)));
+ return IRQ_HANDLED;
+}
+
+static int mxs_spi_txrx_dma(struct mxs_spi *spi, int cs,
+ unsigned char *buf, int len,
+ int *first, int *last, int write)
+{
+ struct mxs_ssp *ssp = &spi->ssp;
+ struct dma_async_tx_descriptor *desc = NULL;
+ const bool vmalloced_buf = is_vmalloc_addr(buf);
+ const int desc_len = vmalloced_buf ? PAGE_SIZE : SG_MAXLEN;
+ const int sgs = DIV_ROUND_UP(len, desc_len);
+ int sg_count;
+ int min, ret;
+ uint32_t ctrl0;
+ struct page *vm_page;
+ void *sg_buf;
+ struct {
+ uint32_t pio[4];
+ struct scatterlist sg;
+ } *dma_xfer;
+
+ if (!len)
+ return -EINVAL;
+
+ dma_xfer = kzalloc(sizeof(*dma_xfer) * sgs, GFP_KERNEL);
+ if (!dma_xfer)
+ return -ENOMEM;
+
+ INIT_COMPLETION(spi->c);
+
+ ctrl0 = readl(ssp->base + HW_SSP_CTRL0);
+ ctrl0 |= BM_SSP_CTRL0_DATA_XFER | mxs_spi_cs_to_reg(cs);
+
+ if (*first)
+ ctrl0 |= BM_SSP_CTRL0_LOCK_CS;
+ if (!write)
+ ctrl0 |= BM_SSP_CTRL0_READ;
+
+ /* Queue the DMA data transfer. */
+ for (sg_count = 0; sg_count < sgs; sg_count++) {
+ min = min(len, desc_len);
+
+ /* Prepare the transfer descriptor. */
+ if ((sg_count + 1 == sgs) && *last)
+ ctrl0 |= BM_SSP_CTRL0_IGNORE_CRC;
+
+ if (ssp->devid == IMX23_SSP)
+ ctrl0 |= min;
+
+ dma_xfer[sg_count].pio[0] = ctrl0;
+ dma_xfer[sg_count].pio[3] = min;
+
+ if (vmalloced_buf) {
+ vm_page = vmalloc_to_page(buf);
+ if (!vm_page) {
+ ret = -ENOMEM;
+ goto err_vmalloc;
+ }
+ sg_buf = page_address(vm_page) +
+ ((size_t)buf & ~PAGE_MASK);
+ } else {
+ sg_buf = buf;
+ }
+
+ sg_init_one(&dma_xfer[sg_count].sg, sg_buf, min);
+ ret = dma_map_sg(ssp->dev, &dma_xfer[sg_count].sg, 1,
+ write ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
+
+ len -= min;
+ buf += min;
+
+ /* Queue the PIO register write transfer. */
+ desc = dmaengine_prep_slave_sg(ssp->dmach,
+ (struct scatterlist *)dma_xfer[sg_count].pio,
+ (ssp->devid == IMX23_SSP) ? 1 : 4,
+ DMA_TRANS_NONE,
+ sg_count ? DMA_PREP_INTERRUPT : 0);
+ if (!desc) {
+ dev_err(ssp->dev,
+ "Failed to get PIO reg. write descriptor.\n");
+ ret = -EINVAL;
+ goto err_mapped;
+ }
+
+ desc = dmaengine_prep_slave_sg(ssp->dmach,
+ &dma_xfer[sg_count].sg, 1,
+ write ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM,
+ DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+
+ if (!desc) {
+ dev_err(ssp->dev,
+ "Failed to get DMA data write descriptor.\n");
+ ret = -EINVAL;
+ goto err_mapped;
+ }
+ }
+
+ /*
+ * The last descriptor must have this callback,
+ * to finish the DMA transaction.
+ */
+ desc->callback = mxs_ssp_dma_irq_callback;
+ desc->callback_param = spi;
+
+ /* Start the transfer. */
+ dmaengine_submit(desc);
+ dma_async_issue_pending(ssp->dmach);
+
+ ret = wait_for_completion_timeout(&spi->c,
+ msecs_to_jiffies(SSP_TIMEOUT));
+ if (!ret) {
+ dev_err(ssp->dev, "DMA transfer timeout\n");
+ ret = -ETIMEDOUT;
+ goto err_vmalloc;
+ }
+
+ ret = 0;
+
+err_vmalloc:
+ while (--sg_count >= 0) {
+err_mapped:
+ dma_unmap_sg(ssp->dev, &dma_xfer[sg_count].sg, 1,
+ write ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
+ }
+
+ kfree(dma_xfer);
+
+ return ret;
+}
+
+static int mxs_spi_txrx_pio(struct mxs_spi *spi, int cs,
+ unsigned char *buf, int len,
+ int *first, int *last, int write)
+{
+ struct mxs_ssp *ssp = &spi->ssp;
+
+ if (*first)
+ mxs_spi_enable(spi);
+
+ mxs_spi_set_cs(spi, cs);
+
+ while (len--) {
+ if (*last && len == 0)
+ mxs_spi_disable(spi);
+
+ if (ssp->devid == IMX23_SSP) {
+ writel(BM_SSP_CTRL0_XFER_COUNT,
+ ssp->base + HW_SSP_CTRL0 + STMP_OFFSET_REG_CLR);
+ writel(1,
+ ssp->base + HW_SSP_CTRL0 + STMP_OFFSET_REG_SET);
+ } else {
+ writel(1, ssp->base + HW_SSP_XFER_SIZE);
+ }
+
+ if (write)
+ writel(BM_SSP_CTRL0_READ,
+ ssp->base + HW_SSP_CTRL0 + STMP_OFFSET_REG_CLR);
+ else
+ writel(BM_SSP_CTRL0_READ,
+ ssp->base + HW_SSP_CTRL0 + STMP_OFFSET_REG_SET);
+
+ writel(BM_SSP_CTRL0_RUN,
+ ssp->base + HW_SSP_CTRL0 + STMP_OFFSET_REG_SET);
+
+ if (mxs_ssp_wait(spi, HW_SSP_CTRL0, BM_SSP_CTRL0_RUN, 1))
+ return -ETIMEDOUT;
+
+ if (write)
+ writel(*buf, ssp->base + HW_SSP_DATA(ssp));
+
+ writel(BM_SSP_CTRL0_DATA_XFER,
+ ssp->base + HW_SSP_CTRL0 + STMP_OFFSET_REG_SET);
+
+ if (!write) {
+ if (mxs_ssp_wait(spi, HW_SSP_STATUS(ssp),
+ BM_SSP_STATUS_FIFO_EMPTY, 0))
+ return -ETIMEDOUT;
+
+ *buf = (readl(ssp->base + HW_SSP_DATA(ssp)) & 0xff);
+ }
+
+ if (mxs_ssp_wait(spi, HW_SSP_CTRL0, BM_SSP_CTRL0_RUN, 0))
+ return -ETIMEDOUT;
+
+ buf++;
+ }
+
+ if (len <= 0)
+ return 0;
+
+ return -ETIMEDOUT;
+}
+
+static int mxs_spi_transfer_one(struct spi_master *master,
+ struct spi_message *m)
+{
+ struct mxs_spi *spi = spi_master_get_devdata(master);
+ struct mxs_ssp *ssp = &spi->ssp;
+ int first, last;
+ struct spi_transfer *t, *tmp_t;
+ int status = 0;
+ int cs;
+
+ first = last = 0;
+
+ cs = m->spi->chip_select;
+
+ list_for_each_entry_safe(t, tmp_t, &m->transfers, transfer_list) {
+
+ status = mxs_spi_setup_transfer(m->spi, t);
+ if (status)
+ break;
+
+ if (&t->transfer_list == m->transfers.next)
+ first = 1;
+ if (&t->transfer_list == m->transfers.prev)
+ last = 1;
+ if ((t->rx_buf && t->tx_buf) || (t->rx_dma && t->tx_dma)) {
+ dev_err(ssp->dev,
+ "Cannot send and receive simultaneously\n");
+ status = -EINVAL;
+ break;
+ }
+
+ /*
+ * Small blocks can be transfered via PIO.
+ * Measured by empiric means:
+ *
+ * dd if=/dev/mtdblock0 of=/dev/null bs=1024k count=1
+ *
+ * DMA only: 2.164808 seconds, 473.0KB/s
+ * Combined: 1.676276 seconds, 610.9KB/s
+ */
+ if (t->len < 32) {
+ writel(BM_SSP_CTRL1_DMA_ENABLE,
+ ssp->base + HW_SSP_CTRL1(ssp) +
+ STMP_OFFSET_REG_CLR);
+
+ if (t->tx_buf)
+ status = mxs_spi_txrx_pio(spi, cs,
+ (void *)t->tx_buf,
+ t->len, &first, &last, 1);
+ if (t->rx_buf)
+ status = mxs_spi_txrx_pio(spi, cs,
+ t->rx_buf, t->len,
+ &first, &last, 0);
+ } else {
+ writel(BM_SSP_CTRL1_DMA_ENABLE,
+ ssp->base + HW_SSP_CTRL1(ssp) +
+ STMP_OFFSET_REG_SET);
+
+ if (t->tx_buf)
+ status = mxs_spi_txrx_dma(spi, cs,
+ (void *)t->tx_buf, t->len,
+ &first, &last, 1);
+ if (t->rx_buf)
+ status = mxs_spi_txrx_dma(spi, cs,
+ t->rx_buf, t->len,
+ &first, &last, 0);
+ }
+
+ if (status) {
+ stmp_reset_block(ssp->base);
+ break;
+ }
+
+ m->actual_length += t->len;
+ first = last = 0;
+ }
+
+ m->status = 0;
+ spi_finalize_current_message(master);
+
+ return status;
+}
+
+static bool mxs_ssp_dma_filter(struct dma_chan *chan, void *param)
+{
+ struct mxs_ssp *ssp = param;
+
+ if (!mxs_dma_is_apbh(chan))
+ return false;
+
+ if (chan->chan_id != ssp->dma_channel)
+ return false;
+
+ chan->private = &ssp->dma_data;
+
+ return true;
+}
+
+static const struct of_device_id mxs_spi_dt_ids[] = {
+ { .compatible = "fsl,imx23-spi", .data = (void *) IMX23_SSP, },
+ { .compatible = "fsl,imx28-spi", .data = (void *) IMX28_SSP, },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, mxs_spi_dt_ids);
+
+static int __devinit mxs_spi_probe(struct platform_device *pdev)
+{
+ const struct of_device_id *of_id =
+ of_match_device(mxs_spi_dt_ids, &pdev->dev);
+ struct device_node *np = pdev->dev.of_node;
+ struct spi_master *master;
+ struct mxs_spi *spi;
+ struct mxs_ssp *ssp;
+ struct resource *iores, *dmares;
+ struct pinctrl *pinctrl;
+ struct clk *clk;
+ void __iomem *base;
+ int devid, dma_channel, clk_freq;
+ int ret = 0, irq_err, irq_dma;
+ dma_cap_mask_t mask;
+
+ /*
+ * Default clock speed for the SPI core. 160MHz seems to
+ * work reasonably well with most SPI flashes, so use this
+ * as a default. Override with "clock-frequency" DT prop.
+ */
+ const int clk_freq_default = 160000000;
+
+ iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ irq_err = platform_get_irq(pdev, 0);
+ irq_dma = platform_get_irq(pdev, 1);
+ if (!iores || irq_err < 0 || irq_dma < 0)
+ return -EINVAL;
+
+ base = devm_request_and_ioremap(&pdev->dev, iores);
+ if (!base)
+ return -EADDRNOTAVAIL;
+
+ pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
+ if (IS_ERR(pinctrl))
+ return PTR_ERR(pinctrl);
+
+ clk = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(clk))
+ return PTR_ERR(clk);
+
+ if (np) {
+ devid = (enum mxs_ssp_id) of_id->data;
+ /*
+ * TODO: This is a temporary solution and should be changed
+ * to use generic DMA binding later when the helpers get in.
+ */
+ ret = of_property_read_u32(np, "fsl,ssp-dma-channel",
+ &dma_channel);
+ if (ret) {
+ dev_err(&pdev->dev,
+ "Failed to get DMA channel\n");
+ return -EINVAL;
+ }
+
+ ret = of_property_read_u32(np, "clock-frequency",
+ &clk_freq);
+ if (ret)
+ clk_freq = clk_freq_default;
+ } else {
+ dmares = platform_get_resource(pdev, IORESOURCE_DMA, 0);
+ if (!dmares)
+ return -EINVAL;
+ devid = pdev->id_entry->driver_data;
+ dma_channel = dmares->start;
+ clk_freq = clk_freq_default;
+ }
+
+ master = spi_alloc_master(&pdev->dev, sizeof(*spi));
+ if (!master)
+ return -ENOMEM;
+
+ master->transfer_one_message = mxs_spi_transfer_one;
+ master->setup = mxs_spi_setup;
+ master->mode_bits = SPI_CPOL | SPI_CPHA;
+ master->num_chipselect = 3;
+ master->dev.of_node = np;
+ master->flags = SPI_MASTER_HALF_DUPLEX;
+
+ spi = spi_master_get_devdata(master);
+ ssp = &spi->ssp;
+ ssp->dev = &pdev->dev;
+ ssp->clk = clk;
+ ssp->base = base;
+ ssp->devid = devid;
+ ssp->dma_channel = dma_channel;
+
+ init_completion(&spi->c);
+
+ ret = devm_request_irq(&pdev->dev, irq_err, mxs_ssp_irq_handler, 0,
+ DRIVER_NAME, ssp);
+ if (ret)
+ goto out_master_free;
+
+ dma_cap_zero(mask);
+ dma_cap_set(DMA_SLAVE, mask);
+ ssp->dma_data.chan_irq = irq_dma;
+ ssp->dmach = dma_request_channel(mask, mxs_ssp_dma_filter, ssp);
+ if (!ssp->dmach) {
+ dev_err(ssp->dev, "Failed to request DMA\n");
+ goto out_master_free;
+ }
+
+ clk_prepare_enable(ssp->clk);
+ clk_set_rate(ssp->clk, clk_freq);
+ ssp->clk_rate = clk_get_rate(ssp->clk) / 1000;
+
+ stmp_reset_block(ssp->base);
+
+ platform_set_drvdata(pdev, master);
+
+ ret = spi_register_master(master);
+ if (ret) {
+ dev_err(&pdev->dev, "Cannot register SPI master, %d\n", ret);
+ goto out_free_dma;
+ }
+
+ return 0;
+
+out_free_dma:
+ dma_release_channel(ssp->dmach);
+ clk_disable_unprepare(ssp->clk);
+out_master_free:
+ spi_master_put(master);
+ return ret;
+}
+
+static int __devexit mxs_spi_remove(struct platform_device *pdev)
+{
+ struct spi_master *master;
+ struct mxs_spi *spi;
+ struct mxs_ssp *ssp;
+
+ master = spi_master_get(platform_get_drvdata(pdev));
+ spi = spi_master_get_devdata(master);
+ ssp = &spi->ssp;
+
+ spi_unregister_master(master);
+
+ dma_release_channel(ssp->dmach);
+
+ clk_disable_unprepare(ssp->clk);
+
+ spi_master_put(master);
+
+ return 0;
+}
+
+static struct platform_driver mxs_spi_driver = {
+ .probe = mxs_spi_probe,
+ .remove = __devexit_p(mxs_spi_remove),
+ .driver = {
+ .name = DRIVER_NAME,
+ .owner = THIS_MODULE,
+ .of_match_table = mxs_spi_dt_ids,
+ },
+};
+
+module_platform_driver(mxs_spi_driver);
+
+MODULE_AUTHOR("Marek Vasut <marex@denx.de>");
+MODULE_DESCRIPTION("MXS SPI master driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:mxs-spi");
diff --git a/drivers/spi/spi-nuc900.c b/drivers/spi/spi-nuc900.c
index dae8be229c5..a6eca6ffdab 100644
--- a/drivers/spi/spi-nuc900.c
+++ b/drivers/spi/spi-nuc900.c
@@ -26,7 +26,7 @@
#include <linux/spi/spi.h>
#include <linux/spi/spi_bitbang.h>
-#include <mach/nuc900_spi.h>
+#include <linux/platform_data/spi-nuc900.h>
/* usi registers offset */
#define USI_CNT 0x00
diff --git a/drivers/spi/spi-oc-tiny.c b/drivers/spi/spi-oc-tiny.c
index 698018fd992..9d9071b730b 100644
--- a/drivers/spi/spi-oc-tiny.c
+++ b/drivers/spi/spi-oc-tiny.c
@@ -129,7 +129,7 @@ static int tiny_spi_txrx_bufs(struct spi_device *spi, struct spi_transfer *t)
unsigned int i;
if (hw->irq >= 0) {
- /* use intrrupt driven data transfer */
+ /* use interrupt driven data transfer */
hw->len = t->len;
hw->txp = t->tx_buf;
hw->rxp = t->rx_buf;
diff --git a/drivers/spi/spi-omap-uwire.c b/drivers/spi/spi-omap-uwire.c
index 9b0d7169603..0a94d9dc9c3 100644
--- a/drivers/spi/spi-omap-uwire.c
+++ b/drivers/spi/spi-omap-uwire.c
@@ -52,8 +52,9 @@
#include <asm/io.h>
#include <asm/mach-types.h>
-#include <plat/mux.h>
-#include <plat/omap7xx.h> /* OMAP7XX_IO_CONF registers */
+#include <mach/mux.h>
+
+#include <mach/omap7xx.h> /* OMAP7XX_IO_CONF registers */
/* FIXME address is now a platform device resource,
diff --git a/drivers/spi/spi-omap2-mcspi.c b/drivers/spi/spi-omap2-mcspi.c
index b2fb141da37..474e2174e08 100644
--- a/drivers/spi/spi-omap2-mcspi.c
+++ b/drivers/spi/spi-omap2-mcspi.c
@@ -38,11 +38,13 @@
#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>
#include <plat/clock.h>
-#include <plat/mcspi.h>
+#include <linux/platform_data/spi-omap2-mcspi.h>
#define OMAP2_MCSPI_MAX_FREQ 48000000
#define SPI_AUTOSUSPEND_TIMEOUT 2000
@@ -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;
}
@@ -1116,7 +1142,7 @@ MODULE_DEVICE_TABLE(of, omap_mcspi_of_match);
static int __devinit omap2_mcspi_probe(struct platform_device *pdev)
{
struct spi_master *master;
- struct omap2_mcspi_platform_config *pdata;
+ const struct omap2_mcspi_platform_config *pdata;
struct omap2_mcspi *mcspi;
struct resource *r;
int status = 0, i;
@@ -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..919464102d3 100644
--- a/drivers/spi/spi-pl022.c
+++ b/drivers/spi/spi-pl022.c
@@ -1,7 +1,7 @@
/*
* A driver for the ARM PL022 PrimeCell SSP/SPI bus master.
*
- * Copyright (C) 2008-2009 ST-Ericsson AB
+ * Copyright (C) 2008-2012 ST-Ericsson AB
* Copyright (C) 2006 STMicroelectronics Pvt. Ltd.
*
* Author: Linus Walleij <linus.walleij@stericsson.com>
@@ -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,22 +2064,31 @@ 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");
- status = -ENODEV;
- goto err_no_pdata;
+ 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");
+ return -ENODEV;
+ }
+
+ if (platform_info->num_chipselect) {
+ num_cs = platform_info->num_chipselect;
+ } else {
+ dev_err(dev, "probe: no chip select defined\n");
+ return -ENODEV;
}
/* Allocate master with space for data */
master = spi_alloc_master(dev, sizeof(struct pl022));
if (master == NULL) {
dev_err(&adev->dev, "probe - cannot alloc SPI master\n");
- status = -ENOMEM;
- goto err_no_master;
+ return -ENOMEM;
}
pl022 = spi_master_get_devdata(master);
@@ -2016,19 +2096,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 (devm_gpio_request(dev, 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
@@ -2045,7 +2177,8 @@ pl022_probe(struct amba_device *adev, const struct amba_id *id)
goto err_no_ioregion;
pl022->phybase = adev->res.start;
- pl022->virtbase = ioremap(adev->res.start, resource_size(&adev->res));
+ pl022->virtbase = devm_ioremap(dev, adev->res.start,
+ resource_size(&adev->res));
if (pl022->virtbase == NULL) {
status = -ENOMEM;
goto err_no_ioremap;
@@ -2055,7 +2188,7 @@ pl022_probe(struct amba_device *adev, const struct amba_id *id)
pm_runtime_resume(dev);
- pl022->clk = clk_get(&adev->dev, NULL);
+ pl022->clk = devm_clk_get(&adev->dev, NULL);
if (IS_ERR(pl022->clk)) {
status = PTR_ERR(pl022->clk);
dev_err(&adev->dev, "could not retrieve SSP/SPI bus clock\n");
@@ -2083,8 +2216,8 @@ pl022_probe(struct amba_device *adev, const struct amba_id *id)
SSP_CR1(pl022->virtbase));
load_ssp_default_config(pl022);
- status = request_irq(adev->irq[0], pl022_interrupt_handler, 0, "pl022",
- pl022);
+ status = devm_request_irq(dev, adev->irq[0], pl022_interrupt_handler,
+ 0, "pl022", pl022);
if (status < 0) {
dev_err(&adev->dev, "probe - cannot get IRQ (%d)\n", status);
goto err_no_irq;
@@ -2124,22 +2257,18 @@ pl022_probe(struct amba_device *adev, const struct amba_id *id)
err_spi_register:
if (platform_info->enable_dma)
pl022_dma_remove(pl022);
-
- free_irq(adev->irq[0], pl022);
err_no_irq:
clk_disable(pl022->clk);
err_no_clk_en:
clk_unprepare(pl022->clk);
err_clk_prep:
- clk_put(pl022->clk);
err_no_clk:
- iounmap(pl022->virtbase);
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:
return status;
}
@@ -2161,20 +2290,55 @@ pl022_remove(struct amba_device *adev)
if (pl022->master_info->enable_dma)
pl022_dma_remove(pl022);
- free_irq(adev->irq[0], pl022);
clk_disable(pl022->clk);
clk_unprepare(pl022->clk);
- clk_put(pl022->clk);
pm_runtime_disable(&adev->dev);
- iounmap(pl022->virtbase);
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;
}
+#if defined(CONFIG_SUSPEND) || defined(CONFIG_PM_RUNTIME)
+/*
+ * These two functions are used from both suspend/resume and
+ * the runtime counterparts to handle external resources like
+ * clocks, pins and regulators when going to sleep.
+ */
+static void pl022_suspend_resources(struct pl022 *pl022)
+{
+ int ret;
+
+ clk_disable(pl022->clk);
+
+ /* Optionally let pins go into sleep states */
+ if (!IS_ERR(pl022->pins_sleep)) {
+ ret = pinctrl_select_state(pl022->pinctrl,
+ pl022->pins_sleep);
+ if (ret)
+ dev_err(&pl022->adev->dev,
+ "could not set pins to sleep state\n");
+ }
+}
+
+static void pl022_resume_resources(struct pl022 *pl022)
+{
+ int ret;
+
+ /* Optionaly enable pins to be muxed in and configured */
+ if (!IS_ERR(pl022->pins_default)) {
+ ret = pinctrl_select_state(pl022->pinctrl,
+ pl022->pins_default);
+ if (ret)
+ dev_err(&pl022->adev->dev,
+ "could not set default pins\n");
+ }
+
+ clk_enable(pl022->clk);
+}
+#endif
+
#ifdef CONFIG_SUSPEND
static int pl022_suspend(struct device *dev)
{
@@ -2186,6 +2350,7 @@ static int pl022_suspend(struct device *dev)
dev_warn(dev, "cannot suspend master\n");
return ret;
}
+ pl022_suspend_resources(pl022);
dev_dbg(dev, "suspended\n");
return 0;
@@ -2196,6 +2361,8 @@ static int pl022_resume(struct device *dev)
struct pl022 *pl022 = dev_get_drvdata(dev);
int ret;
+ pl022_resume_resources(pl022);
+
/* Start the queue running */
ret = spi_master_resume(pl022->master);
if (ret)
@@ -2212,8 +2379,7 @@ static int pl022_runtime_suspend(struct device *dev)
{
struct pl022 *pl022 = dev_get_drvdata(dev);
- clk_disable(pl022->clk);
-
+ pl022_suspend_resources(pl022);
return 0;
}
@@ -2221,8 +2387,7 @@ static int pl022_runtime_resume(struct device *dev)
{
struct pl022 *pl022 = dev_get_drvdata(dev);
- clk_enable(pl022->clk);
-
+ pl022_resume_resources(pl022);
return 0;
}
#endif
diff --git a/drivers/spi/spi-ppc4xx.c b/drivers/spi/spi-ppc4xx.c
index 75ac9d48ef4..7a85f22b647 100644
--- a/drivers/spi/spi-ppc4xx.c
+++ b/drivers/spi/spi-ppc4xx.c
@@ -101,7 +101,7 @@ struct spi_ppc4xx_regs {
u8 dummy;
/*
* Clock divisor modulus register
- * This uses the follwing formula:
+ * This uses the following formula:
* SCPClkOut = OPBCLK/(4(CDM + 1))
* or
* CDM = (OPBCLK/4*SCPClkOut) - 1
@@ -201,7 +201,7 @@ static int spi_ppc4xx_setupxfer(struct spi_device *spi, struct spi_transfer *t)
return -EINVAL;
}
- /* Write new configration */
+ /* Write new configuration */
out_8(&hw->regs->mode, cs->mode);
/* Set the clock */
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..1a81c90a4a7 100644
--- a/drivers/spi/spi-s3c64xx.c
+++ b/drivers/spi/spi-s3c64xx.c
@@ -32,7 +32,7 @@
#include <linux/of_gpio.h>
#include <mach/dma.h>
-#include <plat/s3c64xx-spi.h>
+#include <linux/platform_data/spi-s3c64xx.h>
#define MAX_SPI_PORTS 3
@@ -835,9 +835,7 @@ static struct s3c64xx_spi_csinfo *s3c64xx_get_slave_ctrldata(
return ERR_PTR(-EINVAL);
}
- for_each_child_of_node(slave_np, data_np)
- if (!strcmp(data_np->name, "controller-data"))
- break;
+ data_np = of_get_child_by_name(slave_np, "controller-data");
if (!data_np) {
dev_err(&spi->dev, "child node 'controller-data' not found\n");
return ERR_PTR(-EINVAL);
@@ -847,6 +845,7 @@ static struct s3c64xx_spi_csinfo *s3c64xx_get_slave_ctrldata(
if (!cs) {
dev_err(&spi->dev, "could not allocate memory for controller"
" data\n");
+ of_node_put(data_np);
return ERR_PTR(-ENOMEM);
}
@@ -855,11 +854,13 @@ static struct s3c64xx_spi_csinfo *s3c64xx_get_slave_ctrldata(
dev_err(&spi->dev, "chip select gpio is not specified or "
"invalid\n");
kfree(cs);
+ of_node_put(data_np);
return ERR_PTR(-EINVAL);
}
of_property_read_u32(data_np, "samsung,spi-feedback-delay", &fb_delay);
cs->fb_delay = fb_delay;
+ of_node_put(data_np);
return cs;
}
@@ -976,7 +977,8 @@ err_msgq:
spi_set_ctldata(spi, NULL);
err_gpio_req:
- kfree(cs);
+ if (spi->dev.of_node)
+ kfree(cs);
return err;
}
@@ -1409,7 +1411,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 +1430,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 +1454,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 +1465,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
deleted file mode 100644
index ef52c1c6f5c..00000000000
--- a/drivers/spi/spi-tegra.c
+++ /dev/null
@@ -1,700 +0,0 @@
-/*
- * Driver for Nvidia TEGRA spi controller.
- *
- * Copyright (C) 2010 Google, Inc.
- *
- * Author:
- * Erik Gilling <konkers@android.com>
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * 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.
- *
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/err.h>
-#include <linux/platform_device.h>
-#include <linux/io.h>
-#include <linux/dma-mapping.h>
-#include <linux/dmapool.h>
-#include <linux/clk.h>
-#include <linux/interrupt.h>
-#include <linux/delay.h>
-
-#include <linux/spi/spi.h>
-#include <linux/dmaengine.h>
-
-#include <mach/dma.h>
-
-#define SLINK_COMMAND 0x000
-#define SLINK_BIT_LENGTH(x) (((x) & 0x1f) << 0)
-#define SLINK_WORD_SIZE(x) (((x) & 0x1f) << 5)
-#define SLINK_BOTH_EN (1 << 10)
-#define SLINK_CS_SW (1 << 11)
-#define SLINK_CS_VALUE (1 << 12)
-#define SLINK_CS_POLARITY (1 << 13)
-#define SLINK_IDLE_SDA_DRIVE_LOW (0 << 16)
-#define SLINK_IDLE_SDA_DRIVE_HIGH (1 << 16)
-#define SLINK_IDLE_SDA_PULL_LOW (2 << 16)
-#define SLINK_IDLE_SDA_PULL_HIGH (3 << 16)
-#define SLINK_IDLE_SDA_MASK (3 << 16)
-#define SLINK_CS_POLARITY1 (1 << 20)
-#define SLINK_CK_SDA (1 << 21)
-#define SLINK_CS_POLARITY2 (1 << 22)
-#define SLINK_CS_POLARITY3 (1 << 23)
-#define SLINK_IDLE_SCLK_DRIVE_LOW (0 << 24)
-#define SLINK_IDLE_SCLK_DRIVE_HIGH (1 << 24)
-#define SLINK_IDLE_SCLK_PULL_LOW (2 << 24)
-#define SLINK_IDLE_SCLK_PULL_HIGH (3 << 24)
-#define SLINK_IDLE_SCLK_MASK (3 << 24)
-#define SLINK_M_S (1 << 28)
-#define SLINK_WAIT (1 << 29)
-#define SLINK_GO (1 << 30)
-#define SLINK_ENB (1 << 31)
-
-#define SLINK_COMMAND2 0x004
-#define SLINK_LSBFE (1 << 0)
-#define SLINK_SSOE (1 << 1)
-#define SLINK_SPIE (1 << 4)
-#define SLINK_BIDIROE (1 << 6)
-#define SLINK_MODFEN (1 << 7)
-#define SLINK_INT_SIZE(x) (((x) & 0x1f) << 8)
-#define SLINK_CS_ACTIVE_BETWEEN (1 << 17)
-#define SLINK_SS_EN_CS(x) (((x) & 0x3) << 18)
-#define SLINK_SS_SETUP(x) (((x) & 0x3) << 20)
-#define SLINK_FIFO_REFILLS_0 (0 << 22)
-#define SLINK_FIFO_REFILLS_1 (1 << 22)
-#define SLINK_FIFO_REFILLS_2 (2 << 22)
-#define SLINK_FIFO_REFILLS_3 (3 << 22)
-#define SLINK_FIFO_REFILLS_MASK (3 << 22)
-#define SLINK_WAIT_PACK_INT(x) (((x) & 0x7) << 26)
-#define SLINK_SPC0 (1 << 29)
-#define SLINK_TXEN (1 << 30)
-#define SLINK_RXEN (1 << 31)
-
-#define SLINK_STATUS 0x008
-#define SLINK_COUNT(val) (((val) >> 0) & 0x1f)
-#define SLINK_WORD(val) (((val) >> 5) & 0x1f)
-#define SLINK_BLK_CNT(val) (((val) >> 0) & 0xffff)
-#define SLINK_MODF (1 << 16)
-#define SLINK_RX_UNF (1 << 18)
-#define SLINK_TX_OVF (1 << 19)
-#define SLINK_TX_FULL (1 << 20)
-#define SLINK_TX_EMPTY (1 << 21)
-#define SLINK_RX_FULL (1 << 22)
-#define SLINK_RX_EMPTY (1 << 23)
-#define SLINK_TX_UNF (1 << 24)
-#define SLINK_RX_OVF (1 << 25)
-#define SLINK_TX_FLUSH (1 << 26)
-#define SLINK_RX_FLUSH (1 << 27)
-#define SLINK_SCLK (1 << 28)
-#define SLINK_ERR (1 << 29)
-#define SLINK_RDY (1 << 30)
-#define SLINK_BSY (1 << 31)
-
-#define SLINK_MAS_DATA 0x010
-#define SLINK_SLAVE_DATA 0x014
-
-#define SLINK_DMA_CTL 0x018
-#define SLINK_DMA_BLOCK_SIZE(x) (((x) & 0xffff) << 0)
-#define SLINK_TX_TRIG_1 (0 << 16)
-#define SLINK_TX_TRIG_4 (1 << 16)
-#define SLINK_TX_TRIG_8 (2 << 16)
-#define SLINK_TX_TRIG_16 (3 << 16)
-#define SLINK_TX_TRIG_MASK (3 << 16)
-#define SLINK_RX_TRIG_1 (0 << 18)
-#define SLINK_RX_TRIG_4 (1 << 18)
-#define SLINK_RX_TRIG_8 (2 << 18)
-#define SLINK_RX_TRIG_16 (3 << 18)
-#define SLINK_RX_TRIG_MASK (3 << 18)
-#define SLINK_PACKED (1 << 20)
-#define SLINK_PACK_SIZE_4 (0 << 21)
-#define SLINK_PACK_SIZE_8 (1 << 21)
-#define SLINK_PACK_SIZE_16 (2 << 21)
-#define SLINK_PACK_SIZE_32 (3 << 21)
-#define SLINK_PACK_SIZE_MASK (3 << 21)
-#define SLINK_IE_TXC (1 << 26)
-#define SLINK_IE_RXC (1 << 27)
-#define SLINK_DMA_EN (1 << 31)
-
-#define SLINK_STATUS2 0x01c
-#define SLINK_TX_FIFO_EMPTY_COUNT(val) (((val) & 0x3f) >> 0)
-#define SLINK_RX_FIFO_FULL_COUNT(val) (((val) & 0x3f) >> 16)
-
-#define SLINK_TX_FIFO 0x100
-#define SLINK_RX_FIFO 0x180
-
-static const unsigned long spi_tegra_req_sels[] = {
- TEGRA_DMA_REQ_SEL_SL2B1,
- TEGRA_DMA_REQ_SEL_SL2B2,
- TEGRA_DMA_REQ_SEL_SL2B3,
- TEGRA_DMA_REQ_SEL_SL2B4,
-};
-
-#define BB_LEN 32
-
-struct spi_tegra_data {
- struct spi_master *master;
- struct platform_device *pdev;
- spinlock_t lock;
-
- struct clk *clk;
- void __iomem *base;
- unsigned long phys;
-
- u32 cur_speed;
-
- struct list_head queue;
- struct spi_transfer *cur;
- unsigned cur_pos;
- unsigned cur_len;
- unsigned cur_bytes_per_word;
-
- /* The tegra spi controller has a bug which causes the first word
- * in PIO transactions to be garbage. Since packed DMA transactions
- * require transfers to be 4 byte aligned we need a bounce buffer
- * for the generic case.
- */
- int dma_req_len;
-#if defined(CONFIG_TEGRA_SYSTEM_DMA)
- struct tegra_dma_req rx_dma_req;
- struct tegra_dma_channel *rx_dma;
-#else
- struct dma_chan *rx_dma;
- struct dma_slave_config sconfig;
- struct dma_async_tx_descriptor *rx_dma_desc;
- dma_cookie_t rx_cookie;
-#endif
- u32 *rx_bb;
- dma_addr_t rx_bb_phys;
-};
-
-#if !defined(CONFIG_TEGRA_SYSTEM_DMA)
-static void tegra_spi_rx_dma_complete(void *args);
-#endif
-
-static inline unsigned long spi_tegra_readl(struct spi_tegra_data *tspi,
- unsigned long reg)
-{
- return readl(tspi->base + reg);
-}
-
-static inline void spi_tegra_writel(struct spi_tegra_data *tspi,
- unsigned long val,
- unsigned long reg)
-{
- writel(val, tspi->base + reg);
-}
-
-static void spi_tegra_go(struct spi_tegra_data *tspi)
-{
- unsigned long val;
-
- wmb();
-
- val = spi_tegra_readl(tspi, SLINK_DMA_CTL);
- val &= ~SLINK_DMA_BLOCK_SIZE(~0) & ~SLINK_DMA_EN;
- val |= SLINK_DMA_BLOCK_SIZE(tspi->dma_req_len / 4 - 1);
- spi_tegra_writel(tspi, val, SLINK_DMA_CTL);
-#if defined(CONFIG_TEGRA_SYSTEM_DMA)
- tspi->rx_dma_req.size = tspi->dma_req_len;
- tegra_dma_enqueue_req(tspi->rx_dma, &tspi->rx_dma_req);
-#else
- tspi->rx_dma_desc = dmaengine_prep_slave_single(tspi->rx_dma,
- tspi->rx_bb_phys, tspi->dma_req_len,
- DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT);
- if (!tspi->rx_dma_desc) {
- dev_err(&tspi->pdev->dev, "dmaengine slave prep failed\n");
- return;
- }
- tspi->rx_dma_desc->callback = tegra_spi_rx_dma_complete;
- tspi->rx_dma_desc->callback_param = tspi;
- tspi->rx_cookie = dmaengine_submit(tspi->rx_dma_desc);
- dma_async_issue_pending(tspi->rx_dma);
-#endif
-
- val |= SLINK_DMA_EN;
- spi_tegra_writel(tspi, val, SLINK_DMA_CTL);
-}
-
-static unsigned spi_tegra_fill_tx_fifo(struct spi_tegra_data *tspi,
- struct spi_transfer *t)
-{
- unsigned len = min(t->len - tspi->cur_pos, BB_LEN *
- tspi->cur_bytes_per_word);
- u8 *tx_buf = (u8 *)t->tx_buf + tspi->cur_pos;
- int i, j;
- unsigned long val;
-
- val = spi_tegra_readl(tspi, SLINK_COMMAND);
- val &= ~SLINK_WORD_SIZE(~0);
- val |= SLINK_WORD_SIZE(len / tspi->cur_bytes_per_word - 1);
- spi_tegra_writel(tspi, val, SLINK_COMMAND);
-
- for (i = 0; i < len; i += tspi->cur_bytes_per_word) {
- val = 0;
- for (j = 0; j < tspi->cur_bytes_per_word; j++)
- val |= tx_buf[i + j] << j * 8;
-
- spi_tegra_writel(tspi, val, SLINK_TX_FIFO);
- }
-
- tspi->dma_req_len = len / tspi->cur_bytes_per_word * 4;
-
- return len;
-}
-
-static unsigned spi_tegra_drain_rx_fifo(struct spi_tegra_data *tspi,
- struct spi_transfer *t)
-{
- unsigned len = tspi->cur_len;
- u8 *rx_buf = (u8 *)t->rx_buf + tspi->cur_pos;
- int i, j;
- unsigned long val;
-
- for (i = 0; i < len; i += tspi->cur_bytes_per_word) {
- val = tspi->rx_bb[i / tspi->cur_bytes_per_word];
- for (j = 0; j < tspi->cur_bytes_per_word; j++)
- rx_buf[i + j] = (val >> (j * 8)) & 0xff;
- }
-
- return len;
-}
-
-static void spi_tegra_start_transfer(struct spi_device *spi,
- struct spi_transfer *t)
-{
- struct spi_tegra_data *tspi = spi_master_get_devdata(spi->master);
- u32 speed;
- u8 bits_per_word;
- unsigned long val;
-
- speed = t->speed_hz ? t->speed_hz : spi->max_speed_hz;
- bits_per_word = t->bits_per_word ? t->bits_per_word :
- spi->bits_per_word;
-
- tspi->cur_bytes_per_word = (bits_per_word - 1) / 8 + 1;
-
- if (speed != tspi->cur_speed)
- clk_set_rate(tspi->clk, speed);
-
- if (tspi->cur_speed == 0)
- clk_prepare_enable(tspi->clk);
-
- tspi->cur_speed = speed;
-
- val = spi_tegra_readl(tspi, SLINK_COMMAND2);
- val &= ~SLINK_SS_EN_CS(~0) | SLINK_RXEN | SLINK_TXEN;
- if (t->rx_buf)
- val |= SLINK_RXEN;
- if (t->tx_buf)
- val |= SLINK_TXEN;
- val |= SLINK_SS_EN_CS(spi->chip_select);
- val |= SLINK_SPIE;
- spi_tegra_writel(tspi, val, SLINK_COMMAND2);
-
- val = spi_tegra_readl(tspi, SLINK_COMMAND);
- val &= ~SLINK_BIT_LENGTH(~0);
- val |= SLINK_BIT_LENGTH(bits_per_word - 1);
-
- /* FIXME: should probably control CS manually so that we can be sure
- * it does not go low between transfer and to support delay_usecs
- * correctly.
- */
- val &= ~SLINK_IDLE_SCLK_MASK & ~SLINK_CK_SDA & ~SLINK_CS_SW;
-
- if (spi->mode & SPI_CPHA)
- val |= SLINK_CK_SDA;
-
- if (spi->mode & SPI_CPOL)
- val |= SLINK_IDLE_SCLK_DRIVE_HIGH;
- else
- val |= SLINK_IDLE_SCLK_DRIVE_LOW;
-
- val |= SLINK_M_S;
-
- spi_tegra_writel(tspi, val, SLINK_COMMAND);
-
- spi_tegra_writel(tspi, SLINK_RX_FLUSH | SLINK_TX_FLUSH, SLINK_STATUS);
-
- tspi->cur = t;
- tspi->cur_pos = 0;
- tspi->cur_len = spi_tegra_fill_tx_fifo(tspi, t);
-
- spi_tegra_go(tspi);
-}
-
-static void spi_tegra_start_message(struct spi_device *spi,
- struct spi_message *m)
-{
- struct spi_transfer *t;
-
- m->actual_length = 0;
- m->status = 0;
-
- t = list_first_entry(&m->transfers, struct spi_transfer, transfer_list);
- spi_tegra_start_transfer(spi, t);
-}
-
-static void handle_spi_rx_dma_complete(struct spi_tegra_data *tspi)
-{
- unsigned long flags;
- struct spi_message *m;
- struct spi_device *spi;
- int timeout = 0;
- unsigned long val;
-
- /* the SPI controller may come back with both the BSY and RDY bits
- * set. In this case we need to wait for the BSY bit to clear so
- * that we are sure the DMA is finished. 1000 reads was empirically
- * determined to be long enough.
- */
- while (timeout++ < 1000) {
- if (!(spi_tegra_readl(tspi, SLINK_STATUS) & SLINK_BSY))
- break;
- }
-
- spin_lock_irqsave(&tspi->lock, flags);
-
- val = spi_tegra_readl(tspi, SLINK_STATUS);
- val |= SLINK_RDY;
- spi_tegra_writel(tspi, val, SLINK_STATUS);
-
- m = list_first_entry(&tspi->queue, struct spi_message, queue);
-
- if (timeout >= 1000)
- m->status = -EIO;
-
- spi = m->state;
-
- tspi->cur_pos += spi_tegra_drain_rx_fifo(tspi, tspi->cur);
- m->actual_length += tspi->cur_pos;
-
- if (tspi->cur_pos < tspi->cur->len) {
- tspi->cur_len = spi_tegra_fill_tx_fifo(tspi, tspi->cur);
- spi_tegra_go(tspi);
- } else if (!list_is_last(&tspi->cur->transfer_list,
- &m->transfers)) {
- tspi->cur = list_first_entry(&tspi->cur->transfer_list,
- struct spi_transfer,
- transfer_list);
- spi_tegra_start_transfer(spi, tspi->cur);
- } else {
- list_del(&m->queue);
-
- m->complete(m->context);
-
- if (!list_empty(&tspi->queue)) {
- m = list_first_entry(&tspi->queue, struct spi_message,
- queue);
- spi = m->state;
- spi_tegra_start_message(spi, m);
- } else {
- clk_disable_unprepare(tspi->clk);
- tspi->cur_speed = 0;
- }
- }
-
- spin_unlock_irqrestore(&tspi->lock, flags);
-}
-#if defined(CONFIG_TEGRA_SYSTEM_DMA)
-static void tegra_spi_rx_dma_complete(struct tegra_dma_req *req)
-{
- struct spi_tegra_data *tspi = req->dev;
- handle_spi_rx_dma_complete(tspi);
-}
-#else
-static void tegra_spi_rx_dma_complete(void *args)
-{
- struct spi_tegra_data *tspi = args;
- handle_spi_rx_dma_complete(tspi);
-}
-#endif
-
-static int spi_tegra_setup(struct spi_device *spi)
-{
- struct spi_tegra_data *tspi = spi_master_get_devdata(spi->master);
- unsigned long cs_bit;
- unsigned long val;
- unsigned long flags;
-
- dev_dbg(&spi->dev, "setup %d bpw, %scpol, %scpha, %dHz\n",
- spi->bits_per_word,
- spi->mode & SPI_CPOL ? "" : "~",
- spi->mode & SPI_CPHA ? "" : "~",
- spi->max_speed_hz);
-
-
- switch (spi->chip_select) {
- case 0:
- cs_bit = SLINK_CS_POLARITY;
- break;
-
- case 1:
- cs_bit = SLINK_CS_POLARITY1;
- break;
-
- case 2:
- cs_bit = SLINK_CS_POLARITY2;
- break;
-
- case 4:
- cs_bit = SLINK_CS_POLARITY3;
- break;
-
- default:
- return -EINVAL;
- }
-
- spin_lock_irqsave(&tspi->lock, flags);
-
- val = spi_tegra_readl(tspi, SLINK_COMMAND);
- if (spi->mode & SPI_CS_HIGH)
- val |= cs_bit;
- else
- val &= ~cs_bit;
- spi_tegra_writel(tspi, val, SLINK_COMMAND);
-
- spin_unlock_irqrestore(&tspi->lock, flags);
-
- return 0;
-}
-
-static int spi_tegra_transfer(struct spi_device *spi, struct spi_message *m)
-{
- struct spi_tegra_data *tspi = spi_master_get_devdata(spi->master);
- struct spi_transfer *t;
- unsigned long flags;
- int was_empty;
-
- if (list_empty(&m->transfers) || !m->complete)
- return -EINVAL;
-
- list_for_each_entry(t, &m->transfers, transfer_list) {
- if (t->bits_per_word < 0 || t->bits_per_word > 32)
- return -EINVAL;
-
- if (t->len == 0)
- return -EINVAL;
-
- if (!t->rx_buf && !t->tx_buf)
- return -EINVAL;
- }
-
- m->state = spi;
-
- spin_lock_irqsave(&tspi->lock, flags);
- was_empty = list_empty(&tspi->queue);
- list_add_tail(&m->queue, &tspi->queue);
-
- if (was_empty)
- spi_tegra_start_message(spi, m);
-
- spin_unlock_irqrestore(&tspi->lock, flags);
-
- return 0;
-}
-
-static int __devinit spi_tegra_probe(struct platform_device *pdev)
-{
- struct spi_master *master;
- struct spi_tegra_data *tspi;
- struct resource *r;
- int ret;
-#if !defined(CONFIG_TEGRA_SYSTEM_DMA)
- dma_cap_mask_t mask;
-#endif
-
- master = spi_alloc_master(&pdev->dev, sizeof *tspi);
- if (master == NULL) {
- dev_err(&pdev->dev, "master allocation failed\n");
- return -ENOMEM;
- }
-
- /* the spi->mode bits understood by this driver: */
- master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
-
- master->bus_num = pdev->id;
-
- master->setup = spi_tegra_setup;
- master->transfer = spi_tegra_transfer;
- master->num_chipselect = 4;
-
- dev_set_drvdata(&pdev->dev, master);
- tspi = spi_master_get_devdata(master);
- tspi->master = master;
- tspi->pdev = pdev;
- spin_lock_init(&tspi->lock);
-
- r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (r == NULL) {
- ret = -ENODEV;
- goto err0;
- }
-
- if (!request_mem_region(r->start, resource_size(r),
- dev_name(&pdev->dev))) {
- ret = -EBUSY;
- goto err0;
- }
-
- tspi->phys = r->start;
- tspi->base = ioremap(r->start, resource_size(r));
- if (!tspi->base) {
- dev_err(&pdev->dev, "can't ioremap iomem\n");
- ret = -ENOMEM;
- goto err1;
- }
-
- tspi->clk = clk_get(&pdev->dev, NULL);
- if (IS_ERR(tspi->clk)) {
- dev_err(&pdev->dev, "can not get clock\n");
- ret = PTR_ERR(tspi->clk);
- goto err2;
- }
-
- INIT_LIST_HEAD(&tspi->queue);
-
-#if defined(CONFIG_TEGRA_SYSTEM_DMA)
- tspi->rx_dma = tegra_dma_allocate_channel(TEGRA_DMA_MODE_ONESHOT);
- if (!tspi->rx_dma) {
- dev_err(&pdev->dev, "can not allocate rx dma channel\n");
- ret = -ENODEV;
- goto err3;
- }
-#else
- dma_cap_zero(mask);
- dma_cap_set(DMA_SLAVE, mask);
- tspi->rx_dma = dma_request_channel(mask, NULL, NULL);
- if (!tspi->rx_dma) {
- dev_err(&pdev->dev, "can not allocate rx dma channel\n");
- ret = -ENODEV;
- goto err3;
- }
-
-#endif
-
- tspi->rx_bb = dma_alloc_coherent(&pdev->dev, sizeof(u32) * BB_LEN,
- &tspi->rx_bb_phys, GFP_KERNEL);
- if (!tspi->rx_bb) {
- dev_err(&pdev->dev, "can not allocate rx bounce buffer\n");
- ret = -ENOMEM;
- goto err4;
- }
-
-#if defined(CONFIG_TEGRA_SYSTEM_DMA)
- tspi->rx_dma_req.complete = tegra_spi_rx_dma_complete;
- tspi->rx_dma_req.to_memory = 1;
- tspi->rx_dma_req.dest_addr = tspi->rx_bb_phys;
- tspi->rx_dma_req.dest_bus_width = 32;
- tspi->rx_dma_req.source_addr = tspi->phys + SLINK_RX_FIFO;
- tspi->rx_dma_req.source_bus_width = 32;
- tspi->rx_dma_req.source_wrap = 4;
- tspi->rx_dma_req.req_sel = spi_tegra_req_sels[pdev->id];
- tspi->rx_dma_req.dev = tspi;
-#else
- /* Dmaengine Dma slave config */
- tspi->sconfig.src_addr = tspi->phys + SLINK_RX_FIFO;
- tspi->sconfig.dst_addr = tspi->phys + SLINK_RX_FIFO;
- tspi->sconfig.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
- tspi->sconfig.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
- tspi->sconfig.slave_id = spi_tegra_req_sels[pdev->id];
- tspi->sconfig.src_maxburst = 1;
- tspi->sconfig.dst_maxburst = 1;
- ret = dmaengine_device_control(tspi->rx_dma,
- DMA_SLAVE_CONFIG, (unsigned long) &tspi->sconfig);
- if (ret < 0) {
- dev_err(&pdev->dev, "can not do slave configure for dma %d\n",
- ret);
- goto err4;
- }
-#endif
-
- master->dev.of_node = pdev->dev.of_node;
- ret = spi_register_master(master);
-
- if (ret < 0)
- goto err5;
-
- return ret;
-
-err5:
- dma_free_coherent(&pdev->dev, sizeof(u32) * BB_LEN,
- tspi->rx_bb, tspi->rx_bb_phys);
-err4:
-#if defined(CONFIG_TEGRA_SYSTEM_DMA)
- tegra_dma_free_channel(tspi->rx_dma);
-#else
- dma_release_channel(tspi->rx_dma);
-#endif
-err3:
- clk_put(tspi->clk);
-err2:
- iounmap(tspi->base);
-err1:
- release_mem_region(r->start, resource_size(r));
-err0:
- spi_master_put(master);
- return ret;
-}
-
-static int __devexit spi_tegra_remove(struct platform_device *pdev)
-{
- struct spi_master *master;
- struct spi_tegra_data *tspi;
- struct resource *r;
-
- master = dev_get_drvdata(&pdev->dev);
- tspi = spi_master_get_devdata(master);
-
- spi_unregister_master(master);
-#if defined(CONFIG_TEGRA_SYSTEM_DMA)
- tegra_dma_free_channel(tspi->rx_dma);
-#else
- dma_release_channel(tspi->rx_dma);
-#endif
-
- dma_free_coherent(&pdev->dev, sizeof(u32) * BB_LEN,
- tspi->rx_bb, tspi->rx_bb_phys);
-
- clk_put(tspi->clk);
- iounmap(tspi->base);
-
- r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- release_mem_region(r->start, resource_size(r));
-
- return 0;
-}
-
-MODULE_ALIAS("platform:spi_tegra");
-
-#ifdef CONFIG_OF
-static struct of_device_id spi_tegra_of_match_table[] __devinitdata = {
- { .compatible = "nvidia,tegra20-spi", },
- {}
-};
-MODULE_DEVICE_TABLE(of, spi_tegra_of_match_table);
-#else /* CONFIG_OF */
-#define spi_tegra_of_match_table NULL
-#endif /* CONFIG_OF */
-
-static struct platform_driver spi_tegra_driver = {
- .driver = {
- .name = "spi_tegra",
- .owner = THIS_MODULE,
- .of_match_table = spi_tegra_of_match_table,
- },
- .probe = spi_tegra_probe,
- .remove = __devexit_p(spi_tegra_remove),
-};
-module_platform_driver(spi_tegra_driver);
-
-MODULE_LICENSE("GPL");
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..135f7406f4b 100644
--- a/drivers/spi/spi-topcliff-pch.c
+++ b/drivers/spi/spi-topcliff-pch.c
@@ -505,7 +505,7 @@ static int pch_spi_transfer(struct spi_device *pspi, struct spi_message *pmsg)
}
if (unlikely(pspi->max_speed_hz == 0)) {
- dev_err(&pspi->dev, "%s pch_spi_tranfer maxspeed=%d\n",
+ dev_err(&pspi->dev, "%s pch_spi_transfer maxspeed=%d\n",
__func__, pspi->max_speed_hz);
retval = -EINVAL;
goto err_out;
@@ -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;
}