diff options
author | Mark Brown <broonie@kernel.org> | 2019-07-04 17:35:07 +0100 |
---|---|---|
committer | Mark Brown <broonie@kernel.org> | 2019-07-04 17:35:07 +0100 |
commit | 106dbe24d4146c0804cb025e450ac7af42d72356 (patch) | |
tree | ad196f245894a8546603f8472619f9e5b73b8265 /drivers/spi | |
parent | 2337ff45293f36efa79247b3680223b9c9154392 (diff) | |
parent | 8cc7720470a17558bd6f8d67df63361600e46c55 (diff) |
Merge branch 'spi-5.3' into spi-next
Diffstat (limited to 'drivers/spi')
-rw-r--r-- | drivers/spi/Kconfig | 14 | ||||
-rw-r--r-- | drivers/spi/Makefile | 1 | ||||
-rw-r--r-- | drivers/spi/atmel-quadspi.c | 21 | ||||
-rw-r--r-- | drivers/spi/spi-at91-usart.c | 221 | ||||
-rw-r--r-- | drivers/spi/spi-bcm2835.c | 328 | ||||
-rw-r--r-- | drivers/spi/spi-bcm2835aux.c | 4 | ||||
-rw-r--r-- | drivers/spi/spi-meson-spifc.c | 12 | ||||
-rw-r--r-- | drivers/spi/spi-mt65xx.c | 15 | ||||
-rw-r--r-- | drivers/spi/spi-pxa2xx.c | 14 | ||||
-rw-r--r-- | drivers/spi/spi-qup.c | 4 | ||||
-rw-r--r-- | drivers/spi/spi-rockchip.c | 4 | ||||
-rw-r--r-- | drivers/spi/spi-sh-msiof.c | 2 | ||||
-rw-r--r-- | drivers/spi/spi-stm32-qspi.c | 10 | ||||
-rw-r--r-- | drivers/spi/spi-synquacer.c | 828 | ||||
-rw-r--r-- | drivers/spi/spi-tegra114.c | 170 | ||||
-rw-r--r-- | drivers/spi/spi.c | 194 | ||||
-rw-r--r-- | drivers/spi/spidev.c | 2 |
17 files changed, 1603 insertions, 241 deletions
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index 30a40280c157..3a1d8f1170de 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -120,7 +120,7 @@ config SPI_AXI_SPI_ENGINE config SPI_BCM2835 tristate "BCM2835 SPI controller" depends on GPIOLIB - depends on ARCH_BCM2835 || COMPILE_TEST + depends on ARCH_BCM2835 || ARCH_BRCMSTB || COMPILE_TEST help This selects a driver for the Broadcom BCM2835 SPI master. @@ -131,7 +131,7 @@ config SPI_BCM2835 config SPI_BCM2835AUX tristate "BCM2835 SPI auxiliary controller" - depends on (ARCH_BCM2835 && GPIOLIB) || COMPILE_TEST + depends on ((ARCH_BCM2835 || ARCH_BRCMSTB) && GPIOLIB) || COMPILE_TEST help This selects a driver for the Broadcom BCM2835 SPI aux master. @@ -733,6 +733,16 @@ config SPI_SUN6I help This enables using the SPI controller on the Allwinner A31 SoCs. +config SPI_SYNQUACER + tristate "Socionext's SynQuacer HighSpeed SPI controller" + depends on ARCH_SYNQUACER || COMPILE_TEST + help + SPI driver for Socionext's High speed SPI controller which provides + various operating modes for interfacing to serial peripheral devices + that use the de-facto standard SPI protocol. + + It also supports the new dual-bit and quad-bit SPI protocol. + config SPI_MXIC tristate "Macronix MX25F0A SPI controller" depends on SPI_MASTER diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile index f2f78d03dc28..63dcab552bcb 100644 --- a/drivers/spi/Makefile +++ b/drivers/spi/Makefile @@ -106,6 +106,7 @@ obj-$(CONFIG_SPI_STM32_QSPI) += spi-stm32-qspi.o obj-$(CONFIG_SPI_ST_SSC4) += spi-st-ssc4.o obj-$(CONFIG_SPI_SUN4I) += spi-sun4i.o obj-$(CONFIG_SPI_SUN6I) += spi-sun6i.o +obj-$(CONFIG_SPI_SYNQUACER) += spi-synquacer.o obj-$(CONFIG_SPI_TEGRA114) += spi-tegra114.o obj-$(CONFIG_SPI_TEGRA20_SFLASH) += spi-tegra20-sflash.o obj-$(CONFIG_SPI_TEGRA20_SLINK) += spi-tegra20-slink.o diff --git a/drivers/spi/atmel-quadspi.c b/drivers/spi/atmel-quadspi.c index 9f24d5f0b431..6a7d7b553d95 100644 --- a/drivers/spi/atmel-quadspi.c +++ b/drivers/spi/atmel-quadspi.c @@ -151,6 +151,7 @@ struct atmel_qspi { const struct atmel_qspi_caps *caps; u32 pending; u32 mr; + u32 scr; struct completion cmd_completion; }; @@ -382,7 +383,7 @@ static int atmel_qspi_setup(struct spi_device *spi) struct spi_controller *ctrl = spi->master; struct atmel_qspi *aq = spi_controller_get_devdata(ctrl); unsigned long src_rate; - u32 scr, scbr; + u32 scbr; if (ctrl->busy) return -EBUSY; @@ -399,13 +400,13 @@ static int atmel_qspi_setup(struct spi_device *spi) if (scbr > 0) scbr--; - scr = QSPI_SCR_SCBR(scbr); - writel_relaxed(scr, aq->regs + QSPI_SCR); + aq->scr = QSPI_SCR_SCBR(scbr); + writel_relaxed(aq->scr, aq->regs + QSPI_SCR); return 0; } -static int atmel_qspi_init(struct atmel_qspi *aq) +static void atmel_qspi_init(struct atmel_qspi *aq) { /* Reset the QSPI controller */ writel_relaxed(QSPI_CR_SWRST, aq->regs + QSPI_CR); @@ -416,8 +417,6 @@ static int atmel_qspi_init(struct atmel_qspi *aq) /* Enable the QSPI controller */ writel_relaxed(QSPI_CR_QSPIEN, aq->regs + QSPI_CR); - - return 0; } static irqreturn_t atmel_qspi_interrupt(int irq, void *dev_id) @@ -536,9 +535,7 @@ static int atmel_qspi_probe(struct platform_device *pdev) if (err) goto disable_qspick; - err = atmel_qspi_init(aq); - if (err) - goto disable_qspick; + atmel_qspi_init(aq); err = spi_register_controller(ctrl); if (err) @@ -587,7 +584,11 @@ static int __maybe_unused atmel_qspi_resume(struct device *dev) clk_prepare_enable(aq->pclk); clk_prepare_enable(aq->qspick); - return atmel_qspi_init(aq); + atmel_qspi_init(aq); + + writel_relaxed(aq->scr, aq->regs + QSPI_SCR); + + return 0; } static SIMPLE_DEV_PM_OPS(atmel_qspi_pm_ops, atmel_qspi_suspend, diff --git a/drivers/spi/spi-at91-usart.c b/drivers/spi/spi-at91-usart.c index f763e14bdf12..a40bb2ef89dc 100644 --- a/drivers/spi/spi-at91-usart.c +++ b/drivers/spi/spi-at91-usart.c @@ -8,9 +8,12 @@ #include <linux/clk.h> #include <linux/delay.h> +#include <linux/dmaengine.h> +#include <linux/dma-direction.h> #include <linux/interrupt.h> #include <linux/kernel.h> #include <linux/module.h> +#include <linux/of_platform.h> #include <linux/of_gpio.h> #include <linux/pinctrl/consumer.h> #include <linux/platform_device.h> @@ -59,6 +62,8 @@ #define US_INIT \ (US_MR_SPI_MASTER | US_MR_CHRL | US_MR_CLKO | US_MR_WRDBT) +#define US_DMA_MIN_BYTES 16 +#define US_DMA_TIMEOUT (msecs_to_jiffies(1000)) /* Register access macros */ #define at91_usart_spi_readl(port, reg) \ @@ -72,14 +77,19 @@ writeb_relaxed((value), (port)->regs + US_##reg) struct at91_usart_spi { + struct platform_device *mpdev; struct spi_transfer *current_transfer; void __iomem *regs; struct device *dev; struct clk *clk; + struct completion xfer_completion; + /*used in interrupt to protect data reading*/ spinlock_t lock; + phys_addr_t phybase; + int irq; unsigned int current_tx_remaining_bytes; unsigned int current_rx_remaining_bytes; @@ -88,8 +98,182 @@ struct at91_usart_spi { u32 status; bool xfer_failed; + bool use_dma; }; +static void dma_callback(void *data) +{ + struct spi_controller *ctlr = data; + struct at91_usart_spi *aus = spi_master_get_devdata(ctlr); + + at91_usart_spi_writel(aus, IER, US_IR_RXRDY); + aus->current_rx_remaining_bytes = 0; + complete(&aus->xfer_completion); +} + +static bool at91_usart_spi_can_dma(struct spi_controller *ctrl, + struct spi_device *spi, + struct spi_transfer *xfer) +{ + struct at91_usart_spi *aus = spi_master_get_devdata(ctrl); + + return aus->use_dma && xfer->len >= US_DMA_MIN_BYTES; +} + +static int at91_usart_spi_configure_dma(struct spi_controller *ctlr, + struct at91_usart_spi *aus) +{ + struct dma_slave_config slave_config; + struct device *dev = &aus->mpdev->dev; + phys_addr_t phybase = aus->phybase; + dma_cap_mask_t mask; + int err = 0; + + dma_cap_zero(mask); + dma_cap_set(DMA_SLAVE, mask); + + ctlr->dma_tx = dma_request_slave_channel_reason(dev, "tx"); + if (IS_ERR_OR_NULL(ctlr->dma_tx)) { + if (IS_ERR(ctlr->dma_tx)) { + err = PTR_ERR(ctlr->dma_tx); + goto at91_usart_spi_error_clear; + } + + dev_dbg(dev, + "DMA TX channel not available, SPI unable to use DMA\n"); + err = -EBUSY; + goto at91_usart_spi_error_clear; + } + + ctlr->dma_rx = dma_request_slave_channel_reason(dev, "rx"); + if (IS_ERR_OR_NULL(ctlr->dma_rx)) { + if (IS_ERR(ctlr->dma_rx)) { + err = PTR_ERR(ctlr->dma_rx); + goto at91_usart_spi_error; + } + + dev_dbg(dev, + "DMA RX channel not available, SPI unable to use DMA\n"); + err = -EBUSY; + goto at91_usart_spi_error; + } + + slave_config.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE; + slave_config.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE; + slave_config.dst_addr = (dma_addr_t)phybase + US_THR; + slave_config.src_addr = (dma_addr_t)phybase + US_RHR; + slave_config.src_maxburst = 1; + slave_config.dst_maxburst = 1; + slave_config.device_fc = false; + + slave_config.direction = DMA_DEV_TO_MEM; + if (dmaengine_slave_config(ctlr->dma_rx, &slave_config)) { + dev_err(&ctlr->dev, + "failed to configure rx dma channel\n"); + err = -EINVAL; + goto at91_usart_spi_error; + } + + slave_config.direction = DMA_MEM_TO_DEV; + if (dmaengine_slave_config(ctlr->dma_tx, &slave_config)) { + dev_err(&ctlr->dev, + "failed to configure tx dma channel\n"); + err = -EINVAL; + goto at91_usart_spi_error; + } + + aus->use_dma = true; + return 0; + +at91_usart_spi_error: + if (!IS_ERR_OR_NULL(ctlr->dma_tx)) + dma_release_channel(ctlr->dma_tx); + if (!IS_ERR_OR_NULL(ctlr->dma_rx)) + dma_release_channel(ctlr->dma_rx); + ctlr->dma_tx = NULL; + ctlr->dma_rx = NULL; + +at91_usart_spi_error_clear: + return err; +} + +static void at91_usart_spi_release_dma(struct spi_controller *ctlr) +{ + if (ctlr->dma_rx) + dma_release_channel(ctlr->dma_rx); + if (ctlr->dma_tx) + dma_release_channel(ctlr->dma_tx); +} + +static void at91_usart_spi_stop_dma(struct spi_controller *ctlr) +{ + if (ctlr->dma_rx) + dmaengine_terminate_all(ctlr->dma_rx); + if (ctlr->dma_tx) + dmaengine_terminate_all(ctlr->dma_tx); +} + +static int at91_usart_spi_dma_transfer(struct spi_controller *ctlr, + struct spi_transfer *xfer) +{ + struct at91_usart_spi *aus = spi_master_get_devdata(ctlr); + struct dma_chan *rxchan = ctlr->dma_rx; + struct dma_chan *txchan = ctlr->dma_tx; + struct dma_async_tx_descriptor *rxdesc; + struct dma_async_tx_descriptor *txdesc; + dma_cookie_t cookie; + + /* Disable RX interrupt */ + at91_usart_spi_writel(aus, IDR, US_IR_RXRDY); + + rxdesc = dmaengine_prep_slave_sg(rxchan, + xfer->rx_sg.sgl, + xfer->rx_sg.nents, + DMA_DEV_TO_MEM, + DMA_PREP_INTERRUPT | + DMA_CTRL_ACK); + if (!rxdesc) + goto at91_usart_spi_err_dma; + + txdesc = dmaengine_prep_slave_sg(txchan, + xfer->tx_sg.sgl, + xfer->tx_sg.nents, + DMA_MEM_TO_DEV, + DMA_PREP_INTERRUPT | + DMA_CTRL_ACK); + if (!txdesc) + goto at91_usart_spi_err_dma; + + rxdesc->callback = dma_callback; + rxdesc->callback_param = ctlr; + + cookie = rxdesc->tx_submit(rxdesc); + if (dma_submit_error(cookie)) + goto at91_usart_spi_err_dma; + + cookie = txdesc->tx_submit(txdesc); + if (dma_submit_error(cookie)) + goto at91_usart_spi_err_dma; + + rxchan->device->device_issue_pending(rxchan); + txchan->device->device_issue_pending(txchan); + + return 0; + +at91_usart_spi_err_dma: + /* Enable RX interrupt if something fails and fallback to PIO */ + at91_usart_spi_writel(aus, IER, US_IR_RXRDY); + at91_usart_spi_stop_dma(ctlr); + + return -ENOMEM; +} + +static unsigned long at91_usart_spi_dma_timeout(struct at91_usart_spi *aus) +{ + return wait_for_completion_timeout(&aus->xfer_completion, + US_DMA_TIMEOUT); +} + static inline u32 at91_usart_spi_tx_ready(struct at91_usart_spi *aus) { return aus->status & US_IR_TXRDY; @@ -216,6 +400,8 @@ static int at91_usart_spi_transfer_one(struct spi_controller *ctlr, struct spi_transfer *xfer) { struct at91_usart_spi *aus = spi_master_get_devdata(ctlr); + unsigned long dma_timeout = 0; + int ret = 0; at91_usart_spi_set_xfer_speed(aus, xfer); aus->xfer_failed = false; @@ -225,8 +411,25 @@ static int at91_usart_spi_transfer_one(struct spi_controller *ctlr, while ((aus->current_tx_remaining_bytes || aus->current_rx_remaining_bytes) && !aus->xfer_failed) { - at91_usart_spi_read_status(aus); - at91_usart_spi_tx(aus); + reinit_completion(&aus->xfer_completion); + if (at91_usart_spi_can_dma(ctlr, spi, xfer) && + !ret) { + ret = at91_usart_spi_dma_transfer(ctlr, xfer); + if (ret) + continue; + + dma_timeout = at91_usart_spi_dma_timeout(aus); + + if (WARN_ON(dma_timeout == 0)) { + dev_err(&spi->dev, "DMA transfer timeout\n"); + return -EIO; + } + aus->current_tx_remaining_bytes = 0; + } else { + at91_usart_spi_read_status(aus); + at91_usart_spi_tx(aus); + } + cpu_relax(); } @@ -345,6 +548,7 @@ static int at91_usart_spi_probe(struct platform_device *pdev) controller->transfer_one = at91_usart_spi_transfer_one; controller->prepare_message = at91_usart_spi_prepare_message; controller->unprepare_message = at91_usart_spi_unprepare_message; + controller->can_dma = at91_usart_spi_can_dma; controller->cleanup = at91_usart_spi_cleanup; controller->max_speed_hz = DIV_ROUND_UP(clk_get_rate(clk), US_MIN_CLK_DIV); @@ -376,7 +580,17 @@ static int at91_usart_spi_probe(struct platform_device *pdev) aus->spi_clk = clk_get_rate(clk); at91_usart_spi_init(aus); + aus->phybase = regs->start; + + aus->mpdev = to_platform_device(pdev->dev.parent); + + ret = at91_usart_spi_configure_dma(controller, aus); + if (ret) + goto at91_usart_fail_dma; + spin_lock_init(&aus->lock); + init_completion(&aus->xfer_completion); + ret = devm_spi_register_master(&pdev->dev, controller); if (ret) goto at91_usart_fail_register_master; @@ -389,6 +603,8 @@ static int at91_usart_spi_probe(struct platform_device *pdev) return 0; at91_usart_fail_register_master: + at91_usart_spi_release_dma(controller); +at91_usart_fail_dma: clk_disable_unprepare(clk); at91_usart_spi_probe_fail: spi_master_put(controller); @@ -453,6 +669,7 @@ static int at91_usart_spi_remove(struct platform_device *pdev) struct spi_controller *ctlr = platform_get_drvdata(pdev); struct at91_usart_spi *aus = spi_master_get_devdata(ctlr); + at91_usart_spi_release_dma(ctlr); clk_disable_unprepare(aus->clk); return 0; diff --git a/drivers/spi/spi-bcm2835.c b/drivers/spi/spi-bcm2835.c index 402c1efcd762..6f243a90c844 100644 --- a/drivers/spi/spi-bcm2835.c +++ b/drivers/spi/spi-bcm2835.c @@ -13,6 +13,7 @@ #include <linux/clk.h> #include <linux/completion.h> +#include <linux/debugfs.h> #include <linux/delay.h> #include <linux/dma-mapping.h> #include <linux/dmaengine.h> @@ -64,14 +65,18 @@ #define BCM2835_SPI_FIFO_SIZE 64 #define BCM2835_SPI_FIFO_SIZE_3_4 48 -#define BCM2835_SPI_POLLING_LIMIT_US 30 -#define BCM2835_SPI_POLLING_JIFFIES 2 #define BCM2835_SPI_DMA_MIN_LENGTH 96 #define BCM2835_SPI_MODE_BITS (SPI_CPOL | SPI_CPHA | SPI_CS_HIGH \ | SPI_NO_CS | SPI_3WIRE) #define DRV_NAME "spi-bcm2835" +/* define polling limits */ +unsigned int polling_limit_us = 30; +module_param(polling_limit_us, uint, 0664); +MODULE_PARM_DESC(polling_limit_us, + "time in us to run a transfer in polling mode\n"); + /** * struct bcm2835_spi - BCM2835 SPI controller * @regs: base address of register map @@ -88,6 +93,15 @@ * length is not a multiple of 4 (to overcome hardware limitation) * @tx_spillover: whether @tx_prologue spills over to second TX sglist entry * @dma_pending: whether a DMA transfer is in progress + * @debugfs_dir: the debugfs directory - neede to remove debugfs when + * unloading the module + * @count_transfer_polling: count of how often polling mode is used + * @count_transfer_irq: count of how often interrupt mode is used + * @count_transfer_irq_after_polling: count of how often we fall back to + * interrupt mode after starting in polling mode. + * These are counted as well in @count_transfer_polling and + * @count_transfer_irq + * @count_transfer_dma: count how often dma mode is used */ struct bcm2835_spi { void __iomem *regs; @@ -102,8 +116,55 @@ struct bcm2835_spi { int rx_prologue; unsigned int tx_spillover; unsigned int dma_pending; + + struct dentry *debugfs_dir; + u64 count_transfer_polling; + u64 count_transfer_irq; + u64 count_transfer_irq_after_polling; + u64 count_transfer_dma; }; +#if defined(CONFIG_DEBUG_FS) +static void bcm2835_debugfs_create(struct bcm2835_spi *bs, + const char *dname) +{ + char name[64]; + struct dentry *dir; + + /* get full name */ + snprintf(name, sizeof(name), "spi-bcm2835-%s", dname); + + /* the base directory */ + dir = debugfs_create_dir(name, NULL); + bs->debugfs_dir = dir; + + /* the counters */ + debugfs_create_u64("count_transfer_polling", 0444, dir, + &bs->count_transfer_polling); + debugfs_create_u64("count_transfer_irq", 0444, dir, + &bs->count_transfer_irq); + debugfs_create_u64("count_transfer_irq_after_polling", 0444, dir, + &bs->count_transfer_irq_after_polling); + debugfs_create_u64("count_transfer_dma", 0444, dir, + &bs->count_transfer_dma); +} + +static void bcm2835_debugfs_remove(struct bcm2835_spi *bs) +{ + debugfs_remove_recursive(bs->debugfs_dir); + bs->debugfs_dir = NULL; +} +#else +static void bcm2835_debugfs_create(struct bcm2835_spi *bs, + const char *dname) +{ +} + +static void bcm2835_debugfs_remove(struct bcm2835_spi *bs) +{ +} +#endif /* CONFIG_DEBUG_FS */ + static inline u32 bcm2835_rd(struct bcm2835_spi *bs, unsigned reg) { return readl(bs->regs + reg); @@ -248,9 +309,9 @@ static inline void bcm2835_wr_fifo_blind(struct bcm2835_spi *bs, int count) } } -static void bcm2835_spi_reset_hw(struct spi_master *master) +static void bcm2835_spi_reset_hw(struct spi_controller *ctlr) { - struct bcm2835_spi *bs = spi_master_get_devdata(master); + struct bcm2835_spi *bs = spi_controller_get_devdata(ctlr); u32 cs = bcm2835_rd(bs, BCM2835_SPI_CS); /* Disable SPI interrupts and transfer */ @@ -269,8 +330,8 @@ static void bcm2835_spi_reset_hw(struct spi_master *master) static irqreturn_t bcm2835_spi_interrupt(int irq, void *dev_id) { - struct spi_master *master = dev_id; - struct bcm2835_spi *bs = spi_master_get_devdata(master); + struct spi_controller *ctlr = dev_id; + struct bcm2835_spi *bs = spi_controller_get_devdata(ctlr); u32 cs = bcm2835_rd(bs, BCM2835_SPI_CS); /* @@ -292,20 +353,23 @@ static irqreturn_t bcm2835_spi_interrupt(int irq, void *dev_id) if (!bs->rx_len) { /* Transfer complete - reset SPI HW */ - bcm2835_spi_reset_hw(master); + bcm2835_spi_reset_hw(ctlr); /* wake up the framework */ - complete(&master->xfer_completion); + complete(&ctlr->xfer_completion); } return IRQ_HANDLED; } -static int bcm2835_spi_transfer_one_irq(struct spi_master *master, +static int bcm2835_spi_transfer_one_irq(struct spi_controller *ctlr, struct spi_device *spi, struct spi_transfer *tfr, u32 cs, bool fifo_empty) { - struct bcm2835_spi *bs = spi_master_get_devdata(master); + struct bcm2835_spi *bs = spi_controller_get_devdata(ctlr); + + /* update usage statistics */ + bs->count_transfer_irq++; /* * Enable HW block, but with interrupts still disabled. @@ -328,7 +392,7 @@ static int bcm2835_spi_transfer_one_irq(struct spi_master *master, /** * bcm2835_spi_transfer_prologue() - transfer first few bytes without DMA - * @master: SPI master + * @ctlr: SPI master controller * @tfr: SPI transfer * @bs: BCM2835 SPI controller * @cs: CS register @@ -372,7 +436,7 @@ static int bcm2835_spi_transfer_one_irq(struct spi_master *master, * be transmitted in 32-bit width to ensure that the following DMA transfer can * pick up the residue in the RX FIFO in ungarbled form. */ -static void bcm2835_spi_transfer_prologue(struct spi_master *master, +static void bcm2835_spi_transfer_prologue(struct spi_controller *ctlr, struct spi_transfer *tfr, struct bcm2835_spi *bs, u32 cs) @@ -413,9 +477,9 @@ static void bcm2835_spi_transfer_prologue(struct spi_master *master, bcm2835_wr_fifo_count(bs, bs->rx_prologue); bcm2835_wait_tx_fifo_empty(bs); bcm2835_rd_fifo_count(bs, bs->rx_prologue); - bcm2835_spi_reset_hw(master); + bcm2835_spi_reset_hw(ctlr); - dma_sync_single_for_device(master->dma_rx->device->dev, + dma_sync_single_for_device(ctlr->dma_rx->device->dev, sg_dma_address(&tfr->rx_sg.sgl[0]), bs->rx_prologue, DMA_FROM_DEVICE); @@ -479,11 +543,11 @@ static void bcm2835_spi_undo_prologue(struct bcm2835_spi *bs) static void bcm2835_spi_dma_done(void *data) { - struct spi_master *master = data; - struct bcm2835_spi *bs = spi_master_get_devdata(master); + struct spi_controller *ctlr = data; + struct bcm2835_spi *bs = spi_controller_get_devdata(ctlr); /* reset fifo and HW */ - bcm2835_spi_reset_hw(master); + bcm2835_spi_reset_hw(ctlr); /* and terminate tx-dma as we do not have an irq for it * because when the rx dma will terminate and this callback @@ -491,15 +555,15 @@ static void bcm2835_spi_dma_done(void *data) * situation otherwise... */ if (cmpxchg(&bs->dma_pending, true, false)) { - dmaengine_terminate_async(master->dma_tx); + dmaengine_terminate_async(ctlr->dma_tx); bcm2835_spi_undo_prologue(bs); } /* and mark as completed */; - complete(&master->xfer_completion); + complete(&ctlr->xfer_completion); } -static int bcm2835_spi_prepare_sg(struct spi_master *master, +static int bcm2835_spi_prepare_sg(struct spi_controller *ctlr, struct spi_transfer *tfr, bool is_tx) { @@ -514,14 +578,14 @@ static int bcm2835_spi_prepare_sg(struct spi_master *master, if (is_tx) { dir = DMA_MEM_TO_DEV; - chan = master->dma_tx; + chan = ctlr->dma_tx; nents = tfr->tx_sg.nents; sgl = tfr->tx_sg.sgl; flags = 0 /* no tx interrupt */; } else { dir = DMA_DEV_TO_MEM; - chan = master->dma_rx; + chan = ctlr->dma_rx; nents = tfr->rx_sg.nents; sgl = tfr->rx_sg.sgl; flags = DMA_PREP_INTERRUPT; @@ -534,7 +598,7 @@ static int bcm2835_spi_prepare_sg(struct spi_master *master, /* set callback for rx */ if (!is_tx) { desc->callback = bcm2835_spi_dma_done; - desc->callback_param = master; + desc->callback_param = ctlr; } /* submit it to DMA-engine */ @@ -543,27 +607,30 @@ static int bcm2835_spi_prepare_sg(struct spi_master *master, return dma_submit_error(cookie); } -static int bcm2835_spi_transfer_one_dma(struct spi_master *master, +static int bcm2835_spi_transfer_one_dma(struct spi_controller *ctlr, struct spi_device *spi, struct spi_transfer *tfr, u32 cs) { - struct bcm2835_spi *bs = spi_master_get_devdata(master); + struct bcm2835_spi *bs = spi_controller_get_devdata(ctlr); int ret; + /* update usage statistics */ + bs->count_transfer_dma++; + /* * Transfer first few bytes without DMA if length of first TX or RX * sglist entry is not a multiple of 4 bytes (hardware limitation). */ - bcm2835_spi_transfer_prologue(master, tfr, bs, cs); + bcm2835_spi_transfer_prologue(ctlr, tfr, bs, cs); /* setup tx-DMA */ - ret = bcm2835_spi_prepare_sg(master, tfr, true); + ret = bcm2835_spi_prepare_sg(ctlr, tfr, true); if (ret) goto err_reset_hw; /* start TX early */ - dma_async_issue_pending(master->dma_tx); + dma_async_issue_pending(ctlr->dma_tx); /* mark as dma pending */ bs->dma_pending = 1; @@ -579,27 +646,27 @@ static int bcm2835_spi_transfer_one_dma(struct spi_master *master, * mapping of the rx buffers still takes place * this saves 10us or more. */ - ret = bcm2835_spi_prepare_sg(master, tfr, false); + ret = bcm2835_spi_prepare_sg(ctlr, tfr, false); if (ret) { /* need to reset on errors */ - dmaengine_terminate_sync(master->dma_tx); + dmaengine_terminate_sync(ctlr->dma_tx); bs->dma_pending = false; goto err_reset_hw; } /* start rx dma late */ - dma_async_issue_pending(master->dma_rx); + dma_async_issue_pending(ctlr->dma_rx); /* wait for wakeup in framework */ return 1; err_reset_hw: - bcm2835_spi_reset_hw(master); + bcm2835_spi_reset_hw(ctlr); bcm2835_spi_undo_prologue(bs); return ret; } -static bool bcm2835_spi_can_dma(struct spi_master *master, +static bool bcm2835_spi_can_dma(struct spi_controller *ctlr, struct spi_device *spi, struct spi_transfer *tfr) { @@ -611,21 +678,21 @@ static bool bcm2835_spi_can_dma(struct spi_master *master, return true; } -static void bcm2835_dma_release(struct spi_master *master) +static void bcm2835_dma_release(struct spi_controller *ctlr) { - if (master->dma_tx) { - dmaengine_terminate_sync(master->dma_tx); - dma_release_channel(master->dma_tx); - master->dma_tx = NULL; + if (ctlr->dma_tx) { + dmaengine_terminate_sync(ctlr->dma_tx); + dma_release_channel(ctlr->dma_tx); + ctlr->dma_tx = NULL; } - if (master->dma_rx) { - dmaengine_terminate_sync(master->dma_rx); - dma_release_channel(master->dma_rx); - master->dma_rx = NULL; + if (ctlr->dma_rx) { + dmaengine_terminate_sync(ctlr->dma_rx); + dma_release_channel(ctlr->dma_rx); + ctlr->dma_rx = NULL; } } -static void bcm2835_dma_init(struct spi_master *master, struct device *dev) +static void bcm2835_dma_init(struct spi_controller *ctlr, struct device *dev) { struct dma_slave_config slave_config; const __be32 *addr; @@ -633,7 +700,7 @@ static void bcm2835_dma_init(struct spi_master *master, struct device *dev) int ret; /* base address in dma-space */ - addr = of_get_address(master->dev.of_node, 0, NULL, NULL); + addr = of_get_address(ctlr->dev.of_node, 0, NULL, NULL); if (!addr) { dev_err(dev, "could not get DMA-register address - not using dma mode\n"); goto err; @@ -641,38 +708,36 @@ static void bcm2835_dma_init(struct spi_master *master, struct device *dev) dma_reg_base = be32_to_cpup(addr); /* get tx/rx dma */ - master->dma_tx = dma_request_slave_channel(dev, "tx"); - if (!master->dma_tx) { + ctlr->dma_tx = dma_request_slave_channel(dev, "tx"); + if (!ctlr->dma_tx) { dev_err(dev, "no tx-dma configuration found - not using dma mode\n"); goto err; } - master->dma_rx = dma_request_slave_channel(dev, "rx"); - if (!master->dma_rx) { + ctlr->dma_rx = dma_request_slave_channel(dev, "rx"); + if (!ctlr->dma_rx) { dev_err(dev, "no rx-dma configuration found - not using dma mode\n"); goto err_release; } /* configure DMAs */ - slave_config.direction = DMA_MEM_TO_DEV; slave_config.dst_addr = (u32)(dma_reg_base + BCM2835_SPI_FIFO); slave_config.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; - ret = dmaengine_slave_config(master->dma_tx, &slave_config); + ret = dmaengine_slave_config(ctlr->dma_tx, &slave_config); if (ret) goto err_config; - slave_config.direction = DMA_DEV_TO_MEM; slave_config.src_addr = (u32)(dma_reg_base + BCM2835_SPI_FIFO); slave_config.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; - ret = dmaengine_slave_config(master->dma_rx, &slave_config); + ret = dmaengine_slave_config(ctlr->dma_rx, &slave_config); if (ret) goto err_config; /* all went well, so set can_dma */ - master->can_dma = bcm2835_spi_can_dma; + ctlr->can_dma = bcm2835_spi_can_dma; /* need to do TX AND RX DMA, so we need dummy buffers */ - master->flags = SPI_MASTER_MUST_RX | SPI_MASTER_MUST_TX; + ctlr->flags = SPI_CONTROLLER_MUST_RX | SPI_CONTROLLER_MUST_TX; return; @@ -680,20 +745,22 @@ err_config: dev_err(dev, "issue configuring dma: %d - not using DMA mode\n", ret); err_release: - bcm2835_dma_release(master); + bcm2835_dma_release(ctlr); err: return; } -static int bcm2835_spi_transfer_one_poll(struct spi_master *master, +static int bcm2835_spi_transfer_one_poll(struct spi_controller *ctlr, struct spi_device *spi, struct spi_transfer *tfr, - u32 cs, - unsigned long long xfer_time_us) + u32 cs) { - struct bcm2835_spi *bs = spi_master_get_devdata(master); + struct bcm2835_spi *bs = spi_controller_get_devdata(ctlr); unsigned long timeout; + /* update usage statistics */ + bs->count_transfer_polling++; + /* enable HW block without interrupts */ bcm2835_wr(bs, BCM2835_SPI_CS, cs | BCM2835_SPI_CS_TA); @@ -703,8 +770,8 @@ static int bcm2835_spi_transfer_one_poll(struct spi_master *master, */ bcm2835_wr_fifo_blind(bs, BCM2835_SPI_FIFO_SIZE); - /* set the timeout */ - timeout = jiffies + BCM2835_SPI_POLLING_JIFFIES; + /* set the timeout to at least 2 jiffies */ + timeout = jiffies + 2 + HZ * polling_limit_us / 1000000; /* loop until finished the transfer */ while (bs->rx_len) { @@ -723,25 +790,28 @@ static int bcm2835_spi_transfer_one_poll(struct spi_master *master, jiffies - timeout, bs->tx_len, bs->rx_len); /* fall back to interrupt mode */ - return bcm2835_spi_transfer_one_irq(master, spi, + + /* update usage statistics */ + bs->count_transfer_irq_after_polling++; + + return bcm2835_spi_transfer_one_irq(ctlr, spi, tfr, cs, false); } } /* Transfer complete - reset SPI HW */ - bcm2835_spi_reset_hw(master); + bcm2835_spi_reset_hw(ctlr); /* and return without waiting for completion */ return 0; } -static int bcm2835_spi_transfer_one(struct spi_master *master, +static int bcm2835_spi_transfer_one(struct spi_controller *ctlr, struct spi_device *spi, struct spi_transfer *tfr) { - struct bcm2835_spi *bs = spi_master_get_devdata(master); - unsigned long spi_hz, clk_hz, cdiv; - unsigned long spi_used_hz; - unsigned long long xfer_time_us; + struct bcm2835_spi *bs = spi_controller_get_devdata(ctlr); + unsigned long spi_hz, clk_hz, cdiv, spi_used_hz; + unsigned long hz_per_byte, byte_limit; u32 cs = bcm2835_rd(bs, BCM2835_SPI_CS); /* set clock */ @@ -782,42 +852,49 @@ static int bcm2835_spi_transfer_one(struct spi_master *master, bs->tx_len = tfr->len; bs->rx_len = tfr->len; - /* calculate the estimated time in us the transfer runs */ - xfer_time_us = (unsigned long long)tfr->len - * 9 /* clocks/byte - SPI-HW waits 1 clock after each byte */ - * 1000000; - do_div(xfer_time_us, spi_used_hz); + /* Calculate the estimated time in us the transfer runs. Note that + * there is 1 idle clocks cycles after each byte getting transferred + * so we have 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 us + * per 300,000 Hz of bus clock. + */ + hz_per_byte = polling_limit_us ? (9 * 1000000) / polling_limit_us : 0; + byte_limit = hz_per_byte ? spi_used_hz / hz_per_byte : 1; - /* for short requests run polling*/ - if (xfer_time_us <= BCM2835_SPI_POLLING_LIMIT_US) - return bcm2835_spi_transfer_one_poll(master, spi, tfr, - cs, xfer_time_us); + /* run in polling mode for short transfers */ + if (tfr->len < byte_limit) + return bcm2835_spi_transfer_one_poll(ctlr, spi, tfr, cs); - /* run in dma mode if conditions are right */ - if (master->can_dma && bcm2835_spi_can_dma(master, spi, tfr)) - return bcm2835_spi_transfer_one_dma(master, spi, tfr, cs); + /* run in dma mode if conditions are right + * Note that unlike poll or interrupt mode DMA mode does not have + * this 1 idle clock cycle pattern but runs the spi clock without gaps + */ + if (ctlr->can_dma && bcm2835_spi_can_dma(ctlr, spi, tfr)) + return bcm2835_spi_transfer_one_dma(ctlr, spi, tfr, cs); /* run in interrupt-mode */ - return bcm2835_spi_transfer_one_irq(master, spi, tfr, cs, true); + return bcm2835_spi_transfer_one_irq(ctlr, spi, tfr, cs, true); } -static int bcm2835_spi_prepare_message(struct spi_master *master, +static int bcm2835_spi_prepare_message(struct spi_controller *ctlr, struct spi_message *msg) { struct spi_device *spi = msg->spi; - struct bcm2835_spi *bs = spi_master_get_devdata(master); + struct bcm2835_spi *bs = spi_controller_get_devdata(ctlr); u32 cs = bcm2835_rd(bs, BCM2835_SPI_CS); int ret; - /* - * DMA transfers are limited to 16 bit (0 to 65535 bytes) by the SPI HW - * due to DLEN. Split up transfers (32-bit FIFO aligned) if the limit is - * exceeded. - */ - ret = spi_split_transfers_maxsize(master, msg, 65532, - GFP_KERNEL | GFP_DMA); - if (ret) - return ret; + if (ctlr->can_dma) { + /* + * DMA transfers are limited to 16 bit (0 to 65535 bytes) by + * the SPI HW due to DLEN. Split up transfers (32-bit FIFO + * aligned) if the limit is exceeded. + */ + ret = spi_split_transfers_maxsize(ctlr, msg, 65532, + GFP_KERNEL | GFP_DMA); + if (ret) + return ret; + } cs &= ~(BCM2835_SPI_CS_CPOL | BCM2835_SPI_CS_CPHA); @@ -831,19 +908,19 @@ static int bcm2835_spi_prepare_message(struct spi_master *master, return 0; } -static void bcm2835_spi_handle_err(struct spi_master *master, +static void bcm2835_spi_handle_err(struct spi_controller *ctlr, struct spi_message *msg) { - struct bcm2835_spi *bs = spi_master_get_devdata(master); + struct bcm2835_spi *bs = spi_controller_get_devdata(ctlr); /* if an error occurred and we have an active dma, then terminate */ if (cmpxchg(&bs->dma_pending, true, false)) { - dmaengine_terminate_sync(master->dma_tx); - dmaengine_terminate_sync(master->dma_rx); + dmaengine_terminate_sync(ctlr->dma_tx); + dmaengine_terminate_sync(ctlr->dma_rx); bcm2835_spi_undo_prologue(bs); } /* and reset */ - bcm2835_spi_reset_hw(master); + bcm2835_spi_reset_hw(ctlr); } static int chip_match_name(struct gpio_chip *chip, void *data) @@ -900,85 +977,88 @@ static int bcm2835_spi_setup(struct spi_device *spi) static int bcm2835_spi_probe(struct platform_device *pdev) { - struct spi_master *master; + struct spi_controller *ctlr; struct bcm2835_spi *bs; struct resource *res; int err; - master = spi_alloc_master(&pdev->dev, sizeof(*bs)); - if (!master) { - dev_err(&pdev->dev, "spi_alloc_master() failed\n"); + ctlr = spi_alloc_master(&pdev->dev, sizeof(*bs)); + if (!ctlr) return -ENOMEM; - } - platform_set_drvdata(pdev, master); + platform_set_drvdata(pdev, ctlr); - master->mode_bits = BCM2835_SPI_MODE_BITS; - master->bits_per_word_mask = SPI_BPW_MASK(8); - master->num_chipselect = 3; - master->setup = bcm2835_spi_setup; - master->transfer_one = bcm2835_spi_transfer_one; - master->handle_err = bcm2835_spi_handle_err; - master->prepare_message = bcm2835_spi_prepare_message; - master->dev.of_node = pdev->dev.of_node; + ctlr->mode_bits = BCM2835_SPI_MODE_BITS; + ctlr->bits_per_word_mask = SPI_BPW_MASK(8); + ctlr->num_chipselect = 3; + ctlr->setup = bcm2835_spi_setup; + ctlr->transfer_one = bcm2835_spi_transfer_one; + ctlr->handle_err = bcm2835_spi_handle_err; + ctlr->prepare_message = bcm2835_spi_prepare_message; + ctlr->dev.of_node = pdev->dev.of_node; - bs = spi_master_get_devdata(master); + bs = spi_controller_get_devdata(ctlr); res = platform_get_resource(pdev, IORESOURCE_MEM, 0); bs->regs = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(bs->regs)) { err = PTR_ERR(bs->regs); - goto out_master_put; + goto out_controller_put; } bs->clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(bs->clk)) { err = PTR_ERR(bs->clk); dev_err(&pdev->dev, "could not get clk: %d\n", err); - goto out_master_put; + goto out_controller_put; } bs->irq = platform_get_irq(pdev, 0); if (bs->irq <= 0) { dev_err(&pdev->dev, "could not get IRQ: %d\n", bs->irq); err = bs->irq ? bs->irq : -ENODEV; - goto out_master_put; + goto out_controller_put; } clk_prepare_enable(bs->clk); - bcm2835_dma_init(master, &pdev->dev); + bcm2835_dma_init(ctlr, &pdev->dev); /* initialise the hardware with the default polarities */ bcm2835_wr(bs, BCM2835_SPI_CS, BCM2835_SPI_CS_CLEAR_RX | BCM2835_SPI_CS_CLEAR_TX); err = devm_request_irq(&pdev->dev, bs->irq, bcm2835_spi_interrupt, 0, - dev_name(&pdev->dev), master); + dev_name(&pdev->dev), ctlr); if (err) { dev_err(&pdev->dev, "could not request IRQ: %d\n", err); goto out_clk_disable; } - err = devm_spi_register_master(&pdev->dev, master); + err = devm_spi_register_controller(&pdev->dev, ctlr); if (err) { - dev_err(&pdev->dev, "could not register SPI master: %d\n", err); + dev_err(&pdev->dev, "could not register SPI controller: %d\n", + err); goto out_clk_disable; } + bcm2835_debugfs_create(bs, dev_name(&pdev->dev)); + return 0; out_clk_disable: clk_disable_unprepare(bs->clk); -out_master_put: - spi_master_put(master); +out_controller_put: + spi_controller_put(ctlr); return err; } static int bcm2835_spi_remove(struct platform_device *pdev) { - struct spi_master *master = platform_get_drvdata(pdev); - struct bcm2835_spi *bs = spi_master_get_devdata(master); + struct spi_controller *ctlr = platform_get_drvdata(pdev); + struct bcm2835_spi *bs = spi_controller_get_devdata(ctlr); + + bcm2835_debugfs_remove(bs); /* Clear FIFOs, and disable the HW block */ bcm2835_wr(bs, BCM2835_SPI_CS, @@ -986,7 +1066,7 @@ static int bcm2835_spi_remove(struct platform_device *pdev) clk_disable_unprepare(bs->clk); - bcm2835_dma_release(master); + bcm2835_dma_release(ctlr); return 0; } diff --git a/drivers/spi/spi-bcm2835aux.c b/drivers/spi/spi-bcm2835aux.c index 40dfb7f58efe..bb57035c5770 100644 --- a/drivers/spi/spi-bcm2835aux.c +++ b/drivers/spi/spi-bcm2835aux.c @@ -496,10 +496,8 @@ static int bcm2835aux_spi_probe(struct platform_device *pdev) int err; master = spi_alloc_master(&pdev->dev, sizeof(*bs)); - if (!master) { - dev_err(&pdev->dev, "spi_alloc_master() failed\n"); + if (!master) return -ENOMEM; - } platform_set_drvdata(pdev, master); master->mode_bits = (SPI_CPOL | SPI_CS_HIGH | SPI_NO_CS); diff --git a/drivers/spi/spi-meson-spifc.c b/drivers/spi/spi-meson-spifc.c index ea4b1bf0fa16..f7fe9b13d122 100644 --- a/drivers/spi/spi-meson-spifc.c +++ b/drivers/spi/spi-meson-spifc.c @@ -1,9 +1,9 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Driver for Amlogic Meson SPI flash controller (SPIFC) - * - * Copyright (C) 2014 Beniamino Galvani <b.galvani@gmail.com> - */ +// SPDX-License-Identifier: GPL-2.0+ +// +// Driver for Amlogic Meson SPI flash controller (SPIFC) +// +// Copyright (C) 2014 Beniamino Galvani <b.galvani@gmail.com> +// #include <linux/clk.h> #include <linux/delay.h> diff --git a/drivers/spi/spi-mt65xx.c b/drivers/spi/spi-mt65xx.c index 10041eab36a2..45d8a7048b6c 100644 --- a/drivers/spi/spi-mt65xx.c +++ b/drivers/spi/spi-mt65xx.c @@ -123,8 +123,6 @@ static const struct mtk_spi_compatible mt8183_compat = { * supplies it. */ static const struct mtk_chip_config mtk_default_chip_info = { - .rx_mlsb = 1, - .tx_mlsb = 1, .cs_pol = 0, .sample_sel = 0, }; @@ -195,14 +193,13 @@ static int mtk_spi_prepare_message(struct spi_master *master, reg_val &= ~SPI_CMD_CPOL; /* set the mlsbx and mlsbtx */ - if (chip_config->tx_mlsb) - reg_val |= SPI_CMD_TXMSBF; - else + if (spi->mode & SPI_LSB_FIRST) { reg_val &= ~SPI_CMD_TXMSBF; - if (chip_config->rx_mlsb) - reg_val |= SPI_CMD_RXMSBF; - else reg_val &= ~SPI_CMD_RXMSBF; + } else { + reg_val |= SPI_CMD_TXMSBF; + reg_val |= SPI_CMD_RXMSBF; + } /* set the tx/rx endian */ #ifdef __LITTLE_ENDIAN @@ -599,7 +596,7 @@ static int mtk_spi_probe(struct platform_device *pdev) master->auto_runtime_pm = true; master->dev.of_node = pdev->dev.of_node; - master->mode_bits = SPI_CPOL | SPI_CPHA; + master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST; master->set_cs = mtk_spi_set_cs; master->prepare_message = mtk_spi_prepare_message; diff --git a/drivers/spi/spi-pxa2xx.c b/drivers/spi/spi-pxa2xx.c index af3f37ba82c8..fc7ab4b26880 100644 --- a/drivers/spi/spi-pxa2xx.c +++ b/drivers/spi/spi-pxa2xx.c @@ -1437,6 +1437,10 @@ static const struct pci_device_id pxa2xx_spi_pci_compound_match[] = { { PCI_VDEVICE(INTEL, 0x34aa), LPSS_CNL_SSP }, { PCI_VDEVICE(INTEL, 0x34ab), LPSS_CNL_SSP }, { PCI_VDEVICE(INTEL, 0x34fb), LPSS_CNL_SSP }, + /* EHL */ + { PCI_VDEVICE(INTEL, 0x4b2a), LPSS_BXT_SSP }, + { PCI_VDEVICE(INTEL, 0x4b2b), LPSS_BXT_SSP }, + { PCI_VDEVICE(INTEL, 0x4b37), LPSS_BXT_SSP }, /* APL */ { PCI_VDEVICE(INTEL, 0x5ac2), LPSS_BXT_SSP }, { PCI_VDEVICE(INTEL, 0x5ac4), LPSS_BXT_SSP }, @@ -1704,6 +1708,16 @@ static int pxa2xx_spi_probe(struct platform_device *pdev) goto out_error_dma_irq_alloc; controller->max_speed_hz = clk_get_rate(ssp->clk); + /* + * Set minimum speed for all other platforms than Intel Quark which is + * able do under 1 Hz transfers. + */ + if (!pxa25x_ssp_comp(drv_data)) + controller->min_speed_hz = + DIV_ROUND_UP(controller->max_speed_hz, 4096); + else if (!is_quark_x1000_ssp(drv_data)) + controller->min_speed_hz = + DIV_ROUND_UP(controller->max_speed_hz, 512); /* Load default SSP configuration */ pxa2xx_spi_write(drv_data, SSCR0, 0); diff --git a/drivers/spi/spi-qup.c b/drivers/spi/spi-qup.c index eb8a6a2e91c9..2f559e531100 100644 --- a/drivers/spi/spi-qup.c +++ b/drivers/spi/spi-qup.c @@ -873,10 +873,6 @@ static int spi_qup_transfer_one(struct spi_master *master, else ret = spi_qup_do_pio(spi, xfer, timeout); - if (ret) - goto exit; - -exit: spi_qup_set_state(controller, QUP_STATE_RESET); spin_lock_irqsave(&controller->lock, flags); if (!ret) diff --git a/drivers/spi/spi-rockchip.c b/drivers/spi/spi-rockchip.c index 9b91188a85f9..2cc6d9951b52 100644 --- a/drivers/spi/spi-rockchip.c +++ b/drivers/spi/spi-rockchip.c @@ -417,7 +417,7 @@ static int rockchip_spi_prepare_dma(struct rockchip_spi *rs, .direction = DMA_MEM_TO_DEV, .dst_addr = rs->dma_addr_tx, .dst_addr_width = rs->n_bytes, - .dst_maxburst = rs->fifo_len / 2, + .dst_maxburst = rs->fifo_len / 4, }; dmaengine_slave_config(master->dma_tx, &txconf); @@ -518,7 +518,7 @@ static void rockchip_spi_config(struct rockchip_spi *rs, else writel_relaxed(rs->fifo_len / 2 - 1, rs->regs + ROCKCHIP_SPI_RXFTLR); - writel_relaxed(rs->fifo_len / 2 - 1, rs->regs + ROCKCHIP_SPI_DMATDLR); + writel_relaxed(rs->fifo_len / 2, rs->regs + ROCKCHIP_SPI_DMATDLR); writel_relaxed(0, rs->regs + ROCKCHIP_SPI_DMARDLR); writel_relaxed(dmacr, rs->regs + ROCKCHIP_SPI_DMACR); diff --git a/drivers/spi/spi-sh-msiof.c b/drivers/spi/spi-sh-msiof.c index 6aab7b2136db..b50bdbc27e58 100644 --- a/drivers/spi/spi-sh-msiof.c +++ b/drivers/spi/spi-sh-msiof.c @@ -229,7 +229,7 @@ static int sh_msiof_modify_ctr_wait(struct sh_msiof_spi_priv *p, sh_msiof_write(p, CTR, data); return readl_poll_timeout_atomic(p->mapbase + CTR, data, - (data & mask) == set, 10, 1000); + (data & mask) == set, 1, 100); } static irqreturn_t sh_msiof_spi_irq(int irq, void *data) diff --git a/drivers/spi/spi-stm32-qspi.c b/drivers/spi/spi-stm32-qspi.c index 5dbb6a8e893c..655e4afbfb2a 100644 --- a/drivers/spi/spi-stm32-qspi.c +++ b/drivers/spi/spi-stm32-qspi.c @@ -245,12 +245,8 @@ static int stm32_qspi_tx_dma(struct stm32_qspi *qspi, writel_relaxed(cr | CR_DMAEN, qspi->io_base + QSPI_CR); t_out = sgt.nents * STM32_COMP_TIMEOUT_MS; - if (!wait_for_completion_interruptible_timeout(&qspi->dma_completion, - msecs_to_jiffies(t_out))) - err = -ETIMEDOUT; - - if (dma_async_is_tx_complete(dma_ch, cookie, - NULL, NULL) != DMA_COMPLETE) + if (!wait_for_completion_timeout(&qspi->dma_completion, + msecs_to_jiffies(t_out))) err = -ETIMEDOUT; if (err) @@ -304,7 +300,7 @@ static int stm32_qspi_wait_cmd(struct stm32_qspi *qspi, cr = readl_relaxed(qspi->io_base + QSPI_CR); writel_relaxed(cr | CR_TCIE | CR_TEIE, qspi->io_base + QSPI_CR); - if (!wait_for_completion_interruptible_timeout(&qspi->data_completion, + if (!wait_for_completion_timeout(&qspi->data_completion, msecs_to_jiffies(STM32_COMP_TIMEOUT_MS))) { err = -ETIMEDOUT; } else { diff --git a/drivers/spi/spi-synquacer.c b/drivers/spi/spi-synquacer.c new file mode 100644 index 000000000000..f99abd85c50a --- /dev/null +++ b/drivers/spi/spi-synquacer.c @@ -0,0 +1,828 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Synquacer HSSPI controller driver +// +// Copyright (c) 2015-2018 Socionext Inc. +// Copyright (c) 2018-2019 Linaro Ltd. +// + +#include <linux/acpi.h> +#include <linux/delay.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/platform_device.h> +#include <linux/pm_runtime.h> +#include <linux/scatterlist.h> +#include <linux/slab.h> +#include <linux/spi/spi.h> +#include <linux/spinlock.h> +#include <linux/clk.h> + +/* HSSPI register address definitions */ +#define SYNQUACER_HSSPI_REG_MCTRL 0x00 +#define SYNQUACER_HSSPI_REG_PCC0 0x04 +#define SYNQUACER_HSSPI_REG_PCC(n) (SYNQUACER_HSSPI_REG_PCC0 + (n) * 4) +#define SYNQUACER_HSSPI_REG_TXF 0x14 +#define SYNQUACER_HSSPI_REG_TXE 0x18 +#define SYNQUACER_HSSPI_REG_TXC 0x1C +#define SYNQUACER_HSSPI_REG_RXF 0x20 +#define SYNQUACER_HSSPI_REG_RXE 0x24 +#define SYNQUACER_HSSPI_REG_RXC 0x28 +#define SYNQUACER_HSSPI_REG_FAULTF 0x2C +#define SYNQUACER_HSSPI_REG_FAULTC 0x30 +#define SYNQUACER_HSSPI_REG_DMCFG 0x34 +#define SYNQUACER_HSSPI_REG_DMSTART 0x38 +#define SYNQUACER_HSSPI_REG_DMBCC 0x3C +#define SYNQUACER_HSSPI_REG_DMSTATUS 0x40 +#define SYNQUACER_HSSPI_REG_FIFOCFG 0x4C +#define SYNQUACER_HSSPI_REG_TX_FIFO 0x50 +#define SYNQUACER_HSSPI_REG_RX_FIFO 0x90 +#define SYNQUACER_HSSPI_REG_MID 0xFC + +/* HSSPI register bit definitions */ +#define SYNQUACER_HSSPI_MCTRL_MEN BIT(0) +#define SYNQUACER_HSSPI_MCTRL_COMMAND_SEQUENCE_EN BIT(1) +#define SYNQUACER_HSSPI_MCTRL_CDSS BIT(3) +#define SYNQUACER_HSSPI_MCTRL_MES BIT(4) +#define SYNQUACER_HSSPI_MCTRL_SYNCON BIT(5) + +#define SYNQUACER_HSSPI_PCC_CPHA BIT(0) +#define SYNQUACER_HSSPI_PCC_CPOL BIT(1) +#define SYNQUACER_HSSPI_PCC_ACES BIT(2) +#define SYNQUACER_HSSPI_PCC_RTM BIT(3) +#define SYNQUACER_HSSPI_PCC_SSPOL BIT(4) +#define SYNQUACER_HSSPI_PCC_SDIR BIT(7) +#define SYNQUACER_HSSPI_PCC_SENDIAN BIT(8) +#define SYNQUACER_HSSPI_PCC_SAFESYNC BIT(16) +#define SYNQUACER_HSSPI_PCC_SS2CD_SHIFT 5U +#define SYNQUACER_HSSPI_PCC_CDRS_MASK 0x7f +#define SYNQUACER_HSSPI_PCC_CDRS_SHIFT 9U + +#define SYNQUACER_HSSPI_TXF_FIFO_FULL BIT(0) +#define SYNQUACER_HSSPI_TXF_FIFO_EMPTY BIT(1) +#define SYNQUACER_HSSPI_TXF_SLAVE_RELEASED BIT(6) + +#define SYNQUACER_HSSPI_TXE_FIFO_FULL BIT(0) +#define SYNQUACER_HSSPI_TXE_FIFO_EMPTY BIT(1) +#define SYNQUACER_HSSPI_TXE_SLAVE_RELEASED BIT(6) + +#define SYNQUACER_HSSPI_RXF_FIFO_MORE_THAN_THRESHOLD BIT(5) +#define SYNQUACER_HSSPI_RXF_SLAVE_RELEASED BIT(6) + +#define SYNQUACER_HSSPI_RXE_FIFO_MORE_THAN_THRESHOLD BIT(5) +#define SYNQUACER_HSSPI_RXE_SLAVE_RELEASED BIT(6) + +#define SYNQUACER_HSSPI_DMCFG_SSDC BIT(1) +#define SYNQUACER_HSSPI_DMCFG_MSTARTEN BIT(2) + +#define SYNQUACER_HSSPI_DMSTART_START BIT(0) +#define SYNQUACER_HSSPI_DMSTOP_STOP BIT(8) +#define SYNQUACER_HSSPI_DMPSEL_CS_MASK 0x3 +#define SYNQUACER_HSSPI_DMPSEL_CS_SHIFT 16U +#define SYNQUACER_HSSPI_DMTRP_BUS_WIDTH_SHIFT 24U +#define SYNQUACER_HSSPI_DMTRP_DATA_MASK 0x3 +#define SYNQUACER_HSSPI_DMTRP_DATA_SHIFT 26U +#define SYNQUACER_HSSPI_DMTRP_DATA_TXRX 0 +#define SYNQUACER_HSSPI_DMTRP_DATA_RX 1 +#define SYNQUACER_HSSPI_DMTRP_DATA_TX 2 + +#define SYNQUACER_HSSPI_DMSTATUS_RX_DATA_MASK 0x1f +#define SYNQUACER_HSSPI_DMSTATUS_RX_DATA_SHIFT 8U +#define SYNQUACER_HSSPI_DMSTATUS_TX_DATA_MASK 0x1f +#define SYNQUACER_HSSPI_DMSTATUS_TX_DATA_SHIFT 16U + +#define SYNQUACER_HSSPI_FIFOCFG_RX_THRESHOLD_MASK 0xf +#define SYNQUACER_HSSPI_FIFOCFG_RX_THRESHOLD_SHIFT 0U +#define SYNQUACER_HSSPI_FIFOCFG_TX_THRESHOLD_MASK 0xf +#define SYNQUACER_HSSPI_FIFOCFG_TX_THRESHOLD_SHIFT 4U +#define SYNQUACER_HSSPI_FIFOCFG_FIFO_WIDTH_MASK 0x3 +#define SYNQUACER_HSSPI_FIFOCFG_FIFO_WIDTH_SHIFT 8U +#define SYNQUACER_HSSPI_FIFOCFG_RX_FLUSH BIT(11) +#define SYNQUACER_HSSPI_FIFOCFG_TX_FLUSH BIT(12) + +#define SYNQUACER_HSSPI_FIFO_DEPTH 16U +#define SYNQUACER_HSSPI_FIFO_TX_THRESHOLD 4U +#define SYNQUACER_HSSPI_FIFO_RX_THRESHOLD \ + (SYNQUACER_HSSPI_FIFO_DEPTH - SYNQUACER_HSSPI_FIFO_TX_THRESHOLD) + +#define SYNQUACER_HSSPI_TRANSFER_MODE_TX BIT(1) +#define SYNQUACER_HSSPI_TRANSFER_MODE_RX BIT(2) +#define SYNQUACER_HSSPI_TRANSFER_TMOUT_MSEC 2000U +#define SYNQUACER_HSSPI_ENABLE_TMOUT_MSEC 1000U + +#define SYNQUACER_HSSPI_CLOCK_SRC_IHCLK 0 +#define SYNQUACER_HSSPI_CLOCK_SRC_IPCLK 1 + +#define SYNQUACER_HSSPI_NUM_CHIP_SELECT 4U +#define SYNQUACER_HSSPI_IRQ_NAME_MAX 32U + +struct synquacer_spi { + struct device *dev; + struct completion transfer_done; + unsigned int cs; + unsigned int bpw; + unsigned int mode; + unsigned int speed; + bool aces, rtm; + void *rx_buf; + const void *tx_buf; + struct clk *clk; + int clk_src_type; + void __iomem *regs; + u32 tx_words, rx_words; + unsigned int bus_width; + unsigned int transfer_mode; + char rx_irq_name[SYNQUACER_HSSPI_IRQ_NAME_MAX]; + char tx_irq_name[SYNQUACER_HSSPI_IRQ_NAME_MAX]; +}; + +static int read_fifo(struct synquacer_spi *sspi) +{ + u32 len = readl(sspi->regs + SYNQUACER_HSSPI_REG_DMSTATUS); + + len = (len >> SYNQUACER_HSSPI_DMSTATUS_RX_DATA_SHIFT) & + SYNQUACER_HSSPI_DMSTATUS_RX_DATA_MASK; + len = min(len, sspi->rx_words); + + switch (sspi->bpw) { + case 8: { + u8 *buf = sspi->rx_buf; + + ioread8_rep(sspi->regs + SYNQUACER_HSSPI_REG_RX_FIFO, + buf, len); + sspi->rx_buf = buf + len; + break; + } + case 16: { + u16 *buf = sspi->rx_buf; + + ioread16_rep(sspi->regs + SYNQUACER_HSSPI_REG_RX_FIFO, + buf, len); + sspi->rx_buf = buf + len; + break; + } + case 24: + /* fallthrough, should use 32-bits access */ + case 32: { + u32 *buf = sspi->rx_buf; + + ioread32_rep(sspi->regs + SYNQUACER_HSSPI_REG_RX_FIFO, + buf, len); + sspi->rx_buf = buf + len; + break; + } + default: + return -EINVAL; + } + + sspi->rx_words -= len; + return 0; +} + +static int write_fifo(struct synquacer_spi *sspi) +{ + u32 len = readl(sspi->regs + SYNQUACER_HSSPI_REG_DMSTATUS); + + len = (len >> SYNQUACER_HSSPI_DMSTATUS_TX_DATA_SHIFT) & + SYNQUACER_HSSPI_DMSTATUS_TX_DATA_MASK; + len = min(SYNQUACER_HSSPI_FIFO_DEPTH - len, + sspi->tx_words); + + switch (sspi->bpw) { + case 8: { + const u8 *buf = sspi->tx_buf; + + iowrite8_rep(sspi->regs + SYNQUACER_HSSPI_REG_TX_FIFO, + buf, len); + sspi->tx_buf = buf + len; + break; + } + case 16: { + const u16 *buf = sspi->tx_buf; + + iowrite16_rep(sspi->regs + SYNQUACER_HSSPI_REG_TX_FIFO, + buf, len); + sspi->tx_buf = buf + len; + break; + } + case 24: + /* fallthrough, should use 32-bits access */ + case 32: { + const u32 *buf = sspi->tx_buf; + + iowrite32_rep(sspi->regs + SYNQUACER_HSSPI_REG_TX_FIFO, + buf, len); + sspi->tx_buf = buf + len; + break; + } + default: + return -EINVAL; + } + + sspi->tx_words -= len; + return 0; +} + +static int synquacer_spi_config(struct spi_master *master, + struct spi_device *spi, + struct spi_transfer *xfer) +{ + struct synquacer_spi *sspi = spi_master_get_devdata(master); + unsigned int speed, mode, bpw, cs, bus_width, transfer_mode; + u32 rate, val, div; + + /* Full Duplex only on 1-bit wide bus */ + if (xfer->rx_buf && xfer->tx_buf && + (xfer->rx_nbits != 1 || xfer->tx_nbits != 1)) { + dev_err(sspi->dev, + "RX and TX bus widths must be 1-bit for Full-Duplex!\n"); + return -EINVAL; + } + + if (xfer->tx_buf) { + bus_width = xfer->tx_nbits; + transfer_mode = SYNQUACER_HSSPI_TRANSFER_MODE_TX; + } else { + bus_width = xfer->rx_nbits; + transfer_mode = SYNQUACER_HSSPI_TRANSFER_MODE_RX; + } + + mode = spi->mode; + cs = spi->chip_select; + speed = xfer->speed_hz; + bpw = xfer->bits_per_word; + + /* return if nothing to change */ + if (speed == sspi->speed && + bus_width == sspi->bus_width && bpw == sspi->bpw && + mode == sspi->mode && cs == sspi->cs && + transfer_mode == sspi->transfer_mode) { + return 0; + } + + sspi->transfer_mode = transfer_mode; + rate = master->max_speed_hz; + + div = DIV_ROUND_UP(rate, speed); + if (div > 254) { + dev_err(sspi->dev, "Requested rate too low (%u)\n", + sspi->speed); + return -EINVAL; + } + + val = readl(sspi->regs + SYNQUACER_HSSPI_REG_PCC(cs)); + val &= ~SYNQUACER_HSSPI_PCC_SAFESYNC; + if (bpw == 8 && (mode & (SPI_TX_DUAL | SPI_RX_DUAL)) && div < 3) + val |= SYNQUACER_HSSPI_PCC_SAFESYNC; + if (bpw == 8 && (mode & (SPI_TX_QUAD | SPI_RX_QUAD)) && div < 6) + val |= SYNQUACER_HSSPI_PCC_SAFESYNC; + if (bpw == 16 && (mode & (SPI_TX_QUAD | SPI_RX_QUAD)) && div < 3) + val |= SYNQUACER_HSSPI_PCC_SAFESYNC; + + if (mode & SPI_CPHA) + val |= SYNQUACER_HSSPI_PCC_CPHA; + else + val &= ~SYNQUACER_HSSPI_PCC_CPHA; + + if (mode & SPI_CPOL) + val |= SYNQUACER_HSSPI_PCC_CPOL; + else + val &= ~SYNQUACER_HSSPI_PCC_CPOL; + + if (mode & SPI_CS_HIGH) + val |= SYNQUACER_HSSPI_PCC_SSPOL; + else + val &= ~SYNQUACER_HSSPI_PCC_SSPOL; + + if (mode & SPI_LSB_FIRST) + val |= SYNQUACER_HSSPI_PCC_SDIR; + else + val &= ~SYNQUACER_HSSPI_PCC_SDIR; + + if (sspi->aces) + val |= SYNQUACER_HSSPI_PCC_ACES; + else + val &= ~SYNQUACER_HSSPI_PCC_ACES; + + if (sspi->rtm) + val |= SYNQUACER_HSSPI_PCC_RTM; + else + val &= ~SYNQUACER_HSSPI_PCC_RTM; + + val |= (3 << SYNQUACER_HSSPI_PCC_SS2CD_SHIFT); + val |= SYNQUACER_HSSPI_PCC_SENDIAN; + + val &= ~(SYNQUACER_HSSPI_PCC_CDRS_MASK << + SYNQUACER_HSSPI_PCC_CDRS_SHIFT); + val |= ((div >> 1) << SYNQUACER_HSSPI_PCC_CDRS_SHIFT); + + writel(val, sspi->regs + SYNQUACER_HSSPI_REG_PCC(cs)); + + val = readl(sspi->regs + SYNQUACER_HSSPI_REG_FIFOCFG); + val &= ~(SYNQUACER_HSSPI_FIFOCFG_FIFO_WIDTH_MASK << + SYNQUACER_HSSPI_FIFOCFG_FIFO_WIDTH_SHIFT); + val |= ((bpw / 8 - 1) << SYNQUACER_HSSPI_FIFOCFG_FIFO_WIDTH_SHIFT); + writel(val, sspi->regs + SYNQUACER_HSSPI_REG_FIFOCFG); + + val = readl(sspi->regs + SYNQUACER_HSSPI_REG_DMSTART); + val &= ~(SYNQUACER_HSSPI_DMTRP_DATA_MASK << + SYNQUACER_HSSPI_DMTRP_DATA_SHIFT); + + if (xfer->rx_buf) + val |= (SYNQUACER_HSSPI_DMTRP_DATA_RX << + SYNQUACER_HSSPI_DMTRP_DATA_SHIFT); + else + val |= (SYNQUACER_HSSPI_DMTRP_DATA_TX << + SYNQUACER_HSSPI_DMTRP_DATA_SHIFT); + + val &= ~(3 << SYNQUACER_HSSPI_DMTRP_BUS_WIDTH_SHIFT); + val |= ((bus_width >> 1) << SYNQUACER_HSSPI_DMTRP_BUS_WIDTH_SHIFT); + writel(val, sspi->regs + SYNQUACER_HSSPI_REG_DMSTART); + + sspi->bpw = bpw; + sspi->mode = mode; + sspi->speed = speed; + sspi->cs = spi->chip_select; + sspi->bus_width = bus_width; + + return 0; +} + +static int synquacer_spi_transfer_one(struct spi_master *master, + struct spi_device *spi, + struct spi_transfer *xfer) +{ + struct synquacer_spi *sspi = spi_master_get_devdata(master); + int ret; + int status = 0; + u32 words; + u8 bpw; + u32 val; + + val = readl(sspi->regs + SYNQUACER_HSSPI_REG_DMSTART); + val &= ~SYNQUACER_HSSPI_DMSTOP_STOP; + writel(val, sspi->regs + SYNQUACER_HSSPI_REG_DMSTART); + + val = readl(sspi->regs + SYNQUACER_HSSPI_REG_FIFOCFG); + val |= SYNQUACER_HSSPI_FIFOCFG_RX_FLUSH; + val |= SYNQUACER_HSSPI_FIFOCFG_TX_FLUSH; + writel(val, sspi->regs + SYNQUACER_HSSPI_REG_FIFOCFG); + + /* + * See if we can transfer 4-bytes as 1 word + * to maximize the FIFO buffer efficiency. + */ + bpw = xfer->bits_per_word; + if (bpw == 8 && !(xfer->len % 4) && !(spi->mode & SPI_LSB_FIRST)) + xfer->bits_per_word = 32; + + ret = synquacer_spi_config(master, spi, xfer); + + /* restore */ + xfer->bits_per_word = bpw; + + if (ret) + return ret; + + reinit_completion(&sspi->transfer_done); + + sspi->tx_buf = xfer->tx_buf; + sspi->rx_buf = xfer->rx_buf; + + switch (sspi->bpw) { + case 8: + words = xfer->len; + break; + case 16: + words = xfer->len / 2; + break; + case 24: + /* fallthrough, should use 32-bits access */ + case 32: + words = xfer->len / 4; + break; + default: + dev_err(sspi->dev, "unsupported bpw: %d\n", sspi->bpw); + return -EINVAL; + } + + if (xfer->tx_buf) + sspi->tx_words = words; + else + sspi->tx_words = 0; + + if (xfer->rx_buf) + sspi->rx_words = words; + else + sspi->rx_words = 0; + + if (xfer->tx_buf) { + status = write_fifo(sspi); + if (status < 0) { + dev_err(sspi->dev, "failed write_fifo. status: 0x%x\n", + status); + return status; + } + } + + if (xfer->rx_buf) { + val = readl(sspi->regs + SYNQUACER_HSSPI_REG_FIFOCFG); + val &= ~(SYNQUACER_HSSPI_FIFOCFG_RX_THRESHOLD_MASK << + SYNQUACER_HSSPI_FIFOCFG_RX_THRESHOLD_SHIFT); + val |= ((sspi->rx_words > SYNQUACER_HSSPI_FIFO_DEPTH ? + SYNQUACER_HSSPI_FIFO_RX_THRESHOLD : sspi->rx_words) << + SYNQUACER_HSSPI_FIFOCFG_RX_THRESHOLD_SHIFT); + writel(val, sspi->regs + SYNQUACER_HSSPI_REG_FIFOCFG); + } + + writel(~0, sspi->regs + SYNQUACER_HSSPI_REG_TXC); + writel(~0, sspi->regs + SYNQUACER_HSSPI_REG_RXC); + + /* Trigger */ + val = readl(sspi->regs + SYNQUACER_HSSPI_REG_DMSTART); + val |= SYNQUACER_HSSPI_DMSTART_START; + writel(val, sspi->regs + SYNQUACER_HSSPI_REG_DMSTART); + + if (xfer->tx_buf) { + val = SYNQUACER_HSSPI_TXE_FIFO_EMPTY; + writel(val, sspi->regs + SYNQUACER_HSSPI_REG_TXE); + status = wait_for_completion_timeout(&sspi->transfer_done, + msecs_to_jiffies(SYNQUACER_HSSPI_TRANSFER_TMOUT_MSEC)); + writel(0, sspi->regs + SYNQUACER_HSSPI_REG_TXE); + } + + if (xfer->rx_buf) { + u32 buf[SYNQUACER_HSSPI_FIFO_DEPTH]; + + val = SYNQUACER_HSSPI_RXE_FIFO_MORE_THAN_THRESHOLD | + SYNQUACER_HSSPI_RXE_SLAVE_RELEASED; + writel(val, sspi->regs + SYNQUACER_HSSPI_REG_RXE); + status = wait_for_completion_timeout(&sspi->transfer_done, + msecs_to_jiffies(SYNQUACER_HSSPI_TRANSFER_TMOUT_MSEC)); + writel(0, sspi->regs + SYNQUACER_HSSPI_REG_RXE); + + /* stop RX and clean RXFIFO */ + val = readl(sspi->regs + SYNQUACER_HSSPI_REG_DMSTART); + val |= SYNQUACER_HSSPI_DMSTOP_STOP; + writel(val, sspi->regs + SYNQUACER_HSSPI_REG_DMSTART); + sspi->rx_buf = buf; + sspi->rx_words = SYNQUACER_HSSPI_FIFO_DEPTH; + read_fifo(sspi); + } + + if (status < 0) { + dev_err(sspi->dev, "failed to transfer. status: 0x%x\n", + status); + return status; + } + + return 0; +} + +static void synquacer_spi_set_cs(struct spi_device *spi, bool enable) +{ + struct synquacer_spi *sspi = spi_master_get_devdata(spi->master); + u32 val; + + val = readl(sspi->regs + SYNQUACER_HSSPI_REG_DMSTART); + val &= ~(SYNQUACER_HSSPI_DMPSEL_CS_MASK << + SYNQUACER_HSSPI_DMPSEL_CS_SHIFT); + val |= spi->chip_select << SYNQUACER_HSSPI_DMPSEL_CS_SHIFT; + writel(val, sspi->regs + SYNQUACER_HSSPI_REG_DMSTART); +} + +static int synquacer_spi_wait_status_update(struct synquacer_spi *sspi, + bool enable) +{ + u32 val; + unsigned long timeout = jiffies + + msecs_to_jiffies(SYNQUACER_HSSPI_ENABLE_TMOUT_MSEC); + + /* wait MES(Module Enable Status) is updated */ + do { + val = readl(sspi->regs + SYNQUACER_HSSPI_REG_MCTRL) & + SYNQUACER_HSSPI_MCTRL_MES; + if (enable && val) + return 0; + if (!enable && !val) + return 0; + } while (time_before(jiffies, timeout)); + + dev_err(sspi->dev, "timeout occurs in updating Module Enable Status\n"); + return -EBUSY; +} + +static int synquacer_spi_enable(struct spi_master *master) +{ + u32 val; + int status; + struct synquacer_spi *sspi = spi_master_get_devdata(master); + + /* Disable module */ + writel(0, sspi->regs + SYNQUACER_HSSPI_REG_MCTRL); + status = synquacer_spi_wait_status_update(sspi, false); + if (status < 0) + return status; + + writel(0, sspi->regs + SYNQUACER_HSSPI_REG_TXE); + writel(0, sspi->regs + SYNQUACER_HSSPI_REG_RXE); + writel(~0, sspi->regs + SYNQUACER_HSSPI_REG_TXC); + writel(~0, sspi->regs + SYNQUACER_HSSPI_REG_RXC); + writel(~0, sspi->regs + SYNQUACER_HSSPI_REG_FAULTC); + + val = readl(sspi->regs + SYNQUACER_HSSPI_REG_DMCFG); + val &= ~SYNQUACER_HSSPI_DMCFG_SSDC; + val &= ~SYNQUACER_HSSPI_DMCFG_MSTARTEN; + writel(val, sspi->regs + SYNQUACER_HSSPI_REG_DMCFG); + + val = readl(sspi->regs + SYNQUACER_HSSPI_REG_MCTRL); + if (sspi->clk_src_type == SYNQUACER_HSSPI_CLOCK_SRC_IPCLK) + val |= SYNQUACER_HSSPI_MCTRL_CDSS; + else + val &= ~SYNQUACER_HSSPI_MCTRL_CDSS; + + val &= ~SYNQUACER_HSSPI_MCTRL_COMMAND_SEQUENCE_EN; + val |= SYNQUACER_HSSPI_MCTRL_MEN; + val |= SYNQUACER_HSSPI_MCTRL_SYNCON; + + /* Enable module */ + writel(val, sspi->regs + SYNQUACER_HSSPI_REG_MCTRL); + status = synquacer_spi_wait_status_update(sspi, true); + if (status < 0) + return status; + + return 0; +} + +static irqreturn_t sq_spi_rx_handler(int irq, void *priv) +{ + uint32_t val; + struct synquacer_spi *sspi = priv; + + val = readl(sspi->regs + SYNQUACER_HSSPI_REG_RXF); + if ((val & SYNQUACER_HSSPI_RXF_SLAVE_RELEASED) || + (val & SYNQUACER_HSSPI_RXF_FIFO_MORE_THAN_THRESHOLD)) { + read_fifo(sspi); + + if (sspi->rx_words == 0) { + writel(0, sspi->regs + SYNQUACER_HSSPI_REG_RXE); + complete(&sspi->transfer_done); + } + return IRQ_HANDLED; + } + + return IRQ_NONE; +} + +static irqreturn_t sq_spi_tx_handler(int irq, void *priv) +{ + uint32_t val; + struct synquacer_spi *sspi = priv; + + val = readl(sspi->regs + SYNQUACER_HSSPI_REG_TXF); + if (val & SYNQUACER_HSSPI_TXF_FIFO_EMPTY) { + if (sspi->tx_words == 0) { + writel(0, sspi->regs + SYNQUACER_HSSPI_REG_TXE); + complete(&sspi->transfer_done); + } else { + write_fifo(sspi); + } + return IRQ_HANDLED; + } + + return IRQ_NONE; +} + +static int synquacer_spi_probe(struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; + struct spi_master *master; + struct synquacer_spi *sspi; + int ret; + int rx_irq, tx_irq; + + master = spi_alloc_master(&pdev->dev, sizeof(*sspi)); + if (!master) + return -ENOMEM; + + platform_set_drvdata(pdev, master); + + sspi = spi_master_get_devdata(master); + sspi->dev = &pdev->dev; + + init_completion(&sspi->transfer_done); + + sspi->regs = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(sspi->regs)) { + ret = PTR_ERR(sspi->regs); + goto put_spi; + } + + sspi->clk_src_type = SYNQUACER_HSSPI_CLOCK_SRC_IHCLK; /* Default */ + device_property_read_u32(&pdev->dev, "socionext,ihclk-rate", + &master->max_speed_hz); /* for ACPI */ + + if (dev_of_node(&pdev->dev)) { + if (device_property_match_string(&pdev->dev, + "clock-names", "iHCLK") >= 0) { + sspi->clk_src_type = SYNQUACER_HSSPI_CLOCK_SRC_IHCLK; + sspi->clk = devm_clk_get(sspi->dev, "iHCLK"); + } else if (device_property_match_string(&pdev->dev, + "clock-names", "iPCLK") >= 0) { + sspi->clk_src_type = SYNQUACER_HSSPI_CLOCK_SRC_IPCLK; + sspi->clk = devm_clk_get(sspi->dev, "iPCLK"); + } else { + dev_err(&pdev->dev, "specified wrong clock source\n"); + ret = -EINVAL; + goto put_spi; + } + + if (IS_ERR(sspi->clk)) { + if (!(PTR_ERR(sspi->clk) == -EPROBE_DEFER)) + dev_err(&pdev->dev, "clock not found\n"); + ret = PTR_ERR(sspi->clk); + goto put_spi; + } + + ret = clk_prepare_enable(sspi->clk); + if (ret) { + dev_err(&pdev->dev, "failed to enable clock (%d)\n", + ret); + goto put_spi; + } + + master->max_speed_hz = clk_get_rate(sspi->clk); + } + + if (!master->max_speed_hz) { + dev_err(&pdev->dev, "missing clock source\n"); + return -EINVAL; + } + master->min_speed_hz = master->max_speed_hz / 254; + + sspi->aces = device_property_read_bool(&pdev->dev, + "socionext,set-aces"); + sspi->rtm = device_property_read_bool(&pdev->dev, "socionext,use-rtm"); + + master->num_chipselect = SYNQUACER_HSSPI_NUM_CHIP_SELECT; + + rx_irq = platform_get_irq(pdev, 0); + if (rx_irq <= 0) { + dev_err(&pdev->dev, "get rx_irq failed (%d)\n", rx_irq); + ret = rx_irq; + goto put_spi; + } + snprintf(sspi->rx_irq_name, SYNQUACER_HSSPI_IRQ_NAME_MAX, "%s-rx", + dev_name(&pdev->dev)); + ret = devm_request_irq(&pdev->dev, rx_irq, sq_spi_rx_handler, + 0, sspi->rx_irq_name, sspi); + if (ret) { + dev_err(&pdev->dev, "request rx_irq failed (%d)\n", ret); + goto put_spi; + } + + tx_irq = platform_get_irq(pdev, 1); + if (tx_irq <= 0) { + dev_err(&pdev->dev, "get tx_irq failed (%d)\n", tx_irq); + ret = tx_irq; + goto put_spi; + } + snprintf(sspi->tx_irq_name, SYNQUACER_HSSPI_IRQ_NAME_MAX, "%s-tx", + dev_name(&pdev->dev)); + ret = devm_request_irq(&pdev->dev, tx_irq, sq_spi_tx_handler, + 0, sspi->tx_irq_name, sspi); + if (ret) { + dev_err(&pdev->dev, "request tx_irq failed (%d)\n", ret); + goto put_spi; + } + + master->dev.of_node = np; + master->dev.fwnode = pdev->dev.fwnode; + master->auto_runtime_pm = true; + master->bus_num = pdev->id; + + master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_TX_DUAL | SPI_RX_DUAL | + SPI_TX_QUAD | SPI_RX_QUAD; + master->bits_per_word_mask = SPI_BPW_MASK(32) | SPI_BPW_MASK(24) | + SPI_BPW_MASK(16) | SPI_BPW_MASK(8); + + master->set_cs = synquacer_spi_set_cs; + master->transfer_one = synquacer_spi_transfer_one; + + ret = synquacer_spi_enable(master); + if (ret) + goto fail_enable; + + pm_runtime_set_active(sspi->dev); + pm_runtime_enable(sspi->dev); + + ret = devm_spi_register_master(sspi->dev, master); + if (ret) + goto disable_pm; + + return 0; + +disable_pm: + pm_runtime_disable(sspi->dev); +fail_enable: + clk_disable_unprepare(sspi->clk); +put_spi: + spi_master_put(master); + + return ret; +} + +static int synquacer_spi_remove(struct platform_device *pdev) +{ + struct spi_master *master = platform_get_drvdata(pdev); + struct synquacer_spi *sspi = spi_master_get_devdata(master); + + pm_runtime_disable(sspi->dev); + + clk_disable_unprepare(sspi->clk); + + return 0; +} + +static int __maybe_unused synquacer_spi_suspend(struct device *dev) +{ + struct spi_master *master = dev_get_drvdata(dev); + struct synquacer_spi *sspi = spi_master_get_devdata(master); + int ret; + + ret = spi_master_suspend(master); + if (ret) + return ret; + + if (!pm_runtime_suspended(dev)) + clk_disable_unprepare(sspi->clk); + + return ret; +} + +static int __maybe_unused synquacer_spi_resume(struct device *dev) +{ + struct spi_master *master = dev_get_drvdata(dev); + struct synquacer_spi *sspi = spi_master_get_devdata(master); + int ret; + + if (!pm_runtime_suspended(dev)) { + /* Ensure reconfigure during next xfer */ + sspi->speed = 0; + + ret = clk_prepare_enable(sspi->clk); + if (ret < 0) { + dev_err(dev, "failed to enable clk (%d)\n", + ret); + return ret; + } + + ret = synquacer_spi_enable(master); + if (ret) { + dev_err(dev, "failed to enable spi (%d)\n", ret); + return ret; + } + } + + ret = spi_master_resume(master); + if (ret < 0) + clk_disable_unprepare(sspi->clk); + + return ret; +} + +static SIMPLE_DEV_PM_OPS(synquacer_spi_pm_ops, synquacer_spi_suspend, + synquacer_spi_resume); + +static const struct of_device_id synquacer_spi_of_match[] = { + {.compatible = "socionext,synquacer-spi"}, + {} +}; +MODULE_DEVICE_TABLE(of, synquacer_spi_of_match); + +#ifdef CONFIG_ACPI +static const struct acpi_device_id synquacer_hsspi_acpi_ids[] = { + { "SCX0004" }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(acpi, synquacer_hsspi_acpi_ids); +#endif + +static struct platform_driver synquacer_spi_driver = { + .driver = { + .name = "synquacer-spi", + .pm = &synquacer_spi_pm_ops, + .of_match_table = synquacer_spi_of_match, + .acpi_match_table = ACPI_PTR(synquacer_hsspi_acpi_ids), + }, + .probe = synquacer_spi_probe, + .remove = synquacer_spi_remove, +}; +module_platform_driver(synquacer_spi_driver); + +MODULE_DESCRIPTION("Socionext Synquacer HS-SPI controller driver"); +MODULE_AUTHOR("Masahisa Kojima <masahisa.kojima@linaro.org>"); +MODULE_AUTHOR("Jassi Brar <jaswinder.singh@linaro.org>"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/spi/spi-tegra114.c b/drivers/spi/spi-tegra114.c index d22f4d10413f..39374c2edcf3 100644 --- a/drivers/spi/spi-tegra114.c +++ b/drivers/spi/spi-tegra114.c @@ -84,8 +84,10 @@ (reg = (((val) & 0x1) << ((cs) * 8 + 5)) | \ ((reg) & ~(1 << ((cs) * 8 + 5)))) #define SPI_SET_CYCLES_BETWEEN_PACKETS(reg, cs, val) \ - (reg = (((val) & 0xF) << ((cs) * 8)) | \ - ((reg) & ~(0xF << ((cs) * 8)))) + (reg = (((val) & 0x1F) << ((cs) * 8)) | \ + ((reg) & ~(0x1F << ((cs) * 8)))) +#define MAX_SETUP_HOLD_CYCLES 16 +#define MAX_INACTIVE_CYCLES 32 #define SPI_TRANS_STATUS 0x010 #define SPI_BLK_CNT(val) (((val) >> 0) & 0xFFFF) @@ -156,6 +158,11 @@ struct tegra_spi_soc_data { bool has_intr_mask_reg; }; +struct tegra_spi_client_data { + int tx_clk_tap_delay; + int rx_clk_tap_delay; +}; + struct tegra_spi_data { struct device *dev; struct spi_master *master; @@ -182,6 +189,7 @@ struct tegra_spi_data { unsigned dma_buf_size; unsigned max_buf_size; bool is_curr_dma_xfer; + bool use_hw_based_cs; struct completion rx_dma_complete; struct completion tx_dma_complete; @@ -194,6 +202,10 @@ struct tegra_spi_data { u32 command1_reg; u32 dma_control_reg; u32 def_command1_reg; + u32 def_command2_reg; + u32 spi_cs_timing1; + u32 spi_cs_timing2; + u8 last_used_cs; struct completion xfer_completion; struct spi_transfer *curr_xfer; @@ -711,14 +723,55 @@ static void tegra_spi_deinit_dma_param(struct tegra_spi_data *tspi, dma_release_channel(dma_chan); } +static void tegra_spi_set_hw_cs_timing(struct spi_device *spi, u8 setup_dly, + u8 hold_dly, u8 inactive_dly) +{ + struct tegra_spi_data *tspi = spi_master_get_devdata(spi->master); + u32 setup_hold; + u32 spi_cs_timing; + u32 inactive_cycles; + u8 cs_state; + + setup_dly = min_t(u8, setup_dly, MAX_SETUP_HOLD_CYCLES); + hold_dly = min_t(u8, hold_dly, MAX_SETUP_HOLD_CYCLES); + if (setup_dly && hold_dly) { + setup_hold = SPI_SETUP_HOLD(setup_dly - 1, hold_dly - 1); + spi_cs_timing = SPI_CS_SETUP_HOLD(tspi->spi_cs_timing1, + spi->chip_select, + setup_hold); + if (tspi->spi_cs_timing1 != spi_cs_timing) { + tspi->spi_cs_timing1 = spi_cs_timing; + tegra_spi_writel(tspi, spi_cs_timing, SPI_CS_TIMING1); + } + } + + inactive_cycles = min_t(u8, inactive_dly, MAX_INACTIVE_CYCLES); + if (inactive_cycles) + inactive_cycles--; + cs_state = inactive_cycles ? 0 : 1; + spi_cs_timing = tspi->spi_cs_timing2; + SPI_SET_CS_ACTIVE_BETWEEN_PACKETS(spi_cs_timing, spi->chip_select, + cs_state); + SPI_SET_CYCLES_BETWEEN_PACKETS(spi_cs_timing, spi->chip_select, + inactive_cycles); + if (tspi->spi_cs_timing2 != spi_cs_timing) { + tspi->spi_cs_timing2 = spi_cs_timing; + tegra_spi_writel(tspi, spi_cs_timing, SPI_CS_TIMING2); + } +} + static u32 tegra_spi_setup_transfer_one(struct spi_device *spi, - struct spi_transfer *t, bool is_first_of_msg) + struct spi_transfer *t, + bool is_first_of_msg, + bool is_single_xfer) { struct tegra_spi_data *tspi = spi_master_get_devdata(spi->master); + struct tegra_spi_client_data *cdata = spi->controller_data; u32 speed = t->speed_hz; u8 bits_per_word = t->bits_per_word; - u32 command1; + u32 command1, command2; int req_mode; + u32 tx_tap = 0, rx_tap = 0; if (speed != tspi->cur_speed) { clk_set_rate(tspi->clk, speed); @@ -765,13 +818,34 @@ static u32 tegra_spi_setup_transfer_one(struct spi_device *spi, } else tegra_spi_writel(tspi, command1, SPI_COMMAND1); - command1 |= SPI_CS_SW_HW; - if (spi->mode & SPI_CS_HIGH) - command1 |= SPI_CS_SW_VAL; - else - command1 &= ~SPI_CS_SW_VAL; + /* GPIO based chip select control */ + if (spi->cs_gpiod) + gpiod_set_value(spi->cs_gpiod, 1); + + if (is_single_xfer && !(t->cs_change)) { + tspi->use_hw_based_cs = true; + command1 &= ~(SPI_CS_SW_HW | SPI_CS_SW_VAL); + } else { + tspi->use_hw_based_cs = false; + command1 |= SPI_CS_SW_HW; + if (spi->mode & SPI_CS_HIGH) + command1 |= SPI_CS_SW_VAL; + else + command1 &= ~SPI_CS_SW_VAL; + } + + if (tspi->last_used_cs != spi->chip_select) { + if (cdata && cdata->tx_clk_tap_delay) + tx_tap = cdata->tx_clk_tap_delay; + if (cdata && cdata->rx_clk_tap_delay) + rx_tap = cdata->rx_clk_tap_delay; + command2 = SPI_TX_TAP_DELAY(tx_tap) | + SPI_RX_TAP_DELAY(rx_tap); + if (command2 != tspi->def_command2_reg) + tegra_spi_writel(tspi, command2, SPI_COMMAND2); + tspi->last_used_cs = spi->chip_select; + } - tegra_spi_writel(tspi, 0, SPI_COMMAND2); } else { command1 = tspi->command1_reg; command1 &= ~SPI_BIT_LENGTH(~0); @@ -827,9 +901,42 @@ static int tegra_spi_start_transfer_one(struct spi_device *spi, return ret; } +static struct tegra_spi_client_data + *tegra_spi_parse_cdata_dt(struct spi_device *spi) +{ + struct tegra_spi_client_data *cdata; + struct device_node *slave_np; + + slave_np = spi->dev.of_node; + if (!slave_np) { + dev_dbg(&spi->dev, "device node not found\n"); + return NULL; + } + + cdata = kzalloc(sizeof(*cdata), GFP_KERNEL); + if (!cdata) + return NULL; + + of_property_read_u32(slave_np, "nvidia,tx-clk-tap-delay", + &cdata->tx_clk_tap_delay); + of_property_read_u32(slave_np, "nvidia,rx-clk-tap-delay", + &cdata->rx_clk_tap_delay); + return cdata; +} + +static void tegra_spi_cleanup(struct spi_device *spi) +{ + struct tegra_spi_client_data *cdata = spi->controller_data; + + spi->controller_data = NULL; + if (spi->dev.of_node) + kfree(cdata); +} + static int tegra_spi_setup(struct spi_device *spi) { struct tegra_spi_data *tspi = spi_master_get_devdata(spi->master); + struct tegra_spi_client_data *cdata = spi->controller_data; u32 val; unsigned long flags; int ret; @@ -840,9 +947,16 @@ static int tegra_spi_setup(struct spi_device *spi) spi->mode & SPI_CPHA ? "" : "~", spi->max_speed_hz); + if (!cdata) { + cdata = tegra_spi_parse_cdata_dt(spi); + spi->controller_data = cdata; + } + ret = pm_runtime_get_sync(tspi->dev); if (ret < 0) { dev_err(tspi->dev, "pm runtime failed, e = %d\n", ret); + if (cdata) + tegra_spi_cleanup(spi); return ret; } @@ -853,6 +967,10 @@ static int tegra_spi_setup(struct spi_device *spi) } spin_lock_irqsave(&tspi->lock, flags); + /* GPIO based chip select control */ + if (spi->cs_gpiod) + gpiod_set_value(spi->cs_gpiod, 0); + val = tspi->def_command1_reg; if (spi->mode & SPI_CS_HIGH) val &= ~SPI_CS_POL_INACTIVE(spi->chip_select); @@ -882,11 +1000,18 @@ static void tegra_spi_transfer_end(struct spi_device *spi) struct tegra_spi_data *tspi = spi_master_get_devdata(spi->master); int cs_val = (spi->mode & SPI_CS_HIGH) ? 0 : 1; - if (cs_val) - tspi->command1_reg |= SPI_CS_SW_VAL; - else - tspi->command1_reg &= ~SPI_CS_SW_VAL; - tegra_spi_writel(tspi, tspi->command1_reg, SPI_COMMAND1); + /* GPIO based chip select control */ + if (spi->cs_gpiod) + gpiod_set_value(spi->cs_gpiod, 0); + + if (!tspi->use_hw_based_cs) { + if (cs_val) + tspi->command1_reg |= SPI_CS_SW_VAL; + else + tspi->command1_reg &= ~SPI_CS_SW_VAL; + tegra_spi_writel(tspi, tspi->command1_reg, SPI_COMMAND1); + } + tegra_spi_writel(tspi, tspi->def_command1_reg, SPI_COMMAND1); } @@ -913,16 +1038,19 @@ static int tegra_spi_transfer_one_message(struct spi_master *master, struct spi_device *spi = msg->spi; int ret; bool skip = false; + int single_xfer; msg->status = 0; msg->actual_length = 0; + single_xfer = list_is_singular(&msg->transfers); list_for_each_entry(xfer, &msg->transfers, transfer_list) { u32 cmd1; reinit_completion(&tspi->xfer_completion); - cmd1 = tegra_spi_setup_transfer_one(spi, xfer, is_first_msg); + cmd1 = tegra_spi_setup_transfer_one(spi, xfer, is_first_msg, + single_xfer); if (!xfer->len) { ret = 0; @@ -955,6 +1083,7 @@ static int tegra_spi_transfer_one_message(struct spi_master *master, reset_control_assert(tspi->rst); udelay(2); reset_control_deassert(tspi->rst); + tspi->last_used_cs = master->num_chipselect + 1; goto complete_xfer; } @@ -1188,11 +1317,14 @@ static int tegra_spi_probe(struct platform_device *pdev) master->max_speed_hz = 25000000; /* 25MHz */ /* the spi->mode bits understood by this driver: */ + master->use_gpio_descriptors = true; master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LSB_FIRST | SPI_TX_DUAL | SPI_RX_DUAL | SPI_3WIRE; master->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 32); master->setup = tegra_spi_setup; + master->cleanup = tegra_spi_cleanup; master->transfer_one_message = tegra_spi_transfer_one_message; + master->set_cs_timing = tegra_spi_set_hw_cs_timing; master->num_chipselect = MAX_CHIP_SELECT; master->auto_runtime_pm = true; bus_num = of_alias_get_id(pdev->dev.of_node, "spi"); @@ -1268,6 +1400,10 @@ static int tegra_spi_probe(struct platform_device *pdev) reset_control_deassert(tspi->rst); tspi->def_command1_reg = SPI_M_S; tegra_spi_writel(tspi, tspi->def_command1_reg, SPI_COMMAND1); + tspi->spi_cs_timing1 = tegra_spi_readl(tspi, SPI_CS_TIMING1); + tspi->spi_cs_timing2 = tegra_spi_readl(tspi, SPI_CS_TIMING2); + tspi->def_command2_reg = tegra_spi_readl(tspi, SPI_COMMAND2); + tspi->last_used_cs = master->num_chipselect + 1; pm_runtime_put(&pdev->dev); ret = request_threaded_irq(tspi->irq, tegra_spi_isr, tegra_spi_isr_thread, IRQF_ONESHOT, @@ -1340,6 +1476,8 @@ static int tegra_spi_resume(struct device *dev) return ret; } tegra_spi_writel(tspi, tspi->command1_reg, SPI_COMMAND1); + tegra_spi_writel(tspi, tspi->def_command2_reg, SPI_COMMAND2); + tspi->last_used_cs = master->num_chipselect + 1; pm_runtime_put(dev); return spi_master_resume(master); diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index 5e4654032bfa..81e4d9f7c0f4 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -1090,6 +1090,60 @@ static int spi_transfer_wait(struct spi_controller *ctlr, return 0; } +static void _spi_transfer_delay_ns(u32 ns) +{ + if (!ns) + return; + if (ns <= 1000) { + ndelay(ns); + } else { + u32 us = DIV_ROUND_UP(ns, 1000); + + if (us <= 10) + udelay(us); + else + usleep_range(us, us + DIV_ROUND_UP(us, 10)); + } +} + +static void _spi_transfer_cs_change_delay(struct spi_message *msg, + struct spi_transfer *xfer) +{ + u32 delay = xfer->cs_change_delay; + u32 unit = xfer->cs_change_delay_unit; + u32 hz; + + /* return early on "fast" mode - for everything but USECS */ + if (!delay && unit != SPI_DELAY_UNIT_USECS) + return; + + switch (unit) { + case SPI_DELAY_UNIT_USECS: + /* for compatibility use default of 10us */ + if (!delay) + delay = 10000; + else + delay *= 1000; + break; + case SPI_DELAY_UNIT_NSECS: /* nothing to do here */ + break; + case SPI_DELAY_UNIT_SCK: + /* if there is no effective speed know, then approximate + * by underestimating with half the requested hz + */ + hz = xfer->effective_speed_hz ?: xfer->speed_hz / 2; + delay *= DIV_ROUND_UP(1000000000, hz); + break; + default: + dev_err_once(&msg->spi->dev, + "Use of unsupported delay unit %i, using default of 10us\n", + xfer->cs_change_delay_unit); + delay = 10000; + } + /* now sleep for the requested amount of time */ + _spi_transfer_delay_ns(delay); +} + /* * spi_transfer_one_message - Default implementation of transfer_one_message() * @@ -1148,14 +1202,8 @@ static int spi_transfer_one_message(struct spi_controller *ctlr, if (msg->status != -EINPROGRESS) goto out; - if (xfer->delay_usecs) { - u16 us = xfer->delay_usecs; - - if (us <= 10) - udelay(us); - else - usleep_range(us, us + DIV_ROUND_UP(us, 10)); - } + if (xfer->delay_usecs) + _spi_transfer_delay_ns(xfer->delay_usecs * 1000); if (xfer->cs_change) { if (list_is_last(&xfer->transfer_list, @@ -1163,7 +1211,7 @@ static int spi_transfer_one_message(struct spi_controller *ctlr, keep_cs = true; } else { spi_set_cs(msg->spi, false); - udelay(10); + _spi_transfer_cs_change_delay(msg, xfer); spi_set_cs(msg->spi, true); } } @@ -1804,9 +1852,18 @@ static void of_register_spi_devices(struct spi_controller *ctlr) { } #endif #ifdef CONFIG_ACPI -static void acpi_spi_parse_apple_properties(struct spi_device *spi) +struct acpi_spi_lookup { + struct spi_controller *ctlr; + u32 max_speed_hz; + u32 mode; + int irq; + u8 bits_per_word; + u8 chip_select; +}; + +static void acpi_spi_parse_apple_properties(struct acpi_device *dev, + struct acpi_spi_lookup *lookup) { - struct acpi_device *dev = ACPI_COMPANION(&spi->dev); const union acpi_object *obj; if (!x86_apple_machine) @@ -1814,35 +1871,46 @@ static void acpi_spi_parse_apple_properties(struct spi_device *spi) if (!acpi_dev_get_property(dev, "spiSclkPeriod", ACPI_TYPE_BUFFER, &obj) && obj->buffer.length >= 4) - spi->max_speed_hz = NSEC_PER_SEC / *(u32 *)obj->buffer.pointer; + lookup->max_speed_hz = NSEC_PER_SEC / *(u32 *)obj->buffer.pointer; if (!acpi_dev_get_property(dev, "spiWordSize", ACPI_TYPE_BUFFER, &obj) && obj->buffer.length == 8) - spi->bits_per_word = *(u64 *)obj->buffer.pointer; + lookup->bits_per_word = *(u64 *)obj->buffer.pointer; if (!acpi_dev_get_property(dev, "spiBitOrder", ACPI_TYPE_BUFFER, &obj) && obj->buffer.length == 8 && !*(u64 *)obj->buffer.pointer) - spi->mode |= SPI_LSB_FIRST; + lookup->mode |= SPI_LSB_FIRST; if (!acpi_dev_get_property(dev, "spiSPO", ACPI_TYPE_BUFFER, &obj) && obj->buffer.length == 8 && *(u64 *)obj->buffer.pointer) - spi->mode |= SPI_CPOL; + lookup->mode |= SPI_CPOL; if (!acpi_dev_get_property(dev, "spiSPH", ACPI_TYPE_BUFFER, &obj) && obj->buffer.length == 8 && *(u64 *)obj->buffer.pointer) - spi->mode |= SPI_CPHA; + lookup->mode |= SPI_CPHA; } static int acpi_spi_add_resource(struct acpi_resource *ares, void *data) { - struct spi_device *spi = data; - struct spi_controller *ctlr = spi->controller; + struct acpi_spi_lookup *lookup = data; + struct spi_controller *ctlr = lookup->ctlr; if (ares->type == ACPI_RESOURCE_TYPE_SERIAL_BUS) { struct acpi_resource_spi_serialbus *sb; + acpi_handle parent_handle; + acpi_status status; sb = &ares->data.spi_serial_bus; if (sb->type == ACPI_RESOURCE_SERIAL_TYPE_SPI) { + + status = acpi_get_handle(NULL, + sb->resource_source.string_ptr, + &parent_handle); + + if (ACPI_FAILURE(status) || + ACPI_HANDLE(ctlr->dev.parent) != parent_handle) + return -ENODEV; + /* * ACPI DeviceSelection numbering is handled by the * host controller driver in Windows and can vary @@ -1855,25 +1923,25 @@ static int acpi_spi_add_resource(struct acpi_resource *ares, void *data) sb->device_selection); if (cs < 0) return cs; - spi->chip_select = cs; + lookup->chip_select = cs; } else { - spi->chip_select = sb->device_selection; + lookup->chip_select = sb->device_selection; } - spi->max_speed_hz = sb->connection_speed; + lookup->max_speed_hz = sb->connection_speed; if (sb->clock_phase == ACPI_SPI_SECOND_PHASE) - spi->mode |= SPI_CPHA; + lookup->mode |= SPI_CPHA; if (sb->clock_polarity == ACPI_SPI_START_HIGH) - spi->mode |= SPI_CPOL; + lookup->mode |= SPI_CPOL; if (sb->device_polarity == ACPI_SPI_ACTIVE_HIGH) - spi->mode |= SPI_CS_HIGH; + lookup->mode |= SPI_CS_HIGH; } - } else if (spi->irq < 0) { + } else if (lookup->irq < 0) { struct resource r; if (acpi_dev_resource_interrupt(ares, 0, &r)) - spi->irq = r.start; + lookup->irq = r.start; } /* Always tell the ACPI core to skip this resource */ @@ -1883,7 +1951,9 @@ static int acpi_spi_add_resource(struct acpi_resource *ares, void *data) static acpi_status acpi_register_spi_device(struct spi_controller *ctlr, struct acpi_device *adev) { + acpi_handle parent_handle = NULL; struct list_head resource_list; + struct acpi_spi_lookup lookup = {}; struct spi_device *spi; int ret; @@ -1891,28 +1961,42 @@ static acpi_status acpi_register_spi_device(struct spi_controller *ctlr, acpi_device_enumerated(adev)) return AE_OK; - spi = spi_alloc_device(ctlr); - if (!spi) { - dev_err(&ctlr->dev, "failed to allocate SPI device for %s\n", - dev_name(&adev->dev)); - return AE_NO_MEMORY; - } - - ACPI_COMPANION_SET(&spi->dev, adev); - spi->irq = -1; + lookup.ctlr = ctlr; + lookup.irq = -1; INIT_LIST_HEAD(&resource_list); ret = acpi_dev_get_resources(adev, &resource_list, - acpi_spi_add_resource, spi); + acpi_spi_add_resource, &lookup); acpi_dev_free_resource_list(&resource_list); - acpi_spi_parse_apple_properties(spi); + if (ret < 0) + /* found SPI in _CRS but it points to another controller */ + return AE_OK; - if (ret < 0 || !spi->max_speed_hz) { - spi_dev_put(spi); + if (!lookup.max_speed_hz && + !ACPI_FAILURE(acpi_get_parent(adev->handle, &parent_handle)) && + ACPI_HANDLE(ctlr->dev.parent) == parent_handle) { + /* Apple does not use _CRS but nested devices for SPI slaves */ + acpi_spi_parse_apple_properties(adev, &lookup); + } + + if (!lookup.max_speed_hz) return AE_OK; + + spi = spi_alloc_device(ctlr); + if (!spi) { + dev_err(&ctlr->dev, "failed to allocate SPI device for %s\n", + dev_name(&adev->dev)); + return AE_NO_MEMORY; } + ACPI_COMPANION_SET(&spi->dev, adev); + spi->max_speed_hz = lookup.max_speed_hz; + spi->mode = lookup.mode; + spi->irq = lookup.irq; + spi->bits_per_word = lookup.bits_per_word; + spi->chip_select = lookup.chip_select; + acpi_set_modalias(adev, acpi_device_hid(adev), spi->modalias, sizeof(spi->modalias)); @@ -1944,6 +2028,8 @@ static acpi_status acpi_spi_add_device(acpi_handle handle, u32 level, return acpi_register_spi_device(ctlr, adev); } +#define SPI_ACPI_ENUMERATE_MAX_DEPTH 32 + static void acpi_register_spi_devices(struct spi_controller *ctlr) { acpi_status status; @@ -1953,7 +2039,8 @@ static void acpi_register_spi_devices(struct spi_controller *ctlr) if (!handle) return; - status = acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, 1, + status = acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, + SPI_ACPI_ENUMERATE_MAX_DEPTH, acpi_spi_add_device, NULL, ctlr, NULL); if (ACPI_FAILURE(status)) dev_warn(&ctlr->dev, "failed to enumerate SPI slaves\n"); @@ -2286,11 +2373,6 @@ int spi_register_controller(struct spi_controller *ctlr) if (status) return status; - /* even if it's just one always-selected device, there must - * be at least one chipselect - */ - if (ctlr->num_chipselect == 0) - return -EINVAL; if (ctlr->bus_num >= 0) { /* devices with a fixed bus num must check-in with the num */ mutex_lock(&board_lock); @@ -2361,6 +2443,13 @@ int spi_register_controller(struct spi_controller *ctlr) } } + /* + * Even if it's just one always-selected device, there must + * be at least one chipselect. + */ + if (!ctlr->num_chipselect) + return -EINVAL; + status = device_add(&ctlr->dev); if (status < 0) { /* free bus id */ @@ -2470,7 +2559,6 @@ void spi_unregister_controller(struct spi_controller *ctlr) { struct spi_controller *found; int id = ctlr->bus_num; - int dummy; /* First make sure that this controller was ever added */ mutex_lock(&board_lock); @@ -2484,7 +2572,7 @@ void spi_unregister_controller(struct spi_controller *ctlr) list_del(&ctlr->list); mutex_unlock(&board_lock); - dummy = device_for_each_child(&ctlr->dev, NULL, __unregister); + device_for_each_child(&ctlr->dev, NULL, __unregister); device_unregister(&ctlr->dev); /* free bus id */ mutex_lock(&board_lock); @@ -2633,12 +2721,9 @@ EXPORT_SYMBOL_GPL(spi_res_add); */ void spi_res_release(struct spi_controller *ctlr, struct spi_message *message) { - struct spi_res *res; - - while (!list_empty(&message->resources)) { - res = list_last_entry(&message->resources, - struct spi_res, entry); + struct spi_res *res, *tmp; + list_for_each_entry_safe_reverse(res, tmp, &message->resources, entry) { if (res->release) res->release(ctlr, message, res->data); @@ -2702,8 +2787,7 @@ struct spi_replaced_transfers *spi_replace_transfers( /* allocate the structure using spi_res */ rxfer = spi_res_alloc(msg->spi, __spi_replace_transfers_release, - insert * sizeof(struct spi_transfer) - + sizeof(struct spi_replaced_transfers) + struct_size(rxfer, inserted_transfers, insert) + extradatasize, gfp); if (!rxfer) @@ -3083,6 +3167,7 @@ static int __spi_validate(struct spi_device *spi, struct spi_message *message) */ message->frame_length = 0; list_for_each_entry(xfer, &message->transfers, transfer_list) { + xfer->effective_speed_hz = 0; message->frame_length += xfer->len; if (!xfer->bits_per_word) xfer->bits_per_word = spi->bits_per_word; @@ -3762,4 +3847,3 @@ err0: * include needing to have boardinfo data structures be much more public. */ postcore_initcall(spi_init); - diff --git a/drivers/spi/spidev.c b/drivers/spi/spidev.c index 422bac8cc3e0..255786f2e844 100644 --- a/drivers/spi/spidev.c +++ b/drivers/spi/spidev.c @@ -663,6 +663,8 @@ static const struct of_device_id spidev_dt_ids[] = { { .compatible = "ge,achc" }, { .compatible = "semtech,sx1301" }, { .compatible = "lwn,bk4" }, + { .compatible = "dh,dhcom-board" }, + { .compatible = "menlo,m53cpld" }, {}, }; MODULE_DEVICE_TABLE(of, spidev_dt_ids); |