diff options
60 files changed, 2893 insertions, 938 deletions
diff --git a/Documentation/devicetree/bindings/spi/nvidia,tegra20-sflash.txt b/Documentation/devicetree/bindings/spi/nvidia,tegra20-sflash.txt new file mode 100644 index 00000000000..8cf24f6f0a9 --- /dev/null +++ b/Documentation/devicetree/bindings/spi/nvidia,tegra20-sflash.txt @@ -0,0 +1,26 @@ +NVIDIA Tegra20 SFLASH controller. + +Required properties: +- compatible : should be "nvidia,tegra20-sflash". +- reg: Should contain SFLASH registers location and length. +- interrupts: Should contain SFLASH interrupts. +- nvidia,dma-request-selector : The Tegra DMA controller's phandle and +  request selector for this SFLASH controller. + +Recommended properties: +- spi-max-frequency: Definition as per +                     Documentation/devicetree/bindings/spi/spi-bus.txt + +Example: + +spi@7000d600 { +	compatible = "nvidia,tegra20-sflash"; +	reg = <0x7000c380 0x80>; +	interrupts = <0 39 0x04>; +	nvidia,dma-request-selector = <&apbdma 16>; +	spi-max-frequency = <25000000>; +	#address-cells = <1>; +	#size-cells = <0>; +	status = "disabled"; +}; + diff --git a/Documentation/devicetree/bindings/spi/nvidia,tegra20-slink.txt b/Documentation/devicetree/bindings/spi/nvidia,tegra20-slink.txt new file mode 100644 index 00000000000..f5b1ad1a1ec --- /dev/null +++ b/Documentation/devicetree/bindings/spi/nvidia,tegra20-slink.txt @@ -0,0 +1,26 @@ +NVIDIA Tegra20/Tegra30 SLINK controller. + +Required properties: +- compatible : should be "nvidia,tegra20-slink", "nvidia,tegra30-slink". +- reg: Should contain SLINK registers location and length. +- interrupts: Should contain SLINK interrupts. +- nvidia,dma-request-selector : The Tegra DMA controller's phandle and +  request selector for this SLINK controller. + +Recommended properties: +- spi-max-frequency: Definition as per +                     Documentation/devicetree/bindings/spi/spi-bus.txt + +Example: + +slink@7000d600 { +	compatible = "nvidia,tegra20-slink"; +	reg = <0x7000d600 0x200>; +	interrupts = <0 82 0x04>; +	nvidia,dma-request-selector = <&apbdma 16>; +	spi-max-frequency = <25000000>; +	#address-cells = <1>; +	#size-cells = <0>; +	status = "disabled"; +}; + diff --git a/Documentation/devicetree/bindings/spi/omap-spi.txt b/Documentation/devicetree/bindings/spi/omap-spi.txt index 81df374adbb..938809c6829 100644 --- a/Documentation/devicetree/bindings/spi/omap-spi.txt +++ b/Documentation/devicetree/bindings/spi/omap-spi.txt @@ -6,7 +6,9 @@ Required properties:    - "ti,omap4-spi" for OMAP4+.  - ti,spi-num-cs : Number of chipselect supported  by the instance.  - ti,hwmods: Name of the hwmod associated to the McSPI - +- ti,pindir-d0-out-d1-in: Select the D0 pin as output and D1 as +			  input. The default is D0 as input and +			  D1 as output.  Example: diff --git a/Documentation/devicetree/bindings/spi/spi-bus.txt b/Documentation/devicetree/bindings/spi/spi-bus.txt index d2c33d0f533..296015e3c63 100644 --- a/Documentation/devicetree/bindings/spi/spi-bus.txt +++ b/Documentation/devicetree/bindings/spi/spi-bus.txt @@ -12,6 +12,7 @@ The SPI master node requires the following properties:  - #size-cells     - should be zero.  - compatible      - name of SPI bus controller following generic names      		recommended practice. +- cs-gpios	  - (optional) gpios chip select.  No other properties are required in the SPI bus node.  It is assumed  that a driver for an SPI bus device will understand that it is an SPI bus.  However, the binding does not attempt to define the specific method for @@ -24,6 +25,22 @@ support describing the chip select layout.  Optional property:  - num-cs : total number of chipselects +If cs-gpios is used the number of chip select will automatically increased +with max(cs-gpios > hw cs) + +So if for example the controller has 2 CS lines, and the cs-gpios +property looks like this: + +cs-gpios = <&gpio1 0 0> <0> <&gpio1 1 0> <&gpio1 2 0>; + +Then it should be configured so that num_chipselect = 4 with the +following mapping: + +cs0 : &gpio1 0 0 +cs1 : native +cs2 : &gpio1 1 0 +cs3 : &gpio1 2 0 +  SPI slave nodes must be children of the SPI master node and can  contain the following properties.  - reg             - (required) chip select address of device. @@ -36,6 +53,11 @@ contain the following properties.      		shifted clock phase (CPHA) mode  - spi-cs-high     - (optional) Empty property indicating device requires      		chip select active high +- spi-3wire       - (optional) Empty property indicating device requires +    		    3-wire mode. + +If a gpio chipselect is used for the SPI slave the gpio number will be passed +via the cs_gpio  SPI example for an MPC5200 SPI bus:  	spi@f00 { diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index 1acae359cab..2e188e1127e 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -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) @@ -341,10 +348,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 +379,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 +386,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 diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile index c48df47e4b0..64e970ba261 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 @@ -59,11 +60,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 f1fec2a19d1..5e7314ac51e 100644 --- a/drivers/spi/spi-altera.c +++ b/drivers/spi/spi-altera.c @@ -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 249077e5cc4..9a5d7791c5f 100644 --- a/drivers/spi/spi-ath79.c +++ b/drivers/spi/spi-ath79.c @@ -192,7 +192,7 @@ 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; @@ -251,7 +251,7 @@ 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); @@ -265,7 +265,7 @@ static __devexit int ath79_spi_remove(struct platform_device *pdev)  static struct platform_driver ath79_spi_driver = {  	.probe		= ath79_spi_probe, -	.remove		= __devexit_p(ath79_spi_remove), +	.remove		= ath79_spi_remove,  	.driver		= {  		.name	= DRV_NAME,  		.owner	= THIS_MODULE, diff --git a/drivers/spi/spi-atmel.c b/drivers/spi/spi-atmel.c index 61fb0ec26f0..75c0c4f5fdf 100644 --- a/drivers/spi/spi-atmel.c +++ b/drivers/spi/spi-atmel.c @@ -907,7 +907,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; @@ -1003,7 +1003,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); diff --git a/drivers/spi/spi-bcm63xx.c b/drivers/spi/spi-bcm63xx.c index a9f4049c676..f44ab550853 100644 --- a/drivers/spi/spi-bcm63xx.c +++ b/drivers/spi/spi-bcm63xx.c @@ -36,7 +36,6 @@  #include <bcm63xx_dev_spi.h>  #define PFX		KBUILD_MODNAME -#define DRV_VER		"0.1.2"  struct bcm63xx_spi {  	struct completion	done; @@ -170,13 +169,6 @@ 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); @@ -337,7 +329,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 +433,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 +449,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 +477,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 +492,8 @@ static int bcm63xx_spi_resume(struct device *dev)  	clk_enable(bs->clk); +	spi_master_resume(master); +  	return 0;  } @@ -518,7 +514,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 6555ecd0730..ac7ffca7ba4 100644 --- a/drivers/spi/spi-bfin-sport.c +++ b/drivers/spi/spi-bfin-sport.c @@ -755,8 +755,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 +862,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 +933,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 9bb4d4af854..0429d833f75 100644 --- a/drivers/spi/spi-bfin5xx.c +++ b/drivers/spi/spi-bfin5xx.c @@ -1387,7 +1387,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 +1477,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 aef59b1a15f..8b3d8efafd3 100644 --- a/drivers/spi/spi-bitbang.c +++ b/drivers/spi/spi-bitbang.c @@ -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; diff --git a/drivers/spi/spi-clps711x.c b/drivers/spi/spi-clps711x.c new file mode 100644 index 00000000000..1366c4620d5 --- /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 ? : spi->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 764bfee7592..58466b810da 100644 --- a/drivers/spi/spi-coldfire-qspi.c +++ b/drivers/spi/spi-coldfire-qspi.c @@ -401,7 +401,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 +515,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 +594,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 147dfa87a64..13661e129d9 100644 --- a/drivers/spi/spi-davinci.c +++ b/drivers/spi/spi-davinci.c @@ -769,7 +769,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; @@ -952,7 +952,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; @@ -980,7 +980,7 @@ static struct platform_driver davinci_spi_driver = {  		.owner = THIS_MODULE,  	},  	.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 db2f1ba06ea..4a6d5c9057a 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 ff81abbb306..6055c8d9fdd 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 d1a495f64e2..c1abc06899e 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 3a219599612..acb1e1935c5 100644 --- a/drivers/spi/spi-ep93xx.c +++ b/drivers/spi/spi-ep93xx.c @@ -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; @@ -1138,7 +1138,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 +1180,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 8f6aa735a24..6a6f62ec284 100644 --- a/drivers/spi/spi-falcon.c +++ b/drivers/spi/spi-falcon.c @@ -403,7 +403,7 @@ static int falcon_sflash_xfer_one(struct spi_master *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; @@ -438,7 +438,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 +455,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 27bdc47b525..24610ca8955 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 1503574b215..8ade675a04f 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 6a62934ca74..1a7f6359d99 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; @@ -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 a2b50c516b3..c7cf0b7a069 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; @@ -392,7 +391,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 +484,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 +517,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 c9a0d8467de..904913290aa 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,7 +942,7 @@ 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); diff --git a/drivers/spi/spi-mpc512x-psc.c b/drivers/spi/spi-mpc512x-psc.c index 0a1e39e94d0..cb3a3106bd4 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)  { @@ -492,7 +492,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 +508,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; @@ -539,7 +539,7 @@ static int __devinit mpc512x_psc_spi_of_probe(struct platform_device *op)  				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 +553,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 bd47d262d53..291120b37db 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 04541065021..29f77056eed 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 86dd04d6bc8..a3ede249d05 100644 --- a/drivers/spi/spi-mxs.c +++ b/drivers/spi/spi-mxs.c @@ -509,7 +509,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); @@ -636,7 +636,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 +659,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 a6eca6ffdab..b3f9ec83ef7 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 9d9071b730b..432e66ec308 100644 --- a/drivers/spi/spi-oc-tiny.c +++ b/drivers/spi/spi-oc-tiny.c @@ -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; @@ -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; @@ -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 ea8fb2efb0f..24daf964a40 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 dfb4b7f448c..3aef7fa7d5b 100644 --- a/drivers/spi/spi-omap-100k.c +++ b/drivers/spi/spi-omap-100k.c @@ -486,7 +486,7 @@ static int __init 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; diff --git a/drivers/spi/spi-omap2-mcspi.c b/drivers/spi/spi-omap2-mcspi.c index 3542fdc664b..b610f522ca4 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 { @@ -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; @@ -1085,7 +1088,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; @@ -1138,7 +1141,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 +1170,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 +1183,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; @@ -1272,7 +1278,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 +1347,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 b17c09cf0a0..b7e718254b1 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; @@ -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; @@ -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", },  	{}  }; diff --git a/drivers/spi/spi-pl022.c b/drivers/spi/spi-pl022.c index a1db91a99b8..b0fe393c882 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-pxa2xx-pci.c b/drivers/spi/spi-pxa2xx-pci.c index 9f6ba34b172..cf95587eefd 100644 --- a/drivers/spi/spi-pxa2xx-pci.c +++ b/drivers/spi/spi-pxa2xx-pci.c @@ -51,7 +51,7 @@ void pxa_ssp_free(struct ssp_device *ssp)  }  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)  {  	int ret; @@ -129,7 +129,7 @@ err_nomem:  	return ret;  } -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; @@ -161,7 +161,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.c b/drivers/spi/spi-pxa2xx.c index dc25bee8d33..5c8c4f5883c 100644 --- a/drivers/spi/spi-pxa2xx.c +++ b/drivers/spi/spi-pxa2xx.c @@ -1438,7 +1438,7 @@ static void cleanup(struct spi_device *spi)  	kfree(chip);  } -static int __devinit init_queue(struct driver_data *drv_data) +static int init_queue(struct driver_data *drv_data)  {  	INIT_LIST_HEAD(&drv_data->queue);  	spin_lock_init(&drv_data->lock); @@ -1526,7 +1526,7 @@ static int destroy_queue(struct driver_data *drv_data)  	return 0;  } -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; diff --git a/drivers/spi/spi-rspi.c b/drivers/spi/spi-rspi.c index 30faf6d4ab9..902f2fb902d 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 a2a080b7f42..02d64603fcc 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 6e7a805d324..4dd7b7ce5c5 100644 --- a/drivers/spi/spi-s3c64xx.c +++ b/drivers/spi/spi-s3c64xx.c @@ -516,7 +516,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 +564,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); @@ -1056,7 +1056,7 @@ static void s3c64xx_spi_hwinit(struct s3c64xx_spi_driver_data *sdd, int channel)  	flush_fifo(sdd);  } -static int __devinit s3c64xx_spi_get_dmares( +static int s3c64xx_spi_get_dmares(  			struct s3c64xx_spi_driver_data *sdd, bool tx)  {  	struct platform_device *pdev = sdd->pdev; @@ -1112,7 +1112,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,7 +1135,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( +static struct s3c64xx_spi_info * s3c64xx_spi_parse_dt(  						struct device *dev)  {  	struct s3c64xx_spi_info *sci; @@ -1302,7 +1302,7 @@ static int __init s3c64xx_spi_probe(struct platform_device *pdev)  		goto err3;  	} -	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; @@ -1317,7 +1317,7 @@ static int __init s3c64xx_spi_probe(struct platform_device *pdev)  		goto err5;  	} -	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; @@ -1361,11 +1361,11 @@ static int __init s3c64xx_spi_probe(struct platform_device *pdev)  err8:  	free_irq(irq, sdd);  err7: -	clk_disable(sdd->src_clk); +	clk_disable_unprepare(sdd->src_clk);  err6:  	clk_put(sdd->src_clk);  err5: -	clk_disable(sdd->clk); +	clk_disable_unprepare(sdd->clk);  err4:  	clk_put(sdd->clk);  err3: @@ -1393,10 +1393,10 @@ static int s3c64xx_spi_remove(struct platform_device *pdev)  	free_irq(platform_get_irq(pdev, 0), sdd); -	clk_disable(sdd->src_clk); +	clk_disable_unprepare(sdd->src_clk);  	clk_put(sdd->src_clk); -	clk_disable(sdd->clk); +	clk_disable_unprepare(sdd->clk);  	clk_put(sdd->clk);  	if (!sdd->cntrlr_info->cfg_gpio && pdev->dev.of_node) @@ -1417,8 +1417,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 +1440,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 +1457,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 +1468,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 796c077ef43..32f7b55fce0 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; @@ -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 1f466bc66d9..96358d0eabb 100644 --- a/drivers/spi/spi-sh-msiof.c +++ b/drivers/spi/spi-sh-msiof.c @@ -597,7 +597,6 @@ 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; @@ -614,10 +613,9 @@ static int sh_msiof_spi_probe(struct platform_device *pdev)  	p->info = pdev->dev.platform_data;  	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;  	} diff --git a/drivers/spi/spi-sh.c b/drivers/spi/spi-sh.c index 79442c31bcd..3c3600a994b 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 ecc3d9763d1..e0f43a512e8 100644 --- a/drivers/spi/spi-sirf.c +++ b/drivers/spi/spi-sirf.c @@ -479,7 +479,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; @@ -604,7 +604,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; @@ -673,7 +673,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 911e904b3c8..00000000000 --- 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 00000000000..448a8cc71df --- /dev/null +++ b/drivers/spi/spi-tegra20-sflash.c @@ -0,0 +1,665 @@ +/* + * 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 <mach/clk.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 ? t->speed_hz : spi->max_speed_hz; +	if (!speed) +		speed = tsd->spi_max_frequency; +	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_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->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_request_and_ioremap(&pdev->dev, r); +	if (!tsd->base) { +		dev_err(&pdev->dev, +			"Cannot request memregion/iomap dma address\n"); +		ret = -EADDRNOTAVAIL; +		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, "spi"); +	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 00000000000..651167f2e0a --- /dev/null +++ b/drivers/spi/spi-tegra20-slink.c @@ -0,0 +1,1358 @@ +/* + * 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 <mach/clk.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 ? t->bits_per_word : +						spi->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 ? t->bits_per_word : +						tspi->cur_spi->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 ? t->bits_per_word : +						tspi->cur_spi->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 ? t->speed_hz : spi->max_speed_hz; +	if (!speed) +		speed = tspi->spi_max_frequency; +	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); + +	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_request_and_ioremap(&pdev->dev, r); +	if (!tspi->base) { +		dev_err(&pdev->dev, +			"Cannot request memregion/iomap dma address\n"); +		ret = -EADDRNOTAVAIL; +		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, "slink"); +	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 3f6f6e81c65..46992cab65f 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 24421024dea..6b0874d782e 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 135f7406f4b..f756481b0fe 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-xcomm.c b/drivers/spi/spi-xcomm.c index 266a847e299..4d3ec8b9f47 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 4c5a663b9fa..e1d76960742 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 718cc1f4923..ab095acdb2a 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -30,6 +30,7 @@  #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> @@ -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 @@ -861,6 +866,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); @@ -1046,6 +1053,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) +{ +	u16 nb; +	int 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, 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; + +	memset(cs, -EINVAL, master->num_chipselect); + +	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,6 +1122,10 @@ 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  	 */ @@ -1257,7 +1306,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 +1321,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 +1341,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 +1350,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 +1362,15 @@ static int __spi_async(struct spi_device *spi, struct spi_message *message)  		}  	} +	/** +	 * Set transfer bits_per_word 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; +	} +  	message->spi = spi;  	message->status = -EINPROGRESS;  	return master->transfer(spi, message); @@ -1588,12 +1647,18 @@ 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); +		if (!local_buf) +			return -ENOMEM; +	} else { +		local_buf = buf; +	}  	spi_message_init(&message);  	memset(x, 0, sizeof x); @@ -1606,14 +1671,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 830adbed1d7..2e0655dbe07 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 diff --git a/include/linux/platform_data/spi-clps711x.h b/include/linux/platform_data/spi-clps711x.h new file mode 100644 index 00000000000..301956e6314 --- /dev/null +++ b/include/linux/platform_data/spi-clps711x.h @@ -0,0 +1,21 @@ +/* + *  CLPS711X SPI bus driver definitions + * + *  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. + */ + +#ifndef ____LINUX_PLATFORM_DATA_SPI_CLPS711X_H +#define ____LINUX_PLATFORM_DATA_SPI_CLPS711X_H + +/* Board specific platform_data */ +struct spi_clps711x_pdata { +	int *chipselect;	/* Array of GPIO-numbers */ +	int num_chipselect;	/* Total count of GPIOs */ +}; + +#endif diff --git a/include/linux/platform_data/spi-omap2-mcspi.h b/include/linux/platform_data/spi-omap2-mcspi.h index a357eb26bd2..a65572d5321 100644 --- a/include/linux/platform_data/spi-omap2-mcspi.h +++ b/include/linux/platform_data/spi-omap2-mcspi.h @@ -7,9 +7,13 @@  #define OMAP4_MCSPI_REG_OFFSET 0x100 +#define MCSPI_PINDIR_D0_IN_D1_OUT	0 +#define MCSPI_PINDIR_D0_OUT_D1_IN	1 +  struct omap2_mcspi_platform_config {  	unsigned short	num_cs;  	unsigned int regs_offset; +	unsigned int pin_dir:1;  };  struct omap2_mcspi_dev_attr { diff --git a/include/linux/spi/spi-tegra.h b/include/linux/spi/spi-tegra.h new file mode 100644 index 00000000000..786932c62ed --- /dev/null +++ b/include/linux/spi/spi-tegra.h @@ -0,0 +1,40 @@ +/* + * spi-tegra.h: SPI interface for Nvidia Tegra20 SLINK controller. + * + * Copyright (C) 2011 NVIDIA 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 + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. + */ + +#ifndef _LINUX_SPI_TEGRA_H +#define _LINUX_SPI_TEGRA_H + +struct tegra_spi_platform_data { +	int dma_req_sel; +	unsigned int spi_max_frequency; +}; + +/* + * Controller data from device to pass some info like + * hw based chip select can be used or not and if yes + * then CS hold and setup time. + */ +struct tegra_spi_device_controller_data { +	bool is_hw_based_cs; +	int cs_setup_clk_count; +	int cs_hold_clk_count; +}; + +#endif /* _LINUX_SPI_TEGRA_H */ diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h index fa702aeb503..f62918946d8 100644 --- a/include/linux/spi/spi.h +++ b/include/linux/spi/spi.h @@ -90,6 +90,7 @@ struct spi_device {  	void			*controller_state;  	void			*controller_data;  	char			modalias[SPI_NAME_SIZE]; +	int			cs_gpio;	/* chip select gpio */  	/*  	 * likely need more hooks for more protocol options affecting how @@ -362,6 +363,8 @@ struct spi_master {  	int (*transfer_one_message)(struct spi_master *master,  				    struct spi_message *mesg);  	int (*unprepare_transfer_hardware)(struct spi_master *master); +	/* gpio chip select */ +	int			*cs_gpios;  };  static inline void *spi_master_get_devdata(struct spi_master *master)  |