From 8e04187c1bc7953f6dfad3400c58b1b0b0ad767b Mon Sep 17 00:00:00 2001 From: Xu Yilun Date: Thu, 11 Jun 2020 11:25:07 +0800 Subject: spi: altera: add SPI core parameters support via platform data. This patch introduced SPI core parameters in platform data, it allows passing these SPI core parameters via platform data. Signed-off-by: Wu Hao Signed-off-by: Xu Yilun Signed-off-by: Matthew Gerlach Signed-off-by: Russ Weight Reviewed-by: Tom Rix Link: https://lore.kernel.org/r/1591845911-10197-3-git-send-email-yilun.xu@intel.com Signed-off-by: Mark Brown --- include/linux/spi/altera.h | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 include/linux/spi/altera.h (limited to 'include/linux') diff --git a/include/linux/spi/altera.h b/include/linux/spi/altera.h new file mode 100644 index 000000000000..344a3fce56a4 --- /dev/null +++ b/include/linux/spi/altera.h @@ -0,0 +1,24 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Header File for Altera SPI Driver. + */ +#ifndef __LINUX_SPI_ALTERA_H +#define __LINUX_SPI_ALTERA_H + +#include +#include +#include + +/** + * struct altera_spi_platform_data - Platform data of the Altera SPI driver + * @mode_bits: Mode bits of SPI master. + * @num_chipselect: Number of chipselects. + * @bits_per_word_mask: bitmask of supported bits_per_word for transfers. + */ +struct altera_spi_platform_data { + u16 mode_bits; + u16 num_chipselect; + u32 bits_per_word_mask; +}; + +#endif /* __LINUX_SPI_ALTERA_H */ -- cgit v1.2.3 From 1fccd182a4694a848f2d6f3b1820d6fc71d9c99d Mon Sep 17 00:00:00 2001 From: Xu Yilun Date: Thu, 11 Jun 2020 11:25:08 +0800 Subject: spi: altera: add platform data for slave information. This patch introduces platform data for slave information, it allows spi-altera to add new spi devices once master registration is done. Signed-off-by: Wu Hao Signed-off-by: Xu Yilun Signed-off-by: Matthew Gerlach Signed-off-by: Russ Weight Reviewed-by: Tom Rix Link: https://lore.kernel.org/r/1591845911-10197-4-git-send-email-yilun.xu@intel.com Signed-off-by: Mark Brown --- drivers/spi/spi-altera.c | 11 +++++++++++ include/linux/spi/altera.h | 5 +++++ 2 files changed, 16 insertions(+) (limited to 'include/linux') diff --git a/drivers/spi/spi-altera.c b/drivers/spi/spi-altera.c index e6e6708c7c47..aa9d1a257433 100644 --- a/drivers/spi/spi-altera.c +++ b/drivers/spi/spi-altera.c @@ -189,6 +189,7 @@ static int altera_spi_probe(struct platform_device *pdev) struct altera_spi *hw; struct spi_master *master; int err = -ENODEV; + u16 i; master = spi_alloc_master(&pdev->dev, sizeof(struct altera_spi)); if (!master) @@ -244,6 +245,16 @@ static int altera_spi_probe(struct platform_device *pdev) err = devm_spi_register_master(&pdev->dev, master); if (err) goto exit; + + if (pdata) { + for (i = 0; i < pdata->num_devices; i++) { + if (!spi_new_device(master, pdata->devices + i)) + dev_warn(&pdev->dev, + "unable to create SPI device: %s\n", + pdata->devices[i].modalias); + } + } + dev_info(&pdev->dev, "base %p, irq %d\n", hw->base, hw->irq); return 0; diff --git a/include/linux/spi/altera.h b/include/linux/spi/altera.h index 344a3fce56a4..2d42641499a6 100644 --- a/include/linux/spi/altera.h +++ b/include/linux/spi/altera.h @@ -14,11 +14,16 @@ * @mode_bits: Mode bits of SPI master. * @num_chipselect: Number of chipselects. * @bits_per_word_mask: bitmask of supported bits_per_word for transfers. + * @num_devices: Number of devices that shall be added when the driver + * is probed. + * @devices: The devices to add. */ struct altera_spi_platform_data { u16 mode_bits; u16 num_chipselect; u32 bits_per_word_mask; + u16 num_devices; + struct spi_board_info *devices; }; #endif /* __LINUX_SPI_ALTERA_H */ -- cgit v1.2.3 From 809b1b04df898b6d182069146231a3cbf5f2d9cc Mon Sep 17 00:00:00 2001 From: Robin Gong Date: Wed, 17 Jun 2020 06:42:08 +0800 Subject: spi: introduce fallback to pio Add fallback to pio mode in case dma transfer failed with error status SPI_TRANS_FAIL_NO_START. If spi client driver want to enable this feature please set xfer->error in the proper place such as dmaengine_prep_slave_sg() failure detect(but no any data put into spi bus yet). Besides, add master->fallback checking in its can_dma() so that spi core could switch to pio next time. Please refer to spi-imx.c. Signed-off-by: Robin Gong Link: https://lore.kernel.org/r/1592347329-28363-2-git-send-email-yibin.gong@nxp.com Signed-off-by: Mark Brown --- drivers/spi/spi.c | 12 ++++++++++++ include/linux/spi/spi.h | 7 +++++++ 2 files changed, 19 insertions(+) (limited to 'include/linux') diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index 8158e281f354..6fa56590bba2 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -982,6 +982,8 @@ static int __spi_unmap_msg(struct spi_controller *ctlr, struct spi_message *msg) spi_unmap_buf(ctlr, tx_dev, &xfer->tx_sg, DMA_TO_DEVICE); } + ctlr->cur_msg_mapped = false; + return 0; } #else /* !CONFIG_HAS_DMA */ @@ -1234,8 +1236,17 @@ static int spi_transfer_one_message(struct spi_controller *ctlr, if (xfer->tx_buf || xfer->rx_buf) { reinit_completion(&ctlr->xfer_completion); +fallback_pio: ret = ctlr->transfer_one(ctlr, msg->spi, xfer); if (ret < 0) { + if (ctlr->cur_msg_mapped && + (xfer->error & SPI_TRANS_FAIL_NO_START)) { + __spi_unmap_msg(ctlr, msg); + ctlr->fallback = true; + xfer->error &= ~SPI_TRANS_FAIL_NO_START; + goto fallback_pio; + } + SPI_STATISTICS_INCREMENT_FIELD(statm, errors); SPI_STATISTICS_INCREMENT_FIELD(stats, @@ -1693,6 +1704,7 @@ void spi_finalize_current_message(struct spi_controller *ctlr) spin_lock_irqsave(&ctlr->queue_lock, flags); ctlr->cur_msg = NULL; ctlr->cur_msg_prepared = false; + ctlr->fallback = false; kthread_queue_work(&ctlr->kworker, &ctlr->pump_messages); spin_unlock_irqrestore(&ctlr->queue_lock, flags); diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h index aac57b5b7c21..b4917df79637 100644 --- a/include/linux/spi/spi.h +++ b/include/linux/spi/spi.h @@ -447,6 +447,8 @@ static inline void spi_unregister_driver(struct spi_driver *sdrv) * If the driver does not set this, the SPI core takes the snapshot as * close to the driver hand-over as possible. * @irq_flags: Interrupt enable state during PTP system timestamping + * @fallback: fallback to pio if dma transfer return failure with + * SPI_TRANS_FAIL_NO_START. * * Each SPI controller can communicate with one or more @spi_device * children. These make a small bus, sharing MOSI, MISO and SCK signals @@ -602,6 +604,7 @@ struct spi_controller { bool auto_runtime_pm; bool cur_msg_prepared; bool cur_msg_mapped; + bool fallback; struct completion xfer_completion; size_t max_dma_len; @@ -847,6 +850,7 @@ extern void spi_res_release(struct spi_controller *ctlr, * back unset and they need the better resolution. * @timestamped_post: See above. The reason why both exist is that these * booleans are also used to keep state in the core SPI logic. + * @error: Error status logged by spi controller driver. * * SPI transfers always write the same number of bytes as they read. * Protocol drivers should always provide @rx_buf and/or @tx_buf. @@ -940,6 +944,9 @@ struct spi_transfer { bool timestamped; struct list_head transfer_list; + +#define SPI_TRANS_FAIL_NO_START BIT(0) + u16 error; }; /** -- cgit v1.2.3 From d40f0b6f2e21f2400ae8b1b120d11877d9ffd8ec Mon Sep 17 00:00:00 2001 From: Douglas Anderson Date: Mon, 29 Jun 2020 16:41:06 -0700 Subject: spi: Avoid setting the chip select if we don't need to On some SPI controllers (like spi-geni-qcom) setting the chip select is a heavy operation. For instance on spi-geni-qcom, with the current code, is was measured as taking upwards of 20 us. Even on SPI controllers that aren't as heavy, setting the chip select is at least something like a MMIO operation over some peripheral bus which isn't as fast as a RAM access. While it would be good to find ways to mitigate problems like this in the drivers for those SPI controllers, it can also be noted that the SPI framework could also help out. Specifically, in some situations, we can see the SPI framework calling the driver's set_cs() with the same parameter several times in a row. This is specifically observed when looking at the way the Chrome OS EC SPI driver (cros_ec_spi) works but other drivers likely trip it to some extent. Let's solve this by caching the chip select state in the core and only calling into the controller if there was a change. We check not only the "enable" state but also the chip select mode (active high or active low) since controllers may care about both the mode and the enable flag in their callback. Signed-off-by: Douglas Anderson Link: https://lore.kernel.org/r/20200629164103.1.Ied8e8ad8bbb2df7f947e3bc5ea1c315e041785a2@changeid Signed-off-by: Mark Brown --- drivers/spi/spi.c | 11 +++++++++++ include/linux/spi/spi.h | 4 ++++ 2 files changed, 15 insertions(+) (limited to 'include/linux') diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index 6fa56590bba2..d4ba723a30da 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -778,6 +778,17 @@ static void spi_set_cs(struct spi_device *spi, bool enable) { bool enable1 = enable; + /* + * Avoid calling into the driver (or doing delays) if the chip select + * isn't actually changing from the last time this was called. + */ + if ((spi->controller->last_cs_enable == enable) && + (spi->controller->last_cs_mode_high == (spi->mode & SPI_CS_HIGH))) + return; + + spi->controller->last_cs_enable = enable; + spi->controller->last_cs_mode_high = spi->mode & SPI_CS_HIGH; + if (!spi->controller->set_cs_timing) { if (enable1) spi_delay_exec(&spi->controller->cs_setup, NULL); diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h index b4917df79637..0e67a9a3a1d3 100644 --- a/include/linux/spi/spi.h +++ b/include/linux/spi/spi.h @@ -368,6 +368,8 @@ static inline void spi_unregister_driver(struct spi_driver *sdrv) * @cur_msg_prepared: spi_prepare_message was called for the currently * in-flight message * @cur_msg_mapped: message has been mapped for DMA + * @last_cs_enable: was enable true on the last call to set_cs. + * @last_cs_mode_high: was (mode & SPI_CS_HIGH) true on the last call to set_cs. * @xfer_completion: used by core transfer_one_message() * @busy: message pump is busy * @running: message pump is running @@ -604,6 +606,8 @@ struct spi_controller { bool auto_runtime_pm; bool cur_msg_prepared; bool cur_msg_mapped; + bool last_cs_enable; + bool last_cs_mode_high; bool fallback; struct completion xfer_completion; size_t max_dma_len; -- cgit v1.2.3 From 60a883d119ab9ef63f830c85bbd2f0e2e2314f4f Mon Sep 17 00:00:00 2001 From: Marek Szyprowski Date: Thu, 9 Jul 2020 08:50:07 +0200 Subject: spi: use kthread_create_worker() helper Use kthread_create_worker() helper to simplify the code. It uses the kthread worker API the right way. It will eventually allow to remove the FIXME in kthread_worker_fn() and add more consistency checks in the future. Signed-off-by: Marek Szyprowski Reviewed-by: Petr Mladek Link: https://lore.kernel.org/r/20200709065007.26896-1-m.szyprowski@samsung.com Signed-off-by: Mark Brown --- drivers/spi/spi.c | 26 ++++++++++++-------------- include/linux/spi/spi.h | 6 ++---- 2 files changed, 14 insertions(+), 18 deletions(-) (limited to 'include/linux') diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index d4ba723a30da..1d7bba434225 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -1368,7 +1368,7 @@ static void __spi_pump_messages(struct spi_controller *ctlr, bool in_kthread) /* If another context is idling the device then defer */ if (ctlr->idling) { - kthread_queue_work(&ctlr->kworker, &ctlr->pump_messages); + kthread_queue_work(ctlr->kworker, &ctlr->pump_messages); spin_unlock_irqrestore(&ctlr->queue_lock, flags); return; } @@ -1382,7 +1382,7 @@ static void __spi_pump_messages(struct spi_controller *ctlr, bool in_kthread) /* Only do teardown in the thread */ if (!in_kthread) { - kthread_queue_work(&ctlr->kworker, + kthread_queue_work(ctlr->kworker, &ctlr->pump_messages); spin_unlock_irqrestore(&ctlr->queue_lock, flags); return; @@ -1618,7 +1618,7 @@ static void spi_set_thread_rt(struct spi_controller *ctlr) dev_info(&ctlr->dev, "will run message pump with realtime priority\n"); - sched_setscheduler(ctlr->kworker_task, SCHED_FIFO, ¶m); + sched_setscheduler(ctlr->kworker->task, SCHED_FIFO, ¶m); } static int spi_init_queue(struct spi_controller *ctlr) @@ -1626,13 +1626,12 @@ static int spi_init_queue(struct spi_controller *ctlr) ctlr->running = false; ctlr->busy = false; - kthread_init_worker(&ctlr->kworker); - ctlr->kworker_task = kthread_run(kthread_worker_fn, &ctlr->kworker, - "%s", dev_name(&ctlr->dev)); - if (IS_ERR(ctlr->kworker_task)) { - dev_err(&ctlr->dev, "failed to create message pump task\n"); - return PTR_ERR(ctlr->kworker_task); + ctlr->kworker = kthread_create_worker(0, dev_name(&ctlr->dev)); + if (IS_ERR(ctlr->kworker)) { + dev_err(&ctlr->dev, "failed to create message pump kworker\n"); + return PTR_ERR(ctlr->kworker); } + kthread_init_work(&ctlr->pump_messages, spi_pump_messages); /* @@ -1716,7 +1715,7 @@ void spi_finalize_current_message(struct spi_controller *ctlr) ctlr->cur_msg = NULL; ctlr->cur_msg_prepared = false; ctlr->fallback = false; - kthread_queue_work(&ctlr->kworker, &ctlr->pump_messages); + kthread_queue_work(ctlr->kworker, &ctlr->pump_messages); spin_unlock_irqrestore(&ctlr->queue_lock, flags); trace_spi_message_done(mesg); @@ -1742,7 +1741,7 @@ static int spi_start_queue(struct spi_controller *ctlr) ctlr->cur_msg = NULL; spin_unlock_irqrestore(&ctlr->queue_lock, flags); - kthread_queue_work(&ctlr->kworker, &ctlr->pump_messages); + kthread_queue_work(ctlr->kworker, &ctlr->pump_messages); return 0; } @@ -1798,8 +1797,7 @@ static int spi_destroy_queue(struct spi_controller *ctlr) return ret; } - kthread_flush_worker(&ctlr->kworker); - kthread_stop(ctlr->kworker_task); + kthread_destroy_worker(ctlr->kworker); return 0; } @@ -1822,7 +1820,7 @@ static int __spi_queued_transfer(struct spi_device *spi, list_add_tail(&msg->queue, &ctlr->queue); if (!ctlr->busy && need_pump) - kthread_queue_work(&ctlr->kworker, &ctlr->pump_messages); + kthread_queue_work(ctlr->kworker, &ctlr->pump_messages); spin_unlock_irqrestore(&ctlr->queue_lock, flags); return 0; diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h index 0e67a9a3a1d3..5fcf5da13fdb 100644 --- a/include/linux/spi/spi.h +++ b/include/linux/spi/spi.h @@ -358,8 +358,7 @@ static inline void spi_unregister_driver(struct spi_driver *sdrv) * @cleanup: frees controller-specific state * @can_dma: determine whether this controller supports DMA * @queued: whether this controller is providing an internal message queue - * @kworker: thread struct for message pump - * @kworker_task: pointer to task for message pump kworker thread + * @kworker: pointer to thread struct for message pump * @pump_messages: work struct for scheduling work to the message pump * @queue_lock: spinlock to syncronise access to message queue * @queue: message queue @@ -593,8 +592,7 @@ struct spi_controller { * Over time we expect SPI drivers to be phased over to this API. */ bool queued; - struct kthread_worker kworker; - struct task_struct *kworker_task; + struct kthread_worker *kworker; struct kthread_work pump_messages; spinlock_t queue_lock; struct list_head queue; -- cgit v1.2.3 From 8cdcd8aeee2819199ec7f68114b77b04c10611d3 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Thu, 25 Jun 2020 22:02:52 +0200 Subject: spi: imx/fsl-lpspi: Convert to GPIO descriptors MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This converts the two Freescale i.MX SPI drivers Freescale i.MX (CONFIG_SPI_IMX) and Freescale i.MX LPSPI (CONFIG_SPI_FSL_LPSPI) to use GPIO descriptors handled in the SPI core for GPIO chip selects whether defined in the device tree or a board file. The reason why both are converted at the same time is that they were both using the same platform data and platform device population helpers when using board files intertwining the code so this gives a cleaner cut. The platform device creation was passing a platform data container from each boardfile down to the driver using struct spi_imx_master from , but this was only conveying the number of chipselects and an int * array of the chipselect GPIO numbers. The imx27 and imx31 platforms had code passing the now-unused platform data when creating the platform devices, this has been repurposed to pass around GPIO descriptor tables. The platform data struct that was just passing an array of integers and number of chip selects for the GPIO lines has been removed. The number of chipselects used to be passed from the board file, because this number also limits the number of native chipselects that the platform can use. To deal with this we just augment the i.MX (CONFIG_SPI_IMX) driver to support 3 chipselects if the platform does not define "num-cs" as a device property (such as from the device tree). This covers all the legacy boards as these use <= 3 native chip selects (or GPIO lines, and in that case the number of chip selects is determined by the core from the number of available GPIO lines). Any new boards should use device tree, so this is a reasonable simplification to cover all old boards. The LPSPI driver never assigned the number of chipselects and thus always fall back to the core default of 1 chip select if no GPIOs are defined in the device tree. The Freescale i.MX driver was already partly utilizing the SPI core to obtain the GPIO numbers from the device tree, so this completes the transtion to let the core handle all of it. All board files and the core i.MX boardfile registration code is augmented to account for these changes. This has been compile-tested with the imx_v4_v5_defconfig and the imx_v6_v7_defconfig. Signed-off-by: Linus Walleij Acked-by: Shawn Guo Cc: Uwe Kleine-König Cc: Robin Gong Cc: Trent Piepho Cc: Clark Wang Cc: Shawn Guo Cc: Sascha Hauer Cc: Pengutronix Kernel Team Cc: Fabio Estevam Cc: NXP Linux Team Link: https://lore.kernel.org/r/20200625200252.207614-1-linus.walleij@linaro.org Signed-off-by: Mark Brown --- arch/arm/mach-imx/devices-imx27.h | 10 +-- arch/arm/mach-imx/devices-imx31.h | 10 +-- arch/arm/mach-imx/devices/devices-common.h | 5 +- arch/arm/mach-imx/devices/platform-spi_imx.c | 9 +-- arch/arm/mach-imx/mach-mx27_3ds.c | 40 ++++++++---- arch/arm/mach-imx/mach-mx31_3ds.c | 13 +--- arch/arm/mach-imx/mach-mx31lilly.c | 14 +---- arch/arm/mach-imx/mach-mx31lite.c | 19 +----- arch/arm/mach-imx/mach-mx31moboard.c | 12 +--- arch/arm/mach-imx/mach-pca100.c | 21 +++++-- arch/arm/mach-imx/mach-pcm037_eet.c | 7 +-- drivers/spi/spi-fsl-lpspi.c | 47 +------------- drivers/spi/spi-imx.c | 92 +++++----------------------- include/linux/platform_data/spi-imx.h | 33 ---------- 14 files changed, 88 insertions(+), 244 deletions(-) delete mode 100644 include/linux/platform_data/spi-imx.h (limited to 'include/linux') diff --git a/arch/arm/mach-imx/devices-imx27.h b/arch/arm/mach-imx/devices-imx27.h index f89f4ae0e1ca..583a1d773d68 100644 --- a/arch/arm/mach-imx/devices-imx27.h +++ b/arch/arm/mach-imx/devices-imx27.h @@ -75,11 +75,11 @@ extern const struct imx_mxc_w1_data imx27_mxc_w1_data; imx_add_mxc_w1(&imx27_mxc_w1_data) extern const struct imx_spi_imx_data imx27_cspi_data[]; -#define imx27_add_cspi(id, pdata) \ - imx_add_spi_imx(&imx27_cspi_data[id], pdata) -#define imx27_add_spi_imx0(pdata) imx27_add_cspi(0, pdata) -#define imx27_add_spi_imx1(pdata) imx27_add_cspi(1, pdata) -#define imx27_add_spi_imx2(pdata) imx27_add_cspi(2, pdata) +#define imx27_add_cspi(id, gtable) \ + imx_add_spi_imx(&imx27_cspi_data[id], gtable) +#define imx27_add_spi_imx0(gtable) imx27_add_cspi(0, gtable) +#define imx27_add_spi_imx1(gtable) imx27_add_cspi(1, gtable) +#define imx27_add_spi_imx2(gtable) imx27_add_cspi(2, gtable) extern const struct imx_pata_imx_data imx27_pata_imx_data; #define imx27_add_pata_imx() \ diff --git a/arch/arm/mach-imx/devices-imx31.h b/arch/arm/mach-imx/devices-imx31.h index 5a4ba35a47ed..f7cc62372532 100644 --- a/arch/arm/mach-imx/devices-imx31.h +++ b/arch/arm/mach-imx/devices-imx31.h @@ -69,11 +69,11 @@ extern const struct imx_mxc_w1_data imx31_mxc_w1_data; imx_add_mxc_w1(&imx31_mxc_w1_data) extern const struct imx_spi_imx_data imx31_cspi_data[]; -#define imx31_add_cspi(id, pdata) \ - imx_add_spi_imx(&imx31_cspi_data[id], pdata) -#define imx31_add_spi_imx0(pdata) imx31_add_cspi(0, pdata) -#define imx31_add_spi_imx1(pdata) imx31_add_cspi(1, pdata) -#define imx31_add_spi_imx2(pdata) imx31_add_cspi(2, pdata) +#define imx31_add_cspi(id, gtable) \ + imx_add_spi_imx(&imx31_cspi_data[id], gtable) +#define imx31_add_spi_imx0(gtable) imx31_add_cspi(0, gtable) +#define imx31_add_spi_imx1(gtable) imx31_add_cspi(1, gtable) +#define imx31_add_spi_imx2(gtable) imx31_add_cspi(2, gtable) extern const struct imx_pata_imx_data imx31_pata_imx_data; #define imx31_add_pata_imx() \ diff --git a/arch/arm/mach-imx/devices/devices-common.h b/arch/arm/mach-imx/devices/devices-common.h index 2a685adec1df..f8f3e4967c31 100644 --- a/arch/arm/mach-imx/devices/devices-common.h +++ b/arch/arm/mach-imx/devices/devices-common.h @@ -6,6 +6,7 @@ #include #include #include +#include #include extern struct device mxc_aips_bus; @@ -276,7 +277,6 @@ struct platform_device *__init imx_add_sdhci_esdhc_imx( const struct imx_sdhci_esdhc_imx_data *data, const struct esdhc_platform_data *pdata); -#include struct imx_spi_imx_data { const char *devid; int id; @@ -285,8 +285,7 @@ struct imx_spi_imx_data { int irq; }; struct platform_device *__init imx_add_spi_imx( - const struct imx_spi_imx_data *data, - const struct spi_imx_master *pdata); + const struct imx_spi_imx_data *data, struct gpiod_lookup_table *gtable); struct platform_device *imx_add_imx_dma(char *name, resource_size_t iobase, int irq, int irq_err); diff --git a/arch/arm/mach-imx/devices/platform-spi_imx.c b/arch/arm/mach-imx/devices/platform-spi_imx.c index f2cafa52c187..27747bf628a3 100644 --- a/arch/arm/mach-imx/devices/platform-spi_imx.c +++ b/arch/arm/mach-imx/devices/platform-spi_imx.c @@ -3,6 +3,7 @@ * Copyright (C) 2009-2010 Pengutronix * Uwe Kleine-Koenig */ +#include #include "../hardware.h" #include "devices-common.h" @@ -57,8 +58,7 @@ const struct imx_spi_imx_data imx35_cspi_data[] __initconst = { #endif /* ifdef CONFIG_SOC_IMX35 */ struct platform_device *__init imx_add_spi_imx( - const struct imx_spi_imx_data *data, - const struct spi_imx_master *pdata) + const struct imx_spi_imx_data *data, struct gpiod_lookup_table *gtable) { struct resource res[] = { { @@ -71,7 +71,8 @@ struct platform_device *__init imx_add_spi_imx( .flags = IORESOURCE_IRQ, }, }; - + if (gtable) + gpiod_add_lookup_table(gtable); return imx_add_platform_device(data->devid, data->id, - res, ARRAY_SIZE(res), pdata, sizeof(*pdata)); + res, ARRAY_SIZE(res), NULL, 0); } diff --git a/arch/arm/mach-imx/mach-mx27_3ds.c b/arch/arm/mach-imx/mach-mx27_3ds.c index 1da5f07952ac..2db4475b7f85 100644 --- a/arch/arm/mach-imx/mach-mx27_3ds.c +++ b/arch/arm/mach-imx/mach-mx27_3ds.c @@ -303,18 +303,34 @@ static struct imx_ssi_platform_data mx27_3ds_ssi_pdata = { }; /* SPI */ -static int spi1_chipselect[] = {SPI1_SS0}; - -static const struct spi_imx_master spi1_pdata __initconst = { - .chipselect = spi1_chipselect, - .num_chipselect = ARRAY_SIZE(spi1_chipselect), +static struct gpiod_lookup_table mx27_spi1_gpiod_table = { + .dev_id = "imx27-cspi.0", /* Actual device name for spi1 */ + .table = { + /* + * The i.MX27 has the i.MX21 GPIO controller, the SPI1 CS GPIO + * SPI1_SS0 is numbered IMX_GPIO_NR(4, 28). + * + * This is in "bank 4" which is subtracted by one in the macro + * so this is actually bank 3 on "imx21-gpio.3". + */ + GPIO_LOOKUP_IDX("imx21-gpio.3", 28, "cs", 0, GPIO_ACTIVE_LOW), + { }, + }, }; -static int spi2_chipselect[] = {SPI2_SS0}; - -static const struct spi_imx_master spi2_pdata __initconst = { - .chipselect = spi2_chipselect, - .num_chipselect = ARRAY_SIZE(spi2_chipselect), +static struct gpiod_lookup_table mx27_spi2_gpiod_table = { + .dev_id = "imx27-cspi.1", /* Actual device name for spi2 */ + .table = { + /* + * The i.MX27 has the i.MX21 GPIO controller, the SPI2 CS GPIO + * SPI2_SS0 is numbered IMX_GPIO_NR(4, 21). + * + * This is in "bank 4" which is subtracted by one in the macro + * so this is actually bank 3 on "imx21-gpio.3". + */ + GPIO_LOOKUP_IDX("imx21-gpio.3", 21, "cs", 0, GPIO_ACTIVE_LOW), + { }, + }, }; static struct imx_fb_videomode mx27_3ds_modes[] = { @@ -397,8 +413,8 @@ static void __init mx27pdk_init(void) imx27_add_imx_keypad(&mx27_3ds_keymap_data); imx27_add_imx2_wdt(); - imx27_add_spi_imx1(&spi2_pdata); - imx27_add_spi_imx0(&spi1_pdata); + imx27_add_spi_imx1(&mx27_spi2_gpiod_table); + imx27_add_spi_imx0(&mx27_spi1_gpiod_table); imx27_add_imx_i2c(0, &mx27_3ds_i2c0_data); imx27_add_imx_fb(&mx27_3ds_fb_data); diff --git a/arch/arm/mach-imx/mach-mx31_3ds.c b/arch/arm/mach-imx/mach-mx31_3ds.c index e81386190479..23e63d3b4c6a 100644 --- a/arch/arm/mach-imx/mach-mx31_3ds.c +++ b/arch/arm/mach-imx/mach-mx31_3ds.c @@ -378,15 +378,6 @@ static struct imx_ssi_platform_data mx31_3ds_ssi_pdata = { .flags = IMX_SSI_DMA | IMX_SSI_NET, }; -/* SPI */ -static const struct spi_imx_master spi0_pdata __initconst = { - .num_chipselect = 3, -}; - -static const struct spi_imx_master spi1_pdata __initconst = { - .num_chipselect = 3, -}; - static struct spi_board_info mx31_3ds_spi_devs[] __initdata = { { .modalias = "mc13783", @@ -561,14 +552,14 @@ static void __init mx31_3ds_init(void) imx31_add_imx_uart0(&uart_pdata); imx31_add_mxc_nand(&mx31_3ds_nand_board_info); - imx31_add_spi_imx1(&spi1_pdata); + imx31_add_spi_imx1(NULL); imx31_add_imx_keypad(&mx31_3ds_keymap_data); imx31_add_imx2_wdt(); imx31_add_imx_i2c0(&mx31_3ds_i2c0_data); - imx31_add_spi_imx0(&spi0_pdata); + imx31_add_spi_imx0(NULL); imx31_add_ipu_core(); imx31_add_mx3_sdc_fb(&mx3fb_pdata); diff --git a/arch/arm/mach-imx/mach-mx31lilly.c b/arch/arm/mach-imx/mach-mx31lilly.c index 8f725248299e..4b955ccc92cd 100644 --- a/arch/arm/mach-imx/mach-mx31lilly.c +++ b/arch/arm/mach-imx/mach-mx31lilly.c @@ -215,16 +215,6 @@ static void __init lilly1131_usb_init(void) imx31_add_mxc_ehci_hs(2, &usbh2_pdata); } -/* SPI */ - -static const struct spi_imx_master spi0_pdata __initconst = { - .num_chipselect = 3, -}; - -static const struct spi_imx_master spi1_pdata __initconst = { - .num_chipselect = 3, -}; - static struct mc13xxx_platform_data mc13783_pdata __initdata = { .flags = MC13XXX_USE_RTC | MC13XXX_USE_TOUCHSCREEN, }; @@ -281,8 +271,8 @@ static void __init mx31lilly_board_init(void) mxc_iomux_alloc_pin(MX31_PIN_CSPI2_SS1__SS1, "SPI2_SS1"); mxc_iomux_alloc_pin(MX31_PIN_CSPI2_SS2__SS2, "SPI2_SS2"); - imx31_add_spi_imx0(&spi0_pdata); - imx31_add_spi_imx1(&spi1_pdata); + imx31_add_spi_imx0(NULL); + imx31_add_spi_imx1(NULL); regulator_register_fixed(0, dummy_supplies, ARRAY_SIZE(dummy_supplies)); } diff --git a/arch/arm/mach-imx/mach-mx31lite.c b/arch/arm/mach-imx/mach-mx31lite.c index c0055f57c02d..aaccf52f7ac1 100644 --- a/arch/arm/mach-imx/mach-mx31lite.c +++ b/arch/arm/mach-imx/mach-mx31lite.c @@ -73,11 +73,6 @@ static const struct imxuart_platform_data uart_pdata __initconst = { .flags = IMXUART_HAVE_RTSCTS, }; -/* SPI */ -static const struct spi_imx_master spi0_pdata __initconst = { - .num_chipselect = 3, -}; - static const struct mxc_nand_platform_data mx31lite_nand_board_info __initconst = { .width = 1, @@ -111,16 +106,6 @@ static struct platform_device smsc911x_device = { }, }; -/* - * SPI - * - * The MC13783 is the only hard-wired SPI device on the module. - */ - -static const struct spi_imx_master spi1_pdata __initconst = { - .num_chipselect = 1, -}; - static struct mc13xxx_platform_data mc13783_pdata __initdata = { .flags = MC13XXX_USE_RTC, }; @@ -246,13 +231,13 @@ static void __init mx31lite_init(void) "mx31lite"); imx31_add_imx_uart0(&uart_pdata); - imx31_add_spi_imx0(&spi0_pdata); + imx31_add_spi_imx0(NULL); /* NOR and NAND flash */ platform_device_register(&physmap_flash_device); imx31_add_mxc_nand(&mx31lite_nand_board_info); - imx31_add_spi_imx1(&spi1_pdata); + imx31_add_spi_imx1(NULL); regulator_register_fixed(0, dummy_supplies, ARRAY_SIZE(dummy_supplies)); } diff --git a/arch/arm/mach-imx/mach-mx31moboard.c b/arch/arm/mach-imx/mach-mx31moboard.c index 36f08f45b0ca..96845a4eaf57 100644 --- a/arch/arm/mach-imx/mach-mx31moboard.c +++ b/arch/arm/mach-imx/mach-mx31moboard.c @@ -143,10 +143,6 @@ static const struct imxi2c_platform_data moboard_i2c1_data __initconst = { .bitrate = 100000, }; -static const struct spi_imx_master moboard_spi1_pdata __initconst = { - .num_chipselect = 3, -}; - static struct regulator_consumer_supply sdhc_consumers[] = { { .dev_name = "imx31-mmc.0", @@ -287,10 +283,6 @@ static struct spi_board_info moboard_spi_board_info[] __initdata = { }, }; -static const struct spi_imx_master moboard_spi2_pdata __initconst = { - .num_chipselect = 2, -}; - #define SDHC1_CD IOMUX_TO_GPIO(MX31_PIN_ATA_CS0) #define SDHC1_WP IOMUX_TO_GPIO(MX31_PIN_ATA_CS1) @@ -514,8 +506,8 @@ static void __init mx31moboard_init(void) imx31_add_imx_i2c0(&moboard_i2c0_data); imx31_add_imx_i2c1(&moboard_i2c1_data); - imx31_add_spi_imx1(&moboard_spi1_pdata); - imx31_add_spi_imx2(&moboard_spi2_pdata); + imx31_add_spi_imx1(NULL); + imx31_add_spi_imx2(NULL); mx31moboard_init_cam(); diff --git a/arch/arm/mach-imx/mach-pca100.c b/arch/arm/mach-imx/mach-pca100.c index 2e28e1b5cddf..27a3678e0658 100644 --- a/arch/arm/mach-imx/mach-pca100.c +++ b/arch/arm/mach-imx/mach-pca100.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include @@ -188,11 +189,19 @@ static struct spi_board_info pca100_spi_board_info[] __initdata = { }, }; -static int pca100_spi_cs[] = {SPI1_SS0, SPI1_SS1}; - -static const struct spi_imx_master pca100_spi0_data __initconst = { - .chipselect = pca100_spi_cs, - .num_chipselect = ARRAY_SIZE(pca100_spi_cs), +static struct gpiod_lookup_table pca100_spi0_gpiod_table = { + .dev_id = "imx27-cspi.0", /* Actual device name for spi0 */ + .table = { + /* + * The i.MX27 has the i.MX21 GPIO controller, port D is + * bank 3 and thus named "imx21-gpio.3". + * SPI1_SS0 is GPIO_PORTD + 28 + * SPI1_SS1 is GPIO_PORTD + 27 + */ + GPIO_LOOKUP_IDX("imx21-gpio.3", 28, "cs", 0, GPIO_ACTIVE_LOW), + GPIO_LOOKUP_IDX("imx21-gpio.3", 27, "cs", 1, GPIO_ACTIVE_LOW), + { }, + }, }; static void pca100_ac97_warm_reset(struct snd_ac97 *ac97) @@ -362,7 +371,7 @@ static void __init pca100_init(void) mxc_gpio_mode(GPIO_PORTD | 27 | GPIO_GPIO | GPIO_IN); spi_register_board_info(pca100_spi_board_info, ARRAY_SIZE(pca100_spi_board_info)); - imx27_add_spi_imx0(&pca100_spi0_data); + imx27_add_spi_imx0(&pca100_spi0_gpiod_table); imx27_add_imx_fb(&pca100_fb_data); diff --git a/arch/arm/mach-imx/mach-pcm037_eet.c b/arch/arm/mach-imx/mach-pcm037_eet.c index 51f5142920cf..8b0e03a595c1 100644 --- a/arch/arm/mach-imx/mach-pcm037_eet.c +++ b/arch/arm/mach-imx/mach-pcm037_eet.c @@ -52,11 +52,6 @@ static struct spi_board_info pcm037_spi_dev[] = { }, }; -/* Platform Data for MXC CSPI */ -static const struct spi_imx_master pcm037_spi1_pdata __initconst = { - .num_chipselect = 2, -}; - /* GPIO-keys input device */ static struct gpio_keys_button pcm037_gpio_keys[] = { { @@ -163,7 +158,7 @@ int __init pcm037_eet_init_devices(void) /* SPI */ spi_register_board_info(pcm037_spi_dev, ARRAY_SIZE(pcm037_spi_dev)); - imx31_add_spi_imx0(&pcm037_spi1_pdata); + imx31_add_spi_imx0(NULL); imx_add_gpio_keys(&pcm037_gpio_keys_platform_data); diff --git a/drivers/spi/spi-fsl-lpspi.c b/drivers/spi/spi-fsl-lpspi.c index 1552b28b9515..38b44446c947 100644 --- a/drivers/spi/spi-fsl-lpspi.c +++ b/drivers/spi/spi-fsl-lpspi.c @@ -11,7 +11,6 @@ #include #include #include -#include #include #include #include @@ -19,11 +18,9 @@ #include #include #include -#include #include #include #include -#include #include #include #include @@ -224,20 +221,6 @@ static int lpspi_unprepare_xfer_hardware(struct spi_controller *controller) return 0; } -static int fsl_lpspi_prepare_message(struct spi_controller *controller, - struct spi_message *msg) -{ - struct fsl_lpspi_data *fsl_lpspi = - spi_controller_get_devdata(controller); - struct spi_device *spi = msg->spi; - int gpio = fsl_lpspi->chipselect[spi->chip_select]; - - if (gpio_is_valid(gpio)) - gpio_direction_output(gpio, spi->mode & SPI_CS_HIGH ? 0 : 1); - - return 0; -} - static void fsl_lpspi_write_tx_fifo(struct fsl_lpspi_data *fsl_lpspi) { u8 txfifo_cnt; @@ -831,13 +814,10 @@ static int fsl_lpspi_init_rpm(struct fsl_lpspi_data *fsl_lpspi) static int fsl_lpspi_probe(struct platform_device *pdev) { - struct device_node *np = pdev->dev.of_node; struct fsl_lpspi_data *fsl_lpspi; struct spi_controller *controller; - struct spi_imx_master *lpspi_platform_info = - dev_get_platdata(&pdev->dev); struct resource *res; - int i, ret, irq; + int ret, irq; u32 temp; bool is_slave; @@ -867,6 +847,8 @@ static int fsl_lpspi_probe(struct platform_device *pdev) controller->dev.of_node = pdev->dev.of_node; controller->bus_num = pdev->id; controller->slave_abort = fsl_lpspi_slave_abort; + if (!fsl_lpspi->is_slave) + controller->use_gpio_descriptors = true; ret = devm_spi_register_controller(&pdev->dev, controller); if (ret < 0) { @@ -874,29 +856,6 @@ static int fsl_lpspi_probe(struct platform_device *pdev) goto out_controller_put; } - if (!fsl_lpspi->is_slave) { - for (i = 0; i < controller->num_chipselect; i++) { - int cs_gpio = of_get_named_gpio(np, "cs-gpios", i); - - if (!gpio_is_valid(cs_gpio) && lpspi_platform_info) - cs_gpio = lpspi_platform_info->chipselect[i]; - - fsl_lpspi->chipselect[i] = cs_gpio; - if (!gpio_is_valid(cs_gpio)) - continue; - - ret = devm_gpio_request(&pdev->dev, - fsl_lpspi->chipselect[i], - DRIVER_NAME); - if (ret) { - dev_err(&pdev->dev, "can't get cs gpios\n"); - goto out_controller_put; - } - } - controller->cs_gpios = fsl_lpspi->chipselect; - controller->prepare_message = fsl_lpspi_prepare_message; - } - init_completion(&fsl_lpspi->xfer_done); res = platform_get_resource(pdev, IORESOURCE_MEM, 0); diff --git a/drivers/spi/spi-imx.c b/drivers/spi/spi-imx.c index 2b8d339f1936..fdc25f549378 100644 --- a/drivers/spi/spi-imx.c +++ b/drivers/spi/spi-imx.c @@ -8,7 +8,6 @@ #include #include #include -#include #include #include #include @@ -21,10 +20,9 @@ #include #include #include -#include +#include #include -#include #define DRIVER_NAME "spi_imx" @@ -723,7 +721,7 @@ static int mx31_prepare_transfer(struct spi_imx_data *spi_imx, reg |= MX31_CSPICTRL_POL; if (spi->mode & SPI_CS_HIGH) reg |= MX31_CSPICTRL_SSPOL; - if (!gpio_is_valid(spi->cs_gpio)) + if (!spi->cs_gpiod) reg |= (spi->chip_select) << (is_imx35_cspi(spi_imx) ? MX35_CSPICTRL_CS_SHIFT : MX31_CSPICTRL_CS_SHIFT); @@ -824,7 +822,7 @@ static int mx21_prepare_transfer(struct spi_imx_data *spi_imx, reg |= MX21_CSPICTRL_POL; if (spi->mode & SPI_CS_HIGH) reg |= MX21_CSPICTRL_SSPOL; - if (!gpio_is_valid(spi->cs_gpio)) + if (!spi->cs_gpiod) reg |= spi->chip_select << MX21_CSPICTRL_CS_SHIFT; writel(reg, spi_imx->base + MXC_CSPICTRL); @@ -1056,20 +1054,6 @@ static const struct of_device_id spi_imx_dt_ids[] = { }; MODULE_DEVICE_TABLE(of, spi_imx_dt_ids); -static void spi_imx_chipselect(struct spi_device *spi, int is_active) -{ - int active = is_active != BITBANG_CS_INACTIVE; - int dev_is_lowactive = !(spi->mode & SPI_CS_HIGH); - - if (spi->mode & SPI_NO_CS) - return; - - if (!gpio_is_valid(spi->cs_gpio)) - return; - - gpio_set_value(spi->cs_gpio, dev_is_lowactive ^ active); -} - static void spi_imx_set_burst_len(struct spi_imx_data *spi_imx, int n_bits) { u32 ctrl; @@ -1533,15 +1517,6 @@ static int spi_imx_setup(struct spi_device *spi) dev_dbg(&spi->dev, "%s: mode %d, %u bpw, %d hz\n", __func__, spi->mode, spi->bits_per_word, spi->max_speed_hz); - if (spi->mode & SPI_NO_CS) - return 0; - - if (gpio_is_valid(spi->cs_gpio)) - gpio_direction_output(spi->cs_gpio, - spi->mode & SPI_CS_HIGH ? 0 : 1); - - spi_imx_chipselect(spi, BITBANG_CS_INACTIVE); - return 0; } @@ -1599,20 +1574,14 @@ static int spi_imx_probe(struct platform_device *pdev) struct device_node *np = pdev->dev.of_node; const struct of_device_id *of_id = of_match_device(spi_imx_dt_ids, &pdev->dev); - struct spi_imx_master *mxc_platform_info = - dev_get_platdata(&pdev->dev); struct spi_master *master; struct spi_imx_data *spi_imx; struct resource *res; - int i, ret, irq, spi_drctl; + int ret, irq, spi_drctl; const struct spi_imx_devtype_data *devtype_data = of_id ? of_id->data : (struct spi_imx_devtype_data *)pdev->id_entry->driver_data; bool slave_mode; - - if (!np && !mxc_platform_info) { - dev_err(&pdev->dev, "can't get the platform data\n"); - return -EINVAL; - } + u32 val; slave_mode = devtype_data->has_slavemode && of_property_read_bool(np, "spi-slave"); @@ -1635,6 +1604,7 @@ static int spi_imx_probe(struct platform_device *pdev) master->bits_per_word_mask = SPI_BPW_RANGE_MASK(1, 32); master->bus_num = np ? -1 : pdev->id; + master->use_gpio_descriptors = true; spi_imx = spi_master_get_devdata(master); spi_imx->bitbang.master = master; @@ -1643,28 +1613,17 @@ static int spi_imx_probe(struct platform_device *pdev) spi_imx->devtype_data = devtype_data; - /* Get number of chip selects, either platform data or OF */ - if (mxc_platform_info) { - master->num_chipselect = mxc_platform_info->num_chipselect; - if (mxc_platform_info->chipselect) { - master->cs_gpios = devm_kcalloc(&master->dev, - master->num_chipselect, sizeof(int), - GFP_KERNEL); - if (!master->cs_gpios) - return -ENOMEM; - - for (i = 0; i < master->num_chipselect; i++) - master->cs_gpios[i] = mxc_platform_info->chipselect[i]; - } - } else { - u32 num_cs; - - if (!of_property_read_u32(np, "num-cs", &num_cs)) - master->num_chipselect = num_cs; - /* If not preset, default value of 1 is used */ - } + /* + * Get number of chip selects from device properties. This can be + * coming from device tree or boardfiles, if it is not defined, + * a default value of 3 chip selects will be used, as all the legacy + * board files have <= 3 chip selects. + */ + if (!device_property_read_u32(&pdev->dev, "num-cs", &val)) + master->num_chipselect = val; + else + master->num_chipselect = 3; - spi_imx->bitbang.chipselect = spi_imx_chipselect; spi_imx->bitbang.setup_transfer = spi_imx_setupxfer; spi_imx->bitbang.txrx_bufs = spi_imx_transfer; spi_imx->bitbang.master->setup = spi_imx_setup; @@ -1749,31 +1708,12 @@ static int spi_imx_probe(struct platform_device *pdev) goto out_clk_put; } - /* Request GPIO CS lines, if any */ - if (!spi_imx->slave_mode && master->cs_gpios) { - for (i = 0; i < master->num_chipselect; i++) { - if (!gpio_is_valid(master->cs_gpios[i])) - continue; - - ret = devm_gpio_request(&pdev->dev, - master->cs_gpios[i], - DRIVER_NAME); - if (ret) { - dev_err(&pdev->dev, "Can't get CS GPIO %i\n", - master->cs_gpios[i]); - goto out_spi_bitbang; - } - } - } - dev_info(&pdev->dev, "probed\n"); clk_disable(spi_imx->clk_ipg); clk_disable(spi_imx->clk_per); return ret; -out_spi_bitbang: - spi_bitbang_stop(&spi_imx->bitbang); out_clk_put: clk_disable_unprepare(spi_imx->clk_ipg); out_put_per: diff --git a/include/linux/platform_data/spi-imx.h b/include/linux/platform_data/spi-imx.h deleted file mode 100644 index 328f670d10bd..000000000000 --- a/include/linux/platform_data/spi-imx.h +++ /dev/null @@ -1,33 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ - -#ifndef __MACH_SPI_H_ -#define __MACH_SPI_H_ - -/* - * struct spi_imx_master - device.platform_data for SPI controller devices. - * @chipselect: Array of chipselects for this master or NULL. Numbers >= 0 - * mean GPIO pins, -ENOENT means internal CSPI chipselect - * matching the position in the array. E.g., if chipselect[1] = - * -ENOENT then a SPI slave using chip select 1 will use the - * native SS1 line of the CSPI. Omitting the array will use - * all native chip selects. - - * Normally you want to use gpio based chip selects as the CSPI - * module tries to be intelligent about when to assert the - * chipselect: The CSPI module deasserts the chipselect once it - * runs out of input data. The other problem is that it is not - * possible to mix between high active and low active chipselects - * on one single bus using the internal chipselects. - * Unfortunately, on some SoCs, Freescale decided to put some - * chipselects on dedicated pins which are not usable as gpios, - * so we have to support the internal chipselects. - * - * @num_chipselect: If @chipselect is specified, ARRAY_SIZE(chipselect), - * otherwise the number of native chip selects. - */ -struct spi_imx_master { - int *chipselect; - int num_chipselect; -}; - -#endif /* __MACH_SPI_H_*/ -- cgit v1.2.3 From 4c5e2bba30e49b970a0fd07b43e0b7a3b5fd5ea7 Mon Sep 17 00:00:00 2001 From: Pratyush Yadav Date: Wed, 24 Jun 2020 00:00:14 +0530 Subject: spi: spi-mem: allow specifying whether an op is DTR or not Each phase is given a separate 'dtr' field so mixed protocols like 4S-4D-4D can be supported. Signed-off-by: Pratyush Yadav Reviewed-by: Tudor Ambarus Link: https://lore.kernel.org/r/20200623183030.26591-2-p.yadav@ti.com Signed-off-by: Mark Brown --- drivers/spi/spi-mem.c | 3 +++ include/linux/spi/spi-mem.h | 8 ++++++++ 2 files changed, 11 insertions(+) (limited to 'include/linux') diff --git a/drivers/spi/spi-mem.c b/drivers/spi/spi-mem.c index 9a86cc27fcc0..93e255287ab9 100644 --- a/drivers/spi/spi-mem.c +++ b/drivers/spi/spi-mem.c @@ -156,6 +156,9 @@ bool spi_mem_default_supports_op(struct spi_mem *mem, op->data.dir == SPI_MEM_DATA_OUT)) return false; + if (op->cmd.dtr || op->addr.dtr || op->dummy.dtr || op->data.dtr) + return false; + return true; } EXPORT_SYMBOL_GPL(spi_mem_default_supports_op); diff --git a/include/linux/spi/spi-mem.h b/include/linux/spi/spi-mem.h index af9ff2f0f1b2..e3dcb956bf61 100644 --- a/include/linux/spi/spi-mem.h +++ b/include/linux/spi/spi-mem.h @@ -71,9 +71,11 @@ enum spi_mem_data_dir { * struct spi_mem_op - describes a SPI memory operation * @cmd.buswidth: number of IO lines used to transmit the command * @cmd.opcode: operation opcode + * @cmd.dtr: whether the command opcode should be sent in DTR mode or not * @addr.nbytes: number of address bytes to send. Can be zero if the operation * does not need to send an address * @addr.buswidth: number of IO lines used to transmit the address cycles + * @addr.dtr: whether the address should be sent in DTR mode or not * @addr.val: address value. This value is always sent MSB first on the bus. * Note that only @addr.nbytes are taken into account in this * address value, so users should make sure the value fits in the @@ -81,7 +83,9 @@ enum spi_mem_data_dir { * @dummy.nbytes: number of dummy bytes to send after an opcode or address. Can * be zero if the operation does not require dummy bytes * @dummy.buswidth: number of IO lanes used to transmit the dummy bytes + * @dummy.dtr: whether the dummy bytes should be sent in DTR mode or not * @data.buswidth: number of IO lanes used to send/receive the data + * @data.dtr: whether the data should be sent in DTR mode or not * @data.dir: direction of the transfer * @data.nbytes: number of data bytes to send/receive. Can be zero if the * operation does not involve transferring data @@ -91,22 +95,26 @@ enum spi_mem_data_dir { struct spi_mem_op { struct { u8 buswidth; + u8 dtr : 1; u8 opcode; } cmd; struct { u8 nbytes; u8 buswidth; + u8 dtr : 1; u64 val; } addr; struct { u8 nbytes; u8 buswidth; + u8 dtr : 1; } dummy; struct { u8 buswidth; + u8 dtr : 1; enum spi_mem_data_dir dir; unsigned int nbytes; union { -- cgit v1.2.3 From caf72df48be32c39f74287976ae843501ae06949 Mon Sep 17 00:00:00 2001 From: Pratyush Yadav Date: Wed, 24 Jun 2020 00:00:15 +0530 Subject: spi: spi-mem: allow specifying a command's extension In xSPI mode, flashes expect 2-byte opcodes. The second byte is called the "command extension". There can be 3 types of extensions in xSPI: repeat, invert, and hex. When the extension type is "repeat", the same opcode is sent twice. When it is "invert", the second byte is the inverse of the opcode. When it is "hex" an additional opcode byte based is sent with the command whose value can be anything. So, make opcode a 16-bit value and add a 'nbytes', similar to how multiple address widths are handled. Some places use sizeof(op->cmd.opcode). Replace them with op->cmd.nbytes The spi-mxic and spi-zynq-qspi drivers directly use op->cmd.opcode as a buffer. Now that opcode is a 2-byte field, this can result in different behaviour depending on if the machine is little endian or big endian. Extract the opcode in a local 1-byte variable and use that as the buffer instead. Both these drivers would reject multi-byte opcodes in their supports_op() hook anyway, so we only need to worry about single-byte opcodes for now. The above two changes are put in this commit to keep the series bisectable. Signed-off-by: Pratyush Yadav Reviewed-by: Tudor Ambarus Link: https://lore.kernel.org/r/20200623183030.26591-3-p.yadav@ti.com Signed-off-by: Mark Brown --- drivers/spi/spi-mem.c | 13 +++++++------ drivers/spi/spi-mtk-nor.c | 4 ++-- drivers/spi/spi-mxic.c | 3 ++- drivers/spi/spi-zynq-qspi.c | 11 ++++++----- include/linux/spi/spi-mem.h | 6 +++++- 5 files changed, 22 insertions(+), 15 deletions(-) (limited to 'include/linux') diff --git a/drivers/spi/spi-mem.c b/drivers/spi/spi-mem.c index 93e255287ab9..ef53290b7d24 100644 --- a/drivers/spi/spi-mem.c +++ b/drivers/spi/spi-mem.c @@ -159,6 +159,9 @@ bool spi_mem_default_supports_op(struct spi_mem *mem, if (op->cmd.dtr || op->addr.dtr || op->dummy.dtr || op->data.dtr) return false; + if (op->cmd.nbytes != 1) + return false; + return true; } EXPORT_SYMBOL_GPL(spi_mem_default_supports_op); @@ -173,7 +176,7 @@ static bool spi_mem_buswidth_is_valid(u8 buswidth) static int spi_mem_check_op(const struct spi_mem_op *op) { - if (!op->cmd.buswidth) + if (!op->cmd.buswidth || !op->cmd.nbytes) return -EINVAL; if ((op->addr.nbytes && !op->addr.buswidth) || @@ -309,8 +312,7 @@ int spi_mem_exec_op(struct spi_mem *mem, const struct spi_mem_op *op) return ret; } - tmpbufsize = sizeof(op->cmd.opcode) + op->addr.nbytes + - op->dummy.nbytes; + tmpbufsize = op->cmd.nbytes + op->addr.nbytes + op->dummy.nbytes; /* * Allocate a buffer to transmit the CMD, ADDR cycles with kmalloc() so @@ -325,7 +327,7 @@ int spi_mem_exec_op(struct spi_mem *mem, const struct spi_mem_op *op) tmpbuf[0] = op->cmd.opcode; xfers[xferpos].tx_buf = tmpbuf; - xfers[xferpos].len = sizeof(op->cmd.opcode); + xfers[xferpos].len = op->cmd.nbytes; xfers[xferpos].tx_nbits = op->cmd.buswidth; spi_message_add_tail(&xfers[xferpos], &msg); xferpos++; @@ -427,8 +429,7 @@ int spi_mem_adjust_op_size(struct spi_mem *mem, struct spi_mem_op *op) return ctlr->mem_ops->adjust_op_size(mem, op); if (!ctlr->mem_ops || !ctlr->mem_ops->exec_op) { - len = sizeof(op->cmd.opcode) + op->addr.nbytes + - op->dummy.nbytes; + len = op->cmd.nbytes + op->addr.nbytes + op->dummy.nbytes; if (len > spi_max_transfer_size(mem->spi)) return -EINVAL; diff --git a/drivers/spi/spi-mtk-nor.c b/drivers/spi/spi-mtk-nor.c index 7bc302b50396..d5f393871619 100644 --- a/drivers/spi/spi-mtk-nor.c +++ b/drivers/spi/spi-mtk-nor.c @@ -195,7 +195,7 @@ static int mtk_nor_adjust_op_size(struct spi_mem *mem, struct spi_mem_op *op) } } - len = MTK_NOR_PRG_MAX_SIZE - sizeof(op->cmd.opcode) - op->addr.nbytes - + len = MTK_NOR_PRG_MAX_SIZE - op->cmd.nbytes - op->addr.nbytes - op->dummy.nbytes; if (op->data.nbytes > len) op->data.nbytes = len; @@ -219,7 +219,7 @@ static bool mtk_nor_supports_op(struct spi_mem *mem, (op->dummy.buswidth == 0) && (op->data.buswidth == 1); } - len = sizeof(op->cmd.opcode) + op->addr.nbytes + op->dummy.nbytes; + len = op->cmd.nbytes + op->addr.nbytes + op->dummy.nbytes; if ((len > MTK_NOR_PRG_MAX_SIZE) || ((op->data.nbytes) && (len == MTK_NOR_PRG_MAX_SIZE))) return false; diff --git a/drivers/spi/spi-mxic.c b/drivers/spi/spi-mxic.c index 69491f3a515d..8c630acb0110 100644 --- a/drivers/spi/spi-mxic.c +++ b/drivers/spi/spi-mxic.c @@ -356,6 +356,7 @@ static int mxic_spi_mem_exec_op(struct spi_mem *mem, int nio = 1, i, ret; u32 ss_ctrl; u8 addr[8]; + u8 opcode = op->cmd.opcode; ret = mxic_spi_set_freq(mxic, mem->spi->max_speed_hz); if (ret) @@ -393,7 +394,7 @@ static int mxic_spi_mem_exec_op(struct spi_mem *mem, writel(readl(mxic->regs + HC_CFG) | HC_CFG_MAN_CS_ASSERT, mxic->regs + HC_CFG); - ret = mxic_spi_data_xfer(mxic, &op->cmd.opcode, NULL, 1); + ret = mxic_spi_data_xfer(mxic, &opcode, NULL, 1); if (ret) goto out; diff --git a/drivers/spi/spi-zynq-qspi.c b/drivers/spi/spi-zynq-qspi.c index 17641157354d..bbf3d90561f5 100644 --- a/drivers/spi/spi-zynq-qspi.c +++ b/drivers/spi/spi-zynq-qspi.c @@ -527,20 +527,21 @@ static int zynq_qspi_exec_mem_op(struct spi_mem *mem, struct zynq_qspi *xqspi = spi_controller_get_devdata(mem->spi->master); int err = 0, i; u8 *tmpbuf; + u8 opcode = op->cmd.opcode; dev_dbg(xqspi->dev, "cmd:%#x mode:%d.%d.%d.%d\n", - op->cmd.opcode, op->cmd.buswidth, op->addr.buswidth, + opcode, op->cmd.buswidth, op->addr.buswidth, op->dummy.buswidth, op->data.buswidth); zynq_qspi_chipselect(mem->spi, true); zynq_qspi_config_op(xqspi, mem->spi); - if (op->cmd.opcode) { + if (op->cmd.nbytes) { reinit_completion(&xqspi->data_completion); - xqspi->txbuf = (u8 *)&op->cmd.opcode; + xqspi->txbuf = &opcode; xqspi->rxbuf = NULL; - xqspi->tx_bytes = sizeof(op->cmd.opcode); - xqspi->rx_bytes = sizeof(op->cmd.opcode); + xqspi->tx_bytes = op->cmd.nbytes; + xqspi->rx_bytes = op->cmd.nbytes; zynq_qspi_write_op(xqspi, ZYNQ_QSPI_FIFO_DEPTH, true); zynq_qspi_write(xqspi, ZYNQ_QSPI_IEN_OFFSET, ZYNQ_QSPI_IXR_RXTX_MASK); diff --git a/include/linux/spi/spi-mem.h b/include/linux/spi/spi-mem.h index e3dcb956bf61..159463cc659c 100644 --- a/include/linux/spi/spi-mem.h +++ b/include/linux/spi/spi-mem.h @@ -17,6 +17,7 @@ { \ .buswidth = __buswidth, \ .opcode = __opcode, \ + .nbytes = 1, \ } #define SPI_MEM_OP_ADDR(__nbytes, __val, __buswidth) \ @@ -69,6 +70,8 @@ enum spi_mem_data_dir { /** * struct spi_mem_op - describes a SPI memory operation + * @cmd.nbytes: number of opcode bytes (only 1 or 2 are valid). The opcode is + * sent MSB-first. * @cmd.buswidth: number of IO lines used to transmit the command * @cmd.opcode: operation opcode * @cmd.dtr: whether the command opcode should be sent in DTR mode or not @@ -94,9 +97,10 @@ enum spi_mem_data_dir { */ struct spi_mem_op { struct { + u8 nbytes; u8 buswidth; u8 dtr : 1; - u8 opcode; + u16 opcode; } cmd; struct { -- cgit v1.2.3 From 2ae3de10abfe0be40c9d93ebc2f429b969abf008 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Wed, 15 Jul 2020 18:30:48 -0700 Subject: spi: fix duplicated word in Change doubled word "as" to "as a". Change "Return: Return:" in kernel-doc notation to have only one "Return:". Signed-off-by: Randy Dunlap Cc: Mark Brown Cc: linux-spi@vger.kernel.org Link: https://lore.kernel.org/r/40354d64-be71-3952-a980-63a76a278145@infradead.org Signed-off-by: Mark Brown --- include/linux/spi/spi.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'include/linux') diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h index 5fcf5da13fdb..f8b721fcd5c6 100644 --- a/include/linux/spi/spi.h +++ b/include/linux/spi/spi.h @@ -971,7 +971,7 @@ struct spi_transfer { * each represented by a struct spi_transfer. The sequence is "atomic" * in the sense that no other spi_message may use that SPI bus until that * sequence completes. On some systems, many such sequences can execute as - * as single programmed DMA transfer. On all systems, these messages are + * a single programmed DMA transfer. On all systems, these messages are * queued, and might complete after transactions to other devices. Messages * sent to a given spi_device are always executed in FIFO order. * @@ -1234,7 +1234,7 @@ extern int spi_bus_unlock(struct spi_controller *ctlr); * * For more specific semantics see spi_sync(). * - * Return: Return: zero on success, else a negative error code. + * Return: zero on success, else a negative error code. */ static inline int spi_sync_transfer(struct spi_device *spi, struct spi_transfer *xfers, -- cgit v1.2.3 From cfd97f94d036bf36122fa19d075c5741347aa178 Mon Sep 17 00:00:00 2001 From: Colton Lewis Date: Sat, 25 Jul 2020 05:02:57 +0000 Subject: spi: correct kernel-doc inconsistency Silence documentation build warnings by correcting kernel-doc comment for spi_transfer struct. Signed-off-by: Colton Lewis Link: https://lore.kernel.org/r/20200725050242.279548-1-colton.w.lewis@protonmail.com Signed-off-by: Mark Brown --- include/linux/spi/spi.h | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) (limited to 'include/linux') diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h index f8b721fcd5c6..99380c0825db 100644 --- a/include/linux/spi/spi.h +++ b/include/linux/spi/spi.h @@ -329,6 +329,7 @@ static inline void spi_unregister_driver(struct spi_driver *sdrv) * every chipselect is connected to a slave. * @dma_alignment: SPI controller constraint on DMA buffers alignment. * @mode_bits: flags understood by this controller driver + * @buswidth_override_bits: flags to override for this controller driver * @bits_per_word_mask: A mask indicating which values of bits_per_word are * supported by the driver. Bit n indicates that a bits_per_word n+1 is * supported. If set, the SPI core will reject any transfer with an @@ -846,12 +847,7 @@ extern void spi_res_release(struct spi_controller *ctlr, * processed the word, i.e. the "pre" timestamp should be taken before * transmitting the "pre" word, and the "post" timestamp after receiving * transmit confirmation from the controller for the "post" word. - * @timestamped_pre: Set by the SPI controller driver to denote it has acted - * upon the @ptp_sts request. Not set when the SPI core has taken care of - * the task. SPI device drivers are free to print a warning if this comes - * back unset and they need the better resolution. - * @timestamped_post: See above. The reason why both exist is that these - * booleans are also used to keep state in the core SPI logic. + * @timestamped: true if the transfer has been timestamped * @error: Error status logged by spi controller driver. * * SPI transfers always write the same number of bytes as they read. -- cgit v1.2.3