summaryrefslogtreecommitdiffstats
path: root/drivers/spi
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/spi')
-rw-r--r--drivers/spi/Kconfig63
-rw-r--r--drivers/spi/Makefile10
-rw-r--r--drivers/spi/spi-altera.c8
-rw-r--r--drivers/spi/spi-ath79.c121
-rw-r--r--drivers/spi/spi-atmel.c23
-rw-r--r--drivers/spi/spi-au1550.c8
-rw-r--r--drivers/spi/spi-bcm63xx.c201
-rw-r--r--drivers/spi/spi-bfin-sport.c11
-rw-r--r--drivers/spi/spi-bfin5xx.c9
-rw-r--r--drivers/spi/spi-bitbang.c60
-rw-r--r--drivers/spi/spi-clps711x.c296
-rw-r--r--drivers/spi/spi-coldfire-qspi.c9
-rw-r--r--drivers/spi/spi-davinci.c125
-rw-r--r--drivers/spi/spi-dw-mmio.c6
-rw-r--r--drivers/spi/spi-dw-pci.c6
-rw-r--r--drivers/spi/spi-dw.c6
-rw-r--r--drivers/spi/spi-ep93xx.c15
-rw-r--r--drivers/spi/spi-falcon.c9
-rw-r--r--drivers/spi/spi-fsl-espi.c8
-rw-r--r--drivers/spi/spi-fsl-lib.c4
-rw-r--r--drivers/spi/spi-fsl-spi.c18
-rw-r--r--drivers/spi/spi-gpio.c36
-rw-r--r--drivers/spi/spi-imx.c7
-rw-r--r--drivers/spi/spi-mpc512x-psc.c27
-rw-r--r--drivers/spi/spi-mpc52xx-psc.c8
-rw-r--r--drivers/spi/spi-mpc52xx.c8
-rw-r--r--drivers/spi/spi-mxs.c17
-rw-r--r--drivers/spi/spi-nuc900.c6
-rw-r--r--drivers/spi/spi-oc-tiny.c18
-rw-r--r--drivers/spi/spi-octeon.c6
-rw-r--r--drivers/spi/spi-omap-100k.c8
-rw-r--r--drivers/spi/spi-omap-uwire.c6
-rw-r--r--drivers/spi/spi-omap2-mcspi.c125
-rw-r--r--drivers/spi/spi-orion.c48
-rw-r--r--drivers/spi/spi-pl022.c61
-rw-r--r--drivers/spi/spi-ppc4xx.c10
-rw-r--r--drivers/spi/spi-pxa2xx-dma.c392
-rw-r--r--drivers/spi/spi-pxa2xx-pci.c139
-rw-r--r--drivers/spi/spi-pxa2xx-pxadma.c490
-rw-r--r--drivers/spi/spi-pxa2xx.c1105
-rw-r--r--drivers/spi/spi-pxa2xx.h221
-rw-r--r--drivers/spi/spi-rspi.c10
-rw-r--r--drivers/spi/spi-s3c24xx.c6
-rw-r--r--drivers/spi/spi-s3c64xx.c202
-rw-r--r--drivers/spi/spi-sh-hspi.c51
-rw-r--r--drivers/spi/spi-sh-msiof.c62
-rw-r--r--drivers/spi/spi-sh.c6
-rw-r--r--drivers/spi/spi-sirf.c23
-rw-r--r--drivers/spi/spi-stmp.c664
-rw-r--r--drivers/spi/spi-tegra20-sflash.c671
-rw-r--r--drivers/spi/spi-tegra20-slink.c1353
-rw-r--r--drivers/spi/spi-ti-ssp.c6
-rw-r--r--drivers/spi/spi-tle62x0.c6
-rw-r--r--drivers/spi/spi-topcliff-pch.c12
-rw-r--r--drivers/spi/spi-txx9.c12
-rw-r--r--drivers/spi/spi-xcomm.c6
-rw-r--r--drivers/spi/spi-xilinx.c6
-rw-r--r--drivers/spi/spi.c118
-rw-r--r--drivers/spi/spidev.c16
59 files changed, 4830 insertions, 2154 deletions
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index 1acae359cabe..f80eee74a311 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -88,7 +88,7 @@ config SPI_BFIN_SPORT
config SPI_AU1550
tristate "Au1550/Au1200/Au1300 SPI Controller"
- depends on MIPS_ALCHEMY && EXPERIMENTAL
+ depends on MIPS_ALCHEMY
select SPI_BITBANG
help
If you say yes to this option, support will be included for the
@@ -123,6 +123,13 @@ config SPI_BUTTERFLY
inexpensive battery powered microcontroller evaluation board.
This same cable can be used to flash new firmware.
+config SPI_CLPS711X
+ tristate "CLPS711X host SPI controller"
+ depends on ARCH_CLPS711X
+ help
+ This enables dedicated general purpose SPI/Microwire1-compatible
+ master mode interface (SSI1) for CLPS711X-based CPUs.
+
config SPI_COLDFIRE_QSPI
tristate "Freescale Coldfire QSPI controller"
depends on (M520x || M523x || M5249 || M525x || M527x || M528x || M532x)
@@ -181,7 +188,7 @@ config SPI_IMX
config SPI_LM70_LLP
tristate "Parallel port adapter for LM70 eval board (DEVELOPMENT)"
- depends on PARPORT && EXPERIMENTAL
+ depends on PARPORT
select SPI_BITBANG
help
This driver supports the NS LM70 LLP Evaluation Board,
@@ -197,7 +204,7 @@ config SPI_MPC52xx
config SPI_MPC52xx_PSC
tristate "Freescale MPC52xx PSC SPI controller"
- depends on PPC_MPC52xx && EXPERIMENTAL
+ depends on PPC_MPC52xx
help
This enables using the Freescale MPC52xx Programmable Serial
Controller in master SPI mode.
@@ -266,8 +273,8 @@ config SPI_OMAP_100K
OMAP SPI 100K master controller for omap7xx boards.
config SPI_ORION
- tristate "Orion SPI master (EXPERIMENTAL)"
- depends on PLAT_ORION && EXPERIMENTAL
+ tristate "Orion SPI master"
+ depends on PLAT_ORION
help
This enables using the SPI master controller on the Orion chips.
@@ -290,9 +297,20 @@ config SPI_PPC4xx
help
This selects a driver for the PPC4xx SPI Controller.
+config SPI_PXA2XX_PXADMA
+ bool "PXA2xx SSP legacy PXA DMA API support"
+ depends on SPI_PXA2XX && ARCH_PXA
+ help
+ Enable PXA private legacy DMA API support. Note that this is
+ deprecated in favor of generic DMA engine API.
+
+config SPI_PXA2XX_DMA
+ def_bool y
+ depends on SPI_PXA2XX && !SPI_PXA2XX_PXADMA
+
config SPI_PXA2XX
tristate "PXA2xx SSP SPI master"
- depends on (ARCH_PXA || (X86_32 && PCI)) && EXPERIMENTAL
+ depends on ARCH_PXA || PCI || ACPI
select PXA_SSP if ARCH_PXA
help
This enables using a PXA2xx or Sodaville SSP port as a SPI master
@@ -300,7 +318,7 @@ config SPI_PXA2XX
additional documentation can be found a Documentation/spi/pxa2xx.
config SPI_PXA2XX_PCI
- def_bool SPI_PXA2XX && X86_32 && PCI
+ def_tristate SPI_PXA2XX && PCI
config SPI_RSPI
tristate "Renesas RSPI controller"
@@ -310,7 +328,7 @@ config SPI_RSPI
config SPI_S3C24XX
tristate "Samsung S3C24XX series SPI"
- depends on ARCH_S3C24XX && EXPERIMENTAL
+ depends on ARCH_S3C24XX
select SPI_BITBANG
help
SPI driver for Samsung S3C24XX series ARM SoCs
@@ -341,10 +359,10 @@ config SPI_SC18IS602
config SPI_SH_MSIOF
tristate "SuperH MSIOF SPI controller"
- depends on SUPERH && HAVE_CLK
+ depends on (SUPERH || ARCH_SHMOBILE) && HAVE_CLK
select SPI_BITBANG
help
- SPI driver for SuperH MSIOF blocks.
+ SPI driver for SuperH and SH Mobile MSIOF blocks.
config SPI_SH
tristate "SuperH SPI controller"
@@ -372,12 +390,6 @@ config SPI_SIRF
help
SPI driver for CSR SiRFprimaII SoCs
-config SPI_STMP3XXX
- tristate "Freescale STMP37xx/378x SPI/SSP controller"
- depends on ARCH_STMP3XXX
- help
- SPI driver for Freescale STMP37xx/378x SoC SSP interface
-
config SPI_MXS
tristate "Freescale MXS SPI controller"
depends on ARCH_MXS
@@ -385,6 +397,20 @@ config SPI_MXS
help
SPI driver for Freescale MXS devices.
+config SPI_TEGRA20_SFLASH
+ tristate "Nvidia Tegra20 Serial flash Controller"
+ depends on ARCH_TEGRA
+ help
+ SPI driver for Nvidia Tegra20 Serial flash Controller interface.
+ The main usecase of this controller is to use spi flash as boot
+ device.
+
+config SPI_TEGRA20_SLINK
+ tristate "Nvidia Tegra20/Tegra30 SLINK Controller"
+ depends on ARCH_TEGRA && TEGRA20_APB_DMA
+ help
+ SPI driver for Nvidia Tegra20/Tegra30 SLINK Controller interface.
+
config SPI_TI_SSP
tristate "TI Sequencer Serial Port - SPI Support"
depends on MFD_TI_SSP
@@ -417,7 +443,7 @@ config SPI_XCOMM
config SPI_XILINX
tristate "Xilinx SPI controller common module"
- depends on HAS_IOMEM && EXPERIMENTAL
+ depends on HAS_IOMEM
select SPI_BITBANG
help
This exposes the SPI controller IP from the Xilinx EDK.
@@ -429,7 +455,7 @@ config SPI_XILINX
config SPI_NUC900
tristate "Nuvoton NUC900 series SPI"
- depends on ARCH_W90X900 && EXPERIMENTAL
+ depends on ARCH_W90X900
select SPI_BITBANG
help
SPI driver for Nuvoton NUC900 series ARM SoCs
@@ -463,7 +489,6 @@ comment "SPI Protocol Masters"
config SPI_SPIDEV
tristate "User mode SPI device driver support"
- depends on EXPERIMENTAL
help
This supports user mode SPI protocol drivers.
diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
index c48df47e4b0f..e53c30941340 100644
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
@@ -19,6 +19,7 @@ obj-$(CONFIG_SPI_BFIN5XX) += spi-bfin5xx.o
obj-$(CONFIG_SPI_BFIN_SPORT) += spi-bfin-sport.o
obj-$(CONFIG_SPI_BITBANG) += spi-bitbang.o
obj-$(CONFIG_SPI_BUTTERFLY) += spi-butterfly.o
+obj-$(CONFIG_SPI_CLPS711X) += spi-clps711x.o
obj-$(CONFIG_SPI_COLDFIRE_QSPI) += spi-coldfire-qspi.o
obj-$(CONFIG_SPI_DAVINCI) += spi-davinci.o
obj-$(CONFIG_SPI_DESIGNWARE) += spi-dw.o
@@ -46,7 +47,10 @@ obj-$(CONFIG_SPI_OMAP24XX) += spi-omap2-mcspi.o
obj-$(CONFIG_SPI_ORION) += spi-orion.o
obj-$(CONFIG_SPI_PL022) += spi-pl022.o
obj-$(CONFIG_SPI_PPC4xx) += spi-ppc4xx.o
-obj-$(CONFIG_SPI_PXA2XX) += spi-pxa2xx.o
+spi-pxa2xx-platform-objs := spi-pxa2xx.o
+spi-pxa2xx-platform-$(CONFIG_SPI_PXA2XX_PXADMA) += spi-pxa2xx-pxadma.o
+spi-pxa2xx-platform-$(CONFIG_SPI_PXA2XX_DMA) += spi-pxa2xx-dma.o
+obj-$(CONFIG_SPI_PXA2XX) += spi-pxa2xx-platform.o
obj-$(CONFIG_SPI_PXA2XX_PCI) += spi-pxa2xx-pci.o
obj-$(CONFIG_SPI_RSPI) += spi-rspi.o
obj-$(CONFIG_SPI_S3C24XX) += spi-s3c24xx-hw.o
@@ -59,11 +63,11 @@ 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_TEGRA20_SFLASH) += spi-tegra20-sflash.o
+obj-$(CONFIG_SPI_TEGRA20_SLINK) += spi-tegra20-slink.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
obj-$(CONFIG_SPI_TXX9) += spi-txx9.o
obj-$(CONFIG_SPI_XCOMM) += spi-xcomm.o
obj-$(CONFIG_SPI_XILINX) += spi-xilinx.o
-
diff --git a/drivers/spi/spi-altera.c b/drivers/spi/spi-altera.c
index f1fec2a19d10..a537f8dffc09 100644
--- a/drivers/spi/spi-altera.c
+++ b/drivers/spi/spi-altera.c
@@ -134,7 +134,7 @@ static int altera_spi_txrx(struct spi_device *spi, struct spi_transfer *t)
hw->tx = t->tx_buf;
hw->rx = t->rx_buf;
hw->count = 0;
- hw->bytes_per_word = (t->bits_per_word ? : spi->bits_per_word) / 8;
+ hw->bytes_per_word = t->bits_per_word / 8;
hw->len = t->len / hw->bytes_per_word;
if (hw->irq >= 0) {
@@ -215,7 +215,7 @@ static irqreturn_t altera_spi_irq(int irq, void *dev)
return IRQ_HANDLED;
}
-static int __devinit altera_spi_probe(struct platform_device *pdev)
+static int altera_spi_probe(struct platform_device *pdev)
{
struct altera_spi_platform_data *platp = pdev->dev.platform_data;
struct altera_spi *hw;
@@ -290,7 +290,7 @@ exit:
return err;
}
-static int __devexit altera_spi_remove(struct platform_device *dev)
+static int altera_spi_remove(struct platform_device *dev)
{
struct altera_spi *hw = platform_get_drvdata(dev);
struct spi_master *master = hw->bitbang.master;
@@ -311,7 +311,7 @@ MODULE_DEVICE_TABLE(of, altera_spi_match);
static struct platform_driver altera_spi_driver = {
.probe = altera_spi_probe,
- .remove = __devexit_p(altera_spi_remove),
+ .remove = altera_spi_remove,
.driver = {
.name = DRV_NAME,
.owner = THIS_MODULE,
diff --git a/drivers/spi/spi-ath79.c b/drivers/spi/spi-ath79.c
index 249077e5cc48..e504b7636058 100644
--- a/drivers/spi/spi-ath79.c
+++ b/drivers/spi/spi-ath79.c
@@ -24,17 +24,24 @@
#include <linux/spi/spi_bitbang.h>
#include <linux/bitops.h>
#include <linux/gpio.h>
+#include <linux/clk.h>
+#include <linux/err.h>
#include <asm/mach-ath79/ar71xx_regs.h>
#include <asm/mach-ath79/ath79_spi_platform.h>
#define DRV_NAME "ath79-spi"
+#define ATH79_SPI_RRW_DELAY_FACTOR 12000
+#define MHZ (1000 * 1000)
+
struct ath79_spi {
struct spi_bitbang bitbang;
u32 ioc_base;
u32 reg_ctrl;
void __iomem *base;
+ struct clk *clk;
+ unsigned rrw_delay;
};
static inline u32 ath79_spi_rr(struct ath79_spi *sp, unsigned reg)
@@ -52,6 +59,12 @@ static inline struct ath79_spi *ath79_spidev_to_sp(struct spi_device *spi)
return spi_master_get_devdata(spi->master);
}
+static inline void ath79_spi_delay(struct ath79_spi *sp, unsigned nsecs)
+{
+ if (nsecs > sp->rrw_delay)
+ ndelay(nsecs - sp->rrw_delay);
+}
+
static void ath79_spi_chipselect(struct spi_device *spi, int is_active)
{
struct ath79_spi *sp = ath79_spidev_to_sp(spi);
@@ -83,15 +96,8 @@ static void ath79_spi_chipselect(struct spi_device *spi, int is_active)
}
-static int ath79_spi_setup_cs(struct spi_device *spi)
+static void ath79_spi_enable(struct ath79_spi *sp)
{
- struct ath79_spi *sp = ath79_spidev_to_sp(spi);
- struct ath79_spi_controller_data *cdata;
-
- cdata = spi->controller_data;
- if (spi->chip_select && !cdata)
- return -EINVAL;
-
/* enable GPIO mode */
ath79_spi_wr(sp, AR71XX_SPI_REG_FS, AR71XX_SPI_FS_GPIO);
@@ -101,44 +107,48 @@ static int ath79_spi_setup_cs(struct spi_device *spi)
/* TODO: setup speed? */
ath79_spi_wr(sp, AR71XX_SPI_REG_CTRL, 0x43);
+}
- if (spi->chip_select) {
- int status = 0;
+static void ath79_spi_disable(struct ath79_spi *sp)
+{
+ /* restore CTRL register */
+ ath79_spi_wr(sp, AR71XX_SPI_REG_CTRL, sp->reg_ctrl);
+ /* disable GPIO mode */
+ ath79_spi_wr(sp, AR71XX_SPI_REG_FS, 0);
+}
- status = gpio_request(cdata->gpio, dev_name(&spi->dev));
- if (status)
- return status;
+static int ath79_spi_setup_cs(struct spi_device *spi)
+{
+ struct ath79_spi_controller_data *cdata;
+ int status;
- status = gpio_direction_output(cdata->gpio,
- spi->mode & SPI_CS_HIGH);
- if (status) {
- gpio_free(cdata->gpio);
- return status;
- }
- } else {
+ cdata = spi->controller_data;
+ if (spi->chip_select && !cdata)
+ return -EINVAL;
+
+ status = 0;
+ if (spi->chip_select) {
+ unsigned long flags;
+
+ flags = GPIOF_DIR_OUT;
if (spi->mode & SPI_CS_HIGH)
- sp->ioc_base |= AR71XX_SPI_IOC_CS0;
+ flags |= GPIOF_INIT_HIGH;
else
- sp->ioc_base &= ~AR71XX_SPI_IOC_CS0;
- ath79_spi_wr(sp, AR71XX_SPI_REG_IOC, sp->ioc_base);
+ flags |= GPIOF_INIT_LOW;
+
+ status = gpio_request_one(cdata->gpio, flags,
+ dev_name(&spi->dev));
}
- return 0;
+ return status;
}
static void ath79_spi_cleanup_cs(struct spi_device *spi)
{
- struct ath79_spi *sp = ath79_spidev_to_sp(spi);
-
if (spi->chip_select) {
struct ath79_spi_controller_data *cdata = spi->controller_data;
gpio_free(cdata->gpio);
}
-
- /* restore CTRL register */
- ath79_spi_wr(sp, AR71XX_SPI_REG_CTRL, sp->reg_ctrl);
- /* disable GPIO mode */
- ath79_spi_wr(sp, AR71XX_SPI_REG_FS, 0);
}
static int ath79_spi_setup(struct spi_device *spi)
@@ -184,7 +194,11 @@ static u32 ath79_spi_txrx_mode0(struct spi_device *spi, unsigned nsecs,
/* setup MSB (to slave) on trailing edge */
ath79_spi_wr(sp, AR71XX_SPI_REG_IOC, out);
+ ath79_spi_delay(sp, nsecs);
ath79_spi_wr(sp, AR71XX_SPI_REG_IOC, out | AR71XX_SPI_IOC_CLK);
+ ath79_spi_delay(sp, nsecs);
+ if (bits == 1)
+ ath79_spi_wr(sp, AR71XX_SPI_REG_IOC, out);
word <<= 1;
}
@@ -192,12 +206,13 @@ static u32 ath79_spi_txrx_mode0(struct spi_device *spi, unsigned nsecs,
return ath79_spi_rr(sp, AR71XX_SPI_REG_RDS);
}
-static __devinit int ath79_spi_probe(struct platform_device *pdev)
+static int ath79_spi_probe(struct platform_device *pdev)
{
struct spi_master *master;
struct ath79_spi *sp;
struct ath79_spi_platform_data *pdata;
struct resource *r;
+ unsigned long rate;
int ret;
master = spi_alloc_master(&pdev->dev, sizeof(*sp));
@@ -236,12 +251,39 @@ static __devinit int ath79_spi_probe(struct platform_device *pdev)
goto err_put_master;
}
+ sp->clk = clk_get(&pdev->dev, "ahb");
+ if (IS_ERR(sp->clk)) {
+ ret = PTR_ERR(sp->clk);
+ goto err_unmap;
+ }
+
+ ret = clk_enable(sp->clk);
+ if (ret)
+ goto err_clk_put;
+
+ rate = DIV_ROUND_UP(clk_get_rate(sp->clk), MHZ);
+ if (!rate) {
+ ret = -EINVAL;
+ goto err_clk_disable;
+ }
+
+ sp->rrw_delay = ATH79_SPI_RRW_DELAY_FACTOR / rate;
+ dev_dbg(&pdev->dev, "register read/write delay is %u nsecs\n",
+ sp->rrw_delay);
+
+ ath79_spi_enable(sp);
ret = spi_bitbang_start(&sp->bitbang);
if (ret)
- goto err_unmap;
+ goto err_disable;
return 0;
+err_disable:
+ ath79_spi_disable(sp);
+err_clk_disable:
+ clk_disable(sp->clk);
+err_clk_put:
+ clk_put(sp->clk);
err_unmap:
iounmap(sp->base);
err_put_master:
@@ -251,11 +293,14 @@ err_put_master:
return ret;
}
-static __devexit int ath79_spi_remove(struct platform_device *pdev)
+static int ath79_spi_remove(struct platform_device *pdev)
{
struct ath79_spi *sp = platform_get_drvdata(pdev);
spi_bitbang_stop(&sp->bitbang);
+ ath79_spi_disable(sp);
+ clk_disable(sp->clk);
+ clk_put(sp->clk);
iounmap(sp->base);
platform_set_drvdata(pdev, NULL);
spi_master_put(sp->bitbang.master);
@@ -263,9 +308,15 @@ static __devexit int ath79_spi_remove(struct platform_device *pdev)
return 0;
}
+static void ath79_spi_shutdown(struct platform_device *pdev)
+{
+ ath79_spi_remove(pdev);
+}
+
static struct platform_driver ath79_spi_driver = {
.probe = ath79_spi_probe,
- .remove = __devexit_p(ath79_spi_remove),
+ .remove = ath79_spi_remove,
+ .shutdown = ath79_spi_shutdown,
.driver = {
.name = DRV_NAME,
.owner = THIS_MODULE,
diff --git a/drivers/spi/spi-atmel.c b/drivers/spi/spi-atmel.c
index 61fb0ec26f06..656d137db253 100644
--- a/drivers/spi/spi-atmel.c
+++ b/drivers/spi/spi-atmel.c
@@ -20,6 +20,7 @@
#include <linux/spi/spi.h>
#include <linux/slab.h>
#include <linux/platform_data/atmel.h>
+#include <linux/of.h>
#include <asm/io.h>
#include <asm/gpio.h>
@@ -768,6 +769,10 @@ static int atmel_spi_setup(struct spi_device *spi)
/* chipselect must have been muxed as GPIO (e.g. in board setup) */
npcs_pin = (unsigned int)spi->controller_data;
+
+ if (gpio_is_valid(spi->cs_gpio))
+ npcs_pin = spi->cs_gpio;
+
asd = spi->controller_state;
if (!asd) {
asd = kzalloc(sizeof(struct atmel_spi_device), GFP_KERNEL);
@@ -907,7 +912,7 @@ static void atmel_spi_cleanup(struct spi_device *spi)
/*-------------------------------------------------------------------------*/
-static int __devinit atmel_spi_probe(struct platform_device *pdev)
+static int atmel_spi_probe(struct platform_device *pdev)
{
struct resource *regs;
int irq;
@@ -937,8 +942,9 @@ static int __devinit atmel_spi_probe(struct platform_device *pdev)
/* the spi->mode bits understood by this driver: */
master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
+ master->dev.of_node = pdev->dev.of_node;
master->bus_num = pdev->id;
- master->num_chipselect = 4;
+ master->num_chipselect = master->dev.of_node ? 0 : 4;
master->setup = atmel_spi_setup;
master->transfer = atmel_spi_transfer;
master->cleanup = atmel_spi_cleanup;
@@ -1003,7 +1009,7 @@ out_free:
return ret;
}
-static int __devexit atmel_spi_remove(struct platform_device *pdev)
+static int atmel_spi_remove(struct platform_device *pdev)
{
struct spi_master *master = platform_get_drvdata(pdev);
struct atmel_spi *as = spi_master_get_devdata(master);
@@ -1064,16 +1070,25 @@ static int atmel_spi_resume(struct platform_device *pdev)
#define atmel_spi_resume NULL
#endif
+#if defined(CONFIG_OF)
+static const struct of_device_id atmel_spi_dt_ids[] = {
+ { .compatible = "atmel,at91rm9200-spi" },
+ { /* sentinel */ }
+};
+
+MODULE_DEVICE_TABLE(of, atmel_spi_dt_ids);
+#endif
static struct platform_driver atmel_spi_driver = {
.driver = {
.name = "atmel_spi",
.owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(atmel_spi_dt_ids),
},
.suspend = atmel_spi_suspend,
.resume = atmel_spi_resume,
.probe = atmel_spi_probe,
- .remove = __exit_p(atmel_spi_remove),
+ .remove = atmel_spi_remove,
};
module_platform_driver(atmel_spi_driver);
diff --git a/drivers/spi/spi-au1550.c b/drivers/spi/spi-au1550.c
index 4de66d1cfe51..44dd34b6ad09 100644
--- a/drivers/spi/spi-au1550.c
+++ b/drivers/spi/spi-au1550.c
@@ -717,7 +717,7 @@ static void au1550_spi_bits_handlers_set(struct au1550_spi *hw, int bpw)
}
}
-static void __init au1550_spi_setup_psc_as_spi(struct au1550_spi *hw)
+static void au1550_spi_setup_psc_as_spi(struct au1550_spi *hw)
{
u32 stat, cfg;
@@ -766,7 +766,7 @@ static void __init au1550_spi_setup_psc_as_spi(struct au1550_spi *hw)
}
-static int __init au1550_spi_probe(struct platform_device *pdev)
+static int au1550_spi_probe(struct platform_device *pdev)
{
struct au1550_spi *hw;
struct spi_master *master;
@@ -968,7 +968,7 @@ err_nomem:
return err;
}
-static int __exit au1550_spi_remove(struct platform_device *pdev)
+static int au1550_spi_remove(struct platform_device *pdev)
{
struct au1550_spi *hw = platform_get_drvdata(pdev);
@@ -997,7 +997,7 @@ static int __exit au1550_spi_remove(struct platform_device *pdev)
MODULE_ALIAS("platform:au1550-spi");
static struct platform_driver au1550_spi_drv = {
- .remove = __exit_p(au1550_spi_remove),
+ .remove = au1550_spi_remove,
.driver = {
.name = "au1550-spi",
.owner = THIS_MODULE,
diff --git a/drivers/spi/spi-bcm63xx.c b/drivers/spi/spi-bcm63xx.c
index a9f4049c6769..9578af782a77 100644
--- a/drivers/spi/spi-bcm63xx.c
+++ b/drivers/spi/spi-bcm63xx.c
@@ -36,7 +36,8 @@
#include <bcm63xx_dev_spi.h>
#define PFX KBUILD_MODNAME
-#define DRV_VER "0.1.2"
+
+#define BCM63XX_SPI_MAX_PREPEND 15
struct bcm63xx_spi {
struct completion done;
@@ -50,16 +51,10 @@ struct bcm63xx_spi {
unsigned int msg_type_shift;
unsigned int msg_ctl_width;
- /* Data buffers */
- const unsigned char *tx_ptr;
- unsigned char *rx_ptr;
-
/* data iomem */
u8 __iomem *tx_io;
const u8 __iomem *rx_io;
- int remaining_bytes;
-
struct clk *clk;
struct platform_device *pdev;
};
@@ -170,37 +165,23 @@ static int bcm63xx_spi_setup(struct spi_device *spi)
return -EINVAL;
}
- ret = bcm63xx_spi_check_transfer(spi, NULL);
- if (ret < 0) {
- dev_err(&spi->dev, "setup: unsupported mode bits %x\n",
- spi->mode & ~MODEBITS);
- return ret;
- }
-
dev_dbg(&spi->dev, "%s, mode %d, %u bits/w, %u nsec/bit\n",
__func__, spi->mode & MODEBITS, spi->bits_per_word, 0);
return 0;
}
-/* Fill the TX FIFO with as many bytes as possible */
-static void bcm63xx_spi_fill_tx_fifo(struct bcm63xx_spi *bs)
-{
- u8 size;
-
- /* Fill the Tx FIFO with as many bytes as possible */
- size = bs->remaining_bytes < bs->fifo_size ? bs->remaining_bytes :
- bs->fifo_size;
- memcpy_toio(bs->tx_io, bs->tx_ptr, size);
- bs->remaining_bytes -= size;
-}
-
-static unsigned int bcm63xx_txrx_bufs(struct spi_device *spi,
- struct spi_transfer *t)
+static int bcm63xx_txrx_bufs(struct spi_device *spi, struct spi_transfer *first,
+ unsigned int num_transfers)
{
struct bcm63xx_spi *bs = spi_master_get_devdata(spi->master);
u16 msg_ctl;
u16 cmd;
+ u8 rx_tail;
+ unsigned int i, timeout = 0, prepend_len = 0, len = 0;
+ struct spi_transfer *t = first;
+ bool do_rx = false;
+ bool do_tx = false;
/* Disable the CMD_DONE interrupt */
bcm_spi_writeb(bs, 0, SPI_INT_MASK);
@@ -208,25 +189,45 @@ static unsigned int bcm63xx_txrx_bufs(struct spi_device *spi,
dev_dbg(&spi->dev, "txrx: tx %p, rx %p, len %d\n",
t->tx_buf, t->rx_buf, t->len);
- /* Transmitter is inhibited */
- bs->tx_ptr = t->tx_buf;
- bs->rx_ptr = t->rx_buf;
+ if (num_transfers > 1 && t->tx_buf && t->len <= BCM63XX_SPI_MAX_PREPEND)
+ prepend_len = t->len;
+
+ /* prepare the buffer */
+ for (i = 0; i < num_transfers; i++) {
+ if (t->tx_buf) {
+ do_tx = true;
+ memcpy_toio(bs->tx_io + len, t->tx_buf, t->len);
- if (t->tx_buf) {
- bs->remaining_bytes = t->len;
- bcm63xx_spi_fill_tx_fifo(bs);
+ /* don't prepend more than one tx */
+ if (t != first)
+ prepend_len = 0;
+ }
+
+ if (t->rx_buf) {
+ do_rx = true;
+ /* prepend is half-duplex write only */
+ if (t == first)
+ prepend_len = 0;
+ }
+
+ len += t->len;
+
+ t = list_entry(t->transfer_list.next, struct spi_transfer,
+ transfer_list);
}
+ len -= prepend_len;
+
init_completion(&bs->done);
/* Fill in the Message control register */
- msg_ctl = (t->len << SPI_BYTE_CNT_SHIFT);
+ msg_ctl = (len << SPI_BYTE_CNT_SHIFT);
- if (t->rx_buf && t->tx_buf)
+ if (do_rx && do_tx && prepend_len == 0)
msg_ctl |= (SPI_FD_RW << bs->msg_type_shift);
- else if (t->rx_buf)
+ else if (do_rx)
msg_ctl |= (SPI_HD_R << bs->msg_type_shift);
- else if (t->tx_buf)
+ else if (do_tx)
msg_ctl |= (SPI_HD_W << bs->msg_type_shift);
switch (bs->msg_ctl_width) {
@@ -240,14 +241,41 @@ static unsigned int bcm63xx_txrx_bufs(struct spi_device *spi,
/* Issue the transfer */
cmd = SPI_CMD_START_IMMEDIATE;
- cmd |= (0 << SPI_CMD_PREPEND_BYTE_CNT_SHIFT);
+ cmd |= (prepend_len << SPI_CMD_PREPEND_BYTE_CNT_SHIFT);
cmd |= (spi->chip_select << SPI_CMD_DEVICE_ID_SHIFT);
bcm_spi_writew(bs, cmd, SPI_CMD);
/* Enable the CMD_DONE interrupt */
bcm_spi_writeb(bs, SPI_INTR_CMD_DONE, SPI_INT_MASK);
- return t->len - bs->remaining_bytes;
+ timeout = wait_for_completion_timeout(&bs->done, HZ);
+ if (!timeout)
+ return -ETIMEDOUT;
+
+ /* read out all data */
+ rx_tail = bcm_spi_readb(bs, SPI_RX_TAIL);
+
+ if (do_rx && rx_tail != len)
+ return -EIO;
+
+ if (!rx_tail)
+ return 0;
+
+ len = 0;
+ t = first;
+ /* Read out all the data */
+ for (i = 0; i < num_transfers; i++) {
+ if (t->rx_buf)
+ memcpy_fromio(t->rx_buf, bs->rx_io + len, t->len);
+
+ if (t != first || prepend_len == 0)
+ len += t->len;
+
+ t = list_entry(t->transfer_list.next, struct spi_transfer,
+ transfer_list);
+ }
+
+ return 0;
}
static int bcm63xx_spi_prepare_transfer(struct spi_master *master)
@@ -272,41 +300,76 @@ static int bcm63xx_spi_transfer_one(struct spi_master *master,
struct spi_message *m)
{
struct bcm63xx_spi *bs = spi_master_get_devdata(master);
- struct spi_transfer *t;
+ struct spi_transfer *t, *first = NULL;
struct spi_device *spi = m->spi;
int status = 0;
- unsigned int timeout = 0;
-
+ unsigned int n_transfers = 0, total_len = 0;
+ bool can_use_prepend = false;
+
+ /*
+ * This SPI controller does not support keeping CS active after a
+ * transfer.
+ * Work around this by merging as many transfers we can into one big
+ * full-duplex transfers.
+ */
list_for_each_entry(t, &m->transfers, transfer_list) {
- unsigned int len = t->len;
- u8 rx_tail;
-
status = bcm63xx_spi_check_transfer(spi, t);
if (status < 0)
goto exit;
- /* configure adapter for a new transfer */
- bcm63xx_spi_setup_transfer(spi, t);
+ if (!first)
+ first = t;
+
+ n_transfers++;
+ total_len += t->len;
+
+ if (n_transfers == 2 && !first->rx_buf && !t->tx_buf &&
+ first->len <= BCM63XX_SPI_MAX_PREPEND)
+ can_use_prepend = true;
+ else if (can_use_prepend && t->tx_buf)
+ can_use_prepend = false;
+
+ /* we can only transfer one fifo worth of data */
+ if ((can_use_prepend &&
+ total_len > (bs->fifo_size + BCM63XX_SPI_MAX_PREPEND)) ||
+ (!can_use_prepend && total_len > bs->fifo_size)) {
+ dev_err(&spi->dev, "unable to do transfers larger than FIFO size (%i > %i)\n",
+ total_len, bs->fifo_size);
+ status = -EINVAL;
+ goto exit;
+ }
- while (len) {
- /* send the data */
- len -= bcm63xx_txrx_bufs(spi, t);
+ /* all combined transfers have to have the same speed */
+ if (t->speed_hz != first->speed_hz) {
+ dev_err(&spi->dev, "unable to change speed between transfers\n");
+ status = -EINVAL;
+ goto exit;
+ }
+
+ /* CS will be deasserted directly after transfer */
+ if (t->delay_usecs) {
+ dev_err(&spi->dev, "unable to keep CS asserted after transfer\n");
+ status = -EINVAL;
+ goto exit;
+ }
- timeout = wait_for_completion_timeout(&bs->done, HZ);
- if (!timeout) {
- status = -ETIMEDOUT;
+ if (t->cs_change ||
+ list_is_last(&t->transfer_list, &m->transfers)) {
+ /* configure adapter for a new transfer */
+ bcm63xx_spi_setup_transfer(spi, first);
+
+ /* send the data */
+ status = bcm63xx_txrx_bufs(spi, first, n_transfers);
+ if (status)
goto exit;
- }
- /* read out all data */
- rx_tail = bcm_spi_readb(bs, SPI_RX_TAIL);
+ m->actual_length += total_len;
- /* Read out all the data */
- if (rx_tail)
- memcpy_fromio(bs->rx_ptr, bs->rx_io, rx_tail);
+ first = NULL;
+ n_transfers = 0;
+ total_len = 0;
+ can_use_prepend = false;
}
-
- m->actual_length += t->len;
}
exit:
m->status = status;
@@ -337,7 +400,7 @@ static irqreturn_t bcm63xx_spi_interrupt(int irq, void *dev_id)
}
-static int __devinit bcm63xx_spi_probe(struct platform_device *pdev)
+static int bcm63xx_spi_probe(struct platform_device *pdev)
{
struct resource *r;
struct device *dev = &pdev->dev;
@@ -441,8 +504,8 @@ static int __devinit bcm63xx_spi_probe(struct platform_device *pdev)
goto out_clk_disable;
}
- dev_info(dev, "at 0x%08x (irq %d, FIFOs size %d) v%s\n",
- r->start, irq, bs->fifo_size, DRV_VER);
+ dev_info(dev, "at 0x%08x (irq %d, FIFOs size %d)\n",
+ r->start, irq, bs->fifo_size);
return 0;
@@ -457,7 +520,7 @@ out:
return ret;
}
-static int __devexit bcm63xx_spi_remove(struct platform_device *pdev)
+static int bcm63xx_spi_remove(struct platform_device *pdev)
{
struct spi_master *master = spi_master_get(platform_get_drvdata(pdev));
struct bcm63xx_spi *bs = spi_master_get_devdata(master);
@@ -485,6 +548,8 @@ static int bcm63xx_spi_suspend(struct device *dev)
platform_get_drvdata(to_platform_device(dev));
struct bcm63xx_spi *bs = spi_master_get_devdata(master);
+ spi_master_suspend(master);
+
clk_disable(bs->clk);
return 0;
@@ -498,6 +563,8 @@ static int bcm63xx_spi_resume(struct device *dev)
clk_enable(bs->clk);
+ spi_master_resume(master);
+
return 0;
}
@@ -518,7 +585,7 @@ static struct platform_driver bcm63xx_spi_driver = {
.pm = BCM63XX_SPI_PM_OPS,
},
.probe = bcm63xx_spi_probe,
- .remove = __devexit_p(bcm63xx_spi_remove),
+ .remove = bcm63xx_spi_remove,
};
module_platform_driver(bcm63xx_spi_driver);
diff --git a/drivers/spi/spi-bfin-sport.c b/drivers/spi/spi-bfin-sport.c
index 6555ecd07302..39b0d1711b4e 100644
--- a/drivers/spi/spi-bfin-sport.c
+++ b/drivers/spi/spi-bfin-sport.c
@@ -416,8 +416,7 @@ bfin_sport_spi_pump_transfers(unsigned long data)
drv_data->cs_change = transfer->cs_change;
/* Bits per word setup */
- bits_per_word = transfer->bits_per_word ? :
- message->spi->bits_per_word ? : 8;
+ bits_per_word = transfer->bits_per_word;
if (bits_per_word % 16 == 0)
drv_data->ops = &bfin_sport_transfer_ops_u16;
else
@@ -755,8 +754,7 @@ bfin_sport_spi_destroy_queue(struct bfin_sport_spi_master_data *drv_data)
return 0;
}
-static int __devinit
-bfin_sport_spi_probe(struct platform_device *pdev)
+static int bfin_sport_spi_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct bfin5xx_spi_master *platform_info;
@@ -863,8 +861,7 @@ bfin_sport_spi_probe(struct platform_device *pdev)
}
/* stop hardware and remove the driver */
-static int __devexit
-bfin_sport_spi_remove(struct platform_device *pdev)
+static int bfin_sport_spi_remove(struct platform_device *pdev)
{
struct bfin_sport_spi_master_data *drv_data = platform_get_drvdata(pdev);
int status = 0;
@@ -935,7 +932,7 @@ static struct platform_driver bfin_sport_spi_driver = {
.owner = THIS_MODULE,
},
.probe = bfin_sport_spi_probe,
- .remove = __devexit_p(bfin_sport_spi_remove),
+ .remove = bfin_sport_spi_remove,
.suspend = bfin_sport_spi_suspend,
.resume = bfin_sport_spi_resume,
};
diff --git a/drivers/spi/spi-bfin5xx.c b/drivers/spi/spi-bfin5xx.c
index 9bb4d4af8547..317f564c899c 100644
--- a/drivers/spi/spi-bfin5xx.c
+++ b/drivers/spi/spi-bfin5xx.c
@@ -642,8 +642,7 @@ static void bfin_spi_pump_transfers(unsigned long data)
drv_data->cs_change = transfer->cs_change;
/* Bits per word setup */
- bits_per_word = transfer->bits_per_word ? :
- message->spi->bits_per_word ? : 8;
+ bits_per_word = transfer->bits_per_word;
if (bits_per_word % 16 == 0) {
drv_data->n_bytes = bits_per_word/8;
drv_data->len = (transfer->len) >> 1;
@@ -1274,7 +1273,7 @@ static int bfin_spi_destroy_queue(struct bfin_spi_master_data *drv_data)
return 0;
}
-static int __init bfin_spi_probe(struct platform_device *pdev)
+static int bfin_spi_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct bfin5xx_spi_master *platform_info;
@@ -1387,7 +1386,7 @@ out_error_get_res:
}
/* stop hardware and remove the driver */
-static int __devexit bfin_spi_remove(struct platform_device *pdev)
+static int bfin_spi_remove(struct platform_device *pdev)
{
struct bfin_spi_master_data *drv_data = platform_get_drvdata(pdev);
int status = 0;
@@ -1477,7 +1476,7 @@ static struct platform_driver bfin_spi_driver = {
},
.suspend = bfin_spi_suspend,
.resume = bfin_spi_resume,
- .remove = __devexit_p(bfin_spi_remove),
+ .remove = bfin_spi_remove,
};
static int __init bfin_spi_init(void)
diff --git a/drivers/spi/spi-bitbang.c b/drivers/spi/spi-bitbang.c
index aef59b1a15f7..a63d7da3bfe2 100644
--- a/drivers/spi/spi-bitbang.c
+++ b/drivers/spi/spi-bitbang.c
@@ -69,7 +69,7 @@ static unsigned bitbang_txrx_8(
unsigned ns,
struct spi_transfer *t
) {
- unsigned bits = t->bits_per_word ? : spi->bits_per_word;
+ unsigned bits = t->bits_per_word;
unsigned count = t->len;
const u8 *tx = t->tx_buf;
u8 *rx = t->rx_buf;
@@ -95,7 +95,7 @@ static unsigned bitbang_txrx_16(
unsigned ns,
struct spi_transfer *t
) {
- unsigned bits = t->bits_per_word ? : spi->bits_per_word;
+ unsigned bits = t->bits_per_word;
unsigned count = t->len;
const u16 *tx = t->tx_buf;
u16 *rx = t->rx_buf;
@@ -121,7 +121,7 @@ static unsigned bitbang_txrx_32(
unsigned ns,
struct spi_transfer *t
) {
- unsigned bits = t->bits_per_word ? : spi->bits_per_word;
+ unsigned bits = t->bits_per_word;
unsigned count = t->len;
const u32 *tx = t->tx_buf;
u32 *rx = t->rx_buf;
@@ -260,11 +260,11 @@ static void bitbang_work(struct work_struct *work)
struct spi_bitbang *bitbang =
container_of(work, struct spi_bitbang, work);
unsigned long flags;
+ struct spi_message *m, *_m;
spin_lock_irqsave(&bitbang->lock, flags);
bitbang->busy = 1;
- while (!list_empty(&bitbang->queue)) {
- struct spi_message *m;
+ list_for_each_entry_safe(m, _m, &bitbang->queue, queue) {
struct spi_device *spi;
unsigned nsecs;
struct spi_transfer *t = NULL;
@@ -273,9 +273,7 @@ static void bitbang_work(struct work_struct *work)
int status;
int do_setup = -1;
- m = container_of(bitbang->queue.next, struct spi_message,
- queue);
- list_del_init(&m->queue);
+ list_del(&m->queue);
spin_unlock_irqrestore(&bitbang->lock, flags);
/* FIXME this is made-up ... the correct value is known to
@@ -346,17 +344,14 @@ static void bitbang_work(struct work_struct *work)
if (t->delay_usecs)
udelay(t->delay_usecs);
- if (!cs_change)
- continue;
- if (t->transfer_list.next == &m->transfers)
- break;
-
- /* sometimes a short mid-message deselect of the chip
- * may be needed to terminate a mode or command
- */
- ndelay(nsecs);
- bitbang->chipselect(spi, BITBANG_CS_INACTIVE);
- ndelay(nsecs);
+ if (cs_change && !list_is_last(&t->transfer_list, &m->transfers)) {
+ /* sometimes a short mid-message deselect of the chip
+ * may be needed to terminate a mode or command
+ */
+ ndelay(nsecs);
+ bitbang->chipselect(spi, BITBANG_CS_INACTIVE);
+ ndelay(nsecs);
+ }
}
m->status = status;
@@ -432,40 +427,41 @@ EXPORT_SYMBOL_GPL(spi_bitbang_transfer);
*/
int spi_bitbang_start(struct spi_bitbang *bitbang)
{
- int status;
+ struct spi_master *master = bitbang->master;
+ int status;
- if (!bitbang->master || !bitbang->chipselect)
+ if (!master || !bitbang->chipselect)
return -EINVAL;
INIT_WORK(&bitbang->work, bitbang_work);
spin_lock_init(&bitbang->lock);
INIT_LIST_HEAD(&bitbang->queue);
- if (!bitbang->master->mode_bits)
- bitbang->master->mode_bits = SPI_CPOL | SPI_CPHA | bitbang->flags;
+ if (!master->mode_bits)
+ master->mode_bits = SPI_CPOL | SPI_CPHA | bitbang->flags;
- if (!bitbang->master->transfer)
- bitbang->master->transfer = spi_bitbang_transfer;
+ if (!master->transfer)
+ master->transfer = spi_bitbang_transfer;
if (!bitbang->txrx_bufs) {
bitbang->use_dma = 0;
bitbang->txrx_bufs = spi_bitbang_bufs;
- if (!bitbang->master->setup) {
+ if (!master->setup) {
if (!bitbang->setup_transfer)
bitbang->setup_transfer =
spi_bitbang_setup_transfer;
- bitbang->master->setup = spi_bitbang_setup;
- bitbang->master->cleanup = spi_bitbang_cleanup;
+ master->setup = spi_bitbang_setup;
+ master->cleanup = spi_bitbang_cleanup;
}
- } else if (!bitbang->master->setup)
+ } else if (!master->setup)
return -EINVAL;
- if (bitbang->master->transfer == spi_bitbang_transfer &&
+ if (master->transfer == spi_bitbang_transfer &&
!bitbang->setup_transfer)
return -EINVAL;
/* this task is the only thing to touch the SPI bits */
bitbang->busy = 0;
bitbang->workqueue = create_singlethread_workqueue(
- dev_name(bitbang->master->dev.parent));
+ dev_name(master->dev.parent));
if (bitbang->workqueue == NULL) {
status = -EBUSY;
goto err1;
@@ -474,7 +470,7 @@ int spi_bitbang_start(struct spi_bitbang *bitbang)
/* driver may get busy before register() returns, especially
* if someone registered boardinfo for devices
*/
- status = spi_register_master(bitbang->master);
+ status = spi_register_master(master);
if (status < 0)
goto err2;
diff --git a/drivers/spi/spi-clps711x.c b/drivers/spi/spi-clps711x.c
new file mode 100644
index 000000000000..a11cbf02691a
--- /dev/null
+++ b/drivers/spi/spi-clps711x.c
@@ -0,0 +1,296 @@
+/*
+ * CLPS711X SPI bus driver
+ *
+ * Copyright (C) 2012 Alexander Shiyan <shc_work@mail.ru>
+ *
+ * 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.
+ */
+
+#include <linux/io.h>
+#include <linux/clk.h>
+#include <linux/init.h>
+#include <linux/gpio.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/spi/spi.h>
+#include <linux/platform_data/spi-clps711x.h>
+
+#include <mach/hardware.h>
+
+#define DRIVER_NAME "spi-clps711x"
+
+struct spi_clps711x_data {
+ struct completion done;
+
+ struct clk *spi_clk;
+ u32 max_speed_hz;
+
+ u8 *tx_buf;
+ u8 *rx_buf;
+ int count;
+ int len;
+
+ int chipselect[0];
+};
+
+static int spi_clps711x_setup(struct spi_device *spi)
+{
+ struct spi_clps711x_data *hw = spi_master_get_devdata(spi->master);
+
+ if (spi->bits_per_word != 8) {
+ dev_err(&spi->dev, "Unsupported master bus width %i\n",
+ spi->bits_per_word);
+ return -EINVAL;
+ }
+
+ /* We are expect that SPI-device is not selected */
+ gpio_direction_output(hw->chipselect[spi->chip_select],
+ !(spi->mode & SPI_CS_HIGH));
+
+ return 0;
+}
+
+static void spi_clps711x_setup_mode(struct spi_device *spi)
+{
+ /* Setup edge for transfer */
+ if (spi->mode & SPI_CPHA)
+ clps_writew(clps_readw(SYSCON3) | SYSCON3_ADCCKNSEN, SYSCON3);
+ else
+ clps_writew(clps_readw(SYSCON3) & ~SYSCON3_ADCCKNSEN, SYSCON3);
+}
+
+static int spi_clps711x_setup_xfer(struct spi_device *spi,
+ struct spi_transfer *xfer)
+{
+ u32 speed = xfer->speed_hz ? : spi->max_speed_hz;
+ u8 bpw = xfer->bits_per_word;
+ struct spi_clps711x_data *hw = spi_master_get_devdata(spi->master);
+
+ if (bpw != 8) {
+ dev_err(&spi->dev, "Unsupported master bus width %i\n", bpw);
+ return -EINVAL;
+ }
+
+ /* Setup SPI frequency divider */
+ if (!speed || (speed >= hw->max_speed_hz))
+ clps_writel((clps_readl(SYSCON1) & ~SYSCON1_ADCKSEL_MASK) |
+ SYSCON1_ADCKSEL(3), SYSCON1);
+ else if (speed >= (hw->max_speed_hz / 2))
+ clps_writel((clps_readl(SYSCON1) & ~SYSCON1_ADCKSEL_MASK) |
+ SYSCON1_ADCKSEL(2), SYSCON1);
+ else if (speed >= (hw->max_speed_hz / 8))
+ clps_writel((clps_readl(SYSCON1) & ~SYSCON1_ADCKSEL_MASK) |
+ SYSCON1_ADCKSEL(1), SYSCON1);
+ else
+ clps_writel((clps_readl(SYSCON1) & ~SYSCON1_ADCKSEL_MASK) |
+ SYSCON1_ADCKSEL(0), SYSCON1);
+
+ return 0;
+}
+
+static int spi_clps711x_transfer_one_message(struct spi_master *master,
+ struct spi_message *msg)
+{
+ struct spi_clps711x_data *hw = spi_master_get_devdata(master);
+ struct spi_transfer *xfer;
+ int status = 0, cs = hw->chipselect[msg->spi->chip_select];
+ u32 data;
+
+ spi_clps711x_setup_mode(msg->spi);
+
+ list_for_each_entry(xfer, &msg->transfers, transfer_list) {
+ if (spi_clps711x_setup_xfer(msg->spi, xfer)) {
+ status = -EINVAL;
+ goto out_xfr;
+ }
+
+ gpio_set_value(cs, !!(msg->spi->mode & SPI_CS_HIGH));
+
+ INIT_COMPLETION(hw->done);
+
+ hw->count = 0;
+ hw->len = xfer->len;
+ hw->tx_buf = (u8 *)xfer->tx_buf;
+ hw->rx_buf = (u8 *)xfer->rx_buf;
+
+ /* Initiate transfer */
+ data = hw->tx_buf ? hw->tx_buf[hw->count] : 0;
+ clps_writel(data | SYNCIO_FRMLEN(8) | SYNCIO_TXFRMEN, SYNCIO);
+
+ wait_for_completion(&hw->done);
+
+ if (xfer->delay_usecs)
+ udelay(xfer->delay_usecs);
+
+ if (xfer->cs_change ||
+ list_is_last(&xfer->transfer_list, &msg->transfers))
+ gpio_set_value(cs, !(msg->spi->mode & SPI_CS_HIGH));
+
+ msg->actual_length += xfer->len;
+ }
+
+out_xfr:
+ msg->status = status;
+ spi_finalize_current_message(master);
+
+ return 0;
+}
+
+static irqreturn_t spi_clps711x_isr(int irq, void *dev_id)
+{
+ struct spi_clps711x_data *hw = (struct spi_clps711x_data *)dev_id;
+ u32 data;
+
+ /* Handle RX */
+ data = clps_readb(SYNCIO);
+ if (hw->rx_buf)
+ hw->rx_buf[hw->count] = (u8)data;
+
+ hw->count++;
+
+ /* Handle TX */
+ if (hw->count < hw->len) {
+ data = hw->tx_buf ? hw->tx_buf[hw->count] : 0;
+ clps_writel(data | SYNCIO_FRMLEN(8) | SYNCIO_TXFRMEN, SYNCIO);
+ } else
+ complete(&hw->done);
+
+ return IRQ_HANDLED;
+}
+
+static int spi_clps711x_probe(struct platform_device *pdev)
+{
+ int i, ret;
+ struct spi_master *master;
+ struct spi_clps711x_data *hw;
+ struct spi_clps711x_pdata *pdata = dev_get_platdata(&pdev->dev);
+
+ if (!pdata) {
+ dev_err(&pdev->dev, "No platform data supplied\n");
+ return -EINVAL;
+ }
+
+ if (pdata->num_chipselect < 1) {
+ dev_err(&pdev->dev, "At least one CS must be defined\n");
+ return -EINVAL;
+ }
+
+ master = spi_alloc_master(&pdev->dev,
+ sizeof(struct spi_clps711x_data) +
+ sizeof(int) * pdata->num_chipselect);
+ if (!master) {
+ dev_err(&pdev->dev, "SPI allocating memory error\n");
+ return -ENOMEM;
+ }
+
+ master->bus_num = pdev->id;
+ master->mode_bits = SPI_CPHA | SPI_CS_HIGH;
+ master->num_chipselect = pdata->num_chipselect;
+ master->setup = spi_clps711x_setup;
+ master->transfer_one_message = spi_clps711x_transfer_one_message;
+
+ hw = spi_master_get_devdata(master);
+
+ for (i = 0; i < master->num_chipselect; i++) {
+ hw->chipselect[i] = pdata->chipselect[i];
+ if (!gpio_is_valid(hw->chipselect[i])) {
+ dev_err(&pdev->dev, "Invalid CS GPIO %i\n", i);
+ ret = -EINVAL;
+ goto err_out;
+ }
+ if (gpio_request(hw->chipselect[i], DRIVER_NAME)) {
+ dev_err(&pdev->dev, "Can't get CS GPIO %i\n", i);
+ ret = -EINVAL;
+ goto err_out;
+ }
+ }
+
+ hw->spi_clk = devm_clk_get(&pdev->dev, "spi");
+ if (IS_ERR(hw->spi_clk)) {
+ dev_err(&pdev->dev, "Can't get clocks\n");
+ ret = PTR_ERR(hw->spi_clk);
+ goto err_out;
+ }
+ hw->max_speed_hz = clk_get_rate(hw->spi_clk);
+
+ init_completion(&hw->done);
+ platform_set_drvdata(pdev, master);
+
+ /* Disable extended mode due hardware problems */
+ clps_writew(clps_readw(SYSCON3) & ~SYSCON3_ADCCON, SYSCON3);
+
+ /* Clear possible pending interrupt */
+ clps_readl(SYNCIO);
+
+ ret = devm_request_irq(&pdev->dev, IRQ_SSEOTI, spi_clps711x_isr, 0,
+ dev_name(&pdev->dev), hw);
+ if (ret) {
+ dev_err(&pdev->dev, "Can't request IRQ\n");
+ clk_put(hw->spi_clk);
+ goto clk_out;
+ }
+
+ ret = spi_register_master(master);
+ if (!ret) {
+ dev_info(&pdev->dev,
+ "SPI bus driver initialized. Master clock %u Hz\n",
+ hw->max_speed_hz);
+ return 0;
+ }
+
+ dev_err(&pdev->dev, "Failed to register master\n");
+ devm_free_irq(&pdev->dev, IRQ_SSEOTI, hw);
+
+clk_out:
+ devm_clk_put(&pdev->dev, hw->spi_clk);
+
+err_out:
+ while (--i >= 0)
+ if (gpio_is_valid(hw->chipselect[i]))
+ gpio_free(hw->chipselect[i]);
+
+ platform_set_drvdata(pdev, NULL);
+ spi_master_put(master);
+ kfree(master);
+
+ return ret;
+}
+
+static int spi_clps711x_remove(struct platform_device *pdev)
+{
+ int i;
+ struct spi_master *master = platform_get_drvdata(pdev);
+ struct spi_clps711x_data *hw = spi_master_get_devdata(master);
+
+ devm_free_irq(&pdev->dev, IRQ_SSEOTI, hw);
+
+ for (i = 0; i < master->num_chipselect; i++)
+ if (gpio_is_valid(hw->chipselect[i]))
+ gpio_free(hw->chipselect[i]);
+
+ devm_clk_put(&pdev->dev, hw->spi_clk);
+ platform_set_drvdata(pdev, NULL);
+ spi_unregister_master(master);
+ kfree(master);
+
+ return 0;
+}
+
+static struct platform_driver clps711x_spi_driver = {
+ .driver = {
+ .name = DRIVER_NAME,
+ .owner = THIS_MODULE,
+ },
+ .probe = spi_clps711x_probe,
+ .remove = spi_clps711x_remove,
+};
+module_platform_driver(clps711x_spi_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Alexander Shiyan <shc_work@mail.ru>");
+MODULE_DESCRIPTION("CLPS711X SPI bus driver");
diff --git a/drivers/spi/spi-coldfire-qspi.c b/drivers/spi/spi-coldfire-qspi.c
index 764bfee75920..7b5cc9e4e94d 100644
--- a/drivers/spi/spi-coldfire-qspi.c
+++ b/drivers/spi/spi-coldfire-qspi.c
@@ -329,8 +329,7 @@ static int mcfqspi_transfer_one_message(struct spi_master *master,
mcfqspi_cs_select(mcfqspi, spi->chip_select, cs_high);
mcfqspi_wr_qir(mcfqspi, MCFQSPI_QIR_SPIFE);
- if ((t->bits_per_word ? t->bits_per_word :
- spi->bits_per_word) == 8)
+ if (t->bits_per_word == 8)
mcfqspi_transfer_msg8(mcfqspi, t->len, t->tx_buf,
t->rx_buf);
else
@@ -401,7 +400,7 @@ static int mcfqspi_setup(struct spi_device *spi)
return 0;
}
-static int __devinit mcfqspi_probe(struct platform_device *pdev)
+static int mcfqspi_probe(struct platform_device *pdev)
{
struct spi_master *master;
struct mcfqspi *mcfqspi;
@@ -515,7 +514,7 @@ fail0:
return status;
}
-static int __devexit mcfqspi_remove(struct platform_device *pdev)
+static int mcfqspi_remove(struct platform_device *pdev)
{
struct spi_master *master = platform_get_drvdata(pdev);
struct mcfqspi *mcfqspi = spi_master_get_devdata(master);
@@ -594,7 +593,7 @@ static struct platform_driver mcfqspi_driver = {
.driver.owner = THIS_MODULE,
.driver.pm = &mcfqspi_pm,
.probe = mcfqspi_probe,
- .remove = __devexit_p(mcfqspi_remove),
+ .remove = mcfqspi_remove,
};
module_platform_driver(mcfqspi_driver);
diff --git a/drivers/spi/spi-davinci.c b/drivers/spi/spi-davinci.c
index 147dfa87a64b..8234d2259722 100644
--- a/drivers/spi/spi-davinci.c
+++ b/drivers/spi/spi-davinci.c
@@ -28,6 +28,8 @@
#include <linux/dmaengine.h>
#include <linux/dma-mapping.h>
#include <linux/edma.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
#include <linux/spi/spi.h>
#include <linux/spi/spi_bitbang.h>
#include <linux/slab.h>
@@ -135,7 +137,7 @@ struct davinci_spi {
int dma_rx_chnum;
int dma_tx_chnum;
- struct davinci_spi_platform_data *pdata;
+ struct davinci_spi_platform_data pdata;
void (*get_rx)(u32 rx_data, struct davinci_spi *);
u32 (*get_tx)(struct davinci_spi *);
@@ -213,7 +215,7 @@ static void davinci_spi_chipselect(struct spi_device *spi, int value)
bool gpio_chipsel = false;
dspi = spi_master_get_devdata(spi->master);
- pdata = dspi->pdata;
+ pdata = &dspi->pdata;
if (pdata->chip_sel && chip_sel < pdata->num_chipselect &&
pdata->chip_sel[chip_sel] != SPI_INTERN_CS)
@@ -392,7 +394,7 @@ static int davinci_spi_setup(struct spi_device *spi)
struct davinci_spi_platform_data *pdata;
dspi = spi_master_get_devdata(spi->master);
- pdata = dspi->pdata;
+ pdata = &dspi->pdata;
/* if bits per word length is zero then set it default 8 */
if (!spi->bits_per_word)
@@ -534,7 +536,7 @@ static int davinci_spi_bufs(struct spi_device *spi, struct spi_transfer *t)
struct scatterlist sg_rx, sg_tx;
dspi = spi_master_get_devdata(spi->master);
- pdata = dspi->pdata;
+ pdata = &dspi->pdata;
spicfg = (struct davinci_spi_config *)spi->controller_data;
if (!spicfg)
spicfg = &davinci_spi_default_cfg;
@@ -700,6 +702,19 @@ err_alloc_dummy_buf:
}
/**
+ * dummy_thread_fn - dummy thread function
+ * @irq: IRQ number for this SPI Master
+ * @context_data: structure for SPI Master controller davinci_spi
+ *
+ * This is to satisfy the request_threaded_irq() API so that the irq
+ * handler is called in interrupt context.
+ */
+static irqreturn_t dummy_thread_fn(s32 irq, void *data)
+{
+ return IRQ_HANDLED;
+}
+
+/**
* davinci_spi_irq - Interrupt handler for SPI Master Controller
* @irq: IRQ number for this SPI Master
* @context_data: structure for SPI Master controller davinci_spi
@@ -758,6 +773,70 @@ rx_dma_failed:
return r;
}
+#if defined(CONFIG_OF)
+static const struct of_device_id davinci_spi_of_match[] = {
+ {
+ .compatible = "ti,dm644x-spi",
+ },
+ {
+ .compatible = "ti,da8xx-spi",
+ .data = (void *)SPI_VERSION_2,
+ },
+ { },
+};
+MODULE_DEVICE_TABLE(of, davini_spi_of_match);
+
+/**
+ * spi_davinci_get_pdata - Get platform data from DTS binding
+ * @pdev: ptr to platform data
+ * @dspi: ptr to driver data
+ *
+ * Parses and populates pdata in dspi from device tree bindings.
+ *
+ * NOTE: Not all platform data params are supported currently.
+ */
+static int spi_davinci_get_pdata(struct platform_device *pdev,
+ struct davinci_spi *dspi)
+{
+ struct device_node *node = pdev->dev.of_node;
+ struct davinci_spi_platform_data *pdata;
+ unsigned int num_cs, intr_line = 0;
+ const struct of_device_id *match;
+
+ pdata = &dspi->pdata;
+
+ pdata->version = SPI_VERSION_1;
+ match = of_match_device(of_match_ptr(davinci_spi_of_match),
+ &pdev->dev);
+ if (!match)
+ return -ENODEV;
+
+ /* match data has the SPI version number for SPI_VERSION_2 */
+ if (match->data == (void *)SPI_VERSION_2)
+ pdata->version = SPI_VERSION_2;
+
+ /*
+ * default num_cs is 1 and all chipsel are internal to the chip
+ * indicated by chip_sel being NULL. GPIO based CS is not
+ * supported yet in DT bindings.
+ */
+ num_cs = 1;
+ of_property_read_u32(node, "num-cs", &num_cs);
+ pdata->num_chipselect = num_cs;
+ of_property_read_u32(node, "ti,davinci-spi-intr-line", &intr_line);
+ pdata->intr_line = intr_line;
+ return 0;
+}
+#else
+#define davinci_spi_of_match NULL
+static struct davinci_spi_platform_data
+ *spi_davinci_get_pdata(struct platform_device *pdev,
+ struct davinci_spi *dspi)
+{
+ return -ENODEV;
+}
+#endif
+
/**
* davinci_spi_probe - probe function for SPI Master Controller
* @pdev: platform_device structure which contains plateform specific data
@@ -769,7 +848,7 @@ rx_dma_failed:
* It will invoke spi_bitbang_start to create work queue so that client driver
* can register transfer method to work queue.
*/
-static int __devinit davinci_spi_probe(struct platform_device *pdev)
+static int davinci_spi_probe(struct platform_device *pdev)
{
struct spi_master *master;
struct davinci_spi *dspi;
@@ -780,12 +859,6 @@ static int __devinit davinci_spi_probe(struct platform_device *pdev)
int i = 0, ret = 0;
u32 spipc0;
- pdata = pdev->dev.platform_data;
- if (pdata == NULL) {
- ret = -ENODEV;
- goto err;
- }
-
master = spi_alloc_master(&pdev->dev, sizeof(struct davinci_spi));
if (master == NULL) {
ret = -ENOMEM;
@@ -800,6 +873,19 @@ static int __devinit davinci_spi_probe(struct platform_device *pdev)
goto free_master;
}
+ if (pdev->dev.platform_data) {
+ pdata = pdev->dev.platform_data;
+ dspi->pdata = *pdata;
+ } else {
+ /* update dspi pdata with that from the DT */
+ ret = spi_davinci_get_pdata(pdev, dspi);
+ if (ret < 0)
+ goto free_master;
+ }
+
+ /* pdata in dspi is now updated and point pdata to that */
+ pdata = &dspi->pdata;
+
r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (r == NULL) {
ret = -ENOENT;
@@ -807,7 +893,6 @@ static int __devinit davinci_spi_probe(struct platform_device *pdev)
}
dspi->pbase = r->start;
- dspi->pdata = pdata;
mem = request_mem_region(r->start, resource_size(r), pdev->name);
if (mem == NULL) {
@@ -827,8 +912,8 @@ static int __devinit davinci_spi_probe(struct platform_device *pdev)
goto unmap_io;
}
- ret = request_irq(dspi->irq, davinci_spi_irq, 0, dev_name(&pdev->dev),
- dspi);
+ ret = request_threaded_irq(dspi->irq, davinci_spi_irq, dummy_thread_fn,
+ 0, dev_name(&pdev->dev), dspi);
if (ret)
goto unmap_io;
@@ -843,8 +928,9 @@ static int __devinit davinci_spi_probe(struct platform_device *pdev)
ret = -ENODEV;
goto put_master;
}
- clk_enable(dspi->clk);
+ clk_prepare_enable(dspi->clk);
+ master->dev.of_node = pdev->dev.of_node;
master->bus_num = pdev->id;
master->num_chipselect = pdata->num_chipselect;
master->setup = davinci_spi_setup;
@@ -927,7 +1013,7 @@ free_dma:
dma_release_channel(dspi->dma_rx);
dma_release_channel(dspi->dma_tx);
free_clk:
- clk_disable(dspi->clk);
+ clk_disable_unprepare(dspi->clk);
clk_put(dspi->clk);
put_master:
spi_master_put(master);
@@ -952,7 +1038,7 @@ err:
* It will also call spi_bitbang_stop to destroy the work queue which was
* created by spi_bitbang_start.
*/
-static int __devexit davinci_spi_remove(struct platform_device *pdev)
+static int davinci_spi_remove(struct platform_device *pdev)
{
struct davinci_spi *dspi;
struct spi_master *master;
@@ -963,7 +1049,7 @@ static int __devexit davinci_spi_remove(struct platform_device *pdev)
spi_bitbang_stop(&dspi->bitbang);
- clk_disable(dspi->clk);
+ clk_disable_unprepare(dspi->clk);
clk_put(dspi->clk);
spi_master_put(master);
free_irq(dspi->irq, dspi);
@@ -978,9 +1064,10 @@ static struct platform_driver davinci_spi_driver = {
.driver = {
.name = "spi_davinci",
.owner = THIS_MODULE,
+ .of_match_table = davinci_spi_of_match,
},
.probe = davinci_spi_probe,
- .remove = __devexit_p(davinci_spi_remove),
+ .remove = davinci_spi_remove,
};
module_platform_driver(davinci_spi_driver);
diff --git a/drivers/spi/spi-dw-mmio.c b/drivers/spi/spi-dw-mmio.c
index db2f1ba06eab..4a6d5c9057a4 100644
--- a/drivers/spi/spi-dw-mmio.c
+++ b/drivers/spi/spi-dw-mmio.c
@@ -26,7 +26,7 @@ struct dw_spi_mmio {
struct clk *clk;
};
-static int __devinit dw_spi_mmio_probe(struct platform_device *pdev)
+static int dw_spi_mmio_probe(struct platform_device *pdev)
{
struct dw_spi_mmio *dwsmmio;
struct dw_spi *dws;
@@ -106,7 +106,7 @@ err_end:
return ret;
}
-static int __devexit dw_spi_mmio_remove(struct platform_device *pdev)
+static int dw_spi_mmio_remove(struct platform_device *pdev)
{
struct dw_spi_mmio *dwsmmio = platform_get_drvdata(pdev);
struct resource *mem;
@@ -129,7 +129,7 @@ static int __devexit dw_spi_mmio_remove(struct platform_device *pdev)
static struct platform_driver dw_spi_mmio_driver = {
.probe = dw_spi_mmio_probe,
- .remove = __devexit_p(dw_spi_mmio_remove),
+ .remove = dw_spi_mmio_remove,
.driver = {
.name = DRIVER_NAME,
.owner = THIS_MODULE,
diff --git a/drivers/spi/spi-dw-pci.c b/drivers/spi/spi-dw-pci.c
index ff81abbb3066..6055c8d9fdd7 100644
--- a/drivers/spi/spi-dw-pci.c
+++ b/drivers/spi/spi-dw-pci.c
@@ -32,7 +32,7 @@ struct dw_spi_pci {
struct dw_spi dws;
};
-static int __devinit spi_pci_probe(struct pci_dev *pdev,
+static int spi_pci_probe(struct pci_dev *pdev,
const struct pci_device_id *ent)
{
struct dw_spi_pci *dwpci;
@@ -105,7 +105,7 @@ err_disable:
return ret;
}
-static void __devexit spi_pci_remove(struct pci_dev *pdev)
+static void spi_pci_remove(struct pci_dev *pdev)
{
struct dw_spi_pci *dwpci = pci_get_drvdata(pdev);
@@ -159,7 +159,7 @@ static struct pci_driver dw_spi_driver = {
.name = DRIVER_NAME,
.id_table = pci_ids,
.probe = spi_pci_probe,
- .remove = __devexit_p(spi_pci_remove),
+ .remove = spi_pci_remove,
.suspend = spi_suspend,
.resume = spi_resume,
};
diff --git a/drivers/spi/spi-dw.c b/drivers/spi/spi-dw.c
index d1a495f64e2d..c1abc06899e7 100644
--- a/drivers/spi/spi-dw.c
+++ b/drivers/spi/spi-dw.c
@@ -696,7 +696,7 @@ static void dw_spi_cleanup(struct spi_device *spi)
kfree(chip);
}
-static int __devinit init_queue(struct dw_spi *dws)
+static int init_queue(struct dw_spi *dws)
{
INIT_LIST_HEAD(&dws->queue);
spin_lock_init(&dws->lock);
@@ -795,7 +795,7 @@ static void spi_hw_init(struct dw_spi *dws)
}
}
-int __devinit dw_spi_add_host(struct dw_spi *dws)
+int dw_spi_add_host(struct dw_spi *dws)
{
struct spi_master *master;
int ret;
@@ -877,7 +877,7 @@ exit:
}
EXPORT_SYMBOL_GPL(dw_spi_add_host);
-void __devexit dw_spi_remove_host(struct dw_spi *dws)
+void dw_spi_remove_host(struct dw_spi *dws)
{
int status = 0;
diff --git a/drivers/spi/spi-ep93xx.c b/drivers/spi/spi-ep93xx.c
index 3a219599612a..d7bac60253c9 100644
--- a/drivers/spi/spi-ep93xx.c
+++ b/drivers/spi/spi-ep93xx.c
@@ -446,7 +446,7 @@ static inline int bits_per_word(const struct ep93xx_spi *espi)
struct spi_message *msg = espi->current_msg;
struct spi_transfer *t = msg->state;
- return t->bits_per_word ? t->bits_per_word : msg->spi->bits_per_word;
+ return t->bits_per_word;
}
static void ep93xx_do_write(struct ep93xx_spi *espi, struct spi_transfer *t)
@@ -1023,7 +1023,7 @@ static void ep93xx_spi_release_dma(struct ep93xx_spi *espi)
free_page((unsigned long)espi->zeropage);
}
-static int __devinit ep93xx_spi_probe(struct platform_device *pdev)
+static int ep93xx_spi_probe(struct platform_device *pdev)
{
struct spi_master *master;
struct ep93xx_spi_info *info;
@@ -1085,10 +1085,9 @@ static int __devinit ep93xx_spi_probe(struct platform_device *pdev)
espi->sspdr_phys = res->start + SSPDR;
- espi->regs_base = devm_request_and_ioremap(&pdev->dev, res);
- if (!espi->regs_base) {
- dev_err(&pdev->dev, "failed to map resources\n");
- error = -ENODEV;
+ espi->regs_base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(espi->regs_base)) {
+ error = PTR_ERR(espi->regs_base);
goto fail_put_clock;
}
@@ -1138,7 +1137,7 @@ fail_release_master:
return error;
}
-static int __devexit ep93xx_spi_remove(struct platform_device *pdev)
+static int ep93xx_spi_remove(struct platform_device *pdev)
{
struct spi_master *master = platform_get_drvdata(pdev);
struct ep93xx_spi *espi = spi_master_get_devdata(master);
@@ -1180,7 +1179,7 @@ static struct platform_driver ep93xx_spi_driver = {
.owner = THIS_MODULE,
},
.probe = ep93xx_spi_probe,
- .remove = __devexit_p(ep93xx_spi_remove),
+ .remove = ep93xx_spi_remove,
};
module_platform_driver(ep93xx_spi_driver);
diff --git a/drivers/spi/spi-falcon.c b/drivers/spi/spi-falcon.c
index 8f6aa735a24c..c7a74f0ef892 100644
--- a/drivers/spi/spi-falcon.c
+++ b/drivers/spi/spi-falcon.c
@@ -398,12 +398,12 @@ static int falcon_sflash_xfer_one(struct spi_master *master,
}
m->status = ret;
- m->complete(m->context);
+ spi_finalize_current_message(master);
return 0;
}
-static int __devinit falcon_sflash_probe(struct platform_device *pdev)
+static int falcon_sflash_probe(struct platform_device *pdev)
{
struct falcon_sflash *priv;
struct spi_master *master;
@@ -423,6 +423,7 @@ static int __devinit falcon_sflash_probe(struct platform_device *pdev)
master->mode_bits = SPI_MODE_3;
master->num_chipselect = 1;
+ master->flags = SPI_MASTER_HALF_DUPLEX;
master->bus_num = -1;
master->setup = falcon_sflash_setup;
master->prepare_transfer_hardware = falcon_sflash_prepare_xfer;
@@ -438,7 +439,7 @@ static int __devinit falcon_sflash_probe(struct platform_device *pdev)
return ret;
}
-static int __devexit falcon_sflash_remove(struct platform_device *pdev)
+static int falcon_sflash_remove(struct platform_device *pdev)
{
struct falcon_sflash *priv = platform_get_drvdata(pdev);
@@ -455,7 +456,7 @@ MODULE_DEVICE_TABLE(of, falcon_sflash_match);
static struct platform_driver falcon_sflash_driver = {
.probe = falcon_sflash_probe,
- .remove = __devexit_p(falcon_sflash_remove),
+ .remove = falcon_sflash_remove,
.driver = {
.name = DRV_NAME,
.owner = THIS_MODULE,
diff --git a/drivers/spi/spi-fsl-espi.c b/drivers/spi/spi-fsl-espi.c
index 27bdc47b5250..24610ca8955d 100644
--- a/drivers/spi/spi-fsl-espi.c
+++ b/drivers/spi/spi-fsl-espi.c
@@ -587,7 +587,7 @@ static void fsl_espi_remove(struct mpc8xxx_spi *mspi)
iounmap(mspi->reg_base);
}
-static struct spi_master * __devinit fsl_espi_probe(struct device *dev,
+static struct spi_master * fsl_espi_probe(struct device *dev,
struct resource *mem, unsigned int irq)
{
struct fsl_spi_platform_data *pdata = dev->platform_data;
@@ -686,7 +686,7 @@ static int of_fsl_espi_get_chipselects(struct device *dev)
return 0;
}
-static int __devinit of_fsl_espi_probe(struct platform_device *ofdev)
+static int of_fsl_espi_probe(struct platform_device *ofdev)
{
struct device *dev = &ofdev->dev;
struct device_node *np = ofdev->dev.of_node;
@@ -725,7 +725,7 @@ err:
return ret;
}
-static int __devexit of_fsl_espi_remove(struct platform_device *dev)
+static int of_fsl_espi_remove(struct platform_device *dev)
{
return mpc8xxx_spi_remove(&dev->dev);
}
@@ -743,7 +743,7 @@ static struct platform_driver fsl_espi_driver = {
.of_match_table = of_fsl_espi_match,
},
.probe = of_fsl_espi_probe,
- .remove = __devexit_p(of_fsl_espi_remove),
+ .remove = of_fsl_espi_remove,
};
module_platform_driver(fsl_espi_driver);
diff --git a/drivers/spi/spi-fsl-lib.c b/drivers/spi/spi-fsl-lib.c
index 1503574b215a..8ade675a04f1 100644
--- a/drivers/spi/spi-fsl-lib.c
+++ b/drivers/spi/spi-fsl-lib.c
@@ -169,7 +169,7 @@ err:
return ret;
}
-int __devexit mpc8xxx_spi_remove(struct device *dev)
+int mpc8xxx_spi_remove(struct device *dev)
{
struct mpc8xxx_spi *mpc8xxx_spi;
struct spi_master *master;
@@ -189,7 +189,7 @@ int __devexit mpc8xxx_spi_remove(struct device *dev)
return 0;
}
-int __devinit of_mpc8xxx_spi_probe(struct platform_device *ofdev)
+int of_mpc8xxx_spi_probe(struct platform_device *ofdev)
{
struct device *dev = &ofdev->dev;
struct device_node *np = ofdev->dev.of_node;
diff --git a/drivers/spi/spi-fsl-spi.c b/drivers/spi/spi-fsl-spi.c
index 6a62934ca74c..086a9eef2e05 100644
--- a/drivers/spi/spi-fsl-spi.c
+++ b/drivers/spi/spi-fsl-spi.c
@@ -843,7 +843,7 @@ static void fsl_spi_remove(struct mpc8xxx_spi *mspi)
fsl_spi_cpm_free(mspi);
}
-static struct spi_master * __devinit fsl_spi_probe(struct device *dev,
+static struct spi_master * fsl_spi_probe(struct device *dev,
struct resource *mem, unsigned int irq)
{
struct fsl_spi_platform_data *pdata = dev->platform_data;
@@ -947,12 +947,12 @@ static int of_fsl_spi_get_chipselects(struct device *dev)
struct device_node *np = dev->of_node;
struct fsl_spi_platform_data *pdata = dev->platform_data;
struct mpc8xxx_spi_probe_info *pinfo = to_of_pinfo(pdata);
- unsigned int ngpios;
+ int ngpios;
int i = 0;
int ret;
ngpios = of_gpio_count(np);
- if (!ngpios) {
+ if (ngpios <= 0) {
/*
* SPI w/o chip-select line. One SPI device is still permitted
* though.
@@ -1041,7 +1041,7 @@ static int of_fsl_spi_free_chipselects(struct device *dev)
return 0;
}
-static int __devinit of_fsl_spi_probe(struct platform_device *ofdev)
+static int of_fsl_spi_probe(struct platform_device *ofdev)
{
struct device *dev = &ofdev->dev;
struct device_node *np = ofdev->dev.of_node;
@@ -1081,7 +1081,7 @@ err:
return ret;
}
-static int __devexit of_fsl_spi_remove(struct platform_device *ofdev)
+static int of_fsl_spi_remove(struct platform_device *ofdev)
{
int ret;
@@ -1105,7 +1105,7 @@ static struct platform_driver of_fsl_spi_driver = {
.of_match_table = of_fsl_spi_match,
},
.probe = of_fsl_spi_probe,
- .remove = __devexit_p(of_fsl_spi_remove),
+ .remove = of_fsl_spi_remove,
};
#ifdef CONFIG_MPC832x_RDB
@@ -1116,7 +1116,7 @@ static struct platform_driver of_fsl_spi_driver = {
* tree can work with OpenFirmware driver. But for now we support old trees
* as well.
*/
-static int __devinit plat_mpc8xxx_spi_probe(struct platform_device *pdev)
+static int plat_mpc8xxx_spi_probe(struct platform_device *pdev)
{
struct resource *mem;
int irq;
@@ -1139,7 +1139,7 @@ static int __devinit plat_mpc8xxx_spi_probe(struct platform_device *pdev)
return 0;
}
-static int __devexit plat_mpc8xxx_spi_remove(struct platform_device *pdev)
+static int plat_mpc8xxx_spi_remove(struct platform_device *pdev)
{
return mpc8xxx_spi_remove(&pdev->dev);
}
@@ -1147,7 +1147,7 @@ static int __devexit plat_mpc8xxx_spi_remove(struct platform_device *pdev)
MODULE_ALIAS("platform:mpc8xxx_spi");
static struct platform_driver mpc8xxx_spi_driver = {
.probe = plat_mpc8xxx_spi_probe,
- .remove = __devexit_p(plat_mpc8xxx_spi_remove),
+ .remove = plat_mpc8xxx_spi_remove,
.driver = {
.name = "mpc8xxx_spi",
.owner = THIS_MODULE,
diff --git a/drivers/spi/spi-gpio.c b/drivers/spi/spi-gpio.c
index a2b50c516b31..9ddef55a7165 100644
--- a/drivers/spi/spi-gpio.c
+++ b/drivers/spi/spi-gpio.c
@@ -287,7 +287,7 @@ static void spi_gpio_cleanup(struct spi_device *spi)
spi_bitbang_cleanup(spi);
}
-static int __devinit spi_gpio_alloc(unsigned pin, const char *label, bool is_in)
+static int spi_gpio_alloc(unsigned pin, const char *label, bool is_in)
{
int value;
@@ -301,9 +301,8 @@ static int __devinit spi_gpio_alloc(unsigned pin, const char *label, bool is_in)
return value;
}
-static int __devinit
-spi_gpio_request(struct spi_gpio_platform_data *pdata, const char *label,
- u16 *res_flags)
+static int spi_gpio_request(struct spi_gpio_platform_data *pdata,
+ const char *label, u16 *res_flags)
{
int value;
@@ -366,9 +365,26 @@ static int spi_gpio_probe_dt(struct platform_device *pdev)
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_get_named_gpio(np, "gpio-sck", 0);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "gpio-sck property not found\n");
+ goto error_free;
+ }
+ pdata->sck = ret;
+
+ ret = of_get_named_gpio(np, "gpio-miso", 0);
+ if (ret < 0) {
+ dev_info(&pdev->dev, "gpio-miso property not found, switching to no-rx mode\n");
+ pdata->miso = SPI_GPIO_NO_MISO;
+ } else
+ pdata->miso = ret;
+
+ ret = of_get_named_gpio(np, "gpio-mosi", 0);
+ if (ret < 0) {
+ dev_info(&pdev->dev, "gpio-mosi property not found, switching to no-tx mode\n");
+ pdata->mosi = SPI_GPIO_NO_MOSI;
+ } else
+ pdata->mosi = ret;
ret = of_property_read_u32(np, "num-chipselects", &tmp);
if (ret < 0) {
@@ -392,7 +408,7 @@ static inline int spi_gpio_probe_dt(struct platform_device *pdev)
}
#endif
-static int __devinit spi_gpio_probe(struct platform_device *pdev)
+static int spi_gpio_probe(struct platform_device *pdev)
{
int status;
struct spi_master *master;
@@ -485,7 +501,7 @@ gpio_free:
return status;
}
-static int __devexit spi_gpio_remove(struct platform_device *pdev)
+static int spi_gpio_remove(struct platform_device *pdev)
{
struct spi_gpio *spi_gpio;
struct spi_gpio_platform_data *pdata;
@@ -518,7 +534,7 @@ static struct platform_driver spi_gpio_driver = {
.of_match_table = of_match_ptr(spi_gpio_dt_ids),
},
.probe = spi_gpio_probe,
- .remove = __devexit_p(spi_gpio_remove),
+ .remove = spi_gpio_remove,
};
module_platform_driver(spi_gpio_driver);
diff --git a/drivers/spi/spi-imx.c b/drivers/spi/spi-imx.c
index c9a0d8467de6..0befeeb522f4 100644
--- a/drivers/spi/spi-imx.c
+++ b/drivers/spi/spi-imx.c
@@ -750,7 +750,7 @@ static void spi_imx_cleanup(struct spi_device *spi)
{
}
-static int __devinit spi_imx_probe(struct platform_device *pdev)
+static int spi_imx_probe(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
const struct of_device_id *of_id =
@@ -906,7 +906,7 @@ out_gpio_free:
return ret;
}
-static int __devexit spi_imx_remove(struct platform_device *pdev)
+static int spi_imx_remove(struct platform_device *pdev)
{
struct spi_master *master = platform_get_drvdata(pdev);
struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -942,10 +942,11 @@ static struct platform_driver spi_imx_driver = {
},
.id_table = spi_imx_devtype,
.probe = spi_imx_probe,
- .remove = __devexit_p(spi_imx_remove),
+ .remove = spi_imx_remove,
};
module_platform_driver(spi_imx_driver);
MODULE_DESCRIPTION("SPI Master Controller driver");
MODULE_AUTHOR("Sascha Hauer, Pengutronix");
MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:" DRIVER_NAME);
diff --git a/drivers/spi/spi-mpc512x-psc.c b/drivers/spi/spi-mpc512x-psc.c
index 0a1e39e94d06..89480b281d74 100644
--- a/drivers/spi/spi-mpc512x-psc.c
+++ b/drivers/spi/spi-mpc512x-psc.c
@@ -406,7 +406,7 @@ static irqreturn_t mpc512x_psc_spi_isr(int irq, void *dev_id)
}
/* bus_num is used only for the case dev->platform_data == NULL */
-static int __devinit mpc512x_psc_spi_do_probe(struct device *dev, u32 regaddr,
+static int mpc512x_psc_spi_do_probe(struct device *dev, u32 regaddr,
u32 size, unsigned int irq,
s16 bus_num)
{
@@ -438,6 +438,7 @@ static int __devinit mpc512x_psc_spi_do_probe(struct device *dev, u32 regaddr,
master->num_chipselect = pdata->max_chipselect;
}
+ master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LSB_FIRST;
master->setup = mpc512x_psc_spi_setup;
master->transfer = mpc512x_psc_spi_transfer;
master->cleanup = mpc512x_psc_spi_cleanup;
@@ -492,7 +493,7 @@ free_master:
return ret;
}
-static int __devexit mpc512x_psc_spi_do_remove(struct device *dev)
+static int mpc512x_psc_spi_do_remove(struct device *dev)
{
struct spi_master *master = spi_master_get(dev_get_drvdata(dev));
struct mpc512x_psc_spi *mps = spi_master_get_devdata(master);
@@ -508,7 +509,7 @@ static int __devexit mpc512x_psc_spi_do_remove(struct device *dev)
return 0;
}
-static int __devinit mpc512x_psc_spi_of_probe(struct platform_device *op)
+static int mpc512x_psc_spi_of_probe(struct platform_device *op)
{
const u32 *regaddr_p;
u64 regaddr64, size64;
@@ -522,24 +523,18 @@ static int __devinit mpc512x_psc_spi_of_probe(struct platform_device *op)
regaddr64 = of_translate_address(op->dev.of_node, regaddr_p);
/* get PSC id (0..11, used by port_config) */
- if (op->dev.platform_data == NULL) {
- const u32 *psc_nump;
-
- psc_nump = of_get_property(op->dev.of_node, "cell-index", NULL);
- if (!psc_nump || *psc_nump > 11) {
- dev_err(&op->dev, "mpc512x_psc_spi: Device node %s "
- "has invalid cell-index property\n",
- op->dev.of_node->full_name);
- return -EINVAL;
- }
- id = *psc_nump;
+ id = of_alias_get_id(op->dev.of_node, "spi");
+ if (id < 0) {
+ dev_err(&op->dev, "no alias id for %s\n",
+ op->dev.of_node->full_name);
+ return id;
}
return mpc512x_psc_spi_do_probe(&op->dev, (u32) regaddr64, (u32) size64,
irq_of_parse_and_map(op->dev.of_node, 0), id);
}
-static int __devexit mpc512x_psc_spi_of_remove(struct platform_device *op)
+static int mpc512x_psc_spi_of_remove(struct platform_device *op)
{
return mpc512x_psc_spi_do_remove(&op->dev);
}
@@ -553,7 +548,7 @@ MODULE_DEVICE_TABLE(of, mpc512x_psc_spi_of_match);
static struct platform_driver mpc512x_psc_spi_of_driver = {
.probe = mpc512x_psc_spi_of_probe,
- .remove = __devexit_p(mpc512x_psc_spi_of_remove),
+ .remove = mpc512x_psc_spi_of_remove,
.driver = {
.name = "mpc512x-psc-spi",
.owner = THIS_MODULE,
diff --git a/drivers/spi/spi-mpc52xx-psc.c b/drivers/spi/spi-mpc52xx-psc.c
index bd47d262d53f..291120b37dbb 100644
--- a/drivers/spi/spi-mpc52xx-psc.c
+++ b/drivers/spi/spi-mpc52xx-psc.c
@@ -363,7 +363,7 @@ static irqreturn_t mpc52xx_psc_spi_isr(int irq, void *dev_id)
}
/* bus_num is used only for the case dev->platform_data == NULL */
-static int __devinit mpc52xx_psc_spi_do_probe(struct device *dev, u32 regaddr,
+static int mpc52xx_psc_spi_do_probe(struct device *dev, u32 regaddr,
u32 size, unsigned int irq, s16 bus_num)
{
struct fsl_spi_platform_data *pdata = dev->platform_data;
@@ -450,7 +450,7 @@ free_master:
return ret;
}
-static int __devinit mpc52xx_psc_spi_of_probe(struct platform_device *op)
+static int mpc52xx_psc_spi_of_probe(struct platform_device *op)
{
const u32 *regaddr_p;
u64 regaddr64, size64;
@@ -479,7 +479,7 @@ static int __devinit mpc52xx_psc_spi_of_probe(struct platform_device *op)
irq_of_parse_and_map(op->dev.of_node, 0), id);
}
-static int __devexit mpc52xx_psc_spi_of_remove(struct platform_device *op)
+static int mpc52xx_psc_spi_of_remove(struct platform_device *op)
{
struct spi_master *master = spi_master_get(dev_get_drvdata(&op->dev));
struct mpc52xx_psc_spi *mps = spi_master_get_devdata(master);
@@ -505,7 +505,7 @@ MODULE_DEVICE_TABLE(of, mpc52xx_psc_spi_of_match);
static struct platform_driver mpc52xx_psc_spi_of_driver = {
.probe = mpc52xx_psc_spi_of_probe,
- .remove = __devexit_p(mpc52xx_psc_spi_of_remove),
+ .remove = mpc52xx_psc_spi_of_remove,
.driver = {
.name = "mpc52xx-psc-spi",
.owner = THIS_MODULE,
diff --git a/drivers/spi/spi-mpc52xx.c b/drivers/spi/spi-mpc52xx.c
index 045410650212..29f77056eedc 100644
--- a/drivers/spi/spi-mpc52xx.c
+++ b/drivers/spi/spi-mpc52xx.c
@@ -390,7 +390,7 @@ static int mpc52xx_spi_transfer(struct spi_device *spi, struct spi_message *m)
/*
* OF Platform Bus Binding
*/
-static int __devinit mpc52xx_spi_probe(struct platform_device *op)
+static int mpc52xx_spi_probe(struct platform_device *op)
{
struct spi_master *master;
struct mpc52xx_spi *ms;
@@ -527,7 +527,7 @@ static int __devinit mpc52xx_spi_probe(struct platform_device *op)
return rc;
}
-static int __devexit mpc52xx_spi_remove(struct platform_device *op)
+static int mpc52xx_spi_remove(struct platform_device *op)
{
struct spi_master *master = spi_master_get(dev_get_drvdata(&op->dev));
struct mpc52xx_spi *ms = spi_master_get_devdata(master);
@@ -547,7 +547,7 @@ static int __devexit mpc52xx_spi_remove(struct platform_device *op)
return 0;
}
-static const struct of_device_id mpc52xx_spi_match[] __devinitconst = {
+static const struct of_device_id mpc52xx_spi_match[] = {
{ .compatible = "fsl,mpc5200-spi", },
{}
};
@@ -560,6 +560,6 @@ static struct platform_driver mpc52xx_spi_of_driver = {
.of_match_table = mpc52xx_spi_match,
},
.probe = mpc52xx_spi_probe,
- .remove = __devexit_p(mpc52xx_spi_remove),
+ .remove = mpc52xx_spi_remove,
};
module_platform_driver(mpc52xx_spi_of_driver);
diff --git a/drivers/spi/spi-mxs.c b/drivers/spi/spi-mxs.c
index 86dd04d6bc87..22a0af0147fb 100644
--- a/drivers/spi/spi-mxs.c
+++ b/drivers/spi/spi-mxs.c
@@ -241,6 +241,7 @@ static int mxs_spi_txrx_dma(struct mxs_spi *spi, int cs,
INIT_COMPLETION(spi->c);
ctrl0 = readl(ssp->base + HW_SSP_CTRL0);
+ ctrl0 &= ~BM_SSP_CTRL0_XFER_COUNT;
ctrl0 |= BM_SSP_CTRL0_DATA_XFER | mxs_spi_cs_to_reg(cs);
if (*first)
@@ -256,8 +257,10 @@ static int mxs_spi_txrx_dma(struct mxs_spi *spi, int cs,
if ((sg_count + 1 == sgs) && *last)
ctrl0 |= BM_SSP_CTRL0_IGNORE_CRC;
- if (ssp->devid == IMX23_SSP)
+ if (ssp->devid == IMX23_SSP) {
+ ctrl0 &= ~BM_SSP_CTRL0_XFER_COUNT;
ctrl0 |= min;
+ }
dma_xfer[sg_count].pio[0] = ctrl0;
dma_xfer[sg_count].pio[3] = min;
@@ -509,7 +512,7 @@ static const struct of_device_id mxs_spi_dt_ids[] = {
};
MODULE_DEVICE_TABLE(of, mxs_spi_dt_ids);
-static int __devinit mxs_spi_probe(struct platform_device *pdev)
+static int mxs_spi_probe(struct platform_device *pdev)
{
const struct of_device_id *of_id =
of_match_device(mxs_spi_dt_ids, &pdev->dev);
@@ -538,9 +541,9 @@ static int __devinit mxs_spi_probe(struct platform_device *pdev)
if (!iores || irq_err < 0 || irq_dma < 0)
return -EINVAL;
- base = devm_request_and_ioremap(&pdev->dev, iores);
- if (!base)
- return -EADDRNOTAVAIL;
+ base = devm_ioremap_resource(&pdev->dev, iores);
+ if (IS_ERR(base))
+ return PTR_ERR(base);
pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
if (IS_ERR(pinctrl))
@@ -636,7 +639,7 @@ out_master_free:
return ret;
}
-static int __devexit mxs_spi_remove(struct platform_device *pdev)
+static int mxs_spi_remove(struct platform_device *pdev)
{
struct spi_master *master;
struct mxs_spi *spi;
@@ -659,7 +662,7 @@ static int __devexit mxs_spi_remove(struct platform_device *pdev)
static struct platform_driver mxs_spi_driver = {
.probe = mxs_spi_probe,
- .remove = __devexit_p(mxs_spi_remove),
+ .remove = mxs_spi_remove,
.driver = {
.name = DRIVER_NAME,
.owner = THIS_MODULE,
diff --git a/drivers/spi/spi-nuc900.c b/drivers/spi/spi-nuc900.c
index a6eca6ffdabe..b3f9ec83ef73 100644
--- a/drivers/spi/spi-nuc900.c
+++ b/drivers/spi/spi-nuc900.c
@@ -346,7 +346,7 @@ static void nuc900_init_spi(struct nuc900_spi *hw)
nuc900_enable_int(hw);
}
-static int __devinit nuc900_spi_probe(struct platform_device *pdev)
+static int nuc900_spi_probe(struct platform_device *pdev)
{
struct nuc900_spi *hw;
struct spi_master *master;
@@ -453,7 +453,7 @@ err_nomem:
return err;
}
-static int __devexit nuc900_spi_remove(struct platform_device *dev)
+static int nuc900_spi_remove(struct platform_device *dev)
{
struct nuc900_spi *hw = platform_get_drvdata(dev);
@@ -477,7 +477,7 @@ static int __devexit nuc900_spi_remove(struct platform_device *dev)
static struct platform_driver nuc900_spi_driver = {
.probe = nuc900_spi_probe,
- .remove = __devexit_p(nuc900_spi_remove),
+ .remove = nuc900_spi_remove,
.driver = {
.name = "nuc900-spi",
.owner = THIS_MODULE,
diff --git a/drivers/spi/spi-oc-tiny.c b/drivers/spi/spi-oc-tiny.c
index 9d9071b730be..cb2e284bd814 100644
--- a/drivers/spi/spi-oc-tiny.c
+++ b/drivers/spi/spi-oc-tiny.c
@@ -54,7 +54,7 @@ struct tiny_spi {
unsigned int txc, rxc;
const u8 *txp;
u8 *rxp;
- unsigned int gpio_cs_count;
+ int gpio_cs_count;
int *gpio_cs;
};
@@ -74,7 +74,7 @@ static void tiny_spi_chipselect(struct spi_device *spi, int is_active)
{
struct tiny_spi *hw = tiny_spi_to_hw(spi);
- if (hw->gpio_cs_count) {
+ if (hw->gpio_cs_count > 0) {
gpio_set_value(hw->gpio_cs[spi->chip_select],
(spi->mode & SPI_CS_HIGH) ? is_active : !is_active);
}
@@ -243,7 +243,7 @@ static irqreturn_t tiny_spi_irq(int irq, void *dev)
#ifdef CONFIG_OF
#include <linux/of_gpio.h>
-static int __devinit tiny_spi_of_probe(struct platform_device *pdev)
+static int tiny_spi_of_probe(struct platform_device *pdev)
{
struct tiny_spi *hw = platform_get_drvdata(pdev);
struct device_node *np = pdev->dev.of_node;
@@ -254,7 +254,7 @@ static int __devinit tiny_spi_of_probe(struct platform_device *pdev)
if (!np)
return 0;
hw->gpio_cs_count = of_gpio_count(np);
- if (hw->gpio_cs_count) {
+ if (hw->gpio_cs_count > 0) {
hw->gpio_cs = devm_kzalloc(&pdev->dev,
hw->gpio_cs_count * sizeof(unsigned int),
GFP_KERNEL);
@@ -277,13 +277,13 @@ static int __devinit tiny_spi_of_probe(struct platform_device *pdev)
return 0;
}
#else /* !CONFIG_OF */
-static int __devinit tiny_spi_of_probe(struct platform_device *pdev)
+static int tiny_spi_of_probe(struct platform_device *pdev)
{
return 0;
}
#endif /* CONFIG_OF */
-static int __devinit tiny_spi_probe(struct platform_device *pdev)
+static int tiny_spi_probe(struct platform_device *pdev)
{
struct tiny_spi_platform_data *platp = pdev->dev.platform_data;
struct tiny_spi *hw;
@@ -352,7 +352,7 @@ static int __devinit tiny_spi_probe(struct platform_device *pdev)
goto exit_gpio;
gpio_direction_output(hw->gpio_cs[i], 1);
}
- hw->bitbang.master->num_chipselect = max(1U, hw->gpio_cs_count);
+ hw->bitbang.master->num_chipselect = max(1, hw->gpio_cs_count);
/* register our spi controller */
err = spi_bitbang_start(&hw->bitbang);
@@ -373,7 +373,7 @@ exit:
return err;
}
-static int __devexit tiny_spi_remove(struct platform_device *pdev)
+static int tiny_spi_remove(struct platform_device *pdev)
{
struct tiny_spi *hw = platform_get_drvdata(pdev);
struct spi_master *master = hw->bitbang.master;
@@ -399,7 +399,7 @@ MODULE_DEVICE_TABLE(of, tiny_spi_match);
static struct platform_driver tiny_spi_driver = {
.probe = tiny_spi_probe,
- .remove = __devexit_p(tiny_spi_remove),
+ .remove = tiny_spi_remove,
.driver = {
.name = DRV_NAME,
.owner = THIS_MODULE,
diff --git a/drivers/spi/spi-octeon.c b/drivers/spi/spi-octeon.c
index ea8fb2efb0f8..24daf964a409 100644
--- a/drivers/spi/spi-octeon.c
+++ b/drivers/spi/spi-octeon.c
@@ -266,7 +266,7 @@ static int octeon_spi_nop_transfer_hardware(struct spi_master *master)
return 0;
}
-static int __devinit octeon_spi_probe(struct platform_device *pdev)
+static int octeon_spi_probe(struct platform_device *pdev)
{
struct resource *res_mem;
@@ -326,7 +326,7 @@ fail:
return err;
}
-static int __devexit octeon_spi_remove(struct platform_device *pdev)
+static int octeon_spi_remove(struct platform_device *pdev)
{
struct octeon_spi *p = platform_get_drvdata(pdev);
u64 register_base = p->register_base;
@@ -352,7 +352,7 @@ static struct platform_driver octeon_spi_driver = {
.of_match_table = octeon_spi_match,
},
.probe = octeon_spi_probe,
- .remove = __devexit_p(octeon_spi_remove),
+ .remove = octeon_spi_remove,
};
module_platform_driver(octeon_spi_driver);
diff --git a/drivers/spi/spi-omap-100k.c b/drivers/spi/spi-omap-100k.c
index dfb4b7f448c5..78d29a18dcc4 100644
--- a/drivers/spi/spi-omap-100k.c
+++ b/drivers/spi/spi-omap-100k.c
@@ -481,12 +481,12 @@ static int omap1_spi100k_transfer(struct spi_device *spi, struct spi_message *m)
return 0;
}
-static int __init omap1_spi100k_reset(struct omap1_spi100k *spi100k)
+static int omap1_spi100k_reset(struct omap1_spi100k *spi100k)
{
return 0;
}
-static int __devinit omap1_spi100k_probe(struct platform_device *pdev)
+static int omap1_spi100k_probe(struct platform_device *pdev)
{
struct spi_master *master;
struct omap1_spi100k *spi100k;
@@ -560,7 +560,7 @@ err1:
return status;
}
-static int __exit omap1_spi100k_remove(struct platform_device *pdev)
+static int omap1_spi100k_remove(struct platform_device *pdev)
{
struct spi_master *master;
struct omap1_spi100k *spi100k;
@@ -604,7 +604,7 @@ static struct platform_driver omap1_spi100k_driver = {
.name = "omap1_spi100k",
.owner = THIS_MODULE,
},
- .remove = __exit_p(omap1_spi100k_remove),
+ .remove = omap1_spi100k_remove,
};
diff --git a/drivers/spi/spi-omap-uwire.c b/drivers/spi/spi-omap-uwire.c
index 0a94d9dc9c31..102b233b50c4 100644
--- a/drivers/spi/spi-omap-uwire.c
+++ b/drivers/spi/spi-omap-uwire.c
@@ -476,7 +476,7 @@ static void uwire_off(struct uwire_spi *uwire)
spi_master_put(uwire->bitbang.master);
}
-static int __init uwire_probe(struct platform_device *pdev)
+static int uwire_probe(struct platform_device *pdev)
{
struct spi_master *master;
struct uwire_spi *uwire;
@@ -536,7 +536,7 @@ static int __init uwire_probe(struct platform_device *pdev)
return status;
}
-static int __exit uwire_remove(struct platform_device *pdev)
+static int uwire_remove(struct platform_device *pdev)
{
struct uwire_spi *uwire = dev_get_drvdata(&pdev->dev);
int status;
@@ -557,7 +557,7 @@ static struct platform_driver uwire_driver = {
.name = "omap_uwire",
.owner = THIS_MODULE,
},
- .remove = __exit_p(uwire_remove),
+ .remove = uwire_remove,
// suspend ... unuse ck
// resume ... use ck
};
diff --git a/drivers/spi/spi-omap2-mcspi.c b/drivers/spi/spi-omap2-mcspi.c
index 3542fdc664b1..893c3d78e426 100644
--- a/drivers/spi/spi-omap2-mcspi.c
+++ b/drivers/spi/spi-omap2-mcspi.c
@@ -39,7 +39,6 @@
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/pinctrl/consumer.h>
-#include <linux/err.h>
#include <linux/spi/spi.h>
@@ -130,6 +129,7 @@ struct omap2_mcspi {
struct omap2_mcspi_dma *dma_channels;
struct device *dev;
struct omap2_mcspi_regs ctx;
+ unsigned int pin_dir:1;
};
struct omap2_mcspi_cs {
@@ -298,10 +298,10 @@ static void omap2_mcspi_rx_callback(void *data)
struct omap2_mcspi *mcspi = spi_master_get_devdata(spi->master);
struct omap2_mcspi_dma *mcspi_dma = &mcspi->dma_channels[spi->chip_select];
- complete(&mcspi_dma->dma_rx_completion);
-
/* We must disable the DMA RX request */
omap2_mcspi_set_dma_req(spi, 1, 0);
+
+ complete(&mcspi_dma->dma_rx_completion);
}
static void omap2_mcspi_tx_callback(void *data)
@@ -310,10 +310,10 @@ static void omap2_mcspi_tx_callback(void *data)
struct omap2_mcspi *mcspi = spi_master_get_devdata(spi->master);
struct omap2_mcspi_dma *mcspi_dma = &mcspi->dma_channels[spi->chip_select];
- complete(&mcspi_dma->dma_tx_completion);
-
/* We must disable the DMA TX request */
omap2_mcspi_set_dma_req(spi, 0, 0);
+
+ complete(&mcspi_dma->dma_tx_completion);
}
static void omap2_mcspi_tx_dma(struct spi_device *spi,
@@ -323,19 +323,11 @@ static void omap2_mcspi_tx_dma(struct spi_device *spi,
struct omap2_mcspi *mcspi;
struct omap2_mcspi_dma *mcspi_dma;
unsigned int count;
- u8 * rx;
- const u8 * tx;
- void __iomem *chstat_reg;
- 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;
- rx = xfer->rx_buf;
- tx = xfer->tx_buf;
- chstat_reg = cs->base + OMAP2_MCSPI_CHSTAT0;
-
if (mcspi_dma->dma_tx) {
struct dma_async_tx_descriptor *tx;
struct scatterlist sg;
@@ -359,19 +351,6 @@ static void omap2_mcspi_tx_dma(struct spi_device *spi,
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
@@ -492,6 +471,7 @@ omap2_mcspi_txrx_dma(struct spi_device *spi, struct spi_transfer *xfer)
struct dma_slave_config cfg;
enum dma_slave_buswidth width;
unsigned es;
+ void __iomem *chstat_reg;
mcspi = spi_master_get_devdata(spi->master);
mcspi_dma = &mcspi->dma_channels[spi->chip_select];
@@ -526,8 +506,24 @@ omap2_mcspi_txrx_dma(struct spi_device *spi, struct spi_transfer *xfer)
omap2_mcspi_tx_dma(spi, xfer, cfg);
if (rx != NULL)
- return omap2_mcspi_rx_dma(spi, xfer, cfg, es);
-
+ count = omap2_mcspi_rx_dma(spi, xfer, cfg, es);
+
+ if (tx != NULL) {
+ chstat_reg = cs->base + OMAP2_MCSPI_CHSTAT0;
+ wait_for_completion(&mcspi_dma->dma_tx_completion);
+ dma_unmap_single(mcspi->dev, xfer->tx_dma, xfer->len,
+ 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");
+ }
+ }
return count;
}
@@ -765,8 +761,15 @@ static int omap2_mcspi_setup_transfer(struct spi_device *spi,
/* standard 4-wire master mode: SCK, MOSI/out, MISO/in, nCS
* REVISIT: this controller could support SPI_3WIRE mode.
*/
- l &= ~(OMAP2_MCSPI_CHCONF_IS|OMAP2_MCSPI_CHCONF_DPE1);
- l |= OMAP2_MCSPI_CHCONF_DPE0;
+ if (mcspi->pin_dir == MCSPI_PINDIR_D0_IN_D1_OUT) {
+ l &= ~OMAP2_MCSPI_CHCONF_IS;
+ l &= ~OMAP2_MCSPI_CHCONF_DPE1;
+ l |= OMAP2_MCSPI_CHCONF_DPE0;
+ } else {
+ l |= OMAP2_MCSPI_CHCONF_IS;
+ l |= OMAP2_MCSPI_CHCONF_DPE1;
+ l &= ~OMAP2_MCSPI_CHCONF_DPE0;
+ }
/* wordlength */
l &= ~OMAP2_MCSPI_CHCONF_WL_MASK;
@@ -924,6 +927,7 @@ static void omap2_mcspi_work(struct omap2_mcspi *mcspi, struct spi_message *m)
struct spi_device *spi;
struct spi_transfer *t = NULL;
+ struct spi_master *master;
int cs_active = 0;
struct omap2_mcspi_cs *cs;
struct omap2_mcspi_device_config *cd;
@@ -932,6 +936,7 @@ static void omap2_mcspi_work(struct omap2_mcspi *mcspi, struct spi_message *m)
u32 chconf;
spi = m->spi;
+ master = spi->master;
cs = spi->controller_state;
cd = spi->controller_data;
@@ -949,6 +954,14 @@ static void omap2_mcspi_work(struct omap2_mcspi *mcspi, struct spi_message *m)
if (!t->speed_hz && !t->bits_per_word)
par_override = 0;
}
+ if (cd && cd->cs_per_word) {
+ chconf = mcspi->ctx.modulctrl;
+ chconf &= ~OMAP2_MCSPI_MODULCTRL_SINGLE;
+ mcspi_write_reg(master, OMAP2_MCSPI_MODULCTRL, chconf);
+ mcspi->ctx.modulctrl =
+ mcspi_read_cs_reg(spi, OMAP2_MCSPI_MODULCTRL);
+ }
+
if (!cs_active) {
omap2_mcspi_force_cs(spi, 1);
@@ -1010,6 +1023,14 @@ static void omap2_mcspi_work(struct omap2_mcspi *mcspi, struct spi_message *m)
if (cs_active)
omap2_mcspi_force_cs(spi, 0);
+ if (cd && cd->cs_per_word) {
+ chconf = mcspi->ctx.modulctrl;
+ chconf |= OMAP2_MCSPI_MODULCTRL_SINGLE;
+ mcspi_write_reg(master, OMAP2_MCSPI_MODULCTRL, chconf);
+ mcspi->ctx.modulctrl =
+ mcspi_read_cs_reg(spi, OMAP2_MCSPI_MODULCTRL);
+ }
+
omap2_mcspi_set_enable(spi, 0);
m->status = status;
@@ -1017,7 +1038,7 @@ static void omap2_mcspi_work(struct omap2_mcspi *mcspi, struct spi_message *m)
}
static int omap2_mcspi_transfer_one_message(struct spi_master *master,
- struct spi_message *m)
+ struct spi_message *m)
{
struct omap2_mcspi *mcspi;
struct spi_transfer *t;
@@ -1038,7 +1059,7 @@ static int omap2_mcspi_transfer_one_message(struct spi_master *master,
|| (len && !(rx_buf || tx_buf))
|| (t->bits_per_word &&
( t->bits_per_word < 4
- || t->bits_per_word > 32))) {
+ || t->bits_per_word > 32))) {
dev_dbg(mcspi->dev, "transfer: %d Hz, %d %s%s, %d bpw\n",
t->speed_hz,
len,
@@ -1049,8 +1070,8 @@ static int omap2_mcspi_transfer_one_message(struct spi_master *master,
}
if (t->speed_hz && t->speed_hz < (OMAP2_MCSPI_MAX_FREQ >> 15)) {
dev_dbg(mcspi->dev, "speed_hz %d below minimum %d Hz\n",
- t->speed_hz,
- OMAP2_MCSPI_MAX_FREQ >> 15);
+ t->speed_hz,
+ OMAP2_MCSPI_MAX_FREQ >> 15);
return -EINVAL;
}
@@ -1085,7 +1106,7 @@ static int omap2_mcspi_transfer_one_message(struct spi_master *master,
return 0;
}
-static int __devinit omap2_mcspi_master_setup(struct omap2_mcspi *mcspi)
+static int omap2_mcspi_master_setup(struct omap2_mcspi *mcspi)
{
struct spi_master *master = mcspi->master;
struct omap2_mcspi_regs *ctx = &mcspi->ctx;
@@ -1096,7 +1117,7 @@ static int __devinit omap2_mcspi_master_setup(struct omap2_mcspi *mcspi)
return ret;
mcspi_write_reg(master, OMAP2_MCSPI_WAKEUPENABLE,
- OMAP2_MCSPI_WAKEUPENABLE_WKEN);
+ OMAP2_MCSPI_WAKEUPENABLE_WKEN);
ctx->wakeupenable = OMAP2_MCSPI_WAKEUPENABLE_WKEN;
omap2_mcspi_set_master_mode(master);
@@ -1138,7 +1159,7 @@ static const struct of_device_id omap_mcspi_of_match[] = {
};
MODULE_DEVICE_TABLE(of, omap_mcspi_of_match);
-static int __devinit omap2_mcspi_probe(struct platform_device *pdev)
+static int omap2_mcspi_probe(struct platform_device *pdev)
{
struct spi_master *master;
const struct omap2_mcspi_platform_config *pdata;
@@ -1167,6 +1188,11 @@ static int __devinit omap2_mcspi_probe(struct platform_device *pdev)
master->cleanup = omap2_mcspi_cleanup;
master->dev.of_node = node;
+ dev_set_drvdata(&pdev->dev, master);
+
+ mcspi = spi_master_get_devdata(master);
+ mcspi->master = master;
+
match = of_match_device(omap_mcspi_of_match, &pdev->dev);
if (match) {
u32 num_cs = 1; /* default number of chipselect */
@@ -1175,19 +1201,17 @@ static int __devinit omap2_mcspi_probe(struct platform_device *pdev)
of_property_read_u32(node, "ti,spi-num-cs", &num_cs);
master->num_chipselect = num_cs;
master->bus_num = bus_num++;
+ if (of_get_property(node, "ti,pindir-d0-out-d1-in", NULL))
+ mcspi->pin_dir = MCSPI_PINDIR_D0_OUT_D1_IN;
} else {
pdata = pdev->dev.platform_data;
master->num_chipselect = pdata->num_cs;
if (pdev->id != -1)
master->bus_num = pdev->id;
+ mcspi->pin_dir = pdata->pin_dir;
}
regs_offset = pdata->regs_offset;
- dev_set_drvdata(&pdev->dev, master);
-
- mcspi = spi_master_get_devdata(master);
- mcspi->master = master;
-
r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (r == NULL) {
status = -ENODEV;
@@ -1198,10 +1222,9 @@ static int __devinit omap2_mcspi_probe(struct platform_device *pdev)
r->end += regs_offset;
mcspi->phys = r->start;
- mcspi->base = devm_request_and_ioremap(&pdev->dev, r);
- if (!mcspi->base) {
- dev_dbg(&pdev->dev, "can't ioremap MCSPI\n");
- status = -ENOMEM;
+ mcspi->base = devm_ioremap_resource(&pdev->dev, r);
+ if (IS_ERR(mcspi->base)) {
+ status = PTR_ERR(mcspi->base);
goto free_master;
}
@@ -1222,7 +1245,7 @@ static int __devinit omap2_mcspi_probe(struct platform_device *pdev)
sprintf(dma_ch_name, "rx%d", i);
dma_res = platform_get_resource_byname(pdev, IORESOURCE_DMA,
- dma_ch_name);
+ dma_ch_name);
if (!dma_res) {
dev_dbg(&pdev->dev, "cannot get DMA RX channel\n");
status = -ENODEV;
@@ -1232,7 +1255,7 @@ static int __devinit omap2_mcspi_probe(struct platform_device *pdev)
mcspi->dma_channels[i].dma_rx_sync_dev = dma_res->start;
sprintf(dma_ch_name, "tx%d", i);
dma_res = platform_get_resource_byname(pdev, IORESOURCE_DMA,
- dma_ch_name);
+ dma_ch_name);
if (!dma_res) {
dev_dbg(&pdev->dev, "cannot get DMA TX channel\n");
status = -ENODEV;
@@ -1248,7 +1271,7 @@ static int __devinit omap2_mcspi_probe(struct platform_device *pdev)
pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
if (IS_ERR(pinctrl))
dev_warn(&pdev->dev,
- "pins are not configured from the driver\n");
+ "pins are not configured from the driver\n");
pm_runtime_use_autosuspend(&pdev->dev);
pm_runtime_set_autosuspend_delay(&pdev->dev, SPI_AUTOSUSPEND_TIMEOUT);
@@ -1272,7 +1295,7 @@ free_master:
return status;
}
-static int __devexit omap2_mcspi_remove(struct platform_device *pdev)
+static int omap2_mcspi_remove(struct platform_device *pdev)
{
struct spi_master *master;
struct omap2_mcspi *mcspi;
@@ -1341,7 +1364,7 @@ static struct platform_driver omap2_mcspi_driver = {
.of_match_table = omap_mcspi_of_match,
},
.probe = omap2_mcspi_probe,
- .remove = __devexit_p(omap2_mcspi_remove),
+ .remove = omap2_mcspi_remove,
};
module_platform_driver(omap2_mcspi_driver);
diff --git a/drivers/spi/spi-orion.c b/drivers/spi/spi-orion.c
index b17c09cf0a05..66a5f82cf138 100644
--- a/drivers/spi/spi-orion.c
+++ b/drivers/spi/spi-orion.c
@@ -32,8 +32,12 @@
#define ORION_SPI_DATA_IN_REG 0x0c
#define ORION_SPI_INT_CAUSE_REG 0x10
+#define ORION_SPI_MODE_CPOL (1 << 11)
+#define ORION_SPI_MODE_CPHA (1 << 12)
#define ORION_SPI_IF_8_16_BIT_MODE (1 << 5)
#define ORION_SPI_CLK_PRESCALE_MASK 0x1F
+#define ORION_SPI_MODE_MASK (ORION_SPI_MODE_CPOL | \
+ ORION_SPI_MODE_CPHA)
struct orion_spi {
struct spi_master *master;
@@ -123,6 +127,23 @@ static int orion_spi_baudrate_set(struct spi_device *spi, unsigned int speed)
return 0;
}
+static void
+orion_spi_mode_set(struct spi_device *spi)
+{
+ u32 reg;
+ struct orion_spi *orion_spi;
+
+ orion_spi = spi_master_get_devdata(spi->master);
+
+ reg = readl(spi_reg(orion_spi, ORION_SPI_IF_CONFIG_REG));
+ reg &= ~ORION_SPI_MODE_MASK;
+ if (spi->mode & SPI_CPOL)
+ reg |= ORION_SPI_MODE_CPOL;
+ if (spi->mode & SPI_CPHA)
+ reg |= ORION_SPI_MODE_CPHA;
+ writel(reg, spi_reg(orion_spi, ORION_SPI_IF_CONFIG_REG));
+}
+
/*
* called only when no transfer is active on the bus
*/
@@ -142,6 +163,8 @@ orion_spi_setup_transfer(struct spi_device *spi, struct spi_transfer *t)
if ((t != NULL) && t->bits_per_word)
bits_per_word = t->bits_per_word;
+ orion_spi_mode_set(spi);
+
rc = orion_spi_baudrate_set(spi, speed);
if (rc)
return rc;
@@ -343,7 +366,7 @@ msg_done:
return 0;
}
-static int __init orion_spi_reset(struct orion_spi *orion_spi)
+static int orion_spi_reset(struct orion_spi *orion_spi)
{
/* Verify that the CS is deasserted */
orion_spi_set_cs(orion_spi, 0);
@@ -373,7 +396,7 @@ static int orion_spi_setup(struct spi_device *spi)
return 0;
}
-static int __init orion_spi_probe(struct platform_device *pdev)
+static int orion_spi_probe(struct platform_device *pdev)
{
struct spi_master *master;
struct orion_spi *spi;
@@ -399,7 +422,7 @@ static int __init orion_spi_probe(struct platform_device *pdev)
}
/* we support only mode 0, and no options */
- master->mode_bits = 0;
+ master->mode_bits = SPI_CPHA | SPI_CPOL;
master->setup = orion_spi_setup;
master->transfer_one_message = orion_spi_transfer_one_message;
@@ -456,7 +479,7 @@ out:
}
-static int __exit orion_spi_remove(struct platform_device *pdev)
+static int orion_spi_remove(struct platform_device *pdev)
{
struct spi_master *master;
struct resource *r;
@@ -478,7 +501,7 @@ static int __exit orion_spi_remove(struct platform_device *pdev)
MODULE_ALIAS("platform:" DRIVER_NAME);
-static const struct of_device_id orion_spi_of_match_table[] __devinitdata = {
+static const struct of_device_id orion_spi_of_match_table[] = {
{ .compatible = "marvell,orion-spi", },
{}
};
@@ -490,20 +513,11 @@ static struct platform_driver orion_spi_driver = {
.owner = THIS_MODULE,
.of_match_table = of_match_ptr(orion_spi_of_match_table),
},
- .remove = __exit_p(orion_spi_remove),
+ .probe = orion_spi_probe,
+ .remove = orion_spi_remove,
};
-static int __init orion_spi_init(void)
-{
- return platform_driver_probe(&orion_spi_driver, orion_spi_probe);
-}
-module_init(orion_spi_init);
-
-static void __exit orion_spi_exit(void)
-{
- platform_driver_unregister(&orion_spi_driver);
-}
-module_exit(orion_spi_exit);
+module_platform_driver(orion_spi_driver);
MODULE_DESCRIPTION("Orion SPI driver");
MODULE_AUTHOR("Shadi Ammouri <shadi@marvell.com>");
diff --git a/drivers/spi/spi-pl022.c b/drivers/spi/spi-pl022.c
index a1db91a99b89..b0fe393c882c 100644
--- a/drivers/spi/spi-pl022.c
+++ b/drivers/spi/spi-pl022.c
@@ -371,6 +371,7 @@ struct pl022 {
/* Two optional pin states - default & sleep */
struct pinctrl *pinctrl;
struct pinctrl_state *pins_default;
+ struct pinctrl_state *pins_idle;
struct pinctrl_state *pins_sleep;
struct spi_master *master;
struct pl022_ssp_controller *master_info;
@@ -1088,7 +1089,7 @@ err_alloc_rx_sg:
return -ENOMEM;
}
-static int __devinit pl022_dma_probe(struct pl022 *pl022)
+static int pl022_dma_probe(struct pl022 *pl022)
{
dma_cap_mask_t mask;
@@ -2057,8 +2058,7 @@ pl022_platform_data_dt_get(struct device *dev)
return pd;
}
-static int __devinit
-pl022_probe(struct amba_device *adev, const struct amba_id *id)
+static int pl022_probe(struct amba_device *adev, const struct amba_id *id)
{
struct device *dev = &adev->dev;
struct pl022_ssp_controller *platform_info = adev->dev.platform_data;
@@ -2116,6 +2116,11 @@ pl022_probe(struct amba_device *adev, const struct amba_id *id)
} else
dev_err(dev, "could not get default pinstate\n");
+ pl022->pins_idle = pinctrl_lookup_state(pl022->pinctrl,
+ PINCTRL_STATE_IDLE);
+ if (IS_ERR(pl022->pins_idle))
+ dev_dbg(dev, "could not get idle pinstate\n");
+
pl022->pins_sleep = pinctrl_lookup_state(pl022->pinctrl,
PINCTRL_STATE_SLEEP);
if (IS_ERR(pl022->pins_sleep))
@@ -2246,10 +2251,9 @@ pl022_probe(struct amba_device *adev, const struct amba_id *id)
pm_runtime_set_autosuspend_delay(dev,
platform_info->autosuspend_delay);
pm_runtime_use_autosuspend(dev);
- pm_runtime_put_autosuspend(dev);
- } else {
- pm_runtime_put(dev);
}
+ pm_runtime_put(dev);
+
return 0;
err_spi_register:
@@ -2270,7 +2274,7 @@ pl022_probe(struct amba_device *adev, const struct amba_id *id)
return status;
}
-static int __devexit
+static int
pl022_remove(struct amba_device *adev)
{
struct pl022 *pl022 = amba_get_drvdata(adev);
@@ -2303,35 +2307,47 @@ pl022_remove(struct amba_device *adev)
* the runtime counterparts to handle external resources like
* clocks, pins and regulators when going to sleep.
*/
-static void pl022_suspend_resources(struct pl022 *pl022)
+static void pl022_suspend_resources(struct pl022 *pl022, bool runtime)
{
int ret;
+ struct pinctrl_state *pins_state;
clk_disable(pl022->clk);
+ pins_state = runtime ? pl022->pins_idle : pl022->pins_sleep;
/* Optionally let pins go into sleep states */
- if (!IS_ERR(pl022->pins_sleep)) {
- ret = pinctrl_select_state(pl022->pinctrl,
- pl022->pins_sleep);
+ if (!IS_ERR(pins_state)) {
+ ret = pinctrl_select_state(pl022->pinctrl, pins_state);
if (ret)
- dev_err(&pl022->adev->dev,
- "could not set pins to sleep state\n");
+ dev_err(&pl022->adev->dev, "could not set %s pins\n",
+ runtime ? "idle" : "sleep");
}
}
-static void pl022_resume_resources(struct pl022 *pl022)
+static void pl022_resume_resources(struct pl022 *pl022, bool runtime)
{
int ret;
/* Optionaly enable pins to be muxed in and configured */
+ /* First go to the default state */
if (!IS_ERR(pl022->pins_default)) {
- ret = pinctrl_select_state(pl022->pinctrl,
- 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");
}
+ if (!runtime) {
+ /* Then let's idle the pins until the next transfer happens */
+ if (!IS_ERR(pl022->pins_idle)) {
+ ret = pinctrl_select_state(pl022->pinctrl,
+ pl022->pins_idle);
+ if (ret)
+ dev_err(&pl022->adev->dev,
+ "could not set idle pins\n");
+ }
+ }
+
clk_enable(pl022->clk);
}
#endif
@@ -2347,7 +2363,9 @@ static int pl022_suspend(struct device *dev)
dev_warn(dev, "cannot suspend master\n");
return ret;
}
- pl022_suspend_resources(pl022);
+
+ pm_runtime_get_sync(dev);
+ pl022_suspend_resources(pl022, false);
dev_dbg(dev, "suspended\n");
return 0;
@@ -2358,7 +2376,8 @@ static int pl022_resume(struct device *dev)
struct pl022 *pl022 = dev_get_drvdata(dev);
int ret;
- pl022_resume_resources(pl022);
+ pl022_resume_resources(pl022, false);
+ pm_runtime_put(dev);
/* Start the queue running */
ret = spi_master_resume(pl022->master);
@@ -2376,7 +2395,7 @@ static int pl022_runtime_suspend(struct device *dev)
{
struct pl022 *pl022 = dev_get_drvdata(dev);
- pl022_suspend_resources(pl022);
+ pl022_suspend_resources(pl022, true);
return 0;
}
@@ -2384,7 +2403,7 @@ static int pl022_runtime_resume(struct device *dev)
{
struct pl022 *pl022 = dev_get_drvdata(dev);
- pl022_resume_resources(pl022);
+ pl022_resume_resources(pl022, true);
return 0;
}
#endif
@@ -2464,7 +2483,7 @@ static struct amba_driver pl022_driver = {
},
.id_table = pl022_ids,
.probe = pl022_probe,
- .remove = __devexit_p(pl022_remove),
+ .remove = pl022_remove,
};
static int __init pl022_init(void)
diff --git a/drivers/spi/spi-ppc4xx.c b/drivers/spi/spi-ppc4xx.c
index 7a85f22b6474..357f183a4fb7 100644
--- a/drivers/spi/spi-ppc4xx.c
+++ b/drivers/spi/spi-ppc4xx.c
@@ -389,7 +389,7 @@ static void free_gpios(struct ppc4xx_spi *hw)
/*
* platform_device layer stuff...
*/
-static int __init spi_ppc4xx_of_probe(struct platform_device *op)
+static int spi_ppc4xx_of_probe(struct platform_device *op)
{
struct ppc4xx_spi *hw;
struct spi_master *master;
@@ -419,7 +419,7 @@ static int __init spi_ppc4xx_of_probe(struct platform_device *op)
* This includes both "null" gpio's and real ones.
*/
num_gpios = of_gpio_count(np);
- if (num_gpios) {
+ if (num_gpios > 0) {
int i;
hw->gpios = kzalloc(sizeof(int) * num_gpios, GFP_KERNEL);
@@ -471,7 +471,7 @@ static int __init spi_ppc4xx_of_probe(struct platform_device *op)
SPI_CPHA | SPI_CPOL | SPI_CS_HIGH | SPI_LSB_FIRST;
/* this many pins in all GPIO controllers */
- bbp->master->num_chipselect = num_gpios;
+ bbp->master->num_chipselect = num_gpios > 0 ? num_gpios : 0;
/* Get the clock for the OPB */
opbnp = of_find_compatible_node(NULL, NULL, "ibm,opb");
@@ -560,7 +560,7 @@ free_master:
return ret;
}
-static int __exit spi_ppc4xx_of_remove(struct platform_device *op)
+static int spi_ppc4xx_of_remove(struct platform_device *op)
{
struct spi_master *master = dev_get_drvdata(&op->dev);
struct ppc4xx_spi *hw = spi_master_get_devdata(master);
@@ -583,7 +583,7 @@ MODULE_DEVICE_TABLE(of, spi_ppc4xx_of_match);
static struct platform_driver spi_ppc4xx_of_driver = {
.probe = spi_ppc4xx_of_probe,
- .remove = __exit_p(spi_ppc4xx_of_remove),
+ .remove = spi_ppc4xx_of_remove,
.driver = {
.name = DRIVER_NAME,
.owner = THIS_MODULE,
diff --git a/drivers/spi/spi-pxa2xx-dma.c b/drivers/spi/spi-pxa2xx-dma.c
new file mode 100644
index 000000000000..c735c5a008a2
--- /dev/null
+++ b/drivers/spi/spi-pxa2xx-dma.c
@@ -0,0 +1,392 @@
+/*
+ * PXA2xx SPI DMA engine support.
+ *
+ * Copyright (C) 2013, Intel Corporation
+ * Author: Mika Westerberg <mika.westerberg@linux.intel.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
+#include <linux/dmaengine.h>
+#include <linux/pxa2xx_ssp.h>
+#include <linux/scatterlist.h>
+#include <linux/sizes.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/pxa2xx_spi.h>
+
+#include "spi-pxa2xx.h"
+
+static int pxa2xx_spi_map_dma_buffer(struct driver_data *drv_data,
+ enum dma_data_direction dir)
+{
+ int i, nents, len = drv_data->len;
+ struct scatterlist *sg;
+ struct device *dmadev;
+ struct sg_table *sgt;
+ void *buf, *pbuf;
+
+ /*
+ * Some DMA controllers have problems transferring buffers that are
+ * not multiple of 4 bytes. So we truncate the transfer so that it
+ * is suitable for such controllers, and handle the trailing bytes
+ * manually after the DMA completes.
+ *
+ * REVISIT: It would be better if this information could be
+ * retrieved directly from the DMA device in a similar way than
+ * ->copy_align etc. is done.
+ */
+ len = ALIGN(drv_data->len, 4);
+
+ if (dir == DMA_TO_DEVICE) {
+ dmadev = drv_data->tx_chan->device->dev;
+ sgt = &drv_data->tx_sgt;
+ buf = drv_data->tx;
+ drv_data->tx_map_len = len;
+ } else {
+ dmadev = drv_data->rx_chan->device->dev;
+ sgt = &drv_data->rx_sgt;
+ buf = drv_data->rx;
+ drv_data->rx_map_len = len;
+ }
+
+ nents = DIV_ROUND_UP(len, SZ_2K);
+ if (nents != sgt->nents) {
+ int ret;
+
+ sg_free_table(sgt);
+ ret = sg_alloc_table(sgt, nents, GFP_KERNEL);
+ if (ret)
+ return ret;
+ }
+
+ pbuf = buf;
+ for_each_sg(sgt->sgl, sg, sgt->nents, i) {
+ size_t bytes = min_t(size_t, len, SZ_2K);
+
+ if (buf)
+ sg_set_buf(sg, pbuf, bytes);
+ else
+ sg_set_buf(sg, drv_data->dummy, bytes);
+
+ pbuf += bytes;
+ len -= bytes;
+ }
+
+ nents = dma_map_sg(dmadev, sgt->sgl, sgt->nents, dir);
+ if (!nents)
+ return -ENOMEM;
+
+ return nents;
+}
+
+static void pxa2xx_spi_unmap_dma_buffer(struct driver_data *drv_data,
+ enum dma_data_direction dir)
+{
+ struct device *dmadev;
+ struct sg_table *sgt;
+
+ if (dir == DMA_TO_DEVICE) {
+ dmadev = drv_data->tx_chan->device->dev;
+ sgt = &drv_data->tx_sgt;
+ } else {
+ dmadev = drv_data->rx_chan->device->dev;
+ sgt = &drv_data->rx_sgt;
+ }
+
+ dma_unmap_sg(dmadev, sgt->sgl, sgt->nents, dir);
+}
+
+static void pxa2xx_spi_unmap_dma_buffers(struct driver_data *drv_data)
+{
+ if (!drv_data->dma_mapped)
+ return;
+
+ pxa2xx_spi_unmap_dma_buffer(drv_data, DMA_FROM_DEVICE);
+ pxa2xx_spi_unmap_dma_buffer(drv_data, DMA_TO_DEVICE);
+
+ drv_data->dma_mapped = 0;
+}
+
+static void pxa2xx_spi_dma_transfer_complete(struct driver_data *drv_data,
+ bool error)
+{
+ struct spi_message *msg = drv_data->cur_msg;
+
+ /*
+ * It is possible that one CPU is handling ROR interrupt and other
+ * just gets DMA completion. Calling pump_transfers() twice for the
+ * same transfer leads to problems thus we prevent concurrent calls
+ * by using ->dma_running.
+ */
+ if (atomic_dec_and_test(&drv_data->dma_running)) {
+ void __iomem *reg = drv_data->ioaddr;
+
+ /*
+ * If the other CPU is still handling the ROR interrupt we
+ * might not know about the error yet. So we re-check the
+ * ROR bit here before we clear the status register.
+ */
+ if (!error) {
+ u32 status = read_SSSR(reg) & drv_data->mask_sr;
+ error = status & SSSR_ROR;
+ }
+
+ /* Clear status & disable interrupts */
+ write_SSCR1(read_SSCR1(reg) & ~drv_data->dma_cr1, reg);
+ write_SSSR_CS(drv_data, drv_data->clear_sr);
+ if (!pxa25x_ssp_comp(drv_data))
+ write_SSTO(0, reg);
+
+ if (!error) {
+ pxa2xx_spi_unmap_dma_buffers(drv_data);
+
+ /* Handle the last bytes of unaligned transfer */
+ drv_data->tx += drv_data->tx_map_len;
+ drv_data->write(drv_data);
+
+ drv_data->rx += drv_data->rx_map_len;
+ drv_data->read(drv_data);
+
+ msg->actual_length += drv_data->len;
+ msg->state = pxa2xx_spi_next_transfer(drv_data);
+ } else {
+ /* In case we got an error we disable the SSP now */
+ write_SSCR0(read_SSCR0(reg) & ~SSCR0_SSE, reg);
+
+ msg->state = ERROR_STATE;
+ }
+
+ tasklet_schedule(&drv_data->pump_transfers);
+ }
+}
+
+static void pxa2xx_spi_dma_callback(void *data)
+{
+ pxa2xx_spi_dma_transfer_complete(data, false);
+}
+
+static struct dma_async_tx_descriptor *
+pxa2xx_spi_dma_prepare_one(struct driver_data *drv_data,
+ enum dma_transfer_direction dir)
+{
+ struct pxa2xx_spi_master *pdata = drv_data->master_info;
+ struct chip_data *chip = drv_data->cur_chip;
+ enum dma_slave_buswidth width;
+ struct dma_slave_config cfg;
+ struct dma_chan *chan;
+ struct sg_table *sgt;
+ int nents, ret;
+
+ switch (drv_data->n_bytes) {
+ case 1:
+ width = DMA_SLAVE_BUSWIDTH_1_BYTE;
+ break;
+ case 2:
+ width = DMA_SLAVE_BUSWIDTH_2_BYTES;
+ break;
+ default:
+ width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+ break;
+ }
+
+ memset(&cfg, 0, sizeof(cfg));
+ cfg.direction = dir;
+
+ if (dir == DMA_MEM_TO_DEV) {
+ cfg.dst_addr = drv_data->ssdr_physical;
+ cfg.dst_addr_width = width;
+ cfg.dst_maxburst = chip->dma_burst_size;
+ cfg.slave_id = pdata->tx_slave_id;
+
+ sgt = &drv_data->tx_sgt;
+ nents = drv_data->tx_nents;
+ chan = drv_data->tx_chan;
+ } else {
+ cfg.src_addr = drv_data->ssdr_physical;
+ cfg.src_addr_width = width;
+ cfg.src_maxburst = chip->dma_burst_size;
+ cfg.slave_id = pdata->rx_slave_id;
+
+ sgt = &drv_data->rx_sgt;
+ nents = drv_data->rx_nents;
+ chan = drv_data->rx_chan;
+ }
+
+ ret = dmaengine_slave_config(chan, &cfg);
+ if (ret) {
+ dev_warn(&drv_data->pdev->dev, "DMA slave config failed\n");
+ return NULL;
+ }
+
+ return dmaengine_prep_slave_sg(chan, sgt->sgl, nents, dir,
+ DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+}
+
+static bool pxa2xx_spi_dma_filter(struct dma_chan *chan, void *param)
+{
+ const struct pxa2xx_spi_master *pdata = param;
+
+ return chan->chan_id == pdata->tx_chan_id ||
+ chan->chan_id == pdata->rx_chan_id;
+}
+
+bool pxa2xx_spi_dma_is_possible(size_t len)
+{
+ return len <= MAX_DMA_LEN;
+}
+
+int pxa2xx_spi_map_dma_buffers(struct driver_data *drv_data)
+{
+ const struct chip_data *chip = drv_data->cur_chip;
+ int ret;
+
+ if (!chip->enable_dma)
+ return 0;
+
+ /* Don't bother with DMA if we can't do even a single burst */
+ if (drv_data->len < chip->dma_burst_size)
+ return 0;
+
+ ret = pxa2xx_spi_map_dma_buffer(drv_data, DMA_TO_DEVICE);
+ if (ret <= 0) {
+ dev_warn(&drv_data->pdev->dev, "failed to DMA map TX\n");
+ return 0;
+ }
+
+ drv_data->tx_nents = ret;
+
+ ret = pxa2xx_spi_map_dma_buffer(drv_data, DMA_FROM_DEVICE);
+ if (ret <= 0) {
+ pxa2xx_spi_unmap_dma_buffer(drv_data, DMA_TO_DEVICE);
+ dev_warn(&drv_data->pdev->dev, "failed to DMA map RX\n");
+ return 0;
+ }
+
+ drv_data->rx_nents = ret;
+ return 1;
+}
+
+irqreturn_t pxa2xx_spi_dma_transfer(struct driver_data *drv_data)
+{
+ u32 status;
+
+ status = read_SSSR(drv_data->ioaddr) & drv_data->mask_sr;
+ if (status & SSSR_ROR) {
+ dev_err(&drv_data->pdev->dev, "FIFO overrun\n");
+
+ dmaengine_terminate_all(drv_data->rx_chan);
+ dmaengine_terminate_all(drv_data->tx_chan);
+
+ pxa2xx_spi_dma_transfer_complete(drv_data, true);
+ return IRQ_HANDLED;
+ }
+
+ return IRQ_NONE;
+}
+
+int pxa2xx_spi_dma_prepare(struct driver_data *drv_data, u32 dma_burst)
+{
+ struct dma_async_tx_descriptor *tx_desc, *rx_desc;
+
+ tx_desc = pxa2xx_spi_dma_prepare_one(drv_data, DMA_MEM_TO_DEV);
+ if (!tx_desc) {
+ dev_err(&drv_data->pdev->dev,
+ "failed to get DMA TX descriptor\n");
+ return -EBUSY;
+ }
+
+ rx_desc = pxa2xx_spi_dma_prepare_one(drv_data, DMA_DEV_TO_MEM);
+ if (!rx_desc) {
+ dev_err(&drv_data->pdev->dev,
+ "failed to get DMA RX descriptor\n");
+ return -EBUSY;
+ }
+
+ /* We are ready when RX completes */
+ rx_desc->callback = pxa2xx_spi_dma_callback;
+ rx_desc->callback_param = drv_data;
+
+ dmaengine_submit(rx_desc);
+ dmaengine_submit(tx_desc);
+ return 0;
+}
+
+void pxa2xx_spi_dma_start(struct driver_data *drv_data)
+{
+ dma_async_issue_pending(drv_data->rx_chan);
+ dma_async_issue_pending(drv_data->tx_chan);
+
+ atomic_set(&drv_data->dma_running, 1);
+}
+
+int pxa2xx_spi_dma_setup(struct driver_data *drv_data)
+{
+ struct pxa2xx_spi_master *pdata = drv_data->master_info;
+ dma_cap_mask_t mask;
+
+ dma_cap_zero(mask);
+ dma_cap_set(DMA_SLAVE, mask);
+
+ drv_data->dummy = devm_kzalloc(&drv_data->pdev->dev, SZ_2K, GFP_KERNEL);
+ if (!drv_data->dummy)
+ return -ENOMEM;
+
+ drv_data->tx_chan = dma_request_channel(mask, pxa2xx_spi_dma_filter,
+ pdata);
+ if (!drv_data->tx_chan)
+ return -ENODEV;
+
+ drv_data->rx_chan = dma_request_channel(mask, pxa2xx_spi_dma_filter,
+ pdata);
+ if (!drv_data->rx_chan) {
+ dma_release_channel(drv_data->tx_chan);
+ drv_data->tx_chan = NULL;
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+void pxa2xx_spi_dma_release(struct driver_data *drv_data)
+{
+ if (drv_data->rx_chan) {
+ dmaengine_terminate_all(drv_data->rx_chan);
+ dma_release_channel(drv_data->rx_chan);
+ sg_free_table(&drv_data->rx_sgt);
+ drv_data->rx_chan = NULL;
+ }
+ if (drv_data->tx_chan) {
+ dmaengine_terminate_all(drv_data->tx_chan);
+ dma_release_channel(drv_data->tx_chan);
+ sg_free_table(&drv_data->tx_sgt);
+ drv_data->tx_chan = NULL;
+ }
+}
+
+void pxa2xx_spi_dma_resume(struct driver_data *drv_data)
+{
+}
+
+int pxa2xx_spi_set_dma_burst_and_threshold(struct chip_data *chip,
+ struct spi_device *spi,
+ u8 bits_per_word, u32 *burst_code,
+ u32 *threshold)
+{
+ struct pxa2xx_spi_chip *chip_info = spi->controller_data;
+
+ /*
+ * If the DMA burst size is given in chip_info we use that,
+ * otherwise we use the default. Also we use the default FIFO
+ * thresholds for now.
+ */
+ *burst_code = chip_info ? chip_info->dma_burst_size : 16;
+ *threshold = SSCR1_RxTresh(RX_THRESH_DFLT)
+ | SSCR1_TxTresh(TX_THRESH_DFLT);
+
+ return 0;
+}
diff --git a/drivers/spi/spi-pxa2xx-pci.c b/drivers/spi/spi-pxa2xx-pci.c
index 9f6ba34b172c..364964d2ed04 100644
--- a/drivers/spi/spi-pxa2xx-pci.c
+++ b/drivers/spi/spi-pxa2xx-pci.c
@@ -8,147 +8,58 @@
#include <linux/module.h>
#include <linux/spi/pxa2xx_spi.h>
-struct ce4100_info {
- struct ssp_device ssp;
- struct platform_device *spi_pdev;
-};
-
-static DEFINE_MUTEX(ssp_lock);
-static LIST_HEAD(ssp_list);
-
-struct ssp_device *pxa_ssp_request(int port, const char *label)
-{
- struct ssp_device *ssp = NULL;
-
- mutex_lock(&ssp_lock);
-
- list_for_each_entry(ssp, &ssp_list, node) {
- if (ssp->port_id == port && ssp->use_count == 0) {
- ssp->use_count++;
- ssp->label = label;
- break;
- }
- }
-
- mutex_unlock(&ssp_lock);
-
- if (&ssp->node == &ssp_list)
- return NULL;
-
- return ssp;
-}
-EXPORT_SYMBOL_GPL(pxa_ssp_request);
-
-void pxa_ssp_free(struct ssp_device *ssp)
-{
- mutex_lock(&ssp_lock);
- if (ssp->use_count) {
- ssp->use_count--;
- ssp->label = NULL;
- } else
- dev_err(&ssp->pdev->dev, "device already free\n");
- mutex_unlock(&ssp_lock);
-}
-EXPORT_SYMBOL_GPL(pxa_ssp_free);
-
-static int __devinit ce4100_spi_probe(struct pci_dev *dev,
+static int ce4100_spi_probe(struct pci_dev *dev,
const struct pci_device_id *ent)
{
+ struct platform_device_info pi;
int ret;
- resource_size_t phys_beg;
- resource_size_t phys_len;
- struct ce4100_info *spi_info;
struct platform_device *pdev;
struct pxa2xx_spi_master spi_pdata;
struct ssp_device *ssp;
- ret = pci_enable_device(dev);
+ ret = pcim_enable_device(dev);
if (ret)
return ret;
- phys_beg = pci_resource_start(dev, 0);
- phys_len = pci_resource_len(dev, 0);
-
- if (!request_mem_region(phys_beg, phys_len,
- "CE4100 SPI")) {
- dev_err(&dev->dev, "Can't request register space.\n");
- ret = -EBUSY;
+ ret = pcim_iomap_regions(dev, 1 << 0, "PXA2xx SPI");
+ if (!ret)
return ret;
- }
- pdev = platform_device_alloc("pxa2xx-spi", dev->devfn);
- spi_info = kzalloc(sizeof(*spi_info), GFP_KERNEL);
- if (!pdev || !spi_info ) {
- ret = -ENOMEM;
- goto err_nomem;
- }
memset(&spi_pdata, 0, sizeof(spi_pdata));
spi_pdata.num_chipselect = dev->devfn;
- ret = platform_device_add_data(pdev, &spi_pdata, sizeof(spi_pdata));
- if (ret)
- goto err_nomem;
-
- pdev->dev.parent = &dev->dev;
- pdev->dev.of_node = dev->dev.of_node;
- ssp = &spi_info->ssp;
+ ssp = &spi_pdata.ssp;
ssp->phys_base = pci_resource_start(dev, 0);
- ssp->mmio_base = ioremap(phys_beg, phys_len);
+ ssp->mmio_base = pcim_iomap_table(dev)[0];
if (!ssp->mmio_base) {
- dev_err(&pdev->dev, "failed to ioremap() registers\n");
- ret = -EIO;
- goto err_nomem;
+ dev_err(&dev->dev, "failed to ioremap() registers\n");
+ return -EIO;
}
ssp->irq = dev->irq;
- ssp->port_id = pdev->id;
+ ssp->port_id = dev->devfn;
ssp->type = PXA25x_SSP;
- mutex_lock(&ssp_lock);
- list_add(&ssp->node, &ssp_list);
- mutex_unlock(&ssp_lock);
+ memset(&pi, 0, sizeof(pi));
+ pi.parent = &dev->dev;
+ pi.name = "pxa2xx-spi";
+ pi.id = ssp->port_id;
+ pi.data = &spi_pdata;
+ pi.size_data = sizeof(spi_pdata);
- pci_set_drvdata(dev, spi_info);
+ pdev = platform_device_register_full(&pi);
+ if (!pdev)
+ return -ENOMEM;
- ret = platform_device_add(pdev);
- if (ret)
- goto err_dev_add;
+ pci_set_drvdata(dev, pdev);
- return ret;
-
-err_dev_add:
- pci_set_drvdata(dev, NULL);
- mutex_lock(&ssp_lock);
- list_del(&ssp->node);
- mutex_unlock(&ssp_lock);
- iounmap(ssp->mmio_base);
-
-err_nomem:
- release_mem_region(phys_beg, phys_len);
- platform_device_put(pdev);
- kfree(spi_info);
- return ret;
+ return 0;
}
-static void __devexit ce4100_spi_remove(struct pci_dev *dev)
+static void ce4100_spi_remove(struct pci_dev *dev)
{
- struct ce4100_info *spi_info;
- struct ssp_device *ssp;
-
- spi_info = pci_get_drvdata(dev);
- ssp = &spi_info->ssp;
- platform_device_unregister(spi_info->spi_pdev);
-
- iounmap(ssp->mmio_base);
- release_mem_region(pci_resource_start(dev, 0),
- pci_resource_len(dev, 0));
-
- mutex_lock(&ssp_lock);
- list_del(&ssp->node);
- mutex_unlock(&ssp_lock);
+ struct platform_device *pdev = pci_get_drvdata(dev);
- pci_set_drvdata(dev, NULL);
- pci_disable_device(dev);
- kfree(spi_info);
+ platform_device_unregister(pdev);
}
static DEFINE_PCI_DEVICE_TABLE(ce4100_spi_devices) = {
@@ -161,7 +72,7 @@ static struct pci_driver ce4100_spi_driver = {
.name = "ce4100_spi",
.id_table = ce4100_spi_devices,
.probe = ce4100_spi_probe,
- .remove = __devexit_p(ce4100_spi_remove),
+ .remove = ce4100_spi_remove,
};
module_pci_driver(ce4100_spi_driver);
diff --git a/drivers/spi/spi-pxa2xx-pxadma.c b/drivers/spi/spi-pxa2xx-pxadma.c
new file mode 100644
index 000000000000..2916efc7cfe5
--- /dev/null
+++ b/drivers/spi/spi-pxa2xx-pxadma.c
@@ -0,0 +1,490 @@
+/*
+ * PXA2xx SPI private DMA support.
+ *
+ * Copyright (C) 2005 Stephen Street / StreetFire Sound Labs
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
+#include <linux/pxa2xx_ssp.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/pxa2xx_spi.h>
+
+#include "spi-pxa2xx.h"
+
+#define DMA_INT_MASK (DCSR_ENDINTR | DCSR_STARTINTR | DCSR_BUSERR)
+#define RESET_DMA_CHANNEL (DCSR_NODESC | DMA_INT_MASK)
+
+bool pxa2xx_spi_dma_is_possible(size_t len)
+{
+ /* Try to map dma buffer and do a dma transfer if successful, but
+ * only if the length is non-zero and less than MAX_DMA_LEN.
+ *
+ * Zero-length non-descriptor DMA is illegal on PXA2xx; force use
+ * of PIO instead. Care is needed above because the transfer may
+ * have have been passed with buffers that are already dma mapped.
+ * A zero-length transfer in PIO mode will not try to write/read
+ * to/from the buffers
+ *
+ * REVISIT large transfers are exactly where we most want to be
+ * using DMA. If this happens much, split those transfers into
+ * multiple DMA segments rather than forcing PIO.
+ */
+ return len > 0 && len <= MAX_DMA_LEN;
+}
+
+int pxa2xx_spi_map_dma_buffers(struct driver_data *drv_data)
+{
+ struct spi_message *msg = drv_data->cur_msg;
+ struct device *dev = &msg->spi->dev;
+
+ if (!drv_data->cur_chip->enable_dma)
+ return 0;
+
+ if (msg->is_dma_mapped)
+ return drv_data->rx_dma && drv_data->tx_dma;
+
+ if (!IS_DMA_ALIGNED(drv_data->rx) || !IS_DMA_ALIGNED(drv_data->tx))
+ return 0;
+
+ /* Modify setup if rx buffer is null */
+ if (drv_data->rx == NULL) {
+ *drv_data->null_dma_buf = 0;
+ drv_data->rx = drv_data->null_dma_buf;
+ drv_data->rx_map_len = 4;
+ } else
+ drv_data->rx_map_len = drv_data->len;
+
+
+ /* Modify setup if tx buffer is null */
+ if (drv_data->tx == NULL) {
+ *drv_data->null_dma_buf = 0;
+ drv_data->tx = drv_data->null_dma_buf;
+ drv_data->tx_map_len = 4;
+ } else
+ drv_data->tx_map_len = drv_data->len;
+
+ /* Stream map the tx buffer. Always do DMA_TO_DEVICE first
+ * so we flush the cache *before* invalidating it, in case
+ * the tx and rx buffers overlap.
+ */
+ drv_data->tx_dma = dma_map_single(dev, drv_data->tx,
+ drv_data->tx_map_len, DMA_TO_DEVICE);
+ if (dma_mapping_error(dev, drv_data->tx_dma))
+ return 0;
+
+ /* Stream map the rx buffer */
+ drv_data->rx_dma = dma_map_single(dev, drv_data->rx,
+ drv_data->rx_map_len, DMA_FROM_DEVICE);
+ if (dma_mapping_error(dev, drv_data->rx_dma)) {
+ dma_unmap_single(dev, drv_data->tx_dma,
+ drv_data->tx_map_len, DMA_TO_DEVICE);
+ return 0;
+ }
+
+ return 1;
+}
+
+static void pxa2xx_spi_unmap_dma_buffers(struct driver_data *drv_data)
+{
+ struct device *dev;
+
+ if (!drv_data->dma_mapped)
+ return;
+
+ if (!drv_data->cur_msg->is_dma_mapped) {
+ dev = &drv_data->cur_msg->spi->dev;
+ dma_unmap_single(dev, drv_data->rx_dma,
+ drv_data->rx_map_len, DMA_FROM_DEVICE);
+ dma_unmap_single(dev, drv_data->tx_dma,
+ drv_data->tx_map_len, DMA_TO_DEVICE);
+ }
+
+ drv_data->dma_mapped = 0;
+}
+
+static int wait_ssp_rx_stall(void const __iomem *ioaddr)
+{
+ unsigned long limit = loops_per_jiffy << 1;
+
+ while ((read_SSSR(ioaddr) & SSSR_BSY) && --limit)
+ cpu_relax();
+
+ return limit;
+}
+
+static int wait_dma_channel_stop(int channel)
+{
+ unsigned long limit = loops_per_jiffy << 1;
+
+ while (!(DCSR(channel) & DCSR_STOPSTATE) && --limit)
+ cpu_relax();
+
+ return limit;
+}
+
+static void pxa2xx_spi_dma_error_stop(struct driver_data *drv_data,
+ const char *msg)
+{
+ void __iomem *reg = drv_data->ioaddr;
+
+ /* Stop and reset */
+ DCSR(drv_data->rx_channel) = RESET_DMA_CHANNEL;
+ DCSR(drv_data->tx_channel) = RESET_DMA_CHANNEL;
+ write_SSSR_CS(drv_data, drv_data->clear_sr);
+ write_SSCR1(read_SSCR1(reg) & ~drv_data->dma_cr1, reg);
+ if (!pxa25x_ssp_comp(drv_data))
+ write_SSTO(0, reg);
+ pxa2xx_spi_flush(drv_data);
+ write_SSCR0(read_SSCR0(reg) & ~SSCR0_SSE, reg);
+
+ pxa2xx_spi_unmap_dma_buffers(drv_data);
+
+ dev_err(&drv_data->pdev->dev, "%s\n", msg);
+
+ drv_data->cur_msg->state = ERROR_STATE;
+ tasklet_schedule(&drv_data->pump_transfers);
+}
+
+static void pxa2xx_spi_dma_transfer_complete(struct driver_data *drv_data)
+{
+ void __iomem *reg = drv_data->ioaddr;
+ struct spi_message *msg = drv_data->cur_msg;
+
+ /* Clear and disable interrupts on SSP and DMA channels*/
+ write_SSCR1(read_SSCR1(reg) & ~drv_data->dma_cr1, reg);
+ write_SSSR_CS(drv_data, drv_data->clear_sr);
+ DCSR(drv_data->tx_channel) = RESET_DMA_CHANNEL;
+ DCSR(drv_data->rx_channel) = RESET_DMA_CHANNEL;
+
+ if (wait_dma_channel_stop(drv_data->rx_channel) == 0)
+ dev_err(&drv_data->pdev->dev,
+ "dma_handler: dma rx channel stop failed\n");
+
+ if (wait_ssp_rx_stall(drv_data->ioaddr) == 0)
+ dev_err(&drv_data->pdev->dev,
+ "dma_transfer: ssp rx stall failed\n");
+
+ pxa2xx_spi_unmap_dma_buffers(drv_data);
+
+ /* update the buffer pointer for the amount completed in dma */
+ drv_data->rx += drv_data->len -
+ (DCMD(drv_data->rx_channel) & DCMD_LENGTH);
+
+ /* read trailing data from fifo, it does not matter how many
+ * bytes are in the fifo just read until buffer is full
+ * or fifo is empty, which ever occurs first */
+ drv_data->read(drv_data);
+
+ /* return count of what was actually read */
+ msg->actual_length += drv_data->len -
+ (drv_data->rx_end - drv_data->rx);
+
+ /* Transfer delays and chip select release are
+ * handled in pump_transfers or giveback
+ */
+
+ /* Move to next transfer */
+ msg->state = pxa2xx_spi_next_transfer(drv_data);
+
+ /* Schedule transfer tasklet */
+ tasklet_schedule(&drv_data->pump_transfers);
+}
+
+void pxa2xx_spi_dma_handler(int channel, void *data)
+{
+ struct driver_data *drv_data = data;
+ u32 irq_status = DCSR(channel) & DMA_INT_MASK;
+
+ if (irq_status & DCSR_BUSERR) {
+
+ if (channel == drv_data->tx_channel)
+ pxa2xx_spi_dma_error_stop(drv_data,
+ "dma_handler: bad bus address on tx channel");
+ else
+ pxa2xx_spi_dma_error_stop(drv_data,
+ "dma_handler: bad bus address on rx channel");
+ return;
+ }
+
+ /* PXA255x_SSP has no timeout interrupt, wait for tailing bytes */
+ if ((channel == drv_data->tx_channel)
+ && (irq_status & DCSR_ENDINTR)
+ && (drv_data->ssp_type == PXA25x_SSP)) {
+
+ /* Wait for rx to stall */
+ if (wait_ssp_rx_stall(drv_data->ioaddr) == 0)
+ dev_err(&drv_data->pdev->dev,
+ "dma_handler: ssp rx stall failed\n");
+
+ /* finish this transfer, start the next */
+ pxa2xx_spi_dma_transfer_complete(drv_data);
+ }
+}
+
+irqreturn_t pxa2xx_spi_dma_transfer(struct driver_data *drv_data)
+{
+ u32 irq_status;
+ void __iomem *reg = drv_data->ioaddr;
+
+ irq_status = read_SSSR(reg) & drv_data->mask_sr;
+ if (irq_status & SSSR_ROR) {
+ pxa2xx_spi_dma_error_stop(drv_data,
+ "dma_transfer: fifo overrun");
+ return IRQ_HANDLED;
+ }
+
+ /* Check for false positive timeout */
+ if ((irq_status & SSSR_TINT)
+ && (DCSR(drv_data->tx_channel) & DCSR_RUN)) {
+ write_SSSR(SSSR_TINT, reg);
+ return IRQ_HANDLED;
+ }
+
+ if (irq_status & SSSR_TINT || drv_data->rx == drv_data->rx_end) {
+
+ /* Clear and disable timeout interrupt, do the rest in
+ * dma_transfer_complete */
+ if (!pxa25x_ssp_comp(drv_data))
+ write_SSTO(0, reg);
+
+ /* finish this transfer, start the next */
+ pxa2xx_spi_dma_transfer_complete(drv_data);
+
+ return IRQ_HANDLED;
+ }
+
+ /* Opps problem detected */
+ return IRQ_NONE;
+}
+
+int pxa2xx_spi_dma_prepare(struct driver_data *drv_data, u32 dma_burst)
+{
+ u32 dma_width;
+
+ switch (drv_data->n_bytes) {
+ case 1:
+ dma_width = DCMD_WIDTH1;
+ break;
+ case 2:
+ dma_width = DCMD_WIDTH2;
+ break;
+ default:
+ dma_width = DCMD_WIDTH4;
+ break;
+ }
+
+ /* Setup rx DMA Channel */
+ DCSR(drv_data->rx_channel) = RESET_DMA_CHANNEL;
+ DSADR(drv_data->rx_channel) = drv_data->ssdr_physical;
+ DTADR(drv_data->rx_channel) = drv_data->rx_dma;
+ if (drv_data->rx == drv_data->null_dma_buf)
+ /* No target address increment */
+ DCMD(drv_data->rx_channel) = DCMD_FLOWSRC
+ | dma_width
+ | dma_burst
+ | drv_data->len;
+ else
+ DCMD(drv_data->rx_channel) = DCMD_INCTRGADDR
+ | DCMD_FLOWSRC
+ | dma_width
+ | dma_burst
+ | drv_data->len;
+
+ /* Setup tx DMA Channel */
+ DCSR(drv_data->tx_channel) = RESET_DMA_CHANNEL;
+ DSADR(drv_data->tx_channel) = drv_data->tx_dma;
+ DTADR(drv_data->tx_channel) = drv_data->ssdr_physical;
+ if (drv_data->tx == drv_data->null_dma_buf)
+ /* No source address increment */
+ DCMD(drv_data->tx_channel) = DCMD_FLOWTRG
+ | dma_width
+ | dma_burst
+ | drv_data->len;
+ else
+ DCMD(drv_data->tx_channel) = DCMD_INCSRCADDR
+ | DCMD_FLOWTRG
+ | dma_width
+ | dma_burst
+ | drv_data->len;
+
+ /* Enable dma end irqs on SSP to detect end of transfer */
+ if (drv_data->ssp_type == PXA25x_SSP)
+ DCMD(drv_data->tx_channel) |= DCMD_ENDIRQEN;
+
+ return 0;
+}
+
+void pxa2xx_spi_dma_start(struct driver_data *drv_data)
+{
+ DCSR(drv_data->rx_channel) |= DCSR_RUN;
+ DCSR(drv_data->tx_channel) |= DCSR_RUN;
+}
+
+int pxa2xx_spi_dma_setup(struct driver_data *drv_data)
+{
+ struct device *dev = &drv_data->pdev->dev;
+ struct ssp_device *ssp = drv_data->ssp;
+
+ /* Get two DMA channels (rx and tx) */
+ drv_data->rx_channel = pxa_request_dma("pxa2xx_spi_ssp_rx",
+ DMA_PRIO_HIGH,
+ pxa2xx_spi_dma_handler,
+ drv_data);
+ if (drv_data->rx_channel < 0) {
+ dev_err(dev, "problem (%d) requesting rx channel\n",
+ drv_data->rx_channel);
+ return -ENODEV;
+ }
+ drv_data->tx_channel = pxa_request_dma("pxa2xx_spi_ssp_tx",
+ DMA_PRIO_MEDIUM,
+ pxa2xx_spi_dma_handler,
+ drv_data);
+ if (drv_data->tx_channel < 0) {
+ dev_err(dev, "problem (%d) requesting tx channel\n",
+ drv_data->tx_channel);
+ pxa_free_dma(drv_data->rx_channel);
+ return -ENODEV;
+ }
+
+ DRCMR(ssp->drcmr_rx) = DRCMR_MAPVLD | drv_data->rx_channel;
+ DRCMR(ssp->drcmr_tx) = DRCMR_MAPVLD | drv_data->tx_channel;
+
+ return 0;
+}
+
+void pxa2xx_spi_dma_release(struct driver_data *drv_data)
+{
+ struct ssp_device *ssp = drv_data->ssp;
+
+ DRCMR(ssp->drcmr_rx) = 0;
+ DRCMR(ssp->drcmr_tx) = 0;
+
+ if (drv_data->tx_channel != 0)
+ pxa_free_dma(drv_data->tx_channel);
+ if (drv_data->rx_channel != 0)
+ pxa_free_dma(drv_data->rx_channel);
+}
+
+void pxa2xx_spi_dma_resume(struct driver_data *drv_data)
+{
+ if (drv_data->rx_channel != -1)
+ DRCMR(drv_data->ssp->drcmr_rx) =
+ DRCMR_MAPVLD | drv_data->rx_channel;
+ if (drv_data->tx_channel != -1)
+ DRCMR(drv_data->ssp->drcmr_tx) =
+ DRCMR_MAPVLD | drv_data->tx_channel;
+}
+
+int pxa2xx_spi_set_dma_burst_and_threshold(struct chip_data *chip,
+ struct spi_device *spi,
+ u8 bits_per_word, u32 *burst_code,
+ u32 *threshold)
+{
+ struct pxa2xx_spi_chip *chip_info =
+ (struct pxa2xx_spi_chip *)spi->controller_data;
+ int bytes_per_word;
+ int burst_bytes;
+ int thresh_words;
+ int req_burst_size;
+ int retval = 0;
+
+ /* Set the threshold (in registers) to equal the same amount of data
+ * as represented by burst size (in bytes). The computation below
+ * is (burst_size rounded up to nearest 8 byte, word or long word)
+ * divided by (bytes/register); the tx threshold is the inverse of
+ * the rx, so that there will always be enough data in the rx fifo
+ * to satisfy a burst, and there will always be enough space in the
+ * tx fifo to accept a burst (a tx burst will overwrite the fifo if
+ * there is not enough space), there must always remain enough empty
+ * space in the rx fifo for any data loaded to the tx fifo.
+ * Whenever burst_size (in bytes) equals bits/word, the fifo threshold
+ * will be 8, or half the fifo;
+ * The threshold can only be set to 2, 4 or 8, but not 16, because
+ * to burst 16 to the tx fifo, the fifo would have to be empty;
+ * however, the minimum fifo trigger level is 1, and the tx will
+ * request service when the fifo is at this level, with only 15 spaces.
+ */
+
+ /* find bytes/word */
+ if (bits_per_word <= 8)
+ bytes_per_word = 1;
+ else if (bits_per_word <= 16)
+ bytes_per_word = 2;
+ else
+ bytes_per_word = 4;
+
+ /* use struct pxa2xx_spi_chip->dma_burst_size if available */
+ if (chip_info)
+ req_burst_size = chip_info->dma_burst_size;
+ else {
+ switch (chip->dma_burst_size) {
+ default:
+ /* if the default burst size is not set,
+ * do it now */
+ chip->dma_burst_size = DCMD_BURST8;
+ case DCMD_BURST8:
+ req_burst_size = 8;
+ break;
+ case DCMD_BURST16:
+ req_burst_size = 16;
+ break;
+ case DCMD_BURST32:
+ req_burst_size = 32;
+ break;
+ }
+ }
+ if (req_burst_size <= 8) {
+ *burst_code = DCMD_BURST8;
+ burst_bytes = 8;
+ } else if (req_burst_size <= 16) {
+ if (bytes_per_word == 1) {
+ /* don't burst more than 1/2 the fifo */
+ *burst_code = DCMD_BURST8;
+ burst_bytes = 8;
+ retval = 1;
+ } else {
+ *burst_code = DCMD_BURST16;
+ burst_bytes = 16;
+ }
+ } else {
+ if (bytes_per_word == 1) {
+ /* don't burst more than 1/2 the fifo */
+ *burst_code = DCMD_BURST8;
+ burst_bytes = 8;
+ retval = 1;
+ } else if (bytes_per_word == 2) {
+ /* don't burst more than 1/2 the fifo */
+ *burst_code = DCMD_BURST16;
+ burst_bytes = 16;
+ retval = 1;
+ } else {
+ *burst_code = DCMD_BURST32;
+ burst_bytes = 32;
+ }
+ }
+
+ thresh_words = burst_bytes / bytes_per_word;
+
+ /* thresh_words will be between 2 and 8 */
+ *threshold = (SSCR1_RxTresh(thresh_words) & SSCR1_RFT)
+ | (SSCR1_TxTresh(16-thresh_words) & SSCR1_TFT);
+
+ return retval;
+}
diff --git a/drivers/spi/spi-pxa2xx.c b/drivers/spi/spi-pxa2xx.c
index dc25bee8d33f..90b27a3508a6 100644
--- a/drivers/spi/spi-pxa2xx.c
+++ b/drivers/spi/spi-pxa2xx.c
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2005 Stephen Street / StreetFire Sound Labs
+ * Copyright (C) 2013, Intel Corporation
*
* 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
@@ -24,17 +25,20 @@
#include <linux/interrupt.h>
#include <linux/platform_device.h>
#include <linux/spi/pxa2xx_spi.h>
-#include <linux/dma-mapping.h>
#include <linux/spi/spi.h>
#include <linux/workqueue.h>
#include <linux/delay.h>
#include <linux/gpio.h>
#include <linux/slab.h>
+#include <linux/clk.h>
+#include <linux/pm_runtime.h>
+#include <linux/acpi.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/delay.h>
+#include "spi-pxa2xx.h"
MODULE_AUTHOR("Stephen Street");
MODULE_DESCRIPTION("PXA2xx SSP SPI Controller");
@@ -45,12 +49,6 @@ MODULE_ALIAS("platform:pxa2xx-spi");
#define TIMOUT_DFLT 1000
-#define DMA_INT_MASK (DCSR_ENDINTR | DCSR_STARTINTR | DCSR_BUSERR)
-#define RESET_DMA_CHANNEL (DCSR_NODESC | DMA_INT_MASK)
-#define IS_DMA_ALIGNED(x) ((((u32)(x)) & 0x07) == 0)
-#define MAX_DMA_LEN 8191
-#define DMA_ALIGNMENT 8
-
/*
* for testing SSCR1 changes that require SSP restart, basically
* everything except the service and interrupt enables, the pxa270 developer
@@ -65,115 +63,97 @@ MODULE_ALIAS("platform:pxa2xx-spi");
| SSCR1_RFT | SSCR1_TFT | SSCR1_MWDS \
| SSCR1_SPH | SSCR1_SPO | SSCR1_LBM)
-#define DEFINE_SSP_REG(reg, off) \
-static inline u32 read_##reg(void const __iomem *p) \
-{ return __raw_readl(p + (off)); } \
-\
-static inline void write_##reg(u32 v, void __iomem *p) \
-{ __raw_writel(v, p + (off)); }
-
-DEFINE_SSP_REG(SSCR0, 0x00)
-DEFINE_SSP_REG(SSCR1, 0x04)
-DEFINE_SSP_REG(SSSR, 0x08)
-DEFINE_SSP_REG(SSITR, 0x0c)
-DEFINE_SSP_REG(SSDR, 0x10)
-DEFINE_SSP_REG(SSTO, 0x28)
-DEFINE_SSP_REG(SSPSP, 0x2c)
-
-#define START_STATE ((void*)0)
-#define RUNNING_STATE ((void*)1)
-#define DONE_STATE ((void*)2)
-#define ERROR_STATE ((void*)-1)
-
-#define QUEUE_RUNNING 0
-#define QUEUE_STOPPED 1
-
-struct driver_data {
- /* Driver model hookup */
- struct platform_device *pdev;
-
- /* SSP Info */
- struct ssp_device *ssp;
+#define LPSS_RX_THRESH_DFLT 64
+#define LPSS_TX_LOTHRESH_DFLT 160
+#define LPSS_TX_HITHRESH_DFLT 224
- /* SPI framework hookup */
- enum pxa_ssp_type ssp_type;
- struct spi_master *master;
+/* Offset from drv_data->lpss_base */
+#define SPI_CS_CONTROL 0x18
+#define SPI_CS_CONTROL_SW_MODE BIT(0)
+#define SPI_CS_CONTROL_CS_HIGH BIT(1)
- /* PXA hookup */
- struct pxa2xx_spi_master *master_info;
-
- /* DMA setup stuff */
- int rx_channel;
- int tx_channel;
- u32 *null_dma_buf;
-
- /* SSP register addresses */
- void __iomem *ioaddr;
- u32 ssdr_physical;
-
- /* SSP masks*/
- u32 dma_cr1;
- u32 int_cr1;
- u32 clear_sr;
- u32 mask_sr;
-
- /* Driver message queue */
- struct workqueue_struct *workqueue;
- struct work_struct pump_messages;
- spinlock_t lock;
- struct list_head queue;
- int busy;
- int run;
-
- /* Message Transfer pump */
- struct tasklet_struct pump_transfers;
-
- /* Current message transfer state info */
- struct spi_message* cur_msg;
- struct spi_transfer* cur_transfer;
- struct chip_data *cur_chip;
- size_t len;
- void *tx;
- void *tx_end;
- void *rx;
- void *rx_end;
- int dma_mapped;
- dma_addr_t rx_dma;
- dma_addr_t tx_dma;
- size_t rx_map_len;
- size_t tx_map_len;
- u8 n_bytes;
- u32 dma_width;
- int (*write)(struct driver_data *drv_data);
- int (*read)(struct driver_data *drv_data);
- irqreturn_t (*transfer_handler)(struct driver_data *drv_data);
- void (*cs_control)(u32 command);
-};
+static bool is_lpss_ssp(const struct driver_data *drv_data)
+{
+ return drv_data->ssp_type == LPSS_SSP;
+}
-struct chip_data {
- u32 cr0;
- u32 cr1;
- u32 psp;
- u32 timeout;
- u8 n_bytes;
- u32 dma_width;
- u32 dma_burst_size;
- u32 threshold;
- u32 dma_threshold;
- u8 enable_dma;
- u8 bits_per_word;
- u32 speed_hz;
- union {
- int gpio_cs;
- unsigned int frm;
- };
- int gpio_cs_inverted;
- int (*write)(struct driver_data *drv_data);
- int (*read)(struct driver_data *drv_data);
- void (*cs_control)(u32 command);
-};
+/*
+ * Read and write LPSS SSP private registers. Caller must first check that
+ * is_lpss_ssp() returns true before these can be called.
+ */
+static u32 __lpss_ssp_read_priv(struct driver_data *drv_data, unsigned offset)
+{
+ WARN_ON(!drv_data->lpss_base);
+ return readl(drv_data->lpss_base + offset);
+}
-static void pump_messages(struct work_struct *work);
+static void __lpss_ssp_write_priv(struct driver_data *drv_data,
+ unsigned offset, u32 value)
+{
+ WARN_ON(!drv_data->lpss_base);
+ writel(value, drv_data->lpss_base + offset);
+}
+
+/*
+ * lpss_ssp_setup - perform LPSS SSP specific setup
+ * @drv_data: pointer to the driver private data
+ *
+ * Perform LPSS SSP specific setup. This function must be called first if
+ * one is going to use LPSS SSP private registers.
+ */
+static void lpss_ssp_setup(struct driver_data *drv_data)
+{
+ unsigned offset = 0x400;
+ u32 value, orig;
+
+ if (!is_lpss_ssp(drv_data))
+ return;
+
+ /*
+ * Perform auto-detection of the LPSS SSP private registers. They
+ * can be either at 1k or 2k offset from the base address.
+ */
+ orig = readl(drv_data->ioaddr + offset + SPI_CS_CONTROL);
+
+ value = orig | SPI_CS_CONTROL_SW_MODE;
+ writel(value, drv_data->ioaddr + offset + SPI_CS_CONTROL);
+ value = readl(drv_data->ioaddr + offset + SPI_CS_CONTROL);
+ if (value != (orig | SPI_CS_CONTROL_SW_MODE)) {
+ offset = 0x800;
+ goto detection_done;
+ }
+
+ value &= ~SPI_CS_CONTROL_SW_MODE;
+ writel(value, drv_data->ioaddr + offset + SPI_CS_CONTROL);
+ value = readl(drv_data->ioaddr + offset + SPI_CS_CONTROL);
+ if (value != orig) {
+ offset = 0x800;
+ goto detection_done;
+ }
+
+detection_done:
+ /* Now set the LPSS base */
+ drv_data->lpss_base = drv_data->ioaddr + offset;
+
+ /* Enable software chip select control */
+ value = SPI_CS_CONTROL_SW_MODE | SPI_CS_CONTROL_CS_HIGH;
+ __lpss_ssp_write_priv(drv_data, SPI_CS_CONTROL, value);
+}
+
+static void lpss_ssp_cs_control(struct driver_data *drv_data, bool enable)
+{
+ u32 value;
+
+ if (!is_lpss_ssp(drv_data))
+ return;
+
+ value = __lpss_ssp_read_priv(drv_data, SPI_CS_CONTROL);
+ if (enable)
+ value &= ~SPI_CS_CONTROL_CS_HIGH;
+ else
+ value |= SPI_CS_CONTROL_CS_HIGH;
+ __lpss_ssp_write_priv(drv_data, SPI_CS_CONTROL, value);
+}
static void cs_assert(struct driver_data *drv_data)
{
@@ -189,8 +169,12 @@ static void cs_assert(struct driver_data *drv_data)
return;
}
- if (gpio_is_valid(chip->gpio_cs))
+ if (gpio_is_valid(chip->gpio_cs)) {
gpio_set_value(chip->gpio_cs, chip->gpio_cs_inverted);
+ return;
+ }
+
+ lpss_ssp_cs_control(drv_data, true);
}
static void cs_deassert(struct driver_data *drv_data)
@@ -205,30 +189,15 @@ static void cs_deassert(struct driver_data *drv_data)
return;
}
- if (gpio_is_valid(chip->gpio_cs))
+ if (gpio_is_valid(chip->gpio_cs)) {
gpio_set_value(chip->gpio_cs, !chip->gpio_cs_inverted);
-}
-
-static void write_SSSR_CS(struct driver_data *drv_data, u32 val)
-{
- void __iomem *reg = drv_data->ioaddr;
-
- if (drv_data->ssp_type == CE4100_SSP)
- val |= read_SSSR(reg) & SSSR_ALT_FRM_MASK;
-
- write_SSSR(val, reg);
-}
+ return;
+ }
-static int pxa25x_ssp_comp(struct driver_data *drv_data)
-{
- if (drv_data->ssp_type == PXA25x_SSP)
- return 1;
- if (drv_data->ssp_type == CE4100_SSP)
- return 1;
- return 0;
+ lpss_ssp_cs_control(drv_data, false);
}
-static int flush(struct driver_data *drv_data)
+int pxa2xx_spi_flush(struct driver_data *drv_data)
{
unsigned long limit = loops_per_jiffy << 1;
@@ -354,7 +323,7 @@ static int u32_reader(struct driver_data *drv_data)
return drv_data->rx == drv_data->rx_end;
}
-static void *next_transfer(struct driver_data *drv_data)
+void *pxa2xx_spi_next_transfer(struct driver_data *drv_data)
{
struct spi_message *msg = drv_data->cur_msg;
struct spi_transfer *trans = drv_data->cur_transfer;
@@ -370,89 +339,15 @@ static void *next_transfer(struct driver_data *drv_data)
return DONE_STATE;
}
-static int map_dma_buffers(struct driver_data *drv_data)
-{
- struct spi_message *msg = drv_data->cur_msg;
- struct device *dev = &msg->spi->dev;
-
- if (!drv_data->cur_chip->enable_dma)
- return 0;
-
- if (msg->is_dma_mapped)
- return drv_data->rx_dma && drv_data->tx_dma;
-
- if (!IS_DMA_ALIGNED(drv_data->rx) || !IS_DMA_ALIGNED(drv_data->tx))
- return 0;
-
- /* Modify setup if rx buffer is null */
- if (drv_data->rx == NULL) {
- *drv_data->null_dma_buf = 0;
- drv_data->rx = drv_data->null_dma_buf;
- drv_data->rx_map_len = 4;
- } else
- drv_data->rx_map_len = drv_data->len;
-
-
- /* Modify setup if tx buffer is null */
- if (drv_data->tx == NULL) {
- *drv_data->null_dma_buf = 0;
- drv_data->tx = drv_data->null_dma_buf;
- drv_data->tx_map_len = 4;
- } else
- drv_data->tx_map_len = drv_data->len;
-
- /* Stream map the tx buffer. Always do DMA_TO_DEVICE first
- * so we flush the cache *before* invalidating it, in case
- * the tx and rx buffers overlap.
- */
- drv_data->tx_dma = dma_map_single(dev, drv_data->tx,
- drv_data->tx_map_len, DMA_TO_DEVICE);
- if (dma_mapping_error(dev, drv_data->tx_dma))
- return 0;
-
- /* Stream map the rx buffer */
- drv_data->rx_dma = dma_map_single(dev, drv_data->rx,
- drv_data->rx_map_len, DMA_FROM_DEVICE);
- if (dma_mapping_error(dev, drv_data->rx_dma)) {
- dma_unmap_single(dev, drv_data->tx_dma,
- drv_data->tx_map_len, DMA_TO_DEVICE);
- return 0;
- }
-
- return 1;
-}
-
-static void unmap_dma_buffers(struct driver_data *drv_data)
-{
- struct device *dev;
-
- if (!drv_data->dma_mapped)
- return;
-
- if (!drv_data->cur_msg->is_dma_mapped) {
- dev = &drv_data->cur_msg->spi->dev;
- dma_unmap_single(dev, drv_data->rx_dma,
- drv_data->rx_map_len, DMA_FROM_DEVICE);
- dma_unmap_single(dev, drv_data->tx_dma,
- drv_data->tx_map_len, DMA_TO_DEVICE);
- }
-
- drv_data->dma_mapped = 0;
-}
-
/* caller already set message->status; dma and pio irqs are blocked */
static void giveback(struct driver_data *drv_data)
{
struct spi_transfer* last_transfer;
- unsigned long flags;
struct spi_message *msg;
- spin_lock_irqsave(&drv_data->lock, flags);
msg = drv_data->cur_msg;
drv_data->cur_msg = NULL;
drv_data->cur_transfer = NULL;
- queue_work(drv_data->workqueue, &drv_data->pump_messages);
- spin_unlock_irqrestore(&drv_data->lock, flags);
last_transfer = list_entry(msg->transfers.prev,
struct spi_transfer,
@@ -481,13 +376,7 @@ static void giveback(struct driver_data *drv_data)
*/
/* get a pointer to the next message, if any */
- spin_lock_irqsave(&drv_data->lock, flags);
- if (list_empty(&drv_data->queue))
- next_msg = NULL;
- else
- next_msg = list_entry(drv_data->queue.next,
- struct spi_message, queue);
- spin_unlock_irqrestore(&drv_data->lock, flags);
+ next_msg = spi_get_next_queued_message(drv_data->master);
/* see if the next and current messages point
* to the same chip
@@ -498,168 +387,10 @@ static void giveback(struct driver_data *drv_data)
cs_deassert(drv_data);
}
- msg->state = NULL;
- if (msg->complete)
- msg->complete(msg->context);
-
+ spi_finalize_current_message(drv_data->master);
drv_data->cur_chip = NULL;
}
-static int wait_ssp_rx_stall(void const __iomem *ioaddr)
-{
- unsigned long limit = loops_per_jiffy << 1;
-
- while ((read_SSSR(ioaddr) & SSSR_BSY) && --limit)
- cpu_relax();
-
- return limit;
-}
-
-static int wait_dma_channel_stop(int channel)
-{
- unsigned long limit = loops_per_jiffy << 1;
-
- while (!(DCSR(channel) & DCSR_STOPSTATE) && --limit)
- cpu_relax();
-
- return limit;
-}
-
-static void dma_error_stop(struct driver_data *drv_data, const char *msg)
-{
- void __iomem *reg = drv_data->ioaddr;
-
- /* Stop and reset */
- DCSR(drv_data->rx_channel) = RESET_DMA_CHANNEL;
- DCSR(drv_data->tx_channel) = RESET_DMA_CHANNEL;
- write_SSSR_CS(drv_data, drv_data->clear_sr);
- write_SSCR1(read_SSCR1(reg) & ~drv_data->dma_cr1, reg);
- if (!pxa25x_ssp_comp(drv_data))
- write_SSTO(0, reg);
- flush(drv_data);
- write_SSCR0(read_SSCR0(reg) & ~SSCR0_SSE, reg);
-
- unmap_dma_buffers(drv_data);
-
- dev_err(&drv_data->pdev->dev, "%s\n", msg);
-
- drv_data->cur_msg->state = ERROR_STATE;
- tasklet_schedule(&drv_data->pump_transfers);
-}
-
-static void dma_transfer_complete(struct driver_data *drv_data)
-{
- void __iomem *reg = drv_data->ioaddr;
- struct spi_message *msg = drv_data->cur_msg;
-
- /* Clear and disable interrupts on SSP and DMA channels*/
- write_SSCR1(read_SSCR1(reg) & ~drv_data->dma_cr1, reg);
- write_SSSR_CS(drv_data, drv_data->clear_sr);
- DCSR(drv_data->tx_channel) = RESET_DMA_CHANNEL;
- DCSR(drv_data->rx_channel) = RESET_DMA_CHANNEL;
-
- if (wait_dma_channel_stop(drv_data->rx_channel) == 0)
- dev_err(&drv_data->pdev->dev,
- "dma_handler: dma rx channel stop failed\n");
-
- if (wait_ssp_rx_stall(drv_data->ioaddr) == 0)
- dev_err(&drv_data->pdev->dev,
- "dma_transfer: ssp rx stall failed\n");
-
- unmap_dma_buffers(drv_data);
-
- /* update the buffer pointer for the amount completed in dma */
- drv_data->rx += drv_data->len -
- (DCMD(drv_data->rx_channel) & DCMD_LENGTH);
-
- /* read trailing data from fifo, it does not matter how many
- * bytes are in the fifo just read until buffer is full
- * or fifo is empty, which ever occurs first */
- drv_data->read(drv_data);
-
- /* return count of what was actually read */
- msg->actual_length += drv_data->len -
- (drv_data->rx_end - drv_data->rx);
-
- /* Transfer delays and chip select release are
- * handled in pump_transfers or giveback
- */
-
- /* Move to next transfer */
- msg->state = next_transfer(drv_data);
-
- /* Schedule transfer tasklet */
- tasklet_schedule(&drv_data->pump_transfers);
-}
-
-static void dma_handler(int channel, void *data)
-{
- struct driver_data *drv_data = data;
- u32 irq_status = DCSR(channel) & DMA_INT_MASK;
-
- if (irq_status & DCSR_BUSERR) {
-
- if (channel == drv_data->tx_channel)
- dma_error_stop(drv_data,
- "dma_handler: "
- "bad bus address on tx channel");
- else
- dma_error_stop(drv_data,
- "dma_handler: "
- "bad bus address on rx channel");
- return;
- }
-
- /* PXA255x_SSP has no timeout interrupt, wait for tailing bytes */
- if ((channel == drv_data->tx_channel)
- && (irq_status & DCSR_ENDINTR)
- && (drv_data->ssp_type == PXA25x_SSP)) {
-
- /* Wait for rx to stall */
- if (wait_ssp_rx_stall(drv_data->ioaddr) == 0)
- dev_err(&drv_data->pdev->dev,
- "dma_handler: ssp rx stall failed\n");
-
- /* finish this transfer, start the next */
- dma_transfer_complete(drv_data);
- }
-}
-
-static irqreturn_t dma_transfer(struct driver_data *drv_data)
-{
- u32 irq_status;
- void __iomem *reg = drv_data->ioaddr;
-
- irq_status = read_SSSR(reg) & drv_data->mask_sr;
- if (irq_status & SSSR_ROR) {
- dma_error_stop(drv_data, "dma_transfer: fifo overrun");
- return IRQ_HANDLED;
- }
-
- /* Check for false positive timeout */
- if ((irq_status & SSSR_TINT)
- && (DCSR(drv_data->tx_channel) & DCSR_RUN)) {
- write_SSSR(SSSR_TINT, reg);
- return IRQ_HANDLED;
- }
-
- if (irq_status & SSSR_TINT || drv_data->rx == drv_data->rx_end) {
-
- /* Clear and disable timeout interrupt, do the rest in
- * dma_transfer_complete */
- if (!pxa25x_ssp_comp(drv_data))
- write_SSTO(0, reg);
-
- /* finish this transfer, start the next */
- dma_transfer_complete(drv_data);
-
- return IRQ_HANDLED;
- }
-
- /* Opps problem detected */
- return IRQ_NONE;
-}
-
static void reset_sccr1(struct driver_data *drv_data)
{
void __iomem *reg = drv_data->ioaddr;
@@ -681,7 +412,7 @@ static void int_error_stop(struct driver_data *drv_data, const char* msg)
reset_sccr1(drv_data);
if (!pxa25x_ssp_comp(drv_data))
write_SSTO(0, reg);
- flush(drv_data);
+ pxa2xx_spi_flush(drv_data);
write_SSCR0(read_SSCR0(reg) & ~SSCR0_SSE, reg);
dev_err(&drv_data->pdev->dev, "%s\n", msg);
@@ -709,7 +440,7 @@ static void int_transfer_complete(struct driver_data *drv_data)
*/
/* Move to next transfer */
- drv_data->cur_msg->state = next_transfer(drv_data);
+ drv_data->cur_msg->state = pxa2xx_spi_next_transfer(drv_data);
/* Schedule transfer tasklet */
tasklet_schedule(&drv_data->pump_transfers);
@@ -789,10 +520,20 @@ static irqreturn_t ssp_int(int irq, void *dev_id)
{
struct driver_data *drv_data = dev_id;
void __iomem *reg = drv_data->ioaddr;
- u32 sccr1_reg = read_SSCR1(reg);
+ u32 sccr1_reg;
u32 mask = drv_data->mask_sr;
u32 status;
+ /*
+ * The IRQ might be shared with other peripherals so we must first
+ * check that are we RPM suspended or not. If we are we assume that
+ * the IRQ was not for us (we shouldn't be RPM suspended when the
+ * interrupt is enabled).
+ */
+ if (pm_runtime_suspended(&drv_data->pdev->dev))
+ return IRQ_NONE;
+
+ sccr1_reg = read_SSCR1(reg);
status = read_SSSR(reg);
/* Ignore possible writes if we don't need to write */
@@ -820,106 +561,12 @@ static irqreturn_t ssp_int(int irq, void *dev_id)
return drv_data->transfer_handler(drv_data);
}
-static int set_dma_burst_and_threshold(struct chip_data *chip,
- struct spi_device *spi,
- u8 bits_per_word, u32 *burst_code,
- u32 *threshold)
+static unsigned int ssp_get_clk_div(struct driver_data *drv_data, int rate)
{
- struct pxa2xx_spi_chip *chip_info =
- (struct pxa2xx_spi_chip *)spi->controller_data;
- int bytes_per_word;
- int burst_bytes;
- int thresh_words;
- int req_burst_size;
- int retval = 0;
-
- /* Set the threshold (in registers) to equal the same amount of data
- * as represented by burst size (in bytes). The computation below
- * is (burst_size rounded up to nearest 8 byte, word or long word)
- * divided by (bytes/register); the tx threshold is the inverse of
- * the rx, so that there will always be enough data in the rx fifo
- * to satisfy a burst, and there will always be enough space in the
- * tx fifo to accept a burst (a tx burst will overwrite the fifo if
- * there is not enough space), there must always remain enough empty
- * space in the rx fifo for any data loaded to the tx fifo.
- * Whenever burst_size (in bytes) equals bits/word, the fifo threshold
- * will be 8, or half the fifo;
- * The threshold can only be set to 2, 4 or 8, but not 16, because
- * to burst 16 to the tx fifo, the fifo would have to be empty;
- * however, the minimum fifo trigger level is 1, and the tx will
- * request service when the fifo is at this level, with only 15 spaces.
- */
+ unsigned long ssp_clk = drv_data->max_clk_rate;
+ const struct ssp_device *ssp = drv_data->ssp;
- /* find bytes/word */
- if (bits_per_word <= 8)
- bytes_per_word = 1;
- else if (bits_per_word <= 16)
- bytes_per_word = 2;
- else
- bytes_per_word = 4;
-
- /* use struct pxa2xx_spi_chip->dma_burst_size if available */
- if (chip_info)
- req_burst_size = chip_info->dma_burst_size;
- else {
- switch (chip->dma_burst_size) {
- default:
- /* if the default burst size is not set,
- * do it now */
- chip->dma_burst_size = DCMD_BURST8;
- case DCMD_BURST8:
- req_burst_size = 8;
- break;
- case DCMD_BURST16:
- req_burst_size = 16;
- break;
- case DCMD_BURST32:
- req_burst_size = 32;
- break;
- }
- }
- if (req_burst_size <= 8) {
- *burst_code = DCMD_BURST8;
- burst_bytes = 8;
- } else if (req_burst_size <= 16) {
- if (bytes_per_word == 1) {
- /* don't burst more than 1/2 the fifo */
- *burst_code = DCMD_BURST8;
- burst_bytes = 8;
- retval = 1;
- } else {
- *burst_code = DCMD_BURST16;
- burst_bytes = 16;
- }
- } else {
- if (bytes_per_word == 1) {
- /* don't burst more than 1/2 the fifo */
- *burst_code = DCMD_BURST8;
- burst_bytes = 8;
- retval = 1;
- } else if (bytes_per_word == 2) {
- /* don't burst more than 1/2 the fifo */
- *burst_code = DCMD_BURST16;
- burst_bytes = 16;
- retval = 1;
- } else {
- *burst_code = DCMD_BURST32;
- burst_bytes = 32;
- }
- }
-
- thresh_words = burst_bytes / bytes_per_word;
-
- /* thresh_words will be between 2 and 8 */
- *threshold = (SSCR1_RxTresh(thresh_words) & SSCR1_RFT)
- | (SSCR1_TxTresh(16-thresh_words) & SSCR1_TFT);
-
- return retval;
-}
-
-static unsigned int ssp_get_clk_div(struct ssp_device *ssp, int rate)
-{
- unsigned long ssp_clk = clk_get_rate(ssp->clk);
+ rate = min_t(int, ssp_clk, rate);
if (ssp->type == PXA25x_SSP || ssp->type == CE4100_SSP)
return ((ssp_clk / (2 * rate) - 1) & 0xff) << 8;
@@ -934,7 +581,6 @@ static void pump_transfers(unsigned long data)
struct spi_transfer *transfer = NULL;
struct spi_transfer *previous = NULL;
struct chip_data *chip = NULL;
- struct ssp_device *ssp = drv_data->ssp;
void __iomem *reg = drv_data->ioaddr;
u32 clk_div = 0;
u8 bits = 0;
@@ -976,8 +622,8 @@ static void pump_transfers(unsigned long data)
cs_deassert(drv_data);
}
- /* Check for transfers that need multiple DMA segments */
- if (transfer->len > MAX_DMA_LEN && chip->enable_dma) {
+ /* Check if we can DMA this transfer */
+ if (!pxa2xx_spi_dma_is_possible(transfer->len) && chip->enable_dma) {
/* reject already-mapped transfers; PIO won't always work */
if (message->is_dma_mapped
@@ -1000,21 +646,20 @@ static void pump_transfers(unsigned long data)
}
/* Setup the transfer state based on the type of transfer */
- if (flush(drv_data) == 0) {
+ if (pxa2xx_spi_flush(drv_data) == 0) {
dev_err(&drv_data->pdev->dev, "pump_transfers: flush failed\n");
message->status = -EIO;
giveback(drv_data);
return;
}
drv_data->n_bytes = chip->n_bytes;
- drv_data->dma_width = chip->dma_width;
drv_data->tx = (void *)transfer->tx_buf;
drv_data->tx_end = drv_data->tx + transfer->len;
drv_data->rx = transfer->rx_buf;
drv_data->rx_end = drv_data->rx + transfer->len;
drv_data->rx_dma = transfer->rx_dma;
drv_data->tx_dma = transfer->tx_dma;
- drv_data->len = transfer->len & DCMD_LENGTH;
+ drv_data->len = transfer->len;
drv_data->write = drv_data->tx ? chip->write : null_writer;
drv_data->read = drv_data->rx ? chip->read : null_reader;
@@ -1031,25 +676,22 @@ static void pump_transfers(unsigned long data)
if (transfer->bits_per_word)
bits = transfer->bits_per_word;
- clk_div = ssp_get_clk_div(ssp, speed);
+ clk_div = ssp_get_clk_div(drv_data, speed);
if (bits <= 8) {
drv_data->n_bytes = 1;
- drv_data->dma_width = DCMD_WIDTH1;
drv_data->read = drv_data->read != null_reader ?
u8_reader : null_reader;
drv_data->write = drv_data->write != null_writer ?
u8_writer : null_writer;
} else if (bits <= 16) {
drv_data->n_bytes = 2;
- drv_data->dma_width = DCMD_WIDTH2;
drv_data->read = drv_data->read != null_reader ?
u16_reader : null_reader;
drv_data->write = drv_data->write != null_writer ?
u16_writer : null_writer;
} else if (bits <= 32) {
drv_data->n_bytes = 4;
- drv_data->dma_width = DCMD_WIDTH4;
drv_data->read = drv_data->read != null_reader ?
u32_reader : null_reader;
drv_data->write = drv_data->write != null_writer ?
@@ -1058,7 +700,8 @@ static void pump_transfers(unsigned long data)
/* if bits/word is changed in dma mode, then must check the
* thresholds and burst also */
if (chip->enable_dma) {
- if (set_dma_burst_and_threshold(chip, message->spi,
+ if (pxa2xx_spi_set_dma_burst_and_threshold(chip,
+ message->spi,
bits, &dma_burst,
&dma_thresh))
if (printk_ratelimit())
@@ -1077,70 +720,21 @@ static void pump_transfers(unsigned long data)
message->state = RUNNING_STATE;
- /* Try to map dma buffer and do a dma transfer if successful, but
- * only if the length is non-zero and less than MAX_DMA_LEN.
- *
- * Zero-length non-descriptor DMA is illegal on PXA2xx; force use
- * of PIO instead. Care is needed above because the transfer may
- * have have been passed with buffers that are already dma mapped.
- * A zero-length transfer in PIO mode will not try to write/read
- * to/from the buffers
- *
- * REVISIT large transfers are exactly where we most want to be
- * using DMA. If this happens much, split those transfers into
- * multiple DMA segments rather than forcing PIO.
- */
drv_data->dma_mapped = 0;
- if (drv_data->len > 0 && drv_data->len <= MAX_DMA_LEN)
- drv_data->dma_mapped = map_dma_buffers(drv_data);
+ if (pxa2xx_spi_dma_is_possible(drv_data->len))
+ drv_data->dma_mapped = pxa2xx_spi_map_dma_buffers(drv_data);
if (drv_data->dma_mapped) {
/* Ensure we have the correct interrupt handler */
- drv_data->transfer_handler = dma_transfer;
-
- /* Setup rx DMA Channel */
- DCSR(drv_data->rx_channel) = RESET_DMA_CHANNEL;
- DSADR(drv_data->rx_channel) = drv_data->ssdr_physical;
- DTADR(drv_data->rx_channel) = drv_data->rx_dma;
- if (drv_data->rx == drv_data->null_dma_buf)
- /* No target address increment */
- DCMD(drv_data->rx_channel) = DCMD_FLOWSRC
- | drv_data->dma_width
- | dma_burst
- | drv_data->len;
- else
- DCMD(drv_data->rx_channel) = DCMD_INCTRGADDR
- | DCMD_FLOWSRC
- | drv_data->dma_width
- | dma_burst
- | drv_data->len;
-
- /* Setup tx DMA Channel */
- DCSR(drv_data->tx_channel) = RESET_DMA_CHANNEL;
- DSADR(drv_data->tx_channel) = drv_data->tx_dma;
- DTADR(drv_data->tx_channel) = drv_data->ssdr_physical;
- if (drv_data->tx == drv_data->null_dma_buf)
- /* No source address increment */
- DCMD(drv_data->tx_channel) = DCMD_FLOWTRG
- | drv_data->dma_width
- | dma_burst
- | drv_data->len;
- else
- DCMD(drv_data->tx_channel) = DCMD_INCSRCADDR
- | DCMD_FLOWTRG
- | drv_data->dma_width
- | dma_burst
- | drv_data->len;
-
- /* Enable dma end irqs on SSP to detect end of transfer */
- if (drv_data->ssp_type == PXA25x_SSP)
- DCMD(drv_data->tx_channel) |= DCMD_ENDIRQEN;
+ drv_data->transfer_handler = pxa2xx_spi_dma_transfer;
+
+ pxa2xx_spi_dma_prepare(drv_data, dma_burst);
/* Clear status and start DMA engine */
cr1 = chip->cr1 | dma_thresh | drv_data->dma_cr1;
write_SSSR(drv_data->clear_sr, reg);
- DCSR(drv_data->rx_channel) |= DCSR_RUN;
- DCSR(drv_data->tx_channel) |= DCSR_RUN;
+
+ pxa2xx_spi_dma_start(drv_data);
} else {
/* Ensure we have the correct interrupt handler */
drv_data->transfer_handler = interrupt_transfer;
@@ -1150,6 +744,13 @@ static void pump_transfers(unsigned long data)
write_SSSR_CS(drv_data, drv_data->clear_sr);
}
+ if (is_lpss_ssp(drv_data)) {
+ if ((read_SSIRF(reg) & 0xff) != chip->lpss_rx_threshold)
+ write_SSIRF(chip->lpss_rx_threshold, reg);
+ if ((read_SSITF(reg) & 0xffff) != chip->lpss_tx_threshold)
+ write_SSITF(chip->lpss_tx_threshold, reg);
+ }
+
/* see if we need to reload the config registers */
if ((read_SSCR0(reg) != cr0)
|| (read_SSCR1(reg) & SSCR1_CHANGE_MASK) !=
@@ -1176,31 +777,12 @@ static void pump_transfers(unsigned long data)
write_SSCR1(cr1, reg);
}
-static void pump_messages(struct work_struct *work)
+static int pxa2xx_spi_transfer_one_message(struct spi_master *master,
+ struct spi_message *msg)
{
- struct driver_data *drv_data =
- container_of(work, struct driver_data, pump_messages);
- unsigned long flags;
-
- /* Lock queue and check for queue work */
- spin_lock_irqsave(&drv_data->lock, flags);
- if (list_empty(&drv_data->queue) || drv_data->run == QUEUE_STOPPED) {
- drv_data->busy = 0;
- spin_unlock_irqrestore(&drv_data->lock, flags);
- return;
- }
-
- /* Make sure we are not already running a message */
- if (drv_data->cur_msg) {
- spin_unlock_irqrestore(&drv_data->lock, flags);
- return;
- }
-
- /* Extract head of queue */
- drv_data->cur_msg = list_entry(drv_data->queue.next,
- struct spi_message, queue);
- list_del_init(&drv_data->cur_msg->queue);
+ struct driver_data *drv_data = spi_master_get_devdata(master);
+ drv_data->cur_msg = msg;
/* Initial message state*/
drv_data->cur_msg->state = START_STATE;
drv_data->cur_transfer = list_entry(drv_data->cur_msg->transfers.next,
@@ -1213,34 +795,27 @@ static void pump_messages(struct work_struct *work)
/* Mark as busy and launch transfers */
tasklet_schedule(&drv_data->pump_transfers);
-
- drv_data->busy = 1;
- spin_unlock_irqrestore(&drv_data->lock, flags);
+ return 0;
}
-static int transfer(struct spi_device *spi, struct spi_message *msg)
+static int pxa2xx_spi_prepare_transfer(struct spi_master *master)
{
- struct driver_data *drv_data = spi_master_get_devdata(spi->master);
- unsigned long flags;
-
- spin_lock_irqsave(&drv_data->lock, flags);
-
- if (drv_data->run == QUEUE_STOPPED) {
- spin_unlock_irqrestore(&drv_data->lock, flags);
- return -ESHUTDOWN;
- }
-
- msg->actual_length = 0;
- msg->status = -EINPROGRESS;
- msg->state = START_STATE;
+ struct driver_data *drv_data = spi_master_get_devdata(master);
- list_add_tail(&msg->queue, &drv_data->queue);
+ pm_runtime_get_sync(&drv_data->pdev->dev);
+ return 0;
+}
- if (drv_data->run == QUEUE_RUNNING && !drv_data->busy)
- queue_work(drv_data->workqueue, &drv_data->pump_messages);
+static int pxa2xx_spi_unprepare_transfer(struct spi_master *master)
+{
+ struct driver_data *drv_data = spi_master_get_devdata(master);
- spin_unlock_irqrestore(&drv_data->lock, flags);
+ /* Disable the SSP now */
+ write_SSCR0(read_SSCR0(drv_data->ioaddr) & ~SSCR0_SSE,
+ drv_data->ioaddr);
+ pm_runtime_mark_last_busy(&drv_data->pdev->dev);
+ pm_runtime_put_autosuspend(&drv_data->pdev->dev);
return 0;
}
@@ -1287,10 +862,18 @@ static int setup(struct spi_device *spi)
struct pxa2xx_spi_chip *chip_info = NULL;
struct chip_data *chip;
struct driver_data *drv_data = spi_master_get_devdata(spi->master);
- struct ssp_device *ssp = drv_data->ssp;
unsigned int clk_div;
- uint tx_thres = TX_THRESH_DFLT;
- uint rx_thres = RX_THRESH_DFLT;
+ uint tx_thres, tx_hi_thres, rx_thres;
+
+ if (is_lpss_ssp(drv_data)) {
+ tx_thres = LPSS_TX_LOTHRESH_DFLT;
+ tx_hi_thres = LPSS_TX_HITHRESH_DFLT;
+ rx_thres = LPSS_RX_THRESH_DFLT;
+ } else {
+ tx_thres = TX_THRESH_DFLT;
+ tx_hi_thres = 0;
+ rx_thres = RX_THRESH_DFLT;
+ }
if (!pxa25x_ssp_comp(drv_data)
&& (spi->bits_per_word < 4 || spi->bits_per_word > 32)) {
@@ -1330,8 +913,6 @@ static int setup(struct spi_device *spi)
chip->gpio_cs = -1;
chip->enable_dma = 0;
chip->timeout = TIMOUT_DFLT;
- chip->dma_burst_size = drv_data->master_info->enable_dma ?
- DCMD_BURST8 : 0;
}
/* protocol drivers may change the chip settings, so...
@@ -1345,23 +926,37 @@ static int setup(struct spi_device *spi)
chip->timeout = chip_info->timeout;
if (chip_info->tx_threshold)
tx_thres = chip_info->tx_threshold;
+ if (chip_info->tx_hi_threshold)
+ tx_hi_thres = chip_info->tx_hi_threshold;
if (chip_info->rx_threshold)
rx_thres = chip_info->rx_threshold;
chip->enable_dma = drv_data->master_info->enable_dma;
chip->dma_threshold = 0;
if (chip_info->enable_loopback)
chip->cr1 = SSCR1_LBM;
+ } else if (ACPI_HANDLE(&spi->dev)) {
+ /*
+ * Slave devices enumerated from ACPI namespace don't
+ * usually have chip_info but we still might want to use
+ * DMA with them.
+ */
+ chip->enable_dma = drv_data->master_info->enable_dma;
}
chip->threshold = (SSCR1_RxTresh(rx_thres) & SSCR1_RFT) |
(SSCR1_TxTresh(tx_thres) & SSCR1_TFT);
+ chip->lpss_rx_threshold = SSIRF_RxThresh(rx_thres);
+ chip->lpss_tx_threshold = SSITF_TxLoThresh(tx_thres)
+ | SSITF_TxHiThresh(tx_hi_thres);
+
/* set dma burst and threshold outside of chip_info path so that if
* chip_info goes away after setting chip->enable_dma, the
* burst and threshold can still respond to changes in bits_per_word */
if (chip->enable_dma) {
/* set up legal burst and threshold for dma */
- if (set_dma_burst_and_threshold(chip, spi, spi->bits_per_word,
+ if (pxa2xx_spi_set_dma_burst_and_threshold(chip, spi,
+ spi->bits_per_word,
&chip->dma_burst_size,
&chip->dma_threshold)) {
dev_warn(&spi->dev, "in setup: DMA burst size reduced "
@@ -1369,7 +964,7 @@ static int setup(struct spi_device *spi)
}
}
- clk_div = ssp_get_clk_div(ssp, spi->max_speed_hz);
+ clk_div = ssp_get_clk_div(drv_data, spi->max_speed_hz);
chip->speed_hz = spi->max_speed_hz;
chip->cr0 = clk_div
@@ -1382,32 +977,32 @@ static int setup(struct spi_device *spi)
chip->cr1 |= (((spi->mode & SPI_CPHA) != 0) ? SSCR1_SPH : 0)
| (((spi->mode & SPI_CPOL) != 0) ? SSCR1_SPO : 0);
+ if (spi->mode & SPI_LOOP)
+ chip->cr1 |= SSCR1_LBM;
+
/* NOTE: PXA25x_SSP _could_ use external clocking ... */
if (!pxa25x_ssp_comp(drv_data))
dev_dbg(&spi->dev, "%ld Hz actual, %s\n",
- clk_get_rate(ssp->clk)
+ drv_data->max_clk_rate
/ (1 + ((chip->cr0 & SSCR0_SCR(0xfff)) >> 8)),
chip->enable_dma ? "DMA" : "PIO");
else
dev_dbg(&spi->dev, "%ld Hz actual, %s\n",
- clk_get_rate(ssp->clk) / 2
+ drv_data->max_clk_rate / 2
/ (1 + ((chip->cr0 & SSCR0_SCR(0x0ff)) >> 8)),
chip->enable_dma ? "DMA" : "PIO");
if (spi->bits_per_word <= 8) {
chip->n_bytes = 1;
- chip->dma_width = DCMD_WIDTH1;
chip->read = u8_reader;
chip->write = u8_writer;
} else if (spi->bits_per_word <= 16) {
chip->n_bytes = 2;
- chip->dma_width = DCMD_WIDTH2;
chip->read = u16_reader;
chip->write = u16_writer;
} else if (spi->bits_per_word <= 32) {
chip->cr0 |= SSCR0_EDSS;
chip->n_bytes = 4;
- chip->dma_width = DCMD_WIDTH4;
chip->read = u32_reader;
chip->write = u32_writer;
} else {
@@ -1438,95 +1033,100 @@ static void cleanup(struct spi_device *spi)
kfree(chip);
}
-static int __devinit init_queue(struct driver_data *drv_data)
+#ifdef CONFIG_ACPI
+static int pxa2xx_spi_acpi_add_dma(struct acpi_resource *res, void *data)
{
- INIT_LIST_HEAD(&drv_data->queue);
- spin_lock_init(&drv_data->lock);
-
- drv_data->run = QUEUE_STOPPED;
- drv_data->busy = 0;
-
- tasklet_init(&drv_data->pump_transfers,
- pump_transfers, (unsigned long)drv_data);
-
- INIT_WORK(&drv_data->pump_messages, pump_messages);
- drv_data->workqueue = create_singlethread_workqueue(
- dev_name(drv_data->master->dev.parent));
- if (drv_data->workqueue == NULL)
- return -EBUSY;
+ struct pxa2xx_spi_master *pdata = data;
+
+ if (res->type == ACPI_RESOURCE_TYPE_FIXED_DMA) {
+ const struct acpi_resource_fixed_dma *dma;
+
+ dma = &res->data.fixed_dma;
+ if (pdata->tx_slave_id < 0) {
+ pdata->tx_slave_id = dma->request_lines;
+ pdata->tx_chan_id = dma->channels;
+ } else if (pdata->rx_slave_id < 0) {
+ pdata->rx_slave_id = dma->request_lines;
+ pdata->rx_chan_id = dma->channels;
+ }
+ }
- return 0;
+ /* Tell the ACPI core to skip this resource */
+ return 1;
}
-static int start_queue(struct driver_data *drv_data)
+static struct pxa2xx_spi_master *
+pxa2xx_spi_acpi_get_pdata(struct platform_device *pdev)
{
- unsigned long flags;
-
- spin_lock_irqsave(&drv_data->lock, flags);
-
- if (drv_data->run == QUEUE_RUNNING || drv_data->busy) {
- spin_unlock_irqrestore(&drv_data->lock, flags);
- return -EBUSY;
+ struct pxa2xx_spi_master *pdata;
+ struct list_head resource_list;
+ struct acpi_device *adev;
+ struct ssp_device *ssp;
+ struct resource *res;
+ int devid;
+
+ if (!ACPI_HANDLE(&pdev->dev) ||
+ acpi_bus_get_device(ACPI_HANDLE(&pdev->dev), &adev))
+ return NULL;
+
+ pdata = devm_kzalloc(&pdev->dev, sizeof(*ssp), GFP_KERNEL);
+ if (!pdata) {
+ dev_err(&pdev->dev,
+ "failed to allocate memory for platform data\n");
+ return NULL;
}
- drv_data->run = QUEUE_RUNNING;
- drv_data->cur_msg = NULL;
- drv_data->cur_transfer = NULL;
- drv_data->cur_chip = NULL;
- spin_unlock_irqrestore(&drv_data->lock, flags);
-
- queue_work(drv_data->workqueue, &drv_data->pump_messages);
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res)
+ return NULL;
- return 0;
-}
+ ssp = &pdata->ssp;
-static int stop_queue(struct driver_data *drv_data)
-{
- unsigned long flags;
- unsigned limit = 500;
- int status = 0;
-
- spin_lock_irqsave(&drv_data->lock, flags);
-
- /* This is a bit lame, but is optimized for the common execution path.
- * A wait_queue on the drv_data->busy could be used, but then the common
- * execution path (pump_messages) would be required to call wake_up or
- * friends on every SPI message. Do this instead */
- drv_data->run = QUEUE_STOPPED;
- while ((!list_empty(&drv_data->queue) || drv_data->busy) && limit--) {
- spin_unlock_irqrestore(&drv_data->lock, flags);
- msleep(10);
- spin_lock_irqsave(&drv_data->lock, flags);
+ ssp->phys_base = res->start;
+ ssp->mmio_base = devm_request_and_ioremap(&pdev->dev, res);
+ if (!ssp->mmio_base) {
+ dev_err(&pdev->dev, "failed to ioremap mmio_base\n");
+ return NULL;
}
- if (!list_empty(&drv_data->queue) || drv_data->busy)
- status = -EBUSY;
+ ssp->clk = devm_clk_get(&pdev->dev, NULL);
+ ssp->irq = platform_get_irq(pdev, 0);
+ ssp->type = LPSS_SSP;
+ ssp->pdev = pdev;
- spin_unlock_irqrestore(&drv_data->lock, flags);
+ ssp->port_id = -1;
+ if (adev->pnp.unique_id && !kstrtoint(adev->pnp.unique_id, 0, &devid))
+ ssp->port_id = devid;
- return status;
-}
+ pdata->num_chipselect = 1;
+ pdata->rx_slave_id = -1;
+ pdata->tx_slave_id = -1;
-static int destroy_queue(struct driver_data *drv_data)
-{
- int status;
+ INIT_LIST_HEAD(&resource_list);
+ acpi_dev_get_resources(adev, &resource_list, pxa2xx_spi_acpi_add_dma,
+ pdata);
+ acpi_dev_free_resource_list(&resource_list);
- status = stop_queue(drv_data);
- /* we are unloading the module or failing to load (only two calls
- * to this routine), and neither call can handle a return value.
- * However, destroy_workqueue calls flush_workqueue, and that will
- * block until all work is done. If the reason that stop_queue
- * timed out is that the work will never finish, then it does no
- * good to call destroy_workqueue, so return anyway. */
- if (status != 0)
- return status;
+ pdata->enable_dma = pdata->rx_slave_id >= 0 && pdata->tx_slave_id >= 0;
- destroy_workqueue(drv_data->workqueue);
+ return pdata;
+}
- return 0;
+static struct acpi_device_id pxa2xx_spi_acpi_match[] = {
+ { "INT33C0", 0 },
+ { "INT33C1", 0 },
+ { },
+};
+MODULE_DEVICE_TABLE(acpi, pxa2xx_spi_acpi_match);
+#else
+static inline struct pxa2xx_spi_master *
+pxa2xx_spi_acpi_get_pdata(struct platform_device *pdev)
+{
+ return NULL;
}
+#endif
-static int __devinit pxa2xx_spi_probe(struct platform_device *pdev)
+static int pxa2xx_spi_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct pxa2xx_spi_master *platform_info;
@@ -1535,11 +1135,21 @@ static int __devinit pxa2xx_spi_probe(struct platform_device *pdev)
struct ssp_device *ssp;
int status;
- platform_info = dev->platform_data;
+ platform_info = dev_get_platdata(dev);
+ if (!platform_info) {
+ platform_info = pxa2xx_spi_acpi_get_pdata(pdev);
+ if (!platform_info) {
+ dev_err(&pdev->dev, "missing platform data\n");
+ return -ENODEV;
+ }
+ }
ssp = pxa_ssp_request(pdev->id, pdev->name);
- if (ssp == NULL) {
- dev_err(&pdev->dev, "failed to request SSP%d\n", pdev->id);
+ if (!ssp)
+ ssp = &platform_info->ssp;
+
+ if (!ssp->mmio_base) {
+ dev_err(&pdev->dev, "failed to get ssp\n");
return -ENODEV;
}
@@ -1558,19 +1168,21 @@ static int __devinit pxa2xx_spi_probe(struct platform_device *pdev)
master->dev.parent = &pdev->dev;
master->dev.of_node = pdev->dev.of_node;
+ ACPI_HANDLE_SET(&master->dev, ACPI_HANDLE(&pdev->dev));
/* the spi->mode bits understood by this driver: */
- master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
+ master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LOOP;
- master->bus_num = pdev->id;
+ master->bus_num = ssp->port_id;
master->num_chipselect = platform_info->num_chipselect;
master->dma_alignment = DMA_ALIGNMENT;
master->cleanup = cleanup;
master->setup = setup;
- master->transfer = transfer;
+ master->transfer_one_message = pxa2xx_spi_transfer_one_message;
+ master->prepare_transfer_hardware = pxa2xx_spi_prepare_transfer;
+ master->unprepare_transfer_hardware = pxa2xx_spi_unprepare_transfer;
drv_data->ssp_type = ssp->type;
- drv_data->null_dma_buf = (u32 *)ALIGN((u32)(drv_data +
- sizeof(struct driver_data)), 8);
+ drv_data->null_dma_buf = (u32 *)PTR_ALIGN(&drv_data[1], DMA_ALIGNMENT);
drv_data->ioaddr = ssp->mmio_base;
drv_data->ssdr_physical = ssp->phys_base + SSDR;
@@ -1581,7 +1193,7 @@ static int __devinit pxa2xx_spi_probe(struct platform_device *pdev)
drv_data->mask_sr = SSSR_RFS | SSSR_TFS | SSSR_ROR;
} else {
drv_data->int_cr1 = SSCR1_TIE | SSCR1_RIE | SSCR1_TINTE;
- drv_data->dma_cr1 = SSCR1_TSRE | SSCR1_RSRE | SSCR1_TINTE;
+ drv_data->dma_cr1 = DEFAULT_DMA_CR1;
drv_data->clear_sr = SSSR_ROR | SSSR_TINT;
drv_data->mask_sr = SSSR_TINT | SSSR_RFS | SSSR_TFS | SSSR_ROR;
}
@@ -1597,35 +1209,17 @@ static int __devinit pxa2xx_spi_probe(struct platform_device *pdev)
drv_data->tx_channel = -1;
drv_data->rx_channel = -1;
if (platform_info->enable_dma) {
-
- /* Get two DMA channels (rx and tx) */
- drv_data->rx_channel = pxa_request_dma("pxa2xx_spi_ssp_rx",
- DMA_PRIO_HIGH,
- dma_handler,
- drv_data);
- if (drv_data->rx_channel < 0) {
- dev_err(dev, "problem (%d) requesting rx channel\n",
- drv_data->rx_channel);
- status = -ENODEV;
- goto out_error_irq_alloc;
+ status = pxa2xx_spi_dma_setup(drv_data);
+ if (status) {
+ dev_warn(dev, "failed to setup DMA, using PIO\n");
+ platform_info->enable_dma = false;
}
- drv_data->tx_channel = pxa_request_dma("pxa2xx_spi_ssp_tx",
- DMA_PRIO_MEDIUM,
- dma_handler,
- drv_data);
- if (drv_data->tx_channel < 0) {
- dev_err(dev, "problem (%d) requesting tx channel\n",
- drv_data->tx_channel);
- status = -ENODEV;
- goto out_error_dma_alloc;
- }
-
- DRCMR(ssp->drcmr_rx) = DRCMR_MAPVLD | drv_data->rx_channel;
- DRCMR(ssp->drcmr_tx) = DRCMR_MAPVLD | drv_data->tx_channel;
}
/* Enable SOC clock */
- clk_enable(ssp->clk);
+ clk_prepare_enable(ssp->clk);
+
+ drv_data->max_clk_rate = clk_get_rate(ssp->clk);
/* Load default SSP configuration */
write_SSCR0(0, drv_data->ioaddr);
@@ -1640,41 +1234,29 @@ static int __devinit pxa2xx_spi_probe(struct platform_device *pdev)
write_SSTO(0, drv_data->ioaddr);
write_SSPSP(0, drv_data->ioaddr);
- /* Initial and start queue */
- status = init_queue(drv_data);
- if (status != 0) {
- dev_err(&pdev->dev, "problem initializing queue\n");
- goto out_error_clock_enabled;
- }
- status = start_queue(drv_data);
- if (status != 0) {
- dev_err(&pdev->dev, "problem starting queue\n");
- goto out_error_clock_enabled;
- }
+ lpss_ssp_setup(drv_data);
+
+ tasklet_init(&drv_data->pump_transfers, pump_transfers,
+ (unsigned long)drv_data);
/* Register with the SPI framework */
platform_set_drvdata(pdev, drv_data);
status = spi_register_master(master);
if (status != 0) {
dev_err(&pdev->dev, "problem registering spi master\n");
- goto out_error_queue_alloc;
+ goto out_error_clock_enabled;
}
- return status;
+ pm_runtime_set_autosuspend_delay(&pdev->dev, 50);
+ pm_runtime_use_autosuspend(&pdev->dev);
+ pm_runtime_set_active(&pdev->dev);
+ pm_runtime_enable(&pdev->dev);
-out_error_queue_alloc:
- destroy_queue(drv_data);
+ return status;
out_error_clock_enabled:
- clk_disable(ssp->clk);
-
-out_error_dma_alloc:
- if (drv_data->tx_channel != -1)
- pxa_free_dma(drv_data->tx_channel);
- if (drv_data->rx_channel != -1)
- pxa_free_dma(drv_data->rx_channel);
-
-out_error_irq_alloc:
+ clk_disable_unprepare(ssp->clk);
+ pxa2xx_spi_dma_release(drv_data);
free_irq(ssp->irq, drv_data);
out_error_master_alloc:
@@ -1687,37 +1269,23 @@ static int pxa2xx_spi_remove(struct platform_device *pdev)
{
struct driver_data *drv_data = platform_get_drvdata(pdev);
struct ssp_device *ssp;
- int status = 0;
if (!drv_data)
return 0;
ssp = drv_data->ssp;
- /* Remove the queue */
- status = destroy_queue(drv_data);
- if (status != 0)
- /* the kernel does not check the return status of this
- * this routine (mod->exit, within the kernel). Therefore
- * nothing is gained by returning from here, the module is
- * going away regardless, and we should not leave any more
- * resources allocated than necessary. We cannot free the
- * message memory in drv_data->queue, but we can release the
- * resources below. I think the kernel should honor -EBUSY
- * returns but... */
- dev_err(&pdev->dev, "pxa2xx_spi_remove: workqueue will not "
- "complete, message memory not freed\n");
+ pm_runtime_get_sync(&pdev->dev);
/* Disable the SSP at the peripheral and SOC level */
write_SSCR0(0, drv_data->ioaddr);
- clk_disable(ssp->clk);
+ clk_disable_unprepare(ssp->clk);
/* Release DMA */
- if (drv_data->master_info->enable_dma) {
- DRCMR(ssp->drcmr_rx) = 0;
- DRCMR(ssp->drcmr_tx) = 0;
- pxa_free_dma(drv_data->tx_channel);
- pxa_free_dma(drv_data->rx_channel);
- }
+ if (drv_data->master_info->enable_dma)
+ pxa2xx_spi_dma_release(drv_data);
+
+ pm_runtime_put_noidle(&pdev->dev);
+ pm_runtime_disable(&pdev->dev);
/* Release IRQ */
free_irq(ssp->irq, drv_data);
@@ -1749,11 +1317,11 @@ static int pxa2xx_spi_suspend(struct device *dev)
struct ssp_device *ssp = drv_data->ssp;
int status = 0;
- status = stop_queue(drv_data);
+ status = spi_master_suspend(drv_data->master);
if (status != 0)
return status;
write_SSCR0(0, drv_data->ioaddr);
- clk_disable(ssp->clk);
+ clk_disable_unprepare(ssp->clk);
return 0;
}
@@ -1764,18 +1332,13 @@ static int pxa2xx_spi_resume(struct device *dev)
struct ssp_device *ssp = drv_data->ssp;
int status = 0;
- if (drv_data->rx_channel != -1)
- DRCMR(drv_data->ssp->drcmr_rx) =
- DRCMR_MAPVLD | drv_data->rx_channel;
- if (drv_data->tx_channel != -1)
- DRCMR(drv_data->ssp->drcmr_tx) =
- DRCMR_MAPVLD | drv_data->tx_channel;
+ pxa2xx_spi_dma_resume(drv_data);
/* Enable the SSP clock */
- clk_enable(ssp->clk);
+ clk_prepare_enable(ssp->clk);
/* Start the queue running */
- status = start_queue(drv_data);
+ status = spi_master_resume(drv_data->master);
if (status != 0) {
dev_err(dev, "problem starting queue (%d)\n", status);
return status;
@@ -1783,20 +1346,38 @@ static int pxa2xx_spi_resume(struct device *dev)
return 0;
}
+#endif
+
+#ifdef CONFIG_PM_RUNTIME
+static int pxa2xx_spi_runtime_suspend(struct device *dev)
+{
+ struct driver_data *drv_data = dev_get_drvdata(dev);
+
+ clk_disable_unprepare(drv_data->ssp->clk);
+ return 0;
+}
+
+static int pxa2xx_spi_runtime_resume(struct device *dev)
+{
+ struct driver_data *drv_data = dev_get_drvdata(dev);
+
+ clk_prepare_enable(drv_data->ssp->clk);
+ return 0;
+}
+#endif
static const struct dev_pm_ops pxa2xx_spi_pm_ops = {
- .suspend = pxa2xx_spi_suspend,
- .resume = pxa2xx_spi_resume,
+ SET_SYSTEM_SLEEP_PM_OPS(pxa2xx_spi_suspend, pxa2xx_spi_resume)
+ SET_RUNTIME_PM_OPS(pxa2xx_spi_runtime_suspend,
+ pxa2xx_spi_runtime_resume, NULL)
};
-#endif
static struct platform_driver driver = {
.driver = {
.name = "pxa2xx-spi",
.owner = THIS_MODULE,
-#ifdef CONFIG_PM
.pm = &pxa2xx_spi_pm_ops,
-#endif
+ .acpi_match_table = ACPI_PTR(pxa2xx_spi_acpi_match),
},
.probe = pxa2xx_spi_probe,
.remove = pxa2xx_spi_remove,
diff --git a/drivers/spi/spi-pxa2xx.h b/drivers/spi/spi-pxa2xx.h
new file mode 100644
index 000000000000..5adc2a11c7bc
--- /dev/null
+++ b/drivers/spi/spi-pxa2xx.h
@@ -0,0 +1,221 @@
+/*
+ * Copyright (C) 2005 Stephen Street / StreetFire Sound Labs
+ * Copyright (C) 2013, Intel Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef SPI_PXA2XX_H
+#define SPI_PXA2XX_H
+
+#include <linux/atomic.h>
+#include <linux/dmaengine.h>
+#include <linux/errno.h>
+#include <linux/io.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/pxa2xx_ssp.h>
+#include <linux/scatterlist.h>
+#include <linux/sizes.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/pxa2xx_spi.h>
+
+struct driver_data {
+ /* Driver model hookup */
+ struct platform_device *pdev;
+
+ /* SSP Info */
+ struct ssp_device *ssp;
+
+ /* SPI framework hookup */
+ enum pxa_ssp_type ssp_type;
+ struct spi_master *master;
+
+ /* PXA hookup */
+ struct pxa2xx_spi_master *master_info;
+
+ /* PXA private DMA setup stuff */
+ int rx_channel;
+ int tx_channel;
+ u32 *null_dma_buf;
+
+ /* SSP register addresses */
+ void __iomem *ioaddr;
+ u32 ssdr_physical;
+
+ /* SSP masks*/
+ u32 dma_cr1;
+ u32 int_cr1;
+ u32 clear_sr;
+ u32 mask_sr;
+
+ /* Maximun clock rate */
+ unsigned long max_clk_rate;
+
+ /* Message Transfer pump */
+ struct tasklet_struct pump_transfers;
+
+ /* DMA engine support */
+ struct dma_chan *rx_chan;
+ struct dma_chan *tx_chan;
+ struct sg_table rx_sgt;
+ struct sg_table tx_sgt;
+ int rx_nents;
+ int tx_nents;
+ void *dummy;
+ atomic_t dma_running;
+
+ /* Current message transfer state info */
+ struct spi_message *cur_msg;
+ struct spi_transfer *cur_transfer;
+ struct chip_data *cur_chip;
+ size_t len;
+ void *tx;
+ void *tx_end;
+ void *rx;
+ void *rx_end;
+ int dma_mapped;
+ dma_addr_t rx_dma;
+ dma_addr_t tx_dma;
+ size_t rx_map_len;
+ size_t tx_map_len;
+ u8 n_bytes;
+ int (*write)(struct driver_data *drv_data);
+ int (*read)(struct driver_data *drv_data);
+ irqreturn_t (*transfer_handler)(struct driver_data *drv_data);
+ void (*cs_control)(u32 command);
+
+ void __iomem *lpss_base;
+};
+
+struct chip_data {
+ u32 cr0;
+ u32 cr1;
+ u32 psp;
+ u32 timeout;
+ u8 n_bytes;
+ u32 dma_burst_size;
+ u32 threshold;
+ u32 dma_threshold;
+ u16 lpss_rx_threshold;
+ u16 lpss_tx_threshold;
+ u8 enable_dma;
+ u8 bits_per_word;
+ u32 speed_hz;
+ union {
+ int gpio_cs;
+ unsigned int frm;
+ };
+ int gpio_cs_inverted;
+ int (*write)(struct driver_data *drv_data);
+ int (*read)(struct driver_data *drv_data);
+ void (*cs_control)(u32 command);
+};
+
+#define DEFINE_SSP_REG(reg, off) \
+static inline u32 read_##reg(void const __iomem *p) \
+{ return __raw_readl(p + (off)); } \
+\
+static inline void write_##reg(u32 v, void __iomem *p) \
+{ __raw_writel(v, p + (off)); }
+
+DEFINE_SSP_REG(SSCR0, 0x00)
+DEFINE_SSP_REG(SSCR1, 0x04)
+DEFINE_SSP_REG(SSSR, 0x08)
+DEFINE_SSP_REG(SSITR, 0x0c)
+DEFINE_SSP_REG(SSDR, 0x10)
+DEFINE_SSP_REG(SSTO, 0x28)
+DEFINE_SSP_REG(SSPSP, 0x2c)
+DEFINE_SSP_REG(SSITF, SSITF)
+DEFINE_SSP_REG(SSIRF, SSIRF)
+
+#define START_STATE ((void *)0)
+#define RUNNING_STATE ((void *)1)
+#define DONE_STATE ((void *)2)
+#define ERROR_STATE ((void *)-1)
+
+#define IS_DMA_ALIGNED(x) IS_ALIGNED((unsigned long)(x), DMA_ALIGNMENT)
+#define DMA_ALIGNMENT 8
+
+static inline int pxa25x_ssp_comp(struct driver_data *drv_data)
+{
+ if (drv_data->ssp_type == PXA25x_SSP)
+ return 1;
+ if (drv_data->ssp_type == CE4100_SSP)
+ return 1;
+ return 0;
+}
+
+static inline void write_SSSR_CS(struct driver_data *drv_data, u32 val)
+{
+ void __iomem *reg = drv_data->ioaddr;
+
+ if (drv_data->ssp_type == CE4100_SSP)
+ val |= read_SSSR(reg) & SSSR_ALT_FRM_MASK;
+
+ write_SSSR(val, reg);
+}
+
+extern int pxa2xx_spi_flush(struct driver_data *drv_data);
+extern void *pxa2xx_spi_next_transfer(struct driver_data *drv_data);
+
+/*
+ * Select the right DMA implementation.
+ */
+#if defined(CONFIG_SPI_PXA2XX_PXADMA)
+#define SPI_PXA2XX_USE_DMA 1
+#define MAX_DMA_LEN 8191
+#define DEFAULT_DMA_CR1 (SSCR1_TSRE | SSCR1_RSRE | SSCR1_TINTE)
+#elif defined(CONFIG_SPI_PXA2XX_DMA)
+#define SPI_PXA2XX_USE_DMA 1
+#define MAX_DMA_LEN SZ_64K
+#define DEFAULT_DMA_CR1 (SSCR1_TSRE | SSCR1_RSRE | SSCR1_TRAIL)
+#else
+#undef SPI_PXA2XX_USE_DMA
+#define MAX_DMA_LEN 0
+#define DEFAULT_DMA_CR1 0
+#endif
+
+#ifdef SPI_PXA2XX_USE_DMA
+extern bool pxa2xx_spi_dma_is_possible(size_t len);
+extern int pxa2xx_spi_map_dma_buffers(struct driver_data *drv_data);
+extern irqreturn_t pxa2xx_spi_dma_transfer(struct driver_data *drv_data);
+extern int pxa2xx_spi_dma_prepare(struct driver_data *drv_data, u32 dma_burst);
+extern void pxa2xx_spi_dma_start(struct driver_data *drv_data);
+extern int pxa2xx_spi_dma_setup(struct driver_data *drv_data);
+extern void pxa2xx_spi_dma_release(struct driver_data *drv_data);
+extern void pxa2xx_spi_dma_resume(struct driver_data *drv_data);
+extern int pxa2xx_spi_set_dma_burst_and_threshold(struct chip_data *chip,
+ struct spi_device *spi,
+ u8 bits_per_word,
+ u32 *burst_code,
+ u32 *threshold);
+#else
+static inline bool pxa2xx_spi_dma_is_possible(size_t len) { return false; }
+static inline int pxa2xx_spi_map_dma_buffers(struct driver_data *drv_data)
+{
+ return 0;
+}
+#define pxa2xx_spi_dma_transfer NULL
+static inline void pxa2xx_spi_dma_prepare(struct driver_data *drv_data,
+ u32 dma_burst) {}
+static inline void pxa2xx_spi_dma_start(struct driver_data *drv_data) {}
+static inline int pxa2xx_spi_dma_setup(struct driver_data *drv_data)
+{
+ return 0;
+}
+static inline void pxa2xx_spi_dma_release(struct driver_data *drv_data) {}
+static inline void pxa2xx_spi_dma_resume(struct driver_data *drv_data) {}
+static inline int pxa2xx_spi_set_dma_burst_and_threshold(struct chip_data *chip,
+ struct spi_device *spi,
+ u8 bits_per_word,
+ u32 *burst_code,
+ u32 *threshold)
+{
+ return -ENODEV;
+}
+#endif
+
+#endif /* SPI_PXA2XX_H */
diff --git a/drivers/spi/spi-rspi.c b/drivers/spi/spi-rspi.c
index 30faf6d4ab91..902f2fb902db 100644
--- a/drivers/spi/spi-rspi.c
+++ b/drivers/spi/spi-rspi.c
@@ -661,7 +661,7 @@ static irqreturn_t rspi_irq(int irq, void *_sr)
return ret;
}
-static int __devinit rspi_request_dma(struct rspi_data *rspi,
+static int rspi_request_dma(struct rspi_data *rspi,
struct platform_device *pdev)
{
struct rspi_plat_data *rspi_pd = pdev->dev.platform_data;
@@ -709,7 +709,7 @@ static int __devinit rspi_request_dma(struct rspi_data *rspi,
return 0;
}
-static void __devexit rspi_release_dma(struct rspi_data *rspi)
+static void rspi_release_dma(struct rspi_data *rspi)
{
if (rspi->chan_tx)
dma_release_channel(rspi->chan_tx);
@@ -717,7 +717,7 @@ static void __devexit rspi_release_dma(struct rspi_data *rspi)
dma_release_channel(rspi->chan_rx);
}
-static int __devexit rspi_remove(struct platform_device *pdev)
+static int rspi_remove(struct platform_device *pdev)
{
struct rspi_data *rspi = dev_get_drvdata(&pdev->dev);
@@ -731,7 +731,7 @@ static int __devexit rspi_remove(struct platform_device *pdev)
return 0;
}
-static int __devinit rspi_probe(struct platform_device *pdev)
+static int rspi_probe(struct platform_device *pdev)
{
struct resource *res;
struct spi_master *master;
@@ -827,7 +827,7 @@ error1:
static struct platform_driver rspi_driver = {
.probe = rspi_probe,
- .remove = __devexit_p(rspi_remove),
+ .remove = rspi_remove,
.driver = {
.name = "rspi",
.owner = THIS_MODULE,
diff --git a/drivers/spi/spi-s3c24xx.c b/drivers/spi/spi-s3c24xx.c
index a2a080b7f42b..02d64603fcc5 100644
--- a/drivers/spi/spi-s3c24xx.c
+++ b/drivers/spi/spi-s3c24xx.c
@@ -506,7 +506,7 @@ static void s3c24xx_spi_initialsetup(struct s3c24xx_spi *hw)
}
}
-static int __devinit s3c24xx_spi_probe(struct platform_device *pdev)
+static int s3c24xx_spi_probe(struct platform_device *pdev)
{
struct s3c2410_spi_info *pdata;
struct s3c24xx_spi *hw;
@@ -663,7 +663,7 @@ static int __devinit s3c24xx_spi_probe(struct platform_device *pdev)
return err;
}
-static int __devexit s3c24xx_spi_remove(struct platform_device *dev)
+static int s3c24xx_spi_remove(struct platform_device *dev)
{
struct s3c24xx_spi *hw = platform_get_drvdata(dev);
@@ -722,7 +722,7 @@ static const struct dev_pm_ops s3c24xx_spi_pmops = {
MODULE_ALIAS("platform:s3c2410-spi");
static struct platform_driver s3c24xx_spi_driver = {
.probe = s3c24xx_spi_probe,
- .remove = __devexit_p(s3c24xx_spi_remove),
+ .remove = s3c24xx_spi_remove,
.driver = {
.name = "s3c2410-spi",
.owner = THIS_MODULE,
diff --git a/drivers/spi/spi-s3c64xx.c b/drivers/spi/spi-s3c64xx.c
index 6e7a805d324d..e862ab8853aa 100644
--- a/drivers/spi/spi-s3c64xx.c
+++ b/drivers/spi/spi-s3c64xx.c
@@ -62,7 +62,7 @@
#define S3C64XX_SPI_CLKSEL_SRCMSK (3<<9)
#define S3C64XX_SPI_CLKSEL_SRCSHFT 9
#define S3C64XX_SPI_ENCLK_ENABLE (1<<8)
-#define S3C64XX_SPI_PSR_MASK 0xff
+#define S3C64XX_SPI_PSR_MASK 0xff
#define S3C64XX_SPI_MODE_CH_TSZ_BYTE (0<<29)
#define S3C64XX_SPI_MODE_CH_TSZ_HALFWORD (1<<29)
@@ -134,7 +134,6 @@ struct s3c64xx_spi_dma_data {
unsigned ch;
enum dma_transfer_direction direction;
enum dma_ch dmach;
- struct property *dma_prop;
};
/**
@@ -215,6 +214,10 @@ static void flush_fifo(struct s3c64xx_spi_driver_data *sdd)
writel(0, regs + S3C64XX_SPI_PACKET_CNT);
val = readl(regs + S3C64XX_SPI_CH_CFG);
+ val &= ~(S3C64XX_SPI_CH_RXCH_ON | S3C64XX_SPI_CH_TXCH_ON);
+ writel(val, regs + S3C64XX_SPI_CH_CFG);
+
+ val = readl(regs + S3C64XX_SPI_CH_CFG);
val |= S3C64XX_SPI_CH_SW_RST;
val &= ~S3C64XX_SPI_CH_HS_EN;
writel(val, regs + S3C64XX_SPI_CH_CFG);
@@ -248,10 +251,6 @@ static void flush_fifo(struct s3c64xx_spi_driver_data *sdd)
val = readl(regs + S3C64XX_SPI_MODE_CFG);
val &= ~(S3C64XX_SPI_MODE_TXDMA_ON | S3C64XX_SPI_MODE_RXDMA_ON);
writel(val, regs + S3C64XX_SPI_MODE_CFG);
-
- val = readl(regs + S3C64XX_SPI_CH_CFG);
- val &= ~(S3C64XX_SPI_CH_RXCH_ON | S3C64XX_SPI_CH_TXCH_ON);
- writel(val, regs + S3C64XX_SPI_CH_CFG);
}
static void s3c64xx_spi_dmacb(void *data)
@@ -319,16 +318,15 @@ static void prepare_dma(struct s3c64xx_spi_dma_data *dma,
static int acquire_dma(struct s3c64xx_spi_driver_data *sdd)
{
struct samsung_dma_req req;
+ struct device *dev = &sdd->pdev->dev;
sdd->ops = samsung_dma_get_ops();
req.cap = DMA_SLAVE;
req.client = &s3c64xx_spi_dma_client;
- req.dt_dmach_prop = sdd->rx_dma.dma_prop;
- sdd->rx_dma.ch = sdd->ops->request(sdd->rx_dma.dmach, &req);
- req.dt_dmach_prop = sdd->tx_dma.dma_prop;
- sdd->tx_dma.ch = sdd->ops->request(sdd->tx_dma.dmach, &req);
+ sdd->rx_dma.ch = sdd->ops->request(sdd->rx_dma.dmach, &req, dev, "rx");
+ sdd->tx_dma.ch = sdd->ops->request(sdd->tx_dma.dmach, &req, dev, "tx");
return 1;
}
@@ -516,7 +514,7 @@ static void s3c64xx_spi_config(struct s3c64xx_spi_driver_data *sdd)
/* Disable Clock */
if (sdd->port_conf->clk_from_cmu) {
- clk_disable(sdd->src_clk);
+ clk_disable_unprepare(sdd->src_clk);
} else {
val = readl(regs + S3C64XX_SPI_CLK_CFG);
val &= ~S3C64XX_SPI_ENCLK_ENABLE;
@@ -564,7 +562,7 @@ static void s3c64xx_spi_config(struct s3c64xx_spi_driver_data *sdd)
/* There is half-multiplier before the SPI */
clk_set_rate(sdd->src_clk, sdd->cur_speed * 2);
/* Enable Clock */
- clk_enable(sdd->src_clk);
+ clk_prepare_enable(sdd->src_clk);
} else {
/* Configure Clock */
val = readl(regs + S3C64XX_SPI_CLK_CFG);
@@ -697,7 +695,7 @@ static int s3c64xx_spi_transfer_one_message(struct spi_master *master,
INIT_COMPLETION(sdd->xfer_completion);
/* Only BPW and Speed may change across transfers */
- bpw = xfer->bits_per_word ? : spi->bits_per_word;
+ bpw = xfer->bits_per_word;
speed = xfer->speed_hz ? : spi->max_speed_hz;
if (xfer->len % (bpw / 8)) {
@@ -743,8 +741,7 @@ static int s3c64xx_spi_transfer_one_message(struct spi_master *master,
sdd->regs + S3C64XX_SPI_SLAVE_SEL);
if (status) {
- dev_err(&spi->dev, "I/O Error: "
- "rx-%d tx-%d res:rx-%c tx-%c len-%d\n",
+ dev_err(&spi->dev, "I/O Error: rx-%d tx-%d res:rx-%c tx-%c len-%d\n",
xfer->rx_buf ? 1 : 0, xfer->tx_buf ? 1 : 0,
(sdd->state & RXBUSY) ? 'f' : 'p',
(sdd->state & TXBUSY) ? 'f' : 'p',
@@ -771,8 +768,6 @@ static int s3c64xx_spi_transfer_one_message(struct spi_master *master,
if (list_is_last(&xfer->transfer_list,
&msg->transfers))
cs_toggle = 1;
- else
- disable_cs(sdd, spi);
}
msg->actual_length += xfer->len;
@@ -801,7 +796,7 @@ static int s3c64xx_spi_prepare_transfer(struct spi_master *spi)
/* Acquire DMA channels */
while (!acquire_dma(sdd))
- msleep(10);
+ usleep_range(10000, 11000);
pm_runtime_get_sync(&sdd->pdev->dev);
@@ -843,16 +838,14 @@ static struct s3c64xx_spi_csinfo *s3c64xx_get_slave_ctrldata(
cs = kzalloc(sizeof(*cs), GFP_KERNEL);
if (!cs) {
- dev_err(&spi->dev, "could not allocate memory for controller"
- " data\n");
+ dev_err(&spi->dev, "could not allocate memory for controller data\n");
of_node_put(data_np);
return ERR_PTR(-ENOMEM);
}
cs->line = of_get_named_gpio(data_np, "cs-gpio", 0);
if (!gpio_is_valid(cs->line)) {
- dev_err(&spi->dev, "chip select gpio is not specified or "
- "invalid\n");
+ dev_err(&spi->dev, "chip select gpio is not specified or invalid\n");
kfree(cs);
of_node_put(data_np);
return ERR_PTR(-EINVAL);
@@ -959,6 +952,8 @@ static int s3c64xx_spi_setup(struct spi_device *spi)
if (spi->max_speed_hz >= speed) {
spi->max_speed_hz = speed;
} else {
+ dev_err(&spi->dev, "Can't set %dHz transfer speed\n",
+ spi->max_speed_hz);
err = -EINVAL;
goto setup_exit;
}
@@ -1056,49 +1051,6 @@ static void s3c64xx_spi_hwinit(struct s3c64xx_spi_driver_data *sdd, int channel)
flush_fifo(sdd);
}
-static int __devinit s3c64xx_spi_get_dmares(
- struct s3c64xx_spi_driver_data *sdd, bool tx)
-{
- struct platform_device *pdev = sdd->pdev;
- struct s3c64xx_spi_dma_data *dma_data;
- struct property *prop;
- struct resource *res;
- char prop_name[15], *chan_str;
-
- if (tx) {
- dma_data = &sdd->tx_dma;
- dma_data->direction = DMA_MEM_TO_DEV;
- chan_str = "tx";
- } else {
- dma_data = &sdd->rx_dma;
- dma_data->direction = DMA_DEV_TO_MEM;
- chan_str = "rx";
- }
-
- if (!sdd->pdev->dev.of_node) {
- res = platform_get_resource(pdev, IORESOURCE_DMA, tx ? 0 : 1);
- if (!res) {
- dev_err(&pdev->dev, "Unable to get SPI-%s dma "
- "resource\n", chan_str);
- return -ENXIO;
- }
- dma_data->dmach = res->start;
- return 0;
- }
-
- sprintf(prop_name, "%s-dma-channel", chan_str);
- prop = of_find_property(pdev->dev.of_node, prop_name, NULL);
- if (!prop) {
- dev_err(&pdev->dev, "%s dma channel property not specified\n",
- chan_str);
- return -ENXIO;
- }
-
- dma_data->dmach = DMACH_DT_PROP;
- dma_data->dma_prop = prop;
- return 0;
-}
-
#ifdef CONFIG_OF
static int s3c64xx_spi_parse_dt_gpio(struct s3c64xx_spi_driver_data *sdd)
{
@@ -1112,7 +1064,7 @@ static int s3c64xx_spi_parse_dt_gpio(struct s3c64xx_spi_driver_data *sdd)
dev_err(dev, "invalid gpio[%d]: %d\n", idx, gpio);
goto free_gpio;
}
-
+ sdd->gpios[idx] = gpio;
ret = gpio_request(gpio, "spi-bus");
if (ret) {
dev_err(dev, "gpio [%d] request failed: %d\n",
@@ -1135,8 +1087,7 @@ static void s3c64xx_spi_dt_gpio_free(struct s3c64xx_spi_driver_data *sdd)
gpio_free(sdd->gpios[idx]);
}
-static struct __devinit s3c64xx_spi_info * s3c64xx_spi_parse_dt(
- struct device *dev)
+static struct s3c64xx_spi_info *s3c64xx_spi_parse_dt(struct device *dev)
{
struct s3c64xx_spi_info *sci;
u32 temp;
@@ -1148,16 +1099,14 @@ static struct __devinit s3c64xx_spi_info * s3c64xx_spi_parse_dt(
}
if (of_property_read_u32(dev->of_node, "samsung,spi-src-clk", &temp)) {
- dev_warn(dev, "spi bus clock parent not specified, using "
- "clock at index 0 as parent\n");
+ dev_warn(dev, "spi bus clock parent not specified, using clock at index 0 as parent\n");
sci->src_clk_nr = 0;
} else {
sci->src_clk_nr = temp;
}
if (of_property_read_u32(dev->of_node, "num-cs", &temp)) {
- dev_warn(dev, "number of chip select lines not specified, "
- "assuming 1 chip select line\n");
+ dev_warn(dev, "number of chip select lines not specified, assuming 1 chip select line\n");
sci->num_cs = 1;
} else {
sci->num_cs = temp;
@@ -1197,9 +1146,10 @@ static inline struct s3c64xx_spi_port_config *s3c64xx_spi_get_port_config(
platform_get_device_id(pdev)->driver_data;
}
-static int __init s3c64xx_spi_probe(struct platform_device *pdev)
+static int s3c64xx_spi_probe(struct platform_device *pdev)
{
struct resource *mem_res;
+ struct resource *res;
struct s3c64xx_spi_driver_data *sdd;
struct s3c64xx_spi_info *sci = pdev->dev.platform_data;
struct spi_master *master;
@@ -1247,8 +1197,8 @@ static int __init s3c64xx_spi_probe(struct platform_device *pdev)
if (pdev->dev.of_node) {
ret = of_alias_get_id(pdev->dev.of_node, "spi");
if (ret < 0) {
- dev_err(&pdev->dev, "failed to get alias id, "
- "errno %d\n", ret);
+ dev_err(&pdev->dev, "failed to get alias id, errno %d\n",
+ ret);
goto err0;
}
sdd->port_id = ret;
@@ -1258,13 +1208,26 @@ static int __init s3c64xx_spi_probe(struct platform_device *pdev)
sdd->cur_bpw = 8;
- ret = s3c64xx_spi_get_dmares(sdd, true);
- if (ret)
- goto err0;
+ if (!sdd->pdev->dev.of_node) {
+ res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
+ if (!res) {
+ dev_err(&pdev->dev, "Unable to get SPI tx dma "
+ "resource\n");
+ return -ENXIO;
+ }
+ sdd->tx_dma.dmach = res->start;
- ret = s3c64xx_spi_get_dmares(sdd, false);
- if (ret)
- goto err0;
+ res = platform_get_resource(pdev, IORESOURCE_DMA, 1);
+ if (!res) {
+ dev_err(&pdev->dev, "Unable to get SPI rx dma "
+ "resource\n");
+ return -ENXIO;
+ }
+ sdd->rx_dma.dmach = res->start;
+ }
+
+ sdd->tx_dma.direction = DMA_MEM_TO_DEV;
+ sdd->rx_dma.direction = DMA_DEV_TO_MEM;
master->dev.of_node = pdev->dev.of_node;
master->bus_num = sdd->port_id;
@@ -1278,11 +1241,10 @@ static int __init s3c64xx_spi_probe(struct platform_device *pdev)
/* the spi->mode bits understood by this driver: */
master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
- sdd->regs = devm_request_and_ioremap(&pdev->dev, mem_res);
- if (sdd->regs == NULL) {
- dev_err(&pdev->dev, "Unable to remap IO\n");
- ret = -ENXIO;
- goto err1;
+ sdd->regs = devm_ioremap_resource(&pdev->dev, mem_res);
+ if (IS_ERR(sdd->regs)) {
+ ret = PTR_ERR(sdd->regs);
+ goto err0;
}
if (!sci->cfg_gpio && pdev->dev.of_node) {
@@ -1291,36 +1253,36 @@ static int __init s3c64xx_spi_probe(struct platform_device *pdev)
} else if (sci->cfg_gpio == NULL || sci->cfg_gpio()) {
dev_err(&pdev->dev, "Unable to config gpio\n");
ret = -EBUSY;
- goto err2;
+ goto err0;
}
/* Setup clocks */
- sdd->clk = clk_get(&pdev->dev, "spi");
+ sdd->clk = devm_clk_get(&pdev->dev, "spi");
if (IS_ERR(sdd->clk)) {
dev_err(&pdev->dev, "Unable to acquire clock 'spi'\n");
ret = PTR_ERR(sdd->clk);
- goto err3;
+ goto err1;
}
- if (clk_enable(sdd->clk)) {
+ if (clk_prepare_enable(sdd->clk)) {
dev_err(&pdev->dev, "Couldn't enable clock 'spi'\n");
ret = -EBUSY;
- goto err4;
+ goto err1;
}
sprintf(clk_name, "spi_busclk%d", sci->src_clk_nr);
- sdd->src_clk = clk_get(&pdev->dev, clk_name);
+ sdd->src_clk = devm_clk_get(&pdev->dev, clk_name);
if (IS_ERR(sdd->src_clk)) {
dev_err(&pdev->dev,
"Unable to acquire clock '%s'\n", clk_name);
ret = PTR_ERR(sdd->src_clk);
- goto err5;
+ goto err2;
}
- if (clk_enable(sdd->src_clk)) {
+ if (clk_prepare_enable(sdd->src_clk)) {
dev_err(&pdev->dev, "Couldn't enable clock '%s'\n", clk_name);
ret = -EBUSY;
- goto err6;
+ goto err2;
}
/* Setup Deufult Mode */
@@ -1330,11 +1292,12 @@ static int __init s3c64xx_spi_probe(struct platform_device *pdev)
init_completion(&sdd->xfer_completion);
INIT_LIST_HEAD(&sdd->queue);
- ret = request_irq(irq, s3c64xx_spi_irq, 0, "spi-s3c64xx", sdd);
+ ret = devm_request_irq(&pdev->dev, irq, s3c64xx_spi_irq, 0,
+ "spi-s3c64xx", sdd);
if (ret != 0) {
dev_err(&pdev->dev, "Failed to request IRQ %d: %d\n",
irq, ret);
- goto err7;
+ goto err3;
}
writel(S3C64XX_SPI_INT_RX_OVERRUN_EN | S3C64XX_SPI_INT_RX_UNDERRUN_EN |
@@ -1344,11 +1307,10 @@ static int __init s3c64xx_spi_probe(struct platform_device *pdev)
if (spi_register_master(master)) {
dev_err(&pdev->dev, "cannot register SPI master\n");
ret = -EBUSY;
- goto err8;
+ goto err3;
}
- dev_dbg(&pdev->dev, "Samsung SoC SPI Driver loaded for Bus SPI-%d "
- "with %d Slaves attached\n",
+ dev_dbg(&pdev->dev, "Samsung SoC SPI Driver loaded for Bus SPI-%d with %d Slaves attached\n",
sdd->port_id, master->num_chipselect);
dev_dbg(&pdev->dev, "\tIOmem=[0x%x-0x%x]\tDMA=[Rx-%d, Tx-%d]\n",
mem_res->end, mem_res->start,
@@ -1358,21 +1320,13 @@ static int __init s3c64xx_spi_probe(struct platform_device *pdev)
return 0;
-err8:
- free_irq(irq, sdd);
-err7:
- clk_disable(sdd->src_clk);
-err6:
- clk_put(sdd->src_clk);
-err5:
- clk_disable(sdd->clk);
-err4:
- clk_put(sdd->clk);
err3:
- if (!sdd->cntrlr_info->cfg_gpio && pdev->dev.of_node)
- s3c64xx_spi_dt_gpio_free(sdd);
+ clk_disable_unprepare(sdd->src_clk);
err2:
+ clk_disable_unprepare(sdd->clk);
err1:
+ if (!sdd->cntrlr_info->cfg_gpio && pdev->dev.of_node)
+ s3c64xx_spi_dt_gpio_free(sdd);
err0:
platform_set_drvdata(pdev, NULL);
spi_master_put(master);
@@ -1391,13 +1345,9 @@ static int s3c64xx_spi_remove(struct platform_device *pdev)
writel(0, sdd->regs + S3C64XX_SPI_INT_EN);
- free_irq(platform_get_irq(pdev, 0), sdd);
-
- clk_disable(sdd->src_clk);
- clk_put(sdd->src_clk);
+ clk_disable_unprepare(sdd->src_clk);
- clk_disable(sdd->clk);
- clk_put(sdd->clk);
+ clk_disable_unprepare(sdd->clk);
if (!sdd->cntrlr_info->cfg_gpio && pdev->dev.of_node)
s3c64xx_spi_dt_gpio_free(sdd);
@@ -1417,8 +1367,8 @@ static int s3c64xx_spi_suspend(struct device *dev)
spi_master_suspend(master);
/* Disable the clock */
- clk_disable(sdd->src_clk);
- clk_disable(sdd->clk);
+ clk_disable_unprepare(sdd->src_clk);
+ clk_disable_unprepare(sdd->clk);
if (!sdd->cntrlr_info->cfg_gpio && dev->of_node)
s3c64xx_spi_dt_gpio_free(sdd);
@@ -1440,8 +1390,8 @@ static int s3c64xx_spi_resume(struct device *dev)
sci->cfg_gpio();
/* Enable the clock */
- clk_enable(sdd->src_clk);
- clk_enable(sdd->clk);
+ clk_prepare_enable(sdd->src_clk);
+ clk_prepare_enable(sdd->clk);
s3c64xx_spi_hwinit(sdd, sdd->port_id);
@@ -1457,8 +1407,8 @@ static int s3c64xx_spi_runtime_suspend(struct device *dev)
struct spi_master *master = dev_get_drvdata(dev);
struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(master);
- clk_disable(sdd->clk);
- clk_disable(sdd->src_clk);
+ clk_disable_unprepare(sdd->clk);
+ clk_disable_unprepare(sdd->src_clk);
return 0;
}
@@ -1468,8 +1418,8 @@ static int s3c64xx_spi_runtime_resume(struct device *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);
- clk_enable(sdd->clk);
+ clk_prepare_enable(sdd->src_clk);
+ clk_prepare_enable(sdd->clk);
return 0;
}
diff --git a/drivers/spi/spi-sh-hspi.c b/drivers/spi/spi-sh-hspi.c
index 796c077ef439..60cfae51c713 100644
--- a/drivers/spi/spi-sh-hspi.c
+++ b/drivers/spi/spi-sh-hspi.c
@@ -68,6 +68,16 @@ static u32 hspi_read(struct hspi_priv *hspi, int reg)
return ioread32(hspi->addr + reg);
}
+static void hspi_bit_set(struct hspi_priv *hspi, int reg, u32 mask, u32 set)
+{
+ u32 val = hspi_read(hspi, reg);
+
+ val &= ~mask;
+ val |= set & mask;
+
+ hspi_write(hspi, reg, val);
+}
+
/*
* transfer function
*/
@@ -105,6 +115,13 @@ static int hspi_unprepare_transfer(struct spi_master *master)
return 0;
}
+#define hspi_hw_cs_enable(hspi) hspi_hw_cs_ctrl(hspi, 0)
+#define hspi_hw_cs_disable(hspi) hspi_hw_cs_ctrl(hspi, 1)
+static void hspi_hw_cs_ctrl(struct hspi_priv *hspi, int hi)
+{
+ hspi_bit_set(hspi, SPSCR, (1 << 6), (hi) << 6);
+}
+
static void hspi_hw_setup(struct hspi_priv *hspi,
struct spi_message *msg,
struct spi_transfer *t)
@@ -155,7 +172,7 @@ static void hspi_hw_setup(struct hspi_priv *hspi,
hspi_write(hspi, SPCR, spcr);
hspi_write(hspi, SPSR, 0x0);
- hspi_write(hspi, SPSCR, 0x1); /* master mode */
+ hspi_write(hspi, SPSCR, 0x21); /* master mode / CS control */
}
static int hspi_transfer_one_message(struct spi_master *master,
@@ -166,12 +183,21 @@ static int hspi_transfer_one_message(struct spi_master *master,
u32 tx;
u32 rx;
int ret, i;
+ unsigned int cs_change;
+ const int nsecs = 50;
dev_dbg(hspi->dev, "%s\n", __func__);
+ cs_change = 1;
ret = 0;
list_for_each_entry(t, &msg->transfers, transfer_list) {
- hspi_hw_setup(hspi, msg, t);
+
+ if (cs_change) {
+ hspi_hw_setup(hspi, msg, t);
+ hspi_hw_cs_enable(hspi);
+ ndelay(nsecs);
+ }
+ cs_change = t->cs_change;
for (i = 0; i < t->len; i++) {
@@ -198,9 +224,22 @@ static int hspi_transfer_one_message(struct spi_master *master,
}
msg->actual_length += t->len;
+
+ if (t->delay_usecs)
+ udelay(t->delay_usecs);
+
+ if (cs_change) {
+ ndelay(nsecs);
+ hspi_hw_cs_disable(hspi);
+ ndelay(nsecs);
+ }
}
msg->status = ret;
+ if (!cs_change) {
+ ndelay(nsecs);
+ hspi_hw_cs_disable(hspi);
+ }
spi_finalize_current_message(master);
return ret;
@@ -229,7 +268,7 @@ static void hspi_cleanup(struct spi_device *spi)
dev_dbg(dev, "%s cleanup\n", spi->modalias);
}
-static int __devinit hspi_probe(struct platform_device *pdev)
+static int hspi_probe(struct platform_device *pdev)
{
struct resource *res;
struct spi_master *master;
@@ -251,7 +290,7 @@ static int __devinit hspi_probe(struct platform_device *pdev)
}
clk = clk_get(NULL, "shyway_clk");
- if (!clk) {
+ if (IS_ERR(clk)) {
dev_err(&pdev->dev, "shyway_clk is required\n");
ret = -EINVAL;
goto error0;
@@ -300,7 +339,7 @@ static int __devinit hspi_probe(struct platform_device *pdev)
return ret;
}
-static int __devexit hspi_remove(struct platform_device *pdev)
+static int hspi_remove(struct platform_device *pdev)
{
struct hspi_priv *hspi = dev_get_drvdata(&pdev->dev);
@@ -314,7 +353,7 @@ static int __devexit hspi_remove(struct platform_device *pdev)
static struct platform_driver hspi_driver = {
.probe = hspi_probe,
- .remove = __devexit_p(hspi_remove),
+ .remove = hspi_remove,
.driver = {
.name = "sh-hspi",
.owner = THIS_MODULE,
diff --git a/drivers/spi/spi-sh-msiof.c b/drivers/spi/spi-sh-msiof.c
index 1f466bc66d9d..8b40d0884f8b 100644
--- a/drivers/spi/spi-sh-msiof.c
+++ b/drivers/spi/spi-sh-msiof.c
@@ -20,6 +20,7 @@
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/module.h>
+#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
@@ -592,12 +593,42 @@ static u32 sh_msiof_spi_txrx_word(struct spi_device *spi, unsigned nsecs,
return 0;
}
+#ifdef CONFIG_OF
+static struct sh_msiof_spi_info *sh_msiof_spi_parse_dt(struct device *dev)
+{
+ struct sh_msiof_spi_info *info;
+ struct device_node *np = dev->of_node;
+ u32 num_cs = 0;
+
+ info = devm_kzalloc(dev, sizeof(struct sh_msiof_spi_info), GFP_KERNEL);
+ if (!info) {
+ dev_err(dev, "failed to allocate setup data\n");
+ return NULL;
+ }
+
+ /* Parse the MSIOF properties */
+ of_property_read_u32(np, "num-cs", &num_cs);
+ of_property_read_u32(np, "renesas,tx-fifo-size",
+ &info->tx_fifo_override);
+ of_property_read_u32(np, "renesas,rx-fifo-size",
+ &info->rx_fifo_override);
+
+ info->num_chipselect = num_cs;
+
+ return info;
+}
+#else
+static struct sh_msiof_spi_info *sh_msiof_spi_parse_dt(struct device *dev)
+{
+ return NULL;
+}
+#endif
+
static int sh_msiof_spi_probe(struct platform_device *pdev)
{
struct resource *r;
struct spi_master *master;
struct sh_msiof_spi_priv *p;
- char clk_name[16];
int i;
int ret;
@@ -611,13 +642,22 @@ static int sh_msiof_spi_probe(struct platform_device *pdev)
p = spi_master_get_devdata(master);
platform_set_drvdata(pdev, p);
- p->info = pdev->dev.platform_data;
+ if (pdev->dev.of_node)
+ p->info = sh_msiof_spi_parse_dt(&pdev->dev);
+ else
+ p->info = pdev->dev.platform_data;
+
+ if (!p->info) {
+ dev_err(&pdev->dev, "failed to obtain device info\n");
+ ret = -ENXIO;
+ goto err1;
+ }
+
init_completion(&p->done);
- snprintf(clk_name, sizeof(clk_name), "msiof%d", pdev->id);
- p->clk = clk_get(&pdev->dev, clk_name);
+ p->clk = clk_get(&pdev->dev, NULL);
if (IS_ERR(p->clk)) {
- dev_err(&pdev->dev, "cannot get clock \"%s\"\n", clk_name);
+ dev_err(&pdev->dev, "cannot get clock\n");
ret = PTR_ERR(p->clk);
goto err1;
}
@@ -717,6 +757,17 @@ static int sh_msiof_spi_runtime_nop(struct device *dev)
return 0;
}
+#ifdef CONFIG_OF
+static const struct of_device_id sh_msiof_match[] = {
+ { .compatible = "renesas,sh-msiof", },
+ { .compatible = "renesas,sh-mobile-msiof", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, sh_msiof_match);
+#else
+#define sh_msiof_match NULL
+#endif
+
static struct dev_pm_ops sh_msiof_spi_dev_pm_ops = {
.runtime_suspend = sh_msiof_spi_runtime_nop,
.runtime_resume = sh_msiof_spi_runtime_nop,
@@ -729,6 +780,7 @@ static struct platform_driver sh_msiof_spi_drv = {
.name = "spi_sh_msiof",
.owner = THIS_MODULE,
.pm = &sh_msiof_spi_dev_pm_ops,
+ .of_match_table = sh_msiof_match,
},
};
module_platform_driver(sh_msiof_spi_drv);
diff --git a/drivers/spi/spi-sh.c b/drivers/spi/spi-sh.c
index 79442c31bcd9..3c3600a994bd 100644
--- a/drivers/spi/spi-sh.c
+++ b/drivers/spi/spi-sh.c
@@ -432,7 +432,7 @@ static irqreturn_t spi_sh_irq(int irq, void *_ss)
return IRQ_HANDLED;
}
-static int __devexit spi_sh_remove(struct platform_device *pdev)
+static int spi_sh_remove(struct platform_device *pdev)
{
struct spi_sh_data *ss = dev_get_drvdata(&pdev->dev);
@@ -444,7 +444,7 @@ static int __devexit spi_sh_remove(struct platform_device *pdev)
return 0;
}
-static int __devinit spi_sh_probe(struct platform_device *pdev)
+static int spi_sh_probe(struct platform_device *pdev)
{
struct resource *res;
struct spi_master *master;
@@ -539,7 +539,7 @@ static int __devinit spi_sh_probe(struct platform_device *pdev)
static struct platform_driver spi_sh_driver = {
.probe = spi_sh_probe,
- .remove = __devexit_p(spi_sh_remove),
+ .remove = spi_sh_remove,
.driver = {
.name = "sh_spi",
.owner = THIS_MODULE,
diff --git a/drivers/spi/spi-sirf.c b/drivers/spi/spi-sirf.c
index ecc3d9763d10..f59d4177b419 100644
--- a/drivers/spi/spi-sirf.c
+++ b/drivers/spi/spi-sirf.c
@@ -382,8 +382,7 @@ spi_sirfsoc_setup_transfer(struct spi_device *spi, struct spi_transfer *t)
sspi = spi_master_get_devdata(spi->master);
- bits_per_word = t && t->bits_per_word ? t->bits_per_word :
- spi->bits_per_word;
+ bits_per_word = (t) ? t->bits_per_word : spi->bits_per_word;
hz = t && t->speed_hz ? t->speed_hz : spi->max_speed_hz;
/* Enable IO mode for RX, TX */
@@ -479,7 +478,7 @@ static int spi_sirfsoc_setup(struct spi_device *spi)
return spi_sirfsoc_setup_transfer(spi, NULL);
}
-static int __devinit spi_sirfsoc_probe(struct platform_device *pdev)
+static int spi_sirfsoc_probe(struct platform_device *pdev)
{
struct sirfsoc_spi *sspi;
struct spi_master *master;
@@ -535,10 +534,9 @@ static int __devinit spi_sirfsoc_probe(struct platform_device *pdev)
}
}
- sspi->base = devm_request_and_ioremap(&pdev->dev, mem_res);
- if (!sspi->base) {
- dev_err(&pdev->dev, "IO remap failed!\n");
- ret = -ENOMEM;
+ sspi->base = devm_ioremap_resource(&pdev->dev, mem_res);
+ if (IS_ERR(sspi->base)) {
+ ret = PTR_ERR(sspi->base);
goto free_master;
}
@@ -570,7 +568,7 @@ static int __devinit spi_sirfsoc_probe(struct platform_device *pdev)
ret = -EINVAL;
goto free_pin;
}
- clk_enable(sspi->clk);
+ clk_prepare_enable(sspi->clk);
sspi->ctrl_freq = clk_get_rate(sspi->clk);
init_completion(&sspi->done);
@@ -594,7 +592,7 @@ static int __devinit spi_sirfsoc_probe(struct platform_device *pdev)
return 0;
free_clk:
- clk_disable(sspi->clk);
+ clk_disable_unprepare(sspi->clk);
clk_put(sspi->clk);
free_pin:
pinctrl_put(sspi->p);
@@ -604,7 +602,7 @@ err_cs:
return ret;
}
-static int __devexit spi_sirfsoc_remove(struct platform_device *pdev)
+static int spi_sirfsoc_remove(struct platform_device *pdev)
{
struct spi_master *master;
struct sirfsoc_spi *sspi;
@@ -618,7 +616,7 @@ static int __devexit spi_sirfsoc_remove(struct platform_device *pdev)
if (sspi->chipselect[i] > 0)
gpio_free(sspi->chipselect[i]);
}
- clk_disable(sspi->clk);
+ clk_disable_unprepare(sspi->clk);
clk_put(sspi->clk);
pinctrl_put(sspi->p);
spi_master_put(master);
@@ -659,6 +657,7 @@ static const struct dev_pm_ops spi_sirfsoc_pm_ops = {
static const struct of_device_id spi_sirfsoc_of_match[] = {
{ .compatible = "sirf,prima2-spi", },
+ { .compatible = "sirf,marco-spi", },
{}
};
MODULE_DEVICE_TABLE(of, sirfsoc_spi_of_match);
@@ -673,7 +672,7 @@ static struct platform_driver spi_sirfsoc_driver = {
.of_match_table = spi_sirfsoc_of_match,
},
.probe = spi_sirfsoc_probe,
- .remove = __devexit_p(spi_sirfsoc_remove),
+ .remove = spi_sirfsoc_remove,
};
module_platform_driver(spi_sirfsoc_driver);
diff --git a/drivers/spi/spi-stmp.c b/drivers/spi/spi-stmp.c
deleted file mode 100644
index 911e904b3c84..000000000000
--- a/drivers/spi/spi-stmp.c
+++ /dev/null
@@ -1,664 +0,0 @@
-/*
- * Freescale STMP378X SPI master driver
- *
- * Author: dmitry pervushin <dimka@embeddedalley.com>
- *
- * Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved.
- * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
- */
-
-/*
- * The code contained herein is licensed under the GNU General Public
- * License. You may obtain a copy of the GNU General Public License
- * Version 2 or later at the following locations:
- *
- * http://www.opensource.org/licenses/gpl-license.html
- * http://www.gnu.org/copyleft/gpl.html
- */
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/platform_device.h>
-#include <linux/spi/spi.h>
-#include <linux/err.h>
-#include <linux/clk.h>
-#include <linux/io.h>
-#include <linux/dma-mapping.h>
-#include <linux/delay.h>
-
-#include <mach/platform.h>
-#include <mach/stmp3xxx.h>
-#include <mach/dma.h>
-#include <mach/regs-ssp.h>
-#include <mach/regs-apbh.h>
-
-
-/* 0 means DMA mode(recommended, default), !0 - PIO mode */
-static int pio;
-static int clock;
-
-/* default timeout for busy waits is 2 seconds */
-#define STMP_SPI_TIMEOUT (2 * HZ)
-
-struct stmp_spi {
- int id;
-
- void * __iomem regs; /* vaddr of the control registers */
-
- int irq, err_irq;
- u32 dma;
- struct stmp3xxx_dma_descriptor d;
-
- u32 speed_khz;
- u32 saved_timings;
- u32 divider;
-
- struct clk *clk;
- struct device *master_dev;
-
- struct work_struct work;
- struct workqueue_struct *workqueue;
-
- /* lock protects queue access */
- spinlock_t lock;
- struct list_head queue;
-
- struct completion done;
-};
-
-#define busy_wait(cond) \
- ({ \
- unsigned long end_jiffies = jiffies + STMP_SPI_TIMEOUT; \
- bool succeeded = false; \
- do { \
- if (cond) { \
- succeeded = true; \
- break; \
- } \
- cpu_relax(); \
- } while (time_before(jiffies, end_jiffies)); \
- succeeded; \
- })
-
-/**
- * stmp_spi_init_hw
- * Initialize the SSP port
- */
-static int stmp_spi_init_hw(struct stmp_spi *ss)
-{
- int err = 0;
- void *pins = ss->master_dev->platform_data;
-
- err = stmp3xxx_request_pin_group(pins, dev_name(ss->master_dev));
- if (err)
- goto out;
-
- ss->clk = clk_get(NULL, "ssp");
- if (IS_ERR(ss->clk)) {
- err = PTR_ERR(ss->clk);
- goto out_free_pins;
- }
- clk_enable(ss->clk);
-
- stmp3xxx_reset_block(ss->regs, false);
- stmp3xxx_dma_reset_channel(ss->dma);
-
- return 0;
-
-out_free_pins:
- stmp3xxx_release_pin_group(pins, dev_name(ss->master_dev));
-out:
- return err;
-}
-
-static void stmp_spi_release_hw(struct stmp_spi *ss)
-{
- void *pins = ss->master_dev->platform_data;
-
- if (ss->clk && !IS_ERR(ss->clk)) {
- clk_disable(ss->clk);
- clk_put(ss->clk);
- }
- stmp3xxx_release_pin_group(pins, dev_name(ss->master_dev));
-}
-
-static int stmp_spi_setup_transfer(struct spi_device *spi,
- struct spi_transfer *t)
-{
- u8 bits_per_word;
- u32 hz;
- struct stmp_spi *ss = spi_master_get_devdata(spi->master);
- u16 rate;
-
- bits_per_word = spi->bits_per_word;
- if (t && t->bits_per_word)
- bits_per_word = t->bits_per_word;
-
- /*
- * Calculate speed:
- * - by default, use maximum speed from ssp clk
- * - if device overrides it, use it
- * - if transfer specifies other speed, use transfer's one
- */
- hz = 1000 * ss->speed_khz / ss->divider;
- if (spi->max_speed_hz)
- hz = min(hz, spi->max_speed_hz);
- if (t && t->speed_hz)
- hz = min(hz, t->speed_hz);
-
- if (hz == 0) {
- dev_err(&spi->dev, "Cannot continue with zero clock\n");
- return -EINVAL;
- }
-
- if (bits_per_word != 8) {
- dev_err(&spi->dev, "%s, unsupported bits_per_word=%d\n",
- __func__, bits_per_word);
- return -EINVAL;
- }
-
- dev_dbg(&spi->dev, "Requested clk rate = %uHz, max = %uHz/%d = %uHz\n",
- hz, ss->speed_khz, ss->divider,
- ss->speed_khz * 1000 / ss->divider);
-
- if (ss->speed_khz * 1000 / ss->divider < hz) {
- dev_err(&spi->dev, "%s, unsupported clock rate %uHz\n",
- __func__, hz);
- return -EINVAL;
- }
-
- rate = 1000 * ss->speed_khz/ss->divider/hz;
-
- writel(BF(ss->divider, SSP_TIMING_CLOCK_DIVIDE) |
- BF(rate - 1, SSP_TIMING_CLOCK_RATE),
- HW_SSP_TIMING + ss->regs);
-
- writel(BF(1 /* mode SPI */, SSP_CTRL1_SSP_MODE) |
- BF(4 /* 8 bits */, SSP_CTRL1_WORD_LENGTH) |
- ((spi->mode & SPI_CPOL) ? BM_SSP_CTRL1_POLARITY : 0) |
- ((spi->mode & SPI_CPHA) ? BM_SSP_CTRL1_PHASE : 0) |
- (pio ? 0 : BM_SSP_CTRL1_DMA_ENABLE),
- ss->regs + HW_SSP_CTRL1);
-
- return 0;
-}
-
-static int stmp_spi_setup(struct spi_device *spi)
-{
- /* spi_setup() does basic checks,
- * stmp_spi_setup_transfer() does more later
- */
- if (spi->bits_per_word != 8) {
- dev_err(&spi->dev, "%s, unsupported bits_per_word=%d\n",
- __func__, spi->bits_per_word);
- return -EINVAL;
- }
- return 0;
-}
-
-static inline u32 stmp_spi_cs(unsigned cs)
-{
- return ((cs & 1) ? BM_SSP_CTRL0_WAIT_FOR_CMD : 0) |
- ((cs & 2) ? BM_SSP_CTRL0_WAIT_FOR_IRQ : 0);
-}
-
-static int stmp_spi_txrx_dma(struct stmp_spi *ss, int cs,
- unsigned char *buf, dma_addr_t dma_buf, int len,
- int first, int last, bool write)
-{
- u32 c0 = 0;
- dma_addr_t spi_buf_dma = dma_buf;
- int status = 0;
- enum dma_data_direction dir = write ? DMA_TO_DEVICE : DMA_FROM_DEVICE;
-
- c0 |= (first ? BM_SSP_CTRL0_LOCK_CS : 0);
- c0 |= (last ? BM_SSP_CTRL0_IGNORE_CRC : 0);
- c0 |= (write ? 0 : BM_SSP_CTRL0_READ);
- c0 |= BM_SSP_CTRL0_DATA_XFER;
-
- c0 |= stmp_spi_cs(cs);
-
- c0 |= BF(len, SSP_CTRL0_XFER_COUNT);
-
- if (!dma_buf)
- spi_buf_dma = dma_map_single(ss->master_dev, buf, len, dir);
-
- ss->d.command->cmd =
- BF(len, APBH_CHn_CMD_XFER_COUNT) |
- BF(1, APBH_CHn_CMD_CMDWORDS) |
- BM_APBH_CHn_CMD_WAIT4ENDCMD |
- BM_APBH_CHn_CMD_IRQONCMPLT |
- BF(write ? BV_APBH_CHn_CMD_COMMAND__DMA_READ :
- BV_APBH_CHn_CMD_COMMAND__DMA_WRITE,
- APBH_CHn_CMD_COMMAND);
- ss->d.command->pio_words[0] = c0;
- ss->d.command->buf_ptr = spi_buf_dma;
-
- stmp3xxx_dma_reset_channel(ss->dma);
- stmp3xxx_dma_clear_interrupt(ss->dma);
- stmp3xxx_dma_enable_interrupt(ss->dma);
- init_completion(&ss->done);
- stmp3xxx_dma_go(ss->dma, &ss->d, 1);
- wait_for_completion(&ss->done);
-
- if (!busy_wait(readl(ss->regs + HW_SSP_CTRL0) & BM_SSP_CTRL0_RUN))
- status = -ETIMEDOUT;
-
- if (!dma_buf)
- dma_unmap_single(ss->master_dev, spi_buf_dma, len, dir);
-
- return status;
-}
-
-static inline void stmp_spi_enable(struct stmp_spi *ss)
-{
- stmp3xxx_setl(BM_SSP_CTRL0_LOCK_CS, ss->regs + HW_SSP_CTRL0);
- stmp3xxx_clearl(BM_SSP_CTRL0_IGNORE_CRC, ss->regs + HW_SSP_CTRL0);
-}
-
-static inline void stmp_spi_disable(struct stmp_spi *ss)
-{
- stmp3xxx_clearl(BM_SSP_CTRL0_LOCK_CS, ss->regs + HW_SSP_CTRL0);
- stmp3xxx_setl(BM_SSP_CTRL0_IGNORE_CRC, ss->regs + HW_SSP_CTRL0);
-}
-
-static int stmp_spi_txrx_pio(struct stmp_spi *ss, int cs,
- unsigned char *buf, int len,
- bool first, bool last, bool write)
-{
- if (first)
- stmp_spi_enable(ss);
-
- stmp3xxx_setl(stmp_spi_cs(cs), ss->regs + HW_SSP_CTRL0);
-
- while (len--) {
- if (last && len <= 0)
- stmp_spi_disable(ss);
-
- stmp3xxx_clearl(BM_SSP_CTRL0_XFER_COUNT,
- ss->regs + HW_SSP_CTRL0);
- stmp3xxx_setl(1, ss->regs + HW_SSP_CTRL0);
-
- if (write)
- stmp3xxx_clearl(BM_SSP_CTRL0_READ,
- ss->regs + HW_SSP_CTRL0);
- else
- stmp3xxx_setl(BM_SSP_CTRL0_READ,
- ss->regs + HW_SSP_CTRL0);
-
- /* Run! */
- stmp3xxx_setl(BM_SSP_CTRL0_RUN, ss->regs + HW_SSP_CTRL0);
-
- if (!busy_wait(readl(ss->regs + HW_SSP_CTRL0) &
- BM_SSP_CTRL0_RUN))
- break;
-
- if (write)
- writel(*buf, ss->regs + HW_SSP_DATA);
-
- /* Set TRANSFER */
- stmp3xxx_setl(BM_SSP_CTRL0_DATA_XFER, ss->regs + HW_SSP_CTRL0);
-
- if (!write) {
- if (busy_wait((readl(ss->regs + HW_SSP_STATUS) &
- BM_SSP_STATUS_FIFO_EMPTY)))
- break;
- *buf = readl(ss->regs + HW_SSP_DATA) & 0xFF;
- }
-
- if (!busy_wait(readl(ss->regs + HW_SSP_CTRL0) &
- BM_SSP_CTRL0_RUN))
- break;
-
- /* advance to the next byte */
- buf++;
- }
-
- return len < 0 ? 0 : -ETIMEDOUT;
-}
-
-static int stmp_spi_handle_message(struct stmp_spi *ss, struct spi_message *m)
-{
- bool first, last;
- struct spi_transfer *t, *tmp_t;
- int status = 0;
- int cs;
-
- cs = m->spi->chip_select;
-
- list_for_each_entry_safe(t, tmp_t, &m->transfers, transfer_list) {
-
- first = (&t->transfer_list == m->transfers.next);
- last = (&t->transfer_list == m->transfers.prev);
-
- if (first || t->speed_hz || t->bits_per_word)
- stmp_spi_setup_transfer(m->spi, t);
-
- /* reject "not last" transfers which request to change cs */
- if (t->cs_change && !last) {
- dev_err(&m->spi->dev,
- "Message with t->cs_change has been skipped\n");
- continue;
- }
-
- if (t->tx_buf) {
- status = pio ?
- stmp_spi_txrx_pio(ss, cs, (void *)t->tx_buf,
- t->len, first, last, true) :
- stmp_spi_txrx_dma(ss, cs, (void *)t->tx_buf,
- t->tx_dma, t->len, first, last, true);
-#ifdef DEBUG
- if (t->len < 0x10)
- print_hex_dump_bytes("Tx ",
- DUMP_PREFIX_OFFSET,
- t->tx_buf, t->len);
- else
- pr_debug("Tx: %d bytes\n", t->len);
-#endif
- }
- if (t->rx_buf) {
- status = pio ?
- stmp_spi_txrx_pio(ss, cs, t->rx_buf,
- t->len, first, last, false) :
- stmp_spi_txrx_dma(ss, cs, t->rx_buf,
- t->rx_dma, t->len, first, last, false);
-#ifdef DEBUG
- if (t->len < 0x10)
- print_hex_dump_bytes("Rx ",
- DUMP_PREFIX_OFFSET,
- t->rx_buf, t->len);
- else
- pr_debug("Rx: %d bytes\n", t->len);
-#endif
- }
-
- if (t->delay_usecs)
- udelay(t->delay_usecs);
-
- if (status)
- break;
-
- }
- return status;
-}
-
-/**
- * stmp_spi_handle - handle messages from the queue
- */
-static void stmp_spi_handle(struct work_struct *w)
-{
- struct stmp_spi *ss = container_of(w, struct stmp_spi, work);
- unsigned long flags;
- struct spi_message *m;
-
- spin_lock_irqsave(&ss->lock, flags);
- while (!list_empty(&ss->queue)) {
- m = list_entry(ss->queue.next, struct spi_message, queue);
- list_del_init(&m->queue);
- spin_unlock_irqrestore(&ss->lock, flags);
-
- m->status = stmp_spi_handle_message(ss, m);
- m->complete(m->context);
-
- spin_lock_irqsave(&ss->lock, flags);
- }
- spin_unlock_irqrestore(&ss->lock, flags);
-
- return;
-}
-
-/**
- * stmp_spi_transfer - perform message transfer.
- * Called indirectly from spi_async, queues all the messages to
- * spi_handle_message.
- * @spi: spi device
- * @m: message to be queued
- */
-static int stmp_spi_transfer(struct spi_device *spi, struct spi_message *m)
-{
- struct stmp_spi *ss = spi_master_get_devdata(spi->master);
- unsigned long flags;
-
- m->status = -EINPROGRESS;
- spin_lock_irqsave(&ss->lock, flags);
- list_add_tail(&m->queue, &ss->queue);
- queue_work(ss->workqueue, &ss->work);
- spin_unlock_irqrestore(&ss->lock, flags);
- return 0;
-}
-
-static irqreturn_t stmp_spi_irq(int irq, void *dev_id)
-{
- struct stmp_spi *ss = dev_id;
-
- stmp3xxx_dma_clear_interrupt(ss->dma);
- complete(&ss->done);
- return IRQ_HANDLED;
-}
-
-static irqreturn_t stmp_spi_irq_err(int irq, void *dev_id)
-{
- struct stmp_spi *ss = dev_id;
- u32 c1, st;
-
- c1 = readl(ss->regs + HW_SSP_CTRL1);
- st = readl(ss->regs + HW_SSP_STATUS);
- dev_err(ss->master_dev, "%s: status = 0x%08X, c1 = 0x%08X\n",
- __func__, st, c1);
- stmp3xxx_clearl(c1 & 0xCCCC0000, ss->regs + HW_SSP_CTRL1);
-
- return IRQ_HANDLED;
-}
-
-static int __devinit stmp_spi_probe(struct platform_device *dev)
-{
- int err = 0;
- struct spi_master *master;
- struct stmp_spi *ss;
- struct resource *r;
-
- master = spi_alloc_master(&dev->dev, sizeof(struct stmp_spi));
- if (master == NULL) {
- err = -ENOMEM;
- goto out0;
- }
- master->flags = SPI_MASTER_HALF_DUPLEX;
-
- ss = spi_master_get_devdata(master);
- platform_set_drvdata(dev, master);
-
- /* Get resources(memory, IRQ) associated with the device */
- r = platform_get_resource(dev, IORESOURCE_MEM, 0);
- if (r == NULL) {
- err = -ENODEV;
- goto out_put_master;
- }
- ss->regs = ioremap(r->start, resource_size(r));
- if (!ss->regs) {
- err = -EINVAL;
- goto out_put_master;
- }
-
- ss->master_dev = &dev->dev;
- ss->id = dev->id;
-
- INIT_WORK(&ss->work, stmp_spi_handle);
- INIT_LIST_HEAD(&ss->queue);
- spin_lock_init(&ss->lock);
-
- ss->workqueue = create_singlethread_workqueue(dev_name(&dev->dev));
- if (!ss->workqueue) {
- err = -ENXIO;
- goto out_put_master;
- }
- master->transfer = stmp_spi_transfer;
- master->setup = stmp_spi_setup;
-
- /* the spi->mode bits understood by this driver: */
- master->mode_bits = SPI_CPOL | SPI_CPHA;
-
- ss->irq = platform_get_irq(dev, 0);
- if (ss->irq < 0) {
- err = ss->irq;
- goto out_put_master;
- }
- ss->err_irq = platform_get_irq(dev, 1);
- if (ss->err_irq < 0) {
- err = ss->err_irq;
- goto out_put_master;
- }
-
- r = platform_get_resource(dev, IORESOURCE_DMA, 0);
- if (r == NULL) {
- err = -ENODEV;
- goto out_put_master;
- }
-
- ss->dma = r->start;
- err = stmp3xxx_dma_request(ss->dma, &dev->dev, dev_name(&dev->dev));
- if (err)
- goto out_put_master;
-
- err = stmp3xxx_dma_allocate_command(ss->dma, &ss->d);
- if (err)
- goto out_free_dma;
-
- master->bus_num = dev->id;
- master->num_chipselect = 1;
-
- /* SPI controller initializations */
- err = stmp_spi_init_hw(ss);
- if (err) {
- dev_dbg(&dev->dev, "cannot initialize hardware\n");
- goto out_free_dma_desc;
- }
-
- if (clock) {
- dev_info(&dev->dev, "clock rate forced to %d\n", clock);
- clk_set_rate(ss->clk, clock);
- }
- ss->speed_khz = clk_get_rate(ss->clk);
- ss->divider = 2;
- dev_info(&dev->dev, "max possible speed %d = %ld/%d kHz\n",
- ss->speed_khz, clk_get_rate(ss->clk), ss->divider);
-
- /* Register for SPI interrupt */
- err = request_irq(ss->irq, stmp_spi_irq, 0,
- dev_name(&dev->dev), ss);
- if (err) {
- dev_dbg(&dev->dev, "request_irq failed, %d\n", err);
- goto out_release_hw;
- }
-
- /* ..and shared interrupt for all SSP controllers */
- err = request_irq(ss->err_irq, stmp_spi_irq_err, IRQF_SHARED,
- dev_name(&dev->dev), ss);
- if (err) {
- dev_dbg(&dev->dev, "request_irq(error) failed, %d\n", err);
- goto out_free_irq;
- }
-
- err = spi_register_master(master);
- if (err) {
- dev_dbg(&dev->dev, "cannot register spi master, %d\n", err);
- goto out_free_irq_2;
- }
- dev_info(&dev->dev, "at (mapped) 0x%08X, irq=%d, bus %d, %s mode\n",
- (u32)ss->regs, ss->irq, master->bus_num,
- pio ? "PIO" : "DMA");
- return 0;
-
-out_free_irq_2:
- free_irq(ss->err_irq, ss);
-out_free_irq:
- free_irq(ss->irq, ss);
-out_free_dma_desc:
- stmp3xxx_dma_free_command(ss->dma, &ss->d);
-out_free_dma:
- stmp3xxx_dma_release(ss->dma);
-out_release_hw:
- stmp_spi_release_hw(ss);
-out_put_master:
- if (ss->workqueue)
- destroy_workqueue(ss->workqueue);
- if (ss->regs)
- iounmap(ss->regs);
- platform_set_drvdata(dev, NULL);
- spi_master_put(master);
-out0:
- return err;
-}
-
-static int __devexit stmp_spi_remove(struct platform_device *dev)
-{
- struct stmp_spi *ss;
- struct spi_master *master;
-
- master = spi_master_get(platform_get_drvdata(dev));
- ss = spi_master_get_devdata(master);
-
- spi_unregister_master(master);
-
- free_irq(ss->err_irq, ss);
- free_irq(ss->irq, ss);
- stmp3xxx_dma_free_command(ss->dma, &ss->d);
- stmp3xxx_dma_release(ss->dma);
- stmp_spi_release_hw(ss);
- destroy_workqueue(ss->workqueue);
- iounmap(ss->regs);
- spi_master_put(master);
- return 0;
-}
-
-#ifdef CONFIG_PM
-static int stmp_spi_suspend(struct platform_device *pdev, pm_message_t pmsg)
-{
- struct stmp_spi *ss;
- struct spi_master *master;
-
- master = platform_get_drvdata(pdev);
- ss = spi_master_get_devdata(master);
-
- ss->saved_timings = readl(HW_SSP_TIMING + ss->regs);
- clk_disable(ss->clk);
-
- return 0;
-}
-
-static int stmp_spi_resume(struct platform_device *pdev)
-{
- struct stmp_spi *ss;
- struct spi_master *master;
-
- master = platform_get_drvdata(pdev);
- ss = spi_master_get_devdata(master);
-
- clk_enable(ss->clk);
- stmp3xxx_reset_block(ss->regs, false);
- writel(ss->saved_timings, ss->regs + HW_SSP_TIMING);
-
- return 0;
-}
-
-#else
-#define stmp_spi_suspend NULL
-#define stmp_spi_resume NULL
-#endif
-
-static struct platform_driver stmp_spi_driver = {
- .probe = stmp_spi_probe,
- .remove = __devexit_p(stmp_spi_remove),
- .driver = {
- .name = "stmp3xxx_ssp",
- .owner = THIS_MODULE,
- },
- .suspend = stmp_spi_suspend,
- .resume = stmp_spi_resume,
-};
-module_platform_driver(stmp_spi_driver);
-
-module_param(pio, int, S_IRUGO);
-module_param(clock, int, S_IRUGO);
-MODULE_AUTHOR("dmitry pervushin <dpervushin@embeddedalley.com>");
-MODULE_DESCRIPTION("STMP3xxx SPI/SSP driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/spi/spi-tegra20-sflash.c b/drivers/spi/spi-tegra20-sflash.c
new file mode 100644
index 000000000000..3d6a12b2af04
--- /dev/null
+++ b/drivers/spi/spi-tegra20-sflash.c
@@ -0,0 +1,671 @@
+/*
+ * SPI driver for Nvidia's Tegra20 Serial Flash Controller.
+ *
+ * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved.
+ *
+ * Author: Laxman Dewangan <ldewangan@nvidia.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/clk.h>
+#include <linux/completion.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/kthread.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/spi-tegra.h>
+#include <linux/clk/tegra.h>
+
+#define SPI_COMMAND 0x000
+#define SPI_GO BIT(30)
+#define SPI_M_S BIT(28)
+#define SPI_ACTIVE_SCLK_MASK (0x3 << 26)
+#define SPI_ACTIVE_SCLK_DRIVE_LOW (0 << 26)
+#define SPI_ACTIVE_SCLK_DRIVE_HIGH (1 << 26)
+#define SPI_ACTIVE_SCLK_PULL_LOW (2 << 26)
+#define SPI_ACTIVE_SCLK_PULL_HIGH (3 << 26)
+
+#define SPI_CK_SDA_FALLING (1 << 21)
+#define SPI_CK_SDA_RISING (0 << 21)
+#define SPI_CK_SDA_MASK (1 << 21)
+#define SPI_ACTIVE_SDA (0x3 << 18)
+#define SPI_ACTIVE_SDA_DRIVE_LOW (0 << 18)
+#define SPI_ACTIVE_SDA_DRIVE_HIGH (1 << 18)
+#define SPI_ACTIVE_SDA_PULL_LOW (2 << 18)
+#define SPI_ACTIVE_SDA_PULL_HIGH (3 << 18)
+
+#define SPI_CS_POL_INVERT BIT(16)
+#define SPI_TX_EN BIT(15)
+#define SPI_RX_EN BIT(14)
+#define SPI_CS_VAL_HIGH BIT(13)
+#define SPI_CS_VAL_LOW 0x0
+#define SPI_CS_SW BIT(12)
+#define SPI_CS_HW 0x0
+#define SPI_CS_DELAY_MASK (7 << 9)
+#define SPI_CS3_EN BIT(8)
+#define SPI_CS2_EN BIT(7)
+#define SPI_CS1_EN BIT(6)
+#define SPI_CS0_EN BIT(5)
+
+#define SPI_CS_MASK (SPI_CS3_EN | SPI_CS2_EN | \
+ SPI_CS1_EN | SPI_CS0_EN)
+#define SPI_BIT_LENGTH(x) (((x) & 0x1f) << 0)
+
+#define SPI_MODES (SPI_ACTIVE_SCLK_MASK | SPI_CK_SDA_MASK)
+
+#define SPI_STATUS 0x004
+#define SPI_BSY BIT(31)
+#define SPI_RDY BIT(30)
+#define SPI_TXF_FLUSH BIT(29)
+#define SPI_RXF_FLUSH BIT(28)
+#define SPI_RX_UNF BIT(27)
+#define SPI_TX_OVF BIT(26)
+#define SPI_RXF_EMPTY BIT(25)
+#define SPI_RXF_FULL BIT(24)
+#define SPI_TXF_EMPTY BIT(23)
+#define SPI_TXF_FULL BIT(22)
+#define SPI_BLK_CNT(count) (((count) & 0xffff) + 1)
+
+#define SPI_FIFO_ERROR (SPI_RX_UNF | SPI_TX_OVF)
+#define SPI_FIFO_EMPTY (SPI_TX_EMPTY | SPI_RX_EMPTY)
+
+#define SPI_RX_CMP 0x8
+#define SPI_DMA_CTL 0x0C
+#define SPI_DMA_EN BIT(31)
+#define SPI_IE_RXC BIT(27)
+#define SPI_IE_TXC BIT(26)
+#define SPI_PACKED BIT(20)
+#define SPI_RX_TRIG_MASK (0x3 << 18)
+#define SPI_RX_TRIG_1W (0x0 << 18)
+#define SPI_RX_TRIG_4W (0x1 << 18)
+#define SPI_TX_TRIG_MASK (0x3 << 16)
+#define SPI_TX_TRIG_1W (0x0 << 16)
+#define SPI_TX_TRIG_4W (0x1 << 16)
+#define SPI_DMA_BLK_COUNT(count) (((count) - 1) & 0xFFFF);
+
+#define SPI_TX_FIFO 0x10
+#define SPI_RX_FIFO 0x20
+
+#define DATA_DIR_TX (1 << 0)
+#define DATA_DIR_RX (1 << 1)
+
+#define MAX_CHIP_SELECT 4
+#define SPI_FIFO_DEPTH 4
+#define SPI_DMA_TIMEOUT (msecs_to_jiffies(1000))
+
+struct tegra_sflash_data {
+ struct device *dev;
+ struct spi_master *master;
+ spinlock_t lock;
+
+ struct clk *clk;
+ void __iomem *base;
+ unsigned irq;
+ u32 spi_max_frequency;
+ u32 cur_speed;
+
+ struct spi_device *cur_spi;
+ unsigned cur_pos;
+ unsigned cur_len;
+ unsigned bytes_per_word;
+ unsigned cur_direction;
+ unsigned curr_xfer_words;
+
+ unsigned cur_rx_pos;
+ unsigned cur_tx_pos;
+
+ u32 tx_status;
+ u32 rx_status;
+ u32 status_reg;
+
+ u32 def_command_reg;
+ u32 command_reg;
+ u32 dma_control_reg;
+
+ struct completion xfer_completion;
+ struct spi_transfer *curr_xfer;
+};
+
+static int tegra_sflash_runtime_suspend(struct device *dev);
+static int tegra_sflash_runtime_resume(struct device *dev);
+
+static inline unsigned long tegra_sflash_readl(struct tegra_sflash_data *tsd,
+ unsigned long reg)
+{
+ return readl(tsd->base + reg);
+}
+
+static inline void tegra_sflash_writel(struct tegra_sflash_data *tsd,
+ unsigned long val, unsigned long reg)
+{
+ writel(val, tsd->base + reg);
+}
+
+static void tegra_sflash_clear_status(struct tegra_sflash_data *tsd)
+{
+ /* Write 1 to clear status register */
+ tegra_sflash_writel(tsd, SPI_RDY | SPI_FIFO_ERROR, SPI_STATUS);
+}
+
+static unsigned tegra_sflash_calculate_curr_xfer_param(
+ struct spi_device *spi, struct tegra_sflash_data *tsd,
+ struct spi_transfer *t)
+{
+ unsigned remain_len = t->len - tsd->cur_pos;
+ unsigned max_word;
+
+ tsd->bytes_per_word = (t->bits_per_word - 1) / 8 + 1;
+ max_word = remain_len / tsd->bytes_per_word;
+ if (max_word > SPI_FIFO_DEPTH)
+ max_word = SPI_FIFO_DEPTH;
+ tsd->curr_xfer_words = max_word;
+ return max_word;
+}
+
+static unsigned tegra_sflash_fill_tx_fifo_from_client_txbuf(
+ struct tegra_sflash_data *tsd, struct spi_transfer *t)
+{
+ unsigned nbytes;
+ unsigned long status;
+ unsigned max_n_32bit = tsd->curr_xfer_words;
+ u8 *tx_buf = (u8 *)t->tx_buf + tsd->cur_tx_pos;
+
+ if (max_n_32bit > SPI_FIFO_DEPTH)
+ max_n_32bit = SPI_FIFO_DEPTH;
+ nbytes = max_n_32bit * tsd->bytes_per_word;
+
+ status = tegra_sflash_readl(tsd, SPI_STATUS);
+ while (!(status & SPI_TXF_FULL)) {
+ int i;
+ unsigned int x = 0;
+
+ for (i = 0; nbytes && (i < tsd->bytes_per_word);
+ i++, nbytes--)
+ x |= ((*tx_buf++) << i*8);
+ tegra_sflash_writel(tsd, x, SPI_TX_FIFO);
+ if (!nbytes)
+ break;
+
+ status = tegra_sflash_readl(tsd, SPI_STATUS);
+ }
+ tsd->cur_tx_pos += max_n_32bit * tsd->bytes_per_word;
+ return max_n_32bit;
+}
+
+static int tegra_sflash_read_rx_fifo_to_client_rxbuf(
+ struct tegra_sflash_data *tsd, struct spi_transfer *t)
+{
+ unsigned long status;
+ unsigned int read_words = 0;
+ u8 *rx_buf = (u8 *)t->rx_buf + tsd->cur_rx_pos;
+
+ status = tegra_sflash_readl(tsd, SPI_STATUS);
+ while (!(status & SPI_RXF_EMPTY)) {
+ int i;
+ unsigned long x;
+
+ x = tegra_sflash_readl(tsd, SPI_RX_FIFO);
+ for (i = 0; (i < tsd->bytes_per_word); i++)
+ *rx_buf++ = (x >> (i*8)) & 0xFF;
+ read_words++;
+ status = tegra_sflash_readl(tsd, SPI_STATUS);
+ }
+ tsd->cur_rx_pos += read_words * tsd->bytes_per_word;
+ return 0;
+}
+
+static int tegra_sflash_start_cpu_based_transfer(
+ struct tegra_sflash_data *tsd, struct spi_transfer *t)
+{
+ unsigned long val = 0;
+ unsigned cur_words;
+
+ if (tsd->cur_direction & DATA_DIR_TX)
+ val |= SPI_IE_TXC;
+
+ if (tsd->cur_direction & DATA_DIR_RX)
+ val |= SPI_IE_RXC;
+
+ tegra_sflash_writel(tsd, val, SPI_DMA_CTL);
+ tsd->dma_control_reg = val;
+
+ if (tsd->cur_direction & DATA_DIR_TX)
+ cur_words = tegra_sflash_fill_tx_fifo_from_client_txbuf(tsd, t);
+ else
+ cur_words = tsd->curr_xfer_words;
+ val |= SPI_DMA_BLK_COUNT(cur_words);
+ tegra_sflash_writel(tsd, val, SPI_DMA_CTL);
+ tsd->dma_control_reg = val;
+ val |= SPI_DMA_EN;
+ tegra_sflash_writel(tsd, val, SPI_DMA_CTL);
+ return 0;
+}
+
+static int tegra_sflash_start_transfer_one(struct spi_device *spi,
+ struct spi_transfer *t, bool is_first_of_msg,
+ bool is_single_xfer)
+{
+ struct tegra_sflash_data *tsd = spi_master_get_devdata(spi->master);
+ u32 speed;
+ unsigned long command;
+
+ speed = t->speed_hz;
+ if (speed != tsd->cur_speed) {
+ clk_set_rate(tsd->clk, speed);
+ tsd->cur_speed = speed;
+ }
+
+ tsd->cur_spi = spi;
+ tsd->cur_pos = 0;
+ tsd->cur_rx_pos = 0;
+ tsd->cur_tx_pos = 0;
+ tsd->curr_xfer = t;
+ tegra_sflash_calculate_curr_xfer_param(spi, tsd, t);
+ if (is_first_of_msg) {
+ command = tsd->def_command_reg;
+ command |= SPI_BIT_LENGTH(t->bits_per_word - 1);
+ command |= SPI_CS_VAL_HIGH;
+
+ command &= ~SPI_MODES;
+ if (spi->mode & SPI_CPHA)
+ command |= SPI_CK_SDA_FALLING;
+
+ if (spi->mode & SPI_CPOL)
+ command |= SPI_ACTIVE_SCLK_DRIVE_HIGH;
+ else
+ command |= SPI_ACTIVE_SCLK_DRIVE_LOW;
+ command |= SPI_CS0_EN << spi->chip_select;
+ } else {
+ command = tsd->command_reg;
+ command &= ~SPI_BIT_LENGTH(~0);
+ command |= SPI_BIT_LENGTH(t->bits_per_word - 1);
+ command &= ~(SPI_RX_EN | SPI_TX_EN);
+ }
+
+ tsd->cur_direction = 0;
+ if (t->rx_buf) {
+ command |= SPI_RX_EN;
+ tsd->cur_direction |= DATA_DIR_RX;
+ }
+ if (t->tx_buf) {
+ command |= SPI_TX_EN;
+ tsd->cur_direction |= DATA_DIR_TX;
+ }
+ tegra_sflash_writel(tsd, command, SPI_COMMAND);
+ tsd->command_reg = command;
+
+ return tegra_sflash_start_cpu_based_transfer(tsd, t);
+}
+
+static int tegra_sflash_setup(struct spi_device *spi)
+{
+ struct tegra_sflash_data *tsd = spi_master_get_devdata(spi->master);
+
+ /* Set speed to the spi max fequency if spi device has not set */
+ spi->max_speed_hz = spi->max_speed_hz ? : tsd->spi_max_frequency;
+ return 0;
+}
+
+static int tegra_sflash_transfer_one_message(struct spi_master *master,
+ struct spi_message *msg)
+{
+ bool is_first_msg = true;
+ int single_xfer;
+ struct tegra_sflash_data *tsd = spi_master_get_devdata(master);
+ struct spi_transfer *xfer;
+ struct spi_device *spi = msg->spi;
+ int ret;
+
+ ret = pm_runtime_get_sync(tsd->dev);
+ if (ret < 0) {
+ dev_err(tsd->dev, "pm_runtime_get() failed, err = %d\n", ret);
+ return ret;
+ }
+
+ msg->status = 0;
+ msg->actual_length = 0;
+ single_xfer = list_is_singular(&msg->transfers);
+ list_for_each_entry(xfer, &msg->transfers, transfer_list) {
+ INIT_COMPLETION(tsd->xfer_completion);
+ ret = tegra_sflash_start_transfer_one(spi, xfer,
+ is_first_msg, single_xfer);
+ if (ret < 0) {
+ dev_err(tsd->dev,
+ "spi can not start transfer, err %d\n", ret);
+ goto exit;
+ }
+ is_first_msg = false;
+ ret = wait_for_completion_timeout(&tsd->xfer_completion,
+ SPI_DMA_TIMEOUT);
+ if (WARN_ON(ret == 0)) {
+ dev_err(tsd->dev,
+ "spi trasfer timeout, err %d\n", ret);
+ ret = -EIO;
+ goto exit;
+ }
+
+ if (tsd->tx_status || tsd->rx_status) {
+ dev_err(tsd->dev, "Error in Transfer\n");
+ ret = -EIO;
+ goto exit;
+ }
+ msg->actual_length += xfer->len;
+ if (xfer->cs_change && xfer->delay_usecs) {
+ tegra_sflash_writel(tsd, tsd->def_command_reg,
+ SPI_COMMAND);
+ udelay(xfer->delay_usecs);
+ }
+ }
+ ret = 0;
+exit:
+ tegra_sflash_writel(tsd, tsd->def_command_reg, SPI_COMMAND);
+ msg->status = ret;
+ spi_finalize_current_message(master);
+ pm_runtime_put(tsd->dev);
+ return ret;
+}
+
+static irqreturn_t handle_cpu_based_xfer(struct tegra_sflash_data *tsd)
+{
+ struct spi_transfer *t = tsd->curr_xfer;
+ unsigned long flags;
+
+ spin_lock_irqsave(&tsd->lock, flags);
+ if (tsd->tx_status || tsd->rx_status || (tsd->status_reg & SPI_BSY)) {
+ dev_err(tsd->dev,
+ "CpuXfer ERROR bit set 0x%x\n", tsd->status_reg);
+ dev_err(tsd->dev,
+ "CpuXfer 0x%08x:0x%08x\n", tsd->command_reg,
+ tsd->dma_control_reg);
+ tegra_periph_reset_assert(tsd->clk);
+ udelay(2);
+ tegra_periph_reset_deassert(tsd->clk);
+ complete(&tsd->xfer_completion);
+ goto exit;
+ }
+
+ if (tsd->cur_direction & DATA_DIR_RX)
+ tegra_sflash_read_rx_fifo_to_client_rxbuf(tsd, t);
+
+ if (tsd->cur_direction & DATA_DIR_TX)
+ tsd->cur_pos = tsd->cur_tx_pos;
+ else
+ tsd->cur_pos = tsd->cur_rx_pos;
+
+ if (tsd->cur_pos == t->len) {
+ complete(&tsd->xfer_completion);
+ goto exit;
+ }
+
+ tegra_sflash_calculate_curr_xfer_param(tsd->cur_spi, tsd, t);
+ tegra_sflash_start_cpu_based_transfer(tsd, t);
+exit:
+ spin_unlock_irqrestore(&tsd->lock, flags);
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t tegra_sflash_isr(int irq, void *context_data)
+{
+ struct tegra_sflash_data *tsd = context_data;
+
+ tsd->status_reg = tegra_sflash_readl(tsd, SPI_STATUS);
+ if (tsd->cur_direction & DATA_DIR_TX)
+ tsd->tx_status = tsd->status_reg & SPI_TX_OVF;
+
+ if (tsd->cur_direction & DATA_DIR_RX)
+ tsd->rx_status = tsd->status_reg & SPI_RX_UNF;
+ tegra_sflash_clear_status(tsd);
+
+ return handle_cpu_based_xfer(tsd);
+}
+
+static struct tegra_spi_platform_data *tegra_sflash_parse_dt(
+ struct platform_device *pdev)
+{
+ struct tegra_spi_platform_data *pdata;
+ struct device_node *np = pdev->dev.of_node;
+ u32 max_freq;
+
+ pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
+ if (!pdata) {
+ dev_err(&pdev->dev, "Memory alloc for pdata failed\n");
+ return NULL;
+ }
+
+ if (!of_property_read_u32(np, "spi-max-frequency", &max_freq))
+ pdata->spi_max_frequency = max_freq;
+
+ return pdata;
+}
+
+static struct of_device_id tegra_sflash_of_match[] = {
+ { .compatible = "nvidia,tegra20-sflash", },
+ {}
+};
+MODULE_DEVICE_TABLE(of, tegra_sflash_of_match);
+
+static int tegra_sflash_probe(struct platform_device *pdev)
+{
+ struct spi_master *master;
+ struct tegra_sflash_data *tsd;
+ struct resource *r;
+ struct tegra_spi_platform_data *pdata = pdev->dev.platform_data;
+ int ret;
+ const struct of_device_id *match;
+
+ match = of_match_device(of_match_ptr(tegra_sflash_of_match),
+ &pdev->dev);
+ if (!match) {
+ dev_err(&pdev->dev, "Error: No device match found\n");
+ return -ENODEV;
+ }
+
+ if (!pdata && pdev->dev.of_node)
+ pdata = tegra_sflash_parse_dt(pdev);
+
+ if (!pdata) {
+ dev_err(&pdev->dev, "No platform data, exiting\n");
+ return -ENODEV;
+ }
+
+ if (!pdata->spi_max_frequency)
+ pdata->spi_max_frequency = 25000000; /* 25MHz */
+
+ master = spi_alloc_master(&pdev->dev, sizeof(*tsd));
+ if (!master) {
+ 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;
+ master->setup = tegra_sflash_setup;
+ master->transfer_one_message = tegra_sflash_transfer_one_message;
+ master->num_chipselect = MAX_CHIP_SELECT;
+ master->bus_num = -1;
+
+ dev_set_drvdata(&pdev->dev, master);
+ tsd = spi_master_get_devdata(master);
+ tsd->master = master;
+ tsd->dev = &pdev->dev;
+ spin_lock_init(&tsd->lock);
+
+ r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!r) {
+ dev_err(&pdev->dev, "No IO memory resource\n");
+ ret = -ENODEV;
+ goto exit_free_master;
+ }
+ tsd->base = devm_ioremap_resource(&pdev->dev, r);
+ if (IS_ERR(tsd->base)) {
+ ret = PTR_ERR(tsd->base);
+ goto exit_free_master;
+ }
+
+ tsd->irq = platform_get_irq(pdev, 0);
+ ret = request_irq(tsd->irq, tegra_sflash_isr, 0,
+ dev_name(&pdev->dev), tsd);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "Failed to register ISR for IRQ %d\n",
+ tsd->irq);
+ goto exit_free_master;
+ }
+
+ tsd->clk = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(tsd->clk)) {
+ dev_err(&pdev->dev, "can not get clock\n");
+ ret = PTR_ERR(tsd->clk);
+ goto exit_free_irq;
+ }
+
+ tsd->spi_max_frequency = pdata->spi_max_frequency;
+ init_completion(&tsd->xfer_completion);
+ pm_runtime_enable(&pdev->dev);
+ if (!pm_runtime_enabled(&pdev->dev)) {
+ ret = tegra_sflash_runtime_resume(&pdev->dev);
+ if (ret)
+ goto exit_pm_disable;
+ }
+
+ ret = pm_runtime_get_sync(&pdev->dev);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "pm runtime get failed, e = %d\n", ret);
+ goto exit_pm_disable;
+ }
+
+ /* Reset controller */
+ tegra_periph_reset_assert(tsd->clk);
+ udelay(2);
+ tegra_periph_reset_deassert(tsd->clk);
+
+ tsd->def_command_reg = SPI_M_S | SPI_CS_SW;
+ tegra_sflash_writel(tsd, tsd->def_command_reg, SPI_COMMAND);
+ pm_runtime_put(&pdev->dev);
+
+ master->dev.of_node = pdev->dev.of_node;
+ ret = spi_register_master(master);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "can not register to master err %d\n", ret);
+ goto exit_pm_disable;
+ }
+ return ret;
+
+exit_pm_disable:
+ pm_runtime_disable(&pdev->dev);
+ if (!pm_runtime_status_suspended(&pdev->dev))
+ tegra_sflash_runtime_suspend(&pdev->dev);
+exit_free_irq:
+ free_irq(tsd->irq, tsd);
+exit_free_master:
+ spi_master_put(master);
+ return ret;
+}
+
+static int tegra_sflash_remove(struct platform_device *pdev)
+{
+ struct spi_master *master = dev_get_drvdata(&pdev->dev);
+ struct tegra_sflash_data *tsd = spi_master_get_devdata(master);
+
+ free_irq(tsd->irq, tsd);
+ spi_unregister_master(master);
+
+ pm_runtime_disable(&pdev->dev);
+ if (!pm_runtime_status_suspended(&pdev->dev))
+ tegra_sflash_runtime_suspend(&pdev->dev);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int tegra_sflash_suspend(struct device *dev)
+{
+ struct spi_master *master = dev_get_drvdata(dev);
+
+ return spi_master_suspend(master);
+}
+
+static int tegra_sflash_resume(struct device *dev)
+{
+ struct spi_master *master = dev_get_drvdata(dev);
+ struct tegra_sflash_data *tsd = spi_master_get_devdata(master);
+ int ret;
+
+ ret = pm_runtime_get_sync(dev);
+ if (ret < 0) {
+ dev_err(dev, "pm runtime failed, e = %d\n", ret);
+ return ret;
+ }
+ tegra_sflash_writel(tsd, tsd->command_reg, SPI_COMMAND);
+ pm_runtime_put(dev);
+
+ return spi_master_resume(master);
+}
+#endif
+
+static int tegra_sflash_runtime_suspend(struct device *dev)
+{
+ struct spi_master *master = dev_get_drvdata(dev);
+ struct tegra_sflash_data *tsd = spi_master_get_devdata(master);
+
+ /* Flush all write which are in PPSB queue by reading back */
+ tegra_sflash_readl(tsd, SPI_COMMAND);
+
+ clk_disable_unprepare(tsd->clk);
+ return 0;
+}
+
+static int tegra_sflash_runtime_resume(struct device *dev)
+{
+ struct spi_master *master = dev_get_drvdata(dev);
+ struct tegra_sflash_data *tsd = spi_master_get_devdata(master);
+ int ret;
+
+ ret = clk_prepare_enable(tsd->clk);
+ if (ret < 0) {
+ dev_err(tsd->dev, "clk_prepare failed: %d\n", ret);
+ return ret;
+ }
+ return 0;
+}
+
+static const struct dev_pm_ops slink_pm_ops = {
+ SET_RUNTIME_PM_OPS(tegra_sflash_runtime_suspend,
+ tegra_sflash_runtime_resume, NULL)
+ SET_SYSTEM_SLEEP_PM_OPS(tegra_sflash_suspend, tegra_sflash_resume)
+};
+static struct platform_driver tegra_sflash_driver = {
+ .driver = {
+ .name = "spi-tegra-sflash",
+ .owner = THIS_MODULE,
+ .pm = &slink_pm_ops,
+ .of_match_table = of_match_ptr(tegra_sflash_of_match),
+ },
+ .probe = tegra_sflash_probe,
+ .remove = tegra_sflash_remove,
+};
+module_platform_driver(tegra_sflash_driver);
+
+MODULE_ALIAS("platform:spi-tegra-sflash");
+MODULE_DESCRIPTION("NVIDIA Tegra20 Serial Flash Controller Driver");
+MODULE_AUTHOR("Laxman Dewangan <ldewangan@nvidia.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/spi/spi-tegra20-slink.c b/drivers/spi/spi-tegra20-slink.c
new file mode 100644
index 000000000000..b8698b389ef3
--- /dev/null
+++ b/drivers/spi/spi-tegra20-slink.c
@@ -0,0 +1,1353 @@
+/*
+ * SPI driver for Nvidia's Tegra20/Tegra30 SLINK Controller.
+ *
+ * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/clk.h>
+#include <linux/completion.h>
+#include <linux/delay.h>
+#include <linux/dmaengine.h>
+#include <linux/dma-mapping.h>
+#include <linux/dmapool.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/kthread.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/spi-tegra.h>
+#include <linux/clk/tegra.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_MODES (SLINK_IDLE_SCLK_MASK | SLINK_CK_SDA)
+
+#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_FIFO_ERROR (SLINK_TX_OVF | SLINK_RX_UNF | \
+ SLINK_TX_UNF | SLINK_RX_OVF)
+
+#define SLINK_FIFO_EMPTY (SLINK_TX_EMPTY | SLINK_RX_EMPTY)
+
+#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) & 0x3f0000) >> 16)
+#define SLINK_SS_HOLD_TIME(val) (((val) & 0xF) << 6)
+
+#define SLINK_TX_FIFO 0x100
+#define SLINK_RX_FIFO 0x180
+
+#define DATA_DIR_TX (1 << 0)
+#define DATA_DIR_RX (1 << 1)
+
+#define SLINK_DMA_TIMEOUT (msecs_to_jiffies(1000))
+
+#define DEFAULT_SPI_DMA_BUF_LEN (16*1024)
+#define TX_FIFO_EMPTY_COUNT_MAX SLINK_TX_FIFO_EMPTY_COUNT(0x20)
+#define RX_FIFO_FULL_COUNT_ZERO SLINK_RX_FIFO_FULL_COUNT(0)
+
+#define SLINK_STATUS2_RESET \
+ (TX_FIFO_EMPTY_COUNT_MAX | RX_FIFO_FULL_COUNT_ZERO << 16)
+
+#define MAX_CHIP_SELECT 4
+#define SLINK_FIFO_DEPTH 32
+
+struct tegra_slink_chip_data {
+ bool cs_hold_time;
+};
+
+struct tegra_slink_data {
+ struct device *dev;
+ struct spi_master *master;
+ const struct tegra_slink_chip_data *chip_data;
+ spinlock_t lock;
+
+ struct clk *clk;
+ void __iomem *base;
+ phys_addr_t phys;
+ unsigned irq;
+ int dma_req_sel;
+ u32 spi_max_frequency;
+ u32 cur_speed;
+
+ struct spi_device *cur_spi;
+ unsigned cur_pos;
+ unsigned cur_len;
+ unsigned words_per_32bit;
+ unsigned bytes_per_word;
+ unsigned curr_dma_words;
+ unsigned cur_direction;
+
+ unsigned cur_rx_pos;
+ unsigned cur_tx_pos;
+
+ unsigned dma_buf_size;
+ unsigned max_buf_size;
+ bool is_curr_dma_xfer;
+ bool is_hw_based_cs;
+
+ struct completion rx_dma_complete;
+ struct completion tx_dma_complete;
+
+ u32 tx_status;
+ u32 rx_status;
+ u32 status_reg;
+ bool is_packed;
+ unsigned long packed_size;
+
+ u32 command_reg;
+ u32 command2_reg;
+ u32 dma_control_reg;
+ u32 def_command_reg;
+ u32 def_command2_reg;
+
+ struct completion xfer_completion;
+ struct spi_transfer *curr_xfer;
+ struct dma_chan *rx_dma_chan;
+ u32 *rx_dma_buf;
+ dma_addr_t rx_dma_phys;
+ struct dma_async_tx_descriptor *rx_dma_desc;
+
+ struct dma_chan *tx_dma_chan;
+ u32 *tx_dma_buf;
+ dma_addr_t tx_dma_phys;
+ struct dma_async_tx_descriptor *tx_dma_desc;
+};
+
+static int tegra_slink_runtime_suspend(struct device *dev);
+static int tegra_slink_runtime_resume(struct device *dev);
+
+static inline unsigned long tegra_slink_readl(struct tegra_slink_data *tspi,
+ unsigned long reg)
+{
+ return readl(tspi->base + reg);
+}
+
+static inline void tegra_slink_writel(struct tegra_slink_data *tspi,
+ unsigned long val, unsigned long reg)
+{
+ writel(val, tspi->base + reg);
+
+ /* Read back register to make sure that register writes completed */
+ if (reg != SLINK_TX_FIFO)
+ readl(tspi->base + SLINK_MAS_DATA);
+}
+
+static void tegra_slink_clear_status(struct tegra_slink_data *tspi)
+{
+ unsigned long val;
+ unsigned long val_write = 0;
+
+ val = tegra_slink_readl(tspi, SLINK_STATUS);
+
+ /* Write 1 to clear status register */
+ val_write = SLINK_RDY | SLINK_FIFO_ERROR;
+ tegra_slink_writel(tspi, val_write, SLINK_STATUS);
+}
+
+static unsigned long tegra_slink_get_packed_size(struct tegra_slink_data *tspi,
+ struct spi_transfer *t)
+{
+ unsigned long val;
+
+ switch (tspi->bytes_per_word) {
+ case 0:
+ val = SLINK_PACK_SIZE_4;
+ break;
+ case 1:
+ val = SLINK_PACK_SIZE_8;
+ break;
+ case 2:
+ val = SLINK_PACK_SIZE_16;
+ break;
+ case 4:
+ val = SLINK_PACK_SIZE_32;
+ break;
+ default:
+ val = 0;
+ }
+ return val;
+}
+
+static unsigned tegra_slink_calculate_curr_xfer_param(
+ struct spi_device *spi, struct tegra_slink_data *tspi,
+ struct spi_transfer *t)
+{
+ unsigned remain_len = t->len - tspi->cur_pos;
+ unsigned max_word;
+ unsigned bits_per_word ;
+ unsigned max_len;
+ unsigned total_fifo_words;
+
+ bits_per_word = t->bits_per_word;
+ tspi->bytes_per_word = (bits_per_word - 1) / 8 + 1;
+
+ if (bits_per_word == 8 || bits_per_word == 16) {
+ tspi->is_packed = 1;
+ tspi->words_per_32bit = 32/bits_per_word;
+ } else {
+ tspi->is_packed = 0;
+ tspi->words_per_32bit = 1;
+ }
+ tspi->packed_size = tegra_slink_get_packed_size(tspi, t);
+
+ if (tspi->is_packed) {
+ max_len = min(remain_len, tspi->max_buf_size);
+ tspi->curr_dma_words = max_len/tspi->bytes_per_word;
+ total_fifo_words = max_len/4;
+ } else {
+ max_word = (remain_len - 1) / tspi->bytes_per_word + 1;
+ max_word = min(max_word, tspi->max_buf_size/4);
+ tspi->curr_dma_words = max_word;
+ total_fifo_words = max_word;
+ }
+ return total_fifo_words;
+}
+
+static unsigned tegra_slink_fill_tx_fifo_from_client_txbuf(
+ struct tegra_slink_data *tspi, struct spi_transfer *t)
+{
+ unsigned nbytes;
+ unsigned tx_empty_count;
+ unsigned long fifo_status;
+ unsigned max_n_32bit;
+ unsigned i, count;
+ unsigned long x;
+ unsigned int written_words;
+ unsigned fifo_words_left;
+ u8 *tx_buf = (u8 *)t->tx_buf + tspi->cur_tx_pos;
+
+ fifo_status = tegra_slink_readl(tspi, SLINK_STATUS2);
+ tx_empty_count = SLINK_TX_FIFO_EMPTY_COUNT(fifo_status);
+
+ if (tspi->is_packed) {
+ fifo_words_left = tx_empty_count * tspi->words_per_32bit;
+ written_words = min(fifo_words_left, tspi->curr_dma_words);
+ nbytes = written_words * tspi->bytes_per_word;
+ max_n_32bit = DIV_ROUND_UP(nbytes, 4);
+ for (count = 0; count < max_n_32bit; count++) {
+ x = 0;
+ for (i = 0; (i < 4) && nbytes; i++, nbytes--)
+ x |= (*tx_buf++) << (i*8);
+ tegra_slink_writel(tspi, x, SLINK_TX_FIFO);
+ }
+ } else {
+ max_n_32bit = min(tspi->curr_dma_words, tx_empty_count);
+ written_words = max_n_32bit;
+ nbytes = written_words * tspi->bytes_per_word;
+ for (count = 0; count < max_n_32bit; count++) {
+ x = 0;
+ for (i = 0; nbytes && (i < tspi->bytes_per_word);
+ i++, nbytes--)
+ x |= ((*tx_buf++) << i*8);
+ tegra_slink_writel(tspi, x, SLINK_TX_FIFO);
+ }
+ }
+ tspi->cur_tx_pos += written_words * tspi->bytes_per_word;
+ return written_words;
+}
+
+static unsigned int tegra_slink_read_rx_fifo_to_client_rxbuf(
+ struct tegra_slink_data *tspi, struct spi_transfer *t)
+{
+ unsigned rx_full_count;
+ unsigned long fifo_status;
+ unsigned i, count;
+ unsigned long x;
+ unsigned int read_words = 0;
+ unsigned len;
+ u8 *rx_buf = (u8 *)t->rx_buf + tspi->cur_rx_pos;
+
+ fifo_status = tegra_slink_readl(tspi, SLINK_STATUS2);
+ rx_full_count = SLINK_RX_FIFO_FULL_COUNT(fifo_status);
+ if (tspi->is_packed) {
+ len = tspi->curr_dma_words * tspi->bytes_per_word;
+ for (count = 0; count < rx_full_count; count++) {
+ x = tegra_slink_readl(tspi, SLINK_RX_FIFO);
+ for (i = 0; len && (i < 4); i++, len--)
+ *rx_buf++ = (x >> i*8) & 0xFF;
+ }
+ tspi->cur_rx_pos += tspi->curr_dma_words * tspi->bytes_per_word;
+ read_words += tspi->curr_dma_words;
+ } else {
+ unsigned int bits_per_word;
+
+ bits_per_word = t->bits_per_word;
+ for (count = 0; count < rx_full_count; count++) {
+ x = tegra_slink_readl(tspi, SLINK_RX_FIFO);
+ for (i = 0; (i < tspi->bytes_per_word); i++)
+ *rx_buf++ = (x >> (i*8)) & 0xFF;
+ }
+ tspi->cur_rx_pos += rx_full_count * tspi->bytes_per_word;
+ read_words += rx_full_count;
+ }
+ return read_words;
+}
+
+static void tegra_slink_copy_client_txbuf_to_spi_txbuf(
+ struct tegra_slink_data *tspi, struct spi_transfer *t)
+{
+ unsigned len;
+
+ /* Make the dma buffer to read by cpu */
+ dma_sync_single_for_cpu(tspi->dev, tspi->tx_dma_phys,
+ tspi->dma_buf_size, DMA_TO_DEVICE);
+
+ if (tspi->is_packed) {
+ len = tspi->curr_dma_words * tspi->bytes_per_word;
+ memcpy(tspi->tx_dma_buf, t->tx_buf + tspi->cur_pos, len);
+ } else {
+ unsigned int i;
+ unsigned int count;
+ u8 *tx_buf = (u8 *)t->tx_buf + tspi->cur_tx_pos;
+ unsigned consume = tspi->curr_dma_words * tspi->bytes_per_word;
+ unsigned int x;
+
+ for (count = 0; count < tspi->curr_dma_words; count++) {
+ x = 0;
+ for (i = 0; consume && (i < tspi->bytes_per_word);
+ i++, consume--)
+ x |= ((*tx_buf++) << i * 8);
+ tspi->tx_dma_buf[count] = x;
+ }
+ }
+ tspi->cur_tx_pos += tspi->curr_dma_words * tspi->bytes_per_word;
+
+ /* Make the dma buffer to read by dma */
+ dma_sync_single_for_device(tspi->dev, tspi->tx_dma_phys,
+ tspi->dma_buf_size, DMA_TO_DEVICE);
+}
+
+static void tegra_slink_copy_spi_rxbuf_to_client_rxbuf(
+ struct tegra_slink_data *tspi, struct spi_transfer *t)
+{
+ unsigned len;
+
+ /* Make the dma buffer to read by cpu */
+ dma_sync_single_for_cpu(tspi->dev, tspi->rx_dma_phys,
+ tspi->dma_buf_size, DMA_FROM_DEVICE);
+
+ if (tspi->is_packed) {
+ len = tspi->curr_dma_words * tspi->bytes_per_word;
+ memcpy(t->rx_buf + tspi->cur_rx_pos, tspi->rx_dma_buf, len);
+ } else {
+ unsigned int i;
+ unsigned int count;
+ unsigned char *rx_buf = t->rx_buf + tspi->cur_rx_pos;
+ unsigned int x;
+ unsigned int rx_mask, bits_per_word;
+
+ bits_per_word = t->bits_per_word;
+ rx_mask = (1 << bits_per_word) - 1;
+ for (count = 0; count < tspi->curr_dma_words; count++) {
+ x = tspi->rx_dma_buf[count];
+ x &= rx_mask;
+ for (i = 0; (i < tspi->bytes_per_word); i++)
+ *rx_buf++ = (x >> (i*8)) & 0xFF;
+ }
+ }
+ tspi->cur_rx_pos += tspi->curr_dma_words * tspi->bytes_per_word;
+
+ /* Make the dma buffer to read by dma */
+ dma_sync_single_for_device(tspi->dev, tspi->rx_dma_phys,
+ tspi->dma_buf_size, DMA_FROM_DEVICE);
+}
+
+static void tegra_slink_dma_complete(void *args)
+{
+ struct completion *dma_complete = args;
+
+ complete(dma_complete);
+}
+
+static int tegra_slink_start_tx_dma(struct tegra_slink_data *tspi, int len)
+{
+ INIT_COMPLETION(tspi->tx_dma_complete);
+ tspi->tx_dma_desc = dmaengine_prep_slave_single(tspi->tx_dma_chan,
+ tspi->tx_dma_phys, len, DMA_MEM_TO_DEV,
+ DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+ if (!tspi->tx_dma_desc) {
+ dev_err(tspi->dev, "Not able to get desc for Tx\n");
+ return -EIO;
+ }
+
+ tspi->tx_dma_desc->callback = tegra_slink_dma_complete;
+ tspi->tx_dma_desc->callback_param = &tspi->tx_dma_complete;
+
+ dmaengine_submit(tspi->tx_dma_desc);
+ dma_async_issue_pending(tspi->tx_dma_chan);
+ return 0;
+}
+
+static int tegra_slink_start_rx_dma(struct tegra_slink_data *tspi, int len)
+{
+ INIT_COMPLETION(tspi->rx_dma_complete);
+ tspi->rx_dma_desc = dmaengine_prep_slave_single(tspi->rx_dma_chan,
+ tspi->rx_dma_phys, len, DMA_DEV_TO_MEM,
+ DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+ if (!tspi->rx_dma_desc) {
+ dev_err(tspi->dev, "Not able to get desc for Rx\n");
+ return -EIO;
+ }
+
+ tspi->rx_dma_desc->callback = tegra_slink_dma_complete;
+ tspi->rx_dma_desc->callback_param = &tspi->rx_dma_complete;
+
+ dmaengine_submit(tspi->rx_dma_desc);
+ dma_async_issue_pending(tspi->rx_dma_chan);
+ return 0;
+}
+
+static int tegra_slink_start_dma_based_transfer(
+ struct tegra_slink_data *tspi, struct spi_transfer *t)
+{
+ unsigned long val;
+ unsigned long test_val;
+ unsigned int len;
+ int ret = 0;
+ unsigned long status;
+
+ /* Make sure that Rx and Tx fifo are empty */
+ status = tegra_slink_readl(tspi, SLINK_STATUS);
+ if ((status & SLINK_FIFO_EMPTY) != SLINK_FIFO_EMPTY) {
+ dev_err(tspi->dev,
+ "Rx/Tx fifo are not empty status 0x%08lx\n", status);
+ return -EIO;
+ }
+
+ val = SLINK_DMA_BLOCK_SIZE(tspi->curr_dma_words - 1);
+ val |= tspi->packed_size;
+ if (tspi->is_packed)
+ len = DIV_ROUND_UP(tspi->curr_dma_words * tspi->bytes_per_word,
+ 4) * 4;
+ else
+ len = tspi->curr_dma_words * 4;
+
+ /* Set attention level based on length of transfer */
+ if (len & 0xF)
+ val |= SLINK_TX_TRIG_1 | SLINK_RX_TRIG_1;
+ else if (((len) >> 4) & 0x1)
+ val |= SLINK_TX_TRIG_4 | SLINK_RX_TRIG_4;
+ else
+ val |= SLINK_TX_TRIG_8 | SLINK_RX_TRIG_8;
+
+ if (tspi->cur_direction & DATA_DIR_TX)
+ val |= SLINK_IE_TXC;
+
+ if (tspi->cur_direction & DATA_DIR_RX)
+ val |= SLINK_IE_RXC;
+
+ tegra_slink_writel(tspi, val, SLINK_DMA_CTL);
+ tspi->dma_control_reg = val;
+
+ if (tspi->cur_direction & DATA_DIR_TX) {
+ tegra_slink_copy_client_txbuf_to_spi_txbuf(tspi, t);
+ wmb();
+ ret = tegra_slink_start_tx_dma(tspi, len);
+ if (ret < 0) {
+ dev_err(tspi->dev,
+ "Starting tx dma failed, err %d\n", ret);
+ return ret;
+ }
+
+ /* Wait for tx fifo to be fill before starting slink */
+ test_val = tegra_slink_readl(tspi, SLINK_STATUS);
+ while (!(test_val & SLINK_TX_FULL))
+ test_val = tegra_slink_readl(tspi, SLINK_STATUS);
+ }
+
+ if (tspi->cur_direction & DATA_DIR_RX) {
+ /* Make the dma buffer to read by dma */
+ dma_sync_single_for_device(tspi->dev, tspi->rx_dma_phys,
+ tspi->dma_buf_size, DMA_FROM_DEVICE);
+
+ ret = tegra_slink_start_rx_dma(tspi, len);
+ if (ret < 0) {
+ dev_err(tspi->dev,
+ "Starting rx dma failed, err %d\n", ret);
+ if (tspi->cur_direction & DATA_DIR_TX)
+ dmaengine_terminate_all(tspi->tx_dma_chan);
+ return ret;
+ }
+ }
+ tspi->is_curr_dma_xfer = true;
+ if (tspi->is_packed) {
+ val |= SLINK_PACKED;
+ tegra_slink_writel(tspi, val, SLINK_DMA_CTL);
+ /* HW need small delay after settign Packed mode */
+ udelay(1);
+ }
+ tspi->dma_control_reg = val;
+
+ val |= SLINK_DMA_EN;
+ tegra_slink_writel(tspi, val, SLINK_DMA_CTL);
+ return ret;
+}
+
+static int tegra_slink_start_cpu_based_transfer(
+ struct tegra_slink_data *tspi, struct spi_transfer *t)
+{
+ unsigned long val;
+ unsigned cur_words;
+
+ val = tspi->packed_size;
+ if (tspi->cur_direction & DATA_DIR_TX)
+ val |= SLINK_IE_TXC;
+
+ if (tspi->cur_direction & DATA_DIR_RX)
+ val |= SLINK_IE_RXC;
+
+ tegra_slink_writel(tspi, val, SLINK_DMA_CTL);
+ tspi->dma_control_reg = val;
+
+ if (tspi->cur_direction & DATA_DIR_TX)
+ cur_words = tegra_slink_fill_tx_fifo_from_client_txbuf(tspi, t);
+ else
+ cur_words = tspi->curr_dma_words;
+ val |= SLINK_DMA_BLOCK_SIZE(cur_words - 1);
+ tegra_slink_writel(tspi, val, SLINK_DMA_CTL);
+ tspi->dma_control_reg = val;
+
+ tspi->is_curr_dma_xfer = false;
+ if (tspi->is_packed) {
+ val |= SLINK_PACKED;
+ tegra_slink_writel(tspi, val, SLINK_DMA_CTL);
+ udelay(1);
+ wmb();
+ }
+ tspi->dma_control_reg = val;
+ val |= SLINK_DMA_EN;
+ tegra_slink_writel(tspi, val, SLINK_DMA_CTL);
+ return 0;
+}
+
+static int tegra_slink_init_dma_param(struct tegra_slink_data *tspi,
+ bool dma_to_memory)
+{
+ struct dma_chan *dma_chan;
+ u32 *dma_buf;
+ dma_addr_t dma_phys;
+ int ret;
+ struct dma_slave_config dma_sconfig;
+ dma_cap_mask_t mask;
+
+ dma_cap_zero(mask);
+ dma_cap_set(DMA_SLAVE, mask);
+ dma_chan = dma_request_channel(mask, NULL, NULL);
+ if (!dma_chan) {
+ dev_err(tspi->dev,
+ "Dma channel is not available, will try later\n");
+ return -EPROBE_DEFER;
+ }
+
+ dma_buf = dma_alloc_coherent(tspi->dev, tspi->dma_buf_size,
+ &dma_phys, GFP_KERNEL);
+ if (!dma_buf) {
+ dev_err(tspi->dev, " Not able to allocate the dma buffer\n");
+ dma_release_channel(dma_chan);
+ return -ENOMEM;
+ }
+
+ dma_sconfig.slave_id = tspi->dma_req_sel;
+ if (dma_to_memory) {
+ dma_sconfig.src_addr = tspi->phys + SLINK_RX_FIFO;
+ dma_sconfig.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+ dma_sconfig.src_maxburst = 0;
+ } else {
+ dma_sconfig.dst_addr = tspi->phys + SLINK_TX_FIFO;
+ dma_sconfig.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+ dma_sconfig.dst_maxburst = 0;
+ }
+
+ ret = dmaengine_slave_config(dma_chan, &dma_sconfig);
+ if (ret)
+ goto scrub;
+ if (dma_to_memory) {
+ tspi->rx_dma_chan = dma_chan;
+ tspi->rx_dma_buf = dma_buf;
+ tspi->rx_dma_phys = dma_phys;
+ } else {
+ tspi->tx_dma_chan = dma_chan;
+ tspi->tx_dma_buf = dma_buf;
+ tspi->tx_dma_phys = dma_phys;
+ }
+ return 0;
+
+scrub:
+ dma_free_coherent(tspi->dev, tspi->dma_buf_size, dma_buf, dma_phys);
+ dma_release_channel(dma_chan);
+ return ret;
+}
+
+static void tegra_slink_deinit_dma_param(struct tegra_slink_data *tspi,
+ bool dma_to_memory)
+{
+ u32 *dma_buf;
+ dma_addr_t dma_phys;
+ struct dma_chan *dma_chan;
+
+ if (dma_to_memory) {
+ dma_buf = tspi->rx_dma_buf;
+ dma_chan = tspi->rx_dma_chan;
+ dma_phys = tspi->rx_dma_phys;
+ tspi->rx_dma_chan = NULL;
+ tspi->rx_dma_buf = NULL;
+ } else {
+ dma_buf = tspi->tx_dma_buf;
+ dma_chan = tspi->tx_dma_chan;
+ dma_phys = tspi->tx_dma_phys;
+ tspi->tx_dma_buf = NULL;
+ tspi->tx_dma_chan = NULL;
+ }
+ if (!dma_chan)
+ return;
+
+ dma_free_coherent(tspi->dev, tspi->dma_buf_size, dma_buf, dma_phys);
+ dma_release_channel(dma_chan);
+}
+
+static int tegra_slink_start_transfer_one(struct spi_device *spi,
+ struct spi_transfer *t, bool is_first_of_msg,
+ bool is_single_xfer)
+{
+ struct tegra_slink_data *tspi = spi_master_get_devdata(spi->master);
+ u32 speed;
+ u8 bits_per_word;
+ unsigned total_fifo_words;
+ int ret;
+ struct tegra_spi_device_controller_data *cdata = spi->controller_data;
+ unsigned long command;
+ unsigned long command2;
+
+ bits_per_word = t->bits_per_word;
+ speed = t->speed_hz;
+ if (speed != tspi->cur_speed) {
+ clk_set_rate(tspi->clk, speed * 4);
+ tspi->cur_speed = speed;
+ }
+
+ tspi->cur_spi = spi;
+ tspi->cur_pos = 0;
+ tspi->cur_rx_pos = 0;
+ tspi->cur_tx_pos = 0;
+ tspi->curr_xfer = t;
+ total_fifo_words = tegra_slink_calculate_curr_xfer_param(spi, tspi, t);
+
+ if (is_first_of_msg) {
+ tegra_slink_clear_status(tspi);
+
+ command = tspi->def_command_reg;
+ command |= SLINK_BIT_LENGTH(bits_per_word - 1);
+
+ command2 = tspi->def_command2_reg;
+ command2 |= SLINK_SS_EN_CS(spi->chip_select);
+
+ /* possibly use the hw based chip select */
+ tspi->is_hw_based_cs = false;
+ if (cdata && cdata->is_hw_based_cs && is_single_xfer &&
+ ((tspi->curr_dma_words * tspi->bytes_per_word) ==
+ (t->len - tspi->cur_pos))) {
+ int setup_count;
+ int sts2;
+
+ setup_count = cdata->cs_setup_clk_count >> 1;
+ setup_count = max(setup_count, 3);
+ command2 |= SLINK_SS_SETUP(setup_count);
+ if (tspi->chip_data->cs_hold_time) {
+ int hold_count;
+
+ hold_count = cdata->cs_hold_clk_count;
+ hold_count = max(hold_count, 0xF);
+ sts2 = tegra_slink_readl(tspi, SLINK_STATUS2);
+ sts2 &= ~SLINK_SS_HOLD_TIME(0xF);
+ sts2 |= SLINK_SS_HOLD_TIME(hold_count);
+ tegra_slink_writel(tspi, sts2, SLINK_STATUS2);
+ }
+ tspi->is_hw_based_cs = true;
+ }
+
+ if (tspi->is_hw_based_cs)
+ command &= ~SLINK_CS_SW;
+ else
+ command |= SLINK_CS_SW | SLINK_CS_VALUE;
+
+ command &= ~SLINK_MODES;
+ if (spi->mode & SPI_CPHA)
+ command |= SLINK_CK_SDA;
+
+ if (spi->mode & SPI_CPOL)
+ command |= SLINK_IDLE_SCLK_DRIVE_HIGH;
+ else
+ command |= SLINK_IDLE_SCLK_DRIVE_LOW;
+ } else {
+ command = tspi->command_reg;
+ command &= ~SLINK_BIT_LENGTH(~0);
+ command |= SLINK_BIT_LENGTH(bits_per_word - 1);
+
+ command2 = tspi->command2_reg;
+ command2 &= ~(SLINK_RXEN | SLINK_TXEN);
+ }
+
+ tegra_slink_writel(tspi, command, SLINK_COMMAND);
+ tspi->command_reg = command;
+
+ tspi->cur_direction = 0;
+ if (t->rx_buf) {
+ command2 |= SLINK_RXEN;
+ tspi->cur_direction |= DATA_DIR_RX;
+ }
+ if (t->tx_buf) {
+ command2 |= SLINK_TXEN;
+ tspi->cur_direction |= DATA_DIR_TX;
+ }
+ tegra_slink_writel(tspi, command2, SLINK_COMMAND2);
+ tspi->command2_reg = command2;
+
+ if (total_fifo_words > SLINK_FIFO_DEPTH)
+ ret = tegra_slink_start_dma_based_transfer(tspi, t);
+ else
+ ret = tegra_slink_start_cpu_based_transfer(tspi, t);
+ return ret;
+}
+
+static int tegra_slink_setup(struct spi_device *spi)
+{
+ struct tegra_slink_data *tspi = spi_master_get_devdata(spi->master);
+ unsigned long val;
+ unsigned long flags;
+ int ret;
+ unsigned int cs_pol_bit[MAX_CHIP_SELECT] = {
+ SLINK_CS_POLARITY,
+ SLINK_CS_POLARITY1,
+ SLINK_CS_POLARITY2,
+ SLINK_CS_POLARITY3,
+ };
+
+ 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);
+
+ BUG_ON(spi->chip_select >= MAX_CHIP_SELECT);
+
+ /* Set speed to the spi max fequency if spi device has not set */
+ spi->max_speed_hz = spi->max_speed_hz ? : tspi->spi_max_frequency;
+ ret = pm_runtime_get_sync(tspi->dev);
+ if (ret < 0) {
+ dev_err(tspi->dev, "pm runtime failed, e = %d\n", ret);
+ return ret;
+ }
+
+ spin_lock_irqsave(&tspi->lock, flags);
+ val = tspi->def_command_reg;
+ if (spi->mode & SPI_CS_HIGH)
+ val |= cs_pol_bit[spi->chip_select];
+ else
+ val &= ~cs_pol_bit[spi->chip_select];
+ tspi->def_command_reg = val;
+ tegra_slink_writel(tspi, tspi->def_command_reg, SLINK_COMMAND);
+ spin_unlock_irqrestore(&tspi->lock, flags);
+
+ pm_runtime_put(tspi->dev);
+ return 0;
+}
+
+static int tegra_slink_prepare_transfer(struct spi_master *master)
+{
+ struct tegra_slink_data *tspi = spi_master_get_devdata(master);
+
+ return pm_runtime_get_sync(tspi->dev);
+}
+
+static int tegra_slink_unprepare_transfer(struct spi_master *master)
+{
+ struct tegra_slink_data *tspi = spi_master_get_devdata(master);
+
+ pm_runtime_put(tspi->dev);
+ return 0;
+}
+
+static int tegra_slink_transfer_one_message(struct spi_master *master,
+ struct spi_message *msg)
+{
+ bool is_first_msg = true;
+ int single_xfer;
+ struct tegra_slink_data *tspi = spi_master_get_devdata(master);
+ struct spi_transfer *xfer;
+ struct spi_device *spi = msg->spi;
+ int ret;
+
+ msg->status = 0;
+ msg->actual_length = 0;
+ single_xfer = list_is_singular(&msg->transfers);
+ list_for_each_entry(xfer, &msg->transfers, transfer_list) {
+ INIT_COMPLETION(tspi->xfer_completion);
+ ret = tegra_slink_start_transfer_one(spi, xfer,
+ is_first_msg, single_xfer);
+ if (ret < 0) {
+ dev_err(tspi->dev,
+ "spi can not start transfer, err %d\n", ret);
+ goto exit;
+ }
+ is_first_msg = false;
+ ret = wait_for_completion_timeout(&tspi->xfer_completion,
+ SLINK_DMA_TIMEOUT);
+ if (WARN_ON(ret == 0)) {
+ dev_err(tspi->dev,
+ "spi trasfer timeout, err %d\n", ret);
+ ret = -EIO;
+ goto exit;
+ }
+
+ if (tspi->tx_status || tspi->rx_status) {
+ dev_err(tspi->dev, "Error in Transfer\n");
+ ret = -EIO;
+ goto exit;
+ }
+ msg->actual_length += xfer->len;
+ if (xfer->cs_change && xfer->delay_usecs) {
+ tegra_slink_writel(tspi, tspi->def_command_reg,
+ SLINK_COMMAND);
+ udelay(xfer->delay_usecs);
+ }
+ }
+ ret = 0;
+exit:
+ tegra_slink_writel(tspi, tspi->def_command_reg, SLINK_COMMAND);
+ tegra_slink_writel(tspi, tspi->def_command2_reg, SLINK_COMMAND2);
+ msg->status = ret;
+ spi_finalize_current_message(master);
+ return ret;
+}
+
+static irqreturn_t handle_cpu_based_xfer(struct tegra_slink_data *tspi)
+{
+ struct spi_transfer *t = tspi->curr_xfer;
+ unsigned long flags;
+
+ spin_lock_irqsave(&tspi->lock, flags);
+ if (tspi->tx_status || tspi->rx_status ||
+ (tspi->status_reg & SLINK_BSY)) {
+ dev_err(tspi->dev,
+ "CpuXfer ERROR bit set 0x%x\n", tspi->status_reg);
+ dev_err(tspi->dev,
+ "CpuXfer 0x%08x:0x%08x:0x%08x\n", tspi->command_reg,
+ tspi->command2_reg, tspi->dma_control_reg);
+ tegra_periph_reset_assert(tspi->clk);
+ udelay(2);
+ tegra_periph_reset_deassert(tspi->clk);
+ complete(&tspi->xfer_completion);
+ goto exit;
+ }
+
+ if (tspi->cur_direction & DATA_DIR_RX)
+ tegra_slink_read_rx_fifo_to_client_rxbuf(tspi, t);
+
+ if (tspi->cur_direction & DATA_DIR_TX)
+ tspi->cur_pos = tspi->cur_tx_pos;
+ else
+ tspi->cur_pos = tspi->cur_rx_pos;
+
+ if (tspi->cur_pos == t->len) {
+ complete(&tspi->xfer_completion);
+ goto exit;
+ }
+
+ tegra_slink_calculate_curr_xfer_param(tspi->cur_spi, tspi, t);
+ tegra_slink_start_cpu_based_transfer(tspi, t);
+exit:
+ spin_unlock_irqrestore(&tspi->lock, flags);
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t handle_dma_based_xfer(struct tegra_slink_data *tspi)
+{
+ struct spi_transfer *t = tspi->curr_xfer;
+ long wait_status;
+ int err = 0;
+ unsigned total_fifo_words;
+ unsigned long flags;
+
+ /* Abort dmas if any error */
+ if (tspi->cur_direction & DATA_DIR_TX) {
+ if (tspi->tx_status) {
+ dmaengine_terminate_all(tspi->tx_dma_chan);
+ err += 1;
+ } else {
+ wait_status = wait_for_completion_interruptible_timeout(
+ &tspi->tx_dma_complete, SLINK_DMA_TIMEOUT);
+ if (wait_status <= 0) {
+ dmaengine_terminate_all(tspi->tx_dma_chan);
+ dev_err(tspi->dev, "TxDma Xfer failed\n");
+ err += 1;
+ }
+ }
+ }
+
+ if (tspi->cur_direction & DATA_DIR_RX) {
+ if (tspi->rx_status) {
+ dmaengine_terminate_all(tspi->rx_dma_chan);
+ err += 2;
+ } else {
+ wait_status = wait_for_completion_interruptible_timeout(
+ &tspi->rx_dma_complete, SLINK_DMA_TIMEOUT);
+ if (wait_status <= 0) {
+ dmaengine_terminate_all(tspi->rx_dma_chan);
+ dev_err(tspi->dev, "RxDma Xfer failed\n");
+ err += 2;
+ }
+ }
+ }
+
+ spin_lock_irqsave(&tspi->lock, flags);
+ if (err) {
+ dev_err(tspi->dev,
+ "DmaXfer: ERROR bit set 0x%x\n", tspi->status_reg);
+ dev_err(tspi->dev,
+ "DmaXfer 0x%08x:0x%08x:0x%08x\n", tspi->command_reg,
+ tspi->command2_reg, tspi->dma_control_reg);
+ tegra_periph_reset_assert(tspi->clk);
+ udelay(2);
+ tegra_periph_reset_deassert(tspi->clk);
+ complete(&tspi->xfer_completion);
+ spin_unlock_irqrestore(&tspi->lock, flags);
+ return IRQ_HANDLED;
+ }
+
+ if (tspi->cur_direction & DATA_DIR_RX)
+ tegra_slink_copy_spi_rxbuf_to_client_rxbuf(tspi, t);
+
+ if (tspi->cur_direction & DATA_DIR_TX)
+ tspi->cur_pos = tspi->cur_tx_pos;
+ else
+ tspi->cur_pos = tspi->cur_rx_pos;
+
+ if (tspi->cur_pos == t->len) {
+ complete(&tspi->xfer_completion);
+ goto exit;
+ }
+
+ /* Continue transfer in current message */
+ total_fifo_words = tegra_slink_calculate_curr_xfer_param(tspi->cur_spi,
+ tspi, t);
+ if (total_fifo_words > SLINK_FIFO_DEPTH)
+ err = tegra_slink_start_dma_based_transfer(tspi, t);
+ else
+ err = tegra_slink_start_cpu_based_transfer(tspi, t);
+
+exit:
+ spin_unlock_irqrestore(&tspi->lock, flags);
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t tegra_slink_isr_thread(int irq, void *context_data)
+{
+ struct tegra_slink_data *tspi = context_data;
+
+ if (!tspi->is_curr_dma_xfer)
+ return handle_cpu_based_xfer(tspi);
+ return handle_dma_based_xfer(tspi);
+}
+
+static irqreturn_t tegra_slink_isr(int irq, void *context_data)
+{
+ struct tegra_slink_data *tspi = context_data;
+
+ tspi->status_reg = tegra_slink_readl(tspi, SLINK_STATUS);
+ if (tspi->cur_direction & DATA_DIR_TX)
+ tspi->tx_status = tspi->status_reg &
+ (SLINK_TX_OVF | SLINK_TX_UNF);
+
+ if (tspi->cur_direction & DATA_DIR_RX)
+ tspi->rx_status = tspi->status_reg &
+ (SLINK_RX_OVF | SLINK_RX_UNF);
+ tegra_slink_clear_status(tspi);
+
+ return IRQ_WAKE_THREAD;
+}
+
+static struct tegra_spi_platform_data *tegra_slink_parse_dt(
+ struct platform_device *pdev)
+{
+ struct tegra_spi_platform_data *pdata;
+ const unsigned int *prop;
+ struct device_node *np = pdev->dev.of_node;
+ u32 of_dma[2];
+
+ pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
+ if (!pdata) {
+ dev_err(&pdev->dev, "Memory alloc for pdata failed\n");
+ return NULL;
+ }
+
+ if (of_property_read_u32_array(np, "nvidia,dma-request-selector",
+ of_dma, 2) >= 0)
+ pdata->dma_req_sel = of_dma[1];
+
+ prop = of_get_property(np, "spi-max-frequency", NULL);
+ if (prop)
+ pdata->spi_max_frequency = be32_to_cpup(prop);
+
+ return pdata;
+}
+
+const struct tegra_slink_chip_data tegra30_spi_cdata = {
+ .cs_hold_time = true,
+};
+
+const struct tegra_slink_chip_data tegra20_spi_cdata = {
+ .cs_hold_time = false,
+};
+
+static struct of_device_id tegra_slink_of_match[] = {
+ { .compatible = "nvidia,tegra30-slink", .data = &tegra30_spi_cdata, },
+ { .compatible = "nvidia,tegra20-slink", .data = &tegra20_spi_cdata, },
+ {}
+};
+MODULE_DEVICE_TABLE(of, tegra_slink_of_match);
+
+static int tegra_slink_probe(struct platform_device *pdev)
+{
+ struct spi_master *master;
+ struct tegra_slink_data *tspi;
+ struct resource *r;
+ struct tegra_spi_platform_data *pdata = pdev->dev.platform_data;
+ int ret, spi_irq;
+ const struct tegra_slink_chip_data *cdata = NULL;
+ const struct of_device_id *match;
+
+ match = of_match_device(of_match_ptr(tegra_slink_of_match), &pdev->dev);
+ if (!match) {
+ dev_err(&pdev->dev, "Error: No device match found\n");
+ return -ENODEV;
+ }
+ cdata = match->data;
+ if (!pdata && pdev->dev.of_node)
+ pdata = tegra_slink_parse_dt(pdev);
+
+ if (!pdata) {
+ dev_err(&pdev->dev, "No platform data, exiting\n");
+ return -ENODEV;
+ }
+
+ if (!pdata->spi_max_frequency)
+ pdata->spi_max_frequency = 25000000; /* 25MHz */
+
+ master = spi_alloc_master(&pdev->dev, sizeof(*tspi));
+ if (!master) {
+ 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->setup = tegra_slink_setup;
+ master->prepare_transfer_hardware = tegra_slink_prepare_transfer;
+ master->transfer_one_message = tegra_slink_transfer_one_message;
+ master->unprepare_transfer_hardware = tegra_slink_unprepare_transfer;
+ master->num_chipselect = MAX_CHIP_SELECT;
+ master->bus_num = -1;
+
+ dev_set_drvdata(&pdev->dev, master);
+ tspi = spi_master_get_devdata(master);
+ tspi->master = master;
+ tspi->dma_req_sel = pdata->dma_req_sel;
+ tspi->dev = &pdev->dev;
+ tspi->chip_data = cdata;
+ spin_lock_init(&tspi->lock);
+
+ r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!r) {
+ dev_err(&pdev->dev, "No IO memory resource\n");
+ ret = -ENODEV;
+ goto exit_free_master;
+ }
+ tspi->phys = r->start;
+ tspi->base = devm_ioremap_resource(&pdev->dev, r);
+ if (IS_ERR(tspi->base)) {
+ ret = PTR_ERR(tspi->base);
+ goto exit_free_master;
+ }
+
+ spi_irq = platform_get_irq(pdev, 0);
+ tspi->irq = spi_irq;
+ ret = request_threaded_irq(tspi->irq, tegra_slink_isr,
+ tegra_slink_isr_thread, IRQF_ONESHOT,
+ dev_name(&pdev->dev), tspi);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "Failed to register ISR for IRQ %d\n",
+ tspi->irq);
+ goto exit_free_master;
+ }
+
+ tspi->clk = devm_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 exit_free_irq;
+ }
+
+ tspi->max_buf_size = SLINK_FIFO_DEPTH << 2;
+ tspi->dma_buf_size = DEFAULT_SPI_DMA_BUF_LEN;
+ tspi->spi_max_frequency = pdata->spi_max_frequency;
+
+ if (pdata->dma_req_sel) {
+ ret = tegra_slink_init_dma_param(tspi, true);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "RxDma Init failed, err %d\n", ret);
+ goto exit_free_irq;
+ }
+
+ ret = tegra_slink_init_dma_param(tspi, false);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "TxDma Init failed, err %d\n", ret);
+ goto exit_rx_dma_free;
+ }
+ tspi->max_buf_size = tspi->dma_buf_size;
+ init_completion(&tspi->tx_dma_complete);
+ init_completion(&tspi->rx_dma_complete);
+ }
+
+ init_completion(&tspi->xfer_completion);
+
+ pm_runtime_enable(&pdev->dev);
+ if (!pm_runtime_enabled(&pdev->dev)) {
+ ret = tegra_slink_runtime_resume(&pdev->dev);
+ if (ret)
+ goto exit_pm_disable;
+ }
+
+ ret = pm_runtime_get_sync(&pdev->dev);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "pm runtime get failed, e = %d\n", ret);
+ goto exit_pm_disable;
+ }
+ tspi->def_command_reg = SLINK_M_S;
+ tspi->def_command2_reg = SLINK_CS_ACTIVE_BETWEEN;
+ tegra_slink_writel(tspi, tspi->def_command_reg, SLINK_COMMAND);
+ tegra_slink_writel(tspi, tspi->def_command2_reg, SLINK_COMMAND2);
+ pm_runtime_put(&pdev->dev);
+
+ master->dev.of_node = pdev->dev.of_node;
+ ret = spi_register_master(master);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "can not register to master err %d\n", ret);
+ goto exit_pm_disable;
+ }
+ return ret;
+
+exit_pm_disable:
+ pm_runtime_disable(&pdev->dev);
+ if (!pm_runtime_status_suspended(&pdev->dev))
+ tegra_slink_runtime_suspend(&pdev->dev);
+ tegra_slink_deinit_dma_param(tspi, false);
+exit_rx_dma_free:
+ tegra_slink_deinit_dma_param(tspi, true);
+exit_free_irq:
+ free_irq(spi_irq, tspi);
+exit_free_master:
+ spi_master_put(master);
+ return ret;
+}
+
+static int tegra_slink_remove(struct platform_device *pdev)
+{
+ struct spi_master *master = dev_get_drvdata(&pdev->dev);
+ struct tegra_slink_data *tspi = spi_master_get_devdata(master);
+
+ free_irq(tspi->irq, tspi);
+ spi_unregister_master(master);
+
+ if (tspi->tx_dma_chan)
+ tegra_slink_deinit_dma_param(tspi, false);
+
+ if (tspi->rx_dma_chan)
+ tegra_slink_deinit_dma_param(tspi, true);
+
+ pm_runtime_disable(&pdev->dev);
+ if (!pm_runtime_status_suspended(&pdev->dev))
+ tegra_slink_runtime_suspend(&pdev->dev);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int tegra_slink_suspend(struct device *dev)
+{
+ struct spi_master *master = dev_get_drvdata(dev);
+
+ return spi_master_suspend(master);
+}
+
+static int tegra_slink_resume(struct device *dev)
+{
+ struct spi_master *master = dev_get_drvdata(dev);
+ struct tegra_slink_data *tspi = spi_master_get_devdata(master);
+ int ret;
+
+ ret = pm_runtime_get_sync(dev);
+ if (ret < 0) {
+ dev_err(dev, "pm runtime failed, e = %d\n", ret);
+ return ret;
+ }
+ tegra_slink_writel(tspi, tspi->command_reg, SLINK_COMMAND);
+ tegra_slink_writel(tspi, tspi->command2_reg, SLINK_COMMAND2);
+ pm_runtime_put(dev);
+
+ return spi_master_resume(master);
+}
+#endif
+
+static int tegra_slink_runtime_suspend(struct device *dev)
+{
+ struct spi_master *master = dev_get_drvdata(dev);
+ struct tegra_slink_data *tspi = spi_master_get_devdata(master);
+
+ /* Flush all write which are in PPSB queue by reading back */
+ tegra_slink_readl(tspi, SLINK_MAS_DATA);
+
+ clk_disable_unprepare(tspi->clk);
+ return 0;
+}
+
+static int tegra_slink_runtime_resume(struct device *dev)
+{
+ struct spi_master *master = dev_get_drvdata(dev);
+ struct tegra_slink_data *tspi = spi_master_get_devdata(master);
+ int ret;
+
+ ret = clk_prepare_enable(tspi->clk);
+ if (ret < 0) {
+ dev_err(tspi->dev, "clk_prepare failed: %d\n", ret);
+ return ret;
+ }
+ return 0;
+}
+
+static const struct dev_pm_ops slink_pm_ops = {
+ SET_RUNTIME_PM_OPS(tegra_slink_runtime_suspend,
+ tegra_slink_runtime_resume, NULL)
+ SET_SYSTEM_SLEEP_PM_OPS(tegra_slink_suspend, tegra_slink_resume)
+};
+static struct platform_driver tegra_slink_driver = {
+ .driver = {
+ .name = "spi-tegra-slink",
+ .owner = THIS_MODULE,
+ .pm = &slink_pm_ops,
+ .of_match_table = of_match_ptr(tegra_slink_of_match),
+ },
+ .probe = tegra_slink_probe,
+ .remove = tegra_slink_remove,
+};
+module_platform_driver(tegra_slink_driver);
+
+MODULE_ALIAS("platform:spi-tegra-slink");
+MODULE_DESCRIPTION("NVIDIA Tegra20/Tegra30 SLINK Controller Driver");
+MODULE_AUTHOR("Laxman Dewangan <ldewangan@nvidia.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/spi/spi-ti-ssp.c b/drivers/spi/spi-ti-ssp.c
index 3f6f6e81c655..46992cab65f1 100644
--- a/drivers/spi/spi-ti-ssp.c
+++ b/drivers/spi/spi-ti-ssp.c
@@ -289,7 +289,7 @@ error_unlock:
return error;
}
-static int __devinit ti_ssp_spi_probe(struct platform_device *pdev)
+static int ti_ssp_spi_probe(struct platform_device *pdev)
{
const struct ti_ssp_spi_data *pdata;
struct ti_ssp_spi *hw;
@@ -357,7 +357,7 @@ error_wq:
return error;
}
-static int __devexit ti_ssp_spi_remove(struct platform_device *pdev)
+static int ti_ssp_spi_remove(struct platform_device *pdev)
{
struct ti_ssp_spi *hw = platform_get_drvdata(pdev);
int error;
@@ -378,7 +378,7 @@ static int __devexit ti_ssp_spi_remove(struct platform_device *pdev)
static struct platform_driver ti_ssp_spi_driver = {
.probe = ti_ssp_spi_probe,
- .remove = __devexit_p(ti_ssp_spi_remove),
+ .remove = ti_ssp_spi_remove,
.driver = {
.name = "ti-ssp-spi",
.owner = THIS_MODULE,
diff --git a/drivers/spi/spi-tle62x0.c b/drivers/spi/spi-tle62x0.c
index 24421024deaf..6b0874d782ed 100644
--- a/drivers/spi/spi-tle62x0.c
+++ b/drivers/spi/spi-tle62x0.c
@@ -240,7 +240,7 @@ static int to_gpio_num(struct device_attribute *attr)
return -1;
}
-static int __devinit tle62x0_probe(struct spi_device *spi)
+static int tle62x0_probe(struct spi_device *spi)
{
struct tle62x0_state *st;
struct tle62x0_pdata *pdata;
@@ -294,7 +294,7 @@ static int __devinit tle62x0_probe(struct spi_device *spi)
return ret;
}
-static int __devexit tle62x0_remove(struct spi_device *spi)
+static int tle62x0_remove(struct spi_device *spi)
{
struct tle62x0_state *st = spi_get_drvdata(spi);
int ptr;
@@ -313,7 +313,7 @@ static struct spi_driver tle62x0_driver = {
.owner = THIS_MODULE,
},
.probe = tle62x0_probe,
- .remove = __devexit_p(tle62x0_remove),
+ .remove = tle62x0_remove,
};
module_spi_driver(tle62x0_driver);
diff --git a/drivers/spi/spi-topcliff-pch.c b/drivers/spi/spi-topcliff-pch.c
index 135f7406f4bf..f756481b0fea 100644
--- a/drivers/spi/spi-topcliff-pch.c
+++ b/drivers/spi/spi-topcliff-pch.c
@@ -1401,7 +1401,7 @@ static void pch_alloc_dma_buf(struct pch_spi_board_data *board_dat,
PCH_BUF_SIZE, &dma->rx_buf_dma, GFP_KERNEL);
}
-static int __devinit pch_spi_pd_probe(struct platform_device *plat_dev)
+static int pch_spi_pd_probe(struct platform_device *plat_dev)
{
int ret;
struct spi_master *master;
@@ -1498,7 +1498,7 @@ err_pci_iomap:
return ret;
}
-static int __devexit pch_spi_pd_remove(struct platform_device *plat_dev)
+static int pch_spi_pd_remove(struct platform_device *plat_dev)
{
struct pch_spi_board_data *board_dat = dev_get_platdata(&plat_dev->dev);
struct pch_spi_data *data = platform_get_drvdata(plat_dev);
@@ -1619,12 +1619,12 @@ static struct platform_driver pch_spi_pd_driver = {
.owner = THIS_MODULE,
},
.probe = pch_spi_pd_probe,
- .remove = __devexit_p(pch_spi_pd_remove),
+ .remove = pch_spi_pd_remove,
.suspend = pch_spi_pd_suspend,
.resume = pch_spi_pd_resume
};
-static int __devinit pch_spi_probe(struct pci_dev *pdev,
+static int pch_spi_probe(struct pci_dev *pdev,
const struct pci_device_id *id)
{
struct pch_spi_board_data *board_dat;
@@ -1705,7 +1705,7 @@ err_no_mem:
return retval;
}
-static void __devexit pch_spi_remove(struct pci_dev *pdev)
+static void pch_spi_remove(struct pci_dev *pdev)
{
int i;
struct pch_pd_dev_save *pd_dev_save = pci_get_drvdata(pdev);
@@ -1776,7 +1776,7 @@ static struct pci_driver pch_spi_pcidev_driver = {
.name = "pch_spi",
.id_table = pch_spi_pcidev_id,
.probe = pch_spi_probe,
- .remove = __devexit_p(pch_spi_remove),
+ .remove = pch_spi_remove,
.suspend = pch_spi_suspend,
.resume = pch_spi_resume,
};
diff --git a/drivers/spi/spi-txx9.c b/drivers/spi/spi-txx9.c
index d5a3cbb646cb..adb853047926 100644
--- a/drivers/spi/spi-txx9.c
+++ b/drivers/spi/spi-txx9.c
@@ -189,9 +189,8 @@ static void txx9spi_work_one(struct txx9spi *c, struct spi_message *m)
unsigned int len = t->len;
unsigned int wsize;
u32 speed_hz = t->speed_hz ? : spi->max_speed_hz;
- u8 bits_per_word = t->bits_per_word ? : spi->bits_per_word;
+ u8 bits_per_word = t->bits_per_word;
- bits_per_word = bits_per_word ? : 8;
wsize = bits_per_word >> 3; /* in bytes */
if (prev_speed_hz != speed_hz
@@ -316,9 +315,8 @@ static int txx9spi_transfer(struct spi_device *spi, struct spi_message *m)
/* check each transfer's parameters */
list_for_each_entry (t, &m->transfers, transfer_list) {
u32 speed_hz = t->speed_hz ? : spi->max_speed_hz;
- u8 bits_per_word = t->bits_per_word ? : spi->bits_per_word;
+ u8 bits_per_word = t->bits_per_word;
- bits_per_word = bits_per_word ? : 8;
if (!t->tx_buf && !t->rx_buf && t->len)
return -EINVAL;
if (bits_per_word != 8 && bits_per_word != 16)
@@ -337,7 +335,7 @@ static int txx9spi_transfer(struct spi_device *spi, struct spi_message *m)
return 0;
}
-static int __init txx9spi_probe(struct platform_device *dev)
+static int txx9spi_probe(struct platform_device *dev)
{
struct spi_master *master;
struct txx9spi *c;
@@ -432,7 +430,7 @@ exit:
return ret;
}
-static int __exit txx9spi_remove(struct platform_device *dev)
+static int txx9spi_remove(struct platform_device *dev)
{
struct spi_master *master = spi_master_get(platform_get_drvdata(dev));
struct txx9spi *c = spi_master_get_devdata(master);
@@ -450,7 +448,7 @@ static int __exit txx9spi_remove(struct platform_device *dev)
MODULE_ALIAS("platform:spi_txx9");
static struct platform_driver txx9spi_driver = {
- .remove = __exit_p(txx9spi_remove),
+ .remove = txx9spi_remove,
.driver = {
.name = "spi_txx9",
.owner = THIS_MODULE,
diff --git a/drivers/spi/spi-xcomm.c b/drivers/spi/spi-xcomm.c
index 266a847e2992..4d3ec8b9f479 100644
--- a/drivers/spi/spi-xcomm.c
+++ b/drivers/spi/spi-xcomm.c
@@ -217,7 +217,7 @@ static int spi_xcomm_setup(struct spi_device *spi)
return 0;
}
-static int __devinit spi_xcomm_probe(struct i2c_client *i2c,
+static int spi_xcomm_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
struct spi_xcomm *spi_xcomm;
@@ -246,7 +246,7 @@ static int __devinit spi_xcomm_probe(struct i2c_client *i2c,
return ret;
}
-static int __devexit spi_xcomm_remove(struct i2c_client *i2c)
+static int spi_xcomm_remove(struct i2c_client *i2c)
{
struct spi_master *master = i2c_get_clientdata(i2c);
@@ -267,7 +267,7 @@ static struct i2c_driver spi_xcomm_driver = {
},
.id_table = spi_xcomm_ids,
.probe = spi_xcomm_probe,
- .remove = __devexit_p(spi_xcomm_remove),
+ .remove = spi_xcomm_remove,
};
module_i2c_driver(spi_xcomm_driver);
diff --git a/drivers/spi/spi-xilinx.c b/drivers/spi/spi-xilinx.c
index 4c5a663b9fa8..e1d769607425 100644
--- a/drivers/spi/spi-xilinx.c
+++ b/drivers/spi/spi-xilinx.c
@@ -462,7 +462,7 @@ void xilinx_spi_deinit(struct spi_master *master)
}
EXPORT_SYMBOL(xilinx_spi_deinit);
-static int __devinit xilinx_spi_probe(struct platform_device *dev)
+static int xilinx_spi_probe(struct platform_device *dev)
{
struct xspi_platform_data *pdata;
struct resource *r;
@@ -518,7 +518,7 @@ static int __devinit xilinx_spi_probe(struct platform_device *dev)
return 0;
}
-static int __devexit xilinx_spi_remove(struct platform_device *dev)
+static int xilinx_spi_remove(struct platform_device *dev)
{
xilinx_spi_deinit(platform_get_drvdata(dev));
platform_set_drvdata(dev, 0);
@@ -531,7 +531,7 @@ MODULE_ALIAS("platform:" XILINX_SPI_NAME);
static struct platform_driver xilinx_spi_driver = {
.probe = xilinx_spi_probe,
- .remove = __devexit_p(xilinx_spi_remove),
+ .remove = xilinx_spi_remove,
.driver = {
.name = XILINX_SPI_NAME,
.owner = THIS_MODULE,
diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
index 718cc1f49230..f996c600eb8c 100644
--- a/drivers/spi/spi.c
+++ b/drivers/spi/spi.c
@@ -30,9 +30,10 @@
#include <linux/slab.h>
#include <linux/mod_devicetable.h>
#include <linux/spi/spi.h>
+#include <linux/of_gpio.h>
#include <linux/pm_runtime.h>
#include <linux/export.h>
-#include <linux/sched.h>
+#include <linux/sched/rt.h>
#include <linux/delay.h>
#include <linux/kthread.h>
#include <linux/ioport.h>
@@ -333,6 +334,7 @@ struct spi_device *spi_alloc_device(struct spi_master *master)
spi->dev.parent = &master->dev;
spi->dev.bus = &spi_bus_type;
spi->dev.release = spidev_release;
+ spi->cs_gpio = -EINVAL;
device_initialize(&spi->dev);
return spi;
}
@@ -350,15 +352,16 @@ EXPORT_SYMBOL_GPL(spi_alloc_device);
int spi_add_device(struct spi_device *spi)
{
static DEFINE_MUTEX(spi_add_lock);
- struct device *dev = spi->master->dev.parent;
+ struct spi_master *master = spi->master;
+ struct device *dev = master->dev.parent;
struct device *d;
int status;
/* Chipselects are numbered 0..max; validate. */
- if (spi->chip_select >= spi->master->num_chipselect) {
+ if (spi->chip_select >= master->num_chipselect) {
dev_err(dev, "cs%d >= max %d\n",
spi->chip_select,
- spi->master->num_chipselect);
+ master->num_chipselect);
return -EINVAL;
}
@@ -382,6 +385,9 @@ int spi_add_device(struct spi_device *spi)
goto done;
}
+ if (master->cs_gpios)
+ spi->cs_gpio = master->cs_gpios[spi->chip_select];
+
/* Drivers may modify this initial i/o setup, but will
* normally rely on the device being setup. Devices
* using SPI_CS_HIGH can't coexist well otherwise...
@@ -492,8 +498,7 @@ static void spi_match_master_to_boardinfo(struct spi_master *master,
* The board info passed can safely be __initdata ... but be careful of
* any embedded pointers (platform_data, etc), they're copied as-is.
*/
-int __devinit
-spi_register_board_info(struct spi_board_info const *info, unsigned n)
+int spi_register_board_info(struct spi_board_info const *info, unsigned n)
{
struct boardinfo *bi;
int i;
@@ -806,7 +811,7 @@ err_init_queue:
/*-------------------------------------------------------------------------*/
-#if defined(CONFIG_OF) && !defined(CONFIG_SPARC)
+#if defined(CONFIG_OF)
/**
* of_register_spi_devices() - Register child devices onto the SPI bus
* @master: Pointer to spi_master device
@@ -819,6 +824,7 @@ static void of_register_spi_devices(struct spi_master *master)
struct spi_device *spi;
struct device_node *nc;
const __be32 *prop;
+ char modalias[SPI_NAME_SIZE + 4];
int rc;
int len;
@@ -861,6 +867,8 @@ static void of_register_spi_devices(struct spi_master *master)
spi->mode |= SPI_CPOL;
if (of_find_property(nc, "spi-cs-high", NULL))
spi->mode |= SPI_CS_HIGH;
+ if (of_find_property(nc, "spi-3wire", NULL))
+ spi->mode |= SPI_3WIRE;
/* Device speed */
prop = of_get_property(nc, "spi-max-frequency", &len);
@@ -880,7 +888,9 @@ static void of_register_spi_devices(struct spi_master *master)
spi->dev.of_node = nc;
/* Register the new device */
- request_module(spi->modalias);
+ snprintf(modalias, sizeof(modalias), "%s%s", SPI_MODULE_PREFIX,
+ spi->modalias);
+ request_module(modalias);
rc = spi_add_device(spi);
if (rc) {
dev_err(&master->dev, "spi_device register error %s\n",
@@ -1046,6 +1056,44 @@ struct spi_master *spi_alloc_master(struct device *dev, unsigned size)
}
EXPORT_SYMBOL_GPL(spi_alloc_master);
+#ifdef CONFIG_OF
+static int of_spi_register_master(struct spi_master *master)
+{
+ int nb, i, *cs;
+ struct device_node *np = master->dev.of_node;
+
+ if (!np)
+ return 0;
+
+ nb = of_gpio_named_count(np, "cs-gpios");
+ master->num_chipselect = max(nb, (int)master->num_chipselect);
+
+ if (nb < 1)
+ return 0;
+
+ cs = devm_kzalloc(&master->dev,
+ sizeof(int) * master->num_chipselect,
+ GFP_KERNEL);
+ master->cs_gpios = cs;
+
+ if (!master->cs_gpios)
+ return -ENOMEM;
+
+ for (i = 0; i < master->num_chipselect; i++)
+ cs[i] = -EINVAL;
+
+ for (i = 0; i < nb; i++)
+ cs[i] = of_get_named_gpio(np, "cs-gpios", i);
+
+ return 0;
+}
+#else
+static int of_spi_register_master(struct spi_master *master)
+{
+ return 0;
+}
+#endif
+
/**
* spi_register_master - register SPI master controller
* @master: initialized master, originally from spi_alloc_master()
@@ -1077,12 +1125,19 @@ int spi_register_master(struct spi_master *master)
if (!dev)
return -ENODEV;
+ status = of_spi_register_master(master);
+ if (status)
+ return status;
+
/* even if it's just one always-selected device, there must
* be at least one chipselect
*/
if (master->num_chipselect == 0)
return -EINVAL;
+ if ((master->bus_num < 0) && master->dev.of_node)
+ master->bus_num = of_alias_get_id(master->dev.of_node, "spi");
+
/* convention: dynamically assigned bus IDs count down from the max */
if (master->bus_num < 0) {
/* FIXME switch to an IDR based scheme, something like
@@ -1196,10 +1251,10 @@ int spi_master_resume(struct spi_master *master)
}
EXPORT_SYMBOL_GPL(spi_master_resume);
-static int __spi_master_match(struct device *dev, void *data)
+static int __spi_master_match(struct device *dev, const void *data)
{
struct spi_master *m;
- u16 *bus_num = data;
+ const u16 *bus_num = data;
m = container_of(dev, struct spi_master, dev);
return m->bus_num == *bus_num;
@@ -1257,7 +1312,7 @@ EXPORT_SYMBOL_GPL(spi_busnum_to_master);
int spi_setup(struct spi_device *spi)
{
unsigned bad_bits;
- int status;
+ int status = 0;
/* help drivers fail *cleanly* when they need options
* that aren't supported with their current master
@@ -1272,7 +1327,8 @@ int spi_setup(struct spi_device *spi)
if (!spi->bits_per_word)
spi->bits_per_word = 8;
- status = spi->master->setup(spi);
+ if (spi->master->setup)
+ status = spi->master->setup(spi);
dev_dbg(&spi->dev, "setup mode %d, %s%s%s%s"
"%u bits/w, %u Hz max --> %d\n",
@@ -1291,6 +1347,7 @@ EXPORT_SYMBOL_GPL(spi_setup);
static int __spi_async(struct spi_device *spi, struct spi_message *message)
{
struct spi_master *master = spi->master;
+ struct spi_transfer *xfer;
/* Half-duplex links include original MicroWire, and ones with
* only one data pin like SPI_3WIRE (switches direction) or where
@@ -1299,7 +1356,6 @@ static int __spi_async(struct spi_device *spi, struct spi_message *message)
*/
if ((master->flags & SPI_MASTER_HALF_DUPLEX)
|| (spi->mode & SPI_3WIRE)) {
- struct spi_transfer *xfer;
unsigned flags = master->flags;
list_for_each_entry(xfer, &message->transfers, transfer_list) {
@@ -1312,6 +1368,17 @@ static int __spi_async(struct spi_device *spi, struct spi_message *message)
}
}
+ /**
+ * Set transfer bits_per_word and max speed as spi device default if
+ * it is not set for this transfer.
+ */
+ list_for_each_entry(xfer, &message->transfers, transfer_list) {
+ if (!xfer->bits_per_word)
+ xfer->bits_per_word = spi->bits_per_word;
+ if (!xfer->speed_hz)
+ xfer->speed_hz = spi->max_speed_hz;
+ }
+
message->spi = spi;
message->status = -EINPROGRESS;
return master->transfer(spi, message);
@@ -1588,12 +1655,19 @@ int spi_write_then_read(struct spi_device *spi,
struct spi_transfer x[2];
u8 *local_buf;
- /* Use preallocated DMA-safe buffer. We can't avoid copying here,
- * (as a pure convenience thing), but we can keep heap costs
- * out of the hot path ...
+ /* Use preallocated DMA-safe buffer if we can. We can't avoid
+ * copying here, (as a pure convenience thing), but we can
+ * keep heap costs out of the hot path unless someone else is
+ * using the pre-allocated buffer or the transfer is too large.
*/
- if ((n_tx + n_rx) > SPI_BUFSIZ)
- return -EINVAL;
+ if ((n_tx + n_rx) > SPI_BUFSIZ || !mutex_trylock(&lock)) {
+ local_buf = kmalloc(max((unsigned)SPI_BUFSIZ, n_tx + n_rx),
+ GFP_KERNEL | GFP_DMA);
+ if (!local_buf)
+ return -ENOMEM;
+ } else {
+ local_buf = buf;
+ }
spi_message_init(&message);
memset(x, 0, sizeof x);
@@ -1606,14 +1680,6 @@ int spi_write_then_read(struct spi_device *spi,
spi_message_add_tail(&x[1], &message);
}
- /* ... unless someone else is using the pre-allocated buffer */
- if (!mutex_trylock(&lock)) {
- local_buf = kmalloc(SPI_BUFSIZ, GFP_KERNEL);
- if (!local_buf)
- return -ENOMEM;
- } else
- local_buf = buf;
-
memcpy(local_buf, txbuf, n_tx);
x[0].tx_buf = local_buf;
x[1].rx_buf = local_buf + n_tx;
diff --git a/drivers/spi/spidev.c b/drivers/spi/spidev.c
index 830adbed1d7a..2e0655dbe070 100644
--- a/drivers/spi/spidev.c
+++ b/drivers/spi/spidev.c
@@ -31,6 +31,8 @@
#include <linux/mutex.h>
#include <linux/slab.h>
#include <linux/compat.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
#include <linux/spi/spi.h>
#include <linux/spi/spidev.h>
@@ -571,7 +573,7 @@ static struct class *spidev_class;
/*-------------------------------------------------------------------------*/
-static int __devinit spidev_probe(struct spi_device *spi)
+static int spidev_probe(struct spi_device *spi)
{
struct spidev_data *spidev;
int status;
@@ -620,7 +622,7 @@ static int __devinit spidev_probe(struct spi_device *spi)
return status;
}
-static int __devexit spidev_remove(struct spi_device *spi)
+static int spidev_remove(struct spi_device *spi)
{
struct spidev_data *spidev = spi_get_drvdata(spi);
@@ -642,13 +644,21 @@ static int __devexit spidev_remove(struct spi_device *spi)
return 0;
}
+static const struct of_device_id spidev_dt_ids[] = {
+ { .compatible = "rohm,dh2228fv" },
+ {},
+};
+
+MODULE_DEVICE_TABLE(of, spidev_dt_ids);
+
static struct spi_driver spidev_spi_driver = {
.driver = {
.name = "spidev",
.owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(spidev_dt_ids),
},
.probe = spidev_probe,
- .remove = __devexit_p(spidev_remove),
+ .remove = spidev_remove,
/* NOTE: suspend/resume methods are not necessary here.
* We don't do anything except pass the requests to/from