diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2014-04-01 13:23:53 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2014-04-01 13:23:53 -0700 |
commit | c12ac9f98ec08d6eb69f84e3f72241d56a8b0822 (patch) | |
tree | 8c749a097e54a93e22b0a099c38d60135022a221 /drivers | |
parent | 3786075b5ebc8c4eaefd9e3ebf72883934fb64b3 (diff) | |
parent | 45b15d98a96ffdb3c608bdad952f51930c151420 (diff) |
Merge tag 'spi-v3.15' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi
Pull spi Updates from Mark Brown:
"A busy release for both cleanups and new drivers this time along with
further factoring out of replicated code into the core:
- Provide support in the core for DMA mapping transfers - essentially
all drivers weren't implementing this properly, now there's no
excuse.
- Dual and quad mode support for spidev.
- Fix handling of cs_change in the generic implementation.
- Remove the S3C_DMA code from the s3c64xx driver now that all the
platforms using it have been converted to dmaengine.
- Lots of improvements to the Renesas SPI controllers.
- Drivers for Allwinner A10 and A31, Qualcomm QUP and Xylinx xtfpga.
- Removal of the bitrotted ti-ssp driver"
* tag 'spi-v3.15' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi: (199 commits)
spi: Fix handling of cs_change in core implementation
spi: bitbang: Make spi_bitbang_stop() return void
spi: mpc52xx: Convert to use bits_per_word_mask
spi: omap-100k: Fix memory leak
spi: dw: Don't call kfree for memory allocated by devm_kzalloc
spi: fsl-dspi: Fix memory leak
spi: omap-uwire: add missing iounmap
spi: clps711x: Convert to use master->max_speed_hz
spi: clps711x: Enable driver compilation with COMPILE_TEST
spi: omap-uwire: Remove full duplex check
spi: Do not require a completion
spi: topcliff-pch: Transform noisy message to dev_vdbg
spi: coldfire-qspi: Simplify the code to set register bits for transfer speed
spi: bcm63xx: Remove unused define for PFX
spi: efm32: use $vendor,$device scheme for compatible string
spi: clps711x: Remove <mach/hardware.h> dependency
spi: topcliff-pch: Properly unregister platform devices on probe() error paths
spi: fsl-espi: Remove unused bits_per_word variable in fsl_espi_bufs
spi: altera: Remove the code to get unused platform_data
spi: fsl-lib: Fix memory leak of pinfo
...
Diffstat (limited to 'drivers')
67 files changed, 3629 insertions, 2225 deletions
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index 581ee2a8856..efe1960af2b 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -150,7 +150,7 @@ config SPI_BUTTERFLY config SPI_CLPS711X tristate "CLPS711X host SPI controller" - depends on ARCH_CLPS711X + depends on ARCH_CLPS711X || COMPILE_TEST help This enables dedicated general purpose SPI/Microwire1-compatible master mode interface (SSI1) for CLPS711X-based CPUs. @@ -212,7 +212,6 @@ config SPI_IMX tristate "Freescale i.MX SPI controllers" depends on ARCH_MXC || COMPILE_TEST select SPI_BITBANG - default m if IMX_HAVE_PLATFORM_SPI_IMX help This enables using the Freescale i.MX SPI controllers in master mode. @@ -270,6 +269,7 @@ config SPI_FSL_SPI config SPI_FSL_DSPI tristate "Freescale DSPI controller" select SPI_BITBANG + select REGMAP_MMIO depends on SOC_VF610 || COMPILE_TEST help This enables support for the Freescale DSPI controller in master @@ -307,7 +307,7 @@ config SPI_OMAP_UWIRE config SPI_OMAP24XX tristate "McSPI driver for OMAP" - depends on ARM || ARM64 || AVR32 || HEXAGON || MIPS || SH + depends on ARM || ARM64 || AVR32 || HEXAGON || MIPS || SUPERH depends on ARCH_OMAP2PLUS || COMPILE_TEST help SPI master controller for OMAP24XX and later Multichannel SPI @@ -381,6 +381,19 @@ config SPI_RSPI help SPI driver for Renesas RSPI and QSPI blocks. +config SPI_QUP + tristate "Qualcomm SPI controller with QUP interface" + depends on ARCH_MSM_DT || (ARM && COMPILE_TEST) + help + Qualcomm Universal Peripheral (QUP) core is an AHB slave that + provides a common data path (an output FIFO and an input FIFO) + for serial peripheral interface (SPI) mini-core. SPI in master + mode supports up to 50MHz, up to four chip selects, programmable + data path from 4 bits to 32 bits and numerous protocol variants. + + This driver can also be built as a module. If so, the module + will be called spi_qup. + config SPI_S3C24XX tristate "Samsung S3C24XX series SPI" depends on ARCH_S3C24XX @@ -416,7 +429,6 @@ config SPI_SH_MSIOF tristate "SuperH MSIOF SPI controller" depends on HAVE_CLK depends on SUPERH || ARCH_SHMOBILE || COMPILE_TEST - select SPI_BITBANG help SPI driver for SuperH and SH Mobile MSIOF blocks. @@ -446,6 +458,19 @@ config SPI_SIRF help SPI driver for CSR SiRFprimaII SoCs +config SPI_SUN4I + tristate "Allwinner A10 SoCs SPI controller" + depends on ARCH_SUNXI || COMPILE_TEST + help + SPI driver for Allwinner sun4i, sun5i and sun7i SoCs + +config SPI_SUN6I + tristate "Allwinner A31 SPI controller" + depends on ARCH_SUNXI || COMPILE_TEST + depends on RESET_CONTROLLER + help + This enables using the SPI controller on the Allwinner A31 SoCs. + config SPI_MXS tristate "Freescale MXS SPI controller" depends on ARCH_MXS @@ -478,13 +503,6 @@ config SPI_TEGRA20_SLINK 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 - help - This selects an SPI master implementation using a TI sequencer - serial port. - config SPI_TOPCLIFF_PCH tristate "Intel EG20T PCH/LAPIS Semicon IOH(ML7213/ML7223/ML7831) SPI" depends on PCI @@ -520,6 +538,19 @@ config SPI_XILINX Or for the DS570, see "XPS Serial Peripheral Interface (SPI) (v2.00b)" +config SPI_XTENSA_XTFPGA + tristate "Xtensa SPI controller for xtfpga" + depends on (XTENSA && XTENSA_PLATFORM_XTFPGA) || COMPILE_TEST + select SPI_BITBANG + help + SPI driver for xtfpga SPI master controller. + + This simple SPI master controller is built into xtfpga bitstreams + and is used to control daughterboard audio codec. It always transfers + 16 bit words in SPI mode 0, automatically asserting CS on transfer + start and deasserting on end. + + config SPI_NUC900 tristate "Nuvoton NUC900 series SPI" depends on ARCH_W90X900 @@ -546,7 +577,7 @@ config SPI_DW_MID_DMA config SPI_DW_MMIO tristate "Memory-mapped io interface driver for DW SPI core" - depends on SPI_DESIGNWARE && HAVE_CLK + depends on SPI_DESIGNWARE # # There are lots of SPI device types, with sensors and memory diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile index 95af48d2d36..bd792669e56 100644 --- a/drivers/spi/Makefile +++ b/drivers/spi/Makefile @@ -59,6 +59,7 @@ spi-pxa2xx-platform-$(CONFIG_SPI_PXA2XX_PXADMA) += spi-pxa2xx-pxadma.o spi-pxa2xx-platform-$(CONFIG_SPI_PXA2XX_DMA) += spi-pxa2xx-dma.o obj-$(CONFIG_SPI_PXA2XX) += spi-pxa2xx-platform.o obj-$(CONFIG_SPI_PXA2XX_PCI) += spi-pxa2xx-pci.o +obj-$(CONFIG_SPI_QUP) += spi-qup.o obj-$(CONFIG_SPI_RSPI) += spi-rspi.o obj-$(CONFIG_SPI_S3C24XX) += spi-s3c24xx-hw.o spi-s3c24xx-hw-y := spi-s3c24xx.o @@ -70,12 +71,14 @@ 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_SUN4I) += spi-sun4i.o +obj-$(CONFIG_SPI_SUN6I) += spi-sun6i.o obj-$(CONFIG_SPI_TEGRA114) += spi-tegra114.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 +obj-$(CONFIG_SPI_XTENSA_XTFPGA) += spi-xtensa-xtfpga.o diff --git a/drivers/spi/spi-altera.c b/drivers/spi/spi-altera.c index 5d7deaf6286..5b5709a5c95 100644 --- a/drivers/spi/spi-altera.c +++ b/drivers/spi/spi-altera.c @@ -13,7 +13,6 @@ * published by the Free Software Foundation. */ -#include <linux/init.h> #include <linux/interrupt.h> #include <linux/errno.h> #include <linux/module.h> @@ -200,7 +199,6 @@ static irqreturn_t altera_spi_irq(int irq, void *dev) static int altera_spi_probe(struct platform_device *pdev) { - struct altera_spi_platform_data *platp = dev_get_platdata(&pdev->dev); struct altera_spi *hw; struct spi_master *master; struct resource *res; @@ -214,6 +212,8 @@ static int altera_spi_probe(struct platform_device *pdev) master->bus_num = pdev->id; master->num_chipselect = 16; master->mode_bits = SPI_CS_HIGH; + master->bits_per_word_mask = SPI_BPW_RANGE_MASK(1, 16); + master->dev.of_node = pdev->dev.of_node; hw = spi_master_get_devdata(master); platform_set_drvdata(pdev, hw); @@ -245,9 +245,6 @@ static int altera_spi_probe(struct platform_device *pdev) if (err) goto exit; } - /* find platform data */ - if (!platp) - hw->bitbang.master->dev.of_node = pdev->dev.of_node; /* register our spi controller */ err = spi_bitbang_start(&hw->bitbang); diff --git a/drivers/spi/spi-ath79.c b/drivers/spi/spi-ath79.c index c3b2fb9b671..3898b0b9ee7 100644 --- a/drivers/spi/spi-ath79.c +++ b/drivers/spi/spi-ath79.c @@ -14,7 +14,6 @@ #include <linux/kernel.h> #include <linux/module.h> -#include <linux/init.h> #include <linux/delay.h> #include <linux/spinlock.h> #include <linux/workqueue.h> diff --git a/drivers/spi/spi-atmel.c b/drivers/spi/spi-atmel.c index 5d7b07f0832..8005f986948 100644 --- a/drivers/spi/spi-atmel.c +++ b/drivers/spi/spi-atmel.c @@ -9,7 +9,6 @@ */ #include <linux/kernel.h> -#include <linux/init.h> #include <linux/clk.h> #include <linux/module.h> #include <linux/platform_device.h> @@ -26,6 +25,7 @@ #include <linux/io.h> #include <linux/gpio.h> +#include <linux/pinctrl/consumer.h> /* SPI register offsets */ #define SPI_CR 0x0000 @@ -993,13 +993,6 @@ static int atmel_spi_setup(struct spi_device *spi) as = spi_master_get_devdata(spi->master); - if (spi->chip_select > spi->master->num_chipselect) { - dev_dbg(&spi->dev, - "setup: invalid chipselect %u (%u defined)\n", - spi->chip_select, spi->master->num_chipselect); - return -EINVAL; - } - /* see notes above re chipselect */ if (!atmel_spi_is_v2(as) && spi->chip_select == 0 @@ -1087,14 +1080,6 @@ static int atmel_spi_one_transfer(struct spi_master *master, } } - if (xfer->bits_per_word > 8) { - if (xfer->len % 2) { - dev_dbg(&spi->dev, - "buffer len should be 16 bits aligned\n"); - return -EINVAL; - } - } - /* * DMA map early, for performance (empties dcache ASAP) and * better fault reporting. @@ -1221,9 +1206,6 @@ static int atmel_spi_transfer_one_message(struct spi_master *master, dev_dbg(&spi->dev, "new message %p submitted for %s\n", msg, dev_name(&spi->dev)); - if (unlikely(list_empty(&msg->transfers))) - return -EINVAL; - atmel_spi_lock(as); cs_activate(as, spi); @@ -1244,10 +1226,10 @@ static int atmel_spi_transfer_one_message(struct spi_master *master, list_for_each_entry(xfer, &msg->transfers, transfer_list) { dev_dbg(&spi->dev, - " xfer %p: len %u tx %p/%08x rx %p/%08x\n", + " xfer %p: len %u tx %p/%pad rx %p/%pad\n", xfer, xfer->len, - xfer->tx_buf, xfer->tx_dma, - xfer->rx_buf, xfer->rx_dma); + xfer->tx_buf, &xfer->tx_dma, + xfer->rx_buf, &xfer->rx_dma); } msg_done: @@ -1303,6 +1285,9 @@ static int atmel_spi_probe(struct platform_device *pdev) struct spi_master *master; struct atmel_spi *as; + /* Select default pin state */ + pinctrl_pm_select_default_state(&pdev->dev); + regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!regs) return -ENXIO; @@ -1465,6 +1450,9 @@ static int atmel_spi_suspend(struct device *dev) } clk_disable_unprepare(as->clk); + + pinctrl_pm_select_sleep_state(dev); + return 0; } @@ -1474,6 +1462,8 @@ static int atmel_spi_resume(struct device *dev) struct atmel_spi *as = spi_master_get_devdata(master); int ret; + pinctrl_pm_select_default_state(dev); + clk_prepare_enable(as->clk); /* Start the queue running */ diff --git a/drivers/spi/spi-au1550.c b/drivers/spi/spi-au1550.c index c4141c92bcf..aafb812d7ea 100644 --- a/drivers/spi/spi-au1550.c +++ b/drivers/spi/spi-au1550.c @@ -55,8 +55,6 @@ struct au1550_spi { volatile psc_spi_t __iomem *regs; int irq; - unsigned freq_max; - unsigned freq_min; unsigned len; unsigned tx_count; @@ -248,11 +246,8 @@ static int au1550_spi_setupxfer(struct spi_device *spi, struct spi_transfer *t) hz = t->speed_hz; } - if (hz > spi->max_speed_hz || hz > hw->freq_max || hz < hw->freq_min) { - dev_err(&spi->dev, "setupxfer: clock rate=%d out of range\n", - hz); + if (!hz) return -EINVAL; - } au1550_spi_bits_handlers_set(hw, spi->bits_per_word); @@ -287,23 +282,6 @@ static int au1550_spi_setupxfer(struct spi_device *spi, struct spi_transfer *t) return 0; } -static int au1550_spi_setup(struct spi_device *spi) -{ - struct au1550_spi *hw = spi_master_get_devdata(spi->master); - - if (spi->max_speed_hz == 0) - spi->max_speed_hz = hw->freq_max; - if (spi->max_speed_hz > hw->freq_max - || spi->max_speed_hz < hw->freq_min) - return -EINVAL; - /* - * NOTE: cannot change speed and other hw settings immediately, - * otherwise sharing of spi bus is not possible, - * so do not call setupxfer(spi, NULL) here - */ - return 0; -} - /* * for dma spi transfers, we have to setup rx channel, otherwise there is * no reliable way how to recognize that spi transfer is done @@ -838,7 +816,6 @@ static int au1550_spi_probe(struct platform_device *pdev) hw->bitbang.master = hw->master; hw->bitbang.setup_transfer = au1550_spi_setupxfer; hw->bitbang.chipselect = au1550_spi_chipsel; - hw->bitbang.master->setup = au1550_spi_setup; hw->bitbang.txrx_bufs = au1550_spi_txrx_bufs; if (hw->usedma) { @@ -909,8 +886,9 @@ static int au1550_spi_probe(struct platform_device *pdev) { int min_div = (2 << 0) * (2 * (4 + 1)); int max_div = (2 << 3) * (2 * (63 + 1)); - hw->freq_max = hw->pdata->mainclk_hz / min_div; - hw->freq_min = hw->pdata->mainclk_hz / (max_div + 1) + 1; + master->max_speed_hz = hw->pdata->mainclk_hz / min_div; + master->min_speed_hz = + hw->pdata->mainclk_hz / (max_div + 1) + 1; } au1550_spi_setup_psc_as_spi(hw); diff --git a/drivers/spi/spi-bcm2835.c b/drivers/spi/spi-bcm2835.c index 8a89dd1f265..69167456ec1 100644 --- a/drivers/spi/spi-bcm2835.c +++ b/drivers/spi/spi-bcm2835.c @@ -315,7 +315,6 @@ static int bcm2835_spi_probe(struct platform_device *pdev) master->mode_bits = BCM2835_SPI_MODE_BITS; master->bits_per_word_mask = SPI_BPW_MASK(8); - master->bus_num = -1; master->num_chipselect = 3; master->transfer_one_message = bcm2835_spi_transfer_one; master->dev.of_node = pdev->dev.of_node; diff --git a/drivers/spi/spi-bcm63xx-hsspi.c b/drivers/spi/spi-bcm63xx-hsspi.c index b528f9fc8bc..5a211e98383 100644 --- a/drivers/spi/spi-bcm63xx-hsspi.c +++ b/drivers/spi/spi-bcm63xx-hsspi.c @@ -180,7 +180,7 @@ static int bcm63xx_hsspi_do_txrx(struct spi_device *spi, struct spi_transfer *t) while (pending > 0) { int curr_step = min_t(int, step_size, pending); - init_completion(&bs->done); + reinit_completion(&bs->done); if (tx) { memcpy_toio(bs->fifo + HSSPI_OPCODE_LEN, tx, curr_step); tx += curr_step; @@ -369,6 +369,7 @@ static int bcm63xx_hsspi_probe(struct platform_device *pdev) bs->fifo = (u8 __iomem *)(bs->regs + HSSPI_FIFO_REG(0)); mutex_init(&bs->bus_mutex); + init_completion(&bs->done); master->bus_num = HSSPI_BUS_NUM; master->num_chipselect = 8; @@ -453,9 +454,8 @@ static int bcm63xx_hsspi_resume(struct device *dev) } #endif -static const struct dev_pm_ops bcm63xx_hsspi_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(bcm63xx_hsspi_suspend, bcm63xx_hsspi_resume) -}; +static SIMPLE_DEV_PM_OPS(bcm63xx_hsspi_pm_ops, bcm63xx_hsspi_suspend, + bcm63xx_hsspi_resume); static struct platform_driver bcm63xx_hsspi_driver = { .driver = { diff --git a/drivers/spi/spi-bcm63xx.c b/drivers/spi/spi-bcm63xx.c index 77286aef2ad..0250fa721ce 100644 --- a/drivers/spi/spi-bcm63xx.c +++ b/drivers/spi/spi-bcm63xx.c @@ -20,7 +20,6 @@ */ #include <linux/kernel.h> -#include <linux/init.h> #include <linux/clk.h> #include <linux/io.h> #include <linux/module.h> @@ -35,8 +34,6 @@ #include <bcm63xx_dev_spi.h> -#define PFX KBUILD_MODNAME - #define BCM63XX_SPI_MAX_PREPEND 15 struct bcm63xx_spi { @@ -169,7 +166,7 @@ static int bcm63xx_txrx_bufs(struct spi_device *spi, struct spi_transfer *first, transfer_list); } - init_completion(&bs->done); + reinit_completion(&bs->done); /* Fill in the Message control register */ msg_ctl = (len << SPI_BYTE_CNT_SHIFT); @@ -353,6 +350,7 @@ static int bcm63xx_spi_probe(struct platform_device *pdev) } bs = spi_master_get_devdata(master); + init_completion(&bs->done); platform_set_drvdata(pdev, master); bs->pdev = pdev; diff --git a/drivers/spi/spi-bfin-sport.c b/drivers/spi/spi-bfin-sport.c index 38941e5920b..f515c5e9db5 100644 --- a/drivers/spi/spi-bfin-sport.c +++ b/drivers/spi/spi-bfin-sport.c @@ -8,7 +8,6 @@ * Licensed under the GPL-2 or later. */ -#include <linux/init.h> #include <linux/module.h> #include <linux/delay.h> #include <linux/device.h> diff --git a/drivers/spi/spi-bfin-v3.c b/drivers/spi/spi-bfin-v3.c index 8f8598834b3..4089d0e0d84 100644 --- a/drivers/spi/spi-bfin-v3.c +++ b/drivers/spi/spi-bfin-v3.c @@ -822,7 +822,8 @@ static int bfin_spi_probe(struct platform_device *pdev) master->cleanup = bfin_spi_cleanup; master->setup = bfin_spi_setup; master->transfer_one_message = bfin_spi_transfer_one_message; - master->bits_per_word_mask = BIT(32 - 1) | BIT(16 - 1) | BIT(8 - 1); + master->bits_per_word_mask = SPI_BPW_MASK(32) | SPI_BPW_MASK(16) | + SPI_BPW_MASK(8); drv_data = spi_master_get_devdata(master); drv_data->master = master; diff --git a/drivers/spi/spi-bfin5xx.c b/drivers/spi/spi-bfin5xx.c index f0f195af75d..55e57c3eb9b 100644 --- a/drivers/spi/spi-bfin5xx.c +++ b/drivers/spi/spi-bfin5xx.c @@ -350,7 +350,6 @@ static void *bfin_spi_next_transfer(struct bfin_spi_master_data *drv_data) static void bfin_spi_giveback(struct bfin_spi_master_data *drv_data) { struct bfin_spi_slave_data *chip = drv_data->cur_chip; - struct spi_transfer *last_transfer; unsigned long flags; struct spi_message *msg; @@ -362,9 +361,6 @@ static void bfin_spi_giveback(struct bfin_spi_master_data *drv_data) queue_work(drv_data->workqueue, &drv_data->pump_messages); spin_unlock_irqrestore(&drv_data->lock, flags); - last_transfer = list_entry(msg->transfers.prev, - struct spi_transfer, transfer_list); - msg->state = NULL; if (!drv_data->cs_change) @@ -1030,10 +1026,6 @@ static int bfin_spi_setup(struct spi_device *spi) } /* translate common spi framework into our register */ - if (spi->mode & ~(SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST)) { - dev_err(&spi->dev, "unsupported spi modes detected\n"); - goto error; - } if (spi->mode & SPI_CPOL) chip->ctl_reg |= BIT_CTL_CPOL; if (spi->mode & SPI_CPHA) diff --git a/drivers/spi/spi-bitbang.c b/drivers/spi/spi-bitbang.c index bd222f6b677..dc7d2c2d643 100644 --- a/drivers/spi/spi-bitbang.c +++ b/drivers/spi/spi-bitbang.c @@ -16,7 +16,6 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include <linux/init.h> #include <linux/spinlock.h> #include <linux/workqueue.h> #include <linux/interrupt.h> @@ -467,11 +466,9 @@ EXPORT_SYMBOL_GPL(spi_bitbang_start); /** * spi_bitbang_stop - stops the task providing spi communication */ -int spi_bitbang_stop(struct spi_bitbang *bitbang) +void spi_bitbang_stop(struct spi_bitbang *bitbang) { spi_unregister_master(bitbang->master); - - return 0; } EXPORT_SYMBOL_GPL(spi_bitbang_stop); diff --git a/drivers/spi/spi-butterfly.c b/drivers/spi/spi-butterfly.c index 8081f96bd1d..ee4f91ccd8f 100644 --- a/drivers/spi/spi-butterfly.c +++ b/drivers/spi/spi-butterfly.c @@ -309,7 +309,6 @@ done: static void butterfly_detach(struct parport *p) { struct butterfly *pp; - int status; /* FIXME this global is ugly ... but, how to quickly get from * the parport to the "struct butterfly" associated with it? @@ -321,7 +320,7 @@ static void butterfly_detach(struct parport *p) butterfly = NULL; /* stop() unregisters child devices too */ - status = spi_bitbang_stop(&pp->bitbang); + spi_bitbang_stop(&pp->bitbang); /* turn off VCC */ parport_write_data(pp->port, 0); diff --git a/drivers/spi/spi-clps711x.c b/drivers/spi/spi-clps711x.c index 374ba4a48a9..4cd62f63654 100644 --- a/drivers/spi/spi-clps711x.c +++ b/drivers/spi/spi-clps711x.c @@ -11,158 +11,125 @@ #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/regmap.h> +#include <linux/mfd/syscon.h> +#include <linux/mfd/syscon/clps711x.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; +#define SYNCIO_FRMLEN(x) ((x) << 8) +#define SYNCIO_TXFRMEN (1 << 14) +struct spi_clps711x_data { + void __iomem *syncio; + struct regmap *syscon; + struct regmap *syscon1; struct clk *spi_clk; - u32 max_speed_hz; u8 *tx_buf; u8 *rx_buf; - int count; + unsigned int bpw; 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); - /* We are expect that SPI-device is not selected */ - gpio_direction_output(hw->chipselect[spi->chip_select], - !(spi->mode & SPI_CS_HIGH)); + gpio_direction_output(spi->cs_gpio, !(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) +static void spi_clps711x_setup_xfer(struct spi_device *spi, + struct spi_transfer *xfer) { - u32 speed = xfer->speed_hz ? : spi->max_speed_hz; - u8 bpw = xfer->bits_per_word; - struct spi_clps711x_data *hw = spi_master_get_devdata(spi->master); - - if (bpw != 8) { - dev_err(&spi->dev, "Unsupported master bus width %i\n", bpw); - return -EINVAL; - } + struct spi_master *master = spi->master; + struct spi_clps711x_data *hw = spi_master_get_devdata(master); /* 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); + if (xfer->speed_hz >= master->max_speed_hz) + regmap_update_bits(hw->syscon1, SYSCON_OFFSET, + SYSCON1_ADCKSEL_MASK, SYSCON1_ADCKSEL(3)); + else if (xfer->speed_hz >= (master->max_speed_hz / 2)) + regmap_update_bits(hw->syscon1, SYSCON_OFFSET, + SYSCON1_ADCKSEL_MASK, SYSCON1_ADCKSEL(2)); + else if (xfer->speed_hz >= (master->max_speed_hz / 8)) + regmap_update_bits(hw->syscon1, SYSCON_OFFSET, + SYSCON1_ADCKSEL_MASK, SYSCON1_ADCKSEL(1)); else - clps_writel((clps_readl(SYSCON1) & ~SYSCON1_ADCKSEL_MASK) | - SYSCON1_ADCKSEL(0), SYSCON1); - - return 0; + regmap_update_bits(hw->syscon1, SYSCON_OFFSET, + SYSCON1_ADCKSEL_MASK, SYSCON1_ADCKSEL(0)); } -static int spi_clps711x_transfer_one_message(struct spi_master *master, - struct spi_message *msg) +static int spi_clps711x_prepare_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; - } + struct spi_device *spi = msg->spi; - gpio_set_value(cs, !!(msg->spi->mode & SPI_CS_HIGH)); - - reinit_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); + /* Setup mode for transfer */ + return regmap_update_bits(hw->syscon, SYSCON_OFFSET, SYSCON3_ADCCKNSEN, + (spi->mode & SPI_CPHA) ? + SYSCON3_ADCCKNSEN : 0); +} - if (xfer->delay_usecs) - udelay(xfer->delay_usecs); +static int spi_clps711x_transfer_one(struct spi_master *master, + struct spi_device *spi, + struct spi_transfer *xfer) +{ + struct spi_clps711x_data *hw = spi_master_get_devdata(master); + u8 data; - if (xfer->cs_change || - list_is_last(&xfer->transfer_list, &msg->transfers)) - gpio_set_value(cs, !(msg->spi->mode & SPI_CS_HIGH)); + spi_clps711x_setup_xfer(spi, xfer); - msg->actual_length += xfer->len; - } + hw->len = xfer->len; + hw->bpw = xfer->bits_per_word; + hw->tx_buf = (u8 *)xfer->tx_buf; + hw->rx_buf = (u8 *)xfer->rx_buf; -out_xfr: - msg->status = status; - spi_finalize_current_message(master); + /* Initiate transfer */ + data = hw->tx_buf ? *hw->tx_buf++ : 0; + writel(data | SYNCIO_FRMLEN(hw->bpw) | SYNCIO_TXFRMEN, hw->syncio); - return 0; + return 1; } static irqreturn_t spi_clps711x_isr(int irq, void *dev_id) { - struct spi_clps711x_data *hw = (struct spi_clps711x_data *)dev_id; - u32 data; + struct spi_master *master = dev_id; + struct spi_clps711x_data *hw = spi_master_get_devdata(master); + u8 data; /* Handle RX */ - data = clps_readb(SYNCIO); + data = readb(hw->syncio); if (hw->rx_buf) - hw->rx_buf[hw->count] = (u8)data; - - hw->count++; + *hw->rx_buf++ = data; /* 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); + if (--hw->len > 0) { + data = hw->tx_buf ? *hw->tx_buf++ : 0; + writel(data | SYNCIO_FRMLEN(hw->bpw) | SYNCIO_TXFRMEN, + hw->syncio); } else - complete(&hw->done); + spi_finalize_current_transfer(master); 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); + struct spi_master *master; + struct resource *res; + int i, irq, ret; if (!pdata) { dev_err(&pdev->dev, "No platform data supplied\n"); @@ -174,33 +141,37 @@ static int spi_clps711x_probe(struct platform_device *pdev) 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"); + irq = platform_get_irq(pdev, 0); + if (irq < 0) + return irq; + + master = spi_alloc_master(&pdev->dev, sizeof(*hw)); + if (!master) return -ENOMEM; + + master->cs_gpios = devm_kzalloc(&pdev->dev, sizeof(int) * + pdata->num_chipselect, GFP_KERNEL); + if (!master->cs_gpios) { + ret = -ENOMEM; + goto err_out; } master->bus_num = pdev->id; master->mode_bits = SPI_CPHA | SPI_CS_HIGH; - master->bits_per_word_mask = SPI_BPW_MASK(8); + master->bits_per_word_mask = SPI_BPW_RANGE_MASK(1, 8); master->num_chipselect = pdata->num_chipselect; master->setup = spi_clps711x_setup; - master->transfer_one_message = spi_clps711x_transfer_one_message; + master->prepare_message = spi_clps711x_prepare_message; + master->transfer_one = spi_clps711x_transfer_one; 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 (devm_gpio_request(&pdev->dev, hw->chipselect[i], NULL)) { + master->cs_gpios[i] = pdata->chipselect[i]; + ret = devm_gpio_request(&pdev->dev, master->cs_gpios[i], + DRIVER_NAME); + if (ret) { dev_err(&pdev->dev, "Can't get CS GPIO %i\n", i); - ret = -EINVAL; goto err_out; } } @@ -211,29 +182,45 @@ static int spi_clps711x_probe(struct platform_device *pdev) ret = PTR_ERR(hw->spi_clk); goto err_out; } - hw->max_speed_hz = clk_get_rate(hw->spi_clk); + master->max_speed_hz = clk_get_rate(hw->spi_clk); - init_completion(&hw->done); platform_set_drvdata(pdev, master); + hw->syscon = syscon_regmap_lookup_by_pdevname("syscon.3"); + if (IS_ERR(hw->syscon)) { + ret = PTR_ERR(hw->syscon); + goto err_out; + } + + hw->syscon1 = syscon_regmap_lookup_by_pdevname("syscon.1"); + if (IS_ERR(hw->syscon1)) { + ret = PTR_ERR(hw->syscon1); + goto err_out; + } + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + hw->syncio = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(hw->syncio)) { + ret = PTR_ERR(hw->syncio); + goto err_out; + } + /* Disable extended mode due hardware problems */ - clps_writew(clps_readw(SYSCON3) & ~SYSCON3_ADCCON, SYSCON3); + regmap_update_bits(hw->syscon, SYSCON_OFFSET, SYSCON3_ADCCON, 0); /* Clear possible pending interrupt */ - clps_readl(SYNCIO); + readl(hw->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"); + ret = devm_request_irq(&pdev->dev, irq, spi_clps711x_isr, 0, + dev_name(&pdev->dev), master); + if (ret) goto err_out; - } ret = devm_spi_register_master(&pdev->dev, master); if (!ret) { dev_info(&pdev->dev, "SPI bus driver initialized. Master clock %u Hz\n", - hw->max_speed_hz); + master->max_speed_hz); return 0; } diff --git a/drivers/spi/spi-coldfire-qspi.c b/drivers/spi/spi-coldfire-qspi.c index 28ae470397a..e2fa628e55e 100644 --- a/drivers/spi/spi-coldfire-qspi.c +++ b/drivers/spi/spi-coldfire-qspi.c @@ -77,8 +77,6 @@ struct mcfqspi { struct mcfqspi_cs_control *cs_control; wait_queue_head_t waitq; - - struct device *dev; }; static void mcfqspi_wr_qmr(struct mcfqspi *mcfqspi, u16 val) @@ -135,13 +133,13 @@ static void mcfqspi_cs_deselect(struct mcfqspi *mcfqspi, u8 chip_select, static int mcfqspi_cs_setup(struct mcfqspi *mcfqspi) { - return (mcfqspi->cs_control && mcfqspi->cs_control->setup) ? + return (mcfqspi->cs_control->setup) ? mcfqspi->cs_control->setup(mcfqspi->cs_control) : 0; } static void mcfqspi_cs_teardown(struct mcfqspi *mcfqspi) { - if (mcfqspi->cs_control && mcfqspi->cs_control->teardown) + if (mcfqspi->cs_control->teardown) mcfqspi->cs_control->teardown(mcfqspi->cs_control); } @@ -300,68 +298,45 @@ static void mcfqspi_transfer_msg16(struct mcfqspi *mcfqspi, unsigned count, } } -static int mcfqspi_transfer_one_message(struct spi_master *master, - struct spi_message *msg) +static void mcfqspi_set_cs(struct spi_device *spi, bool enable) { - struct mcfqspi *mcfqspi = spi_master_get_devdata(master); - struct spi_device *spi = msg->spi; - struct spi_transfer *t; - int status = 0; - - list_for_each_entry(t, &msg->transfers, transfer_list) { - bool cs_high = spi->mode & SPI_CS_HIGH; - u16 qmr = MCFQSPI_QMR_MSTR; - - qmr |= t->bits_per_word << 10; - if (spi->mode & SPI_CPHA) - qmr |= MCFQSPI_QMR_CPHA; - if (spi->mode & SPI_CPOL) - qmr |= MCFQSPI_QMR_CPOL; - if (t->speed_hz) - qmr |= mcfqspi_qmr_baud(t->speed_hz); - else - qmr |= mcfqspi_qmr_baud(spi->max_speed_hz); - mcfqspi_wr_qmr(mcfqspi, qmr); + struct mcfqspi *mcfqspi = spi_master_get_devdata(spi->master); + bool cs_high = spi->mode & SPI_CS_HIGH; + if (enable) mcfqspi_cs_select(mcfqspi, spi->chip_select, cs_high); + else + mcfqspi_cs_deselect(mcfqspi, spi->chip_select, cs_high); +} - mcfqspi_wr_qir(mcfqspi, MCFQSPI_QIR_SPIFE); - if (t->bits_per_word == 8) - mcfqspi_transfer_msg8(mcfqspi, t->len, t->tx_buf, - t->rx_buf); - else - mcfqspi_transfer_msg16(mcfqspi, t->len / 2, t->tx_buf, - t->rx_buf); - mcfqspi_wr_qir(mcfqspi, 0); - - if (t->delay_usecs) - udelay(t->delay_usecs); - if (t->cs_change) { - if (!list_is_last(&t->transfer_list, &msg->transfers)) - mcfqspi_cs_deselect(mcfqspi, spi->chip_select, - cs_high); - } else { - if (list_is_last(&t->transfer_list, &msg->transfers)) - mcfqspi_cs_deselect(mcfqspi, spi->chip_select, - cs_high); - } - msg->actual_length += t->len; - } - msg->status = status; - spi_finalize_current_message(master); - - return status; +static int mcfqspi_transfer_one(struct spi_master *master, + struct spi_device *spi, + struct spi_transfer *t) +{ + struct mcfqspi *mcfqspi = spi_master_get_devdata(master); + u16 qmr = MCFQSPI_QMR_MSTR; + + qmr |= t->bits_per_word << 10; + if (spi->mode & SPI_CPHA) + qmr |= MCFQSPI_QMR_CPHA; + if (spi->mode & SPI_CPOL) + qmr |= MCFQSPI_QMR_CPOL; + qmr |= mcfqspi_qmr_baud(t->speed_hz); + mcfqspi_wr_qmr(mcfqspi, qmr); + + mcfqspi_wr_qir(mcfqspi, MCFQSPI_QIR_SPIFE); + if (t->bits_per_word == 8) + mcfqspi_transfer_msg8(mcfqspi, t->len, t->tx_buf, t->rx_buf); + else + mcfqspi_transfer_msg16(mcfqspi, t->len / 2, t->tx_buf, + t->rx_buf); + mcfqspi_wr_qir(mcfqspi, 0); + return 0; } static int mcfqspi_setup(struct spi_device *spi) { - if (spi->chip_select >= spi->master->num_chipselect) { - dev_dbg(&spi->dev, "%d chip select is out of range\n", - spi->chip_select); - return -EINVAL; - } - mcfqspi_cs_deselect(spi_master_get_devdata(spi->master), spi->chip_select, spi->mode & SPI_CS_HIGH); @@ -388,6 +363,11 @@ static int mcfqspi_probe(struct platform_device *pdev) return -ENOENT; } + if (!pdata->cs_control) { + dev_dbg(&pdev->dev, "pdata->cs_control is NULL\n"); + return -EINVAL; + } + master = spi_alloc_master(&pdev->dev, sizeof(*mcfqspi)); if (master == NULL) { dev_dbg(&pdev->dev, "spi_alloc_master failed\n"); @@ -436,12 +416,12 @@ static int mcfqspi_probe(struct platform_device *pdev) } init_waitqueue_head(&mcfqspi->waitq); - mcfqspi->dev = &pdev->dev; master->mode_bits = SPI_CS_HIGH | SPI_CPOL | SPI_CPHA; master->bits_per_word_mask = SPI_BPW_RANGE_MASK(8, 16); master->setup = mcfqspi_setup; - master->transfer_one_message = mcfqspi_transfer_one_message; + master->set_cs = mcfqspi_set_cs; + master->transfer_one = mcfqspi_transfer_one; master->auto_runtime_pm = true; platform_set_drvdata(pdev, master); @@ -451,7 +431,7 @@ static int mcfqspi_probe(struct platform_device *pdev) dev_dbg(&pdev->dev, "spi_register_master failed\n"); goto fail2; } - pm_runtime_enable(mcfqspi->dev); + pm_runtime_enable(&pdev->dev); dev_info(&pdev->dev, "Coldfire QSPI bus driver\n"); @@ -473,9 +453,8 @@ static int mcfqspi_remove(struct platform_device *pdev) { struct spi_master *master = platform_get_drvdata(pdev); struct mcfqspi *mcfqspi = spi_master_get_devdata(master); - struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - pm_runtime_disable(mcfqspi->dev); + pm_runtime_disable(&pdev->dev); /* disable the hardware (set the baud rate to 0) */ mcfqspi_wr_qmr(mcfqspi, MCFQSPI_QMR_MSTR); @@ -490,8 +469,11 @@ static int mcfqspi_suspend(struct device *dev) { struct spi_master *master = dev_get_drvdata(dev); struct mcfqspi *mcfqspi = spi_master_get_devdata(master); + int ret; - spi_master_suspend(master); + ret = spi_master_suspend(master); + if (ret) + return ret; clk_disable(mcfqspi->clk); @@ -503,11 +485,9 @@ static int mcfqspi_resume(struct device *dev) struct spi_master *master = dev_get_drvdata(dev); struct mcfqspi *mcfqspi = spi_master_get_devdata(master); - spi_master_resume(master); - clk_enable(mcfqspi->clk); - return 0; + return spi_master_resume(master); } #endif diff --git a/drivers/spi/spi-davinci.c b/drivers/spi/spi-davinci.c index 5e7389faa2a..50f75098925 100644 --- a/drivers/spi/spi-davinci.c +++ b/drivers/spi/spi-davinci.c @@ -802,8 +802,7 @@ static int spi_davinci_get_pdata(struct platform_device *pdev, pdata = &dspi->pdata; pdata->version = SPI_VERSION_1; - match = of_match_device(of_match_ptr(davinci_spi_of_match), - &pdev->dev); + match = of_match_device(davinci_spi_of_match, &pdev->dev); if (!match) return -ENODEV; @@ -824,7 +823,6 @@ static int spi_davinci_get_pdata(struct platform_device *pdev, return 0; } #else -#define davinci_spi_of_match NULL static struct davinci_spi_platform_data *spi_davinci_get_pdata(struct platform_device *pdev, struct davinci_spi *dspi) @@ -864,10 +862,6 @@ static int davinci_spi_probe(struct platform_device *pdev) platform_set_drvdata(pdev, master); dspi = spi_master_get_devdata(master); - if (dspi == NULL) { - ret = -ENOENT; - goto free_master; - } if (dev_get_platdata(&pdev->dev)) { pdata = dev_get_platdata(&pdev->dev); @@ -908,10 +902,6 @@ static int davinci_spi_probe(struct platform_device *pdev) goto free_master; dspi->bitbang.master = master; - if (dspi->bitbang.master == NULL) { - ret = -ENODEV; - goto free_master; - } dspi->clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(dspi->clk)) { @@ -1040,7 +1030,7 @@ static struct platform_driver davinci_spi_driver = { .driver = { .name = "spi_davinci", .owner = THIS_MODULE, - .of_match_table = davinci_spi_of_match, + .of_match_table = of_match_ptr(davinci_spi_of_match), }, .probe = davinci_spi_probe, .remove = davinci_spi_remove, diff --git a/drivers/spi/spi-dw-mmio.c b/drivers/spi/spi-dw-mmio.c index 9af56cdf154..1492f5ee9aa 100644 --- a/drivers/spi/spi-dw-mmio.c +++ b/drivers/spi/spi-dw-mmio.c @@ -66,7 +66,7 @@ static int dw_spi_mmio_probe(struct platform_device *pdev) if (ret) return ret; - dws->bus_num = 0; + dws->bus_num = pdev->id; dws->num_cs = 4; dws->max_freq = clk_get_rate(dwsmmio->clk); diff --git a/drivers/spi/spi-dw.c b/drivers/spi/spi-dw.c index bf98d63d92b..712ac5629cd 100644 --- a/drivers/spi/spi-dw.c +++ b/drivers/spi/spi-dw.c @@ -276,8 +276,7 @@ static void giveback(struct dw_spi *dws) queue_work(dws->workqueue, &dws->pump_messages); spin_unlock_irqrestore(&dws->lock, flags); - last_transfer = list_entry(msg->transfers.prev, - struct spi_transfer, + last_transfer = list_last_entry(&msg->transfers, struct spi_transfer, transfer_list); if (!last_transfer->cs_change && dws->cs_control) @@ -439,12 +438,6 @@ static void pump_transfers(unsigned long data) if (transfer->speed_hz != speed) { speed = transfer->speed_hz; - if (speed > dws->max_freq) { - printk(KERN_ERR "MRST SPI0: unsupported" - "freq: %dHz\n", speed); - message->status = -EIO; - goto early_exit; - } /* clk_div doesn't support odd number */ clk_div = dws->max_freq / speed; @@ -671,12 +664,6 @@ static int dw_spi_setup(struct spi_device *spi) return 0; } -static void dw_spi_cleanup(struct spi_device *spi) -{ - struct chip_data *chip = spi_get_ctldata(spi); - kfree(chip); -} - static int init_queue(struct dw_spi *dws) { INIT_LIST_HEAD(&dws->queue); @@ -806,9 +793,9 @@ int dw_spi_add_host(struct device *dev, struct dw_spi *dws) master->bits_per_word_mask = SPI_BPW_MASK(8) | SPI_BPW_MASK(16); master->bus_num = dws->bus_num; master->num_chipselect = dws->num_cs; - master->cleanup = dw_spi_cleanup; master->setup = dw_spi_setup; master->transfer = dw_spi_transfer; + master->max_speed_hz = dws->max_freq; /* Basic HW init */ spi_hw_init(dws); diff --git a/drivers/spi/spi-efm32.c b/drivers/spi/spi-efm32.c index d4d3cc53479..be44a3eeb5e 100644 --- a/drivers/spi/spi-efm32.c +++ b/drivers/spi/spi-efm32.c @@ -198,7 +198,7 @@ static int efm32_spi_txrx_bufs(struct spi_device *spi, struct spi_transfer *t) efm32_spi_filltx(ddata); - init_completion(&ddata->done); + reinit_completion(&ddata->done); efm32_spi_write32(ddata, REG_IF_TXBL | REG_IF_RXDATAV, REG_IEN); @@ -287,17 +287,17 @@ static u32 efm32_spi_get_configured_location(struct efm32_spi_ddata *ddata) return (reg & REG_ROUTE_LOCATION__MASK) >> __ffs(REG_ROUTE_LOCATION__MASK); } -static int efm32_spi_probe_dt(struct platform_device *pdev, +static void efm32_spi_probe_dt(struct platform_device *pdev, struct spi_master *master, struct efm32_spi_ddata *ddata) { struct device_node *np = pdev->dev.of_node; u32 location; int ret; - if (!np) - return 1; - - ret = of_property_read_u32(np, "location", &location); + ret = of_property_read_u32(np, "efm32,location", &location); + if (ret) + /* fall back to old and (wrongly) generic property "location" */ + ret = of_property_read_u32(np, "location", &location); if (!ret) { dev_dbg(&pdev->dev, "using location %u\n", location); } else { @@ -308,11 +308,6 @@ static int efm32_spi_probe_dt(struct platform_device *pdev, } ddata->pdata.location = location; - - /* spi core takes care about the bus number using an alias */ - master->bus_num = -1; - - return 0; } static int efm32_spi_probe(struct platform_device *pdev) @@ -322,9 +317,14 @@ static int efm32_spi_probe(struct platform_device *pdev) int ret; struct spi_master *master; struct device_node *np = pdev->dev.of_node; - unsigned int num_cs, i; + int num_cs, i; + + if (!np) + return -EINVAL; num_cs = of_gpio_named_count(np, "cs-gpios"); + if (num_cs < 0) + return num_cs; master = spi_alloc_master(&pdev->dev, sizeof(*ddata) + num_cs * sizeof(unsigned)); @@ -349,6 +349,7 @@ static int efm32_spi_probe(struct platform_device *pdev) ddata->bitbang.txrx_bufs = efm32_spi_txrx_bufs; spin_lock_init(&ddata->lock); + init_completion(&ddata->done); ddata->clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(ddata->clk)) { @@ -415,23 +416,7 @@ static int efm32_spi_probe(struct platform_device *pdev) goto err; } - ret = efm32_spi_probe_dt(pdev, master, ddata); - if (ret > 0) { - /* not created by device tree */ - const struct efm32_spi_pdata *pdata = - dev_get_platdata(&pdev->dev); - - if (pdata) - ddata->pdata = *pdata; - else - ddata->pdata.location = - efm32_spi_get_configured_location(ddata); - - master->bus_num = pdev->id; - - } else if (ret < 0) { - goto err_disable_clk; - } + efm32_spi_probe_dt(pdev, master, ddata); efm32_spi_write32(ddata, 0, REG_IEN); efm32_spi_write32(ddata, REG_ROUTE_TXPEN | REG_ROUTE_RXPEN | @@ -487,6 +472,9 @@ static int efm32_spi_remove(struct platform_device *pdev) static const struct of_device_id efm32_spi_dt_ids[] = { { + .compatible = "energymicro,efm32-spi", + }, { + /* doesn't follow the "vendor,device" scheme, don't use */ .compatible = "efm32,spi", }, { /* sentinel */ diff --git a/drivers/spi/spi-ep93xx.c b/drivers/spi/spi-ep93xx.c index 1bfaed6e407..2f675d32df0 100644 --- a/drivers/spi/spi-ep93xx.c +++ b/drivers/spi/spi-ep93xx.c @@ -73,8 +73,6 @@ * @clk: clock for the controller * @regs_base: pointer to ioremap()'d registers * @sspdr_phys: physical address of the SSPDR register - * @min_rate: minimum clock rate (in Hz) supported by the controller - * @max_rate: maximum clock rate (in Hz) supported by the controller * @wait: wait here until given transfer is completed * @current_msg: message that is currently processed (or %NULL if none) * @tx: current byte in transfer to transmit @@ -95,8 +93,6 @@ struct ep93xx_spi { struct clk *clk; void __iomem *regs_base; unsigned long sspdr_phys; - unsigned long min_rate; - unsigned long max_rate; struct completion wait; struct spi_message *current_msg; size_t tx; @@ -199,9 +195,9 @@ static void ep93xx_spi_disable_interrupts(const struct ep93xx_spi *espi) * @div_scr: pointer to return the scr divider */ static int ep93xx_spi_calc_divisors(const struct ep93xx_spi *espi, - unsigned long rate, - u8 *div_cpsr, u8 *div_scr) + u32 rate, u8 *div_cpsr, u8 *div_scr) { + struct spi_master *master = platform_get_drvdata(espi->pdev); unsigned long spi_clk_rate = clk_get_rate(espi->clk); int cpsr, scr; @@ -210,7 +206,7 @@ static int ep93xx_spi_calc_divisors(const struct ep93xx_spi *espi, * controller. Note that minimum value is already checked in * ep93xx_spi_transfer_one_message(). */ - rate = clamp(rate, espi->min_rate, espi->max_rate); + rate = clamp(rate, master->min_speed_hz, master->max_speed_hz); /* * Calculate divisors so that we can get speed according the @@ -735,13 +731,6 @@ static int ep93xx_spi_transfer_one_message(struct spi_master *master, struct spi_message *msg) { struct ep93xx_spi *espi = spi_master_get_devdata(master); - struct spi_transfer *t; - - /* first validate each transfer */ - list_for_each_entry(t, &msg->transfers, transfer_list) { - if (t->speed_hz < espi->min_rate) - return -EINVAL; - } msg->state = NULL; msg->status = 0; @@ -917,8 +906,8 @@ static int ep93xx_spi_probe(struct platform_device *pdev) * Calculate maximum and minimum supported clock rates * for the controller. */ - espi->max_rate = clk_get_rate(espi->clk) / 2; - espi->min_rate = clk_get_rate(espi->clk) / (254 * 256); + master->max_speed_hz = clk_get_rate(espi->clk) / 2; + master->min_speed_hz = clk_get_rate(espi->clk) / (254 * 256); espi->pdev = pdev; espi->sspdr_phys = res->start + SSPDR; diff --git a/drivers/spi/spi-falcon.c b/drivers/spi/spi-falcon.c index dd5bd468e96..09965f069a1 100644 --- a/drivers/spi/spi-falcon.c +++ b/drivers/spi/spi-falcon.c @@ -312,9 +312,6 @@ static int falcon_sflash_setup(struct spi_device *spi) unsigned int i; unsigned long flags; - if (spi->chip_select > 0) - return -ENODEV; - spin_lock_irqsave(&ebu_lock, flags); if (spi->max_speed_hz >= CLOCK_100M) { @@ -422,9 +419,7 @@ static int falcon_sflash_probe(struct platform_device *pdev) priv->master = master; master->mode_bits = SPI_MODE_3; - master->num_chipselect = 1; master->flags = SPI_MASTER_HALF_DUPLEX; - master->bus_num = -1; master->setup = falcon_sflash_setup; master->prepare_transfer_hardware = falcon_sflash_prepare_xfer; master->transfer_one_message = falcon_sflash_xfer_one; diff --git a/drivers/spi/spi-fsl-dspi.c b/drivers/spi/spi-fsl-dspi.c index a25392065d9..d565eeee3bd 100644 --- a/drivers/spi/spi-fsl-dspi.c +++ b/drivers/spi/spi-fsl-dspi.c @@ -18,6 +18,7 @@ #include <linux/interrupt.h> #include <linux/errno.h> #include <linux/platform_device.h> +#include <linux/regmap.h> #include <linux/sched.h> #include <linux/delay.h> #include <linux/io.h> @@ -108,11 +109,11 @@ struct fsl_dspi { struct spi_bitbang bitbang; struct platform_device *pdev; - void __iomem *base; + struct regmap *regmap; int irq; - struct clk *clk; + struct clk *clk; - struct spi_transfer *cur_transfer; + struct spi_transfer *cur_transfer; struct chip_data *cur_chip; size_t len; void *tx; @@ -123,24 +124,17 @@ struct fsl_dspi { u8 cs; u16 void_write_data; - wait_queue_head_t waitq; - u32 waitflags; + wait_queue_head_t waitq; + u32 waitflags; }; static inline int is_double_byte_mode(struct fsl_dspi *dspi) { - return ((readl(dspi->base + SPI_CTAR(dspi->cs)) & SPI_FRAME_BITS_MASK) - == SPI_FRAME_BITS(8)) ? 0 : 1; -} + unsigned int val; -static void set_bit_mode(struct fsl_dspi *dspi, unsigned char bits) -{ - u32 temp; + regmap_read(dspi->regmap, SPI_CTAR(dspi->cs), &val); - temp = readl(dspi->base + SPI_CTAR(dspi->cs)); - temp &= ~SPI_FRAME_BITS_MASK; - temp |= SPI_FRAME_BITS(bits); - writel(temp, dspi->base + SPI_CTAR(dspi->cs)); + return ((val & SPI_FRAME_BITS_MASK) == SPI_FRAME_BITS(8)) ? 0 : 1; } static void hz_to_spi_baud(char *pbr, char *br, int speed_hz, @@ -188,7 +182,8 @@ static int dspi_transfer_write(struct fsl_dspi *dspi) */ if (tx_word && (dspi->len == 1)) { dspi->dataflags |= TRAN_STATE_WORD_ODD_NUM; - set_bit_mode(dspi, 8); + regmap_update_bits(dspi->regmap, SPI_CTAR(dspi->cs), + SPI_FRAME_BITS_MASK, SPI_FRAME_BITS(8)); tx_word = 0; } @@ -238,7 +233,8 @@ static int dspi_transfer_write(struct fsl_dspi *dspi) dspi_pushr |= SPI_PUSHR_CTCNT; /* clear counter */ } - writel(dspi_pushr, dspi->base + SPI_PUSHR); + regmap_write(dspi->regmap, SPI_PUSHR, dspi_pushr); + tx_count++; } @@ -253,17 +249,23 @@ static int dspi_transfer_read(struct fsl_dspi *dspi) while ((dspi->rx < dspi->rx_end) && (rx_count < DSPI_FIFO_SIZE)) { if (rx_word) { + unsigned int val; + if ((dspi->rx_end - dspi->rx) == 1) break; - d = SPI_POPR_RXDATA(readl(dspi->base + SPI_POPR)); + regmap_read(dspi->regmap, SPI_POPR, &val); + d = SPI_POPR_RXDATA(val); if (!(dspi->dataflags & TRAN_STATE_RX_VOID)) *(u16 *)dspi->rx = d; dspi->rx += 2; } else { - d = SPI_POPR_RXDATA(readl(dspi->base + SPI_POPR)); + unsigned int val; + + regmap_read(dspi->regmap, SPI_POPR, &val); + d = SPI_POPR_RXDATA(val); if (!(dspi->dataflags & TRAN_STATE_RX_VOID)) *(u8 *)dspi->rx = d; dspi->rx++; @@ -295,13 +297,13 @@ static int dspi_txrx_transfer(struct spi_device *spi, struct spi_transfer *t) if (!dspi->tx) dspi->dataflags |= TRAN_STATE_TX_VOID; - writel(dspi->cur_chip->mcr_val, dspi->base + SPI_MCR); - writel(dspi->cur_chip->ctar_val, dspi->base + SPI_CTAR(dspi->cs)); - writel(SPI_RSER_EOQFE, dspi->base + SPI_RSER); + regmap_write(dspi->regmap, SPI_MCR, dspi->cur_chip->mcr_val); + regmap_write(dspi->regmap, SPI_CTAR(dspi->cs), dspi->cur_chip->ctar_val); + regmap_write(dspi->regmap, SPI_RSER, SPI_RSER_EOQFE); if (t->speed_hz) - writel(dspi->cur_chip->ctar_val, - dspi->base + SPI_CTAR(dspi->cs)); + regmap_write(dspi->regmap, SPI_CTAR(dspi->cs), + dspi->cur_chip->ctar_val); dspi_transfer_write(dspi); @@ -315,7 +317,9 @@ static int dspi_txrx_transfer(struct spi_device *spi, struct spi_transfer *t) static void dspi_chipselect(struct spi_device *spi, int value) { struct fsl_dspi *dspi = spi_master_get_devdata(spi->master); - u32 pushr = readl(dspi->base + SPI_PUSHR); + unsigned int pushr; + + regmap_read(dspi->regmap, SPI_PUSHR, &pushr); switch (value) { case BITBANG_CS_ACTIVE: @@ -326,7 +330,7 @@ static void dspi_chipselect(struct spi_device *spi, int value) break; } - writel(pushr, dspi->base + SPI_PUSHR); + regmap_write(dspi->regmap, SPI_PUSHR, pushr); } static int dspi_setup_transfer(struct spi_device *spi, struct spi_transfer *t) @@ -338,7 +342,8 @@ static int dspi_setup_transfer(struct spi_device *spi, struct spi_transfer *t) /* Only alloc on first setup */ chip = spi_get_ctldata(spi); if (chip == NULL) { - chip = kcalloc(1, sizeof(struct chip_data), GFP_KERNEL); + chip = devm_kzalloc(&spi->dev, sizeof(struct chip_data), + GFP_KERNEL); if (!chip) return -ENOMEM; } @@ -349,7 +354,6 @@ static int dspi_setup_transfer(struct spi_device *spi, struct spi_transfer *t) fmsz = spi->bits_per_word - 1; } else { pr_err("Invalid wordsize\n"); - kfree(chip); return -ENODEV; } @@ -382,13 +386,15 @@ static irqreturn_t dspi_interrupt(int irq, void *dev_id) { struct fsl_dspi *dspi = (struct fsl_dspi *)dev_id; - writel(SPI_SR_EOQF, dspi->base + SPI_SR); + regmap_write(dspi->regmap, SPI_SR, SPI_SR_EOQF); dspi_transfer_read(dspi); if (!dspi->len) { if (dspi->dataflags & TRAN_STATE_WORD_ODD_NUM) - set_bit_mode(dspi, 16); + regmap_update_bits(dspi->regmap, SPI_CTAR(dspi->cs), + SPI_FRAME_BITS_MASK, SPI_FRAME_BITS(16)); + dspi->waitflags = 1; wake_up_interruptible(&dspi->waitq); } else { @@ -430,8 +436,13 @@ static int dspi_resume(struct device *dev) } #endif /* CONFIG_PM_SLEEP */ -static const struct dev_pm_ops dspi_pm = { - SET_SYSTEM_SLEEP_PM_OPS(dspi_suspend, dspi_resume) +static SIMPLE_DEV_PM_OPS(dspi_pm, dspi_suspend, dspi_resume); + +static struct regmap_config dspi_regmap_config = { + .reg_bits = 32, + .val_bits = 32, + .reg_stride = 4, + .max_register = 0x88, }; static int dspi_probe(struct platform_device *pdev) @@ -440,6 +451,7 @@ static int dspi_probe(struct platform_device *pdev) struct spi_master *master; struct fsl_dspi *dspi; struct resource *res; + void __iomem *base; int ret = 0, cs_num, bus_num; master = spi_alloc_master(&pdev->dev, sizeof(struct fsl_dspi)); @@ -474,12 +486,24 @@ static int dspi_probe(struct platform_device *pdev) master->bus_num = bus_num; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - dspi->base = devm_ioremap_resource(&pdev->dev, res); - if (IS_ERR(dspi->base)) { - ret = PTR_ERR(dspi->base); + base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(base)) { + ret = PTR_ERR(base); goto out_master_put; } + dspi_regmap_config.lock_arg = dspi; + dspi_regmap_config.val_format_endian = + of_property_read_bool(np, "big-endian") + ? REGMAP_ENDIAN_BIG : REGMAP_ENDIAN_DEFAULT; + dspi->regmap = devm_regmap_init_mmio_clk(&pdev->dev, "dspi", base, + &dspi_regmap_config); + if (IS_ERR(dspi->regmap)) { + dev_err(&pdev->dev, "failed to init regmap: %ld\n", + PTR_ERR(dspi->regmap)); + return PTR_ERR(dspi->regmap); + } + dspi->irq = platform_get_irq(pdev, 0); if (dspi->irq < 0) { dev_err(&pdev->dev, "can't get platform irq\n"); diff --git a/drivers/spi/spi-fsl-espi.c b/drivers/spi/spi-fsl-espi.c index 428dc7a6b62..6fb2b75df82 100644 --- a/drivers/spi/spi-fsl-espi.c +++ b/drivers/spi/spi-fsl-espi.c @@ -219,13 +219,8 @@ static int fsl_espi_bufs(struct spi_device *spi, struct spi_transfer *t) struct mpc8xxx_spi *mpc8xxx_spi = spi_master_get_devdata(spi->master); struct fsl_espi_reg *reg_base = mpc8xxx_spi->reg_base; unsigned int len = t->len; - u8 bits_per_word; int ret; - bits_per_word = spi->bits_per_word; - if (t->bits_per_word) - bits_per_word = t->bits_per_word; - mpc8xxx_spi->len = t->len; len = roundup(len, 4) / 4; diff --git a/drivers/spi/spi-fsl-lib.c b/drivers/spi/spi-fsl-lib.c index 0b75f26158a..e5d45fca355 100644 --- a/drivers/spi/spi-fsl-lib.c +++ b/drivers/spi/spi-fsl-lib.c @@ -200,7 +200,7 @@ int of_mpc8xxx_spi_probe(struct platform_device *ofdev) const void *prop; int ret = -ENOMEM; - pinfo = kzalloc(sizeof(*pinfo), GFP_KERNEL); + pinfo = devm_kzalloc(&ofdev->dev, sizeof(*pinfo), GFP_KERNEL); if (!pinfo) return -ENOMEM; @@ -215,15 +215,13 @@ int of_mpc8xxx_spi_probe(struct platform_device *ofdev) pdata->sysclk = get_brgfreq(); if (pdata->sysclk == -1) { pdata->sysclk = fsl_get_sys_freq(); - if (pdata->sysclk == -1) { - ret = -ENODEV; - goto err; - } + if (pdata->sysclk == -1) + return -ENODEV; } #else ret = of_property_read_u32(np, "clock-frequency", &pdata->sysclk); if (ret) - goto err; + return ret; #endif prop = of_get_property(np, "mode", NULL); @@ -237,8 +235,4 @@ int of_mpc8xxx_spi_probe(struct platform_device *ofdev) pdata->flags = SPI_CPM_MODE | SPI_CPM1; return 0; - -err: - kfree(pinfo); - return ret; } diff --git a/drivers/spi/spi-fsl-spi.c b/drivers/spi/spi-fsl-spi.c index 119f7af9453..f35488ed62a 100644 --- a/drivers/spi/spi-fsl-spi.c +++ b/drivers/spi/spi-fsl-spi.c @@ -239,12 +239,6 @@ static int fsl_spi_setup_transfer(struct spi_device *spi, if (!bits_per_word) bits_per_word = spi->bits_per_word; - /* Make sure its a bit width we support [4..16, 32] */ - if ((bits_per_word < 4) - || ((bits_per_word > 16) && (bits_per_word != 32)) - || (bits_per_word > mpc8xxx_spi->max_bits_per_word)) - return -EINVAL; - if (!hz) hz = spi->max_speed_hz; @@ -362,18 +356,28 @@ static int fsl_spi_bufs(struct spi_device *spi, struct spi_transfer *t, static void fsl_spi_do_one_msg(struct spi_message *m) { struct spi_device *spi = m->spi; - struct spi_transfer *t; + struct spi_transfer *t, *first; unsigned int cs_change; const int nsecs = 50; int status; - cs_change = 1; - status = 0; + /* Don't allow changes if CS is active */ + first = list_first_entry(&m->transfers, struct spi_transfer, + transfer_list); list_for_each_entry(t, &m->transfers, transfer_list) { - if (t->bits_per_word || t->speed_hz) { - /* Don't allow changes if CS is active */ + if ((first->bits_per_word != t->bits_per_word) || + (first->speed_hz != t->speed_hz)) { status = -EINVAL; + dev_err(&spi->dev, + "bits_per_word/speed_hz should be same for the same SPI transfer\n"); + return; + } + } + cs_change = 1; + status = -EINVAL; + list_for_each_entry(t, &m->transfers, transfer_list) { + if (t->bits_per_word || t->speed_hz) { if (cs_change) status = fsl_spi_setup_transfer(spi, t); if (status < 0) @@ -641,6 +645,10 @@ static struct spi_master * fsl_spi_probe(struct device *dev, if (mpc8xxx_spi->type == TYPE_GRLIB) fsl_spi_grlib_probe(dev); + master->bits_per_word_mask = + (SPI_BPW_RANGE_MASK(4, 16) | SPI_BPW_MASK(32)) & + SPI_BPW_RANGE_MASK(1, mpc8xxx_spi->max_bits_per_word); + if (mpc8xxx_spi->flags & SPI_QE_CPU_MODE) mpc8xxx_spi->set_shifts = fsl_spi_qe_cpu_set_shifts; diff --git a/drivers/spi/spi-gpio.c b/drivers/spi/spi-gpio.c index 7beeb29472a..09823076df8 100644 --- a/drivers/spi/spi-gpio.c +++ b/drivers/spi/spi-gpio.c @@ -19,7 +19,6 @@ */ #include <linux/kernel.h> #include <linux/module.h> -#include <linux/init.h> #include <linux/platform_device.h> #include <linux/gpio.h> #include <linux/of.h> @@ -250,7 +249,7 @@ static int spi_gpio_setup(struct spi_device *spi) /* * ... otherwise, take it from spi->controller_data */ - cs = (unsigned int) spi->controller_data; + cs = (unsigned int)(uintptr_t) spi->controller_data; } if (!spi->controller_state) { @@ -503,13 +502,12 @@ static int spi_gpio_remove(struct platform_device *pdev) { struct spi_gpio *spi_gpio; struct spi_gpio_platform_data *pdata; - int status; spi_gpio = platform_get_drvdata(pdev); pdata = dev_get_platdata(&pdev->dev); /* stop() unregisters child devices too */ - status = spi_bitbang_stop(&spi_gpio->bitbang); + spi_bitbang_stop(&spi_gpio->bitbang); if (SPI_MISO_GPIO != SPI_GPIO_NO_MISO) gpio_free(SPI_MISO_GPIO); @@ -518,7 +516,7 @@ static int spi_gpio_remove(struct platform_device *pdev) gpio_free(SPI_SCK_GPIO); spi_master_put(spi_gpio->bitbang.master); - return status; + return 0; } MODULE_ALIAS("platform:" DRIVER_NAME); diff --git a/drivers/spi/spi-imx.c b/drivers/spi/spi-imx.c index 47f15d97e7f..5daff2054ae 100644 --- a/drivers/spi/spi-imx.c +++ b/drivers/spi/spi-imx.c @@ -23,7 +23,6 @@ #include <linux/delay.h> #include <linux/err.h> #include <linux/gpio.h> -#include <linux/init.h> #include <linux/interrupt.h> #include <linux/io.h> #include <linux/irq.h> @@ -741,7 +740,7 @@ static int spi_imx_transfer(struct spi_device *spi, spi_imx->count = transfer->len; spi_imx->txfifo = 0; - init_completion(&spi_imx->xfer_done); + reinit_completion(&spi_imx->xfer_done); spi_imx_push(spi_imx); @@ -880,12 +879,12 @@ static int spi_imx_probe(struct platform_device *pdev) spi_imx->irq = platform_get_irq(pdev, 0); if (spi_imx->irq < 0) { - ret = -EINVAL; + ret = spi_imx->irq; goto out_master_put; } ret = devm_request_irq(&pdev->dev, spi_imx->irq, spi_imx_isr, 0, - DRIVER_NAME, spi_imx); + dev_name(&pdev->dev), spi_imx); if (ret) { dev_err(&pdev->dev, "can't get irq%d: %d\n", spi_imx->irq, ret); goto out_master_put; diff --git a/drivers/spi/spi-mpc512x-psc.c b/drivers/spi/spi-mpc512x-psc.c index 5032141eeee..3822eef2ef9 100644 --- a/drivers/spi/spi-mpc512x-psc.c +++ b/drivers/spi/spi-mpc512x-psc.c @@ -16,7 +16,6 @@ #include <linux/module.h> #include <linux/kernel.h> -#include <linux/init.h> #include <linux/errno.h> #include <linux/interrupt.h> #include <linux/of_address.h> @@ -466,10 +465,8 @@ static void mpc512x_spi_cs_control(struct spi_device *spi, bool onoff) gpio_set_value(spi->cs_gpio, onoff); } -/* bus_num is used only for the case dev->platform_data == NULL */ static int mpc512x_psc_spi_do_probe(struct device *dev, u32 regaddr, - u32 size, unsigned int irq, - s16 bus_num) + u32 size, unsigned int irq) { struct fsl_spi_platform_data *pdata = dev_get_platdata(dev); struct mpc512x_psc_spi *mps; @@ -488,7 +485,6 @@ static int mpc512x_psc_spi_do_probe(struct device *dev, u32 regaddr, if (pdata == NULL) { mps->cs_control = mpc512x_spi_cs_control; - master->bus_num = bus_num; } else { mps->cs_control = pdata->cs_control; master->bus_num = pdata->bus_num; @@ -574,7 +570,6 @@ static int mpc512x_psc_spi_of_probe(struct platform_device *op) { const u32 *regaddr_p; u64 regaddr64, size64; - s16 id = -1; regaddr_p = of_get_address(op->dev.of_node, 0, &size64, NULL); if (!regaddr_p) { @@ -583,16 +578,8 @@ static int mpc512x_psc_spi_of_probe(struct platform_device *op) } regaddr64 = of_translate_address(op->dev.of_node, regaddr_p); - /* get PSC id (0..11, used by port_config) */ - id = of_alias_get_id(op->dev.of_node, "spi"); - if (id < 0) { - dev_err(&op->dev, "no alias id for %s\n", - op->dev.of_node->full_name); - return id; - } - return mpc512x_psc_spi_do_probe(&op->dev, (u32) regaddr64, (u32) size64, - irq_of_parse_and_map(op->dev.of_node, 0), id); + irq_of_parse_and_map(op->dev.of_node, 0)); } static int mpc512x_psc_spi_of_remove(struct platform_device *op) diff --git a/drivers/spi/spi-mpc52xx-psc.c b/drivers/spi/spi-mpc52xx-psc.c index 00ba910ab30..3d18d935118 100644 --- a/drivers/spi/spi-mpc52xx-psc.c +++ b/drivers/spi/spi-mpc52xx-psc.c @@ -12,7 +12,6 @@ */ #include <linux/module.h> -#include <linux/init.h> #include <linux/types.h> #include <linux/errno.h> #include <linux/interrupt.h> diff --git a/drivers/spi/spi-mpc52xx.c b/drivers/spi/spi-mpc52xx.c index 7c675fe8310..aac2a5ddd96 100644 --- a/drivers/spi/spi-mpc52xx.c +++ b/drivers/spi/spi-mpc52xx.c @@ -12,7 +12,6 @@ */ #include <linux/module.h> -#include <linux/init.h> #include <linux/errno.h> #include <linux/of_platform.h> #include <linux/interrupt.h> @@ -357,20 +356,6 @@ static void mpc52xx_spi_wq(struct work_struct *work) * spi_master ops */ -static int mpc52xx_spi_setup(struct spi_device *spi) -{ - if (spi->bits_per_word % 8) - return -EINVAL; - - if (spi->mode & ~(SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST)) - return -EINVAL; - - if (spi->chip_select >= spi->master->num_chipselect) - return -EINVAL; - - return 0; -} - static int mpc52xx_spi_transfer(struct spi_device *spi, struct spi_message *m) { struct mpc52xx_spi *ms = spi_master_get_devdata(spi->master); @@ -433,9 +418,9 @@ static int mpc52xx_spi_probe(struct platform_device *op) goto err_alloc; } - master->setup = mpc52xx_spi_setup; master->transfer = mpc52xx_spi_transfer; master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST; + master->bits_per_word_mask = SPI_BPW_MASK(8); master->dev.of_node = op->dev.of_node; platform_set_drvdata(op, master); diff --git a/drivers/spi/spi-mxs.c b/drivers/spi/spi-mxs.c index 79e5aa2250c..2884f0c2f5f 100644 --- a/drivers/spi/spi-mxs.c +++ b/drivers/spi/spi-mxs.c @@ -29,7 +29,6 @@ */ #include <linux/kernel.h> -#include <linux/init.h> #include <linux/ioport.h> #include <linux/of.h> #include <linux/of_device.h> @@ -371,7 +370,7 @@ static int mxs_spi_transfer_one(struct spi_master *master, { struct mxs_spi *spi = spi_master_get_devdata(master); struct mxs_ssp *ssp = &spi->ssp; - struct spi_transfer *t, *tmp_t; + struct spi_transfer *t; unsigned int flag; int status = 0; @@ -381,7 +380,7 @@ static int mxs_spi_transfer_one(struct spi_master *master, writel(mxs_spi_cs_to_reg(m->spi->chip_select), ssp->base + HW_SSP_CTRL0 + STMP_OFFSET_REG_SET); - list_for_each_entry_safe(t, tmp_t, &m->transfers, transfer_list) { + list_for_each_entry(t, &m->transfers, transfer_list) { status = mxs_spi_setup_transfer(m->spi, t); if (status) @@ -473,7 +472,7 @@ static int mxs_spi_probe(struct platform_device *pdev) iores = platform_get_resource(pdev, IORESOURCE_MEM, 0); irq_err = platform_get_irq(pdev, 0); if (irq_err < 0) - return -EINVAL; + return irq_err; base = devm_ioremap_resource(&pdev->dev, iores); if (IS_ERR(base)) diff --git a/drivers/spi/spi-nuc900.c b/drivers/spi/spi-nuc900.c index bae97ffec4b..16e30de650b 100644 --- a/drivers/spi/spi-nuc900.c +++ b/drivers/spi/spi-nuc900.c @@ -9,7 +9,6 @@ */ #include <linux/module.h> -#include <linux/init.h> #include <linux/spinlock.h> #include <linux/workqueue.h> #include <linux/interrupt.h> @@ -38,7 +37,9 @@ /* usi register bit */ #define ENINT (0x01 << 17) #define ENFLG (0x01 << 16) +#define SLEEP (0x0f << 12) #define TXNUM (0x03 << 8) +#define TXBITLEN (0x1f << 3) #define TXNEG (0x01 << 2) #define RXNEG (0x01 << 1) #define LSB (0x01 << 10) @@ -58,11 +59,8 @@ struct nuc900_spi { unsigned char *rx; struct clk *clk; struct spi_master *master; - struct spi_device *curdev; - struct device *dev; struct nuc900_spi_info *pdata; spinlock_t lock; - struct resource *res; }; static inline struct nuc900_spi *to_hw(struct spi_device *sdev) @@ -119,19 +117,16 @@ static void nuc900_spi_chipsel(struct spi_device *spi, int value) } } -static void nuc900_spi_setup_txnum(struct nuc900_spi *hw, - unsigned int txnum) +static void nuc900_spi_setup_txnum(struct nuc900_spi *hw, unsigned int txnum) { unsigned int val; unsigned long flags; spin_lock_irqsave(&hw->lock, flags); - val = __raw_readl(hw->regs + USI_CNT); + val = __raw_readl(hw->regs + USI_CNT) & ~TXNUM; - if (!txnum) - val &= ~TXNUM; - else + if (txnum) val |= txnum << 0x08; __raw_writel(val, hw->regs + USI_CNT); @@ -148,7 +143,7 @@ static void nuc900_spi_setup_txbitlen(struct nuc900_spi *hw, spin_lock_irqsave(&hw->lock, flags); - val = __raw_readl(hw->regs + USI_CNT); + val = __raw_readl(hw->regs + USI_CNT) & ~TXBITLEN; val |= (txbitlen << 0x03); @@ -287,12 +282,11 @@ static void nuc900_set_sleep(struct nuc900_spi *hw, unsigned int sleep) spin_lock_irqsave(&hw->lock, flags); - val = __raw_readl(hw->regs + USI_CNT); + val = __raw_readl(hw->regs + USI_CNT) & ~SLEEP; if (sleep) val |= (sleep << 12); - else - val &= ~(0x0f << 12); + __raw_writel(val, hw->regs + USI_CNT); spin_unlock_irqrestore(&hw->lock, flags); @@ -338,6 +332,7 @@ static int nuc900_spi_probe(struct platform_device *pdev) { struct nuc900_spi *hw; struct spi_master *master; + struct resource *res; int err = 0; master = spi_alloc_master(&pdev->dev, sizeof(struct nuc900_spi)); @@ -349,7 +344,6 @@ static int nuc900_spi_probe(struct platform_device *pdev) hw = spi_master_get_devdata(master); hw->master = master; hw->pdata = dev_get_platdata(&pdev->dev); - hw->dev = &pdev->dev; if (hw->pdata == NULL) { dev_err(&pdev->dev, "No platform data supplied\n"); @@ -369,8 +363,8 @@ static int nuc900_spi_probe(struct platform_device *pdev) hw->bitbang.chipselect = nuc900_spi_chipsel; hw->bitbang.txrx_bufs = nuc900_spi_txrx; - hw->res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - hw->regs = devm_ioremap_resource(&pdev->dev, hw->res); + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + hw->regs = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(hw->regs)) { err = PTR_ERR(hw->regs); goto err_pdata; diff --git a/drivers/spi/spi-oc-tiny.c b/drivers/spi/spi-oc-tiny.c index f7c896e2981..8998d11c723 100644 --- a/drivers/spi/spi-oc-tiny.c +++ b/drivers/spi/spi-oc-tiny.c @@ -15,7 +15,6 @@ * published by the Free Software Foundation. */ -#include <linux/init.h> #include <linux/interrupt.h> #include <linux/errno.h> #include <linux/module.h> @@ -267,8 +266,6 @@ static int tiny_spi_probe(struct platform_device *pdev) /* setup the state for the bitbang driver */ hw->bitbang.master = master; - if (!hw->bitbang.master) - return err; hw->bitbang.setup_transfer = tiny_spi_setup_transfer; hw->bitbang.chipselect = tiny_spi_chipselect; hw->bitbang.txrx_bufs = tiny_spi_txrx_bufs; diff --git a/drivers/spi/spi-octeon.c b/drivers/spi/spi-octeon.c index 67249a48b39..c5e2f718eeb 100644 --- a/drivers/spi/spi-octeon.c +++ b/drivers/spi/spi-octeon.c @@ -11,7 +11,6 @@ #include <linux/spi/spi.h> #include <linux/module.h> #include <linux/delay.h> -#include <linux/init.h> #include <linux/io.h> #include <linux/of.h> @@ -33,13 +32,6 @@ struct octeon_spi { u64 cs_enax; }; -struct octeon_spi_setup { - u32 max_speed_hz; - u8 chip_select; - u8 mode; - u8 bits_per_word; -}; - static void octeon_spi_wait_ready(struct octeon_spi *p) { union cvmx_mpi_sts mpi_sts; @@ -57,6 +49,7 @@ static int octeon_spi_do_transfer(struct octeon_spi *p, struct spi_transfer *xfer, bool last_xfer) { + struct spi_device *spi = msg->spi; union cvmx_mpi_cfg mpi_cfg; union cvmx_mpi_tx mpi_tx; unsigned int clkdiv; @@ -68,18 +61,11 @@ static int octeon_spi_do_transfer(struct octeon_spi *p, int len; int i; - struct octeon_spi_setup *msg_setup = spi_get_ctldata(msg->spi); - - speed_hz = msg_setup->max_speed_hz; - mode = msg_setup->mode; + mode = spi->mode; cpha = mode & SPI_CPHA; cpol = mode & SPI_CPOL; - if (xfer->speed_hz) - speed_hz = xfer->speed_hz; - - if (speed_hz > OCTEON_SPI_MAX_CLOCK_HZ) - speed_hz = OCTEON_SPI_MAX_CLOCK_HZ; + speed_hz = xfer->speed_hz ? : spi->max_speed_hz; clkdiv = octeon_get_io_clock_rate() / (2 * speed_hz); @@ -93,8 +79,8 @@ static int octeon_spi_do_transfer(struct octeon_spi *p, mpi_cfg.s.cslate = cpha ? 1 : 0; mpi_cfg.s.enable = 1; - if (msg_setup->chip_select < 4) - p->cs_enax |= 1ull << (12 + msg_setup->chip_select); + if (spi->chip_select < 4) + p->cs_enax |= 1ull << (12 + spi->chip_select); mpi_cfg.u64 |= p->cs_enax; if (mpi_cfg.u64 != p->last_cfg) { @@ -114,7 +100,7 @@ static int octeon_spi_do_transfer(struct octeon_spi *p, cvmx_write_csr(p->register_base + OCTEON_SPI_DAT0 + (8 * i), d); } mpi_tx.u64 = 0; - mpi_tx.s.csid = msg_setup->chip_select; + mpi_tx.s.csid = spi->chip_select; mpi_tx.s.leavecs = 1; mpi_tx.s.txnum = tx_buf ? OCTEON_SPI_MAX_BYTES : 0; mpi_tx.s.totnum = OCTEON_SPI_MAX_BYTES; @@ -139,7 +125,7 @@ static int octeon_spi_do_transfer(struct octeon_spi *p, } mpi_tx.u64 = 0; - mpi_tx.s.csid = msg_setup->chip_select; + mpi_tx.s.csid = spi->chip_select; if (last_xfer) mpi_tx.s.leavecs = xfer->cs_change; else @@ -169,17 +155,9 @@ static int octeon_spi_transfer_one_message(struct spi_master *master, int status = 0; struct spi_transfer *xfer; - /* - * We better have set the configuration via a call to .setup - * before we get here. - */ - if (spi_get_ctldata(msg->spi) == NULL) { - status = -EINVAL; - goto err; - } - list_for_each_entry(xfer, &msg->transfers, transfer_list) { - bool last_xfer = &xfer->transfer_list == msg->transfers.prev; + bool last_xfer = list_is_last(&xfer->transfer_list, + &msg->transfers); int r = octeon_spi_do_transfer(p, msg, xfer, last_xfer); if (r < 0) { status = r; @@ -194,41 +172,6 @@ err: return status; } -static struct octeon_spi_setup *octeon_spi_new_setup(struct spi_device *spi) -{ - struct octeon_spi_setup *setup = kzalloc(sizeof(*setup), GFP_KERNEL); - if (!setup) - return NULL; - - setup->max_speed_hz = spi->max_speed_hz; - setup->chip_select = spi->chip_select; - setup->mode = spi->mode; - setup->bits_per_word = spi->bits_per_word; - return setup; -} - -static int octeon_spi_setup(struct spi_device *spi) -{ - struct octeon_spi_setup *new_setup; - struct octeon_spi_setup *old_setup = spi_get_ctldata(spi); - - new_setup = octeon_spi_new_setup(spi); - if (!new_setup) - return -ENOMEM; - - spi_set_ctldata(spi, new_setup); - kfree(old_setup); - - return 0; -} - -static void octeon_spi_cleanup(struct spi_device *spi) -{ - struct octeon_spi_setup *old_setup = spi_get_ctldata(spi); - spi_set_ctldata(spi, NULL); - kfree(old_setup); -} - static int octeon_spi_probe(struct platform_device *pdev) { struct resource *res_mem; @@ -257,8 +200,6 @@ static int octeon_spi_probe(struct platform_device *pdev) p->register_base = (u64)devm_ioremap(&pdev->dev, res_mem->start, resource_size(res_mem)); - /* Dynamic bus numbering */ - master->bus_num = -1; master->num_chipselect = 4; master->mode_bits = SPI_CPHA | SPI_CPOL | @@ -266,10 +207,9 @@ static int octeon_spi_probe(struct platform_device *pdev) SPI_LSB_FIRST | SPI_3WIRE; - master->setup = octeon_spi_setup; - master->cleanup = octeon_spi_cleanup; master->transfer_one_message = octeon_spi_transfer_one_message; master->bits_per_word_mask = SPI_BPW_MASK(8); + master->max_speed_hz = OCTEON_SPI_MAX_CLOCK_HZ; master->dev.of_node = pdev->dev.of_node; err = devm_spi_register_master(&pdev->dev, master); diff --git a/drivers/spi/spi-omap-100k.c b/drivers/spi/spi-omap-100k.c index 0d32054bfc0..e7ffcded4e1 100644 --- a/drivers/spi/spi-omap-100k.c +++ b/drivers/spi/spi-omap-100k.c @@ -83,15 +83,11 @@ #define SPI_SHUTDOWN 1 struct omap1_spi100k { - struct spi_master *master; struct clk *ick; struct clk *fck; /* Virtual base address of the controller */ void __iomem *base; - - /* State of the SPI */ - unsigned int state; }; struct omap1_spi100k_cs { @@ -99,13 +95,6 @@ struct omap1_spi100k_cs { int word_len; }; -#define MOD_REG_BIT(val, mask, set) do { \ - if (set) \ - val |= mask; \ - else \ - val &= ~mask; \ -} while (0) - static void spi100k_enable_clock(struct spi_master *master) { unsigned int val; @@ -139,7 +128,7 @@ static void spi100k_write_data(struct spi_master *master, int len, int data) } spi100k_enable_clock(master); - writew( data , spi100k->base + SPI_TX_MSB); + writew(data , spi100k->base + SPI_TX_MSB); writew(SPI_CTRL_SEN(0) | SPI_CTRL_WORD_SIZE(len) | @@ -147,7 +136,8 @@ static void spi100k_write_data(struct spi_master *master, int len, int data) spi100k->base + SPI_CTRL); /* Wait for bit ack send change */ - while((readw(spi100k->base + SPI_STATUS) & SPI_STATUS_WE) != SPI_STATUS_WE); + while ((readw(spi100k->base + SPI_STATUS) & SPI_STATUS_WE) != SPI_STATUS_WE) + ; udelay(1000); spi100k_disable_clock(master); @@ -155,7 +145,7 @@ static void spi100k_write_data(struct spi_master *master, int len, int data) static int spi100k_read_data(struct spi_master *master, int len) { - int dataH,dataL; + int dataH, dataL; struct omap1_spi100k *spi100k = spi_master_get_devdata(master); /* Always do at least 16 bits */ @@ -168,7 +158,8 @@ static int spi100k_read_data(struct spi_master *master, int len) SPI_CTRL_RD, spi100k->base + SPI_CTRL); - while((readw(spi100k->base + SPI_STATUS) & SPI_STATUS_RD) != SPI_STATUS_RD); + while ((readw(spi100k->base + SPI_STATUS) & SPI_STATUS_RD) != SPI_STATUS_RD) + ; udelay(1000); dataL = readw(spi100k->base + SPI_RX_LSB); @@ -204,12 +195,10 @@ static void omap1_spi100k_force_cs(struct omap1_spi100k *spi100k, int enable) static unsigned omap1_spi100k_txrx_pio(struct spi_device *spi, struct spi_transfer *xfer) { - struct omap1_spi100k *spi100k; struct omap1_spi100k_cs *cs = spi->controller_state; unsigned int count, c; int word_len; - spi100k = spi_master_get_devdata(spi->master); count = xfer->len; c = count; word_len = cs->word_len; @@ -221,12 +210,12 @@ omap1_spi100k_txrx_pio(struct spi_device *spi, struct spi_transfer *xfer) rx = xfer->rx_buf; tx = xfer->tx_buf; do { - c-=1; + c -= 1; if (xfer->tx_buf != NULL) spi100k_write_data(spi->master, word_len, *tx++); if (xfer->rx_buf != NULL) *rx++ = spi100k_read_data(spi->master, word_len); - } while(c); + } while (c); } else if (word_len <= 16) { u16 *rx; const u16 *tx; @@ -234,12 +223,12 @@ omap1_spi100k_txrx_pio(struct spi_device *spi, struct spi_transfer *xfer) rx = xfer->rx_buf; tx = xfer->tx_buf; do { - c-=2; + c -= 2; if (xfer->tx_buf != NULL) - spi100k_write_data(spi->master,word_len, *tx++); + spi100k_write_data(spi->master, word_len, *tx++); if (xfer->rx_buf != NULL) - *rx++ = spi100k_read_data(spi->master,word_len); - } while(c); + *rx++ = spi100k_read_data(spi->master, word_len); + } while (c); } else if (word_len <= 32) { u32 *rx; const u32 *tx; @@ -247,12 +236,12 @@ omap1_spi100k_txrx_pio(struct spi_device *spi, struct spi_transfer *xfer) rx = xfer->rx_buf; tx = xfer->tx_buf; do { - c-=4; + c -= 4; if (xfer->tx_buf != NULL) - spi100k_write_data(spi->master,word_len, *tx); + spi100k_write_data(spi->master, word_len, *tx); if (xfer->rx_buf != NULL) - *rx = spi100k_read_data(spi->master,word_len); - } while(c); + *rx = spi100k_read_data(spi->master, word_len); + } while (c); } return count - c; } @@ -294,7 +283,7 @@ static int omap1_spi100k_setup(struct spi_device *spi) spi100k = spi_master_get_devdata(spi->master); if (!cs) { - cs = kzalloc(sizeof *cs, GFP_KERNEL); + cs = devm_kzalloc(&spi->dev, sizeof(*cs), GFP_KERNEL); if (!cs) return -ENOMEM; cs->base = spi100k->base + spi->chip_select * 0x14; @@ -411,14 +400,14 @@ static int omap1_spi100k_probe(struct platform_device *pdev) if (!pdev->id) return -EINVAL; - master = spi_alloc_master(&pdev->dev, sizeof *spi100k); + master = spi_alloc_master(&pdev->dev, sizeof(*spi100k)); if (master == NULL) { dev_dbg(&pdev->dev, "master allocation failed\n"); return -ENOMEM; } if (pdev->id != -1) - master->bus_num = pdev->id; + master->bus_num = pdev->id; master->setup = omap1_spi100k_setup; master->transfer_one_message = omap1_spi100k_transfer_one_message; @@ -434,7 +423,6 @@ static int omap1_spi100k_probe(struct platform_device *pdev) platform_set_drvdata(pdev, master); spi100k = spi_master_get_devdata(master); - spi100k->master = master; /* * The memory region base address is taken as the platform_data. @@ -461,8 +449,6 @@ static int omap1_spi100k_probe(struct platform_device *pdev) if (status < 0) goto err; - spi100k->state = SPI_RUNNING; - return status; err: diff --git a/drivers/spi/spi-omap-uwire.c b/drivers/spi/spi-omap-uwire.c index 9313fd3b413..be2a2e108e2 100644 --- a/drivers/spi/spi-omap-uwire.c +++ b/drivers/spi/spi-omap-uwire.c @@ -99,7 +99,6 @@ struct uwire_spi { }; struct uwire_state { - unsigned bits_per_word; unsigned div1_idx; }; @@ -210,9 +209,8 @@ static void uwire_chipselect(struct spi_device *spi, int value) static int uwire_txrx(struct spi_device *spi, struct spi_transfer *t) { - struct uwire_state *ust = spi->controller_state; unsigned len = t->len; - unsigned bits = ust->bits_per_word; + unsigned bits = t->bits_per_word ? : spi->bits_per_word; unsigned bytes; u16 val, w; int status = 0; @@ -220,10 +218,6 @@ static int uwire_txrx(struct spi_device *spi, struct spi_transfer *t) if (!t->tx_buf && !t->rx_buf) return 0; - /* Microwire doesn't read and write concurrently */ - if (t->tx_buf && t->rx_buf) - return -EPERM; - w = spi->chip_select << 10; w |= CS_CMD; @@ -322,7 +316,6 @@ static int uwire_setup_transfer(struct spi_device *spi, struct spi_transfer *t) struct uwire_state *ust = spi->controller_state; struct uwire_spi *uwire; unsigned flags = 0; - unsigned bits; unsigned hz; unsigned long rate; int div1_idx; @@ -332,23 +325,6 @@ static int uwire_setup_transfer(struct spi_device *spi, struct spi_transfer *t) uwire = spi_master_get_devdata(spi->master); - if (spi->chip_select > 3) { - pr_debug("%s: cs%d?\n", dev_name(&spi->dev), spi->chip_select); - status = -ENODEV; - goto done; - } - - bits = spi->bits_per_word; - if (t != NULL && t->bits_per_word) - bits = t->bits_per_word; - - if (bits > 16) { - pr_debug("%s: wordsize %d?\n", dev_name(&spi->dev), bits); - status = -ENODEV; - goto done; - } - ust->bits_per_word = bits; - /* mode 0..3, clock inverted separately; * standard nCS signaling; * don't treat DI=high as "not ready" @@ -502,6 +478,7 @@ static int uwire_probe(struct platform_device *pdev) status = PTR_ERR(uwire->ck); dev_dbg(&pdev->dev, "no functional clock?\n"); spi_master_put(master); + iounmap(uwire_base); return status; } clk_enable(uwire->ck); @@ -515,7 +492,7 @@ static int uwire_probe(struct platform_device *pdev) /* the spi->mode bits understood by this driver: */ master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH; - + master->bits_per_word_mask = SPI_BPW_RANGE_MASK(1, 16); master->flags = SPI_MASTER_HALF_DUPLEX; master->bus_num = 2; /* "official" */ @@ -539,14 +516,13 @@ static int uwire_probe(struct platform_device *pdev) static int uwire_remove(struct platform_device *pdev) { struct uwire_spi *uwire = platform_get_drvdata(pdev); - int status; // FIXME remove all child devices, somewhere ... - status = spi_bitbang_stop(&uwire->bitbang); + spi_bitbang_stop(&uwire->bitbang); uwire_off(uwire); iounmap(uwire_base); - return status; + return 0; } /* work with hotplug and coldplug */ diff --git a/drivers/spi/spi-omap2-mcspi.c b/drivers/spi/spi-omap2-mcspi.c index a72127f08e3..2941c5b96eb 100644 --- a/drivers/spi/spi-omap2-mcspi.c +++ b/drivers/spi/spi-omap2-mcspi.c @@ -22,7 +22,6 @@ */ #include <linux/kernel.h> -#include <linux/init.h> #include <linux/interrupt.h> #include <linux/module.h> #include <linux/device.h> @@ -45,6 +44,7 @@ #include <linux/platform_data/spi-omap2-mcspi.h> #define OMAP2_MCSPI_MAX_FREQ 48000000 +#define OMAP2_MCSPI_MAX_DIVIDER 4096 #define OMAP2_MCSPI_MAX_FIFODEPTH 64 #define OMAP2_MCSPI_MAX_FIFOWCNT 0xFFFF #define SPI_AUTOSUSPEND_TIMEOUT 2000 @@ -89,6 +89,7 @@ #define OMAP2_MCSPI_CHCONF_FORCE BIT(20) #define OMAP2_MCSPI_CHCONF_FFET BIT(27) #define OMAP2_MCSPI_CHCONF_FFER BIT(28) +#define OMAP2_MCSPI_CHCONF_CLKG BIT(29) #define OMAP2_MCSPI_CHSTAT_RXS BIT(0) #define OMAP2_MCSPI_CHSTAT_TXS BIT(1) @@ -96,6 +97,7 @@ #define OMAP2_MCSPI_CHSTAT_TXFFE BIT(3) #define OMAP2_MCSPI_CHCTRL_EN BIT(0) +#define OMAP2_MCSPI_CHCTRL_EXTCLK_MASK (0xff << 8) #define OMAP2_MCSPI_WAKEUPENABLE_WKEN BIT(0) @@ -149,7 +151,7 @@ struct omap2_mcspi_cs { int word_len; struct list_head node; /* Context save and restore shadow register */ - u32 chconf0; + u32 chconf0, chctrl0; }; static inline void mcspi_write_reg(struct spi_master *master, @@ -230,10 +232,16 @@ static void omap2_mcspi_set_dma_req(const struct spi_device *spi, static void omap2_mcspi_set_enable(const struct spi_device *spi, int enable) { + struct omap2_mcspi_cs *cs = spi->controller_state; u32 l; - l = enable ? OMAP2_MCSPI_CHCTRL_EN : 0; - mcspi_write_cs_reg(spi, OMAP2_MCSPI_CHCTRL0, l); + l = cs->chctrl0; + if (enable) + l |= OMAP2_MCSPI_CHCTRL_EN; + else + l &= ~OMAP2_MCSPI_CHCTRL_EN; + cs->chctrl0 = l; + mcspi_write_cs_reg(spi, OMAP2_MCSPI_CHCTRL0, cs->chctrl0); /* Flash post-writes */ mcspi_read_cs_reg(spi, OMAP2_MCSPI_CHCTRL0); } @@ -840,7 +848,7 @@ static int omap2_mcspi_setup_transfer(struct spi_device *spi, struct omap2_mcspi_cs *cs = spi->controller_state; struct omap2_mcspi *mcspi; struct spi_master *spi_cntrl; - u32 l = 0, div = 0; + u32 l = 0, clkd = 0, div, extclk = 0, clkg = 0; u8 word_len = spi->bits_per_word; u32 speed_hz = spi->max_speed_hz; @@ -856,7 +864,17 @@ static int omap2_mcspi_setup_transfer(struct spi_device *spi, speed_hz = t->speed_hz; speed_hz = min_t(u32, speed_hz, OMAP2_MCSPI_MAX_FREQ); - div = omap2_mcspi_calc_divisor(speed_hz); + if (speed_hz < (OMAP2_MCSPI_MAX_FREQ / OMAP2_MCSPI_MAX_DIVIDER)) { + clkd = omap2_mcspi_calc_divisor(speed_hz); + speed_hz = OMAP2_MCSPI_MAX_FREQ >> clkd; + clkg = 0; + } else { + div = (OMAP2_MCSPI_MAX_FREQ + speed_hz - 1) / speed_hz; + speed_hz = OMAP2_MCSPI_MAX_FREQ / div; + clkd = (div - 1) & 0xf; + extclk = (div - 1) >> 4; + clkg = OMAP2_MCSPI_CHCONF_CLKG; + } l = mcspi_cached_chconf0(spi); @@ -885,7 +903,16 @@ static int omap2_mcspi_setup_transfer(struct spi_device *spi, /* set clock divisor */ l &= ~OMAP2_MCSPI_CHCONF_CLKD_MASK; - l |= div << 2; + l |= clkd << 2; + + /* set clock granularity */ + l &= ~OMAP2_MCSPI_CHCONF_CLKG; + l |= clkg; + if (clkg) { + cs->chctrl0 &= ~OMAP2_MCSPI_CHCTRL_EXTCLK_MASK; + cs->chctrl0 |= extclk << 8; + mcspi_write_cs_reg(spi, OMAP2_MCSPI_CHCTRL0, cs->chctrl0); + } /* set SPI mode 0..3 */ if (spi->mode & SPI_CPOL) @@ -900,7 +927,7 @@ static int omap2_mcspi_setup_transfer(struct spi_device *spi, mcspi_write_chconf0(spi, l); dev_dbg(&spi->dev, "setup: speed %d, sample %s edge, clk %s\n", - OMAP2_MCSPI_MAX_FREQ >> div, + speed_hz, (spi->mode & SPI_CPHA) ? "trailing" : "leading", (spi->mode & SPI_CPOL) ? "inverted" : "normal"); @@ -972,6 +999,7 @@ static int omap2_mcspi_setup(struct spi_device *spi) cs->base = mcspi->base + spi->chip_select * 0x14; cs->phys = mcspi->phys + spi->chip_select * 0x14; cs->chconf0 = 0; + cs->chctrl0 = 0; spi->controller_state = cs; /* Link this to context save list */ list_add_tail(&cs->node, &ctx->cs); @@ -1057,12 +1085,15 @@ static void omap2_mcspi_work(struct omap2_mcspi *mcspi, struct spi_message *m) status = -EINVAL; break; } - if (par_override || t->speed_hz || t->bits_per_word) { + if (par_override || + (t->speed_hz != spi->max_speed_hz) || + (t->bits_per_word != spi->bits_per_word)) { par_override = 1; status = omap2_mcspi_setup_transfer(spi, t); if (status < 0) break; - if (!t->speed_hz && !t->bits_per_word) + if (t->speed_hz == spi->max_speed_hz && + t->bits_per_word == spi->bits_per_word) par_override = 0; } if (cd && cd->cs_per_word) { @@ -1176,16 +1207,12 @@ static int omap2_mcspi_transfer_one_message(struct spi_master *master, m->actual_length = 0; m->status = 0; - /* reject invalid messages and transfers */ - if (list_empty(&m->transfers)) - return -EINVAL; list_for_each_entry(t, &m->transfers, transfer_list) { const void *tx_buf = t->tx_buf; void *rx_buf = t->rx_buf; unsigned len = t->len; - if (t->speed_hz > OMAP2_MCSPI_MAX_FREQ - || (len && !(rx_buf || tx_buf))) { + if ((len && !(rx_buf || tx_buf))) { dev_dbg(mcspi->dev, "transfer: %d Hz, %d %s%s, %d bpw\n", t->speed_hz, len, @@ -1194,12 +1221,6 @@ static int omap2_mcspi_transfer_one_message(struct spi_master *master, t->bits_per_word); return -EINVAL; } - if (t->speed_hz && t->speed_hz < (OMAP2_MCSPI_MAX_FREQ >> 15)) { - dev_dbg(mcspi->dev, "speed_hz %d below minimum %d Hz\n", - t->speed_hz, - OMAP2_MCSPI_MAX_FREQ >> 15); - return -EINVAL; - } if (m->is_dma_mapped || len < DMA_MIN_BYTES) continue; @@ -1311,6 +1332,8 @@ static int omap2_mcspi_probe(struct platform_device *pdev) master->transfer_one_message = omap2_mcspi_transfer_one_message; master->cleanup = omap2_mcspi_cleanup; master->dev.of_node = node; + master->max_speed_hz = OMAP2_MCSPI_MAX_FREQ; + master->min_speed_hz = OMAP2_MCSPI_MAX_FREQ >> 15; platform_set_drvdata(pdev, master); diff --git a/drivers/spi/spi-orion.c b/drivers/spi/spi-orion.c index 7f2121fe262..d018a4aac3a 100644 --- a/drivers/spi/spi-orion.c +++ b/drivers/spi/spi-orion.c @@ -9,7 +9,6 @@ * published by the Free Software Foundation. */ -#include <linux/init.h> #include <linux/interrupt.h> #include <linux/delay.h> #include <linux/platform_device.h> @@ -43,8 +42,6 @@ struct orion_spi { struct spi_master *master; void __iomem *base; - unsigned int max_speed; - unsigned int min_speed; struct clk *clk; }; @@ -75,23 +72,6 @@ orion_spi_clrbits(struct orion_spi *orion_spi, u32 reg, u32 mask) writel(val, reg_addr); } -static int orion_spi_set_transfer_size(struct orion_spi *orion_spi, int size) -{ - if (size == 16) { - orion_spi_setbits(orion_spi, ORION_SPI_IF_CONFIG_REG, - ORION_SPI_IF_8_16_BIT_MODE); - } else if (size == 8) { - orion_spi_clrbits(orion_spi, ORION_SPI_IF_CONFIG_REG, - ORION_SPI_IF_8_16_BIT_MODE); - } else { - pr_debug("Bad bits per word value %d (only 8 or 16 are allowed).\n", - size); - return -EINVAL; - } - - return 0; -} - static int orion_spi_baudrate_set(struct spi_device *spi, unsigned int speed) { u32 tclk_hz; @@ -170,7 +150,14 @@ orion_spi_setup_transfer(struct spi_device *spi, struct spi_transfer *t) if (rc) return rc; - return orion_spi_set_transfer_size(orion_spi, bits_per_word); + if (bits_per_word == 16) + orion_spi_setbits(orion_spi, ORION_SPI_IF_CONFIG_REG, + ORION_SPI_IF_8_16_BIT_MODE); + else + orion_spi_clrbits(orion_spi, ORION_SPI_IF_CONFIG_REG, + ORION_SPI_IF_8_16_BIT_MODE); + + return 0; } static void orion_spi_set_cs(struct orion_spi *orion_spi, int enable) @@ -260,11 +247,9 @@ orion_spi_write_read_16bit(struct spi_device *spi, static unsigned int orion_spi_write_read(struct spi_device *spi, struct spi_transfer *xfer) { - struct orion_spi *orion_spi; unsigned int count; int word_len; - orion_spi = spi_master_get_devdata(spi->master); word_len = spi->bits_per_word; count = xfer->len; @@ -310,27 +295,6 @@ static int orion_spi_transfer_one_message(struct spi_master *master, goto msg_done; list_for_each_entry(t, &m->transfers, transfer_list) { - /* make sure buffer length is even when working in 16 - * bit mode*/ - if ((t->bits_per_word == 16) && (t->len & 1)) { - dev_err(&spi->dev, - "message rejected : " - "odd data length %d while in 16 bit mode\n", - t->len); - status = -EIO; - goto msg_done; - } - - if (t->speed_hz && t->speed_hz < orion_spi->min_speed) { - dev_err(&spi->dev, - "message rejected : " - "device min speed (%d Hz) exceeds " - "required transfer speed (%d Hz)\n", - orion_spi->min_speed, t->speed_hz); - status = -EIO; - goto msg_done; - } - if (par_override || t->speed_hz || t->bits_per_word) { par_override = 1; status = orion_spi_setup_transfer(spi, t); @@ -375,28 +339,6 @@ static int orion_spi_reset(struct orion_spi *orion_spi) return 0; } -static int orion_spi_setup(struct spi_device *spi) -{ - struct orion_spi *orion_spi; - - orion_spi = spi_master_get_devdata(spi->master); - - if ((spi->max_speed_hz == 0) - || (spi->max_speed_hz > orion_spi->max_speed)) - spi->max_speed_hz = orion_spi->max_speed; - - if (spi->max_speed_hz < orion_spi->min_speed) { - dev_err(&spi->dev, "setup: requested speed too low %d Hz\n", - spi->max_speed_hz); - return -EINVAL; - } - - /* - * baudrate & width will be set orion_spi_setup_transfer - */ - return 0; -} - static int orion_spi_probe(struct platform_device *pdev) { struct spi_master *master; @@ -425,9 +367,9 @@ static int orion_spi_probe(struct platform_device *pdev) /* we support only mode 0, and no options */ master->mode_bits = SPI_CPHA | SPI_CPOL; - master->setup = orion_spi_setup; master->transfer_one_message = orion_spi_transfer_one_message; master->num_chipselect = ORION_NUM_CHIPSELECTS; + master->bits_per_word_mask = SPI_BPW_MASK(8) | SPI_BPW_MASK(16); platform_set_drvdata(pdev, master); @@ -443,8 +385,8 @@ static int orion_spi_probe(struct platform_device *pdev) clk_prepare(spi->clk); clk_enable(spi->clk); tclk_hz = clk_get_rate(spi->clk); - spi->max_speed = DIV_ROUND_UP(tclk_hz, 4); - spi->min_speed = DIV_ROUND_UP(tclk_hz, 30); + master->max_speed_hz = DIV_ROUND_UP(tclk_hz, 4); + master->min_speed_hz = DIV_ROUND_UP(tclk_hz, 30); r = platform_get_resource(pdev, IORESOURCE_MEM, 0); spi->base = devm_ioremap_resource(&pdev->dev, r); diff --git a/drivers/spi/spi-pl022.c b/drivers/spi/spi-pl022.c index 2789b452e71..51d99779682 100644 --- a/drivers/spi/spi-pl022.c +++ b/drivers/spi/spi-pl022.c @@ -459,9 +459,8 @@ static void giveback(struct pl022 *pl022) struct spi_transfer *last_transfer; pl022->next_msg_cs_active = false; - last_transfer = list_entry(pl022->cur_msg->transfers.prev, - struct spi_transfer, - transfer_list); + last_transfer = list_last_entry(&pl022->cur_msg->transfers, + struct spi_transfer, transfer_list); /* Delay if requested before any change in chip select */ if (last_transfer->delay_usecs) @@ -2109,8 +2108,6 @@ static int pl022_probe(struct amba_device *adev, const struct amba_id *id) pl022->chipselects = devm_kzalloc(dev, num_cs * sizeof(int), GFP_KERNEL); - pinctrl_pm_select_default_state(dev); - /* * Bus Number Which has been Assigned to this SSP controller * on this board @@ -2183,13 +2180,7 @@ static int pl022_probe(struct amba_device *adev, const struct amba_id *id) goto err_no_clk; } - status = clk_prepare(pl022->clk); - if (status) { - dev_err(&adev->dev, "could not prepare SSP/SPI bus clock\n"); - goto err_clk_prep; - } - - status = clk_enable(pl022->clk); + status = clk_prepare_enable(pl022->clk); if (status) { dev_err(&adev->dev, "could not enable SSP/SPI bus clock\n"); goto err_no_clk_en; @@ -2250,10 +2241,8 @@ static int pl022_probe(struct amba_device *adev, const struct amba_id *id) if (platform_info->enable_dma) pl022_dma_remove(pl022); err_no_irq: - clk_disable(pl022->clk); + clk_disable_unprepare(pl022->clk); err_no_clk_en: - clk_unprepare(pl022->clk); - err_clk_prep: err_no_clk: err_no_ioremap: amba_release_regions(adev); @@ -2281,42 +2270,13 @@ pl022_remove(struct amba_device *adev) if (pl022->master_info->enable_dma) pl022_dma_remove(pl022); - clk_disable(pl022->clk); - clk_unprepare(pl022->clk); + clk_disable_unprepare(pl022->clk); amba_release_regions(adev); tasklet_disable(&pl022->pump_transfers); return 0; } -#if defined(CONFIG_SUSPEND) || defined(CONFIG_PM_RUNTIME) -/* - * These two functions are used from both suspend/resume and - * the runtime counterparts to handle external resources like - * clocks, pins and regulators when going to sleep. - */ -static void pl022_suspend_resources(struct pl022 *pl022, bool runtime) -{ - clk_disable(pl022->clk); - - if (runtime) - pinctrl_pm_select_idle_state(&pl022->adev->dev); - else - pinctrl_pm_select_sleep_state(&pl022->adev->dev); -} - -static void pl022_resume_resources(struct pl022 *pl022, bool runtime) -{ - /* First go to the default state */ - pinctrl_pm_select_default_state(&pl022->adev->dev); - if (!runtime) - /* Then let's idle the pins until the next transfer happens */ - pinctrl_pm_select_idle_state(&pl022->adev->dev); - - clk_enable(pl022->clk); -} -#endif - -#ifdef CONFIG_SUSPEND +#ifdef CONFIG_PM_SLEEP static int pl022_suspend(struct device *dev) { struct pl022 *pl022 = dev_get_drvdata(dev); @@ -2328,8 +2288,13 @@ static int pl022_suspend(struct device *dev) return ret; } - pm_runtime_get_sync(dev); - pl022_suspend_resources(pl022, false); + ret = pm_runtime_force_suspend(dev); + if (ret) { + spi_master_resume(pl022->master); + return ret; + } + + pinctrl_pm_select_sleep_state(dev); dev_dbg(dev, "suspended\n"); return 0; @@ -2340,8 +2305,9 @@ static int pl022_resume(struct device *dev) struct pl022 *pl022 = dev_get_drvdata(dev); int ret; - pl022_resume_resources(pl022, false); - pm_runtime_put(dev); + ret = pm_runtime_force_resume(dev); + if (ret) + dev_err(dev, "problem resuming\n"); /* Start the queue running */ ret = spi_master_resume(pl022->master); @@ -2352,14 +2318,16 @@ static int pl022_resume(struct device *dev) return ret; } -#endif /* CONFIG_PM */ +#endif -#ifdef CONFIG_PM_RUNTIME +#ifdef CONFIG_PM static int pl022_runtime_suspend(struct device *dev) { struct pl022 *pl022 = dev_get_drvdata(dev); - pl022_suspend_resources(pl022, true); + clk_disable_unprepare(pl022->clk); + pinctrl_pm_select_idle_state(dev); + return 0; } @@ -2367,14 +2335,16 @@ static int pl022_runtime_resume(struct device *dev) { struct pl022 *pl022 = dev_get_drvdata(dev); - pl022_resume_resources(pl022, true); + pinctrl_pm_select_default_state(dev); + clk_prepare_enable(pl022->clk); + return 0; } #endif static const struct dev_pm_ops pl022_dev_pm_ops = { SET_SYSTEM_SLEEP_PM_OPS(pl022_suspend, pl022_resume) - SET_RUNTIME_PM_OPS(pl022_runtime_suspend, pl022_runtime_resume, NULL) + SET_PM_RUNTIME_PM_OPS(pl022_runtime_suspend, pl022_runtime_resume, NULL) }; static struct vendor_data vendor_arm = { diff --git a/drivers/spi/spi-ppc4xx.c b/drivers/spi/spi-ppc4xx.c index 5ee56726f8d..80b8408ac3e 100644 --- a/drivers/spi/spi-ppc4xx.c +++ b/drivers/spi/spi-ppc4xx.c @@ -24,7 +24,6 @@ */ #include <linux/module.h> -#include <linux/init.h> #include <linux/sched.h> #include <linux/slab.h> #include <linux/errno.h> diff --git a/drivers/spi/spi-pxa2xx-dma.c b/drivers/spi/spi-pxa2xx-dma.c index 3c0b55125f1..713af4806f2 100644 --- a/drivers/spi/spi-pxa2xx-dma.c +++ b/drivers/spi/spi-pxa2xx-dma.c @@ -9,7 +9,6 @@ * published by the Free Software Foundation. */ -#include <linux/init.h> #include <linux/device.h> #include <linux/dma-mapping.h> #include <linux/dmaengine.h> diff --git a/drivers/spi/spi-pxa2xx-pxadma.c b/drivers/spi/spi-pxa2xx-pxadma.c index 2916efc7cfe..e8a26f25d5c 100644 --- a/drivers/spi/spi-pxa2xx-pxadma.c +++ b/drivers/spi/spi-pxa2xx-pxadma.c @@ -18,7 +18,6 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include <linux/init.h> #include <linux/delay.h> #include <linux/device.h> #include <linux/dma-mapping.h> diff --git a/drivers/spi/spi-pxa2xx.c b/drivers/spi/spi-pxa2xx.c index c702fc536a7..41185d0557f 100644 --- a/drivers/spi/spi-pxa2xx.c +++ b/drivers/spi/spi-pxa2xx.c @@ -362,8 +362,7 @@ static void giveback(struct driver_data *drv_data) drv_data->cur_msg = NULL; drv_data->cur_transfer = NULL; - last_transfer = list_entry(msg->transfers.prev, - struct spi_transfer, + last_transfer = list_last_entry(&msg->transfers, struct spi_transfer, transfer_list); /* Delay if requested before any change in chip select */ diff --git a/drivers/spi/spi-qup.c b/drivers/spi/spi-qup.c new file mode 100644 index 00000000000..b032e8885e2 --- /dev/null +++ b/drivers/spi/spi-qup.c @@ -0,0 +1,779 @@ +/* + * Copyright (c) 2008-2014, The Linux foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License rev 2 and + * only rev 2 as published by the free Software foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or fITNESS fOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/clk.h> +#include <linux/delay.h> +#include <linux/err.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/list.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/platform_device.h> +#include <linux/pm_runtime.h> +#include <linux/spi/spi.h> + +#define QUP_CONFIG 0x0000 +#define QUP_STATE 0x0004 +#define QUP_IO_M_MODES 0x0008 +#define QUP_SW_RESET 0x000c +#define QUP_OPERATIONAL 0x0018 +#define QUP_ERROR_FLAGS 0x001c +#define QUP_ERROR_FLAGS_EN 0x0020 +#define QUP_OPERATIONAL_MASK 0x0028 +#define QUP_HW_VERSION 0x0030 +#define QUP_MX_OUTPUT_CNT 0x0100 +#define QUP_OUTPUT_FIFO 0x0110 +#define QUP_MX_WRITE_CNT 0x0150 +#define QUP_MX_INPUT_CNT 0x0200 +#define QUP_MX_READ_CNT 0x0208 +#define QUP_INPUT_FIFO 0x0218 + +#define SPI_CONFIG 0x0300 +#define SPI_IO_CONTROL 0x0304 +#define SPI_ERROR_FLAGS 0x0308 +#define SPI_ERROR_FLAGS_EN 0x030c + +/* QUP_CONFIG fields */ +#define QUP_CONFIG_SPI_MODE (1 << 8) +#define QUP_CONFIG_CLOCK_AUTO_GATE BIT(13) +#define QUP_CONFIG_NO_INPUT BIT(7) +#define QUP_CONFIG_NO_OUTPUT BIT(6) +#define QUP_CONFIG_N 0x001f + +/* QUP_STATE fields */ +#define QUP_STATE_VALID BIT(2) +#define QUP_STATE_RESET 0 +#define QUP_STATE_RUN 1 +#define QUP_STATE_PAUSE 3 +#define QUP_STATE_MASK 3 +#define QUP_STATE_CLEAR 2 + +#define QUP_HW_VERSION_2_1_1 0x20010001 + +/* QUP_IO_M_MODES fields */ +#define QUP_IO_M_PACK_EN BIT(15) +#define QUP_IO_M_UNPACK_EN BIT(14) +#define QUP_IO_M_INPUT_MODE_MASK_SHIFT 12 +#define QUP_IO_M_OUTPUT_MODE_MASK_SHIFT 10 +#define QUP_IO_M_INPUT_MODE_MASK (3 << QUP_IO_M_INPUT_MODE_MASK_SHIFT) +#define QUP_IO_M_OUTPUT_MODE_MASK (3 << QUP_IO_M_OUTPUT_MODE_MASK_SHIFT) + +#define QUP_IO_M_OUTPUT_BLOCK_SIZE(x) (((x) & (0x03 << 0)) >> 0) +#define QUP_IO_M_OUTPUT_FIFO_SIZE(x) (((x) & (0x07 << 2)) >> 2) +#define QUP_IO_M_INPUT_BLOCK_SIZE(x) (((x) & (0x03 << 5)) >> 5) +#define QUP_IO_M_INPUT_FIFO_SIZE(x) (((x) & (0x07 << 7)) >> 7) + +#define QUP_IO_M_MODE_FIFO 0 +#define QUP_IO_M_MODE_BLOCK 1 +#define QUP_IO_M_MODE_DMOV 2 +#define QUP_IO_M_MODE_BAM 3 + +/* QUP_OPERATIONAL fields */ +#define QUP_OP_MAX_INPUT_DONE_FLAG BIT(11) +#define QUP_OP_MAX_OUTPUT_DONE_FLAG BIT(10) +#define QUP_OP_IN_SERVICE_FLAG BIT(9) +#define QUP_OP_OUT_SERVICE_FLAG BIT(8) +#define QUP_OP_IN_FIFO_FULL BIT(7) +#define QUP_OP_OUT_FIFO_FULL BIT(6) +#define QUP_OP_IN_FIFO_NOT_EMPTY BIT(5) +#define QUP_OP_OUT_FIFO_NOT_EMPTY BIT(4) + +/* QUP_ERROR_FLAGS and QUP_ERROR_FLAGS_EN fields */ +#define QUP_ERROR_OUTPUT_OVER_RUN BIT(5) +#define QUP_ERROR_INPUT_UNDER_RUN BIT(4) +#define QUP_ERROR_OUTPUT_UNDER_RUN BIT(3) +#define QUP_ERROR_INPUT_OVER_RUN BIT(2) + +/* SPI_CONFIG fields */ +#define SPI_CONFIG_HS_MODE BIT(10) +#define SPI_CONFIG_INPUT_FIRST BIT(9) +#define SPI_CONFIG_LOOPBACK BIT(8) + +/* SPI_IO_CONTROL fields */ +#define SPI_IO_C_FORCE_CS BIT(11) +#define SPI_IO_C_CLK_IDLE_HIGH BIT(10) +#define SPI_IO_C_MX_CS_MODE BIT(8) +#define SPI_IO_C_CS_N_POLARITY_0 BIT(4) +#define SPI_IO_C_CS_SELECT(x) (((x) & 3) << 2) +#define SPI_IO_C_CS_SELECT_MASK 0x000c +#define SPI_IO_C_TRISTATE_CS BIT(1) +#define SPI_IO_C_NO_TRI_STATE BIT(0) + +/* SPI_ERROR_FLAGS and SPI_ERROR_FLAGS_EN fields */ +#define SPI_ERROR_CLK_OVER_RUN BIT(1) +#define SPI_ERROR_CLK_UNDER_RUN BIT(0) + +#define SPI_NUM_CHIPSELECTS 4 + +/* high speed mode is when bus rate is greater then 26MHz */ +#define SPI_HS_MIN_RATE 26000000 +#define SPI_MAX_RATE 50000000 + +#define SPI_DELAY_THRESHOLD 1 +#define SPI_DELAY_RETRY 10 + +struct spi_qup { + void __iomem *base; + struct device *dev; + struct clk *cclk; /* core clock */ + struct clk *iclk; /* interface clock */ + int irq; + spinlock_t lock; + + int in_fifo_sz; + int out_fifo_sz; + int in_blk_sz; + int out_blk_sz; + + struct spi_transfer *xfer; + struct completion done; + int error; + int w_size; /* bytes per SPI word */ + int tx_bytes; + int rx_bytes; +}; + + +static inline bool spi_qup_is_valid_state(struct spi_qup *controller) +{ + u32 opstate = readl_relaxed(controller->base + QUP_STATE); + + return opstate & QUP_STATE_VALID; +} + +static int spi_qup_set_state(struct spi_qup *controller, u32 state) +{ + unsigned long loop; + u32 cur_state; + + loop = 0; + while (!spi_qup_is_valid_state(controller)) { + + usleep_range(SPI_DELAY_THRESHOLD, SPI_DELAY_THRESHOLD * 2); + + if (++loop > SPI_DELAY_RETRY) + return -EIO; + } + + if (loop) + dev_dbg(controller->dev, "invalid state for %ld,us %d\n", + loop, state); + + cur_state = readl_relaxed(controller->base + QUP_STATE); + /* + * Per spec: for PAUSE_STATE to RESET_STATE, two writes + * of (b10) are required + */ + if (((cur_state & QUP_STATE_MASK) == QUP_STATE_PAUSE) && + (state == QUP_STATE_RESET)) { + writel_relaxed(QUP_STATE_CLEAR, controller->base + QUP_STATE); + writel_relaxed(QUP_STATE_CLEAR, controller->base + QUP_STATE); + } else { + cur_state &= ~QUP_STATE_MASK; + cur_state |= state; + writel_relaxed(cur_state, controller->base + QUP_STATE); + } + + loop = 0; + while (!spi_qup_is_valid_state(controller)) { + + usleep_range(SPI_DELAY_THRESHOLD, SPI_DELAY_THRESHOLD * 2); + + if (++loop > SPI_DELAY_RETRY) + return -EIO; + } + + return 0; +} + + +static void spi_qup_fifo_read(struct spi_qup *controller, + struct spi_transfer *xfer) +{ + u8 *rx_buf = xfer->rx_buf; + u32 word, state; + int idx, shift, w_size; + + w_size = controller->w_size; + + while (controller->rx_bytes < xfer->len) { + + state = readl_relaxed(controller->base + QUP_OPERATIONAL); + if (0 == (state & QUP_OP_IN_FIFO_NOT_EMPTY)) + break; + + word = readl_relaxed(controller->base + QUP_INPUT_FIFO); + + if (!rx_buf) { + controller->rx_bytes += w_size; + continue; + } + + for (idx = 0; idx < w_size; idx++, controller->rx_bytes++) { + /* + * The data format depends on bytes per SPI word: + * 4 bytes: 0x12345678 + * 2 bytes: 0x00001234 + * 1 byte : 0x00000012 + */ + shift = BITS_PER_BYTE; + shift *= (w_size - idx - 1); + rx_buf[controller->rx_bytes] = word >> shift; + } + } +} + +static void spi_qup_fifo_write(struct spi_qup *controller, + struct spi_transfer *xfer) +{ + const u8 *tx_buf = xfer->tx_buf; + u32 word, state, data; + int idx, w_size; + + w_size = controller->w_size; + + while (controller->tx_bytes < xfer->len) { + + state = readl_relaxed(controller->base + QUP_OPERATIONAL); + if (state & QUP_OP_OUT_FIFO_FULL) + break; + + word = 0; + for (idx = 0; idx < w_size; idx++, controller->tx_bytes++) { + + if (!tx_buf) { + controller->tx_bytes += w_size; + break; + } + + data = tx_buf[controller->tx_bytes]; + word |= data << (BITS_PER_BYTE * (3 - idx)); + } + + writel_relaxed(word, controller->base + QUP_OUTPUT_FIFO); + } +} + +static irqreturn_t spi_qup_qup_irq(int irq, void *dev_id) +{ + struct spi_qup *controller = dev_id; + struct spi_transfer *xfer; + u32 opflags, qup_err, spi_err; + unsigned long flags; + int error = 0; + + spin_lock_irqsave(&controller->lock, flags); + xfer = controller->xfer; + controller->xfer = NULL; + spin_unlock_irqrestore(&controller->lock, flags); + + qup_err = readl_relaxed(controller->base + QUP_ERROR_FLAGS); + spi_err = readl_relaxed(controller->base + SPI_ERROR_FLAGS); + opflags = readl_relaxed(controller->base + QUP_OPERATIONAL); + + writel_relaxed(qup_err, controller->base + QUP_ERROR_FLAGS); + writel_relaxed(spi_err, controller->base + SPI_ERROR_FLAGS); + writel_relaxed(opflags, controller->base + QUP_OPERATIONAL); + + if (!xfer) { + dev_err_ratelimited(controller->dev, "unexpected irq %x08 %x08 %x08\n", + qup_err, spi_err, opflags); + return IRQ_HANDLED; + } + + if (qup_err) { + if (qup_err & QUP_ERROR_OUTPUT_OVER_RUN) + dev_warn(controller->dev, "OUTPUT_OVER_RUN\n"); + if (qup_err & QUP_ERROR_INPUT_UNDER_RUN) + dev_warn(controller->dev, "INPUT_UNDER_RUN\n"); + if (qup_err & QUP_ERROR_OUTPUT_UNDER_RUN) + dev_warn(controller->dev, "OUTPUT_UNDER_RUN\n"); + if (qup_err & QUP_ERROR_INPUT_OVER_RUN) + dev_warn(controller->dev, "INPUT_OVER_RUN\n"); + + error = -EIO; + } + + if (spi_err) { + if (spi_err & SPI_ERROR_CLK_OVER_RUN) + dev_warn(controller->dev, "CLK_OVER_RUN\n"); + if (spi_err & SPI_ERROR_CLK_UNDER_RUN) + dev_warn(controller->dev, "CLK_UNDER_RUN\n"); + + error = -EIO; + } + + if (opflags & QUP_OP_IN_SERVICE_FLAG) + spi_qup_fifo_read(controller, xfer); + + if (opflags & QUP_OP_OUT_SERVICE_FLAG) + spi_qup_fifo_write(controller, xfer); + + spin_lock_irqsave(&controller->lock, flags); + controller->error = error; + controller->xfer = xfer; + spin_unlock_irqrestore(&controller->lock, flags); + + if (controller->rx_bytes == xfer->len || error) + complete(&controller->done); + + return IRQ_HANDLED; +} + + +/* set clock freq ... bits per word */ +static int spi_qup_io_config(struct spi_device *spi, struct spi_transfer *xfer) +{ + struct spi_qup *controller = spi_master_get_devdata(spi->master); + u32 config, iomode, mode; + int ret, n_words, w_size; + + if (spi->mode & SPI_LOOP && xfer->len > controller->in_fifo_sz) { + dev_err(controller->dev, "too big size for loopback %d > %d\n", + xfer->len, controller->in_fifo_sz); + return -EIO; + } + + ret = clk_set_rate(controller->cclk, xfer->speed_hz); + if (ret) { + dev_err(controller->dev, "fail to set frequency %d", + xfer->speed_hz); + return -EIO; + } + + if (spi_qup_set_state(controller, QUP_STATE_RESET)) { + dev_err(controller->dev, "cannot set RESET state\n"); + return -EIO; + } + + w_size = 4; + if (xfer->bits_per_word <= 8) + w_size = 1; + else if (xfer->bits_per_word <= 16) + w_size = 2; + + n_words = xfer->len / w_size; + controller->w_size = w_size; + + if (n_words <= controller->in_fifo_sz) { + mode = QUP_IO_M_MODE_FIFO; + writel_relaxed(n_words, controller->base + QUP_MX_READ_CNT); + writel_relaxed(n_words, controller->base + QUP_MX_WRITE_CNT); + /* must be zero for FIFO */ + writel_relaxed(0, controller->base + QUP_MX_INPUT_CNT); + writel_relaxed(0, controller->base + QUP_MX_OUTPUT_CNT); + } else { + mode = QUP_IO_M_MODE_BLOCK; + writel_relaxed(n_words, controller->base + QUP_MX_INPUT_CNT); + writel_relaxed(n_words, controller->base + QUP_MX_OUTPUT_CNT); + /* must be zero for BLOCK and BAM */ + writel_relaxed(0, controller->base + QUP_MX_READ_CNT); + writel_relaxed(0, controller->base + QUP_MX_WRITE_CNT); + } + + iomode = readl_relaxed(controller->base + QUP_IO_M_MODES); + /* Set input and output transfer mode */ + iomode &= ~(QUP_IO_M_INPUT_MODE_MASK | QUP_IO_M_OUTPUT_MODE_MASK); + iomode &= ~(QUP_IO_M_PACK_EN | QUP_IO_M_UNPACK_EN); + iomode |= (mode << QUP_IO_M_OUTPUT_MODE_MASK_SHIFT); + iomode |= (mode << QUP_IO_M_INPUT_MODE_MASK_SHIFT); + + writel_relaxed(iomode, controller->base + QUP_IO_M_MODES); + + config = readl_relaxed(controller->base + SPI_CONFIG); + + if (spi->mode & SPI_LOOP) + config |= SPI_CONFIG_LOOPBACK; + else + config &= ~SPI_CONFIG_LOOPBACK; + + if (spi->mode & SPI_CPHA) + config &= ~SPI_CONFIG_INPUT_FIRST; + else + config |= SPI_CONFIG_INPUT_FIRST; + + /* + * HS_MODE improves signal stability for spi-clk high rates, + * but is invalid in loop back mode. + */ + if ((xfer->speed_hz >= SPI_HS_MIN_RATE) && !(spi->mode & SPI_LOOP)) + config |= SPI_CONFIG_HS_MODE; + else + config &= ~SPI_CONFIG_HS_MODE; + + writel_relaxed(config, controller->base + SPI_CONFIG); + + config = readl_relaxed(controller->base + QUP_CONFIG); + config &= ~(QUP_CONFIG_NO_INPUT | QUP_CONFIG_NO_OUTPUT | QUP_CONFIG_N); + config |= xfer->bits_per_word - 1; + config |= QUP_CONFIG_SPI_MODE; + writel_relaxed(config, controller->base + QUP_CONFIG); + + writel_relaxed(0, controller->base + QUP_OPERATIONAL_MASK); + return 0; +} + +static void spi_qup_set_cs(struct spi_device *spi, bool enable) +{ + struct spi_qup *controller = spi_master_get_devdata(spi->master); + + u32 iocontol, mask; + + iocontol = readl_relaxed(controller->base + SPI_IO_CONTROL); + + /* Disable auto CS toggle and use manual */ + iocontol &= ~SPI_IO_C_MX_CS_MODE; + iocontol |= SPI_IO_C_FORCE_CS; + + iocontol &= ~SPI_IO_C_CS_SELECT_MASK; + iocontol |= SPI_IO_C_CS_SELECT(spi->chip_select); + + mask = SPI_IO_C_CS_N_POLARITY_0 << spi->chip_select; + + if (enable) + iocontol |= mask; + else + iocontol &= ~mask; + + writel_relaxed(iocontol, controller->base + SPI_IO_CONTROL); +} + +static int spi_qup_transfer_one(struct spi_master *master, + struct spi_device *spi, + struct spi_transfer *xfer) +{ + struct spi_qup *controller = spi_master_get_devdata(master); + unsigned long timeout, flags; + int ret = -EIO; + + ret = spi_qup_io_config(spi, xfer); + if (ret) + return ret; + + timeout = DIV_ROUND_UP(xfer->speed_hz, MSEC_PER_SEC); + timeout = DIV_ROUND_UP(xfer->len * 8, timeout); + timeout = 100 * msecs_to_jiffies(timeout); + + reinit_completion(&controller->done); + + spin_lock_irqsave(&controller->lock, flags); + controller->xfer = xfer; + controller->error = 0; + controller->rx_bytes = 0; + controller->tx_bytes = 0; + spin_unlock_irqrestore(&controller->lock, flags); + + if (spi_qup_set_state(controller, QUP_STATE_RUN)) { + dev_warn(controller->dev, "cannot set RUN state\n"); + goto exit; + } + + if (spi_qup_set_state(controller, QUP_STATE_PAUSE)) { + dev_warn(controller->dev, "cannot set PAUSE state\n"); + goto exit; + } + + spi_qup_fifo_write(controller, xfer); + + if (spi_qup_set_state(controller, QUP_STATE_RUN)) { + dev_warn(controller->dev, "cannot set EXECUTE state\n"); + goto exit; + } + + if (!wait_for_completion_timeout(&controller->done, timeout)) + ret = -ETIMEDOUT; +exit: + spi_qup_set_state(controller, QUP_STATE_RESET); + spin_lock_irqsave(&controller->lock, flags); + controller->xfer = NULL; + if (!ret) + ret = controller->error; + spin_unlock_irqrestore(&controller->lock, flags); + return ret; +} + +static int spi_qup_probe(struct platform_device *pdev) +{ + struct spi_master *master; + struct clk *iclk, *cclk; + struct spi_qup *controller; + struct resource *res; + struct device *dev; + void __iomem *base; + u32 data, max_freq, iomode; + int ret, irq, size; + + dev = &pdev->dev; + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + base = devm_ioremap_resource(dev, res); + if (IS_ERR(base)) + return PTR_ERR(base); + + irq = platform_get_irq(pdev, 0); + if (irq < 0) + return irq; + + cclk = devm_clk_get(dev, "core"); + if (IS_ERR(cclk)) + return PTR_ERR(cclk); + + iclk = devm_clk_get(dev, "iface"); + if (IS_ERR(iclk)) + return PTR_ERR(iclk); + + /* This is optional parameter */ + if (of_property_read_u32(dev->of_node, "spi-max-frequency", &max_freq)) + max_freq = SPI_MAX_RATE; + + if (!max_freq || max_freq > SPI_MAX_RATE) { + dev_err(dev, "invalid clock frequency %d\n", max_freq); + return -ENXIO; + } + + ret = clk_prepare_enable(cclk); + if (ret) { + dev_err(dev, "cannot enable core clock\n"); + return ret; + } + + ret = clk_prepare_enable(iclk); + if (ret) { + clk_disable_unprepare(cclk); + dev_err(dev, "cannot enable iface clock\n"); + return ret; + } + + data = readl_relaxed(base + QUP_HW_VERSION); + + if (data < QUP_HW_VERSION_2_1_1) { + clk_disable_unprepare(cclk); + clk_disable_unprepare(iclk); + dev_err(dev, "v.%08x is not supported\n", data); + return -ENXIO; + } + + master = spi_alloc_master(dev, sizeof(struct spi_qup)); + if (!master) { + clk_disable_unprepare(cclk); + clk_disable_unprepare(iclk); + dev_err(dev, "cannot allocate master\n"); + return -ENOMEM; + } + + master->bus_num = pdev->id; + master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LOOP; + master->num_chipselect = SPI_NUM_CHIPSELECTS; + master->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 32); + master->max_speed_hz = max_freq; + master->set_cs = spi_qup_set_cs; + master->transfer_one = spi_qup_transfer_one; + master->dev.of_node = pdev->dev.of_node; + master->auto_runtime_pm = true; + + platform_set_drvdata(pdev, master); + + controller = spi_master_get_devdata(master); + + controller->dev = dev; + controller->base = base; + controller->iclk = iclk; + controller->cclk = cclk; + controller->irq = irq; + + spin_lock_init(&controller->lock); + init_completion(&controller->done); + + iomode = readl_relaxed(base + QUP_IO_M_MODES); + + size = QUP_IO_M_OUTPUT_BLOCK_SIZE(iomode); + if (size) + controller->out_blk_sz = size * 16; + else + controller->out_blk_sz = 4; + + size = QUP_IO_M_INPUT_BLOCK_SIZE(iomode); + if (size) + controller->in_blk_sz = size * 16; + else + controller->in_blk_sz = 4; + + size = QUP_IO_M_OUTPUT_FIFO_SIZE(iomode); + controller->out_fifo_sz = controller->out_blk_sz * (2 << size); + + size = QUP_IO_M_INPUT_FIFO_SIZE(iomode); + controller->in_fifo_sz = controller->in_blk_sz * (2 << size); + + dev_info(dev, "v.%08x IN:block:%d, fifo:%d, OUT:block:%d, fifo:%d\n", + data, controller->in_blk_sz, controller->in_fifo_sz, + controller->out_blk_sz, controller->out_fifo_sz); + + writel_relaxed(1, base + QUP_SW_RESET); + + ret = spi_qup_set_state(controller, QUP_STATE_RESET); + if (ret) { + dev_err(dev, "cannot set RESET state\n"); + goto error; + } + + writel_relaxed(0, base + QUP_OPERATIONAL); + writel_relaxed(0, base + QUP_IO_M_MODES); + writel_relaxed(0, base + QUP_OPERATIONAL_MASK); + writel_relaxed(SPI_ERROR_CLK_UNDER_RUN | SPI_ERROR_CLK_OVER_RUN, + base + SPI_ERROR_FLAGS_EN); + + writel_relaxed(0, base + SPI_CONFIG); + writel_relaxed(SPI_IO_C_NO_TRI_STATE, base + SPI_IO_CONTROL); + + ret = devm_request_irq(dev, irq, spi_qup_qup_irq, + IRQF_TRIGGER_HIGH, pdev->name, controller); + if (ret) + goto error; + + ret = devm_spi_register_master(dev, master); + if (ret) + goto error; + + pm_runtime_set_autosuspend_delay(dev, MSEC_PER_SEC); + pm_runtime_use_autosuspend(dev); + pm_runtime_set_active(dev); + pm_runtime_enable(dev); + return 0; + +error: + clk_disable_unprepare(cclk); + clk_disable_unprepare(iclk); + spi_master_put(master); + return ret; +} + +#ifdef CONFIG_PM_RUNTIME +static int spi_qup_pm_suspend_runtime(struct device *device) +{ + struct spi_master *master = dev_get_drvdata(device); + struct spi_qup *controller = spi_master_get_devdata(master); + u32 config; + + /* Enable clocks auto gaiting */ + config = readl(controller->base + QUP_CONFIG); + config |= QUP_CONFIG_CLOCK_AUTO_GATE; + writel_relaxed(config, controller->base + QUP_CONFIG); + return 0; +} + +static int spi_qup_pm_resume_runtime(struct device *device) +{ + struct spi_master *master = dev_get_drvdata(device); + struct spi_qup *controller = spi_master_get_devdata(master); + u32 config; + + /* Disable clocks auto gaiting */ + config = readl_relaxed(controller->base + QUP_CONFIG); + config &= ~QUP_CONFIG_CLOCK_AUTO_GATE; + writel_relaxed(config, controller->base + QUP_CONFIG); + return 0; +} +#endif /* CONFIG_PM_RUNTIME */ + +#ifdef CONFIG_PM_SLEEP +static int spi_qup_suspend(struct device *device) +{ + struct spi_master *master = dev_get_drvdata(device); + struct spi_qup *controller = spi_master_get_devdata(master); + int ret; + + ret = spi_master_suspend(master); + if (ret) + return ret; + + ret = spi_qup_set_state(controller, QUP_STATE_RESET); + if (ret) + return ret; + + clk_disable_unprepare(controller->cclk); + clk_disable_unprepare(controller->iclk); + return 0; +} + +static int spi_qup_resume(struct device *device) +{ + struct spi_master *master = dev_get_drvdata(device); + struct spi_qup *controller = spi_master_get_devdata(master); + int ret; + + ret = clk_prepare_enable(controller->iclk); + if (ret) + return ret; + + ret = clk_prepare_enable(controller->cclk); + if (ret) + return ret; + + ret = spi_qup_set_state(controller, QUP_STATE_RESET); + if (ret) + return ret; + + return spi_master_resume(master); +} +#endif /* CONFIG_PM_SLEEP */ + +static int spi_qup_remove(struct platform_device *pdev) +{ + struct spi_master *master = dev_get_drvdata(&pdev->dev); + struct spi_qup *controller = spi_master_get_devdata(master); + int ret; + + ret = pm_runtime_get_sync(&pdev->dev); + if (ret) + return ret; + + ret = spi_qup_set_state(controller, QUP_STATE_RESET); + if (ret) + return ret; + + clk_disable_unprepare(controller->cclk); + clk_disable_unprepare(controller->iclk); + + pm_runtime_put_noidle(&pdev->dev); + pm_runtime_disable(&pdev->dev); + return 0; +} + +static struct of_device_id spi_qup_dt_match[] = { + { .compatible = "qcom,spi-qup-v2.1.1", }, + { .compatible = "qcom,spi-qup-v2.2.1", }, + { } +}; +MODULE_DEVICE_TABLE(of, spi_qup_dt_match); + +static const struct dev_pm_ops spi_qup_dev_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(spi_qup_suspend, spi_qup_resume) + SET_RUNTIME_PM_OPS(spi_qup_pm_suspend_runtime, + spi_qup_pm_resume_runtime, + NULL) +}; + +static struct platform_driver spi_qup_driver = { + .driver = { + .name = "spi_qup", + .owner = THIS_MODULE, + .pm = &spi_qup_dev_pm_ops, + .of_match_table = spi_qup_dt_match, + }, + .probe = spi_qup_probe, + .remove = spi_qup_remove, +}; +module_platform_driver(spi_qup_driver); + +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:spi_qup"); diff --git a/drivers/spi/spi-rspi.c b/drivers/spi/spi-rspi.c index 28987d9fcfe..1fb0ad21332 100644 --- a/drivers/spi/spi-rspi.c +++ b/drivers/spi/spi-rspi.c @@ -1,7 +1,8 @@ /* * SH RSPI driver * - * Copyright (C) 2012 Renesas Solutions Corp. + * Copyright (C) 2012, 2013 Renesas Solutions Corp. + * Copyright (C) 2014 Glider bvba * * Based on spi-sh.c: * Copyright (C) 2011 Renesas Solutions Corp. @@ -25,14 +26,14 @@ #include <linux/kernel.h> #include <linux/sched.h> #include <linux/errno.h> -#include <linux/list.h> -#include <linux/workqueue.h> #include <linux/interrupt.h> #include <linux/platform_device.h> #include <linux/io.h> #include <linux/clk.h> #include <linux/dmaengine.h> #include <linux/dma-mapping.h> +#include <linux/of_device.h> +#include <linux/pm_runtime.h> #include <linux/sh_dma.h> #include <linux/spi/spi.h> #include <linux/spi/rspi.h> @@ -49,7 +50,7 @@ #define RSPI_SPCKD 0x0c /* Clock Delay Register */ #define RSPI_SSLND 0x0d /* Slave Select Negation Delay Register */ #define RSPI_SPND 0x0e /* Next-Access Delay Register */ -#define RSPI_SPCR2 0x0f /* Control Register 2 */ +#define RSPI_SPCR2 0x0f /* Control Register 2 (SH only) */ #define RSPI_SPCMD0 0x10 /* Command Register 0 */ #define RSPI_SPCMD1 0x12 /* Command Register 1 */ #define RSPI_SPCMD2 0x14 /* Command Register 2 */ @@ -58,16 +59,23 @@ #define RSPI_SPCMD5 0x1a /* Command Register 5 */ #define RSPI_SPCMD6 0x1c /* Command Register 6 */ #define RSPI_SPCMD7 0x1e /* Command Register 7 */ +#define RSPI_SPCMD(i) (RSPI_SPCMD0 + (i) * 2) +#define RSPI_NUM_SPCMD 8 +#define RSPI_RZ_NUM_SPCMD 4 +#define QSPI_NUM_SPCMD 4 + +/* RSPI on RZ only */ #define RSPI_SPBFCR 0x20 /* Buffer Control Register */ #define RSPI_SPBFDR 0x22 /* Buffer Data Count Setting Register */ -/*qspi only */ +/* QSPI only */ #define QSPI_SPBFCR 0x18 /* Buffer Control Register */ #define QSPI_SPBDCR 0x1a /* Buffer Data Count Register */ #define QSPI_SPBMUL0 0x1c /* Transfer Data Length Multiplier Setting Register 0 */ #define QSPI_SPBMUL1 0x20 /* Transfer Data Length Multiplier Setting Register 1 */ #define QSPI_SPBMUL2 0x24 /* Transfer Data Length Multiplier Setting Register 2 */ #define QSPI_SPBMUL3 0x28 /* Transfer Data Length Multiplier Setting Register 3 */ +#define QSPI_SPBMUL(i) (QSPI_SPBMUL0 + (i) * 4) /* SPCR - Control Register */ #define SPCR_SPRIE 0x80 /* Receive Interrupt Enable */ @@ -104,7 +112,7 @@ #define SPSR_PERF 0x08 /* Parity Error Flag */ #define SPSR_MODF 0x04 /* Mode Fault Error Flag */ #define SPSR_IDLNF 0x02 /* RSPI Idle Flag */ -#define SPSR_OVRF 0x01 /* Overrun Error Flag */ +#define SPSR_OVRF 0x01 /* Overrun Error Flag (RSPI only) */ /* SPSCR - Sequence Control Register */ #define SPSCR_SPSLN_MASK 0x07 /* Sequence Length Specification */ @@ -121,13 +129,13 @@ #define SPDCR_SPLWORD SPDCR_SPLW1 #define SPDCR_SPLBYTE SPDCR_SPLW0 #define SPDCR_SPLW 0x20 /* Access Width Specification (SH) */ -#define SPDCR_SPRDTD 0x10 /* Receive Transmit Data Select */ +#define SPDCR_SPRDTD 0x10 /* Receive Transmit Data Select (SH) */ #define SPDCR_SLSEL1 0x08 #define SPDCR_SLSEL0 0x04 -#define SPDCR_SLSEL_MASK 0x0c /* SSL1 Output Select */ +#define SPDCR_SLSEL_MASK 0x0c /* SSL1 Output Select (SH) */ #define SPDCR_SPFC1 0x02 #define SPDCR_SPFC0 0x01 -#define SPDCR_SPFC_MASK 0x03 /* Frame Count Setting (1-4) */ +#define SPDCR_SPFC_MASK 0x03 /* Frame Count Setting (1-4) (SH) */ /* SPCKD - Clock Delay Register */ #define SPCKD_SCKDL_MASK 0x07 /* Clock Delay Setting (1-8) */ @@ -151,7 +159,7 @@ #define SPCMD_LSBF 0x1000 /* LSB First */ #define SPCMD_SPB_MASK 0x0f00 /* Data Length Setting */ #define SPCMD_SPB_8_TO_16(bit) (((bit - 1) << 8) & SPCMD_SPB_MASK) -#define SPCMD_SPB_8BIT 0x0000 /* qspi only */ +#define SPCMD_SPB_8BIT 0x0000 /* QSPI only */ #define SPCMD_SPB_16BIT 0x0100 #define SPCMD_SPB_20BIT 0x0000 #define SPCMD_SPB_24BIT 0x0100 @@ -170,8 +178,8 @@ #define SPCMD_CPHA 0x0001 /* Clock Phase Setting */ /* SPBFCR - Buffer Control Register */ -#define SPBFCR_TXRST 0x80 /* Transmit Buffer Data Reset (qspi only) */ -#define SPBFCR_RXRST 0x40 /* Receive Buffer Data Reset (qspi only) */ +#define SPBFCR_TXRST 0x80 /* Transmit Buffer Data Reset */ +#define SPBFCR_RXRST 0x40 /* Receive Buffer Data Reset */ #define SPBFCR_TXTRG_MASK 0x30 /* Transmit Buffer Data Triggering Number */ #define SPBFCR_RXTRG_MASK 0x07 /* Receive Buffer Data Triggering Number */ @@ -181,22 +189,21 @@ struct rspi_data { void __iomem *addr; u32 max_speed_hz; struct spi_master *master; - struct list_head queue; - struct work_struct ws; wait_queue_head_t wait; - spinlock_t lock; struct clk *clk; - u8 spsr; u16 spcmd; + u8 spsr; + u8 sppcr; + int rx_irq, tx_irq; const struct spi_ops *ops; /* for dmaengine */ struct dma_chan *chan_tx; struct dma_chan *chan_rx; - int irq; unsigned dma_width_16bit:1; unsigned dma_callbacked:1; + unsigned byte_access:1; }; static void rspi_write8(const struct rspi_data *rspi, u8 data, u16 offset) @@ -224,34 +231,47 @@ static u16 rspi_read16(const struct rspi_data *rspi, u16 offset) return ioread16(rspi->addr + offset); } +static void rspi_write_data(const struct rspi_data *rspi, u16 data) +{ + if (rspi->byte_access) + rspi_write8(rspi, data, RSPI_SPDR); + else /* 16 bit */ + rspi_write16(rspi, data, RSPI_SPDR); +} + +static u16 rspi_read_data(const struct rspi_data *rspi) +{ + if (rspi->byte_access) + return rspi_read8(rspi, RSPI_SPDR); + else /* 16 bit */ + return rspi_read16(rspi, RSPI_SPDR); +} + /* optional functions */ struct spi_ops { - int (*set_config_register)(const struct rspi_data *rspi, - int access_size); - int (*send_pio)(struct rspi_data *rspi, struct spi_message *mesg, - struct spi_transfer *t); - int (*receive_pio)(struct rspi_data *rspi, struct spi_message *mesg, - struct spi_transfer *t); - + int (*set_config_register)(struct rspi_data *rspi, int access_size); + int (*transfer_one)(struct spi_master *master, struct spi_device *spi, + struct spi_transfer *xfer); + u16 mode_bits; }; /* - * functions for RSPI + * functions for RSPI on legacy SH */ -static int rspi_set_config_register(const struct rspi_data *rspi, - int access_size) +static int rspi_set_config_register(struct rspi_data *rspi, int access_size) { int spbr; - /* Sets output mode(CMOS) and MOSI signal(from previous transfer) */ - rspi_write8(rspi, 0x00, RSPI_SPPCR); + /* Sets output mode, MOSI signal, and (optionally) loopback */ + rspi_write8(rspi, rspi->sppcr, RSPI_SPPCR); /* Sets transfer bit rate */ spbr = clk_get_rate(rspi->clk) / (2 * rspi->max_speed_hz) - 1; rspi_write8(rspi, clamp(spbr, 0, 255), RSPI_SPBR); - /* Sets number of frames to be used: 1 frame */ - rspi_write8(rspi, 0x00, RSPI_SPDCR); + /* Disable dummy transmission, set 16-bit word access, 1 frame */ + rspi_write8(rspi, 0, RSPI_SPDCR); + rspi->byte_access = 0; /* Sets RSPCK, SSL, next-access delay value */ rspi_write8(rspi, 0x00, RSPI_SPCKD); @@ -262,8 +282,41 @@ static int rspi_set_config_register(const struct rspi_data *rspi, rspi_write8(rspi, 0x00, RSPI_SPCR2); /* Sets SPCMD */ - rspi_write16(rspi, SPCMD_SPB_8_TO_16(access_size) | rspi->spcmd, - RSPI_SPCMD0); + rspi->spcmd |= SPCMD_SPB_8_TO_16(access_size); + rspi_write16(rspi, rspi->spcmd, RSPI_SPCMD0); + + /* Sets RSPI mode */ + rspi_write8(rspi, SPCR_MSTR, RSPI_SPCR); + + return 0; +} + +/* + * functions for RSPI on RZ + */ +static int rspi_rz_set_config_register(struct rspi_data *rspi, int access_size) +{ + int spbr; + + /* Sets output mode, MOSI signal, and (optionally) loopback */ + rspi_write8(rspi, rspi->sppcr, RSPI_SPPCR); + + /* Sets transfer bit rate */ + spbr = clk_get_rate(rspi->clk) / (2 * rspi->max_speed_hz) - 1; + rspi_write8(rspi, clamp(spbr, 0, 255), RSPI_SPBR); + + /* Disable dummy transmission, set byte access */ + rspi_write8(rspi, SPDCR_SPLBYTE, RSPI_SPDCR); + rspi->byte_access = 1; + + /* Sets RSPCK, SSL, next-access delay value */ + rspi_write8(rspi, 0x00, RSPI_SPCKD); + rspi_write8(rspi, 0x00, RSPI_SSLND); + rspi_write8(rspi, 0x00, RSPI_SPND); + + /* Sets SPCMD */ + rspi->spcmd |= SPCMD_SPB_8_TO_16(access_size); + rspi_write16(rspi, rspi->spcmd, RSPI_SPCMD0); /* Sets RSPI mode */ rspi_write8(rspi, SPCR_MSTR, RSPI_SPCR); @@ -274,21 +327,20 @@ static int rspi_set_config_register(const struct rspi_data *rspi, /* * functions for QSPI */ -static int qspi_set_config_register(const struct rspi_data *rspi, - int access_size) +static int qspi_set_config_register(struct rspi_data *rspi, int access_size) { - u16 spcmd; int spbr; - /* Sets output mode(CMOS) and MOSI signal(from previous transfer) */ - rspi_write8(rspi, 0x00, RSPI_SPPCR); + /* Sets output mode, MOSI signal, and (optionally) loopback */ + rspi_write8(rspi, rspi->sppcr, RSPI_SPPCR); /* Sets transfer bit rate */ spbr = clk_get_rate(rspi->clk) / (2 * rspi->max_speed_hz); rspi_write8(rspi, clamp(spbr, 0, 255), RSPI_SPBR); - /* Sets number of frames to be used: 1 frame */ - rspi_write8(rspi, 0x00, RSPI_SPDCR); + /* Disable dummy transmission, set byte access */ + rspi_write8(rspi, 0, RSPI_SPDCR); + rspi->byte_access = 1; /* Sets RSPCK, SSL, next-access delay value */ rspi_write8(rspi, 0x00, RSPI_SPCKD); @@ -297,13 +349,13 @@ static int qspi_set_config_register(const struct rspi_data *rspi, /* Data Length Setting */ if (access_size == 8) - spcmd = SPCMD_SPB_8BIT; + rspi->spcmd |= SPCMD_SPB_8BIT; else if (access_size == 16) - spcmd = SPCMD_SPB_16BIT; + rspi->spcmd |= SPCMD_SPB_16BIT; else - spcmd = SPCMD_SPB_32BIT; + rspi->spcmd |= SPCMD_SPB_32BIT; - spcmd |= SPCMD_SCKDEN | SPCMD_SLNDEN | rspi->spcmd | SPCMD_SPNDEN; + rspi->spcmd |= SPCMD_SCKDEN | SPCMD_SLNDEN | SPCMD_SPNDEN; /* Resets transfer data length */ rspi_write32(rspi, 0, QSPI_SPBMUL0); @@ -314,9 +366,9 @@ static int qspi_set_config_register(const struct rspi_data *rspi, rspi_write8(rspi, 0x00, QSPI_SPBFCR); /* Sets SPCMD */ - rspi_write16(rspi, spcmd, RSPI_SPCMD0); + rspi_write16(rspi, rspi->spcmd, RSPI_SPCMD0); - /* Enables SPI function in a master mode */ + /* Enables SPI function in master mode */ rspi_write8(rspi, SPCR_SPE | SPCR_MSTR, RSPI_SPCR); return 0; @@ -340,6 +392,9 @@ static int rspi_wait_for_interrupt(struct rspi_data *rspi, u8 wait_mask, int ret; rspi->spsr = rspi_read8(rspi, RSPI_SPSR); + if (rspi->spsr & wait_mask) + return 0; + rspi_enable_irq(rspi, enable_bit); ret = wait_event_timeout(rspi->wait, rspi->spsr & wait_mask, HZ); if (ret == 0 && !(rspi->spsr & wait_mask)) @@ -348,78 +403,39 @@ static int rspi_wait_for_interrupt(struct rspi_data *rspi, u8 wait_mask, return 0; } -static void rspi_assert_ssl(const struct rspi_data *rspi) -{ - rspi_write8(rspi, rspi_read8(rspi, RSPI_SPCR) | SPCR_SPE, RSPI_SPCR); -} - -static void rspi_negate_ssl(const struct rspi_data *rspi) +static int rspi_data_out(struct rspi_data *rspi, u8 data) { - rspi_write8(rspi, rspi_read8(rspi, RSPI_SPCR) & ~SPCR_SPE, RSPI_SPCR); + if (rspi_wait_for_interrupt(rspi, SPSR_SPTEF, SPCR_SPTIE) < 0) { + dev_err(&rspi->master->dev, "transmit timeout\n"); + return -ETIMEDOUT; + } + rspi_write_data(rspi, data); + return 0; } -static int rspi_send_pio(struct rspi_data *rspi, struct spi_message *mesg, - struct spi_transfer *t) +static int rspi_data_in(struct rspi_data *rspi) { - int remain = t->len; - const u8 *data = t->tx_buf; - while (remain > 0) { - rspi_write8(rspi, rspi_read8(rspi, RSPI_SPCR) | SPCR_TXMD, - RSPI_SPCR); - - if (rspi_wait_for_interrupt(rspi, SPSR_SPTEF, SPCR_SPTIE) < 0) { - dev_err(&rspi->master->dev, - "%s: tx empty timeout\n", __func__); - return -ETIMEDOUT; - } + u8 data; - rspi_write16(rspi, *data, RSPI_SPDR); - data++; - remain--; + if (rspi_wait_for_interrupt(rspi, SPSR_SPRF, SPCR_SPRIE) < 0) { + dev_err(&rspi->master->dev, "receive timeout\n"); + return -ETIMEDOUT; } - - /* Waiting for the last transmission */ - rspi_wait_for_interrupt(rspi, SPSR_SPTEF, SPCR_SPTIE); - - return 0; + data = rspi_read_data(rspi); + return data; } -static int qspi_send_pio(struct rspi_data *rspi, struct spi_message *mesg, - struct spi_transfer *t) +static int rspi_data_out_in(struct rspi_data *rspi, u8 data) { - int remain = t->len; - const u8 *data = t->tx_buf; - - rspi_write8(rspi, SPBFCR_TXRST, QSPI_SPBFCR); - rspi_write8(rspi, 0x00, QSPI_SPBFCR); - - while (remain > 0) { - - if (rspi_wait_for_interrupt(rspi, SPSR_SPTEF, SPCR_SPTIE) < 0) { - dev_err(&rspi->master->dev, - "%s: tx empty timeout\n", __func__); - return -ETIMEDOUT; - } - rspi_write8(rspi, *data++, RSPI_SPDR); - - if (rspi_wait_for_interrupt(rspi, SPSR_SPRF, SPCR_SPRIE) < 0) { - dev_err(&rspi->master->dev, - "%s: receive timeout\n", __func__); - return -ETIMEDOUT; - } - rspi_read8(rspi, RSPI_SPDR); - - remain--; - } + int ret; - /* Waiting for the last transmission */ - rspi_wait_for_interrupt(rspi, SPSR_SPTEF, SPCR_SPTIE); + ret = rspi_data_out(rspi, data); + if (ret < 0) + return ret; - return 0; + return rspi_data_in(rspi); } -#define send_pio(spi, mesg, t) spi->ops->send_pio(spi, mesg, t) - static void rspi_dma_complete(void *arg) { struct rspi_data *rspi = arg; @@ -471,7 +487,7 @@ static int rspi_send_dma(struct rspi_data *rspi, struct spi_transfer *t) struct scatterlist sg; const void *buf = NULL; struct dma_async_tx_descriptor *desc; - unsigned len; + unsigned int len; int ret = 0; if (rspi->dma_width_16bit) { @@ -509,7 +525,7 @@ static int rspi_send_dma(struct rspi_data *rspi, struct spi_transfer *t) * DMAC needs SPTIE, but if SPTIE is set, this IRQ routine will be * called. So, this driver disables the IRQ while DMA transfer. */ - disable_irq(rspi->irq); + disable_irq(rspi->tx_irq); rspi_write8(rspi, rspi_read8(rspi, RSPI_SPCR) | SPCR_TXMD, RSPI_SPCR); rspi_enable_irq(rspi, SPCR_SPTIE); @@ -528,7 +544,7 @@ static int rspi_send_dma(struct rspi_data *rspi, struct spi_transfer *t) ret = -ETIMEDOUT; rspi_disable_irq(rspi, SPCR_SPTIE); - enable_irq(rspi->irq); + enable_irq(rspi->tx_irq); end: rspi_dma_unmap_sg(&sg, rspi->chan_tx, DMA_TO_DEVICE); @@ -545,46 +561,17 @@ static void rspi_receive_init(const struct rspi_data *rspi) spsr = rspi_read8(rspi, RSPI_SPSR); if (spsr & SPSR_SPRF) - rspi_read16(rspi, RSPI_SPDR); /* dummy read */ + rspi_read_data(rspi); /* dummy read */ if (spsr & SPSR_OVRF) rspi_write8(rspi, rspi_read8(rspi, RSPI_SPSR) & ~SPSR_OVRF, RSPI_SPSR); } -static int rspi_receive_pio(struct rspi_data *rspi, struct spi_message *mesg, - struct spi_transfer *t) +static void rspi_rz_receive_init(const struct rspi_data *rspi) { - int remain = t->len; - u8 *data; - rspi_receive_init(rspi); - - data = t->rx_buf; - while (remain > 0) { - rspi_write8(rspi, rspi_read8(rspi, RSPI_SPCR) & ~SPCR_TXMD, - RSPI_SPCR); - - if (rspi_wait_for_interrupt(rspi, SPSR_SPTEF, SPCR_SPTIE) < 0) { - dev_err(&rspi->master->dev, - "%s: tx empty timeout\n", __func__); - return -ETIMEDOUT; - } - /* dummy write for generate clock */ - rspi_write16(rspi, DUMMY_DATA, RSPI_SPDR); - - if (rspi_wait_for_interrupt(rspi, SPSR_SPRF, SPCR_SPRIE) < 0) { - dev_err(&rspi->master->dev, - "%s: receive timeout\n", __func__); - return -ETIMEDOUT; - } - /* SPDR allows 16 or 32-bit access only */ - *data = (u8)rspi_read16(rspi, RSPI_SPDR); - - data++; - remain--; - } - - return 0; + rspi_write8(rspi, SPBFCR_TXRST | SPBFCR_RXRST, RSPI_SPBFCR); + rspi_write8(rspi, 0, RSPI_SPBFCR); } static void qspi_receive_init(const struct rspi_data *rspi) @@ -593,51 +580,17 @@ static void qspi_receive_init(const struct rspi_data *rspi) spsr = rspi_read8(rspi, RSPI_SPSR); if (spsr & SPSR_SPRF) - rspi_read8(rspi, RSPI_SPDR); /* dummy read */ + rspi_read_data(rspi); /* dummy read */ rspi_write8(rspi, SPBFCR_TXRST | SPBFCR_RXRST, QSPI_SPBFCR); - rspi_write8(rspi, 0x00, QSPI_SPBFCR); + rspi_write8(rspi, 0, QSPI_SPBFCR); } -static int qspi_receive_pio(struct rspi_data *rspi, struct spi_message *mesg, - struct spi_transfer *t) -{ - int remain = t->len; - u8 *data; - - qspi_receive_init(rspi); - - data = t->rx_buf; - while (remain > 0) { - - if (rspi_wait_for_interrupt(rspi, SPSR_SPTEF, SPCR_SPTIE) < 0) { - dev_err(&rspi->master->dev, - "%s: tx empty timeout\n", __func__); - return -ETIMEDOUT; - } - /* dummy write for generate clock */ - rspi_write8(rspi, DUMMY_DATA, RSPI_SPDR); - - if (rspi_wait_for_interrupt(rspi, SPSR_SPRF, SPCR_SPRIE) < 0) { - dev_err(&rspi->master->dev, - "%s: receive timeout\n", __func__); - return -ETIMEDOUT; - } - /* SPDR allows 8, 16 or 32-bit access */ - *data++ = rspi_read8(rspi, RSPI_SPDR); - remain--; - } - - return 0; -} - -#define receive_pio(spi, mesg, t) spi->ops->receive_pio(spi, mesg, t) - static int rspi_receive_dma(struct rspi_data *rspi, struct spi_transfer *t) { struct scatterlist sg, sg_dummy; void *dummy = NULL, *rx_buf = NULL; struct dma_async_tx_descriptor *desc, *desc_dummy; - unsigned len; + unsigned int len; int ret = 0; if (rspi->dma_width_16bit) { @@ -695,7 +648,9 @@ static int rspi_receive_dma(struct rspi_data *rspi, struct spi_transfer *t) * DMAC needs SPTIE, but if SPTIE is set, this IRQ routine will be * called. So, this driver disables the IRQ while DMA transfer. */ - disable_irq(rspi->irq); + disable_irq(rspi->tx_irq); + if (rspi->rx_irq != rspi->tx_irq) + disable_irq(rspi->rx_irq); rspi_write8(rspi, rspi_read8(rspi, RSPI_SPCR) & ~SPCR_TXMD, RSPI_SPCR); rspi_enable_irq(rspi, SPCR_SPTIE | SPCR_SPRIE); @@ -718,7 +673,9 @@ static int rspi_receive_dma(struct rspi_data *rspi, struct spi_transfer *t) ret = -ETIMEDOUT; rspi_disable_irq(rspi, SPCR_SPTIE | SPCR_SPRIE); - enable_irq(rspi->irq); + enable_irq(rspi->tx_irq); + if (rspi->rx_irq != rspi->tx_irq) + enable_irq(rspi->rx_irq); end: rspi_dma_unmap_sg(&sg, rspi->chan_rx, DMA_FROM_DEVICE); @@ -746,56 +703,175 @@ static int rspi_is_dma(const struct rspi_data *rspi, struct spi_transfer *t) return 0; } -static void rspi_work(struct work_struct *work) +static int rspi_transfer_out_in(struct rspi_data *rspi, + struct spi_transfer *xfer) { - struct rspi_data *rspi = container_of(work, struct rspi_data, ws); - struct spi_message *mesg; - struct spi_transfer *t; - unsigned long flags; - int ret; + int remain = xfer->len, ret; + const u8 *tx_buf = xfer->tx_buf; + u8 *rx_buf = xfer->rx_buf; + u8 spcr, data; - while (1) { - spin_lock_irqsave(&rspi->lock, flags); - if (list_empty(&rspi->queue)) { - spin_unlock_irqrestore(&rspi->lock, flags); - break; - } - mesg = list_entry(rspi->queue.next, struct spi_message, queue); - list_del_init(&mesg->queue); - spin_unlock_irqrestore(&rspi->lock, flags); - - rspi_assert_ssl(rspi); - - list_for_each_entry(t, &mesg->transfers, transfer_list) { - if (t->tx_buf) { - if (rspi_is_dma(rspi, t)) - ret = rspi_send_dma(rspi, t); - else - ret = send_pio(rspi, mesg, t); - if (ret < 0) - goto error; - } - if (t->rx_buf) { - if (rspi_is_dma(rspi, t)) - ret = rspi_receive_dma(rspi, t); - else - ret = receive_pio(rspi, mesg, t); - if (ret < 0) - goto error; - } - mesg->actual_length += t->len; + rspi_receive_init(rspi); + + spcr = rspi_read8(rspi, RSPI_SPCR); + if (rx_buf) + spcr &= ~SPCR_TXMD; + else + spcr |= SPCR_TXMD; + rspi_write8(rspi, spcr, RSPI_SPCR); + + while (remain > 0) { + data = tx_buf ? *tx_buf++ : DUMMY_DATA; + ret = rspi_data_out(rspi, data); + if (ret < 0) + return ret; + if (rx_buf) { + ret = rspi_data_in(rspi); + if (ret < 0) + return ret; + *rx_buf++ = ret; } - rspi_negate_ssl(rspi); + remain--; + } + + /* Wait for the last transmission */ + rspi_wait_for_interrupt(rspi, SPSR_SPTEF, SPCR_SPTIE); + + return 0; +} + +static int rspi_transfer_one(struct spi_master *master, struct spi_device *spi, + struct spi_transfer *xfer) +{ + struct rspi_data *rspi = spi_master_get_devdata(master); + int ret; + + if (!rspi_is_dma(rspi, xfer)) + return rspi_transfer_out_in(rspi, xfer); + + if (xfer->tx_buf) { + ret = rspi_send_dma(rspi, xfer); + if (ret < 0) + return ret; + } + if (xfer->rx_buf) + return rspi_receive_dma(rspi, xfer); + + return 0; +} + +static int rspi_rz_transfer_out_in(struct rspi_data *rspi, + struct spi_transfer *xfer) +{ + int remain = xfer->len, ret; + const u8 *tx_buf = xfer->tx_buf; + u8 *rx_buf = xfer->rx_buf; + u8 data; + + rspi_rz_receive_init(rspi); + + while (remain > 0) { + data = tx_buf ? *tx_buf++ : DUMMY_DATA; + ret = rspi_data_out_in(rspi, data); + if (ret < 0) + return ret; + if (rx_buf) + *rx_buf++ = ret; + remain--; + } + + /* Wait for the last transmission */ + rspi_wait_for_interrupt(rspi, SPSR_SPTEF, SPCR_SPTIE); + + return 0; +} + +static int rspi_rz_transfer_one(struct spi_master *master, + struct spi_device *spi, + struct spi_transfer *xfer) +{ + struct rspi_data *rspi = spi_master_get_devdata(master); + + return rspi_rz_transfer_out_in(rspi, xfer); +} + +static int qspi_transfer_out_in(struct rspi_data *rspi, + struct spi_transfer *xfer) +{ + int remain = xfer->len, ret; + const u8 *tx_buf = xfer->tx_buf; + u8 *rx_buf = xfer->rx_buf; + u8 data; - mesg->status = 0; - mesg->complete(mesg->context); + qspi_receive_init(rspi); + + while (remain > 0) { + data = tx_buf ? *tx_buf++ : DUMMY_DATA; + ret = rspi_data_out_in(rspi, data); + if (ret < 0) + return ret; + if (rx_buf) + *rx_buf++ = ret; + remain--; + } + + /* Wait for the last transmission */ + rspi_wait_for_interrupt(rspi, SPSR_SPTEF, SPCR_SPTIE); + + return 0; +} + +static int qspi_transfer_out(struct rspi_data *rspi, struct spi_transfer *xfer) +{ + const u8 *buf = xfer->tx_buf; + unsigned int i; + int ret; + + for (i = 0; i < xfer->len; i++) { + ret = rspi_data_out(rspi, *buf++); + if (ret < 0) + return ret; } - return; + /* Wait for the last transmission */ + rspi_wait_for_interrupt(rspi, SPSR_SPTEF, SPCR_SPTIE); -error: - mesg->status = ret; - mesg->complete(mesg->context); + return 0; +} + +static int qspi_transfer_in(struct rspi_data *rspi, struct spi_transfer *xfer) +{ + u8 *buf = xfer->rx_buf; + unsigned int i; + int ret; + + for (i = 0; i < xfer->len; i++) { + ret = rspi_data_in(rspi); + if (ret < 0) + return ret; + *buf++ = ret; + } + + return 0; +} + +static int qspi_transfer_one(struct spi_master *master, struct spi_device *spi, + struct spi_transfer *xfer) +{ + struct rspi_data *rspi = spi_master_get_devdata(master); + + if (spi->mode & SPI_LOOP) { + return qspi_transfer_out_in(rspi, xfer); + } else if (xfer->tx_buf && xfer->tx_nbits > SPI_NBITS_SINGLE) { + /* Quad or Dual SPI Write */ + return qspi_transfer_out(rspi, xfer); + } else if (xfer->rx_buf && xfer->rx_nbits > SPI_NBITS_SINGLE) { + /* Quad or Dual SPI Read */ + return qspi_transfer_in(rspi, xfer); + } else { + /* Single SPI Transfer */ + return qspi_transfer_out_in(rspi, xfer); + } } static int rspi_setup(struct spi_device *spi) @@ -810,32 +886,115 @@ static int rspi_setup(struct spi_device *spi) if (spi->mode & SPI_CPHA) rspi->spcmd |= SPCMD_CPHA; + /* CMOS output mode and MOSI signal from previous transfer */ + rspi->sppcr = 0; + if (spi->mode & SPI_LOOP) + rspi->sppcr |= SPPCR_SPLP; + set_config_register(rspi, 8); return 0; } -static int rspi_transfer(struct spi_device *spi, struct spi_message *mesg) +static u16 qspi_transfer_mode(const struct spi_transfer *xfer) { - struct rspi_data *rspi = spi_master_get_devdata(spi->master); - unsigned long flags; + if (xfer->tx_buf) + switch (xfer->tx_nbits) { + case SPI_NBITS_QUAD: + return SPCMD_SPIMOD_QUAD; + case SPI_NBITS_DUAL: + return SPCMD_SPIMOD_DUAL; + default: + return 0; + } + if (xfer->rx_buf) + switch (xfer->rx_nbits) { + case SPI_NBITS_QUAD: + return SPCMD_SPIMOD_QUAD | SPCMD_SPRW; + case SPI_NBITS_DUAL: + return SPCMD_SPIMOD_DUAL | SPCMD_SPRW; + default: + return 0; + } + + return 0; +} - mesg->actual_length = 0; - mesg->status = -EINPROGRESS; +static int qspi_setup_sequencer(struct rspi_data *rspi, + const struct spi_message *msg) +{ + const struct spi_transfer *xfer; + unsigned int i = 0, len = 0; + u16 current_mode = 0xffff, mode; + + list_for_each_entry(xfer, &msg->transfers, transfer_list) { + mode = qspi_transfer_mode(xfer); + if (mode == current_mode) { + len += xfer->len; + continue; + } + + /* Transfer mode change */ + if (i) { + /* Set transfer data length of previous transfer */ + rspi_write32(rspi, len, QSPI_SPBMUL(i - 1)); + } - spin_lock_irqsave(&rspi->lock, flags); - list_add_tail(&mesg->queue, &rspi->queue); - schedule_work(&rspi->ws); - spin_unlock_irqrestore(&rspi->lock, flags); + if (i >= QSPI_NUM_SPCMD) { + dev_err(&msg->spi->dev, + "Too many different transfer modes"); + return -EINVAL; + } + + /* Program transfer mode for this transfer */ + rspi_write16(rspi, rspi->spcmd | mode, RSPI_SPCMD(i)); + current_mode = mode; + len = xfer->len; + i++; + } + if (i) { + /* Set final transfer data length and sequence length */ + rspi_write32(rspi, len, QSPI_SPBMUL(i - 1)); + rspi_write8(rspi, i - 1, RSPI_SPSCR); + } return 0; } -static void rspi_cleanup(struct spi_device *spi) +static int rspi_prepare_message(struct spi_master *master, + struct spi_message *msg) { + struct rspi_data *rspi = spi_master_get_devdata(master); + int ret; + + if (msg->spi->mode & + (SPI_TX_DUAL | SPI_TX_QUAD | SPI_RX_DUAL | SPI_RX_QUAD)) { + /* Setup sequencer for messages with multiple transfer modes */ + ret = qspi_setup_sequencer(rspi, msg); + if (ret < 0) + return ret; + } + + /* Enable SPI function in master mode */ + rspi_write8(rspi, rspi_read8(rspi, RSPI_SPCR) | SPCR_SPE, RSPI_SPCR); + return 0; } -static irqreturn_t rspi_irq(int irq, void *_sr) +static int rspi_unprepare_message(struct spi_master *master, + struct spi_message *msg) +{ + struct rspi_data *rspi = spi_master_get_devdata(master); + + /* Disable SPI function */ + rspi_write8(rspi, rspi_read8(rspi, RSPI_SPCR) & ~SPCR_SPE, RSPI_SPCR); + + /* Reset sequencer for Single SPI Transfers */ + rspi_write16(rspi, rspi->spcmd, RSPI_SPCMD0); + rspi_write8(rspi, 0, RSPI_SPSCR); + return 0; +} + +static irqreturn_t rspi_irq_mux(int irq, void *_sr) { struct rspi_data *rspi = _sr; u8 spsr; @@ -857,6 +1016,36 @@ static irqreturn_t rspi_irq(int irq, void *_sr) return ret; } +static irqreturn_t rspi_irq_rx(int irq, void *_sr) +{ + struct rspi_data *rspi = _sr; + u8 spsr; + + rspi->spsr = spsr = rspi_read8(rspi, RSPI_SPSR); + if (spsr & SPSR_SPRF) { + rspi_disable_irq(rspi, SPCR_SPRIE); + wake_up(&rspi->wait); + return IRQ_HANDLED; + } + + return 0; +} + +static irqreturn_t rspi_irq_tx(int irq, void *_sr) +{ + struct rspi_data *rspi = _sr; + u8 spsr; + + rspi->spsr = spsr = rspi_read8(rspi, RSPI_SPSR); + if (spsr & SPSR_SPTEF) { + rspi_disable_irq(rspi, SPCR_SPTIE); + wake_up(&rspi->wait); + return IRQ_HANDLED; + } + + return 0; +} + static int rspi_request_dma(struct rspi_data *rspi, struct platform_device *pdev) { @@ -923,34 +1112,89 @@ static int rspi_remove(struct platform_device *pdev) struct rspi_data *rspi = platform_get_drvdata(pdev); rspi_release_dma(rspi); - clk_disable(rspi->clk); + pm_runtime_disable(&pdev->dev); return 0; } +static const struct spi_ops rspi_ops = { + .set_config_register = rspi_set_config_register, + .transfer_one = rspi_transfer_one, + .mode_bits = SPI_CPHA | SPI_CPOL | SPI_LOOP, +}; + +static const struct spi_ops rspi_rz_ops = { + .set_config_register = rspi_rz_set_config_register, + .transfer_one = rspi_rz_transfer_one, + .mode_bits = SPI_CPHA | SPI_CPOL | SPI_LOOP, +}; + +static const struct spi_ops qspi_ops = { + .set_config_register = qspi_set_config_register, + .transfer_one = qspi_transfer_one, + .mode_bits = SPI_CPHA | SPI_CPOL | SPI_LOOP | + SPI_TX_DUAL | SPI_TX_QUAD | + SPI_RX_DUAL | SPI_RX_QUAD, +}; + +#ifdef CONFIG_OF +static const struct of_device_id rspi_of_match[] = { + /* RSPI on legacy SH */ + { .compatible = "renesas,rspi", .data = &rspi_ops }, + /* RSPI on RZ/A1H */ + { .compatible = "renesas,rspi-rz", .data = &rspi_rz_ops }, + /* QSPI on R-Car Gen2 */ + { .compatible = "renesas,qspi", .data = &qspi_ops }, + { /* sentinel */ } +}; + +MODULE_DEVICE_TABLE(of, rspi_of_match); + +static int rspi_parse_dt(struct device *dev, struct spi_master *master) +{ + u32 num_cs; + int error; + + /* Parse DT properties */ + error = of_property_read_u32(dev->of_node, "num-cs", &num_cs); + if (error) { + dev_err(dev, "of_property_read_u32 num-cs failed %d\n", error); + return error; + } + + master->num_chipselect = num_cs; + return 0; +} +#else +#define rspi_of_match NULL +static inline int rspi_parse_dt(struct device *dev, struct spi_master *master) +{ + return -EINVAL; +} +#endif /* CONFIG_OF */ + +static int rspi_request_irq(struct device *dev, unsigned int irq, + irq_handler_t handler, const char *suffix, + void *dev_id) +{ + const char *base = dev_name(dev); + size_t len = strlen(base) + strlen(suffix) + 2; + char *name = devm_kzalloc(dev, len, GFP_KERNEL); + if (!name) + return -ENOMEM; + snprintf(name, len, "%s:%s", base, suffix); + return devm_request_irq(dev, irq, handler, 0, name, dev_id); +} + static int rspi_probe(struct platform_device *pdev) { struct resource *res; struct spi_master *master; struct rspi_data *rspi; - int ret, irq; - char clk_name[16]; - const struct rspi_plat_data *rspi_pd = dev_get_platdata(&pdev->dev); + int ret; + const struct of_device_id *of_id; + const struct rspi_plat_data *rspi_pd; const struct spi_ops *ops; - const struct platform_device_id *id_entry = pdev->id_entry; - - ops = (struct spi_ops *)id_entry->driver_data; - /* ops parameter check */ - if (!ops->set_config_register) { - dev_err(&pdev->dev, "there is no set_config_register\n"); - return -ENODEV; - } - - irq = platform_get_irq(pdev, 0); - if (irq < 0) { - dev_err(&pdev->dev, "platform_get_irq error\n"); - return -ENODEV; - } master = spi_alloc_master(&pdev->dev, sizeof(struct rspi_data)); if (master == NULL) { @@ -958,6 +1202,28 @@ static int rspi_probe(struct platform_device *pdev) return -ENOMEM; } + of_id = of_match_device(rspi_of_match, &pdev->dev); + if (of_id) { + ops = of_id->data; + ret = rspi_parse_dt(&pdev->dev, master); + if (ret) + goto error1; + } else { + ops = (struct spi_ops *)pdev->id_entry->driver_data; + rspi_pd = dev_get_platdata(&pdev->dev); + if (rspi_pd && rspi_pd->num_chipselect) + master->num_chipselect = rspi_pd->num_chipselect; + else + master->num_chipselect = 2; /* default */ + }; + + /* ops parameter check */ + if (!ops->set_config_register) { + dev_err(&pdev->dev, "there is no set_config_register\n"); + ret = -ENODEV; + goto error1; + } + rspi = spi_master_get_devdata(master); platform_set_drvdata(pdev, rspi); rspi->ops = ops; @@ -970,39 +1236,61 @@ static int rspi_probe(struct platform_device *pdev) goto error1; } - snprintf(clk_name, sizeof(clk_name), "%s%d", id_entry->name, pdev->id); - rspi->clk = devm_clk_get(&pdev->dev, clk_name); + rspi->clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(rspi->clk)) { dev_err(&pdev->dev, "cannot get clock\n"); ret = PTR_ERR(rspi->clk); goto error1; } - clk_enable(rspi->clk); - INIT_LIST_HEAD(&rspi->queue); - spin_lock_init(&rspi->lock); - INIT_WORK(&rspi->ws, rspi_work); - init_waitqueue_head(&rspi->wait); + pm_runtime_enable(&pdev->dev); - if (rspi_pd && rspi_pd->num_chipselect) - master->num_chipselect = rspi_pd->num_chipselect; - else - master->num_chipselect = 2; /* default */ + init_waitqueue_head(&rspi->wait); master->bus_num = pdev->id; master->setup = rspi_setup; - master->transfer = rspi_transfer; - master->cleanup = rspi_cleanup; - master->mode_bits = SPI_CPHA | SPI_CPOL; + master->auto_runtime_pm = true; + master->transfer_one = ops->transfer_one; + master->prepare_message = rspi_prepare_message; + master->unprepare_message = rspi_unprepare_message; + master->mode_bits = ops->mode_bits; + master->dev.of_node = pdev->dev.of_node; + + ret = platform_get_irq_byname(pdev, "rx"); + if (ret < 0) { + ret = platform_get_irq_byname(pdev, "mux"); + if (ret < 0) + ret = platform_get_irq(pdev, 0); + if (ret >= 0) + rspi->rx_irq = rspi->tx_irq = ret; + } else { + rspi->rx_irq = ret; + ret = platform_get_irq_byname(pdev, "tx"); + if (ret >= 0) + rspi->tx_irq = ret; + } + if (ret < 0) { + dev_err(&pdev->dev, "platform_get_irq error\n"); + goto error2; + } - ret = devm_request_irq(&pdev->dev, irq, rspi_irq, 0, - dev_name(&pdev->dev), rspi); + if (rspi->rx_irq == rspi->tx_irq) { + /* Single multiplexed interrupt */ + ret = rspi_request_irq(&pdev->dev, rspi->rx_irq, rspi_irq_mux, + "mux", rspi); + } else { + /* Multi-interrupt mode, only SPRI and SPTI are used */ + ret = rspi_request_irq(&pdev->dev, rspi->rx_irq, rspi_irq_rx, + "rx", rspi); + if (!ret) + ret = rspi_request_irq(&pdev->dev, rspi->tx_irq, + rspi_irq_tx, "tx", rspi); + } if (ret < 0) { dev_err(&pdev->dev, "request_irq error\n"); goto error2; } - rspi->irq = irq; ret = rspi_request_dma(rspi, pdev); if (ret < 0) { dev_err(&pdev->dev, "rspi_request_dma failed.\n"); @@ -1022,27 +1310,16 @@ static int rspi_probe(struct platform_device *pdev) error3: rspi_release_dma(rspi); error2: - clk_disable(rspi->clk); + pm_runtime_disable(&pdev->dev); error1: spi_master_put(master); return ret; } -static struct spi_ops rspi_ops = { - .set_config_register = rspi_set_config_register, - .send_pio = rspi_send_pio, - .receive_pio = rspi_receive_pio, -}; - -static struct spi_ops qspi_ops = { - .set_config_register = qspi_set_config_register, - .send_pio = qspi_send_pio, - .receive_pio = qspi_receive_pio, -}; - static struct platform_device_id spi_driver_ids[] = { { "rspi", (kernel_ulong_t)&rspi_ops }, + { "rspi-rz", (kernel_ulong_t)&rspi_rz_ops }, { "qspi", (kernel_ulong_t)&qspi_ops }, {}, }; @@ -1056,6 +1333,7 @@ static struct platform_driver rspi_driver = { .driver = { .name = "renesas_spi", .owner = THIS_MODULE, + .of_match_table = of_match_ptr(rspi_of_match), }, }; module_platform_driver(rspi_driver); diff --git a/drivers/spi/spi-s3c24xx.c b/drivers/spi/spi-s3c24xx.c index 746424aa535..bed23384dfa 100644 --- a/drivers/spi/spi-s3c24xx.c +++ b/drivers/spi/spi-s3c24xx.c @@ -9,7 +9,6 @@ * */ -#include <linux/init.h> #include <linux/spinlock.h> #include <linux/workqueue.h> #include <linux/interrupt.h> @@ -123,25 +122,15 @@ static int s3c24xx_spi_update_state(struct spi_device *spi, { struct s3c24xx_spi *hw = to_hw(spi); struct s3c24xx_spi_devstate *cs = spi->controller_state; - unsigned int bpw; unsigned int hz; unsigned int div; unsigned long clk; - bpw = t ? t->bits_per_word : spi->bits_per_word; hz = t ? t->speed_hz : spi->max_speed_hz; - if (!bpw) - bpw = 8; - if (!hz) hz = spi->max_speed_hz; - if (bpw != 8) { - dev_err(&spi->dev, "invalid bits-per-word (%d)\n", bpw); - return -EINVAL; - } - if (spi->mode != cs->mode) { u8 spcon = SPCON_DEFAULT | S3C2410_SPCON_ENSCK; @@ -544,6 +533,7 @@ static int s3c24xx_spi_probe(struct platform_device *pdev) master->num_chipselect = hw->pdata->num_cs; master->bus_num = pdata->bus_num; + master->bits_per_word_mask = SPI_BPW_MASK(8); /* setup the state for the bitbang driver */ @@ -643,6 +633,11 @@ static int s3c24xx_spi_remove(struct platform_device *dev) static int s3c24xx_spi_suspend(struct device *dev) { struct s3c24xx_spi *hw = dev_get_drvdata(dev); + int ret; + + ret = spi_master_suspend(hw->master); + if (ret) + return ret; if (hw->pdata && hw->pdata->gpio_setup) hw->pdata->gpio_setup(hw->pdata, 0); @@ -656,7 +651,7 @@ static int s3c24xx_spi_resume(struct device *dev) struct s3c24xx_spi *hw = dev_get_drvdata(dev); s3c24xx_spi_initialsetup(hw); - return 0; + return spi_master_resume(hw->master); } static const struct dev_pm_ops s3c24xx_spi_pmops = { diff --git a/drivers/spi/spi-s3c64xx.c b/drivers/spi/spi-s3c64xx.c index ae907dde137..f19cd97855e 100644 --- a/drivers/spi/spi-s3c64xx.c +++ b/drivers/spi/spi-s3c64xx.c @@ -34,10 +34,6 @@ #include <linux/platform_data/spi-s3c64xx.h> -#ifdef CONFIG_S3C_DMA -#include <mach/dma.h> -#endif - #define MAX_SPI_PORTS 3 #define S3C64XX_SPI_QUIRK_POLL (1 << 0) @@ -200,9 +196,6 @@ struct s3c64xx_spi_driver_data { unsigned cur_speed; struct s3c64xx_spi_dma_data rx_dma; struct s3c64xx_spi_dma_data tx_dma; -#ifdef CONFIG_S3C_DMA - struct samsung_dma_ops *ops; -#endif struct s3c64xx_spi_port_config *port_conf; unsigned int port_id; bool cs_gpio; @@ -284,104 +277,8 @@ static void s3c64xx_spi_dmacb(void *data) spin_unlock_irqrestore(&sdd->lock, flags); } -#ifdef CONFIG_S3C_DMA -/* FIXME: remove this section once arch/arm/mach-s3c64xx uses dmaengine */ - -static struct s3c2410_dma_client s3c64xx_spi_dma_client = { - .name = "samsung-spi-dma", -}; - -static void prepare_dma(struct s3c64xx_spi_dma_data *dma, - unsigned len, dma_addr_t buf) -{ - struct s3c64xx_spi_driver_data *sdd; - struct samsung_dma_prep info; - struct samsung_dma_config config; - - if (dma->direction == DMA_DEV_TO_MEM) { - sdd = container_of((void *)dma, - struct s3c64xx_spi_driver_data, rx_dma); - config.direction = sdd->rx_dma.direction; - config.fifo = sdd->sfr_start + S3C64XX_SPI_RX_DATA; - config.width = sdd->cur_bpw / 8; - sdd->ops->config((enum dma_ch)sdd->rx_dma.ch, &config); - } else { - sdd = container_of((void *)dma, - struct s3c64xx_spi_driver_data, tx_dma); - config.direction = sdd->tx_dma.direction; - config.fifo = sdd->sfr_start + S3C64XX_SPI_TX_DATA; - config.width = sdd->cur_bpw / 8; - sdd->ops->config((enum dma_ch)sdd->tx_dma.ch, &config); - } - - info.cap = DMA_SLAVE; - info.len = len; - info.fp = s3c64xx_spi_dmacb; - info.fp_param = dma; - info.direction = dma->direction; - info.buf = buf; - - sdd->ops->prepare((enum dma_ch)dma->ch, &info); - sdd->ops->trigger((enum dma_ch)dma->ch); -} - -static int acquire_dma(struct s3c64xx_spi_driver_data *sdd) -{ - struct samsung_dma_req req; - struct device *dev = &sdd->pdev->dev; - - sdd->ops = samsung_dma_get_ops(); - - req.cap = DMA_SLAVE; - req.client = &s3c64xx_spi_dma_client; - - sdd->rx_dma.ch = (struct dma_chan *)(unsigned long)sdd->ops->request( - sdd->rx_dma.dmach, &req, dev, "rx"); - sdd->tx_dma.ch = (struct dma_chan *)(unsigned long)sdd->ops->request( - sdd->tx_dma.dmach, &req, dev, "tx"); - - return 1; -} - -static int s3c64xx_spi_prepare_transfer(struct spi_master *spi) -{ - struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(spi); - - /* - * If DMA resource was not available during - * probe, no need to continue with dma requests - * else Acquire DMA channels - */ - while (!is_polling(sdd) && !acquire_dma(sdd)) - usleep_range(10000, 11000); - - return 0; -} - -static int s3c64xx_spi_unprepare_transfer(struct spi_master *spi) -{ - struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(spi); - - /* Free DMA channels */ - if (!is_polling(sdd)) { - sdd->ops->release((enum dma_ch)sdd->rx_dma.ch, - &s3c64xx_spi_dma_client); - sdd->ops->release((enum dma_ch)sdd->tx_dma.ch, - &s3c64xx_spi_dma_client); - } - - return 0; -} - -static void s3c64xx_spi_dma_stop(struct s3c64xx_spi_driver_data *sdd, - struct s3c64xx_spi_dma_data *dma) -{ - sdd->ops->stop((enum dma_ch)dma->ch); -} -#else - static void prepare_dma(struct s3c64xx_spi_dma_data *dma, - unsigned len, dma_addr_t buf) + struct sg_table *sgt) { struct s3c64xx_spi_driver_data *sdd; struct dma_slave_config config; @@ -407,8 +304,8 @@ static void prepare_dma(struct s3c64xx_spi_dma_data *dma, dmaengine_slave_config(dma->ch, &config); } - desc = dmaengine_prep_slave_single(dma->ch, buf, len, - dma->direction, DMA_PREP_INTERRUPT); + desc = dmaengine_prep_slave_sg(dma->ch, sgt->sgl, sgt->nents, + dma->direction, DMA_PREP_INTERRUPT); desc->callback = s3c64xx_spi_dmacb; desc->callback_param = dma; @@ -437,6 +334,7 @@ static int s3c64xx_spi_prepare_transfer(struct spi_master *spi) ret = -EBUSY; goto out; } + spi->dma_rx = sdd->rx_dma.ch; sdd->tx_dma.ch = dma_request_slave_channel_compat(mask, filter, (void *)sdd->tx_dma.dmach, dev, "tx"); @@ -445,6 +343,7 @@ static int s3c64xx_spi_prepare_transfer(struct spi_master *spi) ret = -EBUSY; goto out_rx; } + spi->dma_tx = sdd->tx_dma.ch; } ret = pm_runtime_get_sync(&sdd->pdev->dev); @@ -477,12 +376,14 @@ static int s3c64xx_spi_unprepare_transfer(struct spi_master *spi) return 0; } -static void s3c64xx_spi_dma_stop(struct s3c64xx_spi_driver_data *sdd, - struct s3c64xx_spi_dma_data *dma) +static bool s3c64xx_spi_can_dma(struct spi_master *master, + struct spi_device *spi, + struct spi_transfer *xfer) { - dmaengine_terminate_all(dma->ch); + struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(master); + + return xfer->len > (FIFO_LVL_MASK(sdd) >> 1) + 1; } -#endif static void enable_datapath(struct s3c64xx_spi_driver_data *sdd, struct spi_device *spi, @@ -515,7 +416,7 @@ static void enable_datapath(struct s3c64xx_spi_driver_data *sdd, chcfg |= S3C64XX_SPI_CH_TXCH_ON; if (dma_mode) { modecfg |= S3C64XX_SPI_MODE_TXDMA_ON; - prepare_dma(&sdd->tx_dma, xfer->len, xfer->tx_dma); + prepare_dma(&sdd->tx_dma, &xfer->tx_sg); } else { switch (sdd->cur_bpw) { case 32: @@ -547,7 +448,7 @@ static void enable_datapath(struct s3c64xx_spi_driver_data *sdd, writel(((xfer->len * 8 / sdd->cur_bpw) & 0xffff) | S3C64XX_SPI_PACKET_CNT_EN, regs + S3C64XX_SPI_PACKET_CNT); - prepare_dma(&sdd->rx_dma, xfer->len, xfer->rx_dma); + prepare_dma(&sdd->rx_dma, &xfer->rx_sg); } } @@ -555,23 +456,6 @@ static void enable_datapath(struct s3c64xx_spi_driver_data *sdd, writel(chcfg, regs + S3C64XX_SPI_CH_CFG); } -static inline void enable_cs(struct s3c64xx_spi_driver_data *sdd, - struct spi_device *spi) -{ - if (sdd->tgl_spi != NULL) { /* If last device toggled after mssg */ - if (sdd->tgl_spi != spi) { /* if last mssg on diff device */ - /* Deselect the last toggled device */ - if (spi->cs_gpio >= 0) - gpio_set_value(spi->cs_gpio, - spi->mode & SPI_CS_HIGH ? 0 : 1); - } - sdd->tgl_spi = NULL; - } - - if (spi->cs_gpio >= 0) - gpio_set_value(spi->cs_gpio, spi->mode & SPI_CS_HIGH ? 1 : 0); -} - static u32 s3c64xx_spi_wait_for_timeout(struct s3c64xx_spi_driver_data *sdd, int timeout_ms) { @@ -593,112 +477,111 @@ static u32 s3c64xx_spi_wait_for_timeout(struct s3c64xx_spi_driver_data *sdd, return RX_FIFO_LVL(status, sdd); } -static int wait_for_xfer(struct s3c64xx_spi_driver_data *sdd, - struct spi_transfer *xfer, int dma_mode) +static int wait_for_dma(struct s3c64xx_spi_driver_data *sdd, + struct spi_transfer *xfer) { void __iomem *regs = sdd->regs; unsigned long val; + u32 status; int ms; /* millisecs to xfer 'len' bytes @ 'cur_speed' */ ms = xfer->len * 8 * 1000 / sdd->cur_speed; ms += 10; /* some tolerance */ - if (dma_mode) { - val = msecs_to_jiffies(ms) + 10; - val = wait_for_completion_timeout(&sdd->xfer_completion, val); - } else { - u32 status; - val = msecs_to_loops(ms); - do { + val = msecs_to_jiffies(ms) + 10; + val = wait_for_completion_timeout(&sdd->xfer_completion, val); + + /* + * If the previous xfer was completed within timeout, then + * proceed further else return -EIO. + * DmaTx returns after simply writing data in the FIFO, + * w/o waiting for real transmission on the bus to finish. + * DmaRx returns only after Dma read data from FIFO which + * needs bus transmission to finish, so we don't worry if + * Xfer involved Rx(with or without Tx). + */ + if (val && !xfer->rx_buf) { + val = msecs_to_loops(10); + status = readl(regs + S3C64XX_SPI_STATUS); + while ((TX_FIFO_LVL(status, sdd) + || !S3C64XX_SPI_ST_TX_DONE(status, sdd)) + && --val) { + cpu_relax(); status = readl(regs + S3C64XX_SPI_STATUS); - } while (RX_FIFO_LVL(status, sdd) < xfer->len && --val); + } + } - if (dma_mode) { - u32 status; - - /* - * If the previous xfer was completed within timeout, then - * proceed further else return -EIO. - * DmaTx returns after simply writing data in the FIFO, - * w/o waiting for real transmission on the bus to finish. - * DmaRx returns only after Dma read data from FIFO which - * needs bus transmission to finish, so we don't worry if - * Xfer involved Rx(with or without Tx). - */ - if (val && !xfer->rx_buf) { - val = msecs_to_loops(10); - status = readl(regs + S3C64XX_SPI_STATUS); - while ((TX_FIFO_LVL(status, sdd) - || !S3C64XX_SPI_ST_TX_DONE(status, sdd)) - && --val) { - cpu_relax(); - status = readl(regs + S3C64XX_SPI_STATUS); - } + /* If timed out while checking rx/tx status return error */ + if (!val) + return -EIO; - } + return 0; +} - /* If timed out while checking rx/tx status return error */ - if (!val) - return -EIO; - } else { - int loops; - u32 cpy_len; - u8 *buf; - - /* If it was only Tx */ - if (!xfer->rx_buf) { - sdd->state &= ~TXBUSY; - return 0; - } +static int wait_for_pio(struct s3c64xx_spi_driver_data *sdd, + struct spi_transfer *xfer) +{ + void __iomem *regs = sdd->regs; + unsigned long val; + u32 status; + int loops; + u32 cpy_len; + u8 *buf; + int ms; - /* - * If the receive length is bigger than the controller fifo - * size, calculate the loops and read the fifo as many times. - * loops = length / max fifo size (calculated by using the - * fifo mask). - * For any size less than the fifo size the below code is - * executed atleast once. - */ - loops = xfer->len / ((FIFO_LVL_MASK(sdd) >> 1) + 1); - buf = xfer->rx_buf; - do { - /* wait for data to be received in the fifo */ - cpy_len = s3c64xx_spi_wait_for_timeout(sdd, - (loops ? ms : 0)); + /* millisecs to xfer 'len' bytes @ 'cur_speed' */ + ms = xfer->len * 8 * 1000 / sdd->cur_speed; + ms += 10; /* some tolerance */ - switch (sdd->cur_bpw) { - case 32: - ioread32_rep(regs + S3C64XX_SPI_RX_DATA, - buf, cpy_len / 4); - break; - case 16: - ioread16_rep(regs + S3C64XX_SPI_RX_DATA, - buf, cpy_len / 2); - break; - default: - ioread8_rep(regs + S3C64XX_SPI_RX_DATA, - buf, cpy_len); - break; - } + val = msecs_to_loops(ms); + do { + status = readl(regs + S3C64XX_SPI_STATUS); + } while (RX_FIFO_LVL(status, sdd) < xfer->len && --val); - buf = buf + cpy_len; - } while (loops--); - sdd->state &= ~RXBUSY; + + /* If it was only Tx */ + if (!xfer->rx_buf) { + sdd->state &= ~TXBUSY; + return 0; } - return 0; -} + /* + * If the receive length is bigger than the controller fifo + * size, calculate the loops and read the fifo as many times. + * loops = length / max fifo size (calculated by using the + * fifo mask). + * For any size less than the fifo size the below code is + * executed atleast once. + */ + loops = xfer->len / ((FIFO_LVL_MASK(sdd) >> 1) + 1); + buf = xfer->rx_buf; + do { + /* wait for data to be received in the fifo */ + cpy_len = s3c64xx_spi_wait_for_timeout(sdd, + (loops ? ms : 0)); + + switch (sdd->cur_bpw) { + case 32: + ioread32_rep(regs + S3C64XX_SPI_RX_DATA, + buf, cpy_len / 4); + break; + case 16: + ioread16_rep(regs + S3C64XX_SPI_RX_DATA, + buf, cpy_len / 2); + break; + default: + ioread8_rep(regs + S3C64XX_SPI_RX_DATA, + buf, cpy_len); + break; + } -static inline void disable_cs(struct s3c64xx_spi_driver_data *sdd, - struct spi_device *spi) -{ - if (sdd->tgl_spi == spi) - sdd->tgl_spi = NULL; + buf = buf + cpy_len; + } while (loops--); + sdd->state &= ~RXBUSY; - if (spi->cs_gpio >= 0) - gpio_set_value(spi->cs_gpio, spi->mode & SPI_CS_HIGH ? 0 : 1); + return 0; } static void s3c64xx_spi_config(struct s3c64xx_spi_driver_data *sdd) @@ -774,81 +657,6 @@ static void s3c64xx_spi_config(struct s3c64xx_spi_driver_data *sdd) #define XFER_DMAADDR_INVALID DMA_BIT_MASK(32) -static int s3c64xx_spi_map_mssg(struct s3c64xx_spi_driver_data *sdd, - struct spi_message *msg) -{ - struct device *dev = &sdd->pdev->dev; - struct spi_transfer *xfer; - - if (is_polling(sdd) || msg->is_dma_mapped) - return 0; - - /* First mark all xfer unmapped */ - list_for_each_entry(xfer, &msg->transfers, transfer_list) { - xfer->rx_dma = XFER_DMAADDR_INVALID; - xfer->tx_dma = XFER_DMAADDR_INVALID; - } - - /* Map until end or first fail */ - list_for_each_entry(xfer, &msg->transfers, transfer_list) { - - if (xfer->len <= ((FIFO_LVL_MASK(sdd) >> 1) + 1)) - continue; - - if (xfer->tx_buf != NULL) { - xfer->tx_dma = dma_map_single(dev, - (void *)xfer->tx_buf, xfer->len, - DMA_TO_DEVICE); - if (dma_mapping_error(dev, xfer->tx_dma)) { - dev_err(dev, "dma_map_single Tx failed\n"); - xfer->tx_dma = XFER_DMAADDR_INVALID; - return -ENOMEM; - } - } - - if (xfer->rx_buf != NULL) { - xfer->rx_dma = dma_map_single(dev, xfer->rx_buf, - xfer->len, DMA_FROM_DEVICE); - if (dma_mapping_error(dev, xfer->rx_dma)) { - dev_err(dev, "dma_map_single Rx failed\n"); - dma_unmap_single(dev, xfer->tx_dma, - xfer->len, DMA_TO_DEVICE); - xfer->tx_dma = XFER_DMAADDR_INVALID; - xfer->rx_dma = XFER_DMAADDR_INVALID; - return -ENOMEM; - } - } - } - - return 0; -} - -static void s3c64xx_spi_unmap_mssg(struct s3c64xx_spi_driver_data *sdd, - struct spi_message *msg) -{ - struct device *dev = &sdd->pdev->dev; - struct spi_transfer *xfer; - - if (is_polling(sdd) || msg->is_dma_mapped) - return; - - list_for_each_entry(xfer, &msg->transfers, transfer_list) { - - if (xfer->len <= ((FIFO_LVL_MASK(sdd) >> 1) + 1)) - continue; - - if (xfer->rx_buf != NULL - && xfer->rx_dma != XFER_DMAADDR_INVALID) - dma_unmap_single(dev, xfer->rx_dma, - xfer->len, DMA_FROM_DEVICE); - - if (xfer->tx_buf != NULL - && xfer->tx_dma != XFER_DMAADDR_INVALID) - dma_unmap_single(dev, xfer->tx_dma, - xfer->len, DMA_TO_DEVICE); - } -} - static int s3c64xx_spi_prepare_message(struct spi_master *master, struct spi_message *msg) { @@ -866,13 +674,6 @@ static int s3c64xx_spi_prepare_message(struct spi_master *master, s3c64xx_spi_config(sdd); } - /* Map all the transfers if needed */ - if (s3c64xx_spi_map_mssg(sdd, msg)) { - dev_err(&spi->dev, - "Xfer: Unable to map message buffers!\n"); - return -ENOMEM; - } - /* Configure feedback delay */ writel(cs->fb_delay & 0x3, sdd->regs + S3C64XX_SPI_FB_CLK); @@ -896,13 +697,6 @@ static int s3c64xx_spi_transfer_one(struct spi_master *master, bpw = xfer->bits_per_word; speed = xfer->speed_hz ? : spi->max_speed_hz; - if (xfer->len % (bpw / 8)) { - dev_err(&spi->dev, - "Xfer length(%u) not a multiple of word size(%u)\n", - xfer->len, bpw / 8); - return -EIO; - } - if (bpw != sdd->cur_bpw || speed != sdd->cur_speed) { sdd->cur_bpw = bpw; sdd->cur_speed = speed; @@ -929,7 +723,10 @@ static int s3c64xx_spi_transfer_one(struct spi_master *master, spin_unlock_irqrestore(&sdd->lock, flags); - status = wait_for_xfer(sdd, xfer, use_dma); + if (use_dma) + status = wait_for_dma(sdd, xfer); + else + status = wait_for_pio(sdd, xfer); if (status) { dev_err(&spi->dev, "I/O Error: rx-%d tx-%d res:rx-%c tx-%c len-%d\n", @@ -941,10 +738,10 @@ static int s3c64xx_spi_transfer_one(struct spi_master *master, if (use_dma) { if (xfer->tx_buf != NULL && (sdd->state & TXBUSY)) - s3c64xx_spi_dma_stop(sdd, &sdd->tx_dma); + dmaengine_terminate_all(sdd->tx_dma.ch); if (xfer->rx_buf != NULL && (sdd->state & RXBUSY)) - s3c64xx_spi_dma_stop(sdd, &sdd->rx_dma); + dmaengine_terminate_all(sdd->rx_dma.ch); } } else { flush_fifo(sdd); @@ -953,16 +750,6 @@ static int s3c64xx_spi_transfer_one(struct spi_master *master, return status; } -static int s3c64xx_spi_unprepare_message(struct spi_master *master, - struct spi_message *msg) -{ - struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(master); - - s3c64xx_spi_unmap_mssg(sdd, msg); - - return 0; -} - static struct s3c64xx_spi_csinfo *s3c64xx_get_slave_ctrldata( struct spi_device *spi) { @@ -1092,14 +879,12 @@ static int s3c64xx_spi_setup(struct spi_device *spi) pm_runtime_put(&sdd->pdev->dev); writel(S3C64XX_SPI_SLAVE_SIG_INACT, sdd->regs + S3C64XX_SPI_SLAVE_SEL); - disable_cs(sdd, spi); return 0; setup_exit: pm_runtime_put(&sdd->pdev->dev); /* setup() returns with device de-selected */ writel(S3C64XX_SPI_SLAVE_SIG_INACT, sdd->regs + S3C64XX_SPI_SLAVE_SEL); - disable_cs(sdd, spi); gpio_free(cs->line); spi_set_ctldata(spi, NULL); @@ -1338,7 +1123,6 @@ static int s3c64xx_spi_probe(struct platform_device *pdev) master->prepare_transfer_hardware = s3c64xx_spi_prepare_transfer; master->prepare_message = s3c64xx_spi_prepare_message; master->transfer_one = s3c64xx_spi_transfer_one; - master->unprepare_message = s3c64xx_spi_unprepare_message; master->unprepare_transfer_hardware = s3c64xx_spi_unprepare_transfer; master->num_chipselect = sci->num_cs; master->dma_alignment = 8; @@ -1347,6 +1131,8 @@ static int s3c64xx_spi_probe(struct platform_device *pdev) /* the spi->mode bits understood by this driver: */ master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH; master->auto_runtime_pm = true; + if (!is_polling(sdd)) + master->can_dma = s3c64xx_spi_can_dma; sdd->regs = devm_ioremap_resource(&pdev->dev, mem_res); if (IS_ERR(sdd->regs)) { diff --git a/drivers/spi/spi-sc18is602.c b/drivers/spi/spi-sc18is602.c index 121c2e1dea3..237f2e7a717 100644 --- a/drivers/spi/spi-sc18is602.c +++ b/drivers/spi/spi-sc18is602.c @@ -183,17 +183,9 @@ static int sc18is602_setup_transfer(struct sc18is602 *hw, u32 hz, u8 mode) static int sc18is602_check_transfer(struct spi_device *spi, struct spi_transfer *t, int tlen) { - uint32_t hz; - if (t && t->len + tlen > SC18IS602_BUFSIZ) return -EINVAL; - hz = spi->max_speed_hz; - if (t && t->speed_hz) - hz = t->speed_hz; - if (hz == 0) - return -EINVAL; - return 0; } @@ -205,22 +197,15 @@ static int sc18is602_transfer_one(struct spi_master *master, struct spi_transfer *t; int status = 0; - /* SC18IS602 does not support CS2 */ - if (hw->id == sc18is602 && spi->chip_select == 2) { - status = -ENXIO; - goto error; - } - hw->tlen = 0; list_for_each_entry(t, &m->transfers, transfer_list) { - u32 hz = t->speed_hz ? : spi->max_speed_hz; bool do_transfer; status = sc18is602_check_transfer(spi, t, hw->tlen); if (status < 0) break; - status = sc18is602_setup_transfer(hw, hz, spi->mode); + status = sc18is602_setup_transfer(hw, t->speed_hz, spi->mode); if (status < 0) break; @@ -238,7 +223,6 @@ static int sc18is602_transfer_one(struct spi_master *master, if (t->delay_usecs) udelay(t->delay_usecs); } -error: m->status = status; spi_finalize_current_message(master); @@ -247,10 +231,13 @@ error: static int sc18is602_setup(struct spi_device *spi) { - if (spi->mode & ~(SPI_CPHA | SPI_CPOL | SPI_LSB_FIRST)) - return -EINVAL; + struct sc18is602 *hw = spi_master_get_devdata(spi->master); - return sc18is602_check_transfer(spi, NULL, 0); + /* SC18IS602 does not support CS2 */ + if (hw->id == sc18is602 && spi->chip_select == 2) + return -ENXIO; + + return 0; } static int sc18is602_probe(struct i2c_client *client, @@ -309,6 +296,8 @@ static int sc18is602_probe(struct i2c_client *client, master->setup = sc18is602_setup; master->transfer_one_message = sc18is602_transfer_one; master->dev.of_node = np; + master->min_speed_hz = hw->freq / 128; + master->max_speed_hz = hw->freq / 4; error = devm_spi_register_master(dev, master); if (error) diff --git a/drivers/spi/spi-sh-hspi.c b/drivers/spi/spi-sh-hspi.c index 82d2f922ffa..9009456bdf4 100644 --- a/drivers/spi/spi-sh-hspi.c +++ b/drivers/spi/spi-sh-hspi.c @@ -46,8 +46,6 @@ /* SPSR */ #define RXFL (1 << 2) -#define hspi2info(h) (h->dev->platform_data) - struct hspi_priv { void __iomem *addr; struct spi_master *master; @@ -113,14 +111,9 @@ static void hspi_hw_setup(struct hspi_priv *hspi, { struct spi_device *spi = msg->spi; struct device *dev = hspi->dev; - u32 target_rate; u32 spcr, idiv_clk; u32 rate, best_rate, min, tmp; - target_rate = t ? t->speed_hz : 0; - if (!target_rate) - target_rate = spi->max_speed_hz; - /* * find best IDIV/CLKCx settings */ @@ -140,7 +133,7 @@ static void hspi_hw_setup(struct hspi_priv *hspi, rate /= (((idiv_clk & 0x1F) + 1) * 2); /* save best settings */ - tmp = abs(target_rate - rate); + tmp = abs(t->speed_hz - rate); if (tmp < min) { min = tmp; spcr = idiv_clk; @@ -153,7 +146,7 @@ static void hspi_hw_setup(struct hspi_priv *hspi, if (spi->mode & SPI_CPOL) spcr |= 1 << 6; - dev_dbg(dev, "speed %d/%d\n", target_rate, best_rate); + dev_dbg(dev, "speed %d/%d\n", t->speed_hz, best_rate); hspi_write(hspi, SPCR, spcr); hspi_write(hspi, SPSR, 0x0); @@ -230,29 +223,6 @@ static int hspi_transfer_one_message(struct spi_master *master, return ret; } -static int hspi_setup(struct spi_device *spi) -{ - struct hspi_priv *hspi = spi_master_get_devdata(spi->master); - struct device *dev = hspi->dev; - - if (8 != spi->bits_per_word) { - dev_err(dev, "bits_per_word should be 8\n"); - return -EIO; - } - - dev_dbg(dev, "%s setup\n", spi->modalias); - - return 0; -} - -static void hspi_cleanup(struct spi_device *spi) -{ - struct hspi_priv *hspi = spi_master_get_devdata(spi->master); - struct device *dev = hspi->dev; - - dev_dbg(dev, "%s cleanup\n", spi->modalias); -} - static int hspi_probe(struct platform_device *pdev) { struct resource *res; @@ -298,22 +268,23 @@ static int hspi_probe(struct platform_device *pdev) pm_runtime_enable(&pdev->dev); - master->num_chipselect = 1; master->bus_num = pdev->id; - master->setup = hspi_setup; - master->cleanup = hspi_cleanup; master->mode_bits = SPI_CPOL | SPI_CPHA; master->dev.of_node = pdev->dev.of_node; master->auto_runtime_pm = true; master->transfer_one_message = hspi_transfer_one_message; + master->bits_per_word_mask = SPI_BPW_MASK(8); + ret = devm_spi_register_master(&pdev->dev, master); if (ret < 0) { dev_err(&pdev->dev, "spi_register_master error.\n"); - goto error1; + goto error2; } return 0; + error2: + pm_runtime_disable(&pdev->dev); error1: clk_put(clk); error0: diff --git a/drivers/spi/spi-sh-msiof.c b/drivers/spi/spi-sh-msiof.c index 81cc02f5f9b..e850d03e719 100644 --- a/drivers/spi/spi-sh-msiof.c +++ b/drivers/spi/spi-sh-msiof.c @@ -15,59 +15,108 @@ #include <linux/delay.h> #include <linux/err.h> #include <linux/gpio.h> -#include <linux/init.h> #include <linux/interrupt.h> #include <linux/io.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/of.h> +#include <linux/of_device.h> #include <linux/platform_device.h> #include <linux/pm_runtime.h> #include <linux/spi/sh_msiof.h> #include <linux/spi/spi.h> -#include <linux/spi/spi_bitbang.h> #include <asm/unaligned.h> + +struct sh_msiof_chipdata { + u16 tx_fifo_size; + u16 rx_fifo_size; + u16 master_flags; +}; + struct sh_msiof_spi_priv { - struct spi_bitbang bitbang; /* must be first for spi_bitbang.c */ void __iomem *mapbase; struct clk *clk; struct platform_device *pdev; + const struct sh_msiof_chipdata *chipdata; struct sh_msiof_spi_info *info; struct completion done; - unsigned long flags; int tx_fifo_size; int rx_fifo_size; }; -#define TMDR1 0x00 -#define TMDR2 0x04 -#define TMDR3 0x08 -#define RMDR1 0x10 -#define RMDR2 0x14 -#define RMDR3 0x18 -#define TSCR 0x20 -#define RSCR 0x22 -#define CTR 0x28 -#define FCTR 0x30 -#define STR 0x40 -#define IER 0x44 -#define TDR1 0x48 -#define TDR2 0x4c -#define TFDR 0x50 -#define RDR1 0x58 -#define RDR2 0x5c -#define RFDR 0x60 - -#define CTR_TSCKE (1 << 15) -#define CTR_TFSE (1 << 14) -#define CTR_TXE (1 << 9) -#define CTR_RXE (1 << 8) - -#define STR_TEOF (1 << 23) -#define STR_REOF (1 << 7) +#define TMDR1 0x00 /* Transmit Mode Register 1 */ +#define TMDR2 0x04 /* Transmit Mode Register 2 */ +#define TMDR3 0x08 /* Transmit Mode Register 3 */ +#define RMDR1 0x10 /* Receive Mode Register 1 */ +#define RMDR2 0x14 /* Receive Mode Register 2 */ +#define RMDR3 0x18 /* Receive Mode Register 3 */ +#define TSCR 0x20 /* Transmit Clock Select Register */ +#define RSCR 0x22 /* Receive Clock Select Register (SH, A1, APE6) */ +#define CTR 0x28 /* Control Register */ +#define FCTR 0x30 /* FIFO Control Register */ +#define STR 0x40 /* Status Register */ +#define IER 0x44 /* Interrupt Enable Register */ +#define TDR1 0x48 /* Transmit Control Data Register 1 (SH, A1) */ +#define TDR2 0x4c /* Transmit Control Data Register 2 (SH, A1) */ +#define TFDR 0x50 /* Transmit FIFO Data Register */ +#define RDR1 0x58 /* Receive Control Data Register 1 (SH, A1) */ +#define RDR2 0x5c /* Receive Control Data Register 2 (SH, A1) */ +#define RFDR 0x60 /* Receive FIFO Data Register */ + +/* TMDR1 and RMDR1 */ +#define MDR1_TRMD 0x80000000 /* Transfer Mode (1 = Master mode) */ +#define MDR1_SYNCMD_MASK 0x30000000 /* SYNC Mode */ +#define MDR1_SYNCMD_SPI 0x20000000 /* Level mode/SPI */ +#define MDR1_SYNCMD_LR 0x30000000 /* L/R mode */ +#define MDR1_SYNCAC_SHIFT 25 /* Sync Polarity (1 = Active-low) */ +#define MDR1_BITLSB_SHIFT 24 /* MSB/LSB First (1 = LSB first) */ +#define MDR1_FLD_MASK 0x000000c0 /* Frame Sync Signal Interval (0-3) */ +#define MDR1_FLD_SHIFT 2 +#define MDR1_XXSTP 0x00000001 /* Transmission/Reception Stop on FIFO */ +/* TMDR1 */ +#define TMDR1_PCON 0x40000000 /* Transfer Signal Connection */ + +/* TMDR2 and RMDR2 */ +#define MDR2_BITLEN1(i) (((i) - 1) << 24) /* Data Size (8-32 bits) */ +#define MDR2_WDLEN1(i) (((i) - 1) << 16) /* Word Count (1-64/256 (SH, A1))) */ +#define MDR2_GRPMASK1 0x00000001 /* Group Output Mask 1 (SH, A1) */ + +/* TSCR and RSCR */ +#define SCR_BRPS_MASK 0x1f00 /* Prescaler Setting (1-32) */ +#define SCR_BRPS(i) (((i) - 1) << 8) +#define SCR_BRDV_MASK 0x0007 /* Baud Rate Generator's Division Ratio */ +#define SCR_BRDV_DIV_2 0x0000 +#define SCR_BRDV_DIV_4 0x0001 +#define SCR_BRDV_DIV_8 0x0002 +#define SCR_BRDV_DIV_16 0x0003 +#define SCR_BRDV_DIV_32 0x0004 +#define SCR_BRDV_DIV_1 0x0007 + +/* CTR */ +#define CTR_TSCKIZ_MASK 0xc0000000 /* Transmit Clock I/O Polarity Select */ +#define CTR_TSCKIZ_SCK 0x80000000 /* Disable SCK when TX disabled */ +#define CTR_TSCKIZ_POL_SHIFT 30 /* Transmit Clock Polarity */ +#define CTR_RSCKIZ_MASK 0x30000000 /* Receive Clock Polarity Select */ +#define CTR_RSCKIZ_SCK 0x20000000 /* Must match CTR_TSCKIZ_SCK */ +#define CTR_RSCKIZ_POL_SHIFT 28 /* Receive Clock Polarity */ +#define CTR_TEDG_SHIFT 27 /* Transmit Timing (1 = falling edge) */ +#define CTR_REDG_SHIFT 26 /* Receive Timing (1 = falling edge) */ +#define CTR_TXDIZ_MASK 0x00c00000 /* Pin Output When TX is Disabled */ +#define CTR_TXDIZ_LOW 0x00000000 /* 0 */ +#define CTR_TXDIZ_HIGH 0x00400000 /* 1 */ +#define CTR_TXDIZ_HIZ 0x00800000 /* High-impedance */ +#define CTR_TSCKE 0x00008000 /* Transmit Serial Clock Output Enable */ +#define CTR_TFSE 0x00004000 /* Transmit Frame Sync Signal Output Enable */ +#define CTR_TXE 0x00000200 /* Transmit Enable */ +#define CTR_RXE 0x00000100 /* Receive Enable */ + +/* STR and IER */ +#define STR_TEOF 0x00800000 /* Frame Transmission End */ +#define STR_REOF 0x00000080 /* Frame Reception End */ + static u32 sh_msiof_read(struct sh_msiof_spi_priv *p, int reg_offs) { @@ -131,22 +180,21 @@ static struct { unsigned short div; unsigned short scr; } const sh_msiof_spi_clk_table[] = { - { 1, 0x0007 }, - { 2, 0x0000 }, - { 4, 0x0001 }, - { 8, 0x0002 }, - { 16, 0x0003 }, - { 32, 0x0004 }, - { 64, 0x1f00 }, - { 128, 0x1f01 }, - { 256, 0x1f02 }, - { 512, 0x1f03 }, - { 1024, 0x1f04 }, + { 1, SCR_BRPS( 1) | SCR_BRDV_DIV_1 }, + { 2, SCR_BRPS( 1) | SCR_BRDV_DIV_2 }, + { 4, SCR_BRPS( 1) | SCR_BRDV_DIV_4 }, + { 8, SCR_BRPS( 1) | SCR_BRDV_DIV_8 }, + { 16, SCR_BRPS( 1) | SCR_BRDV_DIV_16 }, + { 32, SCR_BRPS( 1) | SCR_BRDV_DIV_32 }, + { 64, SCR_BRPS(32) | SCR_BRDV_DIV_2 }, + { 128, SCR_BRPS(32) | SCR_BRDV_DIV_4 }, + { 256, SCR_BRPS(32) | SCR_BRDV_DIV_8 }, + { 512, SCR_BRPS(32) | SCR_BRDV_DIV_16 }, + { 1024, SCR_BRPS(32) | SCR_BRDV_DIV_32 }, }; static void sh_msiof_spi_set_clk_regs(struct sh_msiof_spi_priv *p, - unsigned long parent_rate, - unsigned long spi_hz) + unsigned long parent_rate, u32 spi_hz) { unsigned long div = 1024; size_t k; @@ -164,7 +212,8 @@ static void sh_msiof_spi_set_clk_regs(struct sh_msiof_spi_priv *p, k = min_t(int, k, ARRAY_SIZE(sh_msiof_spi_clk_table) - 1); sh_msiof_write(p, TSCR, sh_msiof_spi_clk_table[k].scr); - sh_msiof_write(p, RSCR, sh_msiof_spi_clk_table[k].scr); + if (!(p->chipdata->master_flags & SPI_MASTER_MUST_TX)) + sh_msiof_write(p, RSCR, sh_msiof_spi_clk_table[k].scr); } static void sh_msiof_spi_set_pin_regs(struct sh_msiof_spi_priv *p, @@ -183,21 +232,25 @@ static void sh_msiof_spi_set_pin_regs(struct sh_msiof_spi_priv *p, */ sh_msiof_write(p, FCTR, 0); - tmp = 0; - tmp |= !cs_high << 25; - tmp |= lsb_first << 24; - sh_msiof_write(p, TMDR1, 0xe0000005 | tmp); - sh_msiof_write(p, RMDR1, 0x20000005 | tmp); + tmp = MDR1_SYNCMD_SPI | 1 << MDR1_FLD_SHIFT | MDR1_XXSTP; + tmp |= !cs_high << MDR1_SYNCAC_SHIFT; + tmp |= lsb_first << MDR1_BITLSB_SHIFT; + sh_msiof_write(p, TMDR1, tmp | MDR1_TRMD | TMDR1_PCON); + if (p->chipdata->master_flags & SPI_MASTER_MUST_TX) { + /* These bits are reserved if RX needs TX */ + tmp &= ~0x0000ffff; + } + sh_msiof_write(p, RMDR1, tmp); - tmp = 0xa0000000; - tmp |= cpol << 30; /* TSCKIZ */ - tmp |= cpol << 28; /* RSCKIZ */ + tmp = 0; + tmp |= CTR_TSCKIZ_SCK | cpol << CTR_TSCKIZ_POL_SHIFT; + tmp |= CTR_RSCKIZ_SCK | cpol << CTR_RSCKIZ_POL_SHIFT; edge = cpol ^ !cpha; - tmp |= edge << 27; /* TEDG */ - tmp |= edge << 26; /* REDG */ - tmp |= (tx_hi_z ? 2 : 0) << 22; /* TXDIZ */ + tmp |= edge << CTR_TEDG_SHIFT; + tmp |= edge << CTR_REDG_SHIFT; + tmp |= tx_hi_z ? CTR_TXDIZ_HIZ : CTR_TXDIZ_LOW; sh_msiof_write(p, CTR, tmp); } @@ -205,12 +258,12 @@ static void sh_msiof_spi_set_mode_regs(struct sh_msiof_spi_priv *p, const void *tx_buf, void *rx_buf, u32 bits, u32 words) { - u32 dr2 = ((bits - 1) << 24) | ((words - 1) << 16); + u32 dr2 = MDR2_BITLEN1(bits) | MDR2_WDLEN1(words); - if (tx_buf) + if (tx_buf || (p->chipdata->master_flags & SPI_MASTER_MUST_TX)) sh_msiof_write(p, TMDR2, dr2); else - sh_msiof_write(p, TMDR2, dr2 | 1); + sh_msiof_write(p, TMDR2, dr2 | MDR2_GRPMASK1); if (rx_buf) sh_msiof_write(p, RMDR2, dr2); @@ -363,77 +416,45 @@ static void sh_msiof_spi_read_fifo_s32u(struct sh_msiof_spi_priv *p, put_unaligned(swab32(sh_msiof_read(p, RFDR) >> fs), &buf_32[k]); } -static int sh_msiof_spi_bits(struct spi_device *spi, struct spi_transfer *t) +static int sh_msiof_spi_setup(struct spi_device *spi) { - int bits; - - bits = t ? t->bits_per_word : 0; - if (!bits) - bits = spi->bits_per_word; - return bits; -} - -static unsigned long sh_msiof_spi_hz(struct spi_device *spi, - struct spi_transfer *t) -{ - unsigned long hz; - - hz = t ? t->speed_hz : 0; - if (!hz) - hz = spi->max_speed_hz; - return hz; -} + struct device_node *np = spi->master->dev.of_node; + struct sh_msiof_spi_priv *p = spi_master_get_devdata(spi->master); -static int sh_msiof_spi_setup_transfer(struct spi_device *spi, - struct spi_transfer *t) -{ - int bits; + if (!np) { + /* + * Use spi->controller_data for CS (same strategy as spi_gpio), + * if any. otherwise let HW control CS + */ + spi->cs_gpio = (uintptr_t)spi->controller_data; + } - /* noting to check hz values against since parent clock is disabled */ + /* Configure pins before deasserting CS */ + sh_msiof_spi_set_pin_regs(p, !!(spi->mode & SPI_CPOL), + !!(spi->mode & SPI_CPHA), + !!(spi->mode & SPI_3WIRE), + !!(spi->mode & SPI_LSB_FIRST), + !!(spi->mode & SPI_CS_HIGH)); - bits = sh_msiof_spi_bits(spi, t); - if (bits < 8) - return -EINVAL; - if (bits > 32) - return -EINVAL; + if (spi->cs_gpio >= 0) + gpio_set_value(spi->cs_gpio, !(spi->mode & SPI_CS_HIGH)); - return spi_bitbang_setup_transfer(spi, t); + return 0; } -static void sh_msiof_spi_chipselect(struct spi_device *spi, int is_on) +static int sh_msiof_prepare_message(struct spi_master *master, + struct spi_message *msg) { - struct sh_msiof_spi_priv *p = spi_master_get_devdata(spi->master); - int value; - - /* chip select is active low unless SPI_CS_HIGH is set */ - if (spi->mode & SPI_CS_HIGH) - value = (is_on == BITBANG_CS_ACTIVE) ? 1 : 0; - else - value = (is_on == BITBANG_CS_ACTIVE) ? 0 : 1; - - if (is_on == BITBANG_CS_ACTIVE) { - if (!test_and_set_bit(0, &p->flags)) { - pm_runtime_get_sync(&p->pdev->dev); - clk_enable(p->clk); - } - - /* Configure pins before asserting CS */ - sh_msiof_spi_set_pin_regs(p, !!(spi->mode & SPI_CPOL), - !!(spi->mode & SPI_CPHA), - !!(spi->mode & SPI_3WIRE), - !!(spi->mode & SPI_LSB_FIRST), - !!(spi->mode & SPI_CS_HIGH)); - } + struct sh_msiof_spi_priv *p = spi_master_get_devdata(master); + const struct spi_device *spi = msg->spi; - /* use spi->controller data for CS (same strategy as spi_gpio) */ - gpio_set_value((uintptr_t)spi->controller_data, value); - - if (is_on == BITBANG_CS_INACTIVE) { - if (test_and_clear_bit(0, &p->flags)) { - clk_disable(p->clk); - pm_runtime_put(&p->pdev->dev); - } - } + /* Configure pins before asserting CS */ + sh_msiof_spi_set_pin_regs(p, !!(spi->mode & SPI_CPOL), + !!(spi->mode & SPI_CPHA), + !!(spi->mode & SPI_3WIRE), + !!(spi->mode & SPI_LSB_FIRST), + !!(spi->mode & SPI_CS_HIGH)); + return 0; } static int sh_msiof_spi_txrx_once(struct sh_msiof_spi_priv *p, @@ -487,7 +508,7 @@ static int sh_msiof_spi_txrx_once(struct sh_msiof_spi_priv *p, /* clear status bits */ sh_msiof_reset_str(p); - /* shut down frame, tx/tx and clock signals */ + /* shut down frame, rx/tx and clock signals */ ret = sh_msiof_modify_ctr_wait(p, CTR_TFSE, 0); ret = ret ? ret : sh_msiof_modify_ctr_wait(p, CTR_TXE, 0); if (rx_buf) @@ -505,9 +526,11 @@ static int sh_msiof_spi_txrx_once(struct sh_msiof_spi_priv *p, return ret; } -static int sh_msiof_spi_txrx(struct spi_device *spi, struct spi_transfer *t) +static int sh_msiof_transfer_one(struct spi_master *master, + struct spi_device *spi, + struct spi_transfer *t) { - struct sh_msiof_spi_priv *p = spi_master_get_devdata(spi->master); + struct sh_msiof_spi_priv *p = spi_master_get_devdata(master); void (*tx_fifo)(struct sh_msiof_spi_priv *, const void *, int, int); void (*rx_fifo)(struct sh_msiof_spi_priv *, void *, int, int); int bits; @@ -517,7 +540,7 @@ static int sh_msiof_spi_txrx(struct spi_device *spi, struct spi_transfer *t) int n; bool swab; - bits = sh_msiof_spi_bits(spi, t); + bits = t->bits_per_word; if (bits <= 8 && t->len > 15 && !(t->len & 3)) { bits = 32; @@ -567,8 +590,7 @@ static int sh_msiof_spi_txrx(struct spi_device *spi, struct spi_transfer *t) } /* setup clocks (clock already enabled in chipselect()) */ - sh_msiof_spi_set_clk_regs(p, clk_get_rate(p->clk), - sh_msiof_spi_hz(spi, t)); + sh_msiof_spi_set_clk_regs(p, clk_get_rate(p->clk), t->speed_hz); /* transfer in fifo sized chunks */ words = t->len / bytes_per_word; @@ -588,22 +610,36 @@ static int sh_msiof_spi_txrx(struct spi_device *spi, struct spi_transfer *t) words -= n; } - return bytes_done; -} - -static u32 sh_msiof_spi_txrx_word(struct spi_device *spi, unsigned nsecs, - u32 word, u8 bits) -{ - BUG(); /* unused but needed by bitbang code */ return 0; } +static const struct sh_msiof_chipdata sh_data = { + .tx_fifo_size = 64, + .rx_fifo_size = 64, + .master_flags = 0, +}; + +static const struct sh_msiof_chipdata r8a779x_data = { + .tx_fifo_size = 64, + .rx_fifo_size = 256, + .master_flags = SPI_MASTER_MUST_TX, +}; + +static const struct of_device_id sh_msiof_match[] = { + { .compatible = "renesas,sh-msiof", .data = &sh_data }, + { .compatible = "renesas,sh-mobile-msiof", .data = &sh_data }, + { .compatible = "renesas,msiof-r8a7790", .data = &r8a779x_data }, + { .compatible = "renesas,msiof-r8a7791", .data = &r8a779x_data }, + {}, +}; +MODULE_DEVICE_TABLE(of, sh_msiof_match); + #ifdef CONFIG_OF static struct sh_msiof_spi_info *sh_msiof_spi_parse_dt(struct device *dev) { struct sh_msiof_spi_info *info; struct device_node *np = dev->of_node; - u32 num_cs = 0; + u32 num_cs = 1; info = devm_kzalloc(dev, sizeof(struct sh_msiof_spi_info), GFP_KERNEL); if (!info) { @@ -633,6 +669,7 @@ static int sh_msiof_spi_probe(struct platform_device *pdev) { struct resource *r; struct spi_master *master; + const struct of_device_id *of_id; struct sh_msiof_spi_priv *p; int i; int ret; @@ -646,10 +683,15 @@ static int sh_msiof_spi_probe(struct platform_device *pdev) p = spi_master_get_devdata(master); platform_set_drvdata(pdev, p); - if (pdev->dev.of_node) + + of_id = of_match_device(sh_msiof_match, &pdev->dev); + if (of_id) { + p->chipdata = of_id->data; p->info = sh_msiof_spi_parse_dt(&pdev->dev); - else + } else { + p->chipdata = (const void *)pdev->id_entry->driver_data; p->info = dev_get_platdata(&pdev->dev); + } if (!p->info) { dev_err(&pdev->dev, "failed to obtain device info\n"); @@ -687,49 +729,40 @@ static int sh_msiof_spi_probe(struct platform_device *pdev) goto err1; } - ret = clk_prepare(p->clk); - if (ret < 0) { - dev_err(&pdev->dev, "unable to prepare clock\n"); - goto err1; - } - p->pdev = pdev; pm_runtime_enable(&pdev->dev); - /* The standard version of MSIOF use 64 word FIFOs */ - p->tx_fifo_size = 64; - p->rx_fifo_size = 64; - /* Platform data may override FIFO sizes */ + p->tx_fifo_size = p->chipdata->tx_fifo_size; + p->rx_fifo_size = p->chipdata->rx_fifo_size; if (p->info->tx_fifo_override) p->tx_fifo_size = p->info->tx_fifo_override; if (p->info->rx_fifo_override) p->rx_fifo_size = p->info->rx_fifo_override; - /* init master and bitbang code */ + /* init master code */ master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH; master->mode_bits |= SPI_LSB_FIRST | SPI_3WIRE; - master->flags = 0; + master->flags = p->chipdata->master_flags; master->bus_num = pdev->id; + master->dev.of_node = pdev->dev.of_node; master->num_chipselect = p->info->num_chipselect; - master->setup = spi_bitbang_setup; - master->cleanup = spi_bitbang_cleanup; - - p->bitbang.master = master; - p->bitbang.chipselect = sh_msiof_spi_chipselect; - p->bitbang.setup_transfer = sh_msiof_spi_setup_transfer; - p->bitbang.txrx_bufs = sh_msiof_spi_txrx; - p->bitbang.txrx_word[SPI_MODE_0] = sh_msiof_spi_txrx_word; - p->bitbang.txrx_word[SPI_MODE_1] = sh_msiof_spi_txrx_word; - p->bitbang.txrx_word[SPI_MODE_2] = sh_msiof_spi_txrx_word; - p->bitbang.txrx_word[SPI_MODE_3] = sh_msiof_spi_txrx_word; - - ret = spi_bitbang_start(&p->bitbang); - if (ret == 0) - return 0; + master->setup = sh_msiof_spi_setup; + master->prepare_message = sh_msiof_prepare_message; + master->bits_per_word_mask = SPI_BPW_RANGE_MASK(8, 32); + master->auto_runtime_pm = true; + master->transfer_one = sh_msiof_transfer_one; + + ret = devm_spi_register_master(&pdev->dev, master); + if (ret < 0) { + dev_err(&pdev->dev, "spi_register_master error.\n"); + goto err2; + } + return 0; + + err2: pm_runtime_disable(&pdev->dev); - clk_unprepare(p->clk); err1: spi_master_put(master); return ret; @@ -737,30 +770,22 @@ static int sh_msiof_spi_probe(struct platform_device *pdev) static int sh_msiof_spi_remove(struct platform_device *pdev) { - struct sh_msiof_spi_priv *p = platform_get_drvdata(pdev); - int ret; - - ret = spi_bitbang_stop(&p->bitbang); - if (!ret) { - pm_runtime_disable(&pdev->dev); - clk_unprepare(p->clk); - spi_master_put(p->bitbang.master); - } - return ret; + pm_runtime_disable(&pdev->dev); + return 0; } -#ifdef CONFIG_OF -static const struct of_device_id sh_msiof_match[] = { - { .compatible = "renesas,sh-msiof", }, - { .compatible = "renesas,sh-mobile-msiof", }, +static struct platform_device_id spi_driver_ids[] = { + { "spi_sh_msiof", (kernel_ulong_t)&sh_data }, + { "spi_r8a7790_msiof", (kernel_ulong_t)&r8a779x_data }, + { "spi_r8a7791_msiof", (kernel_ulong_t)&r8a779x_data }, {}, }; -MODULE_DEVICE_TABLE(of, sh_msiof_match); -#endif +MODULE_DEVICE_TABLE(platform, spi_driver_ids); static struct platform_driver sh_msiof_spi_drv = { .probe = sh_msiof_spi_probe, .remove = sh_msiof_spi_remove, + .id_table = spi_driver_ids, .driver = { .name = "spi_sh_msiof", .owner = THIS_MODULE, diff --git a/drivers/spi/spi-sh-sci.c b/drivers/spi/spi-sh-sci.c index 38eb24df796..8b44b71f502 100644 --- a/drivers/spi/spi-sh-sci.c +++ b/drivers/spi/spi-sh-sci.c @@ -14,7 +14,6 @@ */ #include <linux/kernel.h> -#include <linux/init.h> #include <linux/delay.h> #include <linux/spinlock.h> #include <linux/workqueue.h> @@ -109,7 +108,7 @@ static void sh_sci_spi_chipselect(struct spi_device *dev, int value) { struct sh_sci_spi *sp = spi_master_get_devdata(dev->master); - if (sp->info && sp->info->chip_select) + if (sp->info->chip_select) (sp->info->chip_select)(sp->info, dev->chip_select, value); } @@ -131,6 +130,11 @@ static int sh_sci_spi_probe(struct platform_device *dev) platform_set_drvdata(dev, sp); sp->info = dev_get_platdata(&dev->dev); + if (!sp->info) { + dev_err(&dev->dev, "platform data is missing\n"); + ret = -ENOENT; + goto err1; + } /* setup spi bitbang adaptor */ sp->bitbang.master = master; diff --git a/drivers/spi/spi-sirf.c b/drivers/spi/spi-sirf.c index e430689c383..1a77ad52812 100644 --- a/drivers/spi/spi-sirf.c +++ b/drivers/spi/spi-sirf.c @@ -22,7 +22,6 @@ #include <linux/dmaengine.h> #include <linux/dma-direction.h> #include <linux/dma-mapping.h> -#include <linux/sirfsoc_dma.h> #define DRIVER_NAME "sirfsoc_spi" @@ -132,6 +131,8 @@ #define IS_DMA_VALID(x) (x && ALIGNED(x->tx_buf) && ALIGNED(x->rx_buf) && \ ALIGNED(x->len) && (x->len < 2 * PAGE_SIZE)) +#define SIRFSOC_MAX_CMD_BYTES 4 + struct sirfsoc_spi { struct spi_bitbang bitbang; struct completion rx_done; @@ -162,6 +163,12 @@ struct sirfsoc_spi { void *dummypage; int word_width; /* in bytes */ + /* + * if tx size is not more than 4 and rx size is NULL, use + * command model + */ + bool tx_by_cmd; + int chipselect[0]; }; @@ -260,6 +267,12 @@ static irqreturn_t spi_sirfsoc_irq(int irq, void *dev_id) writel(spi_stat, sspi->base + SIRFSOC_SPI_INT_STATUS); + if (sspi->tx_by_cmd && (spi_stat & SIRFSOC_SPI_FRM_END)) { + complete(&sspi->tx_done); + writel(0x0, sspi->base + SIRFSOC_SPI_INT_EN); + return IRQ_HANDLED; + } + /* Error Conditions */ if (spi_stat & SIRFSOC_SPI_RX_OFLOW || spi_stat & SIRFSOC_SPI_TX_UFLOW) { @@ -310,6 +323,34 @@ static int spi_sirfsoc_transfer(struct spi_device *spi, struct spi_transfer *t) writel(SIRFSOC_SPI_INT_MASK_ALL, sspi->base + SIRFSOC_SPI_INT_STATUS); + /* + * fill tx_buf into command register and wait for its completion + */ + if (sspi->tx_by_cmd) { + u32 cmd; + memcpy(&cmd, sspi->tx, t->len); + + if (sspi->word_width == 1 && !(spi->mode & SPI_LSB_FIRST)) + cmd = cpu_to_be32(cmd) >> + ((SIRFSOC_MAX_CMD_BYTES - t->len) * 8); + if (sspi->word_width == 2 && t->len == 4 && + (!(spi->mode & SPI_LSB_FIRST))) + cmd = ((cmd & 0xffff) << 16) | (cmd >> 16); + + writel(cmd, sspi->base + SIRFSOC_SPI_CMD); + writel(SIRFSOC_SPI_FRM_END_INT_EN, + sspi->base + SIRFSOC_SPI_INT_EN); + writel(SIRFSOC_SPI_CMD_TX_EN, + sspi->base + SIRFSOC_SPI_TX_RX_EN); + + if (wait_for_completion_timeout(&sspi->tx_done, timeout) == 0) { + dev_err(&spi->dev, "transfer timeout\n"); + return 0; + } + + return t->len; + } + if (sspi->left_tx_word == 1) { writel(readl(sspi->base + SIRFSOC_SPI_CTRL) | SIRFSOC_SPI_ENA_AUTO_CLR, @@ -459,11 +500,6 @@ spi_sirfsoc_setup_transfer(struct spi_device *spi, struct spi_transfer *t) regval |= SIRFSOC_SPI_TRAN_DAT_FORMAT_8; sspi->rx_word = spi_sirfsoc_rx_word_u8; sspi->tx_word = spi_sirfsoc_tx_word_u8; - txfifo_ctrl = SIRFSOC_SPI_FIFO_THD(SIRFSOC_SPI_FIFO_SIZE / 2) | - SIRFSOC_SPI_FIFO_WIDTH_BYTE; - rxfifo_ctrl = SIRFSOC_SPI_FIFO_THD(SIRFSOC_SPI_FIFO_SIZE / 2) | - SIRFSOC_SPI_FIFO_WIDTH_BYTE; - sspi->word_width = 1; break; case 12: case 16: @@ -471,26 +507,22 @@ spi_sirfsoc_setup_transfer(struct spi_device *spi, struct spi_transfer *t) SIRFSOC_SPI_TRAN_DAT_FORMAT_16; sspi->rx_word = spi_sirfsoc_rx_word_u16; sspi->tx_word = spi_sirfsoc_tx_word_u16; - txfifo_ctrl = SIRFSOC_SPI_FIFO_THD(SIRFSOC_SPI_FIFO_SIZE / 2) | - SIRFSOC_SPI_FIFO_WIDTH_WORD; - rxfifo_ctrl = SIRFSOC_SPI_FIFO_THD(SIRFSOC_SPI_FIFO_SIZE / 2) | - SIRFSOC_SPI_FIFO_WIDTH_WORD; - sspi->word_width = 2; break; case 32: regval |= SIRFSOC_SPI_TRAN_DAT_FORMAT_32; sspi->rx_word = spi_sirfsoc_rx_word_u32; sspi->tx_word = spi_sirfsoc_tx_word_u32; - txfifo_ctrl = SIRFSOC_SPI_FIFO_THD(SIRFSOC_SPI_FIFO_SIZE / 2) | - SIRFSOC_SPI_FIFO_WIDTH_DWORD; - rxfifo_ctrl = SIRFSOC_SPI_FIFO_THD(SIRFSOC_SPI_FIFO_SIZE / 2) | - SIRFSOC_SPI_FIFO_WIDTH_DWORD; - sspi->word_width = 4; break; default: BUG(); } + sspi->word_width = DIV_ROUND_UP(bits_per_word, 8); + txfifo_ctrl = SIRFSOC_SPI_FIFO_THD(SIRFSOC_SPI_FIFO_SIZE / 2) | + sspi->word_width; + rxfifo_ctrl = SIRFSOC_SPI_FIFO_THD(SIRFSOC_SPI_FIFO_SIZE / 2) | + sspi->word_width; + if (!(spi->mode & SPI_CS_HIGH)) regval |= SIRFSOC_SPI_CS_IDLE_STAT; if (!(spi->mode & SPI_LSB_FIRST)) @@ -519,6 +551,14 @@ spi_sirfsoc_setup_transfer(struct spi_device *spi, struct spi_transfer *t) writel(txfifo_ctrl, sspi->base + SIRFSOC_SPI_TXFIFO_CTRL); writel(rxfifo_ctrl, sspi->base + SIRFSOC_SPI_RXFIFO_CTRL); + if (t && t->tx_buf && !t->rx_buf && (t->len <= SIRFSOC_MAX_CMD_BYTES)) { + regval |= (SIRFSOC_SPI_CMD_BYTE_NUM((t->len - 1)) | + SIRFSOC_SPI_CMD_MODE); + sspi->tx_by_cmd = true; + } else { + regval &= ~SIRFSOC_SPI_CMD_MODE; + sspi->tx_by_cmd = false; + } writel(regval, sspi->base + SIRFSOC_SPI_CTRL); if (IS_DMA_VALID(t)) { @@ -548,8 +588,6 @@ static int spi_sirfsoc_probe(struct platform_device *pdev) struct spi_master *master; struct resource *mem_res; int num_cs, cs_gpio, irq; - u32 rx_dma_ch, tx_dma_ch; - dma_cap_mask_t dma_cap_mask; int i; int ret; @@ -560,20 +598,6 @@ static int spi_sirfsoc_probe(struct platform_device *pdev) goto err_cs; } - ret = of_property_read_u32(pdev->dev.of_node, - "sirf,spi-dma-rx-channel", &rx_dma_ch); - if (ret < 0) { - dev_err(&pdev->dev, "Unable to get rx dma channel\n"); - goto err_cs; - } - - ret = of_property_read_u32(pdev->dev.of_node, - "sirf,spi-dma-tx-channel", &tx_dma_ch); - if (ret < 0) { - dev_err(&pdev->dev, "Unable to get tx dma channel\n"); - goto err_cs; - } - master = spi_alloc_master(&pdev->dev, sizeof(*sspi) + sizeof(int) * num_cs); if (!master) { dev_err(&pdev->dev, "Unable to allocate SPI master\n"); @@ -637,18 +661,13 @@ static int spi_sirfsoc_probe(struct platform_device *pdev) sspi->bitbang.master->dev.of_node = pdev->dev.of_node; /* request DMA channels */ - dma_cap_zero(dma_cap_mask); - dma_cap_set(DMA_INTERLEAVE, dma_cap_mask); - - sspi->rx_chan = dma_request_channel(dma_cap_mask, (dma_filter_fn)sirfsoc_dma_filter_id, - (void *)rx_dma_ch); + sspi->rx_chan = dma_request_slave_channel(&pdev->dev, "rx"); if (!sspi->rx_chan) { dev_err(&pdev->dev, "can not allocate rx dma channel\n"); ret = -ENODEV; goto free_master; } - sspi->tx_chan = dma_request_channel(dma_cap_mask, (dma_filter_fn)sirfsoc_dma_filter_id, - (void *)tx_dma_ch); + sspi->tx_chan = dma_request_slave_channel(&pdev->dev, "tx"); if (!sspi->tx_chan) { dev_err(&pdev->dev, "can not allocate tx dma channel\n"); ret = -ENODEV; @@ -724,11 +743,16 @@ static int spi_sirfsoc_remove(struct platform_device *pdev) return 0; } -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP static int spi_sirfsoc_suspend(struct device *dev) { struct spi_master *master = dev_get_drvdata(dev); struct sirfsoc_spi *sspi = spi_master_get_devdata(master); + int ret; + + ret = spi_master_suspend(master); + if (ret) + return ret; clk_disable(sspi->clk); return 0; @@ -745,15 +769,13 @@ static int spi_sirfsoc_resume(struct device *dev) writel(SIRFSOC_SPI_FIFO_START, sspi->base + SIRFSOC_SPI_RXFIFO_OP); writel(SIRFSOC_SPI_FIFO_START, sspi->base + SIRFSOC_SPI_TXFIFO_OP); - return 0; + return spi_master_resume(master); } - -static const struct dev_pm_ops spi_sirfsoc_pm_ops = { - .suspend = spi_sirfsoc_suspend, - .resume = spi_sirfsoc_resume, -}; #endif +static SIMPLE_DEV_PM_OPS(spi_sirfsoc_pm_ops, spi_sirfsoc_suspend, + spi_sirfsoc_resume); + static const struct of_device_id spi_sirfsoc_of_match[] = { { .compatible = "sirf,prima2-spi", }, { .compatible = "sirf,marco-spi", }, @@ -765,9 +787,7 @@ static struct platform_driver spi_sirfsoc_driver = { .driver = { .name = DRIVER_NAME, .owner = THIS_MODULE, -#ifdef CONFIG_PM .pm = &spi_sirfsoc_pm_ops, -#endif .of_match_table = spi_sirfsoc_of_match, }, .probe = spi_sirfsoc_probe, diff --git a/drivers/spi/spi-sun4i.c b/drivers/spi/spi-sun4i.c new file mode 100644 index 00000000000..d266a870206 --- /dev/null +++ b/drivers/spi/spi-sun4i.c @@ -0,0 +1,478 @@ +/* + * Copyright (C) 2012 - 2014 Allwinner Tech + * Pan Nan <pannan@allwinnertech.com> + * + * Copyright (C) 2014 Maxime Ripard + * Maxime Ripard <maxime.ripard@free-electrons.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + */ + +#include <linux/clk.h> +#include <linux/delay.h> +#include <linux/device.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/pm_runtime.h> +#include <linux/workqueue.h> + +#include <linux/spi/spi.h> + +#define SUN4I_FIFO_DEPTH 64 + +#define SUN4I_RXDATA_REG 0x00 + +#define SUN4I_TXDATA_REG 0x04 + +#define SUN4I_CTL_REG 0x08 +#define SUN4I_CTL_ENABLE BIT(0) +#define SUN4I_CTL_MASTER BIT(1) +#define SUN4I_CTL_CPHA BIT(2) +#define SUN4I_CTL_CPOL BIT(3) +#define SUN4I_CTL_CS_ACTIVE_LOW BIT(4) +#define SUN4I_CTL_LMTF BIT(6) +#define SUN4I_CTL_TF_RST BIT(8) +#define SUN4I_CTL_RF_RST BIT(9) +#define SUN4I_CTL_XCH BIT(10) +#define SUN4I_CTL_CS_MASK 0x3000 +#define SUN4I_CTL_CS(cs) (((cs) << 12) & SUN4I_CTL_CS_MASK) +#define SUN4I_CTL_DHB BIT(15) +#define SUN4I_CTL_CS_MANUAL BIT(16) +#define SUN4I_CTL_CS_LEVEL BIT(17) +#define SUN4I_CTL_TP BIT(18) + +#define SUN4I_INT_CTL_REG 0x0c +#define SUN4I_INT_CTL_TC BIT(16) + +#define SUN4I_INT_STA_REG 0x10 + +#define SUN4I_DMA_CTL_REG 0x14 + +#define SUN4I_WAIT_REG 0x18 + +#define SUN4I_CLK_CTL_REG 0x1c +#define SUN4I_CLK_CTL_CDR2_MASK 0xff +#define SUN4I_CLK_CTL_CDR2(div) ((div) & SUN4I_CLK_CTL_CDR2_MASK) +#define SUN4I_CLK_CTL_CDR1_MASK 0xf +#define SUN4I_CLK_CTL_CDR1(div) (((div) & SUN4I_CLK_CTL_CDR1_MASK) << 8) +#define SUN4I_CLK_CTL_DRS BIT(12) + +#define SUN4I_BURST_CNT_REG 0x20 +#define SUN4I_BURST_CNT(cnt) ((cnt) & 0xffffff) + +#define SUN4I_XMIT_CNT_REG 0x24 +#define SUN4I_XMIT_CNT(cnt) ((cnt) & 0xffffff) + +#define SUN4I_FIFO_STA_REG 0x28 +#define SUN4I_FIFO_STA_RF_CNT_MASK 0x7f +#define SUN4I_FIFO_STA_RF_CNT_BITS 0 +#define SUN4I_FIFO_STA_TF_CNT_MASK 0x7f +#define SUN4I_FIFO_STA_TF_CNT_BITS 16 + +struct sun4i_spi { + struct spi_master *master; + void __iomem *base_addr; + struct clk *hclk; + struct clk *mclk; + + struct completion done; + + const u8 *tx_buf; + u8 *rx_buf; + int len; +}; + +static inline u32 sun4i_spi_read(struct sun4i_spi *sspi, u32 reg) +{ + return readl(sspi->base_addr + reg); +} + +static inline void sun4i_spi_write(struct sun4i_spi *sspi, u32 reg, u32 value) +{ + writel(value, sspi->base_addr + reg); +} + +static inline void sun4i_spi_drain_fifo(struct sun4i_spi *sspi, int len) +{ + u32 reg, cnt; + u8 byte; + + /* See how much data is available */ + reg = sun4i_spi_read(sspi, SUN4I_FIFO_STA_REG); + reg &= SUN4I_FIFO_STA_RF_CNT_MASK; + cnt = reg >> SUN4I_FIFO_STA_RF_CNT_BITS; + + if (len > cnt) + len = cnt; + + while (len--) { + byte = readb(sspi->base_addr + SUN4I_RXDATA_REG); + if (sspi->rx_buf) + *sspi->rx_buf++ = byte; + } +} + +static inline void sun4i_spi_fill_fifo(struct sun4i_spi *sspi, int len) +{ + u8 byte; + + if (len > sspi->len) + len = sspi->len; + + while (len--) { + byte = sspi->tx_buf ? *sspi->tx_buf++ : 0; + writeb(byte, sspi->base_addr + SUN4I_TXDATA_REG); + sspi->len--; + } +} + +static void sun4i_spi_set_cs(struct spi_device *spi, bool enable) +{ + struct sun4i_spi *sspi = spi_master_get_devdata(spi->master); + u32 reg; + + reg = sun4i_spi_read(sspi, SUN4I_CTL_REG); + + reg &= ~SUN4I_CTL_CS_MASK; + reg |= SUN4I_CTL_CS(spi->chip_select); + + if (enable) + reg |= SUN4I_CTL_CS_LEVEL; + else + reg &= ~SUN4I_CTL_CS_LEVEL; + + /* + * Even though this looks irrelevant since we are supposed to + * be controlling the chip select manually, this bit also + * controls the levels of the chip select for inactive + * devices. + * + * If we don't set it, the chip select level will go low by + * default when the device is idle, which is not really + * expected in the common case where the chip select is active + * low. + */ + if (spi->mode & SPI_CS_HIGH) + reg &= ~SUN4I_CTL_CS_ACTIVE_LOW; + else + reg |= SUN4I_CTL_CS_ACTIVE_LOW; + + sun4i_spi_write(sspi, SUN4I_CTL_REG, reg); +} + +static int sun4i_spi_transfer_one(struct spi_master *master, + struct spi_device *spi, + struct spi_transfer *tfr) +{ + struct sun4i_spi *sspi = spi_master_get_devdata(master); + unsigned int mclk_rate, div, timeout; + unsigned int tx_len = 0; + int ret = 0; + u32 reg; + + /* We don't support transfer larger than the FIFO */ + if (tfr->len > SUN4I_FIFO_DEPTH) + return -EINVAL; + + reinit_completion(&sspi->done); + sspi->tx_buf = tfr->tx_buf; + sspi->rx_buf = tfr->rx_buf; + sspi->len = tfr->len; + + /* Clear pending interrupts */ + sun4i_spi_write(sspi, SUN4I_INT_STA_REG, ~0); + + + reg = sun4i_spi_read(sspi, SUN4I_CTL_REG); + + /* Reset FIFOs */ + sun4i_spi_write(sspi, SUN4I_CTL_REG, + reg | SUN4I_CTL_RF_RST | SUN4I_CTL_TF_RST); + + /* + * Setup the transfer control register: Chip Select, + * polarities, etc. + */ + if (spi->mode & SPI_CPOL) + reg |= SUN4I_CTL_CPOL; + else + reg &= ~SUN4I_CTL_CPOL; + + if (spi->mode & SPI_CPHA) + reg |= SUN4I_CTL_CPHA; + else + reg &= ~SUN4I_CTL_CPHA; + + if (spi->mode & SPI_LSB_FIRST) + reg |= SUN4I_CTL_LMTF; + else + reg &= ~SUN4I_CTL_LMTF; + + + /* + * If it's a TX only transfer, we don't want to fill the RX + * FIFO with bogus data + */ + if (sspi->rx_buf) + reg &= ~SUN4I_CTL_DHB; + else + reg |= SUN4I_CTL_DHB; + + /* We want to control the chip select manually */ + reg |= SUN4I_CTL_CS_MANUAL; + + sun4i_spi_write(sspi, SUN4I_CTL_REG, reg); + + /* Ensure that we have a parent clock fast enough */ + mclk_rate = clk_get_rate(sspi->mclk); + if (mclk_rate < (2 * spi->max_speed_hz)) { + clk_set_rate(sspi->mclk, 2 * spi->max_speed_hz); + mclk_rate = clk_get_rate(sspi->mclk); + } + + /* + * Setup clock divider. + * + * We have two choices there. Either we can use the clock + * divide rate 1, which is calculated thanks to this formula: + * SPI_CLK = MOD_CLK / (2 ^ (cdr + 1)) + * Or we can use CDR2, which is calculated with the formula: + * SPI_CLK = MOD_CLK / (2 * (cdr + 1)) + * Wether we use the former or the latter is set through the + * DRS bit. + * + * First try CDR2, and if we can't reach the expected + * frequency, fall back to CDR1. + */ + div = mclk_rate / (2 * spi->max_speed_hz); + if (div <= (SUN4I_CLK_CTL_CDR2_MASK + 1)) { + if (div > 0) + div--; + + reg = SUN4I_CLK_CTL_CDR2(div) | SUN4I_CLK_CTL_DRS; + } else { + div = ilog2(mclk_rate) - ilog2(spi->max_speed_hz); + reg = SUN4I_CLK_CTL_CDR1(div); + } + + sun4i_spi_write(sspi, SUN4I_CLK_CTL_REG, reg); + + /* Setup the transfer now... */ + if (sspi->tx_buf) + tx_len = tfr->len; + + /* Setup the counters */ + sun4i_spi_write(sspi, SUN4I_BURST_CNT_REG, SUN4I_BURST_CNT(tfr->len)); + sun4i_spi_write(sspi, SUN4I_XMIT_CNT_REG, SUN4I_XMIT_CNT(tx_len)); + + /* Fill the TX FIFO */ + sun4i_spi_fill_fifo(sspi, SUN4I_FIFO_DEPTH); + + /* Enable the interrupts */ + sun4i_spi_write(sspi, SUN4I_INT_CTL_REG, SUN4I_INT_CTL_TC); + + /* Start the transfer */ + reg = sun4i_spi_read(sspi, SUN4I_CTL_REG); + sun4i_spi_write(sspi, SUN4I_CTL_REG, reg | SUN4I_CTL_XCH); + + timeout = wait_for_completion_timeout(&sspi->done, + msecs_to_jiffies(1000)); + if (!timeout) { + ret = -ETIMEDOUT; + goto out; + } + + sun4i_spi_drain_fifo(sspi, SUN4I_FIFO_DEPTH); + +out: + sun4i_spi_write(sspi, SUN4I_INT_CTL_REG, 0); + + return ret; +} + +static irqreturn_t sun4i_spi_handler(int irq, void *dev_id) +{ + struct sun4i_spi *sspi = dev_id; + u32 status = sun4i_spi_read(sspi, SUN4I_INT_STA_REG); + + /* Transfer complete */ + if (status & SUN4I_INT_CTL_TC) { + sun4i_spi_write(sspi, SUN4I_INT_STA_REG, SUN4I_INT_CTL_TC); + complete(&sspi->done); + return IRQ_HANDLED; + } + + return IRQ_NONE; +} + +static int sun4i_spi_runtime_resume(struct device *dev) +{ + struct spi_master *master = dev_get_drvdata(dev); + struct sun4i_spi *sspi = spi_master_get_devdata(master); + int ret; + + ret = clk_prepare_enable(sspi->hclk); + if (ret) { + dev_err(dev, "Couldn't enable AHB clock\n"); + goto out; + } + + ret = clk_prepare_enable(sspi->mclk); + if (ret) { + dev_err(dev, "Couldn't enable module clock\n"); + goto err; + } + + sun4i_spi_write(sspi, SUN4I_CTL_REG, + SUN4I_CTL_ENABLE | SUN4I_CTL_MASTER | SUN4I_CTL_TP); + + return 0; + +err: + clk_disable_unprepare(sspi->hclk); +out: + return ret; +} + +static int sun4i_spi_runtime_suspend(struct device *dev) +{ + struct spi_master *master = dev_get_drvdata(dev); + struct sun4i_spi *sspi = spi_master_get_devdata(master); + + clk_disable_unprepare(sspi->mclk); + clk_disable_unprepare(sspi->hclk); + + return 0; +} + +static int sun4i_spi_probe(struct platform_device *pdev) +{ + struct spi_master *master; + struct sun4i_spi *sspi; + struct resource *res; + int ret = 0, irq; + + master = spi_alloc_master(&pdev->dev, sizeof(struct sun4i_spi)); + if (!master) { + dev_err(&pdev->dev, "Unable to allocate SPI Master\n"); + return -ENOMEM; + } + + platform_set_drvdata(pdev, master); + sspi = spi_master_get_devdata(master); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + sspi->base_addr = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(sspi->base_addr)) { + ret = PTR_ERR(sspi->base_addr); + goto err_free_master; + } + + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + dev_err(&pdev->dev, "No spi IRQ specified\n"); + ret = -ENXIO; + goto err_free_master; + } + + ret = devm_request_irq(&pdev->dev, irq, sun4i_spi_handler, + 0, "sun4i-spi", sspi); + if (ret) { + dev_err(&pdev->dev, "Cannot request IRQ\n"); + goto err_free_master; + } + + sspi->master = master; + master->set_cs = sun4i_spi_set_cs; + master->transfer_one = sun4i_spi_transfer_one; + master->num_chipselect = 4; + master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LSB_FIRST; + master->bits_per_word_mask = SPI_BPW_MASK(8); + master->dev.of_node = pdev->dev.of_node; + master->auto_runtime_pm = true; + + sspi->hclk = devm_clk_get(&pdev->dev, "ahb"); + if (IS_ERR(sspi->hclk)) { + dev_err(&pdev->dev, "Unable to acquire AHB clock\n"); + ret = PTR_ERR(sspi->hclk); + goto err_free_master; + } + + sspi->mclk = devm_clk_get(&pdev->dev, "mod"); + if (IS_ERR(sspi->mclk)) { + dev_err(&pdev->dev, "Unable to acquire module clock\n"); + ret = PTR_ERR(sspi->mclk); + goto err_free_master; + } + + init_completion(&sspi->done); + + /* + * This wake-up/shutdown pattern is to be able to have the + * device woken up, even if runtime_pm is disabled + */ + ret = sun4i_spi_runtime_resume(&pdev->dev); + if (ret) { + dev_err(&pdev->dev, "Couldn't resume the device\n"); + goto err_free_master; + } + + pm_runtime_set_active(&pdev->dev); + pm_runtime_enable(&pdev->dev); + pm_runtime_idle(&pdev->dev); + + ret = devm_spi_register_master(&pdev->dev, master); + if (ret) { + dev_err(&pdev->dev, "cannot register SPI master\n"); + goto err_pm_disable; + } + + return 0; + +err_pm_disable: + pm_runtime_disable(&pdev->dev); + sun4i_spi_runtime_suspend(&pdev->dev); +err_free_master: + spi_master_put(master); + return ret; +} + +static int sun4i_spi_remove(struct platform_device *pdev) +{ + pm_runtime_disable(&pdev->dev); + + return 0; +} + +static const struct of_device_id sun4i_spi_match[] = { + { .compatible = "allwinner,sun4i-a10-spi", }, + {} +}; +MODULE_DEVICE_TABLE(of, sun4i_spi_match); + +static const struct dev_pm_ops sun4i_spi_pm_ops = { + .runtime_resume = sun4i_spi_runtime_resume, + .runtime_suspend = sun4i_spi_runtime_suspend, +}; + +static struct platform_driver sun4i_spi_driver = { + .probe = sun4i_spi_probe, + .remove = sun4i_spi_remove, + .driver = { + .name = "sun4i-spi", + .owner = THIS_MODULE, + .of_match_table = sun4i_spi_match, + .pm = &sun4i_spi_pm_ops, + }, +}; +module_platform_driver(sun4i_spi_driver); + +MODULE_AUTHOR("Pan Nan <pannan@allwinnertech.com>"); +MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com>"); +MODULE_DESCRIPTION("Allwinner A1X/A20 SPI controller driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/spi/spi-sun6i.c b/drivers/spi/spi-sun6i.c new file mode 100644 index 00000000000..b3e3498a7e6 --- /dev/null +++ b/drivers/spi/spi-sun6i.c @@ -0,0 +1,484 @@ +/* + * Copyright (C) 2012 - 2014 Allwinner Tech + * Pan Nan <pannan@allwinnertech.com> + * + * Copyright (C) 2014 Maxime Ripard + * Maxime Ripard <maxime.ripard@free-electrons.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + */ + +#include <linux/clk.h> +#include <linux/delay.h> +#include <linux/device.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/pm_runtime.h> +#include <linux/reset.h> +#include <linux/workqueue.h> + +#include <linux/spi/spi.h> + +#define SUN6I_FIFO_DEPTH 128 + +#define SUN6I_GBL_CTL_REG 0x04 +#define SUN6I_GBL_CTL_BUS_ENABLE BIT(0) +#define SUN6I_GBL_CTL_MASTER BIT(1) +#define SUN6I_GBL_CTL_TP BIT(7) +#define SUN6I_GBL_CTL_RST BIT(31) + +#define SUN6I_TFR_CTL_REG 0x08 +#define SUN6I_TFR_CTL_CPHA BIT(0) +#define SUN6I_TFR_CTL_CPOL BIT(1) +#define SUN6I_TFR_CTL_SPOL BIT(2) +#define SUN6I_TFR_CTL_CS_MASK 0x30 +#define SUN6I_TFR_CTL_CS(cs) (((cs) << 4) & SUN6I_TFR_CTL_CS_MASK) +#define SUN6I_TFR_CTL_CS_MANUAL BIT(6) +#define SUN6I_TFR_CTL_CS_LEVEL BIT(7) +#define SUN6I_TFR_CTL_DHB BIT(8) +#define SUN6I_TFR_CTL_FBS BIT(12) +#define SUN6I_TFR_CTL_XCH BIT(31) + +#define SUN6I_INT_CTL_REG 0x10 +#define SUN6I_INT_CTL_RF_OVF BIT(8) +#define SUN6I_INT_CTL_TC BIT(12) + +#define SUN6I_INT_STA_REG 0x14 + +#define SUN6I_FIFO_CTL_REG 0x18 +#define SUN6I_FIFO_CTL_RF_RST BIT(15) +#define SUN6I_FIFO_CTL_TF_RST BIT(31) + +#define SUN6I_FIFO_STA_REG 0x1c +#define SUN6I_FIFO_STA_RF_CNT_MASK 0x7f +#define SUN6I_FIFO_STA_RF_CNT_BITS 0 +#define SUN6I_FIFO_STA_TF_CNT_MASK 0x7f +#define SUN6I_FIFO_STA_TF_CNT_BITS 16 + +#define SUN6I_CLK_CTL_REG 0x24 +#define SUN6I_CLK_CTL_CDR2_MASK 0xff +#define SUN6I_CLK_CTL_CDR2(div) (((div) & SUN6I_CLK_CTL_CDR2_MASK) << 0) +#define SUN6I_CLK_CTL_CDR1_MASK 0xf +#define SUN6I_CLK_CTL_CDR1(div) (((div) & SUN6I_CLK_CTL_CDR1_MASK) << 8) +#define SUN6I_CLK_CTL_DRS BIT(12) + +#define SUN6I_BURST_CNT_REG 0x30 +#define SUN6I_BURST_CNT(cnt) ((cnt) & 0xffffff) + +#define SUN6I_XMIT_CNT_REG 0x34 +#define SUN6I_XMIT_CNT(cnt) ((cnt) & 0xffffff) + +#define SUN6I_BURST_CTL_CNT_REG 0x38 +#define SUN6I_BURST_CTL_CNT_STC(cnt) ((cnt) & 0xffffff) + +#define SUN6I_TXDATA_REG 0x200 +#define SUN6I_RXDATA_REG 0x300 + +struct sun6i_spi { + struct spi_master *master; + void __iomem *base_addr; + struct clk *hclk; + struct clk *mclk; + struct reset_control *rstc; + + struct completion done; + + const u8 *tx_buf; + u8 *rx_buf; + int len; +}; + +static inline u32 sun6i_spi_read(struct sun6i_spi *sspi, u32 reg) +{ + return readl(sspi->base_addr + reg); +} + +static inline void sun6i_spi_write(struct sun6i_spi *sspi, u32 reg, u32 value) +{ + writel(value, sspi->base_addr + reg); +} + +static inline void sun6i_spi_drain_fifo(struct sun6i_spi *sspi, int len) +{ + u32 reg, cnt; + u8 byte; + + /* See how much data is available */ + reg = sun6i_spi_read(sspi, SUN6I_FIFO_STA_REG); + reg &= SUN6I_FIFO_STA_RF_CNT_MASK; + cnt = reg >> SUN6I_FIFO_STA_RF_CNT_BITS; + + if (len > cnt) + len = cnt; + + while (len--) { + byte = readb(sspi->base_addr + SUN6I_RXDATA_REG); + if (sspi->rx_buf) + *sspi->rx_buf++ = byte; + } +} + +static inline void sun6i_spi_fill_fifo(struct sun6i_spi *sspi, int len) +{ + u8 byte; + + if (len > sspi->len) + len = sspi->len; + + while (len--) { + byte = sspi->tx_buf ? *sspi->tx_buf++ : 0; + writeb(byte, sspi->base_addr + SUN6I_TXDATA_REG); + sspi->len--; + } +} + +static void sun6i_spi_set_cs(struct spi_device *spi, bool enable) +{ + struct sun6i_spi *sspi = spi_master_get_devdata(spi->master); + u32 reg; + + reg = sun6i_spi_read(sspi, SUN6I_TFR_CTL_REG); + reg &= ~SUN6I_TFR_CTL_CS_MASK; + reg |= SUN6I_TFR_CTL_CS(spi->chip_select); + + if (enable) + reg |= SUN6I_TFR_CTL_CS_LEVEL; + else + reg &= ~SUN6I_TFR_CTL_CS_LEVEL; + + sun6i_spi_write(sspi, SUN6I_TFR_CTL_REG, reg); +} + + +static int sun6i_spi_transfer_one(struct spi_master *master, + struct spi_device *spi, + struct spi_transfer *tfr) +{ + struct sun6i_spi *sspi = spi_master_get_devdata(master); + unsigned int mclk_rate, div, timeout; + unsigned int tx_len = 0; + int ret = 0; + u32 reg; + + /* We don't support transfer larger than the FIFO */ + if (tfr->len > SUN6I_FIFO_DEPTH) + return -EINVAL; + + reinit_completion(&sspi->done); + sspi->tx_buf = tfr->tx_buf; + sspi->rx_buf = tfr->rx_buf; + sspi->len = tfr->len; + + /* Clear pending interrupts */ + sun6i_spi_write(sspi, SUN6I_INT_STA_REG, ~0); + + /* Reset FIFO */ + sun6i_spi_write(sspi, SUN6I_FIFO_CTL_REG, + SUN6I_FIFO_CTL_RF_RST | SUN6I_FIFO_CTL_TF_RST); + + /* + * Setup the transfer control register: Chip Select, + * polarities, etc. + */ + reg = sun6i_spi_read(sspi, SUN6I_TFR_CTL_REG); + + if (spi->mode & SPI_CPOL) + reg |= SUN6I_TFR_CTL_CPOL; + else + reg &= ~SUN6I_TFR_CTL_CPOL; + + if (spi->mode & SPI_CPHA) + reg |= SUN6I_TFR_CTL_CPHA; + else + reg &= ~SUN6I_TFR_CTL_CPHA; + + if (spi->mode & SPI_LSB_FIRST) + reg |= SUN6I_TFR_CTL_FBS; + else + reg &= ~SUN6I_TFR_CTL_FBS; + + /* + * If it's a TX only transfer, we don't want to fill the RX + * FIFO with bogus data + */ + if (sspi->rx_buf) + reg &= ~SUN6I_TFR_CTL_DHB; + else + reg |= SUN6I_TFR_CTL_DHB; + + /* We want to control the chip select manually */ + reg |= SUN6I_TFR_CTL_CS_MANUAL; + + sun6i_spi_write(sspi, SUN6I_TFR_CTL_REG, reg); + + /* Ensure that we have a parent clock fast enough */ + mclk_rate = clk_get_rate(sspi->mclk); + if (mclk_rate < (2 * spi->max_speed_hz)) { + clk_set_rate(sspi->mclk, 2 * spi->max_speed_hz); + mclk_rate = clk_get_rate(sspi->mclk); + } + + /* + * Setup clock divider. + * + * We have two choices there. Either we can use the clock + * divide rate 1, which is calculated thanks to this formula: + * SPI_CLK = MOD_CLK / (2 ^ cdr) + * Or we can use CDR2, which is calculated with the formula: + * SPI_CLK = MOD_CLK / (2 * (cdr + 1)) + * Wether we use the former or the latter is set through the + * DRS bit. + * + * First try CDR2, and if we can't reach the expected + * frequency, fall back to CDR1. + */ + div = mclk_rate / (2 * spi->max_speed_hz); + if (div <= (SUN6I_CLK_CTL_CDR2_MASK + 1)) { + if (div > 0) + div--; + + reg = SUN6I_CLK_CTL_CDR2(div) | SUN6I_CLK_CTL_DRS; + } else { + div = ilog2(mclk_rate) - ilog2(spi->max_speed_hz); + reg = SUN6I_CLK_CTL_CDR1(div); + } + + sun6i_spi_write(sspi, SUN6I_CLK_CTL_REG, reg); + + /* Setup the transfer now... */ + if (sspi->tx_buf) + tx_len = tfr->len; + + /* Setup the counters */ + sun6i_spi_write(sspi, SUN6I_BURST_CNT_REG, SUN6I_BURST_CNT(tfr->len)); + sun6i_spi_write(sspi, SUN6I_XMIT_CNT_REG, SUN6I_XMIT_CNT(tx_len)); + sun6i_spi_write(sspi, SUN6I_BURST_CTL_CNT_REG, + SUN6I_BURST_CTL_CNT_STC(tx_len)); + + /* Fill the TX FIFO */ + sun6i_spi_fill_fifo(sspi, SUN6I_FIFO_DEPTH); + + /* Enable the interrupts */ + sun6i_spi_write(sspi, SUN6I_INT_CTL_REG, SUN6I_INT_CTL_TC); + + /* Start the transfer */ + reg = sun6i_spi_read(sspi, SUN6I_TFR_CTL_REG); + sun6i_spi_write(sspi, SUN6I_TFR_CTL_REG, reg | SUN6I_TFR_CTL_XCH); + + timeout = wait_for_completion_timeout(&sspi->done, + msecs_to_jiffies(1000)); + if (!timeout) { + ret = -ETIMEDOUT; + goto out; + } + + sun6i_spi_drain_fifo(sspi, SUN6I_FIFO_DEPTH); + +out: + sun6i_spi_write(sspi, SUN6I_INT_CTL_REG, 0); + + return ret; +} + +static irqreturn_t sun6i_spi_handler(int irq, void *dev_id) +{ + struct sun6i_spi *sspi = dev_id; + u32 status = sun6i_spi_read(sspi, SUN6I_INT_STA_REG); + + /* Transfer complete */ + if (status & SUN6I_INT_CTL_TC) { + sun6i_spi_write(sspi, SUN6I_INT_STA_REG, SUN6I_INT_CTL_TC); + complete(&sspi->done); + return IRQ_HANDLED; + } + + return IRQ_NONE; +} + +static int sun6i_spi_runtime_resume(struct device *dev) +{ + struct spi_master *master = dev_get_drvdata(dev); + struct sun6i_spi *sspi = spi_master_get_devdata(master); + int ret; + + ret = clk_prepare_enable(sspi->hclk); + if (ret) { + dev_err(dev, "Couldn't enable AHB clock\n"); + goto out; + } + + ret = clk_prepare_enable(sspi->mclk); + if (ret) { + dev_err(dev, "Couldn't enable module clock\n"); + goto err; + } + + ret = reset_control_deassert(sspi->rstc); + if (ret) { + dev_err(dev, "Couldn't deassert the device from reset\n"); + goto err2; + } + + sun6i_spi_write(sspi, SUN6I_GBL_CTL_REG, + SUN6I_GBL_CTL_BUS_ENABLE | SUN6I_GBL_CTL_MASTER | SUN6I_GBL_CTL_TP); + + return 0; + +err2: + clk_disable_unprepare(sspi->mclk); +err: + clk_disable_unprepare(sspi->hclk); +out: + return ret; +} + +static int sun6i_spi_runtime_suspend(struct device *dev) +{ + struct spi_master *master = dev_get_drvdata(dev); + struct sun6i_spi *sspi = spi_master_get_devdata(master); + + reset_control_assert(sspi->rstc); + clk_disable_unprepare(sspi->mclk); + clk_disable_unprepare(sspi->hclk); + + return 0; +} + +static int sun6i_spi_probe(struct platform_device *pdev) +{ + struct spi_master *master; + struct sun6i_spi *sspi; + struct resource *res; + int ret = 0, irq; + + master = spi_alloc_master(&pdev->dev, sizeof(struct sun6i_spi)); + if (!master) { + dev_err(&pdev->dev, "Unable to allocate SPI Master\n"); + return -ENOMEM; + } + + platform_set_drvdata(pdev, master); + sspi = spi_master_get_devdata(master); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + sspi->base_addr = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(sspi->base_addr)) { + ret = PTR_ERR(sspi->base_addr); + goto err_free_master; + } + + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + dev_err(&pdev->dev, "No spi IRQ specified\n"); + ret = -ENXIO; + goto err_free_master; + } + + ret = devm_request_irq(&pdev->dev, irq, sun6i_spi_handler, + 0, "sun6i-spi", sspi); + if (ret) { + dev_err(&pdev->dev, "Cannot request IRQ\n"); + goto err_free_master; + } + + sspi->master = master; + master->set_cs = sun6i_spi_set_cs; + master->transfer_one = sun6i_spi_transfer_one; + master->num_chipselect = 4; + master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LSB_FIRST; + master->bits_per_word_mask = SPI_BPW_MASK(8); + master->dev.of_node = pdev->dev.of_node; + master->auto_runtime_pm = true; + + sspi->hclk = devm_clk_get(&pdev->dev, "ahb"); + if (IS_ERR(sspi->hclk)) { + dev_err(&pdev->dev, "Unable to acquire AHB clock\n"); + ret = PTR_ERR(sspi->hclk); + goto err_free_master; + } + + sspi->mclk = devm_clk_get(&pdev->dev, "mod"); + if (IS_ERR(sspi->mclk)) { + dev_err(&pdev->dev, "Unable to acquire module clock\n"); + ret = PTR_ERR(sspi->mclk); + goto err_free_master; + } + + init_completion(&sspi->done); + + sspi->rstc = devm_reset_control_get(&pdev->dev, NULL); + if (IS_ERR(sspi->rstc)) { + dev_err(&pdev->dev, "Couldn't get reset controller\n"); + ret = PTR_ERR(sspi->rstc); + goto err_free_master; + } + + /* + * This wake-up/shutdown pattern is to be able to have the + * device woken up, even if runtime_pm is disabled + */ + ret = sun6i_spi_runtime_resume(&pdev->dev); + if (ret) { + dev_err(&pdev->dev, "Couldn't resume the device\n"); + goto err_free_master; + } + + pm_runtime_set_active(&pdev->dev); + pm_runtime_enable(&pdev->dev); + pm_runtime_idle(&pdev->dev); + + ret = devm_spi_register_master(&pdev->dev, master); + if (ret) { + dev_err(&pdev->dev, "cannot register SPI master\n"); + goto err_pm_disable; + } + + return 0; + +err_pm_disable: + pm_runtime_disable(&pdev->dev); + sun6i_spi_runtime_suspend(&pdev->dev); +err_free_master: + spi_master_put(master); + return ret; +} + +static int sun6i_spi_remove(struct platform_device *pdev) +{ + pm_runtime_disable(&pdev->dev); + + return 0; +} + +static const struct of_device_id sun6i_spi_match[] = { + { .compatible = "allwinner,sun6i-a31-spi", }, + {} +}; +MODULE_DEVICE_TABLE(of, sun6i_spi_match); + +static const struct dev_pm_ops sun6i_spi_pm_ops = { + .runtime_resume = sun6i_spi_runtime_resume, + .runtime_suspend = sun6i_spi_runtime_suspend, +}; + +static struct platform_driver sun6i_spi_driver = { + .probe = sun6i_spi_probe, + .remove = sun6i_spi_remove, + .driver = { + .name = "sun6i-spi", + .owner = THIS_MODULE, + .of_match_table = sun6i_spi_match, + .pm = &sun6i_spi_pm_ops, + }, +}; +module_platform_driver(sun6i_spi_driver); + +MODULE_AUTHOR("Pan Nan <pannan@allwinnertech.com>"); +MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com>"); +MODULE_DESCRIPTION("Allwinner A31 SPI controller driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/spi/spi-tegra114.c b/drivers/spi/spi-tegra114.c index 413c7184349..40064959550 100644 --- a/drivers/spi/spi-tegra114.c +++ b/drivers/spi/spi-tegra114.c @@ -23,7 +23,6 @@ #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> @@ -172,7 +171,6 @@ struct tegra_spi_data { void __iomem *base; phys_addr_t phys; unsigned irq; - u32 spi_max_frequency; u32 cur_speed; struct spi_device *cur_spi; @@ -761,11 +759,6 @@ static int tegra_spi_setup(struct spi_device *spi) spi->mode & SPI_CPHA ? "" : "~", spi->max_speed_hz); - BUG_ON(spi->chip_select >= MAX_CHIP_SELECT); - - /* Set speed to the spi max fequency if spi device has not set */ - spi->max_speed_hz = spi->max_speed_hz ? : tspi->spi_max_frequency; - ret = pm_runtime_get_sync(tspi->dev); if (ret < 0) { dev_err(tspi->dev, "pm runtime failed, e = %d\n", ret); @@ -853,8 +846,8 @@ complete_xfer: SPI_COMMAND1); tegra_spi_transfer_delay(xfer->delay_usecs); goto exit; - } else if (msg->transfers.prev == &xfer->transfer_list) { - /* This is the last transfer in message */ + } else if (list_is_last(&xfer->transfer_list, + &msg->transfers)) { if (xfer->cs_change) tspi->cs_control = spi; else { @@ -1019,16 +1012,6 @@ static irqreturn_t tegra_spi_isr(int irq, void *context_data) return IRQ_WAKE_THREAD; } -static void tegra_spi_parse_dt(struct platform_device *pdev, - struct tegra_spi_data *tspi) -{ - struct device_node *np = pdev->dev.of_node; - - if (of_property_read_u32(np, "spi-max-frequency", - &tspi->spi_max_frequency)) - tspi->spi_max_frequency = 25000000; /* 25MHz */ -} - static struct of_device_id tegra_spi_of_match[] = { { .compatible = "nvidia,tegra114-spi", }, {} @@ -1050,15 +1033,15 @@ static int tegra_spi_probe(struct platform_device *pdev) platform_set_drvdata(pdev, master); tspi = spi_master_get_devdata(master); - /* Parse DT */ - tegra_spi_parse_dt(pdev, tspi); + if (of_property_read_u32(pdev->dev.of_node, "spi-max-frequency", + &master->max_speed_hz)) + master->max_speed_hz = 25000000; /* 25MHz */ /* the spi->mode bits understood by this driver: */ master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH; master->setup = tegra_spi_setup; master->transfer_one_message = tegra_spi_transfer_one_message; master->num_chipselect = MAX_CHIP_SELECT; - master->bus_num = -1; master->auto_runtime_pm = true; tspi->master = master; diff --git a/drivers/spi/spi-tegra20-sflash.c b/drivers/spi/spi-tegra20-sflash.c index 08794977f21..47869ea636e 100644 --- a/drivers/spi/spi-tegra20-sflash.c +++ b/drivers/spi/spi-tegra20-sflash.c @@ -22,7 +22,6 @@ #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> @@ -121,7 +120,6 @@ struct tegra_sflash_data { struct reset_control *rst; void __iomem *base; unsigned irq; - u32 spi_max_frequency; u32 cur_speed; struct spi_device *cur_spi; @@ -315,15 +313,6 @@ static int tegra_sflash_start_transfer_one(struct spi_device *spi, return tegra_sflash_start_cpu_based_transfer(tsd, t); } -static int tegra_sflash_setup(struct spi_device *spi) -{ - struct tegra_sflash_data *tsd = spi_master_get_devdata(spi->master); - - /* Set speed to the spi max fequency if spi device has not set */ - spi->max_speed_hz = spi->max_speed_hz ? : tsd->spi_max_frequency; - return 0; -} - static int tegra_sflash_transfer_one_message(struct spi_master *master, struct spi_message *msg) { @@ -430,15 +419,6 @@ static irqreturn_t tegra_sflash_isr(int irq, void *context_data) return handle_cpu_based_xfer(tsd); } -static void tegra_sflash_parse_dt(struct tegra_sflash_data *tsd) -{ - struct device_node *np = tsd->dev->of_node; - - if (of_property_read_u32(np, "spi-max-frequency", - &tsd->spi_max_frequency)) - tsd->spi_max_frequency = 25000000; /* 25MHz */ -} - static struct of_device_id tegra_sflash_of_match[] = { { .compatible = "nvidia,tegra20-sflash", }, {} @@ -467,11 +447,9 @@ static int tegra_sflash_probe(struct platform_device *pdev) /* the spi->mode bits understood by this driver: */ master->mode_bits = SPI_CPOL | SPI_CPHA; - master->setup = tegra_sflash_setup; master->transfer_one_message = tegra_sflash_transfer_one_message; master->auto_runtime_pm = true; master->num_chipselect = MAX_CHIP_SELECT; - master->bus_num = -1; platform_set_drvdata(pdev, master); tsd = spi_master_get_devdata(master); @@ -479,7 +457,9 @@ static int tegra_sflash_probe(struct platform_device *pdev) tsd->dev = &pdev->dev; spin_lock_init(&tsd->lock); - tegra_sflash_parse_dt(tsd); + if (of_property_read_u32(tsd->dev->of_node, "spi-max-frequency", + &master->max_speed_hz)) + master->max_speed_hz = 25000000; /* 25MHz */ r = platform_get_resource(pdev, IORESOURCE_MEM, 0); tsd->base = devm_ioremap_resource(&pdev->dev, r); diff --git a/drivers/spi/spi-tegra20-slink.c b/drivers/spi/spi-tegra20-slink.c index be3a069879c..e3c1b93e45d 100644 --- a/drivers/spi/spi-tegra20-slink.c +++ b/drivers/spi/spi-tegra20-slink.c @@ -23,7 +23,6 @@ #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> @@ -171,7 +170,6 @@ struct tegra_slink_data { void __iomem *base; phys_addr_t phys; unsigned irq; - u32 spi_max_frequency; u32 cur_speed; struct spi_device *cur_spi; @@ -761,10 +759,6 @@ static int tegra_slink_setup(struct spi_device *spi) spi->mode & SPI_CPHA ? "" : "~", spi->max_speed_hz); - BUG_ON(spi->chip_select >= MAX_CHIP_SELECT); - - /* Set speed to the spi max fequency if spi device has not set */ - spi->max_speed_hz = spi->max_speed_hz ? : tspi->spi_max_frequency; ret = pm_runtime_get_sync(tspi->dev); if (ret < 0) { dev_err(tspi->dev, "pm runtime failed, e = %d\n", ret); @@ -999,15 +993,6 @@ static irqreturn_t tegra_slink_isr(int irq, void *context_data) return IRQ_WAKE_THREAD; } -static void tegra_slink_parse_dt(struct tegra_slink_data *tspi) -{ - struct device_node *np = tspi->dev->of_node; - - if (of_property_read_u32(np, "spi-max-frequency", - &tspi->spi_max_frequency)) - tspi->spi_max_frequency = 25000000; /* 25MHz */ -} - static const struct tegra_slink_chip_data tegra30_spi_cdata = { .cs_hold_time = true, }; @@ -1053,7 +1038,6 @@ static int tegra_slink_probe(struct platform_device *pdev) master->unprepare_message = tegra_slink_unprepare_message; master->auto_runtime_pm = true; master->num_chipselect = MAX_CHIP_SELECT; - master->bus_num = -1; platform_set_drvdata(pdev, master); tspi = spi_master_get_devdata(master); @@ -1062,7 +1046,9 @@ static int tegra_slink_probe(struct platform_device *pdev) tspi->chip_data = cdata; spin_lock_init(&tspi->lock); - tegra_slink_parse_dt(tspi); + if (of_property_read_u32(tspi->dev->of_node, "spi-max-frequency", + &master->max_speed_hz)) + master->max_speed_hz = 25000000; /* 25MHz */ r = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!r) { diff --git a/drivers/spi/spi-ti-qspi.c b/drivers/spi/spi-ti-qspi.c index 3d09265b513..6c211d1910b 100644 --- a/drivers/spi/spi-ti-qspi.c +++ b/drivers/spi/spi-ti-qspi.c @@ -429,13 +429,13 @@ static int ti_qspi_probe(struct platform_device *pdev) master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_RX_DUAL | SPI_RX_QUAD; - master->bus_num = -1; master->flags = SPI_MASTER_HALF_DUPLEX; master->setup = ti_qspi_setup; master->auto_runtime_pm = true; master->transfer_one_message = ti_qspi_start_transfer_one; master->dev.of_node = pdev->dev.of_node; - master->bits_per_word_mask = BIT(32 - 1) | BIT(16 - 1) | BIT(8 - 1); + master->bits_per_word_mask = SPI_BPW_MASK(32) | SPI_BPW_MASK(16) | + SPI_BPW_MASK(8); if (!of_property_read_u32(np, "num-cs", &num_cs)) master->num_chipselect = num_cs; @@ -461,7 +461,6 @@ static int ti_qspi_probe(struct platform_device *pdev) if (res_mmap == NULL) { dev_err(&pdev->dev, "memory mapped resource not required\n"); - return -ENODEV; } } diff --git a/drivers/spi/spi-ti-ssp.c b/drivers/spi/spi-ti-ssp.c deleted file mode 100644 index 7d20e121e4c..00000000000 --- a/drivers/spi/spi-ti-ssp.c +++ /dev/null @@ -1,378 +0,0 @@ -/* - * Sequencer Serial Port (SSP) based SPI master driver - * - * Copyright (C) 2010 Texas Instruments Inc - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include <linux/kernel.h> -#include <linux/err.h> -#include <linux/completion.h> -#include <linux/delay.h> -#include <linux/module.h> -#include <linux/platform_device.h> -#include <linux/spi/spi.h> -#include <linux/mfd/ti_ssp.h> - -#define MODE_BITS (SPI_CPHA | SPI_CPOL | SPI_CS_HIGH) - -struct ti_ssp_spi { - struct spi_master *master; - struct device *dev; - spinlock_t lock; - struct list_head msg_queue; - struct completion complete; - bool shutdown; - struct workqueue_struct *workqueue; - struct work_struct work; - u8 mode, bpw; - int cs_active; - u32 pc_en, pc_dis, pc_wr, pc_rd; - void (*select)(int cs); -}; - -static u32 ti_ssp_spi_rx(struct ti_ssp_spi *hw) -{ - u32 ret; - - ti_ssp_run(hw->dev, hw->pc_rd, 0, &ret); - return ret; -} - -static void ti_ssp_spi_tx(struct ti_ssp_spi *hw, u32 data) -{ - ti_ssp_run(hw->dev, hw->pc_wr, data << (32 - hw->bpw), NULL); -} - -static int ti_ssp_spi_txrx(struct ti_ssp_spi *hw, struct spi_message *msg, - struct spi_transfer *t) -{ - int count; - - if (hw->bpw <= 8) { - u8 *rx = t->rx_buf; - const u8 *tx = t->tx_buf; - - for (count = 0; count < t->len; count += 1) { - if (t->tx_buf) - ti_ssp_spi_tx(hw, *tx++); - if (t->rx_buf) - *rx++ = ti_ssp_spi_rx(hw); - } - } else if (hw->bpw <= 16) { - u16 *rx = t->rx_buf; - const u16 *tx = t->tx_buf; - - for (count = 0; count < t->len; count += 2) { - if (t->tx_buf) - ti_ssp_spi_tx(hw, *tx++); - if (t->rx_buf) - *rx++ = ti_ssp_spi_rx(hw); - } - } else { - u32 *rx = t->rx_buf; - const u32 *tx = t->tx_buf; - - for (count = 0; count < t->len; count += 4) { - if (t->tx_buf) - ti_ssp_spi_tx(hw, *tx++); - if (t->rx_buf) - *rx++ = ti_ssp_spi_rx(hw); - } - } - - msg->actual_length += count; /* bytes transferred */ - - dev_dbg(&msg->spi->dev, "xfer %s%s, %d bytes, %d bpw, count %d%s\n", - t->tx_buf ? "tx" : "", t->rx_buf ? "rx" : "", t->len, - hw->bpw, count, (count < t->len) ? " (under)" : ""); - - return (count < t->len) ? -EIO : 0; /* left over data */ -} - -static void ti_ssp_spi_chip_select(struct ti_ssp_spi *hw, int cs_active) -{ - cs_active = !!cs_active; - if (cs_active == hw->cs_active) - return; - ti_ssp_run(hw->dev, cs_active ? hw->pc_en : hw->pc_dis, 0, NULL); - hw->cs_active = cs_active; -} - -#define __SHIFT_OUT(bits) (SSP_OPCODE_SHIFT | SSP_OUT_MODE | \ - cs_en | clk | SSP_COUNT((bits) * 2 - 1)) -#define __SHIFT_IN(bits) (SSP_OPCODE_SHIFT | SSP_IN_MODE | \ - cs_en | clk | SSP_COUNT((bits) * 2 - 1)) - -static int ti_ssp_spi_setup_transfer(struct ti_ssp_spi *hw, u8 bpw, u8 mode) -{ - int error, idx = 0; - u32 seqram[16]; - u32 cs_en, cs_dis, clk; - u32 topbits, botbits; - - mode &= MODE_BITS; - if (mode == hw->mode && bpw == hw->bpw) - return 0; - - cs_en = (mode & SPI_CS_HIGH) ? SSP_CS_HIGH : SSP_CS_LOW; - cs_dis = (mode & SPI_CS_HIGH) ? SSP_CS_LOW : SSP_CS_HIGH; - clk = (mode & SPI_CPOL) ? SSP_CLK_HIGH : SSP_CLK_LOW; - - /* Construct instructions */ - - /* Disable Chip Select */ - hw->pc_dis = idx; - seqram[idx++] = SSP_OPCODE_DIRECT | SSP_OUT_MODE | cs_dis | clk; - seqram[idx++] = SSP_OPCODE_STOP | SSP_OUT_MODE | cs_dis | clk; - - /* Enable Chip Select */ - hw->pc_en = idx; - seqram[idx++] = SSP_OPCODE_DIRECT | SSP_OUT_MODE | cs_en | clk; - seqram[idx++] = SSP_OPCODE_STOP | SSP_OUT_MODE | cs_en | clk; - - /* Reads and writes need to be split for bpw > 16 */ - topbits = (bpw > 16) ? 16 : bpw; - botbits = bpw - topbits; - - /* Write */ - hw->pc_wr = idx; - seqram[idx++] = __SHIFT_OUT(topbits) | SSP_ADDR_REG; - if (botbits) - seqram[idx++] = __SHIFT_OUT(botbits) | SSP_DATA_REG; - seqram[idx++] = SSP_OPCODE_STOP | SSP_OUT_MODE | cs_en | clk; - - /* Read */ - hw->pc_rd = idx; - if (botbits) - seqram[idx++] = __SHIFT_IN(botbits) | SSP_ADDR_REG; - seqram[idx++] = __SHIFT_IN(topbits) | SSP_DATA_REG; - seqram[idx++] = SSP_OPCODE_STOP | SSP_OUT_MODE | cs_en | clk; - - error = ti_ssp_load(hw->dev, 0, seqram, idx); - if (error < 0) - return error; - - error = ti_ssp_set_mode(hw->dev, ((mode & SPI_CPHA) ? - 0 : SSP_EARLY_DIN)); - if (error < 0) - return error; - - hw->bpw = bpw; - hw->mode = mode; - - return error; -} - -static void ti_ssp_spi_work(struct work_struct *work) -{ - struct ti_ssp_spi *hw = container_of(work, struct ti_ssp_spi, work); - - spin_lock(&hw->lock); - - while (!list_empty(&hw->msg_queue)) { - struct spi_message *m; - struct spi_device *spi; - struct spi_transfer *t = NULL; - int status = 0; - - m = container_of(hw->msg_queue.next, struct spi_message, - queue); - - list_del_init(&m->queue); - - spin_unlock(&hw->lock); - - spi = m->spi; - - if (hw->select) - hw->select(spi->chip_select); - - list_for_each_entry(t, &m->transfers, transfer_list) { - int bpw = spi->bits_per_word; - int xfer_status; - - if (t->bits_per_word) - bpw = t->bits_per_word; - - if (ti_ssp_spi_setup_transfer(hw, bpw, spi->mode) < 0) - break; - - ti_ssp_spi_chip_select(hw, 1); - - xfer_status = ti_ssp_spi_txrx(hw, m, t); - if (xfer_status < 0) - status = xfer_status; - - if (t->delay_usecs) - udelay(t->delay_usecs); - - if (t->cs_change) - ti_ssp_spi_chip_select(hw, 0); - } - - ti_ssp_spi_chip_select(hw, 0); - m->status = status; - m->complete(m->context); - - spin_lock(&hw->lock); - } - - if (hw->shutdown) - complete(&hw->complete); - - spin_unlock(&hw->lock); -} - -static int ti_ssp_spi_transfer(struct spi_device *spi, struct spi_message *m) -{ - struct ti_ssp_spi *hw; - struct spi_transfer *t; - int error = 0; - - m->actual_length = 0; - m->status = -EINPROGRESS; - - hw = spi_master_get_devdata(spi->master); - - if (list_empty(&m->transfers) || !m->complete) - return -EINVAL; - - list_for_each_entry(t, &m->transfers, transfer_list) { - if (t->len && !(t->rx_buf || t->tx_buf)) { - dev_err(&spi->dev, "invalid xfer, no buffer\n"); - return -EINVAL; - } - - if (t->len && t->rx_buf && t->tx_buf) { - dev_err(&spi->dev, "invalid xfer, full duplex\n"); - return -EINVAL; - } - } - - spin_lock(&hw->lock); - if (hw->shutdown) { - error = -ESHUTDOWN; - goto error_unlock; - } - list_add_tail(&m->queue, &hw->msg_queue); - queue_work(hw->workqueue, &hw->work); -error_unlock: - spin_unlock(&hw->lock); - return error; -} - -static int ti_ssp_spi_probe(struct platform_device *pdev) -{ - const struct ti_ssp_spi_data *pdata; - struct ti_ssp_spi *hw; - struct spi_master *master; - struct device *dev = &pdev->dev; - int error = 0; - - pdata = dev_get_platdata(dev); - if (!pdata) { - dev_err(dev, "platform data not found\n"); - return -EINVAL; - } - - master = spi_alloc_master(dev, sizeof(struct ti_ssp_spi)); - if (!master) { - dev_err(dev, "cannot allocate SPI master\n"); - return -ENOMEM; - } - - hw = spi_master_get_devdata(master); - platform_set_drvdata(pdev, hw); - - hw->master = master; - hw->dev = dev; - hw->select = pdata->select; - - spin_lock_init(&hw->lock); - init_completion(&hw->complete); - INIT_LIST_HEAD(&hw->msg_queue); - INIT_WORK(&hw->work, ti_ssp_spi_work); - - hw->workqueue = create_singlethread_workqueue(dev_name(dev)); - if (!hw->workqueue) { - error = -ENOMEM; - dev_err(dev, "work queue creation failed\n"); - goto error_wq; - } - - error = ti_ssp_set_iosel(hw->dev, pdata->iosel); - if (error < 0) { - dev_err(dev, "io setup failed\n"); - goto error_iosel; - } - - master->bus_num = pdev->id; - master->num_chipselect = pdata->num_cs; - master->mode_bits = MODE_BITS; - master->bits_per_word_mask = SPI_BPW_RANGE_MASK(1, 32); - master->flags = SPI_MASTER_HALF_DUPLEX; - master->transfer = ti_ssp_spi_transfer; - - error = spi_register_master(master); - if (error) { - dev_err(dev, "master registration failed\n"); - goto error_reg; - } - - return 0; - -error_reg: -error_iosel: - destroy_workqueue(hw->workqueue); -error_wq: - spi_master_put(master); - return error; -} - -static int ti_ssp_spi_remove(struct platform_device *pdev) -{ - struct ti_ssp_spi *hw = platform_get_drvdata(pdev); - int error; - - hw->shutdown = 1; - while (!list_empty(&hw->msg_queue)) { - error = wait_for_completion_interruptible(&hw->complete); - if (error < 0) { - hw->shutdown = 0; - return error; - } - } - destroy_workqueue(hw->workqueue); - spi_unregister_master(hw->master); - - return 0; -} - -static struct platform_driver ti_ssp_spi_driver = { - .probe = ti_ssp_spi_probe, - .remove = ti_ssp_spi_remove, - .driver = { - .name = "ti-ssp-spi", - .owner = THIS_MODULE, - }, -}; -module_platform_driver(ti_ssp_spi_driver); - -MODULE_DESCRIPTION("SSP SPI Master"); -MODULE_AUTHOR("Cyril Chemparathy"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:ti-ssp-spi"); diff --git a/drivers/spi/spi-topcliff-pch.c b/drivers/spi/spi-topcliff-pch.c index 88eb57e858b..f406b30af96 100644 --- a/drivers/spi/spi-topcliff-pch.c +++ b/drivers/spi/spi-topcliff-pch.c @@ -332,7 +332,7 @@ static void pch_spi_handler_sub(struct pch_spi_data *data, u32 reg_spsr_val, data->transfer_active = false; wake_up(&data->wait); } else { - dev_err(&data->master->dev, + dev_vdbg(&data->master->dev, "%s : Transfer is not completed", __func__); } @@ -464,20 +464,6 @@ static void pch_spi_reset(struct spi_master *master) pch_spi_writereg(master, PCH_SRST, 0x0); } -static int pch_spi_setup(struct spi_device *pspi) -{ - /* Check baud rate setting */ - /* if baud rate of chip is greater than - max we can support,return error */ - if ((pspi->max_speed_hz) > PCH_MAX_BAUDRATE) - pspi->max_speed_hz = PCH_MAX_BAUDRATE; - - dev_dbg(&pspi->dev, "%s MODE = %x\n", __func__, - (pspi->mode) & (SPI_CPOL | SPI_CPHA)); - - return 0; -} - static int pch_spi_transfer(struct spi_device *pspi, struct spi_message *pmsg) { @@ -486,23 +472,6 @@ static int pch_spi_transfer(struct spi_device *pspi, struct spi_message *pmsg) int retval; unsigned long flags; - /* validate spi message and baud rate */ - if (unlikely(list_empty(&pmsg->transfers) == 1)) { - dev_err(&pspi->dev, "%s list empty\n", __func__); - retval = -EINVAL; - goto err_out; - } - - if (unlikely(pspi->max_speed_hz == 0)) { - dev_err(&pspi->dev, "%s pch_spi_transfer maxspeed=%d\n", - __func__, pspi->max_speed_hz); - retval = -EINVAL; - goto err_out; - } - - dev_dbg(&pspi->dev, - "%s Transfer List not empty. Transfer Speed is set.\n", __func__); - spin_lock_irqsave(&data->lock, flags); /* validate Tx/Rx buffers and Transfer length */ list_for_each_entry(transfer, &pmsg->transfers, transfer_list) { @@ -523,10 +492,6 @@ static int pch_spi_transfer(struct spi_device *pspi, struct spi_message *pmsg) dev_dbg(&pspi->dev, "%s Tx/Rx buffer valid. Transfer length valid\n", __func__); - - /* if baud rate has been specified validate the same */ - if (transfer->speed_hz > PCH_MAX_BAUDRATE) - transfer->speed_hz = PCH_MAX_BAUDRATE; } spin_unlock_irqrestore(&data->lock, flags); @@ -1151,8 +1116,7 @@ static void pch_spi_handle_dma(struct pch_spi_data *data, int *bpw) dma->nent = num; dma->desc_tx = desc_tx; - dev_dbg(&data->master->dev, "\n%s:Pulling down SSN low - writing " - "0x2 to SSNXCR\n", __func__); + dev_dbg(&data->master->dev, "%s:Pulling down SSN low - writing 0x2 to SSNXCR\n", __func__); spin_lock_irqsave(&data->lock, flags); pch_spi_writereg(data->master, PCH_SSNXCR, SSN_LOW); @@ -1418,10 +1382,10 @@ static int pch_spi_pd_probe(struct platform_device *plat_dev) /* initialize members of SPI master */ master->num_chipselect = PCH_MAX_CS; - master->setup = pch_spi_setup; master->transfer = pch_spi_transfer; master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST; master->bits_per_word_mask = SPI_BPW_MASK(8) | SPI_BPW_MASK(16); + master->max_speed_hz = PCH_MAX_BAUDRATE; data->board_dat = board_dat; data->plat_dev = plat_dev; @@ -1605,8 +1569,7 @@ static struct platform_driver pch_spi_pd_driver = { .resume = pch_spi_pd_resume }; -static int pch_spi_probe(struct pci_dev *pdev, - const struct pci_device_id *id) +static int pch_spi_probe(struct pci_dev *pdev, const struct pci_device_id *id) { struct pch_spi_board_data *board_dat; struct platform_device *pd_dev = NULL; @@ -1676,6 +1639,8 @@ static int pch_spi_probe(struct pci_dev *pdev, return 0; err_platform_device: + while (--i >= 0) + platform_device_unregister(pd_dev_save->pd_save[i]); pci_disable_device(pdev); pci_enable_device: pci_release_regions(pdev); diff --git a/drivers/spi/spi-txx9.c b/drivers/spi/spi-txx9.c index 6191ced514b..820b499816f 100644 --- a/drivers/spi/spi-txx9.c +++ b/drivers/spi/spi-txx9.c @@ -80,7 +80,6 @@ struct txx9spi { void __iomem *membase; int baseclk; struct clk *clk; - u32 max_speed_hz, min_speed_hz; int last_chipselect; int last_chipselect_val; }; @@ -117,9 +116,7 @@ static int txx9spi_setup(struct spi_device *spi) { struct txx9spi *c = spi_master_get_devdata(spi->master); - if (!spi->max_speed_hz - || spi->max_speed_hz > c->max_speed_hz - || spi->max_speed_hz < c->min_speed_hz) + if (!spi->max_speed_hz) return -EINVAL; if (gpio_direction_output(spi->chip_select, @@ -309,15 +306,8 @@ static int txx9spi_transfer(struct spi_device *spi, struct spi_message *m) /* check each transfer's parameters */ list_for_each_entry(t, &m->transfers, transfer_list) { - u32 speed_hz = t->speed_hz ? : spi->max_speed_hz; - u8 bits_per_word = t->bits_per_word; - if (!t->tx_buf && !t->rx_buf && t->len) return -EINVAL; - if (t->len & ((bits_per_word >> 3) - 1)) - return -EINVAL; - if (speed_hz < c->min_speed_hz || speed_hz > c->max_speed_hz) - return -EINVAL; } spin_lock_irqsave(&c->lock, flags); @@ -360,17 +350,12 @@ static int txx9spi_probe(struct platform_device *dev) goto exit; } c->baseclk = clk_get_rate(c->clk); - c->min_speed_hz = DIV_ROUND_UP(c->baseclk, SPI_MAX_DIVIDER + 1); - c->max_speed_hz = c->baseclk / (SPI_MIN_DIVIDER + 1); + master->min_speed_hz = DIV_ROUND_UP(c->baseclk, SPI_MAX_DIVIDER + 1); + master->max_speed_hz = c->baseclk / (SPI_MIN_DIVIDER + 1); res = platform_get_resource(dev, IORESOURCE_MEM, 0); - if (!res) - goto exit_busy; - if (!devm_request_mem_region(&dev->dev, res->start, resource_size(res), - "spi_txx9")) - goto exit_busy; - c->membase = devm_ioremap(&dev->dev, res->start, resource_size(res)); - if (!c->membase) + c->membase = devm_ioremap_resource(&dev->dev, res); + if (IS_ERR(c->membase)) goto exit_busy; /* enter config mode */ diff --git a/drivers/spi/spi-xcomm.c b/drivers/spi/spi-xcomm.c index 24c40b13dab..bb478dccf1d 100644 --- a/drivers/spi/spi-xcomm.c +++ b/drivers/spi/spi-xcomm.c @@ -8,7 +8,6 @@ */ #include <linux/kernel.h> -#include <linux/init.h> #include <linux/module.h> #include <linux/delay.h> #include <linux/i2c.h> @@ -74,15 +73,13 @@ static void spi_xcomm_chipselect(struct spi_xcomm *spi_xcomm, static int spi_xcomm_setup_transfer(struct spi_xcomm *spi_xcomm, struct spi_device *spi, struct spi_transfer *t, unsigned int *settings) { - unsigned int speed; - if (t->len > 62) return -EINVAL; - speed = t->speed_hz ? t->speed_hz : spi->max_speed_hz; + if (t->speed_hz != spi_xcomm->current_speed) { + unsigned int divider; - if (speed != spi_xcomm->current_speed) { - unsigned int divider = DIV_ROUND_UP(SPI_XCOMM_CLOCK, speed); + divider = DIV_ROUND_UP(SPI_XCOMM_CLOCK, t->speed_hz); if (divider >= 64) *settings |= SPI_XCOMM_SETTINGS_CLOCK_DIV_64; else if (divider >= 16) @@ -90,7 +87,7 @@ static int spi_xcomm_setup_transfer(struct spi_xcomm *spi_xcomm, else *settings |= SPI_XCOMM_SETTINGS_CLOCK_DIV_4; - spi_xcomm->current_speed = speed; + spi_xcomm->current_speed = t->speed_hz; } if (spi->mode & SPI_CPOL) @@ -148,8 +145,6 @@ static int spi_xcomm_transfer_one(struct spi_master *master, int status = 0; bool is_last; - is_first = true; - spi_xcomm_chipselect(spi_xcomm, spi, true); list_for_each_entry(t, &msg->transfers, transfer_list) { diff --git a/drivers/spi/spi-xilinx.c b/drivers/spi/spi-xilinx.c index 6d4ce461516..a3b0b9944bf 100644 --- a/drivers/spi/spi-xilinx.c +++ b/drivers/spi/spi-xilinx.c @@ -14,7 +14,6 @@ */ #include <linux/module.h> -#include <linux/init.h> #include <linux/interrupt.h> #include <linux/of.h> #include <linux/platform_device.h> @@ -88,10 +87,10 @@ struct xilinx_spi { const u8 *tx_ptr; /* pointer in the Rx buffer */ int remaining_bytes; /* the number of bytes left to transfer */ u8 bits_per_word; - unsigned int (*read_fn) (void __iomem *); - void (*write_fn) (u32, void __iomem *); - void (*tx_fn) (struct xilinx_spi *); - void (*rx_fn) (struct xilinx_spi *); + unsigned int (*read_fn)(void __iomem *); + void (*write_fn)(u32, void __iomem *); + void (*tx_fn)(struct xilinx_spi *); + void (*rx_fn)(struct xilinx_spi *); }; static void xspi_write32(u32 val, void __iomem *addr) @@ -209,26 +208,11 @@ static void xilinx_spi_chipselect(struct spi_device *spi, int is_on) } /* spi_bitbang requires custom setup_transfer() to be defined if there is a - * custom txrx_bufs(). We have nothing to setup here as the SPI IP block - * supports 8 or 16 bits per word which cannot be changed in software. - * SPI clock can't be changed in software either. - * Check for correct bits per word. Chip select delay calculations could be - * added here as soon as bitbang_work() can be made aware of the delay value. + * custom txrx_bufs(). */ static int xilinx_spi_setup_transfer(struct spi_device *spi, struct spi_transfer *t) { - struct xilinx_spi *xspi = spi_master_get_devdata(spi->master); - u8 bits_per_word; - - bits_per_word = (t && t->bits_per_word) - ? t->bits_per_word : spi->bits_per_word; - if (bits_per_word != xspi->bits_per_word) { - dev_err(&spi->dev, "%s, unsupported bits_per_word=%d\n", - __func__, bits_per_word); - return -EINVAL; - } - return 0; } @@ -407,6 +391,7 @@ static int xilinx_spi_probe(struct platform_device *pdev) xspi->write_fn = xspi_write32_be; } + master->bits_per_word_mask = SPI_BPW_MASK(bits_per_word); xspi->bits_per_word = bits_per_word; if (xspi->bits_per_word == 8) { xspi->tx_fn = xspi_tx8; diff --git a/drivers/spi/spi-xtensa-xtfpga.c b/drivers/spi/spi-xtensa-xtfpga.c new file mode 100644 index 00000000000..41e158187f9 --- /dev/null +++ b/drivers/spi/spi-xtensa-xtfpga.c @@ -0,0 +1,170 @@ +/* + * Xtensa xtfpga SPI controller driver + * + * Copyright (c) 2014 Cadence Design Systems Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/delay.h> +#include <linux/io.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/platform_device.h> +#include <linux/spi/spi.h> +#include <linux/spi/spi_bitbang.h> + +#define XTFPGA_SPI_NAME "xtfpga_spi" + +#define XTFPGA_SPI_START 0x0 +#define XTFPGA_SPI_BUSY 0x4 +#define XTFPGA_SPI_DATA 0x8 + +#define BUSY_WAIT_US 100 + +struct xtfpga_spi { + struct spi_bitbang bitbang; + void __iomem *regs; + u32 data; + unsigned data_sz; +}; + +static inline void xtfpga_spi_write32(const struct xtfpga_spi *spi, + unsigned addr, u32 val) +{ + iowrite32(val, spi->regs + addr); +} + +static inline unsigned int xtfpga_spi_read32(const struct xtfpga_spi *spi, + unsigned addr) +{ + return ioread32(spi->regs + addr); +} + +static inline void xtfpga_spi_wait_busy(struct xtfpga_spi *xspi) +{ + unsigned i; + for (i = 0; xtfpga_spi_read32(xspi, XTFPGA_SPI_BUSY) && + i < BUSY_WAIT_US; ++i) + udelay(1); + WARN_ON_ONCE(i == BUSY_WAIT_US); +} + +static u32 xtfpga_spi_txrx_word(struct spi_device *spi, unsigned nsecs, + u32 v, u8 bits) +{ + struct xtfpga_spi *xspi = spi_master_get_devdata(spi->master); + + xspi->data = (xspi->data << bits) | (v & GENMASK(bits - 1, 0)); + xspi->data_sz += bits; + if (xspi->data_sz >= 16) { + xtfpga_spi_write32(xspi, XTFPGA_SPI_DATA, + xspi->data >> (xspi->data_sz - 16)); + xspi->data_sz -= 16; + xtfpga_spi_write32(xspi, XTFPGA_SPI_START, 1); + xtfpga_spi_wait_busy(xspi); + xtfpga_spi_write32(xspi, XTFPGA_SPI_START, 0); + } + + return 0; +} + +static void xtfpga_spi_chipselect(struct spi_device *spi, int is_on) +{ + struct xtfpga_spi *xspi = spi_master_get_devdata(spi->master); + + WARN_ON(xspi->data_sz != 0); + xspi->data_sz = 0; +} + +static int xtfpga_spi_probe(struct platform_device *pdev) +{ + struct xtfpga_spi *xspi; + struct resource *mem; + int ret; + struct spi_master *master; + + master = spi_alloc_master(&pdev->dev, sizeof(struct xtfpga_spi)); + if (!master) + return -ENOMEM; + + master->flags = SPI_MASTER_NO_RX; + master->bits_per_word_mask = SPI_BPW_RANGE_MASK(1, 16); + master->bus_num = pdev->dev.id; + master->dev.of_node = pdev->dev.of_node; + + xspi = spi_master_get_devdata(master); + xspi->bitbang.master = master; + xspi->bitbang.chipselect = xtfpga_spi_chipselect; + xspi->bitbang.txrx_word[SPI_MODE_0] = xtfpga_spi_txrx_word; + + mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!mem) { + dev_err(&pdev->dev, "No memory resource\n"); + ret = -ENODEV; + goto err; + } + xspi->regs = devm_ioremap_resource(&pdev->dev, mem); + if (IS_ERR(xspi->regs)) { + ret = PTR_ERR(xspi->regs); + goto err; + } + + xtfpga_spi_write32(xspi, XTFPGA_SPI_START, 0); + usleep_range(1000, 2000); + if (xtfpga_spi_read32(xspi, XTFPGA_SPI_BUSY)) { + dev_err(&pdev->dev, "Device stuck in busy state\n"); + ret = -EBUSY; + goto err; + } + + ret = spi_bitbang_start(&xspi->bitbang); + if (ret < 0) { + dev_err(&pdev->dev, "spi_bitbang_start failed\n"); + goto err; + } + + platform_set_drvdata(pdev, master); + return 0; +err: + spi_master_put(master); + return ret; +} + +static int xtfpga_spi_remove(struct platform_device *pdev) +{ + struct spi_master *master = platform_get_drvdata(pdev); + struct xtfpga_spi *xspi = spi_master_get_devdata(master); + + spi_bitbang_stop(&xspi->bitbang); + spi_master_put(master); + + return 0; +} + +MODULE_ALIAS("platform:" XTFPGA_SPI_NAME); + +#ifdef CONFIG_OF +static const struct of_device_id xtfpga_spi_of_match[] = { + { .compatible = "cdns,xtfpga-spi", }, + {} +}; +MODULE_DEVICE_TABLE(of, xtfpga_spi_of_match); +#endif + +static struct platform_driver xtfpga_spi_driver = { + .probe = xtfpga_spi_probe, + .remove = xtfpga_spi_remove, + .driver = { + .name = XTFPGA_SPI_NAME, + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(xtfpga_spi_of_match), + }, +}; +module_platform_driver(xtfpga_spi_driver); + +MODULE_AUTHOR("Max Filippov <jcmvbkbc@gmail.com>"); +MODULE_DESCRIPTION("xtensa xtfpga SPI driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index d0b28bba38b..4eb9bf02996 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -24,6 +24,8 @@ #include <linux/device.h> #include <linux/init.h> #include <linux/cache.h> +#include <linux/dma-mapping.h> +#include <linux/dmaengine.h> #include <linux/mutex.h> #include <linux/of_device.h> #include <linux/of_irq.h> @@ -255,13 +257,12 @@ EXPORT_SYMBOL_GPL(spi_bus_type); static int spi_drv_probe(struct device *dev) { const struct spi_driver *sdrv = to_spi_driver(dev->driver); - struct spi_device *spi = to_spi_device(dev); int ret; - acpi_dev_pm_attach(&spi->dev, true); - ret = sdrv->probe(spi); + acpi_dev_pm_attach(dev, true); + ret = sdrv->probe(to_spi_device(dev)); if (ret) - acpi_dev_pm_detach(&spi->dev, true); + acpi_dev_pm_detach(dev, true); return ret; } @@ -269,11 +270,10 @@ static int spi_drv_probe(struct device *dev) static int spi_drv_remove(struct device *dev) { const struct spi_driver *sdrv = to_spi_driver(dev->driver); - struct spi_device *spi = to_spi_device(dev); int ret; - ret = sdrv->remove(spi); - acpi_dev_pm_detach(&spi->dev, true); + ret = sdrv->remove(to_spi_device(dev)); + acpi_dev_pm_detach(dev, true); return ret; } @@ -580,6 +580,169 @@ static void spi_set_cs(struct spi_device *spi, bool enable) spi->master->set_cs(spi, !enable); } +static int spi_map_buf(struct spi_master *master, struct device *dev, + struct sg_table *sgt, void *buf, size_t len, + enum dma_data_direction dir) +{ + const bool vmalloced_buf = is_vmalloc_addr(buf); + const int desc_len = vmalloced_buf ? PAGE_SIZE : master->max_dma_len; + const int sgs = DIV_ROUND_UP(len, desc_len); + struct page *vm_page; + void *sg_buf; + size_t min; + int i, ret; + + ret = sg_alloc_table(sgt, sgs, GFP_KERNEL); + if (ret != 0) + return ret; + + for (i = 0; i < sgs; i++) { + min = min_t(size_t, len, desc_len); + + if (vmalloced_buf) { + vm_page = vmalloc_to_page(buf); + if (!vm_page) { + sg_free_table(sgt); + return -ENOMEM; + } + sg_buf = page_address(vm_page) + + ((size_t)buf & ~PAGE_MASK); + } else { + sg_buf = buf; + } + + sg_set_buf(&sgt->sgl[i], sg_buf, min); + + buf += min; + len -= min; + } + + ret = dma_map_sg(dev, sgt->sgl, sgt->nents, dir); + if (ret < 0) { + sg_free_table(sgt); + return ret; + } + + sgt->nents = ret; + + return 0; +} + +static void spi_unmap_buf(struct spi_master *master, struct device *dev, + struct sg_table *sgt, enum dma_data_direction dir) +{ + if (sgt->orig_nents) { + dma_unmap_sg(dev, sgt->sgl, sgt->orig_nents, dir); + sg_free_table(sgt); + } +} + +static int spi_map_msg(struct spi_master *master, struct spi_message *msg) +{ + struct device *tx_dev, *rx_dev; + struct spi_transfer *xfer; + void *tmp; + unsigned int max_tx, max_rx; + int ret; + + if (master->flags & (SPI_MASTER_MUST_RX | SPI_MASTER_MUST_TX)) { + max_tx = 0; + max_rx = 0; + + list_for_each_entry(xfer, &msg->transfers, transfer_list) { + if ((master->flags & SPI_MASTER_MUST_TX) && + !xfer->tx_buf) + max_tx = max(xfer->len, max_tx); + if ((master->flags & SPI_MASTER_MUST_RX) && + !xfer->rx_buf) + max_rx = max(xfer->len, max_rx); + } + + if (max_tx) { + tmp = krealloc(master->dummy_tx, max_tx, + GFP_KERNEL | GFP_DMA); + if (!tmp) + return -ENOMEM; + master->dummy_tx = tmp; + memset(tmp, 0, max_tx); + } + + if (max_rx) { + tmp = krealloc(master->dummy_rx, max_rx, + GFP_KERNEL | GFP_DMA); + if (!tmp) + return -ENOMEM; + master->dummy_rx = tmp; + } + + if (max_tx || max_rx) { + list_for_each_entry(xfer, &msg->transfers, + transfer_list) { + if (!xfer->tx_buf) + xfer->tx_buf = master->dummy_tx; + if (!xfer->rx_buf) + xfer->rx_buf = master->dummy_rx; + } + } + } + + if (!master->can_dma) + return 0; + + tx_dev = &master->dma_tx->dev->device; + rx_dev = &master->dma_rx->dev->device; + + list_for_each_entry(xfer, &msg->transfers, transfer_list) { + if (!master->can_dma(master, msg->spi, xfer)) + continue; + + if (xfer->tx_buf != NULL) { + ret = spi_map_buf(master, tx_dev, &xfer->tx_sg, + (void *)xfer->tx_buf, xfer->len, + DMA_TO_DEVICE); + if (ret != 0) + return ret; + } + + if (xfer->rx_buf != NULL) { + ret = spi_map_buf(master, rx_dev, &xfer->rx_sg, + xfer->rx_buf, xfer->len, + DMA_FROM_DEVICE); + if (ret != 0) { + spi_unmap_buf(master, tx_dev, &xfer->tx_sg, + DMA_TO_DEVICE); + return ret; + } + } + } + + master->cur_msg_mapped = true; + + return 0; +} + +static int spi_unmap_msg(struct spi_master *master, struct spi_message *msg) +{ + struct spi_transfer *xfer; + struct device *tx_dev, *rx_dev; + + if (!master->cur_msg_mapped || !master->can_dma) + return 0; + + tx_dev = &master->dma_tx->dev->device; + rx_dev = &master->dma_rx->dev->device; + + list_for_each_entry(xfer, &msg->transfers, transfer_list) { + if (!master->can_dma(master, msg->spi, xfer)) + continue; + + spi_unmap_buf(master, rx_dev, &xfer->rx_sg, DMA_FROM_DEVICE); + spi_unmap_buf(master, tx_dev, &xfer->tx_sg, DMA_TO_DEVICE); + } + + return 0; +} + /* * spi_transfer_one_message - Default implementation of transfer_one_message() * @@ -591,9 +754,9 @@ static int spi_transfer_one_message(struct spi_master *master, struct spi_message *msg) { struct spi_transfer *xfer; - bool cur_cs = true; bool keep_cs = false; int ret = 0; + int ms = 1; spi_set_cs(msg->spi, true); @@ -611,7 +774,16 @@ static int spi_transfer_one_message(struct spi_master *master, if (ret > 0) { ret = 0; - wait_for_completion(&master->xfer_completion); + ms = xfer->len * 8 * 1000 / xfer->speed_hz; + ms += 10; /* some tolerance */ + + ms = wait_for_completion_timeout(&master->xfer_completion, + msecs_to_jiffies(ms)); + } + + if (ms == 0) { + dev_err(&msg->spi->dev, "SPI transfer timed out\n"); + msg->status = -ETIMEDOUT; } trace_spi_transfer_stop(msg, xfer); @@ -627,8 +799,9 @@ static int spi_transfer_one_message(struct spi_master *master, &msg->transfers)) { keep_cs = true; } else { - cur_cs = !cur_cs; - spi_set_cs(msg->spi, cur_cs); + spi_set_cs(msg->spi, false); + udelay(10); + spi_set_cs(msg->spi, true); } } @@ -686,6 +859,10 @@ static void spi_pump_messages(struct kthread_work *work) } master->busy = false; spin_unlock_irqrestore(&master->queue_lock, flags); + kfree(master->dummy_rx); + master->dummy_rx = NULL; + kfree(master->dummy_tx); + master->dummy_tx = NULL; if (master->unprepare_transfer_hardware && master->unprepare_transfer_hardware(master)) dev_err(&master->dev, @@ -752,6 +929,13 @@ static void spi_pump_messages(struct kthread_work *work) master->cur_msg_prepared = true; } + ret = spi_map_msg(master, master->cur_msg); + if (ret) { + master->cur_msg->status = ret; + spi_finalize_current_message(master); + return; + } + ret = master->transfer_one_message(master, master->cur_msg); if (ret) { dev_err(&master->dev, @@ -839,6 +1023,8 @@ void spi_finalize_current_message(struct spi_master *master) queue_kthread_work(&master->kworker, &master->pump_messages); spin_unlock_irqrestore(&master->queue_lock, flags); + spi_unmap_msg(master, mesg); + if (master->cur_msg_prepared && master->unprepare_message) { ret = master->unprepare_message(master, mesg); if (ret) { @@ -892,7 +1078,7 @@ static int spi_stop_queue(struct spi_master *master) */ while ((!list_empty(&master->queue) || master->busy) && limit--) { spin_unlock_irqrestore(&master->queue_lock, flags); - msleep(10); + usleep_range(10000, 11000); spin_lock_irqsave(&master->queue_lock, flags); } @@ -1372,6 +1558,8 @@ int spi_register_master(struct spi_master *master) mutex_init(&master->bus_lock_mutex); master->bus_lock_flag = 0; init_completion(&master->xfer_completion); + if (!master->max_dma_len) + master->max_dma_len = INT_MAX; /* register the device, then userspace will see it. * registration fails if the bus ID is in use. @@ -1597,6 +1785,9 @@ int spi_setup(struct spi_device *spi) if (!spi->bits_per_word) spi->bits_per_word = 8; + if (!spi->max_speed_hz) + spi->max_speed_hz = spi->master->max_speed_hz; + if (spi->master->setup) status = spi->master->setup(spi); @@ -1617,11 +1808,10 @@ static int __spi_validate(struct spi_device *spi, struct spi_message *message) { struct spi_master *master = spi->master; struct spi_transfer *xfer; + int w_size; if (list_empty(&message->transfers)) return -EINVAL; - if (!message->complete) - return -EINVAL; /* Half-duplex links include original MicroWire, and ones with * only one data pin like SPI_3WIRE (switches direction) or where @@ -1652,12 +1842,13 @@ static int __spi_validate(struct spi_device *spi, struct spi_message *message) message->frame_length += xfer->len; if (!xfer->bits_per_word) xfer->bits_per_word = spi->bits_per_word; - if (!xfer->speed_hz) { + + if (!xfer->speed_hz) xfer->speed_hz = spi->max_speed_hz; - if (master->max_speed_hz && - xfer->speed_hz > master->max_speed_hz) - xfer->speed_hz = master->max_speed_hz; - } + + if (master->max_speed_hz && + xfer->speed_hz > master->max_speed_hz) + xfer->speed_hz = master->max_speed_hz; if (master->bits_per_word_mask) { /* Only 32 bits fit in the mask */ @@ -1668,12 +1859,24 @@ static int __spi_validate(struct spi_device *spi, struct spi_message *message) return -EINVAL; } + /* + * SPI transfer length should be multiple of SPI word size + * where SPI word size should be power-of-two multiple + */ + if (xfer->bits_per_word <= 8) + w_size = 1; + else if (xfer->bits_per_word <= 16) + w_size = 2; + else + w_size = 4; + + /* No partial transfers accepted */ + if (xfer->len % w_size) + return -EINVAL; + if (xfer->speed_hz && master->min_speed_hz && xfer->speed_hz < master->min_speed_hz) return -EINVAL; - if (xfer->speed_hz && master->max_speed_hz && - xfer->speed_hz > master->max_speed_hz) - return -EINVAL; if (xfer->tx_buf && !xfer->tx_nbits) xfer->tx_nbits = SPI_NBITS_SINGLE; diff --git a/drivers/spi/spidev.c b/drivers/spi/spidev.c index d7c6e36021e..e3bc23bb588 100644 --- a/drivers/spi/spidev.c +++ b/drivers/spi/spidev.c @@ -73,7 +73,8 @@ static DECLARE_BITMAP(minors, N_SPI_MINORS); */ #define SPI_MODE_MASK (SPI_CPHA | SPI_CPOL | SPI_CS_HIGH \ | SPI_LSB_FIRST | SPI_3WIRE | SPI_LOOP \ - | SPI_NO_CS | SPI_READY) + | SPI_NO_CS | SPI_READY | SPI_TX_DUAL \ + | SPI_TX_QUAD | SPI_RX_DUAL | SPI_RX_QUAD) struct spidev_data { dev_t devt; @@ -265,6 +266,8 @@ static int spidev_message(struct spidev_data *spidev, buf += k_tmp->len; k_tmp->cs_change = !!u_tmp->cs_change; + k_tmp->tx_nbits = u_tmp->tx_nbits; + k_tmp->rx_nbits = u_tmp->rx_nbits; k_tmp->bits_per_word = u_tmp->bits_per_word; k_tmp->delay_usecs = u_tmp->delay_usecs; k_tmp->speed_hz = u_tmp->speed_hz; @@ -359,6 +362,10 @@ spidev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) retval = __put_user(spi->mode & SPI_MODE_MASK, (__u8 __user *)arg); break; + case SPI_IOC_RD_MODE32: + retval = __put_user(spi->mode & SPI_MODE_MASK, + (__u32 __user *)arg); + break; case SPI_IOC_RD_LSB_FIRST: retval = __put_user((spi->mode & SPI_LSB_FIRST) ? 1 : 0, (__u8 __user *)arg); @@ -372,9 +379,13 @@ spidev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) /* write requests */ case SPI_IOC_WR_MODE: - retval = __get_user(tmp, (u8 __user *)arg); + case SPI_IOC_WR_MODE32: + if (cmd == SPI_IOC_WR_MODE) + retval = __get_user(tmp, (u8 __user *)arg); + else + retval = __get_user(tmp, (u32 __user *)arg); if (retval == 0) { - u8 save = spi->mode; + u32 save = spi->mode; if (tmp & ~SPI_MODE_MASK) { retval = -EINVAL; @@ -382,18 +393,18 @@ spidev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) } tmp |= spi->mode & ~SPI_MODE_MASK; - spi->mode = (u8)tmp; + spi->mode = (u16)tmp; retval = spi_setup(spi); if (retval < 0) spi->mode = save; else - dev_dbg(&spi->dev, "spi mode %02x\n", tmp); + dev_dbg(&spi->dev, "spi mode %x\n", tmp); } break; case SPI_IOC_WR_LSB_FIRST: retval = __get_user(tmp, (__u8 __user *)arg); if (retval == 0) { - u8 save = spi->mode; + u32 save = spi->mode; if (tmp) spi->mode |= SPI_LSB_FIRST; |