From 104e51af79a0dbb80627d4db5e1421dd2a2f590c Mon Sep 17 00:00:00 2001 From: Jarkko Nikula Date: Fri, 9 Feb 2018 16:31:07 +0200 Subject: spi: pxa2xx: Move SSP idle waiting to cs_deassert() Move SSP idle waiting before CS deassert from error and end of message handling function giveback() to cs_deassert(). This ensures idle waiting is done also if there is CS change between transfers. Signed-off-by: Jarkko Nikula Signed-off-by: Mark Brown --- drivers/spi/spi-pxa2xx.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi-pxa2xx.c b/drivers/spi/spi-pxa2xx.c index b0822d1dba29..31117f9985ea 100644 --- a/drivers/spi/spi-pxa2xx.c +++ b/drivers/spi/spi-pxa2xx.c @@ -415,10 +415,17 @@ static void cs_deassert(struct driver_data *drv_data) { struct chip_data *chip = spi_get_ctldata(drv_data->master->cur_msg->spi); + unsigned long timeout; if (drv_data->ssp_type == CE4100_SSP) return; + /* Wait until SSP becomes idle before deasserting the CS */ + timeout = jiffies + msecs_to_jiffies(10); + while (pxa2xx_spi_read(drv_data, SSSR) & SSSR_BSY && + !time_after(jiffies, timeout)) + cpu_relax(); + if (chip->cs_control) { chip->cs_control(PXA2XX_CS_DEASSERT); return; @@ -563,7 +570,6 @@ static void giveback(struct driver_data *drv_data) { struct spi_transfer* last_transfer; struct spi_message *msg; - unsigned long timeout; msg = drv_data->master->cur_msg; drv_data->cur_transfer = NULL; @@ -575,12 +581,6 @@ static void giveback(struct driver_data *drv_data) if (last_transfer->delay_usecs) udelay(last_transfer->delay_usecs); - /* Wait until SSP becomes idle before deasserting the CS */ - timeout = jiffies + msecs_to_jiffies(10); - while (pxa2xx_spi_read(drv_data, SSSR) & SSSR_BSY && - !time_after(jiffies, timeout)) - cpu_relax(); - /* Drop chip select UNLESS cs_change is true or we are returning * a message with an error, or next message is for another chip */ -- cgit v1.2.3 From e3d001a0c29d6c9a87dd9e86bcb84fc66c2ddbe8 Mon Sep 17 00:00:00 2001 From: Ulf Magnusson Date: Thu, 8 Feb 2018 23:00:16 +0100 Subject: spi: kconfig: Remove AVR32 dep. from SPI_ATMEL The AVR32 symbol was removed in commit 26202873bb51 ("avr32: remove support for AVR32 architecture"). Signed-off-by: Ulf Magnusson Signed-off-by: Mark Brown --- drivers/spi/Kconfig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/spi') diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index 603783976b81..6fb0347a24f2 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -72,10 +72,10 @@ config SPI_ARMADA_3700 config SPI_ATMEL tristate "Atmel SPI Controller" depends on HAS_DMA - depends on (ARCH_AT91 || AVR32 || COMPILE_TEST) + depends on (ARCH_AT91 || COMPILE_TEST) help This selects a driver for the Atmel SPI Controller, present on - many AT32 (AVR32) and AT91 (ARM) chips. + many AT91 (ARM) chips. config SPI_AU1550 tristate "Au1550/Au1200/Au1300 SPI Controller" -- cgit v1.2.3 From 721483e28889431426a15fe906f48aacd17f0999 Mon Sep 17 00:00:00 2001 From: Jarkko Nikula Date: Thu, 1 Feb 2018 17:17:29 +0200 Subject: spi: dw: Convert to generalized SPI controller API Convert to generalized SPI controller API introduced by the commit 8caab75fd2c2 ("spi: Generalize SPI "master" to "controller""). Inside driver variable name "master" is still used to indicate the driver is master only. Signed-off-by: Jarkko Nikula Signed-off-by: Mark Brown --- drivers/spi/spi-dw-mid.c | 6 +++--- drivers/spi/spi-dw.c | 26 +++++++++++++------------- drivers/spi/spi-dw.h | 4 ++-- 3 files changed, 18 insertions(+), 18 deletions(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi-dw-mid.c b/drivers/spi/spi-dw-mid.c index 837cb8d0bac6..3db905f5f345 100644 --- a/drivers/spi/spi-dw-mid.c +++ b/drivers/spi/spi-dw-mid.c @@ -112,10 +112,10 @@ static irqreturn_t dma_transfer(struct dw_spi *dws) return IRQ_HANDLED; } -static bool mid_spi_can_dma(struct spi_master *master, struct spi_device *spi, - struct spi_transfer *xfer) +static bool mid_spi_can_dma(struct spi_controller *master, + struct spi_device *spi, struct spi_transfer *xfer) { - struct dw_spi *dws = spi_master_get_devdata(master); + struct dw_spi *dws = spi_controller_get_devdata(master); if (!dws->dma_inited) return false; diff --git a/drivers/spi/spi-dw.c b/drivers/spi/spi-dw.c index 211cc7d75bf8..f693bfe95ab9 100644 --- a/drivers/spi/spi-dw.c +++ b/drivers/spi/spi-dw.c @@ -135,7 +135,7 @@ static inline void dw_spi_debugfs_remove(struct dw_spi *dws) static void dw_spi_set_cs(struct spi_device *spi, bool enable) { - struct dw_spi *dws = spi_master_get_devdata(spi->master); + struct dw_spi *dws = spi_controller_get_devdata(spi->controller); struct chip_data *chip = spi_get_ctldata(spi); /* Chip select logic is inverted from spi_set_cs() */ @@ -250,8 +250,8 @@ static irqreturn_t interrupt_transfer(struct dw_spi *dws) static irqreturn_t dw_spi_irq(int irq, void *dev_id) { - struct spi_master *master = dev_id; - struct dw_spi *dws = spi_master_get_devdata(master); + struct spi_controller *master = dev_id; + struct dw_spi *dws = spi_controller_get_devdata(master); u16 irq_status = dw_readl(dws, DW_SPI_ISR) & 0x3f; if (!irq_status) @@ -277,10 +277,10 @@ static int poll_transfer(struct dw_spi *dws) return 0; } -static int dw_spi_transfer_one(struct spi_master *master, +static int dw_spi_transfer_one(struct spi_controller *master, struct spi_device *spi, struct spi_transfer *transfer) { - struct dw_spi *dws = spi_master_get_devdata(master); + struct dw_spi *dws = spi_controller_get_devdata(master); struct chip_data *chip = spi_get_ctldata(spi); u8 imask = 0; u16 txlevel = 0; @@ -383,10 +383,10 @@ static int dw_spi_transfer_one(struct spi_master *master, return 1; } -static void dw_spi_handle_err(struct spi_master *master, +static void dw_spi_handle_err(struct spi_controller *master, struct spi_message *msg) { - struct dw_spi *dws = spi_master_get_devdata(master); + struct dw_spi *dws = spi_controller_get_devdata(master); if (dws->dma_mapped) dws->dma_ops->dma_stop(dws); @@ -471,7 +471,7 @@ static void spi_hw_init(struct device *dev, struct dw_spi *dws) int dw_spi_add_host(struct device *dev, struct dw_spi *dws) { - struct spi_master *master; + struct spi_controller *master; int ret; BUG_ON(dws == NULL); @@ -518,8 +518,8 @@ int dw_spi_add_host(struct device *dev, struct dw_spi *dws) } } - spi_master_set_devdata(master, dws); - ret = devm_spi_register_master(dev, master); + spi_controller_set_devdata(master, dws); + ret = devm_spi_register_controller(dev, master); if (ret) { dev_err(&master->dev, "problem registering spi master\n"); goto err_dma_exit; @@ -534,7 +534,7 @@ err_dma_exit: spi_enable_chip(dws, 0); free_irq(dws->irq, master); err_free_master: - spi_master_put(master); + spi_controller_put(master); return ret; } EXPORT_SYMBOL_GPL(dw_spi_add_host); @@ -556,7 +556,7 @@ int dw_spi_suspend_host(struct dw_spi *dws) { int ret; - ret = spi_master_suspend(dws->master); + ret = spi_controller_suspend(dws->master); if (ret) return ret; @@ -570,7 +570,7 @@ int dw_spi_resume_host(struct dw_spi *dws) int ret; spi_hw_init(&dws->master->dev, dws); - ret = spi_master_resume(dws->master); + ret = spi_controller_resume(dws->master); if (ret) dev_err(&dws->master->dev, "fail to start queue (%d)\n", ret); return ret; diff --git a/drivers/spi/spi-dw.h b/drivers/spi/spi-dw.h index 5c07cf8f19e0..2cde2473b3e9 100644 --- a/drivers/spi/spi-dw.h +++ b/drivers/spi/spi-dw.h @@ -93,14 +93,14 @@ struct dw_spi_dma_ops { int (*dma_init)(struct dw_spi *dws); void (*dma_exit)(struct dw_spi *dws); int (*dma_setup)(struct dw_spi *dws, struct spi_transfer *xfer); - bool (*can_dma)(struct spi_master *master, struct spi_device *spi, + bool (*can_dma)(struct spi_controller *master, struct spi_device *spi, struct spi_transfer *xfer); int (*dma_transfer)(struct dw_spi *dws, struct spi_transfer *xfer); void (*dma_stop)(struct dw_spi *dws); }; struct dw_spi { - struct spi_master *master; + struct spi_controller *master; enum dw_ssi_type type; void __iomem *regs; -- cgit v1.2.3 From 3cc7b0e35745ae4e153f174038df34a79a385b32 Mon Sep 17 00:00:00 2001 From: Jarkko Nikula Date: Thu, 1 Feb 2018 17:17:30 +0200 Subject: spi: pxa2xx: Convert to generalized SPI controller API Convert to generalized SPI controller API introduced by the commit 8caab75fd2c2 ("spi: Generalize SPI "master" to "controller""). Inside driver variable name "master" is still used to indicate the driver is master only. While at it, change "unsigned cs" to "unsigned int cs" in pxa2xx_spi_fw_translate_cs() to suppress checkpatch warning. Signed-off-by: Jarkko Nikula Signed-off-by: Mark Brown --- drivers/spi/spi-pxa2xx-dma.c | 4 ++-- drivers/spi/spi-pxa2xx.c | 40 ++++++++++++++++++++++------------------ drivers/spi/spi-pxa2xx.h | 2 +- 3 files changed, 25 insertions(+), 21 deletions(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi-pxa2xx-dma.c b/drivers/spi/spi-pxa2xx-dma.c index 04f3eecf5cf3..3d7f66080c57 100644 --- a/drivers/spi/spi-pxa2xx-dma.c +++ b/drivers/spi/spi-pxa2xx-dma.c @@ -191,7 +191,7 @@ int pxa2xx_spi_dma_setup(struct driver_data *drv_data) { struct pxa2xx_spi_master *pdata = drv_data->master_info; struct device *dev = &drv_data->pdev->dev; - struct spi_master *master = drv_data->master; + struct spi_controller *master = drv_data->master; dma_cap_mask_t mask; dma_cap_zero(mask); @@ -215,7 +215,7 @@ int pxa2xx_spi_dma_setup(struct driver_data *drv_data) void pxa2xx_spi_dma_release(struct driver_data *drv_data) { - struct spi_master *master = drv_data->master; + struct spi_controller *master = drv_data->master; if (master->dma_rx) { dmaengine_terminate_sync(master->dma_rx); diff --git a/drivers/spi/spi-pxa2xx.c b/drivers/spi/spi-pxa2xx.c index 31117f9985ea..713506eff07d 100644 --- a/drivers/spi/spi-pxa2xx.c +++ b/drivers/spi/spi-pxa2xx.c @@ -962,7 +962,7 @@ static unsigned int pxa2xx_ssp_get_clk_div(struct driver_data *drv_data, return clk_div << 8; } -static bool pxa2xx_spi_can_dma(struct spi_master *master, +static bool pxa2xx_spi_can_dma(struct spi_controller *master, struct spi_device *spi, struct spi_transfer *xfer) { @@ -976,7 +976,7 @@ static bool pxa2xx_spi_can_dma(struct spi_master *master, static void pump_transfers(unsigned long data) { struct driver_data *drv_data = (struct driver_data *)data; - struct spi_master *master = drv_data->master; + struct spi_controller *master = drv_data->master; struct spi_message *message = master->cur_msg; struct chip_data *chip = spi_get_ctldata(message->spi); u32 dma_thresh = chip->dma_threshold; @@ -1182,10 +1182,10 @@ static void pump_transfers(unsigned long data) pxa2xx_spi_write(drv_data, SSCR1, cr1); } -static int pxa2xx_spi_transfer_one_message(struct spi_master *master, +static int pxa2xx_spi_transfer_one_message(struct spi_controller *master, struct spi_message *msg) { - struct driver_data *drv_data = spi_master_get_devdata(master); + struct driver_data *drv_data = spi_controller_get_devdata(master); /* Initial message state*/ msg->state = START_STATE; @@ -1198,9 +1198,9 @@ static int pxa2xx_spi_transfer_one_message(struct spi_master *master, return 0; } -static int pxa2xx_spi_unprepare_transfer(struct spi_master *master) +static int pxa2xx_spi_unprepare_transfer(struct spi_controller *master) { - struct driver_data *drv_data = spi_master_get_devdata(master); + struct driver_data *drv_data = spi_controller_get_devdata(master); /* Disable the SSP now */ pxa2xx_spi_write(drv_data, SSCR0, @@ -1212,7 +1212,8 @@ static int pxa2xx_spi_unprepare_transfer(struct spi_master *master) static int setup_cs(struct spi_device *spi, struct chip_data *chip, struct pxa2xx_spi_chip *chip_info) { - struct driver_data *drv_data = spi_master_get_devdata(spi->master); + struct driver_data *drv_data = + spi_controller_get_devdata(spi->controller); struct gpio_desc *gpiod; int err = 0; @@ -1270,7 +1271,8 @@ static int setup(struct spi_device *spi) struct pxa2xx_spi_chip *chip_info; struct chip_data *chip; const struct lpss_config *config; - struct driver_data *drv_data = spi_master_get_devdata(spi->master); + struct driver_data *drv_data = + spi_controller_get_devdata(spi->controller); uint tx_thres, tx_hi_thres, rx_thres; switch (drv_data->ssp_type) { @@ -1410,7 +1412,8 @@ static int setup(struct spi_device *spi) static void cleanup(struct spi_device *spi) { struct chip_data *chip = spi_get_ctldata(spi); - struct driver_data *drv_data = spi_master_get_devdata(spi->master); + struct driver_data *drv_data = + spi_controller_get_devdata(spi->controller); if (!chip) return; @@ -1575,9 +1578,10 @@ pxa2xx_spi_init_pdata(struct platform_device *pdev) } #endif -static int pxa2xx_spi_fw_translate_cs(struct spi_master *master, unsigned cs) +static int pxa2xx_spi_fw_translate_cs(struct spi_controller *master, + unsigned int cs) { - struct driver_data *drv_data = spi_master_get_devdata(master); + struct driver_data *drv_data = spi_controller_get_devdata(master); if (has_acpi_companion(&drv_data->pdev->dev)) { switch (drv_data->ssp_type) { @@ -1602,7 +1606,7 @@ static int pxa2xx_spi_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct pxa2xx_spi_master *platform_info; - struct spi_master *master; + struct spi_controller *master; struct driver_data *drv_data; struct ssp_device *ssp; const struct lpss_config *config; @@ -1633,7 +1637,7 @@ static int pxa2xx_spi_probe(struct platform_device *pdev) pxa_ssp_free(ssp); return -ENOMEM; } - drv_data = spi_master_get_devdata(master); + drv_data = spi_controller_get_devdata(master); drv_data->master = master; drv_data->master_info = platform_info; drv_data->pdev = pdev; @@ -1651,7 +1655,7 @@ static int pxa2xx_spi_probe(struct platform_device *pdev) master->unprepare_transfer_hardware = pxa2xx_spi_unprepare_transfer; master->fw_translate_cs = pxa2xx_spi_fw_translate_cs; master->auto_runtime_pm = true; - master->flags = SPI_MASTER_MUST_RX | SPI_MASTER_MUST_TX; + master->flags = SPI_CONTROLLER_MUST_RX | SPI_CONTROLLER_MUST_TX; drv_data->ssp_type = ssp->type; @@ -1793,7 +1797,7 @@ static int pxa2xx_spi_probe(struct platform_device *pdev) /* Register with the SPI framework */ platform_set_drvdata(pdev, drv_data); - status = devm_spi_register_master(&pdev->dev, master); + status = devm_spi_register_controller(&pdev->dev, master); if (status != 0) { dev_err(&pdev->dev, "problem registering spi master\n"); goto out_error_clock_enabled; @@ -1807,7 +1811,7 @@ out_error_clock_enabled: free_irq(ssp->irq, drv_data); out_error_master_alloc: - spi_master_put(master); + spi_controller_put(master); pxa_ssp_free(ssp); return status; } @@ -1858,7 +1862,7 @@ static int pxa2xx_spi_suspend(struct device *dev) struct ssp_device *ssp = drv_data->ssp; int status; - status = spi_master_suspend(drv_data->master); + status = spi_controller_suspend(drv_data->master); if (status != 0) return status; pxa2xx_spi_write(drv_data, SSCR0, 0); @@ -1884,7 +1888,7 @@ static int pxa2xx_spi_resume(struct device *dev) lpss_ssp_setup(drv_data); /* Start the queue running */ - status = spi_master_resume(drv_data->master); + status = spi_controller_resume(drv_data->master); if (status != 0) { dev_err(dev, "problem starting queue (%d)\n", status); return status; diff --git a/drivers/spi/spi-pxa2xx.h b/drivers/spi/spi-pxa2xx.h index 94f7b0713281..513ec6c6e25b 100644 --- a/drivers/spi/spi-pxa2xx.h +++ b/drivers/spi/spi-pxa2xx.h @@ -31,7 +31,7 @@ struct driver_data { /* SPI framework hookup */ enum pxa_ssp_type ssp_type; - struct spi_master *master; + struct spi_controller *master; /* PXA hookup */ struct pxa2xx_spi_master *master_info; -- cgit v1.2.3 From 9b00bc7b901ff672a9252002d3810fdf9489bc64 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Mon, 12 Feb 2018 13:45:30 +0100 Subject: spi: spi-gpio: Rewrite to use GPIO descriptors This converts the bit-banged GPIO SPI driver to looking up and using GPIO descriptors to get a handle on GPIO lines for SCK, MOSI, MISO and all CS lines. All existing board files are converted in one go to keep it all consistent. With these conversions I rarely find any interrim steps that makes any sense. Device tree probing and GPIO handling should work like before also after this patch. For board files, we stop using controller data to pass the GPIO line for chip select, instead we pass this as a GPIO descriptor lookup like everything else. In some s3c24xx machines the names of the SPI devices were set to "spi-gpio" rather than "spi_gpio" which can never have worked, I fixed it working (I guess) as part of this patch set. Sometimes I wonder how this code got upstream in the first place, it obviously is not tested. mach-s3c64xx/mach-smartq.c has the same problem and additionally defines the *same* GPIO line for MOSI and MISO which is not going to be accepted by gpiolib. As the lines were number 1,2,2 I assumed it was a typo and use lines 1,2,3. A comment gives awat that line 0 is chip select though no actual SPI device is provided for the LCD supposed to be on this bit-banged SPI bus. I left it intact instead of just deleting the bus though. Kill off board file code that try to initialize the SPI lines to the same values that they will later be set by the spi_gpio driver anyways. Given the huge number of weird things in these board files I do not think this code is very tested or put in with much afterthought anyways. In order to assert that we do not get performance regressions on this crucial bing-banged driver, a ran a script like this dumping the Ilitek ILI9322 regmap 10000 times (it has no caching obviously) on an otherwise idle system in two iterations before and after the patches: #!/bin/sh for run in `seq 10000` do cat /debug/regmap/spi0.0/registers > /dev/null done Before the patch: time test.sh real 3m 41.03s user 0m 29.41s sys 3m 7.22s time test.sh real 3m 44.24s user 0m 32.31s sys 3m 7.60s After the patch: time test.sh real 3m 41.32s user 0m 28.92s sys 3m 8.08s time test.sh real 3m 39.92s user 0m 30.20s sys 3m 5.56s So any performance differences seems to be in the error margin. Signed-off-by: Linus Walleij Acked-by: Olof Johansson Reviewed-by: Andy Shevchenko Signed-off-by: Mark Brown --- arch/arm/mach-pxa/cm-x300.c | 21 ++- arch/arm/mach-pxa/raumfeld.c | 26 +++- arch/arm/mach-s3c24xx/mach-jive.c | 55 ++++--- arch/arm/mach-s3c24xx/mach-qt2410.c | 26 +++- arch/arm/mach-s3c64xx/mach-smartq.c | 22 ++- arch/mips/alchemy/devboards/db1000.c | 24 ++- arch/mips/jz4740/board-qi_lb60.c | 26 +++- drivers/misc/eeprom/digsy_mtc_eeprom.c | 29 +++- drivers/spi/spi-gpio.c | 270 +++++++++++---------------------- include/linux/spi/spi_gpio.h | 49 +----- 10 files changed, 262 insertions(+), 286 deletions(-) (limited to 'drivers/spi') diff --git a/arch/arm/mach-pxa/cm-x300.c b/arch/arm/mach-pxa/cm-x300.c index c487401b6fdb..69d7f48a4183 100644 --- a/arch/arm/mach-pxa/cm-x300.c +++ b/arch/arm/mach-pxa/cm-x300.c @@ -23,6 +23,7 @@ #include #include +#include #include #include #include @@ -343,9 +344,6 @@ static inline void cm_x300_init_bl(void) {} #define LCD_SPI_BUS_NUM (1) static struct spi_gpio_platform_data cm_x300_spi_gpio_pdata = { - .sck = GPIO_LCD_SCL, - .mosi = GPIO_LCD_DIN, - .miso = GPIO_LCD_DOUT, .num_chipselect = 1, }; @@ -357,6 +355,21 @@ static struct platform_device cm_x300_spi_gpio = { }, }; +static struct gpiod_lookup_table cm_x300_spi_gpiod_table = { + .dev_id = "spi_gpio", + .table = { + GPIO_LOOKUP("gpio-pxa", GPIO_LCD_SCL, + "sck", GPIO_ACTIVE_HIGH), + GPIO_LOOKUP("gpio-pxa", GPIO_LCD_DIN, + "mosi", GPIO_ACTIVE_HIGH), + GPIO_LOOKUP("gpio-pxa", GPIO_LCD_DOUT, + "miso", GPIO_ACTIVE_HIGH), + GPIO_LOOKUP("gpio-pxa", GPIO_LCD_CS, + "cs", GPIO_ACTIVE_HIGH), + { }, + }, +}; + static struct tdo24m_platform_data cm_x300_tdo24m_pdata = { .model = TDO35S, }; @@ -367,7 +380,6 @@ static struct spi_board_info cm_x300_spi_devices[] __initdata = { .max_speed_hz = 1000000, .bus_num = LCD_SPI_BUS_NUM, .chip_select = 0, - .controller_data = (void *) GPIO_LCD_CS, .platform_data = &cm_x300_tdo24m_pdata, }, }; @@ -376,6 +388,7 @@ static void __init cm_x300_init_spi(void) { spi_register_board_info(cm_x300_spi_devices, ARRAY_SIZE(cm_x300_spi_devices)); + gpiod_add_lookup_table(&cm_x300_spi_gpiod_table); platform_device_register(&cm_x300_spi_gpio); } #else diff --git a/arch/arm/mach-pxa/raumfeld.c b/arch/arm/mach-pxa/raumfeld.c index 4d5d05cf87d6..e7ac7dcb95e9 100644 --- a/arch/arm/mach-pxa/raumfeld.c +++ b/arch/arm/mach-pxa/raumfeld.c @@ -646,9 +646,6 @@ static void __init raumfeld_lcd_init(void) */ static struct spi_gpio_platform_data raumfeld_spi_platform_data = { - .sck = GPIO_SPI_CLK, - .mosi = GPIO_SPI_MOSI, - .miso = GPIO_SPI_MISO, .num_chipselect = 3, }; @@ -660,6 +657,25 @@ static struct platform_device raumfeld_spi_device = { } }; +static struct gpiod_lookup_table raumfeld_spi_gpiod_table = { + .dev_id = "spi_gpio", + .table = { + GPIO_LOOKUP("gpio-0", GPIO_SPI_CLK, + "sck", GPIO_ACTIVE_HIGH), + GPIO_LOOKUP("gpio-0", GPIO_SPI_MOSI, + "mosi", GPIO_ACTIVE_HIGH), + GPIO_LOOKUP("gpio-0", GPIO_SPI_MISO, + "miso", GPIO_ACTIVE_HIGH), + GPIO_LOOKUP_IDX("gpio-0", GPIO_SPDIF_CS, + "cs", 0, GPIO_ACTIVE_HIGH), + GPIO_LOOKUP_IDX("gpio-0", GPIO_ACCEL_CS, + "cs", 1, GPIO_ACTIVE_HIGH), + GPIO_LOOKUP_IDX("gpio-0", GPIO_MCLK_DAC_CS, + "cs", 2, GPIO_ACTIVE_HIGH), + { }, + }, +}; + static struct lis3lv02d_platform_data lis3_pdata = { .click_flags = LIS3_CLICK_SINGLE_X | LIS3_CLICK_SINGLE_Y | @@ -680,7 +696,6 @@ static struct lis3lv02d_platform_data lis3_pdata = { .max_speed_hz = 10000, \ .bus_num = 0, \ .chip_select = 0, \ - .controller_data = (void *) GPIO_SPDIF_CS, \ } #define SPI_LIS3 \ @@ -689,7 +704,6 @@ static struct lis3lv02d_platform_data lis3_pdata = { .max_speed_hz = 1000000, \ .bus_num = 0, \ .chip_select = 1, \ - .controller_data = (void *) GPIO_ACCEL_CS, \ .platform_data = &lis3_pdata, \ .irq = PXA_GPIO_TO_IRQ(GPIO_ACCEL_IRQ), \ } @@ -700,7 +714,6 @@ static struct lis3lv02d_platform_data lis3_pdata = { .max_speed_hz = 1000000, \ .bus_num = 0, \ .chip_select = 2, \ - .controller_data = (void *) GPIO_MCLK_DAC_CS, \ } static struct spi_board_info connector_spi_devices[] __initdata = { @@ -1066,6 +1079,7 @@ static void __init raumfeld_common_init(void) else gpio_direction_output(GPIO_SHUTDOWN_SUPPLY, 0); + gpiod_add_lookup_table(&raumfeld_spi_gpiod_table); platform_add_devices(ARRAY_AND_SIZE(raumfeld_common_devices)); i2c_register_board_info(1, &raumfeld_pwri2c_board_info, 1); } diff --git a/arch/arm/mach-s3c24xx/mach-jive.c b/arch/arm/mach-s3c24xx/mach-jive.c index a3ddbbbd6d92..59589a4a0d4b 100644 --- a/arch/arm/mach-s3c24xx/mach-jive.c +++ b/arch/arm/mach-s3c24xx/mach-jive.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -388,32 +389,53 @@ static struct ili9320_platdata jive_lcm_config = { /* LCD SPI support */ static struct spi_gpio_platform_data jive_lcd_spi = { - .sck = S3C2410_GPG(8), - .mosi = S3C2410_GPB(8), - .miso = SPI_GPIO_NO_MISO, + .num_chipselect = 1, }; static struct platform_device jive_device_lcdspi = { - .name = "spi-gpio", + .name = "spi_gpio", .id = 1, .dev.platform_data = &jive_lcd_spi, }; +static struct gpiod_lookup_table jive_lcdspi_gpiod_table = { + .dev_id = "spi_gpio", + .table = { + GPIO_LOOKUP("GPIOG", 8, + "sck", GPIO_ACTIVE_HIGH), + GPIO_LOOKUP("GPIOB", 8, + "mosi", GPIO_ACTIVE_HIGH), + GPIO_LOOKUP("GPIOB", 7, + "cs", GPIO_ACTIVE_HIGH), + { }, + }, +}; /* WM8750 audio code SPI definition */ static struct spi_gpio_platform_data jive_wm8750_spi = { - .sck = S3C2410_GPB(4), - .mosi = S3C2410_GPB(9), - .miso = SPI_GPIO_NO_MISO, + .num_chipselect = 1, }; static struct platform_device jive_device_wm8750 = { - .name = "spi-gpio", + .name = "spi_gpio", .id = 2, .dev.platform_data = &jive_wm8750_spi, }; +static struct gpiod_lookup_table jive_wm8750_gpiod_table = { + .dev_id = "spi_gpio", + .table = { + GPIO_LOOKUP("GPIOB", 4, + "gpio-sck", GPIO_ACTIVE_HIGH), + GPIO_LOOKUP("GPIOB", 9, + "gpio-mosi", GPIO_ACTIVE_HIGH), + GPIO_LOOKUP("GPIOH", 10, + "cs", GPIO_ACTIVE_HIGH), + { }, + }, +}; + /* JIVE SPI devices. */ static struct spi_board_info __initdata jive_spi_devs[] = { @@ -424,14 +446,12 @@ static struct spi_board_info __initdata jive_spi_devs[] = { .mode = SPI_MODE_3, /* CPOL=1, CPHA=1 */ .max_speed_hz = 100000, .platform_data = &jive_lcm_config, - .controller_data = (void *)S3C2410_GPB(7), }, { .modalias = "WM8750", .bus_num = 2, .chip_select = 0, .mode = SPI_MODE_0, /* CPOL=0, CPHA=0 */ .max_speed_hz = 100000, - .controller_data = (void *)S3C2410_GPH(10), }, }; @@ -619,25 +639,12 @@ static void __init jive_machine_init(void) /** TODO - check that this is after the cmdline option! */ s3c_nand_set_platdata(&jive_nand_info); - /* initialise the spi */ - gpio_request(S3C2410_GPG(13), "lcm reset"); gpio_direction_output(S3C2410_GPG(13), 0); - gpio_request(S3C2410_GPB(7), "jive spi"); - gpio_direction_output(S3C2410_GPB(7), 1); - gpio_request_one(S3C2410_GPB(6), GPIOF_OUT_INIT_LOW, NULL); gpio_free(S3C2410_GPB(6)); - gpio_request_one(S3C2410_GPG(8), GPIOF_OUT_INIT_HIGH, NULL); - gpio_free(S3C2410_GPG(8)); - - /* initialise the WM8750 spi */ - - gpio_request(S3C2410_GPH(10), "jive wm8750 spi"); - gpio_direction_output(S3C2410_GPH(10), 1); - /* Turn off suspend on both USB ports, and switch the * selectable USB port to USB device mode. */ @@ -655,6 +662,8 @@ static void __init jive_machine_init(void) pm_power_off = jive_power_off; + gpiod_add_lookup_table(&jive_lcdspi_gpiod_table); + gpiod_add_lookup_table(&jive_wm8750_gpiod_table); platform_add_devices(jive_devices, ARRAY_SIZE(jive_devices)); } diff --git a/arch/arm/mach-s3c24xx/mach-qt2410.c b/arch/arm/mach-s3c24xx/mach-qt2410.c index 9c8373b8d9c3..5d48e5b6e738 100644 --- a/arch/arm/mach-s3c24xx/mach-qt2410.c +++ b/arch/arm/mach-s3c24xx/mach-qt2410.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -194,17 +195,30 @@ static struct platform_device qt2410_led = { /* SPI */ static struct spi_gpio_platform_data spi_gpio_cfg = { - .sck = S3C2410_GPG(7), - .mosi = S3C2410_GPG(6), - .miso = S3C2410_GPG(5), + .num_chipselect = 1, }; static struct platform_device qt2410_spi = { - .name = "spi-gpio", + .name = "spi_gpio", .id = 1, .dev.platform_data = &spi_gpio_cfg, }; +static struct gpiod_lookup_table qt2410_spi_gpiod_table = { + .dev_id = "spi_gpio", + .table = { + GPIO_LOOKUP("GPIOG", 7, + "sck", GPIO_ACTIVE_HIGH), + GPIO_LOOKUP("GPIOG", 6, + "mosi", GPIO_ACTIVE_HIGH), + GPIO_LOOKUP("GPIOG", 5, + "miso", GPIO_ACTIVE_HIGH), + GPIO_LOOKUP("GPIOB", 5, + "cs", GPIO_ACTIVE_HIGH), + { }, + }, +}; + /* Board devices */ static struct platform_device *qt2410_devices[] __initdata = { @@ -323,9 +337,7 @@ static void __init qt2410_machine_init(void) s3c24xx_udc_set_platdata(&qt2410_udc_cfg); s3c_i2c0_set_platdata(NULL); - WARN_ON(gpio_request(S3C2410_GPB(5), "spi cs")); - gpio_direction_output(S3C2410_GPB(5), 1); - + gpiod_add_lookup_table(&qt2410_spi_gpiod_table); platform_add_devices(qt2410_devices, ARRAY_SIZE(qt2410_devices)); s3c_pm_init(); } diff --git a/arch/arm/mach-s3c64xx/mach-smartq.c b/arch/arm/mach-s3c64xx/mach-smartq.c index 5655fe968b1f..951208f168e7 100644 --- a/arch/arm/mach-s3c64xx/mach-smartq.c +++ b/arch/arm/mach-s3c64xx/mach-smartq.c @@ -206,17 +206,30 @@ static int __init smartq_lcd_setup_gpio(void) /* GPM0 -> CS */ static struct spi_gpio_platform_data smartq_lcd_control = { - .sck = S3C64XX_GPM(1), - .mosi = S3C64XX_GPM(2), - .miso = S3C64XX_GPM(2), + .num_chipselect = 1, }; static struct platform_device smartq_lcd_control_device = { - .name = "spi-gpio", + .name = "spi_gpio", .id = 1, .dev.platform_data = &smartq_lcd_control, }; +static struct gpiod_lookup_table smartq_lcd_control_gpiod_table = { + .dev_id = "spi_gpio", + .table = { + GPIO_LOOKUP("GPIOM", 1, + "sck", GPIO_ACTIVE_HIGH), + GPIO_LOOKUP("GPIOM", 2, + "mosi", GPIO_ACTIVE_HIGH), + GPIO_LOOKUP("GPIOM", 3, + "miso", GPIO_ACTIVE_HIGH), + GPIO_LOOKUP("GPIOM", 0, + "cs", GPIO_ACTIVE_HIGH), + { }, + }, +}; + static void smartq_lcd_power_set(struct plat_lcd_data *pd, unsigned int power) { gpio_direction_output(S3C64XX_GPM(3), power); @@ -404,6 +417,7 @@ void __init smartq_machine_init(void) WARN_ON(smartq_wifi_init()); pwm_add_table(smartq_pwm_lookup, ARRAY_SIZE(smartq_pwm_lookup)); + gpiod_add_lookup_table(&smartq_lcd_control_gpiod_table); platform_add_devices(smartq_devices, ARRAY_SIZE(smartq_devices)); gpiod_add_lookup_table(&smartq_audio_gpios); diff --git a/arch/mips/alchemy/devboards/db1000.c b/arch/mips/alchemy/devboards/db1000.c index 433c4b9a9f0a..13e3c84859fe 100644 --- a/arch/mips/alchemy/devboards/db1000.c +++ b/arch/mips/alchemy/devboards/db1000.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -447,9 +448,6 @@ static struct ads7846_platform_data db1100_touch_pd = { }; static struct spi_gpio_platform_data db1100_spictl_pd = { - .sck = 209, - .mosi = 208, - .miso = 207, .num_chipselect = 1, }; @@ -462,7 +460,6 @@ static struct spi_board_info db1100_spi_info[] __initdata = { .mode = 0, .irq = AU1100_GPIO21_INT, .platform_data = &db1100_touch_pd, - .controller_data = (void *)210, /* for spi_gpio: CS# GPIO210 */ }, }; @@ -474,6 +471,24 @@ static struct platform_device db1100_spi_dev = { }, }; +/* + * Alchemy GPIO 2 has its base at 200 so the GPIO lines + * 207 thru 210 are GPIOs at offset 7 thru 10 at this chip. + */ +static struct gpiod_lookup_table db1100_spi_gpiod_table = { + .dev_id = "spi_gpio", + .table = { + GPIO_LOOKUP("alchemy-gpio2", 9, + "sck", GPIO_ACTIVE_HIGH), + GPIO_LOOKUP("alchemy-gpio2", 8, + "mosi", GPIO_ACTIVE_HIGH), + GPIO_LOOKUP("alchemy-gpio2", 7, + "miso", GPIO_ACTIVE_HIGH), + GPIO_LOOKUP("alchemy-gpio2", 10, + "cs", GPIO_ACTIVE_HIGH), + { }, + }, +}; static struct platform_device *db1x00_devs[] = { &db1x00_codec_dev, @@ -541,6 +556,7 @@ int __init db1000_dev_setup(void) clk_put(p); platform_add_devices(db1100_devs, ARRAY_SIZE(db1100_devs)); + gpiod_add_lookup_table(&db1100_spi_gpiod_table); platform_device_register(&db1100_spi_dev); } else if (board == BCSR_WHOAMI_DB1000) { c0 = AU1000_GPIO2_INT; diff --git a/arch/mips/jz4740/board-qi_lb60.c b/arch/mips/jz4740/board-qi_lb60.c index 6d7f97552200..60f0767507c6 100644 --- a/arch/mips/jz4740/board-qi_lb60.c +++ b/arch/mips/jz4740/board-qi_lb60.c @@ -313,25 +313,34 @@ static struct jz4740_fb_platform_data qi_lb60_fb_pdata = { .pixclk_falling_edge = 1, }; -struct spi_gpio_platform_data spigpio_platform_data = { - .sck = JZ_GPIO_PORTC(23), - .mosi = JZ_GPIO_PORTC(22), - .miso = -1, +struct spi_gpio_platform_data qi_lb60_spigpio_platform_data = { .num_chipselect = 1, }; -static struct platform_device spigpio_device = { +static struct platform_device qi_lb60_spigpio_device = { .name = "spi_gpio", .id = 1, .dev = { - .platform_data = &spigpio_platform_data, + .platform_data = &qi_lb60_spigpio_platform_data, + }, +}; + +static struct gpiod_lookup_table qi_lb60_spigpio_gpio_table = { + .dev_id = "spi_gpio", + .table = { + GPIO_LOOKUP("GPIOC", 23, + "sck", GPIO_ACTIVE_HIGH), + GPIO_LOOKUP("GPIOC", 22, + "mosi", GPIO_ACTIVE_HIGH), + GPIO_LOOKUP("GPIOC", 21, + "cs", GPIO_ACTIVE_HIGH), + { }, }, }; static struct spi_board_info qi_lb60_spi_board_info[] = { { .modalias = "ili8960", - .controller_data = (void *)JZ_GPIO_PORTC(21), .chip_select = 0, .bus_num = 1, .max_speed_hz = 30 * 1000, @@ -435,7 +444,7 @@ static struct platform_device *jz_platform_devices[] __initdata = { &jz4740_mmc_device, &jz4740_nand_device, &qi_lb60_keypad, - &spigpio_device, + &qi_lb60_spigpio_device, &jz4740_framebuffer_device, &jz4740_pcm_device, &jz4740_i2s_device, @@ -489,6 +498,7 @@ static int __init qi_lb60_init_platform_devices(void) gpiod_add_lookup_table(&qi_lb60_audio_gpio_table); gpiod_add_lookup_table(&qi_lb60_nand_gpio_table); + gpiod_add_lookup_table(&qi_lb60_spigpio_gpio_table); spi_register_board_info(qi_lb60_spi_board_info, ARRAY_SIZE(qi_lb60_spi_board_info)); diff --git a/drivers/misc/eeprom/digsy_mtc_eeprom.c b/drivers/misc/eeprom/digsy_mtc_eeprom.c index 66d9e1baeae5..fbde2516c04f 100644 --- a/drivers/misc/eeprom/digsy_mtc_eeprom.c +++ b/drivers/misc/eeprom/digsy_mtc_eeprom.c @@ -7,9 +7,18 @@ * 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. + * + * FIXME: this driver is used on a device-tree probed platform: it + * should be defined as a bit-banged SPI device and probed from the device + * tree and not like this with static grabbing of a few numbered GPIO + * lines at random. + * + * Add proper SPI and EEPROM in arch/powerpc/boot/dts/digsy_mtc.dts + * and delete this driver. */ #include +#include #include #include #include @@ -42,9 +51,6 @@ struct eeprom_93xx46_platform_data digsy_mtc_eeprom_data = { }; static struct spi_gpio_platform_data eeprom_spi_gpio_data = { - .sck = GPIO_EEPROM_CLK, - .mosi = GPIO_EEPROM_DI, - .miso = GPIO_EEPROM_DO, .num_chipselect = 1, }; @@ -56,6 +62,21 @@ static struct platform_device digsy_mtc_eeprom = { }, }; +static struct gpiod_lookup_table eeprom_spi_gpiod_table = { + .dev_id = "spi_gpio", + .table = { + GPIO_LOOKUP("gpio@b00", GPIO_EEPROM_CLK, + "sck", GPIO_ACTIVE_HIGH), + GPIO_LOOKUP("gpio@b00", GPIO_EEPROM_DI, + "mosi", GPIO_ACTIVE_HIGH), + GPIO_LOOKUP("gpio@b00", GPIO_EEPROM_DO, + "miso", GPIO_ACTIVE_HIGH), + GPIO_LOOKUP("gpio@b00", GPIO_EEPROM_CS, + "cs", GPIO_ACTIVE_HIGH), + { }, + }, +}; + static struct spi_board_info digsy_mtc_eeprom_info[] __initdata = { { .modalias = "93xx46", @@ -63,7 +84,6 @@ static struct spi_board_info digsy_mtc_eeprom_info[] __initdata = { .bus_num = EE_SPI_BUS_NUM, .chip_select = 0, .mode = SPI_MODE_0, - .controller_data = (void *)GPIO_EEPROM_CS, .platform_data = &digsy_mtc_eeprom_data, }, }; @@ -78,6 +98,7 @@ static int __init digsy_mtc_eeprom_devices_init(void) pr_err("can't request gpio %d\n", GPIO_EEPROM_OE); return ret; } + gpiod_add_lookup_table(&eeprom_spi_gpiod_table); spi_register_board_info(digsy_mtc_eeprom_info, ARRAY_SIZE(digsy_mtc_eeprom_info)); return platform_device_register(&digsy_mtc_eeprom); diff --git a/drivers/spi/spi-gpio.c b/drivers/spi/spi-gpio.c index 1c34c9314c8a..b85a93cad44a 100644 --- a/drivers/spi/spi-gpio.c +++ b/drivers/spi/spi-gpio.c @@ -2,6 +2,7 @@ * SPI master driver using generic bitbanged GPIO * * Copyright (C) 2006,2008 David Brownell + * Copyright (C) 2017 Linus Walleij * * 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 @@ -16,10 +17,9 @@ #include #include #include -#include +#include #include #include -#include #include #include @@ -44,7 +44,11 @@ struct spi_gpio { struct spi_bitbang bitbang; struct spi_gpio_platform_data pdata; struct platform_device *pdev; - unsigned long cs_gpios[0]; + struct gpio_desc *sck; + struct gpio_desc *miso; + struct gpio_desc *mosi; + struct gpio_desc **cs_gpios; + bool has_cs; }; /*----------------------------------------------------------------------*/ @@ -77,13 +81,6 @@ struct spi_gpio { #define GENERIC_BITBANG /* vs tight inlines */ -/* all functions referencing these symbols must define pdata */ -#define SPI_MISO_GPIO ((pdata)->miso) -#define SPI_MOSI_GPIO ((pdata)->mosi) -#define SPI_SCK_GPIO ((pdata)->sck) - -#define SPI_N_CHIPSEL ((pdata)->num_chipselect) - #endif /*----------------------------------------------------------------------*/ @@ -105,25 +102,27 @@ spi_to_pdata(const struct spi_device *spi) return &spi_to_spi_gpio(spi)->pdata; } -/* this is #defined to avoid unused-variable warnings when inlining */ -#define pdata spi_to_pdata(spi) - +/* These helpers are in turn called by the bitbang inlines */ static inline void setsck(const struct spi_device *spi, int is_on) { - gpio_set_value_cansleep(SPI_SCK_GPIO, is_on); + struct spi_gpio *spi_gpio = spi_to_spi_gpio(spi); + + gpiod_set_value_cansleep(spi_gpio->sck, is_on); } static inline void setmosi(const struct spi_device *spi, int is_on) { - gpio_set_value_cansleep(SPI_MOSI_GPIO, is_on); + struct spi_gpio *spi_gpio = spi_to_spi_gpio(spi); + + gpiod_set_value_cansleep(spi_gpio->mosi, is_on); } static inline int getmiso(const struct spi_device *spi) { - return !!gpio_get_value_cansleep(SPI_MISO_GPIO); -} + struct spi_gpio *spi_gpio = spi_to_spi_gpio(spi); -#undef pdata + return !!gpiod_get_value_cansleep(spi_gpio->miso); +} /* * NOTE: this clocks "as fast as we can". It "should" be a function of the @@ -216,123 +215,89 @@ static u32 spi_gpio_spec_txrx_word_mode3(struct spi_device *spi, static void spi_gpio_chipselect(struct spi_device *spi, int is_active) { struct spi_gpio *spi_gpio = spi_to_spi_gpio(spi); - unsigned long cs = spi_gpio->cs_gpios[spi->chip_select]; - /* set initial clock polarity */ + /* set initial clock line level */ if (is_active) - setsck(spi, spi->mode & SPI_CPOL); + gpiod_set_value_cansleep(spi_gpio->sck, spi->mode & SPI_CPOL); + + /* Drive chip select line, if we have one */ + if (spi_gpio->has_cs) { + struct gpio_desc *cs = spi_gpio->cs_gpios[spi->chip_select]; - if (cs != SPI_GPIO_NO_CHIPSELECT) { - /* SPI is normally active-low */ - gpio_set_value_cansleep(cs, (spi->mode & SPI_CS_HIGH) ? is_active : !is_active); + /* SPI chip selects are normally active-low */ + gpiod_set_value_cansleep(cs, (spi->mode & SPI_CS_HIGH) ? is_active : !is_active); } } static int spi_gpio_setup(struct spi_device *spi) { - unsigned long cs; + struct gpio_desc *cs; int status = 0; struct spi_gpio *spi_gpio = spi_to_spi_gpio(spi); - struct device_node *np = spi->master->dev.of_node; - - if (np) { - /* - * In DT environments, the CS GPIOs have already been - * initialized from the "cs-gpios" property of the node. - */ - cs = spi_gpio->cs_gpios[spi->chip_select]; - } else { - /* - * ... otherwise, take it from spi->controller_data - */ - cs = (uintptr_t) spi->controller_data; - } - if (!spi->controller_state) { - if (cs != SPI_GPIO_NO_CHIPSELECT) { - status = gpio_request(cs, dev_name(&spi->dev)); - if (status) - return status; - status = gpio_direction_output(cs, - !(spi->mode & SPI_CS_HIGH)); - } - } - if (!status) { - /* in case it was initialized from static board data */ - spi_gpio->cs_gpios[spi->chip_select] = cs; + /* + * The CS GPIOs have already been + * initialized from the descriptor lookup. + */ + cs = spi_gpio->cs_gpios[spi->chip_select]; + if (!spi->controller_state && cs) + status = gpiod_direction_output(cs, + !(spi->mode & SPI_CS_HIGH)); + + if (!status) status = spi_bitbang_setup(spi); - } - if (status) { - if (!spi->controller_state && cs != SPI_GPIO_NO_CHIPSELECT) - gpio_free(cs); - } return status; } static void spi_gpio_cleanup(struct spi_device *spi) { - struct spi_gpio *spi_gpio = spi_to_spi_gpio(spi); - unsigned long cs = spi_gpio->cs_gpios[spi->chip_select]; - - if (cs != SPI_GPIO_NO_CHIPSELECT) - gpio_free(cs); spi_bitbang_cleanup(spi); } -static int spi_gpio_alloc(unsigned pin, const char *label, bool is_in) -{ - int value; - - value = gpio_request(pin, label); - if (value == 0) { - if (is_in) - value = gpio_direction_input(pin); - else - value = gpio_direction_output(pin, 0); - } - return value; -} - -static int spi_gpio_request(struct spi_gpio_platform_data *pdata, - const char *label, u16 *res_flags) +/* + * It can be convenient to use this driver with pins that have alternate + * functions associated with a "native" SPI controller if a driver for that + * controller is not available, or is missing important functionality. + * + * On platforms which can do so, configure MISO with a weak pullup unless + * there's an external pullup on that signal. That saves power by avoiding + * floating signals. (A weak pulldown would save power too, but many + * drivers expect to see all-ones data as the no slave "response".) + */ +static int spi_gpio_request(struct device *dev, + struct spi_gpio *spi_gpio, + unsigned int num_chipselects, + u16 *mflags) { - int value; - - /* NOTE: SPI_*_GPIO symbols may reference "pdata" */ + int i; - if (SPI_MOSI_GPIO != SPI_GPIO_NO_MOSI) { - value = spi_gpio_alloc(SPI_MOSI_GPIO, label, false); - if (value) - goto done; - } else { + spi_gpio->mosi = devm_gpiod_get_optional(dev, "mosi", GPIOD_OUT_LOW); + if (IS_ERR(spi_gpio->mosi)) + return PTR_ERR(spi_gpio->mosi); + if (!spi_gpio->mosi) /* HW configuration without MOSI pin */ - *res_flags |= SPI_MASTER_NO_TX; - } + *mflags |= SPI_MASTER_NO_TX; - if (SPI_MISO_GPIO != SPI_GPIO_NO_MISO) { - value = spi_gpio_alloc(SPI_MISO_GPIO, label, true); - if (value) - goto free_mosi; - } else { + spi_gpio->miso = devm_gpiod_get_optional(dev, "miso", GPIOD_IN); + if (IS_ERR(spi_gpio->miso)) + return PTR_ERR(spi_gpio->miso); + if (!spi_gpio->miso) /* HW configuration without MISO pin */ - *res_flags |= SPI_MASTER_NO_RX; - } + *mflags |= SPI_MASTER_NO_RX; - value = spi_gpio_alloc(SPI_SCK_GPIO, label, false); - if (value) - goto free_miso; + spi_gpio->sck = devm_gpiod_get(dev, "sck", GPIOD_OUT_LOW); + if (IS_ERR(spi_gpio->mosi)) + return PTR_ERR(spi_gpio->mosi); - goto done; + for (i = 0; i < num_chipselects; i++) { + spi_gpio->cs_gpios[i] = devm_gpiod_get_index(dev, "cs", + i, GPIOD_OUT_HIGH); + if (IS_ERR(spi_gpio->cs_gpios[i])) + return PTR_ERR(spi_gpio->cs_gpios[i]); + } -free_miso: - if (SPI_MISO_GPIO != SPI_GPIO_NO_MISO) - gpio_free(SPI_MISO_GPIO); -free_mosi: - if (SPI_MOSI_GPIO != SPI_GPIO_NO_MOSI) - gpio_free(SPI_MOSI_GPIO); -done: - return value; + return 0; } #ifdef CONFIG_OF @@ -358,26 +323,6 @@ static int spi_gpio_probe_dt(struct platform_device *pdev) if (!pdata) return -ENOMEM; - ret = of_get_named_gpio(np, "gpio-sck", 0); - if (ret < 0) { - dev_err(&pdev->dev, "gpio-sck property not found\n"); - goto error_free; - } - pdata->sck = ret; - - ret = of_get_named_gpio(np, "gpio-miso", 0); - if (ret < 0) { - dev_info(&pdev->dev, "gpio-miso property not found, switching to no-rx mode\n"); - pdata->miso = SPI_GPIO_NO_MISO; - } else - pdata->miso = ret; - - ret = of_get_named_gpio(np, "gpio-mosi", 0); - if (ret < 0) { - dev_info(&pdev->dev, "gpio-mosi property not found, switching to no-tx mode\n"); - pdata->mosi = SPI_GPIO_NO_MOSI; - } else - pdata->mosi = ret; ret = of_property_read_u32(np, "num-chipselects", &tmp); if (ret < 0) { @@ -409,7 +354,6 @@ static int spi_gpio_probe(struct platform_device *pdev) struct spi_gpio_platform_data *pdata; u16 master_flags = 0; bool use_of = 0; - int num_devices; status = spi_gpio_probe_dt(pdev); if (status < 0) @@ -423,59 +367,41 @@ static int spi_gpio_probe(struct platform_device *pdev) return -ENODEV; #endif - if (use_of && !SPI_N_CHIPSEL) - num_devices = 1; - else - num_devices = SPI_N_CHIPSEL; - - status = spi_gpio_request(pdata, dev_name(&pdev->dev), &master_flags); - if (status < 0) - return status; + master = spi_alloc_master(&pdev->dev, sizeof(*spi_gpio)); + if (!master) + return -ENOMEM; - master = spi_alloc_master(&pdev->dev, sizeof(*spi_gpio) + - (sizeof(unsigned long) * num_devices)); - if (!master) { - status = -ENOMEM; - goto gpio_free; - } spi_gpio = spi_master_get_devdata(master); + + spi_gpio->cs_gpios = devm_kzalloc(&pdev->dev, + pdata->num_chipselect * sizeof(*spi_gpio->cs_gpios), + GFP_KERNEL); + if (!spi_gpio->cs_gpios) + return -ENOMEM; + platform_set_drvdata(pdev, spi_gpio); + /* Determine if we have chip selects connected */ + spi_gpio->has_cs = !!pdata->num_chipselect; + spi_gpio->pdev = pdev; if (pdata) spi_gpio->pdata = *pdata; + status = spi_gpio_request(&pdev->dev, spi_gpio, + pdata->num_chipselect, &master_flags); + if (status) + return status; + master->bits_per_word_mask = SPI_BPW_RANGE_MASK(1, 32); master->flags = master_flags; master->bus_num = pdev->id; - master->num_chipselect = num_devices; + /* The master needs to think there is a chipselect even if not connected */ + master->num_chipselect = spi_gpio->has_cs ? pdata->num_chipselect : 1; master->setup = spi_gpio_setup; master->cleanup = spi_gpio_cleanup; #ifdef CONFIG_OF master->dev.of_node = pdev->dev.of_node; - - if (use_of) { - int i; - struct device_node *np = pdev->dev.of_node; - - /* - * In DT environments, take the CS GPIO from the "cs-gpios" - * property of the node. - */ - - if (!SPI_N_CHIPSEL) - spi_gpio->cs_gpios[0] = SPI_GPIO_NO_CHIPSELECT; - else - for (i = 0; i < SPI_N_CHIPSEL; i++) { - status = of_get_named_gpio(np, "cs-gpios", i); - if (status < 0) { - dev_err(&pdev->dev, - "invalid cs-gpios property\n"); - goto gpio_free; - } - spi_gpio->cs_gpios[i] = status; - } - } #endif spi_gpio->bitbang.master = master; @@ -496,15 +422,8 @@ static int spi_gpio_probe(struct platform_device *pdev) spi_gpio->bitbang.flags = SPI_CS_HIGH; status = spi_bitbang_start(&spi_gpio->bitbang); - if (status < 0) { -gpio_free: - if (SPI_MISO_GPIO != SPI_GPIO_NO_MISO) - gpio_free(SPI_MISO_GPIO); - if (SPI_MOSI_GPIO != SPI_GPIO_NO_MOSI) - gpio_free(SPI_MOSI_GPIO); - gpio_free(SPI_SCK_GPIO); + if (status) spi_master_put(master); - } return status; } @@ -520,11 +439,6 @@ static int spi_gpio_remove(struct platform_device *pdev) /* stop() unregisters child devices too */ spi_bitbang_stop(&spi_gpio->bitbang); - if (SPI_MISO_GPIO != SPI_GPIO_NO_MISO) - gpio_free(SPI_MISO_GPIO); - if (SPI_MOSI_GPIO != SPI_GPIO_NO_MOSI) - gpio_free(SPI_MOSI_GPIO); - gpio_free(SPI_SCK_GPIO); spi_master_put(spi_gpio->bitbang.master); return 0; diff --git a/include/linux/spi/spi_gpio.h b/include/linux/spi/spi_gpio.h index e7bd89a59cd1..9e7e83d8645b 100644 --- a/include/linux/spi/spi_gpio.h +++ b/include/linux/spi/spi_gpio.h @@ -8,64 +8,17 @@ * - id the same as the SPI bus number it implements * - dev.platform data pointing to a struct spi_gpio_platform_data * - * Or, see the driver code for information about speedups that are - * possible on platforms that support inlined access for GPIOs (no - * spi_gpio_platform_data is used). - * - * Use spi_board_info with these busses in the usual way, being sure - * that the controller_data being the GPIO used for each device's - * chipselect: - * - * static struct spi_board_info ... [] = { - * ... - * // this slave uses GPIO 42 for its chipselect - * .controller_data = (void *) 42, - * ... - * // this one uses GPIO 86 for its chipselect - * .controller_data = (void *) 86, - * ... - * }; - * - * If chipselect is not used (there's only one device on the bus), assign - * SPI_GPIO_NO_CHIPSELECT to the controller_data: - * .controller_data = (void *) SPI_GPIO_NO_CHIPSELECT; - * - * If the MISO or MOSI pin is not available then it should be set to - * SPI_GPIO_NO_MISO or SPI_GPIO_NO_MOSI. + * Use spi_board_info with these busses in the usual way. * * If the bitbanged bus is later switched to a "native" controller, * that platform_device and controller_data should be removed. */ -#define SPI_GPIO_NO_CHIPSELECT ((unsigned long)-1l) -#define SPI_GPIO_NO_MISO ((unsigned long)-1l) -#define SPI_GPIO_NO_MOSI ((unsigned long)-1l) - /** * struct spi_gpio_platform_data - parameter for bitbanged SPI master - * @sck: number of the GPIO used for clock output - * @mosi: number of the GPIO used for Master Output, Slave In (MOSI) data - * @miso: number of the GPIO used for Master Input, Slave Output (MISO) data * @num_chipselect: how many slaves to allow - * - * All GPIO signals used with the SPI bus managed through this driver - * (chipselects, MOSI, MISO, SCK) must be configured as GPIOs, instead - * of some alternate function. - * - * It can be convenient to use this driver with pins that have alternate - * functions associated with a "native" SPI controller if a driver for that - * controller is not available, or is missing important functionality. - * - * On platforms which can do so, configure MISO with a weak pullup unless - * there's an external pullup on that signal. That saves power by avoiding - * floating signals. (A weak pulldown would save power too, but many - * drivers expect to see all-ones data as the no slave "response".) */ struct spi_gpio_platform_data { - unsigned sck; - unsigned long mosi; - unsigned long miso; - u16 num_chipselect; }; -- cgit v1.2.3 From d704afffe65c8fab424963c1ba4ec4364c2d6a82 Mon Sep 17 00:00:00 2001 From: Trent Piepho Date: Mon, 12 Feb 2018 11:38:14 -0800 Subject: spi: bcm2835aux: Avoid 64-bit arithmetic in xfer len calc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We want to check for xfers that are over 30 microseconds. Rather than find how many µs a xfer will take, instead find how many bytes can be transferred in 30 µs. The latter must be less than 32 bits (since our clock speed is limited to 32 bits), while the former involves 64 bit quantities and more arithmetic operations. Signed-off-by: Trent Piepho Signed-off-by: Mark Brown --- drivers/spi/spi-bcm2835aux.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi-bcm2835aux.c b/drivers/spi/spi-bcm2835aux.c index 7428091d3f5b..1431cb98fe40 100644 --- a/drivers/spi/spi-bcm2835aux.c +++ b/drivers/spi/spi-bcm2835aux.c @@ -321,7 +321,6 @@ static int bcm2835aux_spi_transfer_one(struct spi_master *master, struct bcm2835aux_spi *bs = spi_master_get_devdata(master); unsigned long spi_hz, clk_hz, speed; unsigned long spi_used_hz; - unsigned long long xfer_time_us; /* calculate the registers to handle * @@ -358,20 +357,21 @@ static int bcm2835aux_spi_transfer_one(struct spi_master *master, bs->rx_len = tfr->len; bs->pending = 0; - /* calculate the estimated time in us the transfer runs - * note that there are are 2 idle clocks after each - * chunk getting transferred - in our case the chunk size - * is 3 bytes, so we approximate this by 9 bits/byte + /* Calculate the estimated time in us the transfer runs. Note that + * there are are 2 idle clocks cycles after each chunk getting + * transferred - in our case the chunk size is 3 bytes, so we + * approximate this by 9 cycles/byte. This is used to find the number + * of Hz per byte per polling limit. E.g., we can transfer 1 byte in + * 30 µs per 300,000 Hz of bus clock. */ - xfer_time_us = tfr->len * 9 * 1000000; - do_div(xfer_time_us, spi_used_hz); - +#define HZ_PER_BYTE ((9 * 1000000) / BCM2835_AUX_SPI_POLLING_LIMIT_US) /* run in polling mode for short transfers */ - if (xfer_time_us < BCM2835_AUX_SPI_POLLING_LIMIT_US) + if (tfr->len < spi_used_hz / HZ_PER_BYTE) return bcm2835aux_spi_transfer_one_poll(master, spi, tfr); /* run in interrupt mode for all others */ return bcm2835aux_spi_transfer_one_irq(master, spi, tfr); +#undef HZ_PER_BYTE } static int bcm2835aux_spi_prepare_message(struct spi_master *master, -- cgit v1.2.3 From 544248623b95eefbe4bea5fa5c68ab0da495eaae Mon Sep 17 00:00:00 2001 From: Jan Kundrát Date: Fri, 26 Jan 2018 23:56:10 +0100 Subject: spi: orion: Rework GPIO CS handling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Claim the GPIO from the driver, not via DT bindings or through the platform code - Find an unused HW CS signal because Orion needs to drive one for each SPI transaction The spi-orion.c was the only driver which supported (or cared about) the CS GPIO, while it wasn't actually requesting it. This change means that the DT bindings should stop hogging the GPIO CS pins because it's now being handled by the driver. Signed-off-by: Jan Kundrát Signed-off-by: Mark Brown --- drivers/spi/spi-orion.c | 47 ++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 44 insertions(+), 3 deletions(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi-orion.c b/drivers/spi/spi-orion.c index deca63e82ff6..b341235d2947 100644 --- a/drivers/spi/spi-orion.c +++ b/drivers/spi/spi-orion.c @@ -96,6 +96,7 @@ struct orion_spi { struct clk *clk; struct clk *axi_clk; const struct orion_spi_dev *devdata; + int unused_hw_gpio; struct orion_direct_acc direct_access[ORION_NUM_CHIPSELECTS]; }; @@ -324,13 +325,13 @@ static void orion_spi_set_cs(struct spi_device *spi, bool enable) struct orion_spi *orion_spi; int cs; + orion_spi = spi_master_get_devdata(spi->master); + if (gpio_is_valid(spi->cs_gpio)) - cs = 0; + cs = orion_spi->unused_hw_gpio; else cs = spi->chip_select; - orion_spi = spi_master_get_devdata(spi->master); - orion_spi_clrbits(orion_spi, ORION_SPI_IF_CTRL_REG, ORION_SPI_CS_MASK); orion_spi_setbits(orion_spi, ORION_SPI_IF_CTRL_REG, ORION_SPI_CS(cs)); @@ -498,6 +499,9 @@ static int orion_spi_transfer_one(struct spi_master *master, static int orion_spi_setup(struct spi_device *spi) { + if (gpio_is_valid(spi->cs_gpio)) { + gpio_direction_output(spi->cs_gpio, !(spi->mode & SPI_CS_HIGH)); + } return orion_spi_setup_transfer(spi, NULL); } @@ -620,6 +624,7 @@ static int orion_spi_probe(struct platform_device *pdev) spi = spi_master_get_devdata(master); spi->master = master; + spi->unused_hw_gpio = -1; of_id = of_match_device(orion_spi_of_match_table, &pdev->dev); devdata = (of_id) ? of_id->data : &orion_spi_dev_data; @@ -731,8 +736,44 @@ static int orion_spi_probe(struct platform_device *pdev) if (status < 0) goto out_rel_pm; + if (master->cs_gpios) { + int i; + for (i = 0; i < master->num_chipselect; ++i) { + char *gpio_name; + + if (!gpio_is_valid(master->cs_gpios[i])) { + continue; + } + + gpio_name = devm_kasprintf(&pdev->dev, GFP_KERNEL, + "%s-CS%d", dev_name(&pdev->dev), i); + if (!gpio_name) { + status = -ENOMEM; + goto out_rel_master; + } + + status = devm_gpio_request(&pdev->dev, + master->cs_gpios[i], gpio_name); + if (status) { + dev_err(&pdev->dev, + "Can't request GPIO for CS %d\n", + master->cs_gpios[i]); + goto out_rel_master; + } + if (spi->unused_hw_gpio == -1) { + dev_info(&pdev->dev, + "Selected unused HW CS#%d " + "for any GPIO CSes\n", i); + spi->unused_hw_gpio = i; + } + } + } + + return status; +out_rel_master: + spi_unregister_master(master); out_rel_pm: pm_runtime_disable(&pdev->dev); out_rel_axi_clk: -- cgit v1.2.3 From 64aa3bd32c2679ed51401cb32fe6b387a1e6b51b Mon Sep 17 00:00:00 2001 From: Jan Kundrát Date: Thu, 15 Feb 2018 15:15:07 +0100 Subject: spi: orion: Make the error message greppable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit 544248623b95 introduced a new user-visible string which was however split into two chunks. Thanks to Mark Brown for noticing. Signed-off-by: Jan Kundrát Signed-off-by: Mark Brown --- drivers/spi/spi-orion.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi-orion.c b/drivers/spi/spi-orion.c index b341235d2947..ca52300baeb1 100644 --- a/drivers/spi/spi-orion.c +++ b/drivers/spi/spi-orion.c @@ -762,8 +762,8 @@ static int orion_spi_probe(struct platform_device *pdev) } if (spi->unused_hw_gpio == -1) { dev_info(&pdev->dev, - "Selected unused HW CS#%d " - "for any GPIO CSes\n", i); + "Selected unused HW CS#%d for any GPIO CSes\n", + i); spi->unused_hw_gpio = i; } } -- cgit v1.2.3 From 5c22af7eeb265413b80eb8e03ae708e1b222728c Mon Sep 17 00:00:00 2001 From: Jan Kundrát Date: Sat, 10 Feb 2018 12:20:23 +0100 Subject: spi: orion: Prepare space for per-child options MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Aggregating all options for a particular child underneath a common struct looks cleaner compared to having a separate array for each per-child option. Signed-off-by: Jan Kundrát Signed-off-by: Mark Brown --- drivers/spi/spi-orion.c | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi-orion.c b/drivers/spi/spi-orion.c index ca52300baeb1..d01a6adc726e 100644 --- a/drivers/spi/spi-orion.c +++ b/drivers/spi/spi-orion.c @@ -90,6 +90,10 @@ struct orion_direct_acc { u32 size; }; +struct orion_child_options { + struct orion_direct_acc direct_access; +}; + struct orion_spi { struct spi_master *master; void __iomem *base; @@ -98,7 +102,7 @@ struct orion_spi { const struct orion_spi_dev *devdata; int unused_hw_gpio; - struct orion_direct_acc direct_access[ORION_NUM_CHIPSELECTS]; + struct orion_child_options child[ORION_NUM_CHIPSELECTS]; }; static inline void __iomem *spi_reg(struct orion_spi *orion_spi, u32 reg) @@ -436,7 +440,7 @@ orion_spi_write_read(struct spi_device *spi, struct spi_transfer *xfer) * Use SPI direct write mode if base address is available. Otherwise * fall back to PIO mode for this transfer. */ - if ((orion_spi->direct_access[cs].vaddr) && (xfer->tx_buf) && + if ((orion_spi->child[cs].direct_access.vaddr) && (xfer->tx_buf) && (word_len == 8)) { unsigned int cnt = count / 4; unsigned int rem = count % 4; @@ -445,12 +449,12 @@ orion_spi_write_read(struct spi_device *spi, struct spi_transfer *xfer) * Send the TX-data to the SPI device via the direct * mapped address window */ - iowrite32_rep(orion_spi->direct_access[cs].vaddr, + iowrite32_rep(orion_spi->child[cs].direct_access.vaddr, xfer->tx_buf, cnt); if (rem) { u32 *buf = (u32 *)xfer->tx_buf; - iowrite8_rep(orion_spi->direct_access[cs].vaddr, + iowrite8_rep(orion_spi->child[cs].direct_access.vaddr, &buf[cnt], rem); } @@ -707,14 +711,14 @@ static int orion_spi_probe(struct platform_device *pdev) * This needs to get extended for the direct SPI-NOR / SPI-NAND * support, once this gets implemented. */ - spi->direct_access[cs].vaddr = devm_ioremap(&pdev->dev, + spi->child[cs].direct_access.vaddr = devm_ioremap(&pdev->dev, r->start, PAGE_SIZE); - if (!spi->direct_access[cs].vaddr) { + if (!spi->child[cs].direct_access.vaddr) { status = -ENOMEM; goto out_rel_axi_clk; } - spi->direct_access[cs].size = PAGE_SIZE; + spi->child[cs].direct_access.size = PAGE_SIZE; dev_info(&pdev->dev, "CS%d configured for direct access\n", cs); } -- cgit v1.2.3 From 9581329eff9db72ab4fbb46a594fd7fdda3c51b0 Mon Sep 17 00:00:00 2001 From: Eugen Hristev Date: Tue, 27 Feb 2018 12:25:07 +0200 Subject: spi: atmel: init FIFOs before spi enable The datasheet recommends initializing FIFOs before SPI enable. If we do not do it like this, there may be a strange behavior. We noticed that DMA does not work properly with FIFOs if we do not clear them beforehand or enable them before SPIEN. Signed-off-by: Eugen Hristev Acked-by: Nicolas Ferre Signed-off-by: Mark Brown Cc: stable@vger.kernel.org --- drivers/spi/spi-atmel.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi-atmel.c b/drivers/spi/spi-atmel.c index 4a11fc0d4136..b7936f815373 100644 --- a/drivers/spi/spi-atmel.c +++ b/drivers/spi/spi-atmel.c @@ -1512,6 +1512,11 @@ static void atmel_spi_init(struct atmel_spi *as) { spi_writel(as, CR, SPI_BIT(SWRST)); spi_writel(as, CR, SPI_BIT(SWRST)); /* AT91SAM9263 Rev B workaround */ + + /* It is recommended to enable FIFOs first thing after reset */ + if (as->fifo_size) + spi_writel(as, CR, SPI_BIT(FIFOEN)); + if (as->caps.has_wdrbt) { spi_writel(as, MR, SPI_BIT(WDRBT) | SPI_BIT(MODFDIS) | SPI_BIT(MSTR)); @@ -1522,9 +1527,6 @@ static void atmel_spi_init(struct atmel_spi *as) if (as->use_pdc) spi_writel(as, PTCR, SPI_BIT(RXTDIS) | SPI_BIT(TXTDIS)); spi_writel(as, CR, SPI_BIT(SPIEN)); - - if (as->fifo_size) - spi_writel(as, CR, SPI_BIT(FIFOEN)); } static int atmel_spi_probe(struct platform_device *pdev) -- cgit v1.2.3 From ce99319a182fe766be67f96338386f3ec73e321c Mon Sep 17 00:00:00 2001 From: Maxime Chevallier Date: Fri, 2 Mar 2018 15:55:09 +0100 Subject: spi: Fix scatterlist elements size in spi_map_buf When SPI transfers can be offloaded using DMA, the SPI core need to build a scatterlist to make sure that the buffer to be transferred is dma-able. This patch fixes the scatterlist entry size computation in the case where the maximum acceptable scatterlist entry supported by the DMA controller is less than PAGE_SIZE, when the buffer is vmalloced. For each entry, the actual size is given by the minimum between the desc_len (which is the max buffer size supported by the DMA controller) and the remaining buffer length until we cross a page boundary. Fixes: 65598c13fd66 ("spi: Fix per-page mapping of unaligned vmalloc-ed buffer") Signed-off-by: Maxime Chevallier Signed-off-by: Mark Brown Cc: stable@vger.kernel.org --- drivers/spi/spi.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index b33a727a0158..4153f959f28c 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -779,8 +779,14 @@ static int spi_map_buf(struct spi_controller *ctlr, struct device *dev, for (i = 0; i < sgs; i++) { if (vmalloced_buf || kmap_buf) { - min = min_t(size_t, - len, desc_len - offset_in_page(buf)); + /* + * Next scatterlist entry size is the minimum between + * the desc_len and the remaining buffer length that + * fits in a page. + */ + min = min_t(size_t, desc_len, + min_t(size_t, len, + PAGE_SIZE - offset_in_page(buf))); if (vmalloced_buf) vm_page = vmalloc_to_page(buf); else -- cgit v1.2.3 From 2172a33279bc2162656f473f5a1256618169b249 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Mon, 5 Mar 2018 17:53:39 -0600 Subject: spi: tegra20-slink: use true and false for boolean values Assign true or false to boolean variables instead of an integer value. This issue was detected with the help of Coccinelle. Signed-off-by: Gustavo A. R. Silva Acked-by: Laxman Dewangan Signed-off-by: Mark Brown --- drivers/spi/spi-tegra20-slink.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi-tegra20-slink.c b/drivers/spi/spi-tegra20-slink.c index 3e12d5f87ee4..6f7b946b5ced 100644 --- a/drivers/spi/spi-tegra20-slink.c +++ b/drivers/spi/spi-tegra20-slink.c @@ -276,10 +276,10 @@ static unsigned tegra_slink_calculate_curr_xfer_param( tspi->bytes_per_word = DIV_ROUND_UP(bits_per_word, 8); if (bits_per_word == 8 || bits_per_word == 16) { - tspi->is_packed = 1; + tspi->is_packed = true; tspi->words_per_32bit = 32/bits_per_word; } else { - tspi->is_packed = 0; + tspi->is_packed = false; tspi->words_per_32bit = 1; } tspi->packed_size = tegra_slink_get_packed_size(tspi, t); -- cgit v1.2.3 From e2b714afee32d368e0fda825c48181626979a551 Mon Sep 17 00:00:00 2001 From: Jarkko Nikula Date: Wed, 7 Mar 2018 17:05:04 +0200 Subject: spi: pxa2xx: Disable runtime PM if controller registration fails Don't leave runtime PM enabled in case devm_spi_register_controller() returns with an error. Otherwise runtime PM will complain when driver is reloaded: [ 693.855811] pxa2xx-spi pxa2xx-spi.13: Unbalanced pm_runtime_enable! Signed-off-by: Jarkko Nikula Signed-off-by: Mark Brown --- drivers/spi/spi-pxa2xx.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/spi') diff --git a/drivers/spi/spi-pxa2xx.c b/drivers/spi/spi-pxa2xx.c index b0822d1dba29..56254b35875d 100644 --- a/drivers/spi/spi-pxa2xx.c +++ b/drivers/spi/spi-pxa2xx.c @@ -1802,6 +1802,8 @@ static int pxa2xx_spi_probe(struct platform_device *pdev) return status; out_error_clock_enabled: + pm_runtime_put_noidle(&pdev->dev); + pm_runtime_disable(&pdev->dev); clk_disable_unprepare(ssp->clk); pxa2xx_spi_dma_release(drv_data); free_irq(ssp->irq, drv_data); -- cgit v1.2.3 From bc3cc75281b3c2b1c5355d88d147b66a753bb9a5 Mon Sep 17 00:00:00 2001 From: Christophe Jaillet Date: Tue, 13 Mar 2018 19:36:58 +0100 Subject: spi: bcm-qspi: fIX some error handling paths For some reason, commit c0368e4db4a3 ("spi: bcm-qspi: Fix use after free in bcm_qspi_probe() in error path") has updated some gotos, but not all of them. This looks spurious, so fix it. Fixes: fa236a7ef240 ("spi: bcm-qspi: Add Broadcom MSPI driver") Signed-off-by: Christophe JAILLET Signed-off-by: Mark Brown --- drivers/spi/spi-bcm-qspi.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi-bcm-qspi.c b/drivers/spi/spi-bcm-qspi.c index a172ab299e80..1596d35498c5 100644 --- a/drivers/spi/spi-bcm-qspi.c +++ b/drivers/spi/spi-bcm-qspi.c @@ -1247,7 +1247,7 @@ int bcm_qspi_probe(struct platform_device *pdev, qspi->base[MSPI] = devm_ioremap_resource(dev, res); if (IS_ERR(qspi->base[MSPI])) { ret = PTR_ERR(qspi->base[MSPI]); - goto qspi_probe_err; + goto qspi_resource_err; } } else { goto qspi_resource_err; @@ -1258,7 +1258,7 @@ int bcm_qspi_probe(struct platform_device *pdev, qspi->base[BSPI] = devm_ioremap_resource(dev, res); if (IS_ERR(qspi->base[BSPI])) { ret = PTR_ERR(qspi->base[BSPI]); - goto qspi_probe_err; + goto qspi_resource_err; } qspi->bspi_mode = true; } else { -- cgit v1.2.3 From 7c2861a6fb2c502d7b7aa85415e178f3c527a468 Mon Sep 17 00:00:00 2001 From: Alexey Khoroshilov Date: Sat, 17 Mar 2018 13:05:44 +0300 Subject: spi: jcore: disable ref_clk after getting its rate The driver does not disable ref_clk on remove. According to the comment, the only reason to enable the clock is to get its rate. So, it should be safe to disable clk just after that. By the way, clk_prepare_enable() looks to be more appropriate than clk_enable() here. Found by Linux Driver Verification project (linuxtesting.org). Signed-off-by: Alexey Khoroshilov Signed-off-by: Mark Brown --- drivers/spi/spi-jcore.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi-jcore.c b/drivers/spi/spi-jcore.c index dafed6280df3..702fe573a47b 100644 --- a/drivers/spi/spi-jcore.c +++ b/drivers/spi/spi-jcore.c @@ -184,10 +184,11 @@ static int jcore_spi_probe(struct platform_device *pdev) */ clock_freq = 50000000; clk = devm_clk_get(&pdev->dev, "ref_clk"); - if (!IS_ERR_OR_NULL(clk)) { - if (clk_enable(clk) == 0) + if (!IS_ERR(clk)) { + if (clk_prepare_enable(clk) == 0) { clock_freq = clk_get_rate(clk); - else + clk_disable_unprepare(clk); + } else dev_warn(&pdev->dev, "could not enable ref_clk\n"); } hw->clock_freq = clock_freq; @@ -198,10 +199,8 @@ static int jcore_spi_probe(struct platform_device *pdev) /* Register our spi controller */ err = devm_spi_register_master(&pdev->dev, master); - if (err) { - clk_disable(clk); + if (err) goto exit; - } return 0; -- cgit v1.2.3 From 768d59f5d0139a6ff09e4430ec29cdc8b436421a Mon Sep 17 00:00:00 2001 From: Stefan Agner Date: Mon, 19 Mar 2018 23:16:22 +0100 Subject: spi: rspi: use correct enum for DMA transfer direction Use enum dma_transfer_direction as required by dmaengine_prep_slave_sg instead of enum dma_data_direction. This won't change behavior in practice as the enum values are equivalent. This fixes two warnings when building with clang: drivers/spi/spi-rspi.c:538:26: warning: implicit conversion from enumeration type 'enum dma_data_direction' to different enumeration type 'enum dma_transfer_direction' [-Wenum-conversion] rx->sgl, rx->nents, DMA_FROM_DEVICE, ^~~~~~~~~~~~~~~ drivers/spi/spi-rspi.c:558:26: warning: implicit conversion from enumeration type 'enum dma_data_direction' to different enumeration type 'enum dma_transfer_direction' [-Wenum-conversion] tx->sgl, tx->nents, DMA_TO_DEVICE, ^~~~~~~~~~~~~ Signed-off-by: Stefan Agner Signed-off-by: Mark Brown --- drivers/spi/spi-rspi.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi-rspi.c b/drivers/spi/spi-rspi.c index 0835a8d88fb8..95dc4d78618d 100644 --- a/drivers/spi/spi-rspi.c +++ b/drivers/spi/spi-rspi.c @@ -535,7 +535,7 @@ static int rspi_dma_transfer(struct rspi_data *rspi, struct sg_table *tx, /* First prepare and submit the DMA request(s), as this may fail */ if (rx) { desc_rx = dmaengine_prep_slave_sg(rspi->master->dma_rx, - rx->sgl, rx->nents, DMA_FROM_DEVICE, + rx->sgl, rx->nents, DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); if (!desc_rx) { ret = -EAGAIN; @@ -555,7 +555,7 @@ static int rspi_dma_transfer(struct rspi_data *rspi, struct sg_table *tx, if (tx) { desc_tx = dmaengine_prep_slave_sg(rspi->master->dma_tx, - tx->sgl, tx->nents, DMA_TO_DEVICE, + tx->sgl, tx->nents, DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); if (!desc_tx) { ret = -EAGAIN; -- cgit v1.2.3 From 613bd1ea387bb48b7c9a71a0bb451ac15cfbbc01 Mon Sep 17 00:00:00 2001 From: Jarkko Nikula Date: Tue, 20 Mar 2018 10:27:50 +0200 Subject: spi: Fix unregistration of controller with fixed SPI bus number Commit 9b61e302210e (spi: Pick spi bus number from Linux idr or spi alias) ceased to unregister SPI buses with fixed bus numbers. Moreover this is visible only if CONFIG_SPI_DEBUG=y is set or when trying to re-register the same SPI controller. rmmod spi_pxa2xx_platform (with CONFIG_SPI_DEBUG=y): [ 26.788362] spi_master spi1: attempting to delete unregistered controller [spi1] modprobe spi_pxa2xx_platform: [ 37.883137] sysfs: cannot create duplicate filename '/devices/pci0000:00/0000:00:19.0/pxa2xx-spi.12/spi_master/spi1' [ 37.894984] CPU: 1 PID: 1467 Comm: modprobe Not tainted 4.16.0-rc4+ #21 [ 37.902384] Call Trace: ... [ 38.122680] kobject_add_internal failed for spi1 with -EEXIST, don't try to register things with the same name in the same directory. [ 38.136154] WARNING: CPU: 1 PID: 1467 at lib/kobject.c:238 kobject_add_internal+0x2a5/0x2f0 ... [ 38.513817] pxa2xx-spi pxa2xx-spi.12: problem registering spi master [ 38.521036] pxa2xx-spi: probe of pxa2xx-spi.12 failed with error -17 Fix this by not returning immediately from spi_unregister_controller() if idr_find() doesn't find controller with given ID/bus number. It finds only those controllers that were registered with dynamic SPI bus numbers. Only conditional cleanup between dynamic and fixed bus numbers is to remove allocated IDR. Fixes: 9b61e302210e (spi: Pick spi bus number from Linux idr or spi alias) Cc: stable@vger.kernel.org Signed-off-by: Jarkko Nikula Signed-off-by: Mark Brown --- drivers/spi/spi.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index b33a727a0158..e90fd442b3f0 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -2254,12 +2254,6 @@ void spi_unregister_controller(struct spi_controller *ctlr) mutex_lock(&board_lock); found = idr_find(&spi_master_idr, id); mutex_unlock(&board_lock); - if (found != ctlr) { - dev_dbg(&ctlr->dev, - "attempting to delete unregistered controller [%s]\n", - dev_name(&ctlr->dev)); - return; - } if (ctlr->queued) { if (spi_destroy_queue(ctlr)) dev_err(&ctlr->dev, "queue remove failed\n"); @@ -2272,7 +2266,8 @@ void spi_unregister_controller(struct spi_controller *ctlr) device_unregister(&ctlr->dev); /* free bus id */ mutex_lock(&board_lock); - idr_remove(&spi_master_idr, id); + if (found == ctlr) + idr_remove(&spi_master_idr, id); mutex_unlock(&board_lock); } EXPORT_SYMBOL_GPL(spi_unregister_controller); -- cgit v1.2.3 From a61aa683655f3182aca6e38404ae9aac03e771ae Mon Sep 17 00:00:00 2001 From: Baolin Wang Date: Tue, 20 Mar 2018 10:42:13 +0800 Subject: spi: sprd: Simplify the transfer function We can move the hardware spinlock protection into the ADI read/write functions to simplify the sprd_adi_transfer_one() function. Moreover this optimization can also help to access PMIC without considering the hardware spinlock using sprd_adi_read/write() functions. Signed-off-by: Baolin Wang Signed-off-by: Mark Brown --- drivers/spi/spi-sprd-adi.c | 64 +++++++++++++++++++++++++--------------------- 1 file changed, 35 insertions(+), 29 deletions(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi-sprd-adi.c b/drivers/spi/spi-sprd-adi.c index 5993bdbf79e4..74bbd045aac0 100644 --- a/drivers/spi/spi-sprd-adi.c +++ b/drivers/spi/spi-sprd-adi.c @@ -123,7 +123,17 @@ static int sprd_adi_fifo_is_full(struct sprd_adi *sadi) static int sprd_adi_read(struct sprd_adi *sadi, u32 reg_paddr, u32 *read_val) { int read_timeout = ADI_READ_TIMEOUT; + unsigned long flags; u32 val, rd_addr; + int ret; + + ret = hwspin_lock_timeout_irqsave(sadi->hwlock, + ADI_HWSPINLOCK_TIMEOUT, + &flags); + if (ret) { + dev_err(sadi->dev, "get the hw lock failed\n"); + return ret; + } /* * Set the physical register address need to read into RD_CMD register, @@ -147,7 +157,8 @@ static int sprd_adi_read(struct sprd_adi *sadi, u32 reg_paddr, u32 *read_val) if (read_timeout == 0) { dev_err(sadi->dev, "ADI read timeout\n"); - return -EBUSY; + ret = -EBUSY; + goto out; } /* @@ -161,21 +172,35 @@ static int sprd_adi_read(struct sprd_adi *sadi, u32 reg_paddr, u32 *read_val) if (rd_addr != (reg_paddr & REG_ADDR_LOW_MASK)) { dev_err(sadi->dev, "read error, reg addr = 0x%x, val = 0x%x\n", reg_paddr, val); - return -EIO; + ret = -EIO; + goto out; } *read_val = val & RD_VALUE_MASK; - return 0; + +out: + hwspin_unlock_irqrestore(sadi->hwlock, &flags); + return ret; } -static int sprd_adi_write(struct sprd_adi *sadi, unsigned long reg, u32 val) +static int sprd_adi_write(struct sprd_adi *sadi, u32 reg_paddr, u32 val) { + unsigned long reg = sprd_adi_to_vaddr(sadi, reg_paddr); u32 timeout = ADI_FIFO_DRAIN_TIMEOUT; + unsigned long flags; int ret; + ret = hwspin_lock_timeout_irqsave(sadi->hwlock, + ADI_HWSPINLOCK_TIMEOUT, + &flags); + if (ret) { + dev_err(sadi->dev, "get the hw lock failed\n"); + return ret; + } + ret = sprd_adi_drain_fifo(sadi); if (ret < 0) - return ret; + goto out; /* * we should wait for write fifo is empty before writing data to PMIC @@ -192,10 +217,12 @@ static int sprd_adi_write(struct sprd_adi *sadi, unsigned long reg, u32 val) if (timeout == 0) { dev_err(sadi->dev, "write fifo is full\n"); - return -EBUSY; + ret = -EBUSY; } - return 0; +out: + hwspin_unlock_irqrestore(sadi->hwlock, &flags); + return ret; } static int sprd_adi_transfer_one(struct spi_controller *ctlr, @@ -203,7 +230,6 @@ static int sprd_adi_transfer_one(struct spi_controller *ctlr, struct spi_transfer *t) { struct sprd_adi *sadi = spi_controller_get_devdata(ctlr); - unsigned long flags, virt_reg; u32 phy_reg, val; int ret; @@ -214,16 +240,7 @@ static int sprd_adi_transfer_one(struct spi_controller *ctlr, if (ret) return ret; - ret = hwspin_lock_timeout_irqsave(sadi->hwlock, - ADI_HWSPINLOCK_TIMEOUT, - &flags); - if (ret) { - dev_err(sadi->dev, "get the hw lock failed\n"); - return ret; - } - ret = sprd_adi_read(sadi, phy_reg, &val); - hwspin_unlock_irqrestore(sadi->hwlock, &flags); if (ret) return ret; @@ -241,19 +258,8 @@ static int sprd_adi_transfer_one(struct spi_controller *ctlr, if (ret) return ret; - virt_reg = sprd_adi_to_vaddr(sadi, phy_reg); val = *p; - - ret = hwspin_lock_timeout_irqsave(sadi->hwlock, - ADI_HWSPINLOCK_TIMEOUT, - &flags); - if (ret) { - dev_err(sadi->dev, "get the hw lock failed\n"); - return ret; - } - - ret = sprd_adi_write(sadi, virt_reg, val); - hwspin_unlock_irqrestore(sadi->hwlock, &flags); + ret = sprd_adi_write(sadi, phy_reg, val); if (ret) return ret; } else { -- cgit v1.2.3 From ac1775012058e13ef1522938e27f5973d9e3f053 Mon Sep 17 00:00:00 2001 From: Baolin Wang Date: Tue, 20 Mar 2018 10:42:14 +0800 Subject: spi: sprd: Add the support of restarting the system On Spreadtrum platform, we use one PMIC watchdog to reset the whole system with loading one suitable timeout value (usually 50ms) for the watchdog. In theory, we should implement the restart function in drivers/power/reset subsystem to access the PMIC watchdog with regmap. When restart the system, other cores will be stopped by IPI, but if other cores were accessing PMIC with holding the regmap mutex lock, that will cause dead-lock issue if we try to access the PMIC watchdog with regmap to restart the whole system. Thus we can implement the restart function in ADI driver to avoid this issue. Signed-off-by: Baolin Wang Signed-off-by: Mark Brown --- drivers/spi/spi-sprd-adi.c | 112 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 112 insertions(+) (limited to 'drivers/spi') diff --git a/drivers/spi/spi-sprd-adi.c b/drivers/spi/spi-sprd-adi.c index 74bbd045aac0..197d4b0d81af 100644 --- a/drivers/spi/spi-sprd-adi.c +++ b/drivers/spi/spi-sprd-adi.c @@ -4,6 +4,7 @@ * SPDX-License-Identifier: GPL-2.0 */ +#include #include #include #include @@ -12,6 +13,7 @@ #include #include #include +#include #include #include @@ -67,6 +69,40 @@ #define ADI_READ_TIMEOUT 2000 #define REG_ADDR_LOW_MASK GENMASK(11, 0) +/* Registers definitions for PMIC watchdog controller */ +#define REG_WDG_LOAD_LOW 0x80 +#define REG_WDG_LOAD_HIGH 0x84 +#define REG_WDG_CTRL 0x88 +#define REG_WDG_LOCK 0xa0 + +/* Bits definitions for register REG_WDG_CTRL */ +#define BIT_WDG_RUN BIT(1) +#define BIT_WDG_RST BIT(3) + +/* Registers definitions for PMIC */ +#define PMIC_RST_STATUS 0xee8 +#define PMIC_MODULE_EN 0xc08 +#define PMIC_CLK_EN 0xc18 +#define BIT_WDG_EN BIT(2) + +/* Definition of PMIC reset status register */ +#define HWRST_STATUS_RECOVERY 0x20 +#define HWRST_STATUS_NORMAL 0x40 +#define HWRST_STATUS_ALARM 0x50 +#define HWRST_STATUS_SLEEP 0x60 +#define HWRST_STATUS_FASTBOOT 0x30 +#define HWRST_STATUS_SPECIAL 0x70 +#define HWRST_STATUS_PANIC 0x80 +#define HWRST_STATUS_CFTREBOOT 0x90 +#define HWRST_STATUS_AUTODLOADER 0xa0 +#define HWRST_STATUS_IQMODE 0xb0 +#define HWRST_STATUS_SPRDISK 0xc0 + +/* Use default timeout 50 ms that converts to watchdog values */ +#define WDG_LOAD_VAL ((50 * 1000) / 32768) +#define WDG_LOAD_MASK GENMASK(15, 0) +#define WDG_UNLOCK_KEY 0xe551 + struct sprd_adi { struct spi_controller *ctlr; struct device *dev; @@ -74,6 +110,7 @@ struct sprd_adi { struct hwspinlock *hwlock; unsigned long slave_vbase; unsigned long slave_pbase; + struct notifier_block restart_handler; }; static int sprd_adi_check_paddr(struct sprd_adi *sadi, u32 paddr) @@ -270,6 +307,72 @@ static int sprd_adi_transfer_one(struct spi_controller *ctlr, return 0; } +static int sprd_adi_restart_handler(struct notifier_block *this, + unsigned long mode, void *cmd) +{ + struct sprd_adi *sadi = container_of(this, struct sprd_adi, + restart_handler); + u32 val, reboot_mode = 0; + + if (!cmd) + reboot_mode = HWRST_STATUS_NORMAL; + else if (!strncmp(cmd, "recovery", 8)) + reboot_mode = HWRST_STATUS_RECOVERY; + else if (!strncmp(cmd, "alarm", 5)) + reboot_mode = HWRST_STATUS_ALARM; + else if (!strncmp(cmd, "fastsleep", 9)) + reboot_mode = HWRST_STATUS_SLEEP; + else if (!strncmp(cmd, "bootloader", 10)) + reboot_mode = HWRST_STATUS_FASTBOOT; + else if (!strncmp(cmd, "panic", 5)) + reboot_mode = HWRST_STATUS_PANIC; + else if (!strncmp(cmd, "special", 7)) + reboot_mode = HWRST_STATUS_SPECIAL; + else if (!strncmp(cmd, "cftreboot", 9)) + reboot_mode = HWRST_STATUS_CFTREBOOT; + else if (!strncmp(cmd, "autodloader", 11)) + reboot_mode = HWRST_STATUS_AUTODLOADER; + else if (!strncmp(cmd, "iqmode", 6)) + reboot_mode = HWRST_STATUS_IQMODE; + else if (!strncmp(cmd, "sprdisk", 7)) + reboot_mode = HWRST_STATUS_SPRDISK; + else + reboot_mode = HWRST_STATUS_NORMAL; + + /* Record the reboot mode */ + sprd_adi_read(sadi, sadi->slave_pbase + PMIC_RST_STATUS, &val); + val |= reboot_mode; + sprd_adi_write(sadi, sadi->slave_pbase + PMIC_RST_STATUS, val); + + /* Enable the interface clock of the watchdog */ + sprd_adi_read(sadi, sadi->slave_pbase + PMIC_MODULE_EN, &val); + val |= BIT_WDG_EN; + sprd_adi_write(sadi, sadi->slave_pbase + PMIC_MODULE_EN, val); + + /* Enable the work clock of the watchdog */ + sprd_adi_read(sadi, sadi->slave_pbase + PMIC_CLK_EN, &val); + val |= BIT_WDG_EN; + sprd_adi_write(sadi, sadi->slave_pbase + PMIC_CLK_EN, val); + + /* Unlock the watchdog */ + sprd_adi_write(sadi, sadi->slave_pbase + REG_WDG_LOCK, WDG_UNLOCK_KEY); + + /* Load the watchdog timeout value, 50ms is always enough. */ + sprd_adi_write(sadi, sadi->slave_pbase + REG_WDG_LOAD_LOW, + WDG_LOAD_VAL & WDG_LOAD_MASK); + sprd_adi_write(sadi, sadi->slave_pbase + REG_WDG_LOAD_HIGH, 0); + + /* Start the watchdog to reset system */ + sprd_adi_read(sadi, sadi->slave_pbase + REG_WDG_CTRL, &val); + val |= BIT_WDG_RUN | BIT_WDG_RST; + sprd_adi_write(sadi, sadi->slave_pbase + REG_WDG_CTRL, val); + + mdelay(1000); + + dev_emerg(sadi->dev, "Unable to restart system\n"); + return NOTIFY_DONE; +} + static void sprd_adi_hw_init(struct sprd_adi *sadi) { struct device_node *np = sadi->dev->of_node; @@ -383,6 +486,14 @@ static int sprd_adi_probe(struct platform_device *pdev) goto free_hwlock; } + sadi->restart_handler.notifier_call = sprd_adi_restart_handler; + sadi->restart_handler.priority = 128; + ret = register_restart_handler(&sadi->restart_handler); + if (ret) { + dev_err(&pdev->dev, "can not register restart handler\n"); + goto free_hwlock; + } + return 0; free_hwlock: @@ -397,6 +508,7 @@ static int sprd_adi_remove(struct platform_device *pdev) struct spi_controller *ctlr = dev_get_drvdata(&pdev->dev); struct sprd_adi *sadi = spi_controller_get_devdata(ctlr); + unregister_restart_handler(&sadi->restart_handler); hwspin_lock_free(sadi->hwlock); return 0; } -- cgit v1.2.3 From da779513d33575fc43a9ae87a95af6b4354cebaa Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Wed, 21 Mar 2018 09:07:23 +0100 Subject: spi: sh-msiof: Use correct enum for DMA transfer direction Use enum dma_transfer_direction as required by dmaengine_prep_slave_sg() instead of enum dma_data_direction. This won't change behavior in practice as the enum values are equivalent. This fixes two warnings when building with clang: drivers/spi/spi-sh-msiof.c:755:27: warning: implicit conversion from enumeration type 'enum dma_data_direction' to different enumeration type 'enum dma_transfer_direction' [-Wenum-conversion] rx->sgl, rx->nents, DMA_FROM_DEVICE, ^~~~~~~~~~~~~~~ drivers/spi/spi-sh-msiof.c:772:27: warning: implicit conversion from enumeration type 'enum dma_data_direction' to different enumeration type 'enum dma_transfer_direction' [-Wenum-conversion] tx->sgl, tx->nents, DMA_TO_DEVICE, ^~~~~~~~~~~~~ Based on commit 768d59f5d0139a6f ("spi: rspi: use correct enum for DMA transfer direction"). Signed-off-by: Geert Uytterhoeven Reviewed-by: Stefan Agner Signed-off-by: Mark Brown --- drivers/spi/spi-sh-msiof.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi-sh-msiof.c b/drivers/spi/spi-sh-msiof.c index c5dcfb434a49..ae086aab57d5 100644 --- a/drivers/spi/spi-sh-msiof.c +++ b/drivers/spi/spi-sh-msiof.c @@ -752,7 +752,7 @@ static int sh_msiof_dma_once(struct sh_msiof_spi_priv *p, const void *tx, if (rx) { ier_bits |= IER_RDREQE | IER_RDMAE; desc_rx = dmaengine_prep_slave_single(p->master->dma_rx, - p->rx_dma_addr, len, DMA_FROM_DEVICE, + p->rx_dma_addr, len, DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); if (!desc_rx) return -EAGAIN; @@ -769,7 +769,7 @@ static int sh_msiof_dma_once(struct sh_msiof_spi_priv *p, const void *tx, dma_sync_single_for_device(p->master->dma_tx->device->dev, p->tx_dma_addr, len, DMA_TO_DEVICE); desc_tx = dmaengine_prep_slave_single(p->master->dma_tx, - p->tx_dma_addr, len, DMA_TO_DEVICE, + p->tx_dma_addr, len, DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); if (!desc_tx) { ret = -EAGAIN; -- cgit v1.2.3 From a687a5337063af99ebd0eebaa6f4b4cf2e07c21b Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 7 Mar 2018 23:30:54 +0100 Subject: treewide: simplify Kconfig dependencies for removed archs A lot of Kconfig symbols have architecture specific dependencies. In those cases that depend on architectures we have already removed, they can be omitted. Acked-by: Kalle Valo Acked-by: Alexandre Belloni Signed-off-by: Arnd Bergmann --- block/bounce.c | 2 +- drivers/ide/Kconfig | 2 +- drivers/ide/ide-generic.c | 12 +----------- drivers/input/joystick/analog.c | 2 +- drivers/isdn/hisax/Kconfig | 10 +++++----- drivers/net/ethernet/davicom/Kconfig | 2 +- drivers/net/ethernet/smsc/Kconfig | 6 +++--- drivers/net/wireless/cisco/Kconfig | 2 +- drivers/pwm/Kconfig | 2 +- drivers/rtc/Kconfig | 2 +- drivers/spi/Kconfig | 4 ++-- drivers/usb/musb/Kconfig | 2 +- drivers/video/console/Kconfig | 3 +-- drivers/watchdog/Kconfig | 6 ------ drivers/watchdog/Makefile | 6 ------ fs/Kconfig.binfmt | 5 ++--- fs/minix/Kconfig | 2 +- include/linux/ide.h | 7 +------ init/Kconfig | 5 ++--- lib/Kconfig.debug | 13 +++++-------- lib/test_user_copy.c | 2 -- mm/Kconfig | 7 ------- mm/percpu.c | 4 ---- 23 files changed, 31 insertions(+), 77 deletions(-) (limited to 'drivers/spi') diff --git a/block/bounce.c b/block/bounce.c index 6a3e68292273..dd0b93f2a871 100644 --- a/block/bounce.c +++ b/block/bounce.c @@ -31,7 +31,7 @@ static struct bio_set *bounce_bio_set, *bounce_bio_split; static mempool_t *page_pool, *isa_page_pool; -#if defined(CONFIG_HIGHMEM) || defined(CONFIG_NEED_BOUNCE_POOL) +#if defined(CONFIG_HIGHMEM) static __init int init_emergency_pool(void) { #if defined(CONFIG_HIGHMEM) && !defined(CONFIG_MEMORY_HOTPLUG) diff --git a/drivers/ide/Kconfig b/drivers/ide/Kconfig index cf1fb3fb5d26..901b8833847f 100644 --- a/drivers/ide/Kconfig +++ b/drivers/ide/Kconfig @@ -200,7 +200,7 @@ comment "IDE chipset support/bugfixes" config IDE_GENERIC tristate "generic/default IDE chipset support" - depends on ALPHA || X86 || IA64 || M32R || MIPS || ARCH_RPC + depends on ALPHA || X86 || IA64 || MIPS || ARCH_RPC default ARM && ARCH_RPC help This is the generic IDE driver. This driver attaches to the diff --git a/drivers/ide/ide-generic.c b/drivers/ide/ide-generic.c index 54d7c4685d23..80c0d69b83ac 100644 --- a/drivers/ide/ide-generic.c +++ b/drivers/ide/ide-generic.c @@ -13,13 +13,10 @@ #include #include -/* FIXME: convert arm and m32r to use ide_platform host driver */ +/* FIXME: convert arm to use ide_platform host driver */ #ifdef CONFIG_ARM #include #endif -#ifdef CONFIG_M32R -#include -#endif #define DRV_NAME "ide_generic" @@ -35,13 +32,6 @@ static const struct ide_port_info ide_generic_port_info = { #ifdef CONFIG_ARM static const u16 legacy_bases[] = { 0x1f0 }; static const int legacy_irqs[] = { IRQ_HARDDISK }; -#elif defined(CONFIG_PLAT_M32700UT) || defined(CONFIG_PLAT_MAPPI2) || \ - defined(CONFIG_PLAT_OPSPUT) -static const u16 legacy_bases[] = { 0x1f0 }; -static const int legacy_irqs[] = { PLD_IRQ_CFIREQ }; -#elif defined(CONFIG_PLAT_MAPPI3) -static const u16 legacy_bases[] = { 0x1f0, 0x170 }; -static const int legacy_irqs[] = { PLD_IRQ_CFIREQ, PLD_IRQ_IDEIREQ }; #elif defined(CONFIG_ALPHA) static const u16 legacy_bases[] = { 0x1f0, 0x170, 0x1e8, 0x168 }; static const int legacy_irqs[] = { 14, 15, 11, 10 }; diff --git a/drivers/input/joystick/analog.c b/drivers/input/joystick/analog.c index be1b4921f22a..eefac7978f93 100644 --- a/drivers/input/joystick/analog.c +++ b/drivers/input/joystick/analog.c @@ -163,7 +163,7 @@ static unsigned int get_time_pit(void) #define GET_TIME(x) do { x = (unsigned int)rdtsc(); } while (0) #define DELTA(x,y) ((y)-(x)) #define TIME_NAME "TSC" -#elif defined(__alpha__) || defined(CONFIG_ARM) || defined(CONFIG_ARM64) || defined(CONFIG_RISCV) || defined(CONFIG_TILE) +#elif defined(__alpha__) || defined(CONFIG_ARM) || defined(CONFIG_ARM64) || defined(CONFIG_RISCV) #define GET_TIME(x) do { x = get_cycles(); } while (0) #define DELTA(x,y) ((y)-(x)) #define TIME_NAME "get_cycles" diff --git a/drivers/isdn/hisax/Kconfig b/drivers/isdn/hisax/Kconfig index eb83d94ab4fe..38cfc8baae19 100644 --- a/drivers/isdn/hisax/Kconfig +++ b/drivers/isdn/hisax/Kconfig @@ -109,7 +109,7 @@ config HISAX_16_3 config HISAX_TELESPCI bool "Teles PCI" - depends on PCI && (BROKEN || !(SPARC || PPC || PARISC || M68K || (MIPS && !CPU_LITTLE_ENDIAN) || FRV || (XTENSA && !CPU_LITTLE_ENDIAN))) + depends on PCI && (BROKEN || !(SPARC || PPC || PARISC || M68K || (MIPS && !CPU_LITTLE_ENDIAN) || (XTENSA && !CPU_LITTLE_ENDIAN))) help This enables HiSax support for the Teles PCI. See on how to configure it. @@ -237,7 +237,7 @@ config HISAX_MIC config HISAX_NETJET bool "NETjet card" - depends on PCI && (BROKEN || !(PPC || PARISC || M68K || (MIPS && !CPU_LITTLE_ENDIAN) || FRV || (XTENSA && !CPU_LITTLE_ENDIAN) || MICROBLAZE)) + depends on PCI && (BROKEN || !(PPC || PARISC || M68K || (MIPS && !CPU_LITTLE_ENDIAN) || (XTENSA && !CPU_LITTLE_ENDIAN) || MICROBLAZE)) depends on VIRT_TO_BUS help This enables HiSax support for the NetJet from Traverse @@ -249,7 +249,7 @@ config HISAX_NETJET config HISAX_NETJET_U bool "NETspider U card" - depends on PCI && (BROKEN || !(PPC || PARISC || M68K || (MIPS && !CPU_LITTLE_ENDIAN) || FRV || (XTENSA && !CPU_LITTLE_ENDIAN) || MICROBLAZE)) + depends on PCI && (BROKEN || !(PPC || PARISC || M68K || (MIPS && !CPU_LITTLE_ENDIAN) || (XTENSA && !CPU_LITTLE_ENDIAN) || MICROBLAZE)) depends on VIRT_TO_BUS help This enables HiSax support for the Netspider U interface ISDN card @@ -318,7 +318,7 @@ config HISAX_GAZEL config HISAX_HFC_PCI bool "HFC PCI-Bus cards" - depends on PCI && (BROKEN || !(SPARC || PPC || PARISC || M68K || (MIPS && !CPU_LITTLE_ENDIAN) || FRV || (XTENSA && !CPU_LITTLE_ENDIAN))) + depends on PCI && (BROKEN || !(SPARC || PPC || PARISC || M68K || (MIPS && !CPU_LITTLE_ENDIAN) || (XTENSA && !CPU_LITTLE_ENDIAN))) help This enables HiSax support for the HFC-S PCI 2BDS0 based cards. @@ -343,7 +343,7 @@ config HISAX_HFC_SX config HISAX_ENTERNOW_PCI bool "Formula-n enter:now PCI card" - depends on HISAX_NETJET && PCI && (BROKEN || !(SPARC || PPC || PARISC || M68K || (MIPS && !CPU_LITTLE_ENDIAN) || FRV || (XTENSA && !CPU_LITTLE_ENDIAN))) + depends on HISAX_NETJET && PCI && (BROKEN || !(SPARC || PPC || PARISC || M68K || (MIPS && !CPU_LITTLE_ENDIAN) || (XTENSA && !CPU_LITTLE_ENDIAN))) help This enables HiSax support for the Formula-n enter:now PCI ISDN card. diff --git a/drivers/net/ethernet/davicom/Kconfig b/drivers/net/ethernet/davicom/Kconfig index 7ec2d74f94d3..680a6d983f37 100644 --- a/drivers/net/ethernet/davicom/Kconfig +++ b/drivers/net/ethernet/davicom/Kconfig @@ -4,7 +4,7 @@ config DM9000 tristate "DM9000 support" - depends on ARM || BLACKFIN || MIPS || COLDFIRE || NIOS2 + depends on ARM || MIPS || COLDFIRE || NIOS2 select CRC32 select MII ---help--- diff --git a/drivers/net/ethernet/smsc/Kconfig b/drivers/net/ethernet/smsc/Kconfig index 948603e9b905..3da0c573d2ab 100644 --- a/drivers/net/ethernet/smsc/Kconfig +++ b/drivers/net/ethernet/smsc/Kconfig @@ -5,8 +5,8 @@ config NET_VENDOR_SMSC bool "SMC (SMSC)/Western Digital devices" default y - depends on ARM || ARM64 || ATARI_ETHERNAT || BLACKFIN || COLDFIRE || \ - ISA || M32R || MAC || MIPS || NIOS2 || PCI || \ + depends on ARM || ARM64 || ATARI_ETHERNAT || COLDFIRE || \ + ISA || MAC || MIPS || NIOS2 || PCI || \ PCMCIA || SUPERH || XTENSA || H8300 ---help--- If you have a network (Ethernet) card belonging to this class, say Y. @@ -37,7 +37,7 @@ config SMC91X select CRC32 select MII depends on !OF || GPIOLIB - depends on ARM || ARM64 || ATARI_ETHERNAT || BLACKFIN || COLDFIRE || \ + depends on ARM || ARM64 || ATARI_ETHERNAT || COLDFIRE || \ M32R || MIPS || NIOS2 || SUPERH || XTENSA || H8300 ---help--- This is a driver for SMC's 91x series of Ethernet chipsets, diff --git a/drivers/net/wireless/cisco/Kconfig b/drivers/net/wireless/cisco/Kconfig index b22567dff893..8ed0b154bb33 100644 --- a/drivers/net/wireless/cisco/Kconfig +++ b/drivers/net/wireless/cisco/Kconfig @@ -33,7 +33,7 @@ config AIRO config AIRO_CS tristate "Cisco/Aironet 34X/35X/4500/4800 PCMCIA cards" - depends on CFG80211 && PCMCIA && (BROKEN || !M32R) + depends on CFG80211 && PCMCIA select WIRELESS_EXT select WEXT_SPY select WEXT_PRIV diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig index 763ee50ea57d..f16aad3bf5d6 100644 --- a/drivers/pwm/Kconfig +++ b/drivers/pwm/Kconfig @@ -43,7 +43,7 @@ config PWM_AB8500 config PWM_ATMEL tristate "Atmel PWM support" - depends on ARCH_AT91 || AVR32 + depends on ARCH_AT91 help Generic PWM framework driver for Atmel SoC. diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index be5a3dc99c11..46af10ac45fc 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -868,7 +868,7 @@ comment "Platform RTC drivers" config RTC_DRV_CMOS tristate "PC-style 'CMOS'" - depends on X86 || ARM || M32R || PPC || MIPS || SPARC64 + depends on X86 || ARM || PPC || MIPS || SPARC64 default y if X86 select RTC_MC146818_LIB help diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index 603783976b81..103c13fcefa0 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -72,10 +72,10 @@ config SPI_ARMADA_3700 config SPI_ATMEL tristate "Atmel SPI Controller" depends on HAS_DMA - depends on (ARCH_AT91 || AVR32 || COMPILE_TEST) + depends on ARCH_AT91 || COMPILE_TEST help This selects a driver for the Atmel SPI Controller, present on - many AT32 (AVR32) and AT91 (ARM) chips. + many AT91 ARM chips. config SPI_AU1550 tristate "Au1550/Au1200/Au1300 SPI Controller" diff --git a/drivers/usb/musb/Kconfig b/drivers/usb/musb/Kconfig index 5506a9c03c1f..e757afc1cfd0 100644 --- a/drivers/usb/musb/Kconfig +++ b/drivers/usb/musb/Kconfig @@ -87,7 +87,7 @@ config USB_MUSB_DA8XX config USB_MUSB_TUSB6010 tristate "TUSB6010" depends on HAS_IOMEM - depends on (ARCH_OMAP2PLUS || COMPILE_TEST) && !BLACKFIN + depends on ARCH_OMAP2PLUS || COMPILE_TEST depends on NOP_USB_XCEIV = USB_MUSB_HDRC # both built-in or both modules config USB_MUSB_OMAP2PLUS diff --git a/drivers/video/console/Kconfig b/drivers/video/console/Kconfig index 005ed87c8216..a9e398c144f8 100644 --- a/drivers/video/console/Kconfig +++ b/drivers/video/console/Kconfig @@ -6,8 +6,7 @@ menu "Console display driver support" config VGA_CONSOLE bool "VGA text console" if EXPERT || !X86 - depends on !4xx && !PPC_8xx && !SPARC && !M68K && !PARISC && !FRV && \ - !SUPERH && !BLACKFIN && !AVR32 && !CRIS && \ + depends on !4xx && !PPC_8xx && !SPARC && !M68K && !PARISC && !SUPERH && \ (!ARM || ARCH_FOOTBRIDGE || ARCH_INTEGRATOR || ARCH_NETWINDER) && \ !ARM64 && !ARC && !MICROBLAZE && !OPENRISC default y diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index 0e19679348d1..79020ce95de2 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig @@ -828,10 +828,6 @@ config BFIN_WDT To compile this driver as a module, choose M here: the module will be called bfin_wdt. -# CRIS Architecture - -# FRV Architecture - # X86 (i386 + ia64 + x86_64) Architecture config ACQUIRE_WDT @@ -1431,8 +1427,6 @@ config NIC7018_WDT To compile this driver as a module, choose M here: the module will be called nic7018_wdt. -# M32R Architecture - # M68K Architecture config M54xx_WATCHDOG diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile index 0474d38aa854..1f9a0235f22c 100644 --- a/drivers/watchdog/Makefile +++ b/drivers/watchdog/Makefile @@ -94,10 +94,6 @@ obj-$(CONFIG_SPRD_WATCHDOG) += sprd_wdt.o # BLACKFIN Architecture obj-$(CONFIG_BFIN_WDT) += bfin_wdt.o -# CRIS Architecture - -# FRV Architecture - # X86 (i386 + ia64 + x86_64) Architecture obj-$(CONFIG_ACQUIRE_WDT) += acquirewdt.o obj-$(CONFIG_ADVANTECH_WDT) += advantechwdt.o @@ -146,8 +142,6 @@ obj-$(CONFIG_INTEL_MEI_WDT) += mei_wdt.o obj-$(CONFIG_NI903X_WDT) += ni903x_wdt.o obj-$(CONFIG_NIC7018_WDT) += nic7018_wdt.o -# M32R Architecture - # M68K Architecture obj-$(CONFIG_M54xx_WATCHDOG) += m54xx_wdt.o diff --git a/fs/Kconfig.binfmt b/fs/Kconfig.binfmt index 58c2bbd385ad..57a27c42b5ac 100644 --- a/fs/Kconfig.binfmt +++ b/fs/Kconfig.binfmt @@ -1,6 +1,6 @@ config BINFMT_ELF bool "Kernel support for ELF binaries" - depends on MMU && (BROKEN || !FRV) + depends on MMU select ELFCORE default y ---help--- @@ -35,7 +35,7 @@ config ARCH_BINFMT_ELF_STATE config BINFMT_ELF_FDPIC bool "Kernel support for FDPIC ELF binaries" default y if !BINFMT_ELF - depends on (ARM || FRV || BLACKFIN || (SUPERH32 && !MMU) || C6X) + depends on (ARM || (SUPERH32 && !MMU) || C6X) select ELFCORE help ELF FDPIC binaries are based on ELF, but allow the individual load @@ -90,7 +90,6 @@ config BINFMT_SCRIPT config BINFMT_FLAT bool "Kernel support for flat binaries" depends on !MMU || ARM || M68K - depends on !FRV || BROKEN help Support uClinux FLAT format binaries. diff --git a/fs/minix/Kconfig b/fs/minix/Kconfig index f2a0cfcef11d..bcd53a79156f 100644 --- a/fs/minix/Kconfig +++ b/fs/minix/Kconfig @@ -18,7 +18,7 @@ config MINIX_FS config MINIX_FS_NATIVE_ENDIAN def_bool MINIX_FS - depends on M32R || MICROBLAZE || MIPS || S390 || SUPERH || SPARC || XTENSA || (M68K && !MMU) + depends on MICROBLAZE || MIPS || S390 || SUPERH || SPARC || XTENSA || (M68K && !MMU) config MINIX_FS_BIG_ENDIAN_16BIT_INDEXED def_bool MINIX_FS diff --git a/include/linux/ide.h b/include/linux/ide.h index 20d42c0d9fb6..1d6f16110eae 100644 --- a/include/linux/ide.h +++ b/include/linux/ide.h @@ -25,15 +25,10 @@ #include #include -#if defined(CONFIG_CRIS) || defined(CONFIG_FRV) -# define SUPPORT_VLB_SYNC 0 -#else -# define SUPPORT_VLB_SYNC 1 -#endif - /* * Probably not wise to fiddle with these */ +#define SUPPORT_VLB_SYNC 1 #define IDE_DEFAULT_MAX_FAILURES 1 #define ERROR_MAX 8 /* Max read/write errors per sector */ #define ERROR_RESET 3 /* Reset controller every 4th retry */ diff --git a/init/Kconfig b/init/Kconfig index a14bcc9724a2..2852692d7c9c 100644 --- a/init/Kconfig +++ b/init/Kconfig @@ -998,7 +998,6 @@ config RELAY config BLK_DEV_INITRD bool "Initial RAM filesystem and RAM disk (initramfs/initrd) support" - depends on BROKEN || !FRV help The initial RAM filesystem is a ramfs which is loaded by the boot loader (loadlin or lilo) and that is mounted as root @@ -1108,7 +1107,7 @@ config MULTIUSER config SGETMASK_SYSCALL bool "sgetmask/ssetmask syscalls support" if EXPERT - def_bool PARISC || BLACKFIN || M68K || PPC || MIPS || X86 || SPARC || CRIS || MICROBLAZE || SUPERH + def_bool PARISC || M68K || PPC || MIPS || X86 || SPARC || MICROBLAZE || SUPERH ---help--- sys_sgetmask and sys_ssetmask are obsolete system calls no longer supported in libc but still enabled by default in some @@ -1370,7 +1369,7 @@ config KALLSYMS_ABSOLUTE_PERCPU config KALLSYMS_BASE_RELATIVE bool depends on KALLSYMS - default !IA64 && !(TILE && 64BIT) + default !IA64 help Instead of emitting them as absolute values in the native word size, emit the symbol references in the kallsyms table as 32-bit entries, diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index 41ac9d294245..6927c6d8d185 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug @@ -165,7 +165,7 @@ config DEBUG_INFO_REDUCED config DEBUG_INFO_SPLIT bool "Produce split debuginfo in .dwo files" - depends on DEBUG_INFO && !FRV + depends on DEBUG_INFO help Generate debug info into separate .dwo files. This significantly reduces the build directory size for builds with DEBUG_INFO, @@ -354,10 +354,7 @@ config ARCH_WANT_FRAME_POINTERS config FRAME_POINTER bool "Compile the kernel with frame pointers" - depends on DEBUG_KERNEL && \ - (CRIS || M68K || FRV || UML || \ - SUPERH || BLACKFIN) || \ - ARCH_WANT_FRAME_POINTERS + depends on DEBUG_KERNEL && (M68K || UML || SUPERH) || ARCH_WANT_FRAME_POINTERS default y if (DEBUG_INFO && UML) || ARCH_WANT_FRAME_POINTERS help If you say Y here the resulting kernel image will be slightly @@ -1138,7 +1135,7 @@ config LOCKDEP bool depends on DEBUG_KERNEL && TRACE_IRQFLAGS_SUPPORT && STACKTRACE_SUPPORT && LOCKDEP_SUPPORT select STACKTRACE - select FRAME_POINTER if !MIPS && !PPC && !ARM_UNWIND && !S390 && !MICROBLAZE && !ARC && !SCORE && !X86 + select FRAME_POINTER if !MIPS && !PPC && !ARM_UNWIND && !S390 && !MICROBLAZE && !ARC && !X86 select KALLSYMS select KALLSYMS_ALL @@ -1571,7 +1568,7 @@ config FAULT_INJECTION_STACKTRACE_FILTER depends on FAULT_INJECTION_DEBUG_FS && STACKTRACE_SUPPORT depends on !X86_64 select STACKTRACE - select FRAME_POINTER if !MIPS && !PPC && !S390 && !MICROBLAZE && !ARM_UNWIND && !ARC && !SCORE && !X86 + select FRAME_POINTER if !MIPS && !PPC && !S390 && !MICROBLAZE && !ARM_UNWIND && !ARC && !X86 help Provide stacktrace filter for fault-injection capabilities @@ -1969,7 +1966,7 @@ config STRICT_DEVMEM bool "Filter access to /dev/mem" depends on MMU && DEVMEM depends on ARCH_HAS_DEVMEM_IS_ALLOWED - default y if TILE || PPC || X86 || ARM64 + default y if PPC || X86 || ARM64 ---help--- If this option is disabled, you allow userspace (root) access to all of memory, including kernel and userspace memory. Accidental diff --git a/lib/test_user_copy.c b/lib/test_user_copy.c index a6556f3364d1..e161f0498f42 100644 --- a/lib/test_user_copy.c +++ b/lib/test_user_copy.c @@ -31,8 +31,6 @@ * their capability at compile-time, we just have to opt-out certain archs. */ #if BITS_PER_LONG == 64 || (!(defined(CONFIG_ARM) && !defined(MMU)) && \ - !defined(CONFIG_BLACKFIN) && \ - !defined(CONFIG_M32R) && \ !defined(CONFIG_M68K) && \ !defined(CONFIG_MICROBLAZE) && \ !defined(CONFIG_NIOS2) && \ diff --git a/mm/Kconfig b/mm/Kconfig index abefa573bcd8..d5004d82a1d6 100644 --- a/mm/Kconfig +++ b/mm/Kconfig @@ -278,13 +278,6 @@ config BOUNCE by default when ZONE_DMA or HIGHMEM is selected, but you may say n to override this. -# On the 'tile' arch, USB OHCI needs the bounce pool since tilegx will often -# have more than 4GB of memory, but we don't currently use the IOTLB to present -# a 32-bit address to OHCI. So we need to use a bounce pool instead. -config NEED_BOUNCE_POOL - bool - default y if TILE && USB_OHCI_HCD - config NR_QUICK int depends on QUICKLIST diff --git a/mm/percpu.c b/mm/percpu.c index 50e7fdf84055..79e3549cab0f 100644 --- a/mm/percpu.c +++ b/mm/percpu.c @@ -2719,11 +2719,7 @@ void __init setup_per_cpu_areas(void) if (pcpu_setup_first_chunk(ai, fc) < 0) panic("Failed to initialize percpu areas."); -#ifdef CONFIG_CRIS -#warning "the CRIS architecture has physical and virtual addresses confused" -#else pcpu_free_alloc_info(ai); -#endif } #endif /* CONFIG_SMP */ -- cgit v1.2.3 From 47838669de9d9e1411fab9323f2ac1457d1944d2 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Fri, 9 Mar 2018 21:10:44 +0100 Subject: spi: remove blackfin related host drivers The blackfin architecture is getting removed, so these won't be needed any more. Acked-by: Mark Brown Acked-by: Aaron Wu Signed-off-by: Arnd Bergmann --- drivers/spi/Kconfig | 19 - drivers/spi/Makefile | 3 - drivers/spi/spi-adi-v3.c | 984 ---------------------------- drivers/spi/spi-bfin-sport.c | 919 -------------------------- drivers/spi/spi-bfin5xx.c | 1462 ------------------------------------------ 5 files changed, 3387 deletions(-) delete mode 100644 drivers/spi/spi-adi-v3.c delete mode 100644 drivers/spi/spi-bfin-sport.c delete mode 100644 drivers/spi/spi-bfin5xx.c (limited to 'drivers/spi') diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index 103c13fcefa0..2d4146ce2f1b 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -115,25 +115,6 @@ config SPI_BCM2835AUX "universal SPI master", and the regular SPI controller. This driver is for the universal/auxiliary SPI controller. -config SPI_BFIN5XX - tristate "SPI controller driver for ADI Blackfin5xx" - depends on BLACKFIN && !BF60x - help - This is the SPI controller master driver for Blackfin 5xx processor. - -config SPI_ADI_V3 - tristate "SPI controller v3 for ADI" - depends on BF60x - help - This is the SPI controller v3 master driver - found on Blackfin 60x processor. - -config SPI_BFIN_SPORT - tristate "SPI bus via Blackfin SPORT" - depends on BLACKFIN - help - Enable support for a SPI bus via the Blackfin SPORT peripheral. - config SPI_BCM53XX tristate "Broadcom BCM53xx SPI controller" depends on ARCH_BCM_5301X diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile index 34c5f2832ddf..b935f10eb961 100644 --- a/drivers/spi/Makefile +++ b/drivers/spi/Makefile @@ -24,9 +24,6 @@ obj-$(CONFIG_SPI_BCM53XX) += spi-bcm53xx.o obj-$(CONFIG_SPI_BCM63XX) += spi-bcm63xx.o obj-$(CONFIG_SPI_BCM63XX_HSSPI) += spi-bcm63xx-hsspi.o obj-$(CONFIG_SPI_BCM_QSPI) += spi-iproc-qspi.o spi-brcmstb-qspi.o spi-bcm-qspi.o -obj-$(CONFIG_SPI_BFIN5XX) += spi-bfin5xx.o -obj-$(CONFIG_SPI_ADI_V3) += spi-adi-v3.o -obj-$(CONFIG_SPI_BFIN_SPORT) += spi-bfin-sport.o obj-$(CONFIG_SPI_BITBANG) += spi-bitbang.o obj-$(CONFIG_SPI_BUTTERFLY) += spi-butterfly.o obj-$(CONFIG_SPI_CADENCE) += spi-cadence.o diff --git a/drivers/spi/spi-adi-v3.c b/drivers/spi/spi-adi-v3.c deleted file mode 100644 index a16b25dcd1e6..000000000000 --- a/drivers/spi/spi-adi-v3.c +++ /dev/null @@ -1,984 +0,0 @@ -/* - * Analog Devices SPI3 controller driver - * - * Copyright (c) 2014 Analog Devices 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. - * - * 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -enum adi_spi_state { - START_STATE, - RUNNING_STATE, - DONE_STATE, - ERROR_STATE -}; - -struct adi_spi_master; - -struct adi_spi_transfer_ops { - void (*write) (struct adi_spi_master *); - void (*read) (struct adi_spi_master *); - void (*duplex) (struct adi_spi_master *); -}; - -/* runtime info for spi master */ -struct adi_spi_master { - /* SPI framework hookup */ - struct spi_master *master; - - /* Regs base of SPI controller */ - struct adi_spi_regs __iomem *regs; - - /* Pin request list */ - u16 *pin_req; - - /* Message Transfer pump */ - struct tasklet_struct pump_transfers; - - /* Current message transfer state info */ - struct spi_message *cur_msg; - struct spi_transfer *cur_transfer; - struct adi_spi_device *cur_chip; - unsigned transfer_len; - - /* transfer buffer */ - void *tx; - void *tx_end; - void *rx; - void *rx_end; - - /* dma info */ - unsigned int tx_dma; - unsigned int rx_dma; - dma_addr_t tx_dma_addr; - dma_addr_t rx_dma_addr; - unsigned long dummy_buffer; /* used in unidirectional transfer */ - unsigned long tx_dma_size; - unsigned long rx_dma_size; - int tx_num; - int rx_num; - - /* store register value for suspend/resume */ - u32 control; - u32 ssel; - - unsigned long sclk; - enum adi_spi_state state; - - const struct adi_spi_transfer_ops *ops; -}; - -struct adi_spi_device { - u32 control; - u32 clock; - u32 ssel; - - u8 cs; - u16 cs_chg_udelay; /* Some devices require > 255usec delay */ - u32 cs_gpio; - u32 tx_dummy_val; /* tx value for rx only transfer */ - bool enable_dma; - const struct adi_spi_transfer_ops *ops; -}; - -static void adi_spi_enable(struct adi_spi_master *drv_data) -{ - u32 ctl; - - ctl = ioread32(&drv_data->regs->control); - ctl |= SPI_CTL_EN; - iowrite32(ctl, &drv_data->regs->control); -} - -static void adi_spi_disable(struct adi_spi_master *drv_data) -{ - u32 ctl; - - ctl = ioread32(&drv_data->regs->control); - ctl &= ~SPI_CTL_EN; - iowrite32(ctl, &drv_data->regs->control); -} - -/* Caculate the SPI_CLOCK register value based on input HZ */ -static u32 hz_to_spi_clock(u32 sclk, u32 speed_hz) -{ - u32 spi_clock = sclk / speed_hz; - - if (spi_clock) - spi_clock--; - return spi_clock; -} - -static int adi_spi_flush(struct adi_spi_master *drv_data) -{ - unsigned long limit = loops_per_jiffy << 1; - - /* wait for stop and clear stat */ - while (!(ioread32(&drv_data->regs->status) & SPI_STAT_SPIF) && --limit) - cpu_relax(); - - iowrite32(0xFFFFFFFF, &drv_data->regs->status); - - return limit; -} - -/* Chip select operation functions for cs_change flag */ -static void adi_spi_cs_active(struct adi_spi_master *drv_data, struct adi_spi_device *chip) -{ - if (likely(chip->cs < MAX_CTRL_CS)) { - u32 reg; - reg = ioread32(&drv_data->regs->ssel); - reg &= ~chip->ssel; - iowrite32(reg, &drv_data->regs->ssel); - } else { - gpio_set_value(chip->cs_gpio, 0); - } -} - -static void adi_spi_cs_deactive(struct adi_spi_master *drv_data, - struct adi_spi_device *chip) -{ - if (likely(chip->cs < MAX_CTRL_CS)) { - u32 reg; - reg = ioread32(&drv_data->regs->ssel); - reg |= chip->ssel; - iowrite32(reg, &drv_data->regs->ssel); - } else { - gpio_set_value(chip->cs_gpio, 1); - } - - /* Move delay here for consistency */ - if (chip->cs_chg_udelay) - udelay(chip->cs_chg_udelay); -} - -/* enable or disable the pin muxed by GPIO and SPI CS to work as SPI CS */ -static inline void adi_spi_cs_enable(struct adi_spi_master *drv_data, - struct adi_spi_device *chip) -{ - if (chip->cs < MAX_CTRL_CS) { - u32 reg; - reg = ioread32(&drv_data->regs->ssel); - reg |= chip->ssel >> 8; - iowrite32(reg, &drv_data->regs->ssel); - } -} - -static inline void adi_spi_cs_disable(struct adi_spi_master *drv_data, - struct adi_spi_device *chip) -{ - if (chip->cs < MAX_CTRL_CS) { - u32 reg; - reg = ioread32(&drv_data->regs->ssel); - reg &= ~(chip->ssel >> 8); - iowrite32(reg, &drv_data->regs->ssel); - } -} - -/* stop controller and re-config current chip*/ -static void adi_spi_restore_state(struct adi_spi_master *drv_data) -{ - struct adi_spi_device *chip = drv_data->cur_chip; - - /* Clear status and disable clock */ - iowrite32(0xFFFFFFFF, &drv_data->regs->status); - iowrite32(0x0, &drv_data->regs->rx_control); - iowrite32(0x0, &drv_data->regs->tx_control); - adi_spi_disable(drv_data); - - /* Load the registers */ - iowrite32(chip->control, &drv_data->regs->control); - iowrite32(chip->clock, &drv_data->regs->clock); - - adi_spi_enable(drv_data); - drv_data->tx_num = drv_data->rx_num = 0; - /* we always choose tx transfer initiate */ - iowrite32(SPI_RXCTL_REN, &drv_data->regs->rx_control); - iowrite32(SPI_TXCTL_TEN | SPI_TXCTL_TTI, &drv_data->regs->tx_control); - adi_spi_cs_active(drv_data, chip); -} - -/* discard invalid rx data and empty rfifo */ -static inline void dummy_read(struct adi_spi_master *drv_data) -{ - while (!(ioread32(&drv_data->regs->status) & SPI_STAT_RFE)) - ioread32(&drv_data->regs->rfifo); -} - -static void adi_spi_u8_write(struct adi_spi_master *drv_data) -{ - dummy_read(drv_data); - while (drv_data->tx < drv_data->tx_end) { - iowrite32(*(u8 *)(drv_data->tx++), &drv_data->regs->tfifo); - while (ioread32(&drv_data->regs->status) & SPI_STAT_RFE) - cpu_relax(); - ioread32(&drv_data->regs->rfifo); - } -} - -static void adi_spi_u8_read(struct adi_spi_master *drv_data) -{ - u32 tx_val = drv_data->cur_chip->tx_dummy_val; - - dummy_read(drv_data); - while (drv_data->rx < drv_data->rx_end) { - iowrite32(tx_val, &drv_data->regs->tfifo); - while (ioread32(&drv_data->regs->status) & SPI_STAT_RFE) - cpu_relax(); - *(u8 *)(drv_data->rx++) = ioread32(&drv_data->regs->rfifo); - } -} - -static void adi_spi_u8_duplex(struct adi_spi_master *drv_data) -{ - dummy_read(drv_data); - while (drv_data->rx < drv_data->rx_end) { - iowrite32(*(u8 *)(drv_data->tx++), &drv_data->regs->tfifo); - while (ioread32(&drv_data->regs->status) & SPI_STAT_RFE) - cpu_relax(); - *(u8 *)(drv_data->rx++) = ioread32(&drv_data->regs->rfifo); - } -} - -static const struct adi_spi_transfer_ops adi_spi_transfer_ops_u8 = { - .write = adi_spi_u8_write, - .read = adi_spi_u8_read, - .duplex = adi_spi_u8_duplex, -}; - -static void adi_spi_u16_write(struct adi_spi_master *drv_data) -{ - dummy_read(drv_data); - while (drv_data->tx < drv_data->tx_end) { - iowrite32(*(u16 *)drv_data->tx, &drv_data->regs->tfifo); - drv_data->tx += 2; - while (ioread32(&drv_data->regs->status) & SPI_STAT_RFE) - cpu_relax(); - ioread32(&drv_data->regs->rfifo); - } -} - -static void adi_spi_u16_read(struct adi_spi_master *drv_data) -{ - u32 tx_val = drv_data->cur_chip->tx_dummy_val; - - dummy_read(drv_data); - while (drv_data->rx < drv_data->rx_end) { - iowrite32(tx_val, &drv_data->regs->tfifo); - while (ioread32(&drv_data->regs->status) & SPI_STAT_RFE) - cpu_relax(); - *(u16 *)drv_data->rx = ioread32(&drv_data->regs->rfifo); - drv_data->rx += 2; - } -} - -static void adi_spi_u16_duplex(struct adi_spi_master *drv_data) -{ - dummy_read(drv_data); - while (drv_data->rx < drv_data->rx_end) { - iowrite32(*(u16 *)drv_data->tx, &drv_data->regs->tfifo); - drv_data->tx += 2; - while (ioread32(&drv_data->regs->status) & SPI_STAT_RFE) - cpu_relax(); - *(u16 *)drv_data->rx = ioread32(&drv_data->regs->rfifo); - drv_data->rx += 2; - } -} - -static const struct adi_spi_transfer_ops adi_spi_transfer_ops_u16 = { - .write = adi_spi_u16_write, - .read = adi_spi_u16_read, - .duplex = adi_spi_u16_duplex, -}; - -static void adi_spi_u32_write(struct adi_spi_master *drv_data) -{ - dummy_read(drv_data); - while (drv_data->tx < drv_data->tx_end) { - iowrite32(*(u32 *)drv_data->tx, &drv_data->regs->tfifo); - drv_data->tx += 4; - while (ioread32(&drv_data->regs->status) & SPI_STAT_RFE) - cpu_relax(); - ioread32(&drv_data->regs->rfifo); - } -} - -static void adi_spi_u32_read(struct adi_spi_master *drv_data) -{ - u32 tx_val = drv_data->cur_chip->tx_dummy_val; - - dummy_read(drv_data); - while (drv_data->rx < drv_data->rx_end) { - iowrite32(tx_val, &drv_data->regs->tfifo); - while (ioread32(&drv_data->regs->status) & SPI_STAT_RFE) - cpu_relax(); - *(u32 *)drv_data->rx = ioread32(&drv_data->regs->rfifo); - drv_data->rx += 4; - } -} - -static void adi_spi_u32_duplex(struct adi_spi_master *drv_data) -{ - dummy_read(drv_data); - while (drv_data->rx < drv_data->rx_end) { - iowrite32(*(u32 *)drv_data->tx, &drv_data->regs->tfifo); - drv_data->tx += 4; - while (ioread32(&drv_data->regs->status) & SPI_STAT_RFE) - cpu_relax(); - *(u32 *)drv_data->rx = ioread32(&drv_data->regs->rfifo); - drv_data->rx += 4; - } -} - -static const struct adi_spi_transfer_ops adi_spi_transfer_ops_u32 = { - .write = adi_spi_u32_write, - .read = adi_spi_u32_read, - .duplex = adi_spi_u32_duplex, -}; - - -/* test if there is more transfer to be done */ -static void adi_spi_next_transfer(struct adi_spi_master *drv) -{ - struct spi_message *msg = drv->cur_msg; - struct spi_transfer *t = drv->cur_transfer; - - /* Move to next transfer */ - if (t->transfer_list.next != &msg->transfers) { - drv->cur_transfer = list_entry(t->transfer_list.next, - struct spi_transfer, transfer_list); - drv->state = RUNNING_STATE; - } else { - drv->state = DONE_STATE; - drv->cur_transfer = NULL; - } -} - -static void adi_spi_giveback(struct adi_spi_master *drv_data) -{ - struct adi_spi_device *chip = drv_data->cur_chip; - - adi_spi_cs_deactive(drv_data, chip); - spi_finalize_current_message(drv_data->master); -} - -static int adi_spi_setup_transfer(struct adi_spi_master *drv) -{ - struct spi_transfer *t = drv->cur_transfer; - u32 cr, cr_width; - - if (t->tx_buf) { - drv->tx = (void *)t->tx_buf; - drv->tx_end = drv->tx + t->len; - } else { - drv->tx = NULL; - } - - if (t->rx_buf) { - drv->rx = t->rx_buf; - drv->rx_end = drv->rx + t->len; - } else { - drv->rx = NULL; - } - - drv->transfer_len = t->len; - - /* bits per word setup */ - switch (t->bits_per_word) { - case 8: - cr_width = SPI_CTL_SIZE08; - drv->ops = &adi_spi_transfer_ops_u8; - break; - case 16: - cr_width = SPI_CTL_SIZE16; - drv->ops = &adi_spi_transfer_ops_u16; - break; - case 32: - cr_width = SPI_CTL_SIZE32; - drv->ops = &adi_spi_transfer_ops_u32; - break; - default: - return -EINVAL; - } - cr = ioread32(&drv->regs->control) & ~SPI_CTL_SIZE; - cr |= cr_width; - iowrite32(cr, &drv->regs->control); - - /* speed setup */ - iowrite32(hz_to_spi_clock(drv->sclk, t->speed_hz), &drv->regs->clock); - return 0; -} - -static int adi_spi_dma_xfer(struct adi_spi_master *drv_data) -{ - struct spi_transfer *t = drv_data->cur_transfer; - struct spi_message *msg = drv_data->cur_msg; - struct adi_spi_device *chip = drv_data->cur_chip; - u32 dma_config; - unsigned long word_count, word_size; - void *tx_buf, *rx_buf; - - switch (t->bits_per_word) { - case 8: - dma_config = WDSIZE_8 | PSIZE_8; - word_count = drv_data->transfer_len; - word_size = 1; - break; - case 16: - dma_config = WDSIZE_16 | PSIZE_16; - word_count = drv_data->transfer_len / 2; - word_size = 2; - break; - default: - dma_config = WDSIZE_32 | PSIZE_32; - word_count = drv_data->transfer_len / 4; - word_size = 4; - break; - } - - if (!drv_data->rx) { - tx_buf = drv_data->tx; - rx_buf = &drv_data->dummy_buffer; - drv_data->tx_dma_size = drv_data->transfer_len; - drv_data->rx_dma_size = sizeof(drv_data->dummy_buffer); - set_dma_x_modify(drv_data->tx_dma, word_size); - set_dma_x_modify(drv_data->rx_dma, 0); - } else if (!drv_data->tx) { - drv_data->dummy_buffer = chip->tx_dummy_val; - tx_buf = &drv_data->dummy_buffer; - rx_buf = drv_data->rx; - drv_data->tx_dma_size = sizeof(drv_data->dummy_buffer); - drv_data->rx_dma_size = drv_data->transfer_len; - set_dma_x_modify(drv_data->tx_dma, 0); - set_dma_x_modify(drv_data->rx_dma, word_size); - } else { - tx_buf = drv_data->tx; - rx_buf = drv_data->rx; - drv_data->tx_dma_size = drv_data->rx_dma_size - = drv_data->transfer_len; - set_dma_x_modify(drv_data->tx_dma, word_size); - set_dma_x_modify(drv_data->rx_dma, word_size); - } - - drv_data->tx_dma_addr = dma_map_single(&msg->spi->dev, - (void *)tx_buf, - drv_data->tx_dma_size, - DMA_TO_DEVICE); - if (dma_mapping_error(&msg->spi->dev, - drv_data->tx_dma_addr)) - return -ENOMEM; - - drv_data->rx_dma_addr = dma_map_single(&msg->spi->dev, - (void *)rx_buf, - drv_data->rx_dma_size, - DMA_FROM_DEVICE); - if (dma_mapping_error(&msg->spi->dev, - drv_data->rx_dma_addr)) { - dma_unmap_single(&msg->spi->dev, - drv_data->tx_dma_addr, - drv_data->tx_dma_size, - DMA_TO_DEVICE); - return -ENOMEM; - } - - dummy_read(drv_data); - set_dma_x_count(drv_data->tx_dma, word_count); - set_dma_x_count(drv_data->rx_dma, word_count); - set_dma_start_addr(drv_data->tx_dma, drv_data->tx_dma_addr); - set_dma_start_addr(drv_data->rx_dma, drv_data->rx_dma_addr); - dma_config |= DMAFLOW_STOP | RESTART | DI_EN; - set_dma_config(drv_data->tx_dma, dma_config); - set_dma_config(drv_data->rx_dma, dma_config | WNR); - enable_dma(drv_data->tx_dma); - enable_dma(drv_data->rx_dma); - - iowrite32(SPI_RXCTL_REN | SPI_RXCTL_RDR_NE, - &drv_data->regs->rx_control); - iowrite32(SPI_TXCTL_TEN | SPI_TXCTL_TTI | SPI_TXCTL_TDR_NF, - &drv_data->regs->tx_control); - - return 0; -} - -static int adi_spi_pio_xfer(struct adi_spi_master *drv_data) -{ - struct spi_message *msg = drv_data->cur_msg; - - if (!drv_data->rx) { - /* write only half duplex */ - drv_data->ops->write(drv_data); - if (drv_data->tx != drv_data->tx_end) - return -EIO; - } else if (!drv_data->tx) { - /* read only half duplex */ - drv_data->ops->read(drv_data); - if (drv_data->rx != drv_data->rx_end) - return -EIO; - } else { - /* full duplex mode */ - drv_data->ops->duplex(drv_data); - if (drv_data->tx != drv_data->tx_end) - return -EIO; - } - - if (!adi_spi_flush(drv_data)) - return -EIO; - msg->actual_length += drv_data->transfer_len; - tasklet_schedule(&drv_data->pump_transfers); - return 0; -} - -static void adi_spi_pump_transfers(unsigned long data) -{ - struct adi_spi_master *drv_data = (struct adi_spi_master *)data; - struct spi_message *msg = NULL; - struct spi_transfer *t = NULL; - struct adi_spi_device *chip = NULL; - int ret; - - /* Get current state information */ - msg = drv_data->cur_msg; - t = drv_data->cur_transfer; - chip = drv_data->cur_chip; - - /* Handle for abort */ - if (drv_data->state == ERROR_STATE) { - msg->status = -EIO; - adi_spi_giveback(drv_data); - return; - } - - if (drv_data->state == RUNNING_STATE) { - if (t->delay_usecs) - udelay(t->delay_usecs); - if (t->cs_change) - adi_spi_cs_deactive(drv_data, chip); - adi_spi_next_transfer(drv_data); - t = drv_data->cur_transfer; - } - /* Handle end of message */ - if (drv_data->state == DONE_STATE) { - msg->status = 0; - adi_spi_giveback(drv_data); - return; - } - - if ((t->len == 0) || (t->tx_buf == NULL && t->rx_buf == NULL)) { - /* Schedule next transfer tasklet */ - tasklet_schedule(&drv_data->pump_transfers); - return; - } - - ret = adi_spi_setup_transfer(drv_data); - if (ret) { - msg->status = ret; - adi_spi_giveback(drv_data); - } - - iowrite32(0xFFFFFFFF, &drv_data->regs->status); - adi_spi_cs_active(drv_data, chip); - drv_data->state = RUNNING_STATE; - - if (chip->enable_dma) - ret = adi_spi_dma_xfer(drv_data); - else - ret = adi_spi_pio_xfer(drv_data); - if (ret) { - msg->status = ret; - adi_spi_giveback(drv_data); - } -} - -static int adi_spi_transfer_one_message(struct spi_master *master, - struct spi_message *m) -{ - struct adi_spi_master *drv_data = spi_master_get_devdata(master); - - drv_data->cur_msg = m; - drv_data->cur_chip = spi_get_ctldata(drv_data->cur_msg->spi); - adi_spi_restore_state(drv_data); - - drv_data->state = START_STATE; - drv_data->cur_transfer = list_entry(drv_data->cur_msg->transfers.next, - struct spi_transfer, transfer_list); - - tasklet_schedule(&drv_data->pump_transfers); - return 0; -} - -#define MAX_SPI_SSEL 7 - -static const u16 ssel[][MAX_SPI_SSEL] = { - {P_SPI0_SSEL1, P_SPI0_SSEL2, P_SPI0_SSEL3, - P_SPI0_SSEL4, P_SPI0_SSEL5, - P_SPI0_SSEL6, P_SPI0_SSEL7}, - - {P_SPI1_SSEL1, P_SPI1_SSEL2, P_SPI1_SSEL3, - P_SPI1_SSEL4, P_SPI1_SSEL5, - P_SPI1_SSEL6, P_SPI1_SSEL7}, - - {P_SPI2_SSEL1, P_SPI2_SSEL2, P_SPI2_SSEL3, - P_SPI2_SSEL4, P_SPI2_SSEL5, - P_SPI2_SSEL6, P_SPI2_SSEL7}, -}; - -static int adi_spi_setup(struct spi_device *spi) -{ - struct adi_spi_master *drv_data = spi_master_get_devdata(spi->master); - struct adi_spi_device *chip = spi_get_ctldata(spi); - u32 ctl_reg = SPI_CTL_ODM | SPI_CTL_PSSE; - int ret = -EINVAL; - - if (!chip) { - struct adi_spi3_chip *chip_info = spi->controller_data; - - chip = kzalloc(sizeof(*chip), GFP_KERNEL); - if (!chip) - return -ENOMEM; - - if (chip_info) { - if (chip_info->control & ~ctl_reg) { - dev_err(&spi->dev, - "do not set bits that the SPI framework manages\n"); - goto error; - } - chip->control = chip_info->control; - chip->cs_chg_udelay = chip_info->cs_chg_udelay; - chip->tx_dummy_val = chip_info->tx_dummy_val; - chip->enable_dma = chip_info->enable_dma; - } - chip->cs = spi->chip_select; - - if (chip->cs < MAX_CTRL_CS) { - chip->ssel = (1 << chip->cs) << 8; - ret = peripheral_request(ssel[spi->master->bus_num] - [chip->cs-1], dev_name(&spi->dev)); - if (ret) { - dev_err(&spi->dev, "peripheral_request() error\n"); - goto error; - } - } else { - chip->cs_gpio = chip->cs - MAX_CTRL_CS; - ret = gpio_request_one(chip->cs_gpio, GPIOF_OUT_INIT_HIGH, - dev_name(&spi->dev)); - if (ret) { - dev_err(&spi->dev, "gpio_request_one() error\n"); - goto error; - } - } - spi_set_ctldata(spi, chip); - } - - /* force a default base state */ - chip->control &= ctl_reg; - - if (spi->mode & SPI_CPOL) - chip->control |= SPI_CTL_CPOL; - if (spi->mode & SPI_CPHA) - chip->control |= SPI_CTL_CPHA; - if (spi->mode & SPI_LSB_FIRST) - chip->control |= SPI_CTL_LSBF; - chip->control |= SPI_CTL_MSTR; - /* we choose software to controll cs */ - chip->control &= ~SPI_CTL_ASSEL; - - chip->clock = hz_to_spi_clock(drv_data->sclk, spi->max_speed_hz); - - adi_spi_cs_enable(drv_data, chip); - adi_spi_cs_deactive(drv_data, chip); - - return 0; -error: - if (chip) { - kfree(chip); - spi_set_ctldata(spi, NULL); - } - - return ret; -} - -static void adi_spi_cleanup(struct spi_device *spi) -{ - struct adi_spi_device *chip = spi_get_ctldata(spi); - struct adi_spi_master *drv_data = spi_master_get_devdata(spi->master); - - if (!chip) - return; - - if (chip->cs < MAX_CTRL_CS) { - peripheral_free(ssel[spi->master->bus_num] - [chip->cs-1]); - adi_spi_cs_disable(drv_data, chip); - } else { - gpio_free(chip->cs_gpio); - } - - kfree(chip); - spi_set_ctldata(spi, NULL); -} - -static irqreturn_t adi_spi_tx_dma_isr(int irq, void *dev_id) -{ - struct adi_spi_master *drv_data = dev_id; - u32 dma_stat = get_dma_curr_irqstat(drv_data->tx_dma); - u32 tx_ctl; - - clear_dma_irqstat(drv_data->tx_dma); - if (dma_stat & DMA_DONE) { - drv_data->tx_num++; - } else { - dev_err(&drv_data->master->dev, - "spi tx dma error: %d\n", dma_stat); - if (drv_data->tx) - drv_data->state = ERROR_STATE; - } - tx_ctl = ioread32(&drv_data->regs->tx_control); - tx_ctl &= ~SPI_TXCTL_TDR_NF; - iowrite32(tx_ctl, &drv_data->regs->tx_control); - return IRQ_HANDLED; -} - -static irqreturn_t adi_spi_rx_dma_isr(int irq, void *dev_id) -{ - struct adi_spi_master *drv_data = dev_id; - struct spi_message *msg = drv_data->cur_msg; - u32 dma_stat = get_dma_curr_irqstat(drv_data->rx_dma); - - clear_dma_irqstat(drv_data->rx_dma); - if (dma_stat & DMA_DONE) { - drv_data->rx_num++; - /* we may fail on tx dma */ - if (drv_data->state != ERROR_STATE) - msg->actual_length += drv_data->transfer_len; - } else { - drv_data->state = ERROR_STATE; - dev_err(&drv_data->master->dev, - "spi rx dma error: %d\n", dma_stat); - } - iowrite32(0, &drv_data->regs->tx_control); - iowrite32(0, &drv_data->regs->rx_control); - if (drv_data->rx_num != drv_data->tx_num) - dev_dbg(&drv_data->master->dev, - "dma interrupt missing: tx=%d,rx=%d\n", - drv_data->tx_num, drv_data->rx_num); - tasklet_schedule(&drv_data->pump_transfers); - return IRQ_HANDLED; -} - -static int adi_spi_probe(struct platform_device *pdev) -{ - struct device *dev = &pdev->dev; - struct adi_spi3_master *info = dev_get_platdata(dev); - struct spi_master *master; - struct adi_spi_master *drv_data; - struct resource *mem, *res; - unsigned int tx_dma, rx_dma; - struct clk *sclk; - int ret; - - if (!info) { - dev_err(dev, "platform data missing!\n"); - return -ENODEV; - } - - sclk = devm_clk_get(dev, "spi"); - if (IS_ERR(sclk)) { - dev_err(dev, "can not get spi clock\n"); - return PTR_ERR(sclk); - } - - res = platform_get_resource(pdev, IORESOURCE_DMA, 0); - if (!res) { - dev_err(dev, "can not get tx dma resource\n"); - return -ENXIO; - } - tx_dma = res->start; - - res = platform_get_resource(pdev, IORESOURCE_DMA, 1); - if (!res) { - dev_err(dev, "can not get rx dma resource\n"); - return -ENXIO; - } - rx_dma = res->start; - - /* allocate master with space for drv_data */ - master = spi_alloc_master(dev, sizeof(*drv_data)); - if (!master) { - dev_err(dev, "can not alloc spi_master\n"); - return -ENOMEM; - } - platform_set_drvdata(pdev, master); - - /* the mode bits supported by this driver */ - master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST; - - master->bus_num = pdev->id; - master->num_chipselect = info->num_chipselect; - master->cleanup = adi_spi_cleanup; - master->setup = adi_spi_setup; - master->transfer_one_message = adi_spi_transfer_one_message; - 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; - drv_data->tx_dma = tx_dma; - drv_data->rx_dma = rx_dma; - drv_data->pin_req = info->pin_req; - drv_data->sclk = clk_get_rate(sclk); - - mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - drv_data->regs = devm_ioremap_resource(dev, mem); - if (IS_ERR(drv_data->regs)) { - ret = PTR_ERR(drv_data->regs); - goto err_put_master; - } - - /* request tx and rx dma */ - ret = request_dma(tx_dma, "SPI_TX_DMA"); - if (ret) { - dev_err(dev, "can not request SPI TX DMA channel\n"); - goto err_put_master; - } - set_dma_callback(tx_dma, adi_spi_tx_dma_isr, drv_data); - - ret = request_dma(rx_dma, "SPI_RX_DMA"); - if (ret) { - dev_err(dev, "can not request SPI RX DMA channel\n"); - goto err_free_tx_dma; - } - set_dma_callback(drv_data->rx_dma, adi_spi_rx_dma_isr, drv_data); - - /* request CLK, MOSI and MISO */ - ret = peripheral_request_list(drv_data->pin_req, "adi-spi3"); - if (ret < 0) { - dev_err(dev, "can not request spi pins\n"); - goto err_free_rx_dma; - } - - iowrite32(SPI_CTL_MSTR | SPI_CTL_CPHA, &drv_data->regs->control); - iowrite32(0x0000FE00, &drv_data->regs->ssel); - iowrite32(0x0, &drv_data->regs->delay); - - tasklet_init(&drv_data->pump_transfers, - adi_spi_pump_transfers, (unsigned long)drv_data); - /* register with the SPI framework */ - ret = devm_spi_register_master(dev, master); - if (ret) { - dev_err(dev, "can not register spi master\n"); - goto err_free_peripheral; - } - - return ret; - -err_free_peripheral: - peripheral_free_list(drv_data->pin_req); -err_free_rx_dma: - free_dma(rx_dma); -err_free_tx_dma: - free_dma(tx_dma); -err_put_master: - spi_master_put(master); - - return ret; -} - -static int adi_spi_remove(struct platform_device *pdev) -{ - struct spi_master *master = platform_get_drvdata(pdev); - struct adi_spi_master *drv_data = spi_master_get_devdata(master); - - adi_spi_disable(drv_data); - peripheral_free_list(drv_data->pin_req); - free_dma(drv_data->rx_dma); - free_dma(drv_data->tx_dma); - return 0; -} - -#ifdef CONFIG_PM -static int adi_spi_suspend(struct device *dev) -{ - struct spi_master *master = dev_get_drvdata(dev); - struct adi_spi_master *drv_data = spi_master_get_devdata(master); - - spi_master_suspend(master); - - drv_data->control = ioread32(&drv_data->regs->control); - drv_data->ssel = ioread32(&drv_data->regs->ssel); - - iowrite32(SPI_CTL_MSTR | SPI_CTL_CPHA, &drv_data->regs->control); - iowrite32(0x0000FE00, &drv_data->regs->ssel); - dma_disable_irq(drv_data->rx_dma); - dma_disable_irq(drv_data->tx_dma); - - return 0; -} - -static int adi_spi_resume(struct device *dev) -{ - struct spi_master *master = dev_get_drvdata(dev); - struct adi_spi_master *drv_data = spi_master_get_devdata(master); - int ret = 0; - - /* bootrom may modify spi and dma status when resume in spi boot mode */ - disable_dma(drv_data->rx_dma); - - dma_enable_irq(drv_data->rx_dma); - dma_enable_irq(drv_data->tx_dma); - iowrite32(drv_data->control, &drv_data->regs->control); - iowrite32(drv_data->ssel, &drv_data->regs->ssel); - - ret = spi_master_resume(master); - if (ret) { - free_dma(drv_data->rx_dma); - free_dma(drv_data->tx_dma); - } - - return ret; -} -#endif -static const struct dev_pm_ops adi_spi_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(adi_spi_suspend, adi_spi_resume) -}; - -MODULE_ALIAS("platform:adi-spi3"); -static struct platform_driver adi_spi_driver = { - .driver = { - .name = "adi-spi3", - .pm = &adi_spi_pm_ops, - }, - .remove = adi_spi_remove, -}; - -module_platform_driver_probe(adi_spi_driver, adi_spi_probe); - -MODULE_DESCRIPTION("Analog Devices SPI3 controller driver"); -MODULE_AUTHOR("Scott Jiang "); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/spi/spi-bfin-sport.c b/drivers/spi/spi-bfin-sport.c deleted file mode 100644 index 01d0ba9c5942..000000000000 --- a/drivers/spi/spi-bfin-sport.c +++ /dev/null @@ -1,919 +0,0 @@ -/* - * SPI bus via the Blackfin SPORT peripheral - * - * Enter bugs at http://blackfin.uclinux.org/ - * - * Copyright 2009-2011 Analog Devices Inc. - * - * Licensed under the GPL-2 or later. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#define DRV_NAME "bfin-sport-spi" -#define DRV_DESC "SPI bus via the Blackfin SPORT" - -MODULE_AUTHOR("Cliff Cai"); -MODULE_DESCRIPTION(DRV_DESC); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:bfin-sport-spi"); - -enum bfin_sport_spi_state { - START_STATE, - RUNNING_STATE, - DONE_STATE, - ERROR_STATE, -}; - -struct bfin_sport_spi_master_data; - -struct bfin_sport_transfer_ops { - void (*write) (struct bfin_sport_spi_master_data *); - void (*read) (struct bfin_sport_spi_master_data *); - void (*duplex) (struct bfin_sport_spi_master_data *); -}; - -struct bfin_sport_spi_master_data { - /* Driver model hookup */ - struct device *dev; - - /* SPI framework hookup */ - struct spi_master *master; - - /* Regs base of SPI controller */ - struct sport_register __iomem *regs; - int err_irq; - - /* Pin request list */ - u16 *pin_req; - - struct work_struct pump_messages; - spinlock_t lock; - struct list_head queue; - int busy; - bool run; - - /* Message Transfer pump */ - struct tasklet_struct pump_transfers; - - /* Current message transfer state info */ - enum bfin_sport_spi_state state; - struct spi_message *cur_msg; - struct spi_transfer *cur_transfer; - struct bfin_sport_spi_slave_data *cur_chip; - union { - void *tx; - u8 *tx8; - u16 *tx16; - }; - void *tx_end; - union { - void *rx; - u8 *rx8; - u16 *rx16; - }; - void *rx_end; - - int cs_change; - struct bfin_sport_transfer_ops *ops; -}; - -struct bfin_sport_spi_slave_data { - u16 ctl_reg; - u16 baud; - u16 cs_chg_udelay; /* Some devices require > 255usec delay */ - u32 cs_gpio; - u16 idle_tx_val; - struct bfin_sport_transfer_ops *ops; -}; - -static void -bfin_sport_spi_enable(struct bfin_sport_spi_master_data *drv_data) -{ - bfin_write_or(&drv_data->regs->tcr1, TSPEN); - bfin_write_or(&drv_data->regs->rcr1, TSPEN); - SSYNC(); -} - -static void -bfin_sport_spi_disable(struct bfin_sport_spi_master_data *drv_data) -{ - bfin_write_and(&drv_data->regs->tcr1, ~TSPEN); - bfin_write_and(&drv_data->regs->rcr1, ~TSPEN); - SSYNC(); -} - -/* Caculate the SPI_BAUD register value based on input HZ */ -static u16 -bfin_sport_hz_to_spi_baud(u32 speed_hz) -{ - u_long clk, sclk = get_sclk(); - int div = (sclk / (2 * speed_hz)) - 1; - - if (div < 0) - div = 0; - - clk = sclk / (2 * (div + 1)); - - if (clk > speed_hz) - div++; - - return div; -} - -/* Chip select operation functions for cs_change flag */ -static void -bfin_sport_spi_cs_active(struct bfin_sport_spi_slave_data *chip) -{ - gpio_direction_output(chip->cs_gpio, 0); -} - -static void -bfin_sport_spi_cs_deactive(struct bfin_sport_spi_slave_data *chip) -{ - gpio_direction_output(chip->cs_gpio, 1); - /* Move delay here for consistency */ - if (chip->cs_chg_udelay) - udelay(chip->cs_chg_udelay); -} - -static void -bfin_sport_spi_stat_poll_complete(struct bfin_sport_spi_master_data *drv_data) -{ - unsigned long timeout = jiffies + HZ; - while (!(bfin_read(&drv_data->regs->stat) & RXNE)) { - if (!time_before(jiffies, timeout)) - break; - } -} - -static void -bfin_sport_spi_u8_writer(struct bfin_sport_spi_master_data *drv_data) -{ - u16 dummy; - - while (drv_data->tx < drv_data->tx_end) { - bfin_write(&drv_data->regs->tx16, *drv_data->tx8++); - bfin_sport_spi_stat_poll_complete(drv_data); - dummy = bfin_read(&drv_data->regs->rx16); - } -} - -static void -bfin_sport_spi_u8_reader(struct bfin_sport_spi_master_data *drv_data) -{ - u16 tx_val = drv_data->cur_chip->idle_tx_val; - - while (drv_data->rx < drv_data->rx_end) { - bfin_write(&drv_data->regs->tx16, tx_val); - bfin_sport_spi_stat_poll_complete(drv_data); - *drv_data->rx8++ = bfin_read(&drv_data->regs->rx16); - } -} - -static void -bfin_sport_spi_u8_duplex(struct bfin_sport_spi_master_data *drv_data) -{ - while (drv_data->rx < drv_data->rx_end) { - bfin_write(&drv_data->regs->tx16, *drv_data->tx8++); - bfin_sport_spi_stat_poll_complete(drv_data); - *drv_data->rx8++ = bfin_read(&drv_data->regs->rx16); - } -} - -static struct bfin_sport_transfer_ops bfin_sport_transfer_ops_u8 = { - .write = bfin_sport_spi_u8_writer, - .read = bfin_sport_spi_u8_reader, - .duplex = bfin_sport_spi_u8_duplex, -}; - -static void -bfin_sport_spi_u16_writer(struct bfin_sport_spi_master_data *drv_data) -{ - u16 dummy; - - while (drv_data->tx < drv_data->tx_end) { - bfin_write(&drv_data->regs->tx16, *drv_data->tx16++); - bfin_sport_spi_stat_poll_complete(drv_data); - dummy = bfin_read(&drv_data->regs->rx16); - } -} - -static void -bfin_sport_spi_u16_reader(struct bfin_sport_spi_master_data *drv_data) -{ - u16 tx_val = drv_data->cur_chip->idle_tx_val; - - while (drv_data->rx < drv_data->rx_end) { - bfin_write(&drv_data->regs->tx16, tx_val); - bfin_sport_spi_stat_poll_complete(drv_data); - *drv_data->rx16++ = bfin_read(&drv_data->regs->rx16); - } -} - -static void -bfin_sport_spi_u16_duplex(struct bfin_sport_spi_master_data *drv_data) -{ - while (drv_data->rx < drv_data->rx_end) { - bfin_write(&drv_data->regs->tx16, *drv_data->tx16++); - bfin_sport_spi_stat_poll_complete(drv_data); - *drv_data->rx16++ = bfin_read(&drv_data->regs->rx16); - } -} - -static struct bfin_sport_transfer_ops bfin_sport_transfer_ops_u16 = { - .write = bfin_sport_spi_u16_writer, - .read = bfin_sport_spi_u16_reader, - .duplex = bfin_sport_spi_u16_duplex, -}; - -/* stop controller and re-config current chip */ -static void -bfin_sport_spi_restore_state(struct bfin_sport_spi_master_data *drv_data) -{ - struct bfin_sport_spi_slave_data *chip = drv_data->cur_chip; - - bfin_sport_spi_disable(drv_data); - dev_dbg(drv_data->dev, "restoring spi ctl state\n"); - - bfin_write(&drv_data->regs->tcr1, chip->ctl_reg); - bfin_write(&drv_data->regs->tclkdiv, chip->baud); - SSYNC(); - - bfin_write(&drv_data->regs->rcr1, chip->ctl_reg & ~(ITCLK | ITFS)); - SSYNC(); - - bfin_sport_spi_cs_active(chip); -} - -/* test if there is more transfer to be done */ -static enum bfin_sport_spi_state -bfin_sport_spi_next_transfer(struct bfin_sport_spi_master_data *drv_data) -{ - struct spi_message *msg = drv_data->cur_msg; - struct spi_transfer *trans = drv_data->cur_transfer; - - /* Move to next transfer */ - if (trans->transfer_list.next != &msg->transfers) { - drv_data->cur_transfer = - list_entry(trans->transfer_list.next, - struct spi_transfer, transfer_list); - return RUNNING_STATE; - } - - return DONE_STATE; -} - -/* - * caller already set message->status; - * dma and pio irqs are blocked give finished message back - */ -static void -bfin_sport_spi_giveback(struct bfin_sport_spi_master_data *drv_data) -{ - struct bfin_sport_spi_slave_data *chip = drv_data->cur_chip; - unsigned long flags; - struct spi_message *msg; - - spin_lock_irqsave(&drv_data->lock, flags); - msg = drv_data->cur_msg; - drv_data->state = START_STATE; - drv_data->cur_msg = NULL; - drv_data->cur_transfer = NULL; - drv_data->cur_chip = NULL; - schedule_work(&drv_data->pump_messages); - spin_unlock_irqrestore(&drv_data->lock, flags); - - if (!drv_data->cs_change) - bfin_sport_spi_cs_deactive(chip); - - if (msg->complete) - msg->complete(msg->context); -} - -static irqreturn_t -sport_err_handler(int irq, void *dev_id) -{ - struct bfin_sport_spi_master_data *drv_data = dev_id; - u16 status; - - dev_dbg(drv_data->dev, "%s enter\n", __func__); - status = bfin_read(&drv_data->regs->stat) & (TOVF | TUVF | ROVF | RUVF); - - if (status) { - bfin_write(&drv_data->regs->stat, status); - SSYNC(); - - bfin_sport_spi_disable(drv_data); - dev_err(drv_data->dev, "status error:%s%s%s%s\n", - status & TOVF ? " TOVF" : "", - status & TUVF ? " TUVF" : "", - status & ROVF ? " ROVF" : "", - status & RUVF ? " RUVF" : ""); - } - - return IRQ_HANDLED; -} - -static void -bfin_sport_spi_pump_transfers(unsigned long data) -{ - struct bfin_sport_spi_master_data *drv_data = (void *)data; - struct spi_message *message = NULL; - struct spi_transfer *transfer = NULL; - struct spi_transfer *previous = NULL; - struct bfin_sport_spi_slave_data *chip = NULL; - unsigned int bits_per_word; - u32 tranf_success = 1; - u32 transfer_speed; - u8 full_duplex = 0; - - /* Get current state information */ - message = drv_data->cur_msg; - transfer = drv_data->cur_transfer; - chip = drv_data->cur_chip; - - transfer_speed = bfin_sport_hz_to_spi_baud(transfer->speed_hz); - bfin_write(&drv_data->regs->tclkdiv, transfer_speed); - SSYNC(); - - /* - * if msg is error or done, report it back using complete() callback - */ - - /* Handle for abort */ - if (drv_data->state == ERROR_STATE) { - dev_dbg(drv_data->dev, "transfer: we've hit an error\n"); - message->status = -EIO; - bfin_sport_spi_giveback(drv_data); - return; - } - - /* Handle end of message */ - if (drv_data->state == DONE_STATE) { - dev_dbg(drv_data->dev, "transfer: all done!\n"); - message->status = 0; - bfin_sport_spi_giveback(drv_data); - return; - } - - /* Delay if requested at end of transfer */ - if (drv_data->state == RUNNING_STATE) { - dev_dbg(drv_data->dev, "transfer: still running ...\n"); - previous = list_entry(transfer->transfer_list.prev, - struct spi_transfer, transfer_list); - if (previous->delay_usecs) - udelay(previous->delay_usecs); - } - - if (transfer->len == 0) { - /* Move to next transfer of this msg */ - drv_data->state = bfin_sport_spi_next_transfer(drv_data); - /* Schedule next transfer tasklet */ - tasklet_schedule(&drv_data->pump_transfers); - } - - if (transfer->tx_buf != NULL) { - drv_data->tx = (void *)transfer->tx_buf; - drv_data->tx_end = drv_data->tx + transfer->len; - dev_dbg(drv_data->dev, "tx_buf is %p, tx_end is %p\n", - transfer->tx_buf, drv_data->tx_end); - } else - drv_data->tx = NULL; - - if (transfer->rx_buf != NULL) { - full_duplex = transfer->tx_buf != NULL; - drv_data->rx = transfer->rx_buf; - drv_data->rx_end = drv_data->rx + transfer->len; - dev_dbg(drv_data->dev, "rx_buf is %p, rx_end is %p\n", - transfer->rx_buf, drv_data->rx_end); - } else - drv_data->rx = NULL; - - drv_data->cs_change = transfer->cs_change; - - /* Bits per word setup */ - bits_per_word = transfer->bits_per_word; - if (bits_per_word == 16) - drv_data->ops = &bfin_sport_transfer_ops_u16; - else - drv_data->ops = &bfin_sport_transfer_ops_u8; - bfin_write(&drv_data->regs->tcr2, bits_per_word - 1); - bfin_write(&drv_data->regs->tfsdiv, bits_per_word - 1); - bfin_write(&drv_data->regs->rcr2, bits_per_word - 1); - - drv_data->state = RUNNING_STATE; - - if (drv_data->cs_change) - bfin_sport_spi_cs_active(chip); - - dev_dbg(drv_data->dev, - "now pumping a transfer: width is %d, len is %d\n", - bits_per_word, transfer->len); - - /* PIO mode write then read */ - dev_dbg(drv_data->dev, "doing IO transfer\n"); - - bfin_sport_spi_enable(drv_data); - if (full_duplex) { - /* full duplex mode */ - BUG_ON((drv_data->tx_end - drv_data->tx) != - (drv_data->rx_end - drv_data->rx)); - drv_data->ops->duplex(drv_data); - - if (drv_data->tx != drv_data->tx_end) - tranf_success = 0; - } else if (drv_data->tx != NULL) { - /* write only half duplex */ - - drv_data->ops->write(drv_data); - - if (drv_data->tx != drv_data->tx_end) - tranf_success = 0; - } else if (drv_data->rx != NULL) { - /* read only half duplex */ - - drv_data->ops->read(drv_data); - if (drv_data->rx != drv_data->rx_end) - tranf_success = 0; - } - bfin_sport_spi_disable(drv_data); - - if (!tranf_success) { - dev_dbg(drv_data->dev, "IO write error!\n"); - drv_data->state = ERROR_STATE; - } else { - /* Update total byte transferred */ - message->actual_length += transfer->len; - /* Move to next transfer of this msg */ - drv_data->state = bfin_sport_spi_next_transfer(drv_data); - if (drv_data->cs_change) - bfin_sport_spi_cs_deactive(chip); - } - - /* Schedule next transfer tasklet */ - tasklet_schedule(&drv_data->pump_transfers); -} - -/* pop a msg from queue and kick off real transfer */ -static void -bfin_sport_spi_pump_messages(struct work_struct *work) -{ - struct bfin_sport_spi_master_data *drv_data; - unsigned long flags; - struct spi_message *next_msg; - - drv_data = container_of(work, struct bfin_sport_spi_master_data, pump_messages); - - /* Lock queue and check for queue work */ - spin_lock_irqsave(&drv_data->lock, flags); - if (list_empty(&drv_data->queue) || !drv_data->run) { - /* pumper kicked off but no work to do */ - drv_data->busy = 0; - spin_unlock_irqrestore(&drv_data->lock, flags); - return; - } - - /* Make sure we are not already running a message */ - if (drv_data->cur_msg) { - spin_unlock_irqrestore(&drv_data->lock, flags); - return; - } - - /* Extract head of queue */ - next_msg = list_entry(drv_data->queue.next, - struct spi_message, queue); - - drv_data->cur_msg = next_msg; - - /* Setup the SSP using the per chip configuration */ - drv_data->cur_chip = spi_get_ctldata(drv_data->cur_msg->spi); - - list_del_init(&drv_data->cur_msg->queue); - - /* Initialize message state */ - drv_data->cur_msg->state = START_STATE; - drv_data->cur_transfer = list_entry(drv_data->cur_msg->transfers.next, - struct spi_transfer, transfer_list); - bfin_sport_spi_restore_state(drv_data); - dev_dbg(drv_data->dev, "got a message to pump, " - "state is set to: baud %d, cs_gpio %i, ctl 0x%x\n", - drv_data->cur_chip->baud, drv_data->cur_chip->cs_gpio, - drv_data->cur_chip->ctl_reg); - - dev_dbg(drv_data->dev, - "the first transfer len is %d\n", - drv_data->cur_transfer->len); - - /* Mark as busy and launch transfers */ - tasklet_schedule(&drv_data->pump_transfers); - - drv_data->busy = 1; - spin_unlock_irqrestore(&drv_data->lock, flags); -} - -/* - * got a msg to transfer, queue it in drv_data->queue. - * And kick off message pumper - */ -static int -bfin_sport_spi_transfer(struct spi_device *spi, struct spi_message *msg) -{ - struct bfin_sport_spi_master_data *drv_data = spi_master_get_devdata(spi->master); - unsigned long flags; - - spin_lock_irqsave(&drv_data->lock, flags); - - if (!drv_data->run) { - spin_unlock_irqrestore(&drv_data->lock, flags); - return -ESHUTDOWN; - } - - msg->actual_length = 0; - msg->status = -EINPROGRESS; - msg->state = START_STATE; - - dev_dbg(&spi->dev, "adding an msg in transfer()\n"); - list_add_tail(&msg->queue, &drv_data->queue); - - if (drv_data->run && !drv_data->busy) - schedule_work(&drv_data->pump_messages); - - spin_unlock_irqrestore(&drv_data->lock, flags); - - return 0; -} - -/* Called every time common spi devices change state */ -static int -bfin_sport_spi_setup(struct spi_device *spi) -{ - struct bfin_sport_spi_slave_data *chip, *first = NULL; - int ret; - - /* Only alloc (or use chip_info) on first setup */ - chip = spi_get_ctldata(spi); - if (chip == NULL) { - struct bfin5xx_spi_chip *chip_info; - - chip = first = kzalloc(sizeof(*chip), GFP_KERNEL); - if (!chip) - return -ENOMEM; - - /* platform chip_info isn't required */ - chip_info = spi->controller_data; - if (chip_info) { - /* - * DITFS and TDTYPE are only thing we don't set, but - * they probably shouldn't be changed by people. - */ - if (chip_info->ctl_reg || chip_info->enable_dma) { - ret = -EINVAL; - dev_err(&spi->dev, "don't set ctl_reg/enable_dma fields\n"); - goto error; - } - chip->cs_chg_udelay = chip_info->cs_chg_udelay; - chip->idle_tx_val = chip_info->idle_tx_val; - } - } - - /* translate common spi framework into our register - * following configure contents are same for tx and rx. - */ - - if (spi->mode & SPI_CPHA) - chip->ctl_reg &= ~TCKFE; - else - chip->ctl_reg |= TCKFE; - - if (spi->mode & SPI_LSB_FIRST) - chip->ctl_reg |= TLSBIT; - else - chip->ctl_reg &= ~TLSBIT; - - /* Sport in master mode */ - chip->ctl_reg |= ITCLK | ITFS | TFSR | LATFS | LTFS; - - chip->baud = bfin_sport_hz_to_spi_baud(spi->max_speed_hz); - - chip->cs_gpio = spi->chip_select; - ret = gpio_request(chip->cs_gpio, spi->modalias); - if (ret) - goto error; - - dev_dbg(&spi->dev, "setup spi chip %s, width is %d\n", - spi->modalias, spi->bits_per_word); - dev_dbg(&spi->dev, "ctl_reg is 0x%x, GPIO is %i\n", - chip->ctl_reg, spi->chip_select); - - spi_set_ctldata(spi, chip); - - bfin_sport_spi_cs_deactive(chip); - - return ret; - - error: - kfree(first); - return ret; -} - -/* - * callback for spi framework. - * clean driver specific data - */ -static void -bfin_sport_spi_cleanup(struct spi_device *spi) -{ - struct bfin_sport_spi_slave_data *chip = spi_get_ctldata(spi); - - if (!chip) - return; - - gpio_free(chip->cs_gpio); - - kfree(chip); -} - -static int -bfin_sport_spi_init_queue(struct bfin_sport_spi_master_data *drv_data) -{ - INIT_LIST_HEAD(&drv_data->queue); - spin_lock_init(&drv_data->lock); - - drv_data->run = false; - drv_data->busy = 0; - - /* init transfer tasklet */ - tasklet_init(&drv_data->pump_transfers, - bfin_sport_spi_pump_transfers, (unsigned long)drv_data); - - INIT_WORK(&drv_data->pump_messages, bfin_sport_spi_pump_messages); - - return 0; -} - -static int -bfin_sport_spi_start_queue(struct bfin_sport_spi_master_data *drv_data) -{ - unsigned long flags; - - spin_lock_irqsave(&drv_data->lock, flags); - - if (drv_data->run || drv_data->busy) { - spin_unlock_irqrestore(&drv_data->lock, flags); - return -EBUSY; - } - - drv_data->run = true; - drv_data->cur_msg = NULL; - drv_data->cur_transfer = NULL; - drv_data->cur_chip = NULL; - spin_unlock_irqrestore(&drv_data->lock, flags); - - schedule_work(&drv_data->pump_messages); - - return 0; -} - -static inline int -bfin_sport_spi_stop_queue(struct bfin_sport_spi_master_data *drv_data) -{ - unsigned long flags; - unsigned limit = 500; - int status = 0; - - spin_lock_irqsave(&drv_data->lock, flags); - - /* - * This is a bit lame, but is optimized for the common execution path. - * A wait_queue on the drv_data->busy could be used, but then the common - * execution path (pump_messages) would be required to call wake_up or - * friends on every SPI message. Do this instead - */ - drv_data->run = false; - while (!list_empty(&drv_data->queue) && drv_data->busy && limit--) { - spin_unlock_irqrestore(&drv_data->lock, flags); - msleep(10); - spin_lock_irqsave(&drv_data->lock, flags); - } - - if (!list_empty(&drv_data->queue) || drv_data->busy) - status = -EBUSY; - - spin_unlock_irqrestore(&drv_data->lock, flags); - - return status; -} - -static inline int -bfin_sport_spi_destroy_queue(struct bfin_sport_spi_master_data *drv_data) -{ - int status; - - status = bfin_sport_spi_stop_queue(drv_data); - if (status) - return status; - - flush_work(&drv_data->pump_messages); - - return 0; -} - -static int bfin_sport_spi_probe(struct platform_device *pdev) -{ - struct device *dev = &pdev->dev; - struct bfin5xx_spi_master *platform_info; - struct spi_master *master; - struct resource *res, *ires; - struct bfin_sport_spi_master_data *drv_data; - int status; - - platform_info = dev_get_platdata(dev); - - /* Allocate master with space for drv_data */ - master = spi_alloc_master(dev, sizeof(*master) + 16); - if (!master) { - dev_err(dev, "cannot alloc spi_master\n"); - return -ENOMEM; - } - - drv_data = spi_master_get_devdata(master); - drv_data->master = master; - drv_data->dev = dev; - drv_data->pin_req = platform_info->pin_req; - - master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST; - master->bits_per_word_mask = SPI_BPW_MASK(8) | SPI_BPW_MASK(16); - master->bus_num = pdev->id; - master->num_chipselect = platform_info->num_chipselect; - master->cleanup = bfin_sport_spi_cleanup; - master->setup = bfin_sport_spi_setup; - master->transfer = bfin_sport_spi_transfer; - - /* Find and map our resources */ - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (res == NULL) { - dev_err(dev, "cannot get IORESOURCE_MEM\n"); - status = -ENOENT; - goto out_error_get_res; - } - - drv_data->regs = ioremap(res->start, resource_size(res)); - if (drv_data->regs == NULL) { - dev_err(dev, "cannot map registers\n"); - status = -ENXIO; - goto out_error_ioremap; - } - - ires = platform_get_resource(pdev, IORESOURCE_IRQ, 0); - if (!ires) { - dev_err(dev, "cannot get IORESOURCE_IRQ\n"); - status = -ENODEV; - goto out_error_get_ires; - } - drv_data->err_irq = ires->start; - - /* Initial and start queue */ - status = bfin_sport_spi_init_queue(drv_data); - if (status) { - dev_err(dev, "problem initializing queue\n"); - goto out_error_queue_alloc; - } - - status = bfin_sport_spi_start_queue(drv_data); - if (status) { - dev_err(dev, "problem starting queue\n"); - goto out_error_queue_alloc; - } - - status = request_irq(drv_data->err_irq, sport_err_handler, - 0, "sport_spi_err", drv_data); - if (status) { - dev_err(dev, "unable to request sport err irq\n"); - goto out_error_irq; - } - - status = peripheral_request_list(drv_data->pin_req, DRV_NAME); - if (status) { - dev_err(dev, "requesting peripherals failed\n"); - goto out_error_peripheral; - } - - /* Register with the SPI framework */ - platform_set_drvdata(pdev, drv_data); - status = spi_register_master(master); - if (status) { - dev_err(dev, "problem registering spi master\n"); - goto out_error_master; - } - - dev_info(dev, "%s, regs_base@%p\n", DRV_DESC, drv_data->regs); - return 0; - - out_error_master: - peripheral_free_list(drv_data->pin_req); - out_error_peripheral: - free_irq(drv_data->err_irq, drv_data); - out_error_irq: - out_error_queue_alloc: - bfin_sport_spi_destroy_queue(drv_data); - out_error_get_ires: - iounmap(drv_data->regs); - out_error_ioremap: - out_error_get_res: - spi_master_put(master); - - return status; -} - -/* stop hardware and remove the driver */ -static int bfin_sport_spi_remove(struct platform_device *pdev) -{ - struct bfin_sport_spi_master_data *drv_data = platform_get_drvdata(pdev); - int status = 0; - - if (!drv_data) - return 0; - - /* Remove the queue */ - status = bfin_sport_spi_destroy_queue(drv_data); - if (status) - return status; - - /* Disable the SSP at the peripheral and SOC level */ - bfin_sport_spi_disable(drv_data); - - /* Disconnect from the SPI framework */ - spi_unregister_master(drv_data->master); - - peripheral_free_list(drv_data->pin_req); - - return 0; -} - -#ifdef CONFIG_PM_SLEEP -static int bfin_sport_spi_suspend(struct device *dev) -{ - struct bfin_sport_spi_master_data *drv_data = dev_get_drvdata(dev); - int status; - - status = bfin_sport_spi_stop_queue(drv_data); - if (status) - return status; - - /* stop hardware */ - bfin_sport_spi_disable(drv_data); - - return status; -} - -static int bfin_sport_spi_resume(struct device *dev) -{ - struct bfin_sport_spi_master_data *drv_data = dev_get_drvdata(dev); - int status; - - /* Enable the SPI interface */ - bfin_sport_spi_enable(drv_data); - - /* Start the queue running */ - status = bfin_sport_spi_start_queue(drv_data); - if (status) - dev_err(drv_data->dev, "problem resuming queue\n"); - - return status; -} - -static SIMPLE_DEV_PM_OPS(bfin_sport_spi_pm_ops, bfin_sport_spi_suspend, - bfin_sport_spi_resume); - -#define BFIN_SPORT_SPI_PM_OPS (&bfin_sport_spi_pm_ops) -#else -#define BFIN_SPORT_SPI_PM_OPS NULL -#endif - -static struct platform_driver bfin_sport_spi_driver = { - .driver = { - .name = DRV_NAME, - .pm = BFIN_SPORT_SPI_PM_OPS, - }, - .probe = bfin_sport_spi_probe, - .remove = bfin_sport_spi_remove, -}; -module_platform_driver(bfin_sport_spi_driver); diff --git a/drivers/spi/spi-bfin5xx.c b/drivers/spi/spi-bfin5xx.c deleted file mode 100644 index 249c7a3677c9..000000000000 --- a/drivers/spi/spi-bfin5xx.c +++ /dev/null @@ -1,1462 +0,0 @@ -/* - * Blackfin On-Chip SPI Driver - * - * Copyright 2004-2010 Analog Devices Inc. - * - * Enter bugs at http://blackfin.uclinux.org/ - * - * Licensed under the GPL-2 or later. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#define DRV_NAME "bfin-spi" -#define DRV_AUTHOR "Bryan Wu, Luke Yang" -#define DRV_DESC "Blackfin on-chip SPI Controller Driver" -#define DRV_VERSION "1.0" - -MODULE_AUTHOR(DRV_AUTHOR); -MODULE_DESCRIPTION(DRV_DESC); -MODULE_LICENSE("GPL"); - -#define START_STATE ((void *)0) -#define RUNNING_STATE ((void *)1) -#define DONE_STATE ((void *)2) -#define ERROR_STATE ((void *)-1) - -struct bfin_spi_master_data; - -struct bfin_spi_transfer_ops { - void (*write) (struct bfin_spi_master_data *); - void (*read) (struct bfin_spi_master_data *); - void (*duplex) (struct bfin_spi_master_data *); -}; - -struct bfin_spi_master_data { - /* Driver model hookup */ - struct platform_device *pdev; - - /* SPI framework hookup */ - struct spi_master *master; - - /* Regs base of SPI controller */ - struct bfin_spi_regs __iomem *regs; - - /* Pin request list */ - u16 *pin_req; - - /* BFIN hookup */ - struct bfin5xx_spi_master *master_info; - - struct work_struct pump_messages; - spinlock_t lock; - struct list_head queue; - int busy; - bool running; - - /* Message Transfer pump */ - struct tasklet_struct pump_transfers; - - /* Current message transfer state info */ - struct spi_message *cur_msg; - struct spi_transfer *cur_transfer; - struct bfin_spi_slave_data *cur_chip; - size_t len_in_bytes; - size_t len; - void *tx; - void *tx_end; - void *rx; - void *rx_end; - - /* DMA stuffs */ - int dma_channel; - int dma_mapped; - int dma_requested; - dma_addr_t rx_dma; - dma_addr_t tx_dma; - - int irq_requested; - int spi_irq; - - size_t rx_map_len; - size_t tx_map_len; - u8 n_bytes; - u16 ctrl_reg; - u16 flag_reg; - - int cs_change; - const struct bfin_spi_transfer_ops *ops; -}; - -struct bfin_spi_slave_data { - u16 ctl_reg; - u16 baud; - u16 flag; - - u8 chip_select_num; - u8 enable_dma; - u16 cs_chg_udelay; /* Some devices require > 255usec delay */ - u32 cs_gpio; - u16 idle_tx_val; - u8 pio_interrupt; /* use spi data irq */ - const struct bfin_spi_transfer_ops *ops; -}; - -static void bfin_spi_enable(struct bfin_spi_master_data *drv_data) -{ - bfin_write_or(&drv_data->regs->ctl, BIT_CTL_ENABLE); -} - -static void bfin_spi_disable(struct bfin_spi_master_data *drv_data) -{ - bfin_write_and(&drv_data->regs->ctl, ~BIT_CTL_ENABLE); -} - -/* Caculate the SPI_BAUD register value based on input HZ */ -static u16 hz_to_spi_baud(u32 speed_hz) -{ - u_long sclk = get_sclk(); - u16 spi_baud = (sclk / (2 * speed_hz)); - - if ((sclk % (2 * speed_hz)) > 0) - spi_baud++; - - if (spi_baud < MIN_SPI_BAUD_VAL) - spi_baud = MIN_SPI_BAUD_VAL; - - return spi_baud; -} - -static int bfin_spi_flush(struct bfin_spi_master_data *drv_data) -{ - unsigned long limit = loops_per_jiffy << 1; - - /* wait for stop and clear stat */ - while (!(bfin_read(&drv_data->regs->stat) & BIT_STAT_SPIF) && --limit) - cpu_relax(); - - bfin_write(&drv_data->regs->stat, BIT_STAT_CLR); - - return limit; -} - -/* Chip select operation functions for cs_change flag */ -static void bfin_spi_cs_active(struct bfin_spi_master_data *drv_data, struct bfin_spi_slave_data *chip) -{ - if (likely(chip->chip_select_num < MAX_CTRL_CS)) - bfin_write_and(&drv_data->regs->flg, ~chip->flag); - else - gpio_set_value(chip->cs_gpio, 0); -} - -static void bfin_spi_cs_deactive(struct bfin_spi_master_data *drv_data, - struct bfin_spi_slave_data *chip) -{ - if (likely(chip->chip_select_num < MAX_CTRL_CS)) - bfin_write_or(&drv_data->regs->flg, chip->flag); - else - gpio_set_value(chip->cs_gpio, 1); - - /* Move delay here for consistency */ - if (chip->cs_chg_udelay) - udelay(chip->cs_chg_udelay); -} - -/* enable or disable the pin muxed by GPIO and SPI CS to work as SPI CS */ -static inline void bfin_spi_cs_enable(struct bfin_spi_master_data *drv_data, - struct bfin_spi_slave_data *chip) -{ - if (chip->chip_select_num < MAX_CTRL_CS) - bfin_write_or(&drv_data->regs->flg, chip->flag >> 8); -} - -static inline void bfin_spi_cs_disable(struct bfin_spi_master_data *drv_data, - struct bfin_spi_slave_data *chip) -{ - if (chip->chip_select_num < MAX_CTRL_CS) - bfin_write_and(&drv_data->regs->flg, ~(chip->flag >> 8)); -} - -/* stop controller and re-config current chip*/ -static void bfin_spi_restore_state(struct bfin_spi_master_data *drv_data) -{ - struct bfin_spi_slave_data *chip = drv_data->cur_chip; - - /* Clear status and disable clock */ - bfin_write(&drv_data->regs->stat, BIT_STAT_CLR); - bfin_spi_disable(drv_data); - dev_dbg(&drv_data->pdev->dev, "restoring spi ctl state\n"); - - SSYNC(); - - /* Load the registers */ - bfin_write(&drv_data->regs->ctl, chip->ctl_reg); - bfin_write(&drv_data->regs->baud, chip->baud); - - bfin_spi_enable(drv_data); - bfin_spi_cs_active(drv_data, chip); -} - -/* used to kick off transfer in rx mode and read unwanted RX data */ -static inline void bfin_spi_dummy_read(struct bfin_spi_master_data *drv_data) -{ - (void) bfin_read(&drv_data->regs->rdbr); -} - -static void bfin_spi_u8_writer(struct bfin_spi_master_data *drv_data) -{ - /* clear RXS (we check for RXS inside the loop) */ - bfin_spi_dummy_read(drv_data); - - while (drv_data->tx < drv_data->tx_end) { - bfin_write(&drv_data->regs->tdbr, (*(u8 *) (drv_data->tx++))); - /* wait until transfer finished. - checking SPIF or TXS may not guarantee transfer completion */ - while (!(bfin_read(&drv_data->regs->stat) & BIT_STAT_RXS)) - cpu_relax(); - /* discard RX data and clear RXS */ - bfin_spi_dummy_read(drv_data); - } -} - -static void bfin_spi_u8_reader(struct bfin_spi_master_data *drv_data) -{ - u16 tx_val = drv_data->cur_chip->idle_tx_val; - - /* discard old RX data and clear RXS */ - bfin_spi_dummy_read(drv_data); - - while (drv_data->rx < drv_data->rx_end) { - bfin_write(&drv_data->regs->tdbr, tx_val); - while (!(bfin_read(&drv_data->regs->stat) & BIT_STAT_RXS)) - cpu_relax(); - *(u8 *) (drv_data->rx++) = bfin_read(&drv_data->regs->rdbr); - } -} - -static void bfin_spi_u8_duplex(struct bfin_spi_master_data *drv_data) -{ - /* discard old RX data and clear RXS */ - bfin_spi_dummy_read(drv_data); - - while (drv_data->rx < drv_data->rx_end) { - bfin_write(&drv_data->regs->tdbr, (*(u8 *) (drv_data->tx++))); - while (!(bfin_read(&drv_data->regs->stat) & BIT_STAT_RXS)) - cpu_relax(); - *(u8 *) (drv_data->rx++) = bfin_read(&drv_data->regs->rdbr); - } -} - -static const struct bfin_spi_transfer_ops bfin_bfin_spi_transfer_ops_u8 = { - .write = bfin_spi_u8_writer, - .read = bfin_spi_u8_reader, - .duplex = bfin_spi_u8_duplex, -}; - -static void bfin_spi_u16_writer(struct bfin_spi_master_data *drv_data) -{ - /* clear RXS (we check for RXS inside the loop) */ - bfin_spi_dummy_read(drv_data); - - while (drv_data->tx < drv_data->tx_end) { - bfin_write(&drv_data->regs->tdbr, (*(u16 *) (drv_data->tx))); - drv_data->tx += 2; - /* wait until transfer finished. - checking SPIF or TXS may not guarantee transfer completion */ - while (!(bfin_read(&drv_data->regs->stat) & BIT_STAT_RXS)) - cpu_relax(); - /* discard RX data and clear RXS */ - bfin_spi_dummy_read(drv_data); - } -} - -static void bfin_spi_u16_reader(struct bfin_spi_master_data *drv_data) -{ - u16 tx_val = drv_data->cur_chip->idle_tx_val; - - /* discard old RX data and clear RXS */ - bfin_spi_dummy_read(drv_data); - - while (drv_data->rx < drv_data->rx_end) { - bfin_write(&drv_data->regs->tdbr, tx_val); - while (!(bfin_read(&drv_data->regs->stat) & BIT_STAT_RXS)) - cpu_relax(); - *(u16 *) (drv_data->rx) = bfin_read(&drv_data->regs->rdbr); - drv_data->rx += 2; - } -} - -static void bfin_spi_u16_duplex(struct bfin_spi_master_data *drv_data) -{ - /* discard old RX data and clear RXS */ - bfin_spi_dummy_read(drv_data); - - while (drv_data->rx < drv_data->rx_end) { - bfin_write(&drv_data->regs->tdbr, (*(u16 *) (drv_data->tx))); - drv_data->tx += 2; - while (!(bfin_read(&drv_data->regs->stat) & BIT_STAT_RXS)) - cpu_relax(); - *(u16 *) (drv_data->rx) = bfin_read(&drv_data->regs->rdbr); - drv_data->rx += 2; - } -} - -static const struct bfin_spi_transfer_ops bfin_bfin_spi_transfer_ops_u16 = { - .write = bfin_spi_u16_writer, - .read = bfin_spi_u16_reader, - .duplex = bfin_spi_u16_duplex, -}; - -/* test if there is more transfer to be done */ -static void *bfin_spi_next_transfer(struct bfin_spi_master_data *drv_data) -{ - struct spi_message *msg = drv_data->cur_msg; - struct spi_transfer *trans = drv_data->cur_transfer; - - /* Move to next transfer */ - if (trans->transfer_list.next != &msg->transfers) { - drv_data->cur_transfer = - list_entry(trans->transfer_list.next, - struct spi_transfer, transfer_list); - return RUNNING_STATE; - } else - return DONE_STATE; -} - -/* - * caller already set message->status; - * dma and pio irqs are blocked give finished message back - */ -static void bfin_spi_giveback(struct bfin_spi_master_data *drv_data) -{ - struct bfin_spi_slave_data *chip = drv_data->cur_chip; - unsigned long flags; - struct spi_message *msg; - - spin_lock_irqsave(&drv_data->lock, flags); - msg = drv_data->cur_msg; - drv_data->cur_msg = NULL; - drv_data->cur_transfer = NULL; - drv_data->cur_chip = NULL; - schedule_work(&drv_data->pump_messages); - spin_unlock_irqrestore(&drv_data->lock, flags); - - msg->state = NULL; - - if (!drv_data->cs_change) - bfin_spi_cs_deactive(drv_data, chip); - - /* Not stop spi in autobuffer mode */ - if (drv_data->tx_dma != 0xFFFF) - bfin_spi_disable(drv_data); - - if (msg->complete) - msg->complete(msg->context); -} - -/* spi data irq handler */ -static irqreturn_t bfin_spi_pio_irq_handler(int irq, void *dev_id) -{ - struct bfin_spi_master_data *drv_data = dev_id; - struct bfin_spi_slave_data *chip = drv_data->cur_chip; - struct spi_message *msg = drv_data->cur_msg; - int n_bytes = drv_data->n_bytes; - int loop = 0; - - /* wait until transfer finished. */ - while (!(bfin_read(&drv_data->regs->stat) & BIT_STAT_RXS)) - cpu_relax(); - - if ((drv_data->tx && drv_data->tx >= drv_data->tx_end) || - (drv_data->rx && drv_data->rx >= (drv_data->rx_end - n_bytes))) { - /* last read */ - if (drv_data->rx) { - dev_dbg(&drv_data->pdev->dev, "last read\n"); - if (!(n_bytes % 2)) { - u16 *buf = (u16 *)drv_data->rx; - for (loop = 0; loop < n_bytes / 2; loop++) - *buf++ = bfin_read(&drv_data->regs->rdbr); - } else { - u8 *buf = (u8 *)drv_data->rx; - for (loop = 0; loop < n_bytes; loop++) - *buf++ = bfin_read(&drv_data->regs->rdbr); - } - drv_data->rx += n_bytes; - } - - msg->actual_length += drv_data->len_in_bytes; - if (drv_data->cs_change) - bfin_spi_cs_deactive(drv_data, chip); - /* Move to next transfer */ - msg->state = bfin_spi_next_transfer(drv_data); - - disable_irq_nosync(drv_data->spi_irq); - - /* Schedule transfer tasklet */ - tasklet_schedule(&drv_data->pump_transfers); - return IRQ_HANDLED; - } - - if (drv_data->rx && drv_data->tx) { - /* duplex */ - dev_dbg(&drv_data->pdev->dev, "duplex: write_TDBR\n"); - if (!(n_bytes % 2)) { - u16 *buf = (u16 *)drv_data->rx; - u16 *buf2 = (u16 *)drv_data->tx; - for (loop = 0; loop < n_bytes / 2; loop++) { - *buf++ = bfin_read(&drv_data->regs->rdbr); - bfin_write(&drv_data->regs->tdbr, *buf2++); - } - } else { - u8 *buf = (u8 *)drv_data->rx; - u8 *buf2 = (u8 *)drv_data->tx; - for (loop = 0; loop < n_bytes; loop++) { - *buf++ = bfin_read(&drv_data->regs->rdbr); - bfin_write(&drv_data->regs->tdbr, *buf2++); - } - } - } else if (drv_data->rx) { - /* read */ - dev_dbg(&drv_data->pdev->dev, "read: write_TDBR\n"); - if (!(n_bytes % 2)) { - u16 *buf = (u16 *)drv_data->rx; - for (loop = 0; loop < n_bytes / 2; loop++) { - *buf++ = bfin_read(&drv_data->regs->rdbr); - bfin_write(&drv_data->regs->tdbr, chip->idle_tx_val); - } - } else { - u8 *buf = (u8 *)drv_data->rx; - for (loop = 0; loop < n_bytes; loop++) { - *buf++ = bfin_read(&drv_data->regs->rdbr); - bfin_write(&drv_data->regs->tdbr, chip->idle_tx_val); - } - } - } else if (drv_data->tx) { - /* write */ - dev_dbg(&drv_data->pdev->dev, "write: write_TDBR\n"); - if (!(n_bytes % 2)) { - u16 *buf = (u16 *)drv_data->tx; - for (loop = 0; loop < n_bytes / 2; loop++) { - bfin_read(&drv_data->regs->rdbr); - bfin_write(&drv_data->regs->tdbr, *buf++); - } - } else { - u8 *buf = (u8 *)drv_data->tx; - for (loop = 0; loop < n_bytes; loop++) { - bfin_read(&drv_data->regs->rdbr); - bfin_write(&drv_data->regs->tdbr, *buf++); - } - } - } - - if (drv_data->tx) - drv_data->tx += n_bytes; - if (drv_data->rx) - drv_data->rx += n_bytes; - - return IRQ_HANDLED; -} - -static irqreturn_t bfin_spi_dma_irq_handler(int irq, void *dev_id) -{ - struct bfin_spi_master_data *drv_data = dev_id; - struct bfin_spi_slave_data *chip = drv_data->cur_chip; - struct spi_message *msg = drv_data->cur_msg; - unsigned long timeout; - unsigned short dmastat = get_dma_curr_irqstat(drv_data->dma_channel); - u16 spistat = bfin_read(&drv_data->regs->stat); - - dev_dbg(&drv_data->pdev->dev, - "in dma_irq_handler dmastat:0x%x spistat:0x%x\n", - dmastat, spistat); - - if (drv_data->rx != NULL) { - u16 cr = bfin_read(&drv_data->regs->ctl); - /* discard old RX data and clear RXS */ - bfin_spi_dummy_read(drv_data); - bfin_write(&drv_data->regs->ctl, cr & ~BIT_CTL_ENABLE); /* Disable SPI */ - bfin_write(&drv_data->regs->ctl, cr & ~BIT_CTL_TIMOD); /* Restore State */ - bfin_write(&drv_data->regs->stat, BIT_STAT_CLR); /* Clear Status */ - } - - clear_dma_irqstat(drv_data->dma_channel); - - /* - * wait for the last transaction shifted out. HRM states: - * at this point there may still be data in the SPI DMA FIFO waiting - * to be transmitted ... software needs to poll TXS in the SPI_STAT - * register until it goes low for 2 successive reads - */ - if (drv_data->tx != NULL) { - while ((bfin_read(&drv_data->regs->stat) & BIT_STAT_TXS) || - (bfin_read(&drv_data->regs->stat) & BIT_STAT_TXS)) - cpu_relax(); - } - - dev_dbg(&drv_data->pdev->dev, - "in dma_irq_handler dmastat:0x%x spistat:0x%x\n", - dmastat, bfin_read(&drv_data->regs->stat)); - - timeout = jiffies + HZ; - while (!(bfin_read(&drv_data->regs->stat) & BIT_STAT_SPIF)) - if (!time_before(jiffies, timeout)) { - dev_warn(&drv_data->pdev->dev, "timeout waiting for SPIF\n"); - break; - } else - cpu_relax(); - - if ((dmastat & DMA_ERR) && (spistat & BIT_STAT_RBSY)) { - msg->state = ERROR_STATE; - dev_err(&drv_data->pdev->dev, "dma receive: fifo/buffer overflow\n"); - } else { - msg->actual_length += drv_data->len_in_bytes; - - if (drv_data->cs_change) - bfin_spi_cs_deactive(drv_data, chip); - - /* Move to next transfer */ - msg->state = bfin_spi_next_transfer(drv_data); - } - - /* Schedule transfer tasklet */ - tasklet_schedule(&drv_data->pump_transfers); - - /* free the irq handler before next transfer */ - dev_dbg(&drv_data->pdev->dev, - "disable dma channel irq%d\n", - drv_data->dma_channel); - dma_disable_irq_nosync(drv_data->dma_channel); - - return IRQ_HANDLED; -} - -static void bfin_spi_pump_transfers(unsigned long data) -{ - struct bfin_spi_master_data *drv_data = (struct bfin_spi_master_data *)data; - struct spi_message *message = NULL; - struct spi_transfer *transfer = NULL; - struct spi_transfer *previous = NULL; - struct bfin_spi_slave_data *chip = NULL; - unsigned int bits_per_word; - u16 cr, cr_width = 0, dma_width, dma_config; - u32 tranf_success = 1; - u8 full_duplex = 0; - - /* Get current state information */ - message = drv_data->cur_msg; - transfer = drv_data->cur_transfer; - chip = drv_data->cur_chip; - - /* - * if msg is error or done, report it back using complete() callback - */ - - /* Handle for abort */ - if (message->state == ERROR_STATE) { - dev_dbg(&drv_data->pdev->dev, "transfer: we've hit an error\n"); - message->status = -EIO; - bfin_spi_giveback(drv_data); - return; - } - - /* Handle end of message */ - if (message->state == DONE_STATE) { - dev_dbg(&drv_data->pdev->dev, "transfer: all done!\n"); - message->status = 0; - bfin_spi_flush(drv_data); - bfin_spi_giveback(drv_data); - return; - } - - /* Delay if requested at end of transfer */ - if (message->state == RUNNING_STATE) { - dev_dbg(&drv_data->pdev->dev, "transfer: still running ...\n"); - previous = list_entry(transfer->transfer_list.prev, - struct spi_transfer, transfer_list); - if (previous->delay_usecs) - udelay(previous->delay_usecs); - } - - /* Flush any existing transfers that may be sitting in the hardware */ - if (bfin_spi_flush(drv_data) == 0) { - dev_err(&drv_data->pdev->dev, "pump_transfers: flush failed\n"); - message->status = -EIO; - bfin_spi_giveback(drv_data); - return; - } - - if (transfer->len == 0) { - /* Move to next transfer of this msg */ - message->state = bfin_spi_next_transfer(drv_data); - /* Schedule next transfer tasklet */ - tasklet_schedule(&drv_data->pump_transfers); - return; - } - - if (transfer->tx_buf != NULL) { - drv_data->tx = (void *)transfer->tx_buf; - drv_data->tx_end = drv_data->tx + transfer->len; - dev_dbg(&drv_data->pdev->dev, "tx_buf is %p, tx_end is %p\n", - transfer->tx_buf, drv_data->tx_end); - } else { - drv_data->tx = NULL; - } - - if (transfer->rx_buf != NULL) { - full_duplex = transfer->tx_buf != NULL; - drv_data->rx = transfer->rx_buf; - drv_data->rx_end = drv_data->rx + transfer->len; - dev_dbg(&drv_data->pdev->dev, "rx_buf is %p, rx_end is %p\n", - transfer->rx_buf, drv_data->rx_end); - } else { - drv_data->rx = NULL; - } - - drv_data->rx_dma = transfer->rx_dma; - drv_data->tx_dma = transfer->tx_dma; - drv_data->len_in_bytes = transfer->len; - drv_data->cs_change = transfer->cs_change; - - /* Bits per word setup */ - bits_per_word = transfer->bits_per_word; - if (bits_per_word == 16) { - drv_data->n_bytes = bits_per_word/8; - drv_data->len = (transfer->len) >> 1; - cr_width = BIT_CTL_WORDSIZE; - drv_data->ops = &bfin_bfin_spi_transfer_ops_u16; - } else if (bits_per_word == 8) { - drv_data->n_bytes = bits_per_word/8; - drv_data->len = transfer->len; - drv_data->ops = &bfin_bfin_spi_transfer_ops_u8; - } - cr = bfin_read(&drv_data->regs->ctl) & ~(BIT_CTL_TIMOD | BIT_CTL_WORDSIZE); - cr |= cr_width; - bfin_write(&drv_data->regs->ctl, cr); - - dev_dbg(&drv_data->pdev->dev, - "transfer: drv_data->ops is %p, chip->ops is %p, u8_ops is %p\n", - drv_data->ops, chip->ops, &bfin_bfin_spi_transfer_ops_u8); - - message->state = RUNNING_STATE; - dma_config = 0; - - bfin_write(&drv_data->regs->baud, hz_to_spi_baud(transfer->speed_hz)); - - bfin_write(&drv_data->regs->stat, BIT_STAT_CLR); - bfin_spi_cs_active(drv_data, chip); - - dev_dbg(&drv_data->pdev->dev, - "now pumping a transfer: width is %d, len is %d\n", - cr_width, transfer->len); - - /* - * Try to map dma buffer and do a dma transfer. If successful use, - * different way to r/w according to the enable_dma settings and if - * we are not doing a full duplex transfer (since the hardware does - * not support full duplex DMA transfers). - */ - if (!full_duplex && drv_data->cur_chip->enable_dma - && drv_data->len > 6) { - - unsigned long dma_start_addr, flags; - - disable_dma(drv_data->dma_channel); - clear_dma_irqstat(drv_data->dma_channel); - - /* config dma channel */ - dev_dbg(&drv_data->pdev->dev, "doing dma transfer\n"); - set_dma_x_count(drv_data->dma_channel, drv_data->len); - if (cr_width == BIT_CTL_WORDSIZE) { - set_dma_x_modify(drv_data->dma_channel, 2); - dma_width = WDSIZE_16; - } else { - set_dma_x_modify(drv_data->dma_channel, 1); - dma_width = WDSIZE_8; - } - - /* poll for SPI completion before start */ - while (!(bfin_read(&drv_data->regs->stat) & BIT_STAT_SPIF)) - cpu_relax(); - - /* dirty hack for autobuffer DMA mode */ - if (drv_data->tx_dma == 0xFFFF) { - dev_dbg(&drv_data->pdev->dev, - "doing autobuffer DMA out.\n"); - - /* no irq in autobuffer mode */ - dma_config = - (DMAFLOW_AUTO | RESTART | dma_width | DI_EN); - set_dma_config(drv_data->dma_channel, dma_config); - set_dma_start_addr(drv_data->dma_channel, - (unsigned long)drv_data->tx); - enable_dma(drv_data->dma_channel); - - /* start SPI transfer */ - bfin_write(&drv_data->regs->ctl, cr | BIT_CTL_TIMOD_DMA_TX); - - /* just return here, there can only be one transfer - * in this mode - */ - message->status = 0; - bfin_spi_giveback(drv_data); - return; - } - - /* In dma mode, rx or tx must be NULL in one transfer */ - dma_config = (RESTART | dma_width | DI_EN); - if (drv_data->rx != NULL) { - /* set transfer mode, and enable SPI */ - dev_dbg(&drv_data->pdev->dev, "doing DMA in to %p (size %zx)\n", - drv_data->rx, drv_data->len_in_bytes); - - /* invalidate caches, if needed */ - if (bfin_addr_dcacheable((unsigned long) drv_data->rx)) - invalidate_dcache_range((unsigned long) drv_data->rx, - (unsigned long) (drv_data->rx + - drv_data->len_in_bytes)); - - dma_config |= WNR; - dma_start_addr = (unsigned long)drv_data->rx; - cr |= BIT_CTL_TIMOD_DMA_RX | BIT_CTL_SENDOPT; - - } else if (drv_data->tx != NULL) { - dev_dbg(&drv_data->pdev->dev, "doing DMA out.\n"); - - /* flush caches, if needed */ - if (bfin_addr_dcacheable((unsigned long) drv_data->tx)) - flush_dcache_range((unsigned long) drv_data->tx, - (unsigned long) (drv_data->tx + - drv_data->len_in_bytes)); - - dma_start_addr = (unsigned long)drv_data->tx; - cr |= BIT_CTL_TIMOD_DMA_TX; - - } else - BUG(); - - /* oh man, here there be monsters ... and i dont mean the - * fluffy cute ones from pixar, i mean the kind that'll eat - * your data, kick your dog, and love it all. do *not* try - * and change these lines unless you (1) heavily test DMA - * with SPI flashes on a loaded system (e.g. ping floods), - * (2) know just how broken the DMA engine interaction with - * the SPI peripheral is, and (3) have someone else to blame - * when you screw it all up anyways. - */ - set_dma_start_addr(drv_data->dma_channel, dma_start_addr); - set_dma_config(drv_data->dma_channel, dma_config); - local_irq_save(flags); - SSYNC(); - bfin_write(&drv_data->regs->ctl, cr); - enable_dma(drv_data->dma_channel); - dma_enable_irq(drv_data->dma_channel); - local_irq_restore(flags); - - return; - } - - /* - * We always use SPI_WRITE mode (transfer starts with TDBR write). - * SPI_READ mode (transfer starts with RDBR read) seems to have - * problems with setting up the output value in TDBR prior to the - * start of the transfer. - */ - bfin_write(&drv_data->regs->ctl, cr | BIT_CTL_TXMOD); - - if (chip->pio_interrupt) { - /* SPI irq should have been disabled by now */ - - /* discard old RX data and clear RXS */ - bfin_spi_dummy_read(drv_data); - - /* start transfer */ - if (drv_data->tx == NULL) - bfin_write(&drv_data->regs->tdbr, chip->idle_tx_val); - else { - int loop; - if (bits_per_word == 16) { - u16 *buf = (u16 *)drv_data->tx; - for (loop = 0; loop < bits_per_word / 16; - loop++) { - bfin_write(&drv_data->regs->tdbr, *buf++); - } - } else if (bits_per_word == 8) { - u8 *buf = (u8 *)drv_data->tx; - for (loop = 0; loop < bits_per_word / 8; loop++) - bfin_write(&drv_data->regs->tdbr, *buf++); - } - - drv_data->tx += drv_data->n_bytes; - } - - /* once TDBR is empty, interrupt is triggered */ - enable_irq(drv_data->spi_irq); - return; - } - - /* IO mode */ - dev_dbg(&drv_data->pdev->dev, "doing IO transfer\n"); - - if (full_duplex) { - /* full duplex mode */ - BUG_ON((drv_data->tx_end - drv_data->tx) != - (drv_data->rx_end - drv_data->rx)); - dev_dbg(&drv_data->pdev->dev, - "IO duplex: cr is 0x%x\n", cr); - - drv_data->ops->duplex(drv_data); - - if (drv_data->tx != drv_data->tx_end) - tranf_success = 0; - } else if (drv_data->tx != NULL) { - /* write only half duplex */ - dev_dbg(&drv_data->pdev->dev, - "IO write: cr is 0x%x\n", cr); - - drv_data->ops->write(drv_data); - - if (drv_data->tx != drv_data->tx_end) - tranf_success = 0; - } else if (drv_data->rx != NULL) { - /* read only half duplex */ - dev_dbg(&drv_data->pdev->dev, - "IO read: cr is 0x%x\n", cr); - - drv_data->ops->read(drv_data); - if (drv_data->rx != drv_data->rx_end) - tranf_success = 0; - } - - if (!tranf_success) { - dev_dbg(&drv_data->pdev->dev, - "IO write error!\n"); - message->state = ERROR_STATE; - } else { - /* Update total byte transferred */ - message->actual_length += drv_data->len_in_bytes; - /* Move to next transfer of this msg */ - message->state = bfin_spi_next_transfer(drv_data); - if (drv_data->cs_change && message->state != DONE_STATE) { - bfin_spi_flush(drv_data); - bfin_spi_cs_deactive(drv_data, chip); - } - } - - /* Schedule next transfer tasklet */ - tasklet_schedule(&drv_data->pump_transfers); -} - -/* pop a msg from queue and kick off real transfer */ -static void bfin_spi_pump_messages(struct work_struct *work) -{ - struct bfin_spi_master_data *drv_data; - unsigned long flags; - - drv_data = container_of(work, struct bfin_spi_master_data, pump_messages); - - /* Lock queue and check for queue work */ - spin_lock_irqsave(&drv_data->lock, flags); - if (list_empty(&drv_data->queue) || !drv_data->running) { - /* pumper kicked off but no work to do */ - drv_data->busy = 0; - spin_unlock_irqrestore(&drv_data->lock, flags); - return; - } - - /* Make sure we are not already running a message */ - if (drv_data->cur_msg) { - spin_unlock_irqrestore(&drv_data->lock, flags); - return; - } - - /* Extract head of queue */ - drv_data->cur_msg = list_entry(drv_data->queue.next, - struct spi_message, queue); - - /* Setup the SSP using the per chip configuration */ - drv_data->cur_chip = spi_get_ctldata(drv_data->cur_msg->spi); - bfin_spi_restore_state(drv_data); - - list_del_init(&drv_data->cur_msg->queue); - - /* Initial message state */ - drv_data->cur_msg->state = START_STATE; - drv_data->cur_transfer = list_entry(drv_data->cur_msg->transfers.next, - struct spi_transfer, transfer_list); - - dev_dbg(&drv_data->pdev->dev, - "got a message to pump, state is set to: baud " - "%d, flag 0x%x, ctl 0x%x\n", - drv_data->cur_chip->baud, drv_data->cur_chip->flag, - drv_data->cur_chip->ctl_reg); - - dev_dbg(&drv_data->pdev->dev, - "the first transfer len is %d\n", - drv_data->cur_transfer->len); - - /* Mark as busy and launch transfers */ - tasklet_schedule(&drv_data->pump_transfers); - - drv_data->busy = 1; - spin_unlock_irqrestore(&drv_data->lock, flags); -} - -/* - * got a msg to transfer, queue it in drv_data->queue. - * And kick off message pumper - */ -static int bfin_spi_transfer(struct spi_device *spi, struct spi_message *msg) -{ - struct bfin_spi_master_data *drv_data = spi_master_get_devdata(spi->master); - unsigned long flags; - - spin_lock_irqsave(&drv_data->lock, flags); - - if (!drv_data->running) { - spin_unlock_irqrestore(&drv_data->lock, flags); - return -ESHUTDOWN; - } - - msg->actual_length = 0; - msg->status = -EINPROGRESS; - msg->state = START_STATE; - - dev_dbg(&spi->dev, "adding an msg in transfer() \n"); - list_add_tail(&msg->queue, &drv_data->queue); - - if (drv_data->running && !drv_data->busy) - schedule_work(&drv_data->pump_messages); - - spin_unlock_irqrestore(&drv_data->lock, flags); - - return 0; -} - -#define MAX_SPI_SSEL 7 - -static const u16 ssel[][MAX_SPI_SSEL] = { - {P_SPI0_SSEL1, P_SPI0_SSEL2, P_SPI0_SSEL3, - P_SPI0_SSEL4, P_SPI0_SSEL5, - P_SPI0_SSEL6, P_SPI0_SSEL7}, - - {P_SPI1_SSEL1, P_SPI1_SSEL2, P_SPI1_SSEL3, - P_SPI1_SSEL4, P_SPI1_SSEL5, - P_SPI1_SSEL6, P_SPI1_SSEL7}, - - {P_SPI2_SSEL1, P_SPI2_SSEL2, P_SPI2_SSEL3, - P_SPI2_SSEL4, P_SPI2_SSEL5, - P_SPI2_SSEL6, P_SPI2_SSEL7}, -}; - -/* setup for devices (may be called multiple times -- not just first setup) */ -static int bfin_spi_setup(struct spi_device *spi) -{ - struct bfin5xx_spi_chip *chip_info; - struct bfin_spi_slave_data *chip = NULL; - struct bfin_spi_master_data *drv_data = spi_master_get_devdata(spi->master); - u16 bfin_ctl_reg; - int ret = -EINVAL; - - /* Only alloc (or use chip_info) on first setup */ - chip_info = NULL; - chip = spi_get_ctldata(spi); - if (chip == NULL) { - chip = kzalloc(sizeof(*chip), GFP_KERNEL); - if (!chip) { - dev_err(&spi->dev, "cannot allocate chip data\n"); - ret = -ENOMEM; - goto error; - } - - chip->enable_dma = 0; - chip_info = spi->controller_data; - } - - /* Let people set non-standard bits directly */ - bfin_ctl_reg = BIT_CTL_OPENDRAIN | BIT_CTL_EMISO | - BIT_CTL_PSSE | BIT_CTL_GM | BIT_CTL_SZ; - - /* chip_info isn't always needed */ - if (chip_info) { - /* Make sure people stop trying to set fields via ctl_reg - * when they should actually be using common SPI framework. - * Currently we let through: WOM EMISO PSSE GM SZ. - * Not sure if a user actually needs/uses any of these, - * but let's assume (for now) they do. - */ - if (chip_info->ctl_reg & ~bfin_ctl_reg) { - dev_err(&spi->dev, - "do not set bits in ctl_reg that the SPI framework manages\n"); - goto error; - } - chip->enable_dma = chip_info->enable_dma != 0 - && drv_data->master_info->enable_dma; - chip->ctl_reg = chip_info->ctl_reg; - chip->cs_chg_udelay = chip_info->cs_chg_udelay; - chip->idle_tx_val = chip_info->idle_tx_val; - chip->pio_interrupt = chip_info->pio_interrupt; - } else { - /* force a default base state */ - chip->ctl_reg &= bfin_ctl_reg; - } - - /* translate common spi framework into our register */ - if (spi->mode & SPI_CPOL) - chip->ctl_reg |= BIT_CTL_CPOL; - if (spi->mode & SPI_CPHA) - chip->ctl_reg |= BIT_CTL_CPHA; - if (spi->mode & SPI_LSB_FIRST) - chip->ctl_reg |= BIT_CTL_LSBF; - /* we dont support running in slave mode (yet?) */ - chip->ctl_reg |= BIT_CTL_MASTER; - - /* - * Notice: for blackfin, the speed_hz is the value of register - * SPI_BAUD, not the real baudrate - */ - chip->baud = hz_to_spi_baud(spi->max_speed_hz); - chip->chip_select_num = spi->chip_select; - if (chip->chip_select_num < MAX_CTRL_CS) { - if (!(spi->mode & SPI_CPHA)) - dev_warn(&spi->dev, - "Warning: SPI CPHA not set: Slave Select not under software control!\n" - "See Documentation/blackfin/bfin-spi-notes.txt\n"); - - chip->flag = (1 << spi->chip_select) << 8; - } else - chip->cs_gpio = chip->chip_select_num - MAX_CTRL_CS; - - if (chip->enable_dma && chip->pio_interrupt) { - dev_err(&spi->dev, - "enable_dma is set, do not set pio_interrupt\n"); - goto error; - } - /* - * if any one SPI chip is registered and wants DMA, request the - * DMA channel for it - */ - if (chip->enable_dma && !drv_data->dma_requested) { - /* register dma irq handler */ - ret = request_dma(drv_data->dma_channel, "BFIN_SPI_DMA"); - if (ret) { - dev_err(&spi->dev, - "Unable to request BlackFin SPI DMA channel\n"); - goto error; - } - drv_data->dma_requested = 1; - - ret = set_dma_callback(drv_data->dma_channel, - bfin_spi_dma_irq_handler, drv_data); - if (ret) { - dev_err(&spi->dev, "Unable to set dma callback\n"); - goto error; - } - dma_disable_irq(drv_data->dma_channel); - } - - if (chip->pio_interrupt && !drv_data->irq_requested) { - ret = request_irq(drv_data->spi_irq, bfin_spi_pio_irq_handler, - 0, "BFIN_SPI", drv_data); - if (ret) { - dev_err(&spi->dev, "Unable to register spi IRQ\n"); - goto error; - } - drv_data->irq_requested = 1; - /* we use write mode, spi irq has to be disabled here */ - disable_irq(drv_data->spi_irq); - } - - if (chip->chip_select_num >= MAX_CTRL_CS) { - /* Only request on first setup */ - if (spi_get_ctldata(spi) == NULL) { - ret = gpio_request(chip->cs_gpio, spi->modalias); - if (ret) { - dev_err(&spi->dev, "gpio_request() error\n"); - goto pin_error; - } - gpio_direction_output(chip->cs_gpio, 1); - } - } - - dev_dbg(&spi->dev, "setup spi chip %s, width is %d, dma is %d\n", - spi->modalias, spi->bits_per_word, chip->enable_dma); - dev_dbg(&spi->dev, "ctl_reg is 0x%x, flag_reg is 0x%x\n", - chip->ctl_reg, chip->flag); - - spi_set_ctldata(spi, chip); - - dev_dbg(&spi->dev, "chip select number is %d\n", chip->chip_select_num); - if (chip->chip_select_num < MAX_CTRL_CS) { - ret = peripheral_request(ssel[spi->master->bus_num] - [chip->chip_select_num-1], spi->modalias); - if (ret) { - dev_err(&spi->dev, "peripheral_request() error\n"); - goto pin_error; - } - } - - bfin_spi_cs_enable(drv_data, chip); - bfin_spi_cs_deactive(drv_data, chip); - - return 0; - - pin_error: - if (chip->chip_select_num >= MAX_CTRL_CS) - gpio_free(chip->cs_gpio); - else - peripheral_free(ssel[spi->master->bus_num] - [chip->chip_select_num - 1]); - error: - if (chip) { - if (drv_data->dma_requested) - free_dma(drv_data->dma_channel); - drv_data->dma_requested = 0; - - kfree(chip); - /* prevent free 'chip' twice */ - spi_set_ctldata(spi, NULL); - } - - return ret; -} - -/* - * callback for spi framework. - * clean driver specific data - */ -static void bfin_spi_cleanup(struct spi_device *spi) -{ - struct bfin_spi_slave_data *chip = spi_get_ctldata(spi); - struct bfin_spi_master_data *drv_data = spi_master_get_devdata(spi->master); - - if (!chip) - return; - - if (chip->chip_select_num < MAX_CTRL_CS) { - peripheral_free(ssel[spi->master->bus_num] - [chip->chip_select_num-1]); - bfin_spi_cs_disable(drv_data, chip); - } else - gpio_free(chip->cs_gpio); - - kfree(chip); - /* prevent free 'chip' twice */ - spi_set_ctldata(spi, NULL); -} - -static int bfin_spi_init_queue(struct bfin_spi_master_data *drv_data) -{ - INIT_LIST_HEAD(&drv_data->queue); - spin_lock_init(&drv_data->lock); - - drv_data->running = false; - drv_data->busy = 0; - - /* init transfer tasklet */ - tasklet_init(&drv_data->pump_transfers, - bfin_spi_pump_transfers, (unsigned long)drv_data); - - INIT_WORK(&drv_data->pump_messages, bfin_spi_pump_messages); - - return 0; -} - -static int bfin_spi_start_queue(struct bfin_spi_master_data *drv_data) -{ - unsigned long flags; - - spin_lock_irqsave(&drv_data->lock, flags); - - if (drv_data->running || drv_data->busy) { - spin_unlock_irqrestore(&drv_data->lock, flags); - return -EBUSY; - } - - drv_data->running = true; - drv_data->cur_msg = NULL; - drv_data->cur_transfer = NULL; - drv_data->cur_chip = NULL; - spin_unlock_irqrestore(&drv_data->lock, flags); - - schedule_work(&drv_data->pump_messages); - - return 0; -} - -static int bfin_spi_stop_queue(struct bfin_spi_master_data *drv_data) -{ - unsigned long flags; - unsigned limit = 500; - int status = 0; - - spin_lock_irqsave(&drv_data->lock, flags); - - /* - * This is a bit lame, but is optimized for the common execution path. - * A wait_queue on the drv_data->busy could be used, but then the common - * execution path (pump_messages) would be required to call wake_up or - * friends on every SPI message. Do this instead - */ - drv_data->running = false; - while ((!list_empty(&drv_data->queue) || drv_data->busy) && limit--) { - spin_unlock_irqrestore(&drv_data->lock, flags); - msleep(10); - spin_lock_irqsave(&drv_data->lock, flags); - } - - if (!list_empty(&drv_data->queue) || drv_data->busy) - status = -EBUSY; - - spin_unlock_irqrestore(&drv_data->lock, flags); - - return status; -} - -static int bfin_spi_destroy_queue(struct bfin_spi_master_data *drv_data) -{ - int status; - - status = bfin_spi_stop_queue(drv_data); - if (status != 0) - return status; - - flush_work(&drv_data->pump_messages); - - return 0; -} - -static int bfin_spi_probe(struct platform_device *pdev) -{ - struct device *dev = &pdev->dev; - struct bfin5xx_spi_master *platform_info; - struct spi_master *master; - struct bfin_spi_master_data *drv_data; - struct resource *res; - int status = 0; - - platform_info = dev_get_platdata(dev); - - /* Allocate master with space for drv_data */ - master = spi_alloc_master(dev, sizeof(*drv_data)); - if (!master) { - dev_err(&pdev->dev, "can not alloc spi_master\n"); - return -ENOMEM; - } - - drv_data = spi_master_get_devdata(master); - drv_data->master = master; - drv_data->master_info = platform_info; - drv_data->pdev = pdev; - drv_data->pin_req = platform_info->pin_req; - - /* the spi->mode bits supported by this driver: */ - master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST; - master->bits_per_word_mask = SPI_BPW_MASK(8) | SPI_BPW_MASK(16); - master->bus_num = pdev->id; - master->num_chipselect = platform_info->num_chipselect; - master->cleanup = bfin_spi_cleanup; - master->setup = bfin_spi_setup; - master->transfer = bfin_spi_transfer; - - /* Find and map our resources */ - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (res == NULL) { - dev_err(dev, "Cannot get IORESOURCE_MEM\n"); - status = -ENOENT; - goto out_error_get_res; - } - - drv_data->regs = ioremap(res->start, resource_size(res)); - if (drv_data->regs == NULL) { - dev_err(dev, "Cannot map IO\n"); - status = -ENXIO; - goto out_error_ioremap; - } - - res = platform_get_resource(pdev, IORESOURCE_DMA, 0); - if (res == NULL) { - dev_err(dev, "No DMA channel specified\n"); - status = -ENOENT; - goto out_error_free_io; - } - drv_data->dma_channel = res->start; - - drv_data->spi_irq = platform_get_irq(pdev, 0); - if (drv_data->spi_irq < 0) { - dev_err(dev, "No spi pio irq specified\n"); - status = -ENOENT; - goto out_error_free_io; - } - - /* Initial and start queue */ - status = bfin_spi_init_queue(drv_data); - if (status != 0) { - dev_err(dev, "problem initializing queue\n"); - goto out_error_queue_alloc; - } - - status = bfin_spi_start_queue(drv_data); - if (status != 0) { - dev_err(dev, "problem starting queue\n"); - goto out_error_queue_alloc; - } - - status = peripheral_request_list(drv_data->pin_req, DRV_NAME); - if (status != 0) { - dev_err(&pdev->dev, ": Requesting Peripherals failed\n"); - goto out_error_queue_alloc; - } - - /* Reset SPI registers. If these registers were used by the boot loader, - * the sky may fall on your head if you enable the dma controller. - */ - bfin_write(&drv_data->regs->ctl, BIT_CTL_CPHA | BIT_CTL_MASTER); - bfin_write(&drv_data->regs->flg, 0xFF00); - - /* Register with the SPI framework */ - platform_set_drvdata(pdev, drv_data); - status = spi_register_master(master); - if (status != 0) { - dev_err(dev, "problem registering spi master\n"); - goto out_error_queue_alloc; - } - - dev_info(dev, "%s, Version %s, regs@%p, dma channel@%d\n", - DRV_DESC, DRV_VERSION, drv_data->regs, - drv_data->dma_channel); - return status; - -out_error_queue_alloc: - bfin_spi_destroy_queue(drv_data); -out_error_free_io: - iounmap(drv_data->regs); -out_error_ioremap: -out_error_get_res: - spi_master_put(master); - - return status; -} - -/* stop hardware and remove the driver */ -static int bfin_spi_remove(struct platform_device *pdev) -{ - struct bfin_spi_master_data *drv_data = platform_get_drvdata(pdev); - int status = 0; - - if (!drv_data) - return 0; - - /* Remove the queue */ - status = bfin_spi_destroy_queue(drv_data); - if (status != 0) - return status; - - /* Disable the SSP at the peripheral and SOC level */ - bfin_spi_disable(drv_data); - - /* Release DMA */ - if (drv_data->master_info->enable_dma) { - if (dma_channel_active(drv_data->dma_channel)) - free_dma(drv_data->dma_channel); - } - - if (drv_data->irq_requested) { - free_irq(drv_data->spi_irq, drv_data); - drv_data->irq_requested = 0; - } - - /* Disconnect from the SPI framework */ - spi_unregister_master(drv_data->master); - - peripheral_free_list(drv_data->pin_req); - - return 0; -} - -#ifdef CONFIG_PM_SLEEP -static int bfin_spi_suspend(struct device *dev) -{ - struct bfin_spi_master_data *drv_data = dev_get_drvdata(dev); - int status = 0; - - status = bfin_spi_stop_queue(drv_data); - if (status != 0) - return status; - - drv_data->ctrl_reg = bfin_read(&drv_data->regs->ctl); - drv_data->flag_reg = bfin_read(&drv_data->regs->flg); - - /* - * reset SPI_CTL and SPI_FLG registers - */ - bfin_write(&drv_data->regs->ctl, BIT_CTL_CPHA | BIT_CTL_MASTER); - bfin_write(&drv_data->regs->flg, 0xFF00); - - return 0; -} - -static int bfin_spi_resume(struct device *dev) -{ - struct bfin_spi_master_data *drv_data = dev_get_drvdata(dev); - int status = 0; - - bfin_write(&drv_data->regs->ctl, drv_data->ctrl_reg); - bfin_write(&drv_data->regs->flg, drv_data->flag_reg); - - /* Start the queue running */ - status = bfin_spi_start_queue(drv_data); - if (status != 0) { - dev_err(dev, "problem starting queue (%d)\n", status); - return status; - } - - return 0; -} - -static SIMPLE_DEV_PM_OPS(bfin_spi_pm_ops, bfin_spi_suspend, bfin_spi_resume); - -#define BFIN_SPI_PM_OPS (&bfin_spi_pm_ops) -#else -#define BFIN_SPI_PM_OPS NULL -#endif - -MODULE_ALIAS("platform:bfin-spi"); -static struct platform_driver bfin_spi_driver = { - .driver = { - .name = DRV_NAME, - .pm = BFIN_SPI_PM_OPS, - }, - .probe = bfin_spi_probe, - .remove = bfin_spi_remove, -}; - -static int __init bfin_spi_init(void) -{ - return platform_driver_register(&bfin_spi_driver); -} -subsys_initcall(bfin_spi_init); - -static void __exit bfin_spi_exit(void) -{ - platform_driver_unregister(&bfin_spi_driver); -} -module_exit(bfin_spi_exit); -- cgit v1.2.3 From 357325764d7eabc4d2169d26af079b441fd48bc5 Mon Sep 17 00:00:00 2001 From: Stefan Agner Date: Sat, 24 Mar 2018 11:48:00 +0100 Subject: spi: spi-atmel: Use correct enum for DMA transfer direction Use enum dma_transfer_direction as required by the functions dmaengine_prep_slave_(sg|single)() instead of enum dma_data_direction. This won't change behavior in practice as the enum values are equivalent. This fixes two warnings when building with clang: drivers/spi/spi-atmel.c:771:12: warning: implicit conversion from enumeration type 'enum dma_data_direction' to different enumeration type 'enum dma_transfer_direction' [-Wenum-conversion] DMA_FROM_DEVICE, ^~~~~~~~~~~~~~~ ... Signed-off-by: Stefan Agner Acked-by: Nicolas Ferre Reviewed-by: Geert Uytterhoeven Signed-off-by: Mark Brown --- drivers/spi/spi-atmel.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi-atmel.c b/drivers/spi/spi-atmel.c index b7936f815373..3f890d162934 100644 --- a/drivers/spi/spi-atmel.c +++ b/drivers/spi/spi-atmel.c @@ -768,14 +768,14 @@ static int atmel_spi_next_xfer_dma_submit(struct spi_master *master, rxdesc = dmaengine_prep_slave_single(rxchan, as->dma_addr_rx_bbuf, xfer->len, - DMA_FROM_DEVICE, + DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); } else { rxdesc = dmaengine_prep_slave_sg(rxchan, xfer->rx_sg.sgl, xfer->rx_sg.nents, - DMA_FROM_DEVICE, + DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); } @@ -787,14 +787,14 @@ static int atmel_spi_next_xfer_dma_submit(struct spi_master *master, memcpy(as->addr_tx_bbuf, xfer->tx_buf, xfer->len); txdesc = dmaengine_prep_slave_single(txchan, as->dma_addr_tx_bbuf, - xfer->len, DMA_TO_DEVICE, + xfer->len, DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); } else { txdesc = dmaengine_prep_slave_sg(txchan, xfer->tx_sg.sgl, xfer->tx_sg.nents, - DMA_TO_DEVICE, + DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); } -- cgit v1.2.3