From d6dc8b7534d5c9dec80fdd7d4af20fd71602d7cb Mon Sep 17 00:00:00 2001 From: Raju Rangoju Date: Wed, 25 Sep 2024 19:06:37 +0530 Subject: [PATCH 01/58] spi: spi_amd: Sort headers alphabetically Sorting headers alphabetically helps locating duplicates, and makes it easier to figure out where to insert new headers. Co-developed-by: Akshata MukundShetty Signed-off-by: Akshata MukundShetty Signed-off-by: Raju Rangoju Link: https://patch.msgid.link/20240925133644.2922359-2-Raju.Rangoju@amd.com Signed-off-by: Mark Brown --- drivers/spi/spi-amd.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/spi/spi-amd.c b/drivers/spi/spi-amd.c index 2245ad54b03a..c52066360dfe 100644 --- a/drivers/spi/spi-amd.c +++ b/drivers/spi/spi-amd.c @@ -7,12 +7,12 @@ // Author: Sanjay R Mehta #include +#include #include +#include #include #include -#include #include -#include #include #define AMD_SPI_CTRL0_REG 0x00 From 769c16fa86f135542e08610e94015ed0f10afae4 Mon Sep 17 00:00:00 2001 From: Raju Rangoju Date: Wed, 25 Sep 2024 19:06:38 +0530 Subject: [PATCH 02/58] spi: spi_amd: Enable dual and quad I/O modes The current spi_amd driver only supports single I/O mode, despite the AMD SPI controller's capability for dual and quad I/O modes for read operations. And AMD SPI0 controller has limited support for quad mode write operations. Update the SPI-MEM support function to reflect these hardware capabilities. Co-developed-by: Krishnamoorthi M Signed-off-by: Krishnamoorthi M Co-developed-by: Akshata MukundShetty Signed-off-by: Akshata MukundShetty Signed-off-by: Raju Rangoju Link: https://patch.msgid.link/20240925133644.2922359-3-Raju.Rangoju@amd.com Signed-off-by: Mark Brown --- drivers/spi/spi-amd.c | 57 ++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 54 insertions(+), 3 deletions(-) diff --git a/drivers/spi/spi-amd.c b/drivers/spi/spi-amd.c index c52066360dfe..17a8401216e4 100644 --- a/drivers/spi/spi-amd.c +++ b/drivers/spi/spi-amd.c @@ -50,6 +50,21 @@ #define AMD_SPI_MAX_HZ 100000000 #define AMD_SPI_MIN_HZ 800000 +/* SPI read command opcodes */ +#define AMD_SPI_OP_READ 0x03 /* Read data bytes (low frequency) */ +#define AMD_SPI_OP_READ_FAST 0x0b /* Read data bytes (high frequency) */ +#define AMD_SPI_OP_READ_1_1_2 0x3b /* Read data bytes (Dual Output SPI) */ +#define AMD_SPI_OP_READ_1_2_2 0xbb /* Read data bytes (Dual I/O SPI) */ +#define AMD_SPI_OP_READ_1_1_4 0x6b /* Read data bytes (Quad Output SPI) */ +#define AMD_SPI_OP_READ_1_4_4 0xeb /* Read data bytes (Quad I/O SPI) */ + +/* SPI read command opcodes - 4B address */ +#define AMD_SPI_OP_READ_FAST_4B 0x0c /* Read data bytes (high frequency) */ +#define AMD_SPI_OP_READ_1_1_2_4B 0x3c /* Read data bytes (Dual Output SPI) */ +#define AMD_SPI_OP_READ_1_2_2_4B 0xbc /* Read data bytes (Dual I/O SPI) */ +#define AMD_SPI_OP_READ_1_1_4_4B 0x6c /* Read data bytes (Quad Output SPI) */ +#define AMD_SPI_OP_READ_1_4_4_4B 0xec /* Read data bytes (Quad I/O SPI) */ + /** * enum amd_spi_versions - SPI controller versions * @AMD_SPI_V1: AMDI0061 hardware version @@ -360,14 +375,50 @@ static inline int amd_spi_fifo_xfer(struct amd_spi *amd_spi, return message->status; } +static inline bool amd_is_spi_read_cmd_4b(const u16 op) +{ + switch (op) { + case AMD_SPI_OP_READ_FAST_4B: + case AMD_SPI_OP_READ_1_1_2_4B: + case AMD_SPI_OP_READ_1_2_2_4B: + case AMD_SPI_OP_READ_1_1_4_4B: + case AMD_SPI_OP_READ_1_4_4_4B: + return true; + default: + return false; + } +} + +static inline bool amd_is_spi_read_cmd(const u16 op) +{ + switch (op) { + case AMD_SPI_OP_READ: + case AMD_SPI_OP_READ_FAST: + case AMD_SPI_OP_READ_1_1_2: + case AMD_SPI_OP_READ_1_2_2: + case AMD_SPI_OP_READ_1_1_4: + case AMD_SPI_OP_READ_1_4_4: + return true; + default: + return amd_is_spi_read_cmd_4b(op); + } +} + static bool amd_spi_supports_op(struct spi_mem *mem, const struct spi_mem_op *op) { /* bus width is number of IO lines used to transmit */ - if (op->cmd.buswidth > 1 || op->addr.buswidth > 1 || - op->data.buswidth > 1 || op->data.nbytes > AMD_SPI_MAX_DATA) + if (op->cmd.buswidth > 1 || op->addr.buswidth > 4 || op->data.nbytes > AMD_SPI_MAX_DATA) return false; + /* AMD SPI controllers support quad mode only for read operations */ + if (amd_is_spi_read_cmd(op->cmd.opcode)) { + if (op->data.buswidth > 4) + return false; + } else if (op->data.buswidth > 1) { + return false; + } + return spi_mem_default_supports_op(mem, op); } @@ -514,7 +565,7 @@ static int amd_spi_probe(struct platform_device *pdev) /* Initialize the spi_controller fields */ host->bus_num = 0; host->num_chipselect = 4; - host->mode_bits = 0; + host->mode_bits = SPI_TX_DUAL | SPI_TX_QUAD | SPI_RX_DUAL | SPI_RX_QUAD; host->flags = SPI_CONTROLLER_HALF_DUPLEX; host->max_speed_hz = AMD_SPI_MAX_HZ; host->min_speed_hz = AMD_SPI_MIN_HZ; From efd9834b86a65f9229e90727fd61a5576c08389c Mon Sep 17 00:00:00 2001 From: Raju Rangoju Date: Wed, 25 Sep 2024 19:06:39 +0530 Subject: [PATCH 03/58] spi: spi_amd: Replace ioread/iowrite calls All `ioread*` and `iowrite*` functions are better suited for architecture independent code to ensure portability across different architectures. Since AMD SoCs support only the x86 architecture, replacing all `ioread*` and `iowrite*` calls with `read*` and `write*` calls can reduce the overhead of ensuring portability and increase the speed of I/O operations. Co-developed-by: Krishnamoorthi M Signed-off-by: Krishnamoorthi M Co-developed-by: Akshata MukundShetty Signed-off-by: Akshata MukundShetty Signed-off-by: Raju Rangoju Link: https://patch.msgid.link/20240925133644.2922359-4-Raju.Rangoju@amd.com Signed-off-by: Mark Brown --- drivers/spi/spi-amd.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/spi/spi-amd.c b/drivers/spi/spi-amd.c index 17a8401216e4..1d1a18ee0bb5 100644 --- a/drivers/spi/spi-amd.c +++ b/drivers/spi/spi-amd.c @@ -114,12 +114,12 @@ struct amd_spi { static inline u8 amd_spi_readreg8(struct amd_spi *amd_spi, int idx) { - return ioread8((u8 __iomem *)amd_spi->io_remap_addr + idx); + return readb((u8 __iomem *)amd_spi->io_remap_addr + idx); } static inline void amd_spi_writereg8(struct amd_spi *amd_spi, int idx, u8 val) { - iowrite8(val, ((u8 __iomem *)amd_spi->io_remap_addr + idx)); + writeb(val, ((u8 __iomem *)amd_spi->io_remap_addr + idx)); } static void amd_spi_setclear_reg8(struct amd_spi *amd_spi, int idx, u8 set, u8 clear) @@ -132,12 +132,12 @@ static void amd_spi_setclear_reg8(struct amd_spi *amd_spi, int idx, u8 set, u8 c static inline u32 amd_spi_readreg32(struct amd_spi *amd_spi, int idx) { - return ioread32((u8 __iomem *)amd_spi->io_remap_addr + idx); + return readl((u8 __iomem *)amd_spi->io_remap_addr + idx); } static inline void amd_spi_writereg32(struct amd_spi *amd_spi, int idx, u32 val) { - iowrite32(val, ((u8 __iomem *)amd_spi->io_remap_addr + idx)); + writel(val, ((u8 __iomem *)amd_spi->io_remap_addr + idx)); } static inline void amd_spi_setclear_reg32(struct amd_spi *amd_spi, int idx, u32 set, u32 clear) From 8cd9141ad4e053d361c854cc24a18a9ca050e0a1 Mon Sep 17 00:00:00 2001 From: Raju Rangoju Date: Wed, 25 Sep 2024 19:06:40 +0530 Subject: [PATCH 04/58] spi: spi_amd: Updates to set tx/rx count functions AMD SPI TX and RX counter registers are 1-byte length registers. The existing value will be overwritten during register write, so masking is not required. Co-developed-by: Krishnamoorthi M Signed-off-by: Krishnamoorthi M Co-developed-by: Akshata MukundShetty Signed-off-by: Akshata MukundShetty Signed-off-by: Raju Rangoju Link: https://patch.msgid.link/20240925133644.2922359-5-Raju.Rangoju@amd.com Signed-off-by: Mark Brown --- drivers/spi/spi-amd.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/spi/spi-amd.c b/drivers/spi/spi-amd.c index 1d1a18ee0bb5..7841f3292a62 100644 --- a/drivers/spi/spi-amd.c +++ b/drivers/spi/spi-amd.c @@ -180,12 +180,12 @@ static int amd_spi_set_opcode(struct amd_spi *amd_spi, u8 cmd_opcode) static inline void amd_spi_set_rx_count(struct amd_spi *amd_spi, u8 rx_count) { - amd_spi_setclear_reg8(amd_spi, AMD_SPI_RX_COUNT_REG, rx_count, 0xff); + amd_spi_writereg8(amd_spi, AMD_SPI_RX_COUNT_REG, rx_count); } static inline void amd_spi_set_tx_count(struct amd_spi *amd_spi, u8 tx_count) { - amd_spi_setclear_reg8(amd_spi, AMD_SPI_TX_COUNT_REG, tx_count, 0xff); + amd_spi_writereg8(amd_spi, AMD_SPI_TX_COUNT_REG, tx_count); } static int amd_spi_busy_wait(struct amd_spi *amd_spi) From d97735d42ab00e2f9ac4bf7cd374249cde9cb193 Mon Sep 17 00:00:00 2001 From: Raju Rangoju Date: Wed, 25 Sep 2024 19:06:41 +0530 Subject: [PATCH 05/58] spi: spi_amd: Optimize IO operations Read and write the maximum number of data bytes at once, rather than byte by byte. This improves AMD SPI controller driver performance by reducing the time required to access FIFO registers. For example, with the new changes, 64 bytes of data from the FIFO queue can be read in 8 read calls (8 bytes per call) instead of 64 read calls(1 byte per call). Co-developed-by: Krishnamoorthi M Signed-off-by: Krishnamoorthi M Co-developed-by: Akshata MukundShetty Signed-off-by: Akshata MukundShetty Signed-off-by: Raju Rangoju Link: https://patch.msgid.link/20240925133644.2922359-6-Raju.Rangoju@amd.com Signed-off-by: Mark Brown --- drivers/spi/spi-amd.c | 53 +++++++++++++++++++++++++++++++++---------- 1 file changed, 41 insertions(+), 12 deletions(-) diff --git a/drivers/spi/spi-amd.c b/drivers/spi/spi-amd.c index 7841f3292a62..00fcec903d91 100644 --- a/drivers/spi/spi-amd.c +++ b/drivers/spi/spi-amd.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -140,6 +141,16 @@ static inline void amd_spi_writereg32(struct amd_spi *amd_spi, int idx, u32 val) writel(val, ((u8 __iomem *)amd_spi->io_remap_addr + idx)); } +static inline u64 amd_spi_readreg64(struct amd_spi *amd_spi, int idx) +{ + return readq((u8 __iomem *)amd_spi->io_remap_addr + idx); +} + +static inline void amd_spi_writereg64(struct amd_spi *amd_spi, int idx, u64 val) +{ + writeq(val, ((u8 __iomem *)amd_spi->io_remap_addr + idx)); +} + static inline void amd_spi_setclear_reg32(struct amd_spi *amd_spi, int idx, u32 set, u32 clear) { u32 tmp = amd_spi_readreg32(amd_spi, idx); @@ -448,15 +459,23 @@ static void amd_spi_mem_data_out(struct amd_spi *amd_spi, const struct spi_mem_op *op) { int base_addr = AMD_SPI_FIFO_BASE + op->addr.nbytes; - u8 *buf = (u8 *)op->data.buf.out; + u64 *buf_64 = (u64 *)op->data.buf.out; u32 nbytes = op->data.nbytes; + u32 left_data = nbytes; + u8 *buf; int i; amd_spi_set_opcode(amd_spi, op->cmd.opcode); amd_spi_set_addr(amd_spi, op); - for (i = 0; i < nbytes; i++) - amd_spi_writereg8(amd_spi, (base_addr + i), buf[i]); + for (i = 0; left_data >= 8; i++, left_data -= 8) + amd_spi_writereg64(amd_spi, base_addr + op->dummy.nbytes + (i * 8), *buf_64++); + + buf = (u8 *)buf_64; + for (i = 0; i < left_data; i++) { + amd_spi_writereg8(amd_spi, base_addr + op->dummy.nbytes + nbytes + i - left_data, + buf[i]); + } amd_spi_set_tx_count(amd_spi, op->addr.nbytes + op->data.nbytes); amd_spi_set_rx_count(amd_spi, 0); @@ -467,23 +486,33 @@ static void amd_spi_mem_data_out(struct amd_spi *amd_spi, static void amd_spi_mem_data_in(struct amd_spi *amd_spi, const struct spi_mem_op *op) { - int offset = (op->addr.nbytes == 0) ? 0 : 1; - u8 *buf = (u8 *)op->data.buf.in; + int base_addr = AMD_SPI_FIFO_BASE + op->addr.nbytes; + u64 *buf_64 = (u64 *)op->data.buf.in; u32 nbytes = op->data.nbytes; - int base_addr, i; - - base_addr = AMD_SPI_FIFO_BASE + op->addr.nbytes + offset; + u32 left_data = nbytes; + u8 *buf; + int i; amd_spi_set_opcode(amd_spi, op->cmd.opcode); amd_spi_set_addr(amd_spi, op); - amd_spi_set_tx_count(amd_spi, op->addr.nbytes); - amd_spi_set_rx_count(amd_spi, op->data.nbytes + 1); + amd_spi_set_tx_count(amd_spi, op->addr.nbytes + op->dummy.nbytes); + + for (i = 0; i < op->dummy.nbytes; i++) + amd_spi_writereg8(amd_spi, (base_addr + i), 0xff); + + amd_spi_set_rx_count(amd_spi, op->data.nbytes); amd_spi_clear_fifo_ptr(amd_spi); amd_spi_execute_opcode(amd_spi); amd_spi_busy_wait(amd_spi); - for (i = 0; i < nbytes; i++) - buf[i] = amd_spi_readreg8(amd_spi, base_addr + i); + for (i = 0; left_data >= 8; i++, left_data -= 8) + *buf_64++ = amd_spi_readreg64(amd_spi, base_addr + op->dummy.nbytes + + (i * 8)); + + buf = (u8 *)buf_64; + for (i = 0; i < left_data; i++) + buf[i] = amd_spi_readreg8(amd_spi, base_addr + op->dummy.nbytes + + nbytes + i - left_data); } static int amd_spi_exec_mem_op(struct spi_mem *mem, From 145d61c0ab3344f7f76f5f8cdd1134477c1def98 Mon Sep 17 00:00:00 2001 From: Raju Rangoju Date: Wed, 25 Sep 2024 19:06:42 +0530 Subject: [PATCH 06/58] spi: spi_amd: Add support for HID2 SPI controller AMD SoC has HID2 SPI controller in addition to the existing SPI0 controller(AMDI0062). Add HID2 SPI controller's ACPI ID AMDI0063 with its version ID to the list of supported devices. Use the version ID to differentiate the register offsets. And, the AMD HID2 SPI controller supports DMA read, allowing for up to 4 KB of data to be read in single transaction. Update the SPI-MEM support function to reflect this capability. Co-developed-by: Krishnamoorthi M Signed-off-by: Krishnamoorthi M Co-developed-by: Akshata MukundShetty Signed-off-by: Akshata MukundShetty Signed-off-by: Raju Rangoju Link: https://patch.msgid.link/20240925133644.2922359-7-Raju.Rangoju@amd.com Signed-off-by: Mark Brown --- drivers/spi/spi-amd.c | 42 ++++++++++++++++++++++++++++++++++++++---- 1 file changed, 38 insertions(+), 4 deletions(-) diff --git a/drivers/spi/spi-amd.c b/drivers/spi/spi-amd.c index 00fcec903d91..f146366a67e7 100644 --- a/drivers/spi/spi-amd.c +++ b/drivers/spi/spi-amd.c @@ -38,6 +38,7 @@ #define AMD_SPI_FIFO_SIZE 70 #define AMD_SPI_MEM_SIZE 200 #define AMD_SPI_MAX_DATA 64 +#define AMD_SPI_HID2_DMA_SIZE 4096 #define AMD_SPI_ENA_REG 0x20 #define AMD_SPI_ALT_SPD_SHIFT 20 @@ -70,10 +71,12 @@ * enum amd_spi_versions - SPI controller versions * @AMD_SPI_V1: AMDI0061 hardware version * @AMD_SPI_V2: AMDI0062 hardware version + * @AMD_HID2_SPI: AMDI0063 hardware version */ enum amd_spi_versions { AMD_SPI_V1 = 1, AMD_SPI_V2, + AMD_HID2_SPI, }; enum amd_spi_speed { @@ -182,6 +185,7 @@ static int amd_spi_set_opcode(struct amd_spi *amd_spi, u8 cmd_opcode) AMD_SPI_OPCODE_MASK); return 0; case AMD_SPI_V2: + case AMD_HID2_SPI: amd_spi_writereg8(amd_spi, AMD_SPI_OPCODE_REG, cmd_opcode); return 0; default: @@ -209,6 +213,7 @@ static int amd_spi_busy_wait(struct amd_spi *amd_spi) reg = AMD_SPI_CTRL0_REG; break; case AMD_SPI_V2: + case AMD_HID2_SPI: reg = AMD_SPI_STATUS_REG; break; default: @@ -234,6 +239,7 @@ static int amd_spi_execute_opcode(struct amd_spi *amd_spi) AMD_SPI_EXEC_CMD); return 0; case AMD_SPI_V2: + case AMD_HID2_SPI: /* Trigger the command execution */ amd_spi_setclear_reg8(amd_spi, AMD_SPI_CMD_TRIGGER_REG, AMD_SPI_TRIGGER_CMD, AMD_SPI_TRIGGER_CMD); @@ -375,6 +381,7 @@ static inline int amd_spi_fifo_xfer(struct amd_spi *amd_spi, case AMD_SPI_V1: break; case AMD_SPI_V2: + case AMD_HID2_SPI: amd_spi_clear_chip(amd_spi, spi_get_chipselect(message->spi, 0)); break; default: @@ -418,15 +425,29 @@ static inline bool amd_is_spi_read_cmd(const u16 op) static bool amd_spi_supports_op(struct spi_mem *mem, const struct spi_mem_op *op) { + struct amd_spi *amd_spi = spi_controller_get_devdata(mem->spi->controller); + /* bus width is number of IO lines used to transmit */ - if (op->cmd.buswidth > 1 || op->addr.buswidth > 4 || op->data.nbytes > AMD_SPI_MAX_DATA) + if (op->cmd.buswidth > 1 || op->addr.buswidth > 4) return false; /* AMD SPI controllers support quad mode only for read operations */ if (amd_is_spi_read_cmd(op->cmd.opcode)) { if (op->data.buswidth > 4) return false; - } else if (op->data.buswidth > 1) { + + /* + * HID2 SPI controller supports DMA read up to 4K bytes and + * doesn't support 4-byte address commands. + */ + if (amd_spi->version == AMD_HID2_SPI) { + if (amd_is_spi_read_cmd_4b(op->cmd.opcode) || + op->data.nbytes > AMD_SPI_HID2_DMA_SIZE) + return false; + } else if (op->data.nbytes > AMD_SPI_MAX_DATA) { + return false; + } + } else if (op->data.buswidth > 1 || op->data.nbytes > AMD_SPI_MAX_DATA) { return false; } @@ -435,7 +456,19 @@ static bool amd_spi_supports_op(struct spi_mem *mem, static int amd_spi_adjust_op_size(struct spi_mem *mem, struct spi_mem_op *op) { - op->data.nbytes = clamp_val(op->data.nbytes, 0, AMD_SPI_MAX_DATA); + struct amd_spi *amd_spi = spi_controller_get_devdata(mem->spi->controller); + + /* + * HID2 SPI controller DMA read mode supports reading up to 4k + * bytes in single transaction, where as SPI0 and HID2 SPI + * controller index mode supports maximum of 64 bytes in a single + * transaction. + */ + if (amd_spi->version == AMD_HID2_SPI && amd_is_spi_read_cmd(op->cmd.opcode)) + op->data.nbytes = clamp_val(op->data.nbytes, 0, AMD_SPI_HID2_DMA_SIZE); + else + op->data.nbytes = clamp_val(op->data.nbytes, 0, AMD_SPI_MAX_DATA); + return 0; } @@ -592,7 +625,7 @@ static int amd_spi_probe(struct platform_device *pdev) amd_spi->version = (uintptr_t) device_get_match_data(dev); /* Initialize the spi_controller fields */ - host->bus_num = 0; + host->bus_num = (amd_spi->version == AMD_HID2_SPI) ? 2 : 0; host->num_chipselect = 4; host->mode_bits = SPI_TX_DUAL | SPI_TX_QUAD | SPI_RX_DUAL | SPI_RX_QUAD; host->flags = SPI_CONTROLLER_HALF_DUPLEX; @@ -616,6 +649,7 @@ static int amd_spi_probe(struct platform_device *pdev) static const struct acpi_device_id spi_acpi_match[] = { { "AMDI0061", AMD_SPI_V1 }, { "AMDI0062", AMD_SPI_V2 }, + { "AMDI0063", AMD_HID2_SPI }, {}, }; MODULE_DEVICE_TABLE(acpi, spi_acpi_match); From 9674f1694e644aa5cc50e1009481cb4c5b4e8f8f Mon Sep 17 00:00:00 2001 From: Raju Rangoju Date: Wed, 25 Sep 2024 19:06:43 +0530 Subject: [PATCH 07/58] spi: spi_amd: Set controller address mode Add changes to set the controller address mode before initiating commands. The AMD SPI0 controller(AMDI0062) supports both 24-bit and 32-bit address modes, while the HID2 SPI controller(AMDI0063) supports only the 24-bit address mode. So this change is applicable only for SPI0 controller. Co-developed-by: Krishnamoorthi M Signed-off-by: Krishnamoorthi M Co-developed-by: Akshata MukundShetty Signed-off-by: Akshata MukundShetty Signed-off-by: Raju Rangoju Link: https://patch.msgid.link/20240925133644.2922359-8-Raju.Rangoju@amd.com Signed-off-by: Mark Brown --- drivers/spi/spi-amd.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/drivers/spi/spi-amd.c b/drivers/spi/spi-amd.c index f146366a67e7..50dfdf2ab6ee 100644 --- a/drivers/spi/spi-amd.c +++ b/drivers/spi/spi-amd.c @@ -34,6 +34,7 @@ #define AMD_SPI_TX_COUNT_REG 0x48 #define AMD_SPI_RX_COUNT_REG 0x4B #define AMD_SPI_STATUS_REG 0x4C +#define AMD_SPI_ADDR32CTRL_REG 0x50 #define AMD_SPI_FIFO_SIZE 70 #define AMD_SPI_MEM_SIZE 200 @@ -548,6 +549,17 @@ static void amd_spi_mem_data_in(struct amd_spi *amd_spi, nbytes + i - left_data); } +static void amd_set_spi_addr_mode(struct amd_spi *amd_spi, + const struct spi_mem_op *op) +{ + u32 val = amd_spi_readreg32(amd_spi, AMD_SPI_ADDR32CTRL_REG); + + if (amd_is_spi_read_cmd_4b(op->cmd.opcode)) + amd_spi_writereg32(amd_spi, AMD_SPI_ADDR32CTRL_REG, val | BIT(0)); + else + amd_spi_writereg32(amd_spi, AMD_SPI_ADDR32CTRL_REG, val & ~BIT(0)); +} + static int amd_spi_exec_mem_op(struct spi_mem *mem, const struct spi_mem_op *op) { @@ -560,6 +572,9 @@ static int amd_spi_exec_mem_op(struct spi_mem *mem, if (ret) return ret; + if (amd_spi->version == AMD_SPI_V2) + amd_set_spi_addr_mode(amd_spi, op); + switch (op->data.dir) { case SPI_MEM_DATA_IN: amd_spi_mem_data_in(amd_spi, op); From 6c30eee359127c31cd8c6b586c8c3ced9f50f74b Mon Sep 17 00:00:00 2001 From: Raju Rangoju Date: Wed, 25 Sep 2024 19:06:44 +0530 Subject: [PATCH 08/58] spi: spi_amd: Add HIDDMA basic read support SPI index mode has hardware limitation of reading only 64 bytes per transaction due to fixed number of FIFO registers. This constraint leads to performance issues when reading data from NAND/NOR flash devices, as the controller must issue multiple requests to read 64-byte chunks, even if the slave can send up to 2 or 4 KB in single transaction. The AMD HID2 SPI controller supports DMA mode, which allows reading up to 4 KB of data in single transaction. This patch introduces changes to implement HID2 DMA read support for the HID2 SPI controller. Co-developed-by: Krishnamoorthi M Signed-off-by: Krishnamoorthi M Co-developed-by: Akshata MukundShetty Signed-off-by: Akshata MukundShetty Signed-off-by: Raju Rangoju Link: https://patch.msgid.link/20240925133644.2922359-9-Raju.Rangoju@amd.com Signed-off-by: Mark Brown --- drivers/spi/spi-amd.c | 170 +++++++++++++++++++++++++++++++++++++----- 1 file changed, 153 insertions(+), 17 deletions(-) diff --git a/drivers/spi/spi-amd.c b/drivers/spi/spi-amd.c index 50dfdf2ab6ee..d30a21b0b05f 100644 --- a/drivers/spi/spi-amd.c +++ b/drivers/spi/spi-amd.c @@ -8,6 +8,7 @@ #include #include +#include #include #include #include @@ -50,9 +51,21 @@ #define AMD_SPI_SPD7_SHIFT 8 #define AMD_SPI_SPD7_MASK GENMASK(13, AMD_SPI_SPD7_SHIFT) +#define AMD_SPI_HID2_INPUT_RING_BUF0 0X100 +#define AMD_SPI_HID2_CNTRL 0x150 +#define AMD_SPI_HID2_INT_STATUS 0x154 +#define AMD_SPI_HID2_CMD_START 0x156 +#define AMD_SPI_HID2_INT_MASK 0x158 +#define AMD_SPI_HID2_READ_CNTRL0 0x170 +#define AMD_SPI_HID2_READ_CNTRL1 0x174 +#define AMD_SPI_HID2_READ_CNTRL2 0x180 + #define AMD_SPI_MAX_HZ 100000000 #define AMD_SPI_MIN_HZ 800000 +#define AMD_SPI_IO_SLEEP_US 20 +#define AMD_SPI_IO_TIMEOUT_US 2000000 + /* SPI read command opcodes */ #define AMD_SPI_OP_READ 0x03 /* Read data bytes (low frequency) */ #define AMD_SPI_OP_READ_FAST 0x0b /* Read data bytes (high frequency) */ @@ -108,11 +121,15 @@ struct amd_spi_freq { /** * struct amd_spi - SPI driver instance * @io_remap_addr: Start address of the SPI controller registers + * @phy_dma_buf: Physical address of DMA buffer + * @dma_virt_addr: Virtual address of DMA buffer * @version: SPI controller hardware version * @speed_hz: Device frequency */ struct amd_spi { void __iomem *io_remap_addr; + dma_addr_t phy_dma_buf; + void *dma_virt_addr; enum amd_spi_versions version; unsigned int speed_hz; }; @@ -135,6 +152,16 @@ static void amd_spi_setclear_reg8(struct amd_spi *amd_spi, int idx, u8 set, u8 c amd_spi_writereg8(amd_spi, idx, tmp); } +static inline u16 amd_spi_readreg16(struct amd_spi *amd_spi, int idx) +{ + return readw((u8 __iomem *)amd_spi->io_remap_addr + idx); +} + +static inline void amd_spi_writereg16(struct amd_spi *amd_spi, int idx, u16 val) +{ + writew(val, ((u8 __iomem *)amd_spi->io_remap_addr + idx)); +} + static inline u32 amd_spi_readreg32(struct amd_spi *amd_spi, int idx) { return readl((u8 __iomem *)amd_spi->io_remap_addr + idx); @@ -517,6 +544,64 @@ static void amd_spi_mem_data_out(struct amd_spi *amd_spi, amd_spi_execute_opcode(amd_spi); } +static void amd_spi_hiddma_read(struct amd_spi *amd_spi, const struct spi_mem_op *op) +{ + u16 hid_cmd_start, val; + u32 hid_regval; + + /* Set the opcode in hid2_read_control0 register */ + hid_regval = amd_spi_readreg32(amd_spi, AMD_SPI_HID2_READ_CNTRL0); + hid_regval = (hid_regval & ~GENMASK(7, 0)) | op->cmd.opcode; + + /* + * Program the address in the hid2_read_control0 register [8:31]. The address should + * be written starting from the 8th bit of the register, requiring an 8-bit shift. + * Additionally, to convert a 2-byte spinand address to a 3-byte address, another + * 8-bit shift is needed. Therefore, a total shift of 16 bits is required. + */ + hid_regval = (hid_regval & ~GENMASK(31, 8)) | (op->addr.val << 16); + amd_spi_writereg32(amd_spi, AMD_SPI_HID2_READ_CNTRL0, hid_regval); + + /* Configure dummy clock cycles for fast read, dual, quad I/O commands */ + hid_regval = amd_spi_readreg32(amd_spi, AMD_SPI_HID2_READ_CNTRL2); + /* Fast read dummy cycle */ + hid_regval &= ~GENMASK(4, 0); + + /* Fast read Dual I/O dummy cycle */ + hid_regval &= ~GENMASK(12, 8); + + /* Fast read Quad I/O dummy cycle */ + hid_regval = (hid_regval & ~GENMASK(20, 16)) | BIT(17); + + /* Set no of preamble bytecount */ + hid_regval &= ~GENMASK(27, 24); + amd_spi_writereg32(amd_spi, AMD_SPI_HID2_READ_CNTRL2, hid_regval); + + /* + * Program the HID2 Input Ring Buffer0. 4k aligned buf_memory_addr[31:12], + * buf_size[4:0], end_input_ring[5]. + */ + hid_regval = amd_spi->phy_dma_buf | BIT(5) | BIT(0); + amd_spi_writereg32(amd_spi, AMD_SPI_HID2_INPUT_RING_BUF0, hid_regval); + + /* Program max read length(no of DWs) in hid2_read_control1 register */ + hid_regval = amd_spi_readreg32(amd_spi, AMD_SPI_HID2_READ_CNTRL1); + hid_regval = (hid_regval & ~GENMASK(15, 0)) | ((op->data.nbytes / 4) - 1); + amd_spi_writereg32(amd_spi, AMD_SPI_HID2_READ_CNTRL1, hid_regval); + + /* Set cmd start bit in hid2_cmd_start register to trigger HID basic read operation */ + hid_cmd_start = amd_spi_readreg16(amd_spi, AMD_SPI_HID2_CMD_START); + amd_spi_writereg16(amd_spi, AMD_SPI_HID2_CMD_START, (hid_cmd_start | BIT(3))); + + /* Check interrupt status of HIDDMA basic read operation in hid2_int_status register */ + readw_poll_timeout(amd_spi->io_remap_addr + AMD_SPI_HID2_INT_STATUS, val, + (val & BIT(3)), AMD_SPI_IO_SLEEP_US, AMD_SPI_IO_TIMEOUT_US); + + /* Clear the interrupts by writing to hid2_int_status register */ + val = amd_spi_readreg16(amd_spi, AMD_SPI_HID2_INT_STATUS); + amd_spi_writereg16(amd_spi, AMD_SPI_HID2_INT_STATUS, val); +} + static void amd_spi_mem_data_in(struct amd_spi *amd_spi, const struct spi_mem_op *op) { @@ -524,29 +609,52 @@ static void amd_spi_mem_data_in(struct amd_spi *amd_spi, u64 *buf_64 = (u64 *)op->data.buf.in; u32 nbytes = op->data.nbytes; u32 left_data = nbytes; + u32 data; u8 *buf; int i; - amd_spi_set_opcode(amd_spi, op->cmd.opcode); - amd_spi_set_addr(amd_spi, op); - amd_spi_set_tx_count(amd_spi, op->addr.nbytes + op->dummy.nbytes); + /* + * Condition for using HID read mode. Only for reading complete page data, use HID read. + * Use index mode otherwise. + */ + if (amd_spi->version == AMD_HID2_SPI && amd_is_spi_read_cmd(op->cmd.opcode)) { + amd_spi_hiddma_read(amd_spi, op); - for (i = 0; i < op->dummy.nbytes; i++) - amd_spi_writereg8(amd_spi, (base_addr + i), 0xff); + for (i = 0; left_data >= 8; i++, left_data -= 8) + *buf_64++ = readq((u8 __iomem *)amd_spi->dma_virt_addr + (i * 8)); - amd_spi_set_rx_count(amd_spi, op->data.nbytes); - amd_spi_clear_fifo_ptr(amd_spi); - amd_spi_execute_opcode(amd_spi); - amd_spi_busy_wait(amd_spi); + buf = (u8 *)buf_64; + for (i = 0; i < left_data; i++) + buf[i] = readb((u8 __iomem *)amd_spi->dma_virt_addr + + (nbytes - left_data + i)); - for (i = 0; left_data >= 8; i++, left_data -= 8) - *buf_64++ = amd_spi_readreg64(amd_spi, base_addr + op->dummy.nbytes + - (i * 8)); + /* Reset HID RX memory logic */ + data = amd_spi_readreg32(amd_spi, AMD_SPI_HID2_CNTRL); + amd_spi_writereg32(amd_spi, AMD_SPI_HID2_CNTRL, data | BIT(5)); + } else { + /* Index mode */ + amd_spi_set_opcode(amd_spi, op->cmd.opcode); + amd_spi_set_addr(amd_spi, op); + amd_spi_set_tx_count(amd_spi, op->addr.nbytes + op->dummy.nbytes); + + for (i = 0; i < op->dummy.nbytes; i++) + amd_spi_writereg8(amd_spi, (base_addr + i), 0xff); + + amd_spi_set_rx_count(amd_spi, op->data.nbytes); + amd_spi_clear_fifo_ptr(amd_spi); + amd_spi_execute_opcode(amd_spi); + amd_spi_busy_wait(amd_spi); + + for (i = 0; left_data >= 8; i++, left_data -= 8) + *buf_64++ = amd_spi_readreg64(amd_spi, base_addr + op->dummy.nbytes + + (i * 8)); + + buf = (u8 *)buf_64; + for (i = 0; i < left_data; i++) + buf[i] = amd_spi_readreg8(amd_spi, base_addr + op->dummy.nbytes + + nbytes + i - left_data); + } - buf = (u8 *)buf_64; - for (i = 0; i < left_data; i++) - buf[i] = amd_spi_readreg8(amd_spi, base_addr + op->dummy.nbytes + - nbytes + i - left_data); } static void amd_set_spi_addr_mode(struct amd_spi *amd_spi, @@ -617,6 +725,31 @@ static size_t amd_spi_max_transfer_size(struct spi_device *spi) return AMD_SPI_FIFO_SIZE; } +static int amd_spi_setup_hiddma(struct amd_spi *amd_spi, struct device *dev) +{ + u32 hid_regval; + + /* Allocate DMA buffer to use for HID basic read operation */ + amd_spi->dma_virt_addr = dma_alloc_coherent(dev, AMD_SPI_HID2_DMA_SIZE, + &amd_spi->phy_dma_buf, GFP_KERNEL); + if (!amd_spi->dma_virt_addr) + return -ENOMEM; + + /* + * Enable interrupts and set mask bits in hid2_int_mask register to generate interrupt + * properly for HIDDMA basic read operations. + */ + hid_regval = amd_spi_readreg32(amd_spi, AMD_SPI_HID2_INT_MASK); + hid_regval = (hid_regval & GENMASK(31, 8)) | BIT(19); + amd_spi_writereg32(amd_spi, AMD_SPI_HID2_INT_MASK, hid_regval); + + /* Configure buffer unit(4k) in hid2_control register */ + hid_regval = amd_spi_readreg32(amd_spi, AMD_SPI_HID2_CNTRL); + amd_spi_writereg32(amd_spi, AMD_SPI_HID2_CNTRL, hid_regval & ~BIT(3)); + + return 0; +} + static int amd_spi_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -657,7 +790,10 @@ static int amd_spi_probe(struct platform_device *pdev) if (err) return dev_err_probe(dev, err, "error registering SPI controller\n"); - return 0; + if (amd_spi->version == AMD_HID2_SPI) + err = amd_spi_setup_hiddma(amd_spi, dev); + + return err; } #ifdef CONFIG_ACPI From 5ba92299badc4e71670269877262c8cc3b6c806f Mon Sep 17 00:00:00 2001 From: Yang Yingliang Date: Mon, 2 Sep 2024 20:59:41 +0800 Subject: [PATCH 09/58] media: usb/msi2500: switch to use spi_alloc_host() Switch to use modern name function spi_alloc_host(). No functional changed. Signed-off-by: Yang Yingliang Link: https://patch.msgid.link/20240902125947.1368-2-yangyingliang@huaweicloud.com Signed-off-by: Mark Brown --- drivers/media/usb/msi2500/msi2500.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/media/usb/msi2500/msi2500.c b/drivers/media/usb/msi2500/msi2500.c index 5138486abfa0..05b0550e840c 100644 --- a/drivers/media/usb/msi2500/msi2500.c +++ b/drivers/media/usb/msi2500/msi2500.c @@ -1219,8 +1219,8 @@ static int msi2500_probe(struct usb_interface *intf, goto err_free_mem; } - /* SPI master adapter */ - ctlr = spi_alloc_master(dev->dev, 0); + /* SPI host adapter */ + ctlr = spi_alloc_host(dev->dev, 0); if (ctlr == NULL) { ret = -ENOMEM; goto err_unregister_v4l2_dev; From ac2f5bbe80e143509cf24527a7ae021f356f8977 Mon Sep 17 00:00:00 2001 From: Yang Yingliang Date: Mon, 2 Sep 2024 20:59:42 +0800 Subject: [PATCH 10/58] media: netup_unidvb: switch to use devm_spi_alloc_host() Switch to use modern name function devm_spi_alloc_host(). No functional changed. Signed-off-by: Yang Yingliang Link: https://patch.msgid.link/20240902125947.1368-3-yangyingliang@huaweicloud.com Signed-off-by: Mark Brown --- drivers/media/pci/netup_unidvb/netup_unidvb_spi.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/media/pci/netup_unidvb/netup_unidvb_spi.c b/drivers/media/pci/netup_unidvb/netup_unidvb_spi.c index e90aa1c1584c..34d6d52f1e4e 100644 --- a/drivers/media/pci/netup_unidvb/netup_unidvb_spi.c +++ b/drivers/media/pci/netup_unidvb/netup_unidvb_spi.c @@ -175,11 +175,11 @@ int netup_spi_init(struct netup_unidvb_dev *ndev) struct spi_controller *ctlr; struct netup_spi *nspi; - ctlr = devm_spi_alloc_master(&ndev->pci_dev->dev, - sizeof(struct netup_spi)); + ctlr = devm_spi_alloc_host(&ndev->pci_dev->dev, + sizeof(struct netup_spi)); if (!ctlr) { dev_err(&ndev->pci_dev->dev, - "%s(): unable to alloc SPI master\n", __func__); + "%s(): unable to alloc SPI host\n", __func__); return -EINVAL; } nspi = spi_controller_get_devdata(ctlr); From 0191e98ae6e22bebae4e9a487ba70f90d2f8714c Mon Sep 17 00:00:00 2001 From: Yang Yingliang Date: Mon, 2 Sep 2024 20:59:43 +0800 Subject: [PATCH 11/58] spi: ch341: switch to use devm_spi_alloc_host() Switch to use modern name function devm_spi_alloc_host(). No functional changed. Signed-off-by: Yang Yingliang Link: https://patch.msgid.link/20240902125947.1368-4-yangyingliang@huaweicloud.com Signed-off-by: Mark Brown --- drivers/spi/spi-ch341.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/spi/spi-ch341.c b/drivers/spi/spi-ch341.c index d2351812d310..46bc208f2d05 100644 --- a/drivers/spi/spi-ch341.c +++ b/drivers/spi/spi-ch341.c @@ -152,7 +152,7 @@ static int ch341_probe(struct usb_interface *intf, if (ret) return ret; - ctrl = devm_spi_alloc_master(&udev->dev, sizeof(struct ch341_spi_dev)); + ctrl = devm_spi_alloc_host(&udev->dev, sizeof(struct ch341_spi_dev)); if (!ctrl) return -ENOMEM; From 4bca15a56edd7b1c8c8573ddd3dd67424ec15e11 Mon Sep 17 00:00:00 2001 From: Yang Yingliang Date: Mon, 2 Sep 2024 20:59:44 +0800 Subject: [PATCH 12/58] spi: slave-mt27xx: switch to use spi_alloc_target() Switch to use modern name function spi_alloc_target(). No functional changed. Signed-off-by: Yang Yingliang Link: https://patch.msgid.link/20240902125947.1368-5-yangyingliang@huaweicloud.com Signed-off-by: Mark Brown --- drivers/spi/spi-slave-mt27xx.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/spi/spi-slave-mt27xx.c b/drivers/spi/spi-slave-mt27xx.c index 4a91b7bae3c6..00d455dad135 100644 --- a/drivers/spi/spi-slave-mt27xx.c +++ b/drivers/spi/spi-slave-mt27xx.c @@ -388,9 +388,9 @@ static int mtk_spi_slave_probe(struct platform_device *pdev) int irq, ret; const struct of_device_id *of_id; - ctlr = spi_alloc_slave(&pdev->dev, sizeof(*mdata)); + ctlr = spi_alloc_target(&pdev->dev, sizeof(*mdata)); if (!ctlr) { - dev_err(&pdev->dev, "failed to alloc spi slave\n"); + dev_err(&pdev->dev, "failed to alloc spi target\n"); return -ENOMEM; } From 5c303090e1d8426c721709d50f0120f66bae6919 Mon Sep 17 00:00:00 2001 From: Yang Yingliang Date: Mon, 2 Sep 2024 20:59:45 +0800 Subject: [PATCH 13/58] video: fbdev: mmp: switch to use spi_alloc_host() Switch to use modern name function spi_alloc_host(). No functional changed. Signed-off-by: Yang Yingliang Link: https://patch.msgid.link/20240902125947.1368-6-yangyingliang@huaweicloud.com Signed-off-by: Mark Brown --- drivers/video/fbdev/mmp/hw/mmp_spi.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/video/fbdev/mmp/hw/mmp_spi.c b/drivers/video/fbdev/mmp/hw/mmp_spi.c index cf23650d7f0b..3f253f4271ac 100644 --- a/drivers/video/fbdev/mmp/hw/mmp_spi.c +++ b/drivers/video/fbdev/mmp/hw/mmp_spi.c @@ -140,9 +140,9 @@ int lcd_spi_register(struct mmphw_ctrl *ctrl) void **p_regbase; int err; - ctlr = spi_alloc_master(ctrl->dev, sizeof(void *)); + ctlr = spi_alloc_host(ctrl->dev, sizeof(void *)); if (!ctlr) { - dev_err(ctrl->dev, "unable to allocate SPI master\n"); + dev_err(ctrl->dev, "unable to allocate SPI host\n"); return -ENOMEM; } p_regbase = spi_controller_get_devdata(ctlr); @@ -156,7 +156,7 @@ int lcd_spi_register(struct mmphw_ctrl *ctrl) err = spi_register_controller(ctlr); if (err < 0) { - dev_err(ctrl->dev, "unable to register SPI master\n"); + dev_err(ctrl->dev, "unable to register SPI host\n"); spi_controller_put(ctlr); return err; } From 0809a9ccac4a2ffdfd1561bb551aec6099775545 Mon Sep 17 00:00:00 2001 From: Yang Yingliang Date: Mon, 2 Sep 2024 20:59:47 +0800 Subject: [PATCH 14/58] spi: remove {devm_}spi_alloc_master/slave() All the {devm_}spi_alloc_master/slave() have been replaced, so they can be removed and replaced in doc and comment. No functional changed. Signed-off-by: Yang Yingliang Link: https://patch.msgid.link/20240902125947.1368-8-yangyingliang@huaweicloud.com Signed-off-by: Mark Brown --- .../driver-api/driver-model/devres.rst | 4 +-- drivers/spi/spi.c | 14 ++++----- include/linux/spi/spi.h | 30 ------------------- 3 files changed, 9 insertions(+), 39 deletions(-) diff --git a/Documentation/driver-api/driver-model/devres.rst b/Documentation/driver-api/driver-model/devres.rst index 5f2ee8d717b1..ebbf8e4cc85f 100644 --- a/Documentation/driver-api/driver-model/devres.rst +++ b/Documentation/driver-api/driver-model/devres.rst @@ -462,8 +462,8 @@ SLAVE DMA ENGINE devm_acpi_dma_controller_free() SPI - devm_spi_alloc_master() - devm_spi_alloc_slave() + devm_spi_alloc_host() + devm_spi_alloc_target() devm_spi_optimize_message() devm_spi_register_controller() devm_spi_register_host() diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index c1dad30a4528..073ffae97767 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -3238,9 +3238,9 @@ static int spi_controller_id_alloc(struct spi_controller *ctlr, int start, int e } /** - * spi_register_controller - register SPI master or slave controller - * @ctlr: initialized master, originally from spi_alloc_master() or - * spi_alloc_slave() + * spi_register_controller - register SPI host or target controller + * @ctlr: initialized controller, originally from spi_alloc_host() or + * spi_alloc_target() * Context: can sleep * * SPI controllers connect to their drivers using some non-SPI bus, @@ -3390,11 +3390,11 @@ static void devm_spi_unregister(struct device *dev, void *res) } /** - * devm_spi_register_controller - register managed SPI master or slave + * devm_spi_register_controller - register managed SPI host or target * controller * @dev: device managing SPI controller - * @ctlr: initialized controller, originally from spi_alloc_master() or - * spi_alloc_slave() + * @ctlr: initialized controller, originally from spi_alloc_host() or + * spi_alloc_target() * Context: can sleep * * Register a SPI device as with spi_register_controller() which will @@ -3478,7 +3478,7 @@ void spi_unregister_controller(struct spi_controller *ctlr) /* * Release the last reference on the controller if its driver - * has not yet been converted to devm_spi_alloc_master/slave(). + * has not yet been converted to devm_spi_alloc_host/target(). */ if (!ctlr->devm_allocated) put_device(&ctlr->dev); diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h index 4b95663163e0..8497f4747e24 100644 --- a/include/linux/spi/spi.h +++ b/include/linux/spi/spi.h @@ -824,21 +824,6 @@ void spi_take_timestamp_post(struct spi_controller *ctlr, extern struct spi_controller *__spi_alloc_controller(struct device *host, unsigned int size, bool slave); -static inline struct spi_controller *spi_alloc_master(struct device *host, - unsigned int size) -{ - return __spi_alloc_controller(host, size, false); -} - -static inline struct spi_controller *spi_alloc_slave(struct device *host, - unsigned int size) -{ - if (!IS_ENABLED(CONFIG_SPI_SLAVE)) - return NULL; - - return __spi_alloc_controller(host, size, true); -} - static inline struct spi_controller *spi_alloc_host(struct device *dev, unsigned int size) { @@ -858,21 +843,6 @@ struct spi_controller *__devm_spi_alloc_controller(struct device *dev, unsigned int size, bool slave); -static inline struct spi_controller *devm_spi_alloc_master(struct device *dev, - unsigned int size) -{ - return __devm_spi_alloc_controller(dev, size, false); -} - -static inline struct spi_controller *devm_spi_alloc_slave(struct device *dev, - unsigned int size) -{ - if (!IS_ENABLED(CONFIG_SPI_SLAVE)) - return NULL; - - return __devm_spi_alloc_controller(dev, size, true); -} - static inline struct spi_controller *devm_spi_alloc_host(struct device *dev, unsigned int size) { From d87ec94e48dd2da27fbe948f2dc6c8fedc98fff4 Mon Sep 17 00:00:00 2001 From: Dragan Simic Date: Thu, 26 Sep 2024 10:38:12 +0200 Subject: [PATCH 15/58] spi: rockchip: Perform trivial code cleanups Perform a few trivial code cleanups, to obey the reverse Christmas tree rule, to avoid unnecessary line wrapping by using the 100-column width better, to actually obey the 100-column width in one case, and to make the way a couple of wrapped function arguments are indented a bit more readable. No intended functional changes are introduced by these code cleanups. Signed-off-by: Dragan Simic Reviewed-by: Heiko Stuebner Link: https://patch.msgid.link/663ec6bb472ab83bb5824a09d11b36ef20a43fc7.1727337732.git.dsimic@manjaro.org Signed-off-by: Mark Brown --- drivers/spi/spi-rockchip.c | 29 +++++++++++++---------------- 1 file changed, 13 insertions(+), 16 deletions(-) diff --git a/drivers/spi/spi-rockchip.c b/drivers/spi/spi-rockchip.c index 0bb33c43b1b4..81046f7b7591 100644 --- a/drivers/spi/spi-rockchip.c +++ b/drivers/spi/spi-rockchip.c @@ -742,22 +742,20 @@ static int rockchip_spi_setup(struct spi_device *spi) static int rockchip_spi_probe(struct platform_device *pdev) { - int ret; - struct rockchip_spi *rs; - struct spi_controller *ctlr; - struct resource *mem; struct device_node *np = pdev->dev.of_node; + struct spi_controller *ctlr; + struct rockchip_spi *rs; + struct resource *mem; u32 rsd_nsecs, num_cs; bool target_mode; + int ret; target_mode = of_property_read_bool(np, "spi-slave"); if (target_mode) - ctlr = spi_alloc_target(&pdev->dev, - sizeof(struct rockchip_spi)); + ctlr = spi_alloc_target(&pdev->dev, sizeof(struct rockchip_spi)); else - ctlr = spi_alloc_host(&pdev->dev, - sizeof(struct rockchip_spi)); + ctlr = spi_alloc_host(&pdev->dev, sizeof(struct rockchip_spi)); if (!ctlr) return -ENOMEM; @@ -769,7 +767,7 @@ static int rockchip_spi_probe(struct platform_device *pdev) /* Get basic io resource and map it */ rs->regs = devm_platform_get_and_ioremap_resource(pdev, 0, &mem); if (IS_ERR(rs->regs)) { - ret = PTR_ERR(rs->regs); + ret = PTR_ERR(rs->regs); goto err_put_ctlr; } @@ -794,7 +792,7 @@ static int rockchip_spi_probe(struct platform_device *pdev) goto err_put_ctlr; ret = devm_request_threaded_irq(&pdev->dev, ret, rockchip_spi_isr, NULL, - IRQF_ONESHOT, dev_name(&pdev->dev), ctlr); + IRQF_ONESHOT, dev_name(&pdev->dev), ctlr); if (ret) goto err_put_ctlr; @@ -804,16 +802,15 @@ static int rockchip_spi_probe(struct platform_device *pdev) if (!of_property_read_u32(pdev->dev.of_node, "rx-sample-delay-ns", &rsd_nsecs)) { /* rx sample delay is expressed in parent clock cycles (max 3) */ - u32 rsd = DIV_ROUND_CLOSEST(rsd_nsecs * (rs->freq >> 8), - 1000000000 >> 8); + u32 rsd = DIV_ROUND_CLOSEST(rsd_nsecs * (rs->freq >> 8), 1000000000 >> 8); if (!rsd) { dev_warn(rs->dev, "%u Hz are too slow to express %u ns delay\n", - rs->freq, rsd_nsecs); + rs->freq, rsd_nsecs); } else if (rsd > CR0_RSD_MAX) { rsd = CR0_RSD_MAX; - dev_warn(rs->dev, "%u Hz are too fast to express %u ns delay, clamping at %u ns\n", - rs->freq, rsd_nsecs, - CR0_RSD_MAX * 1000000000U / rs->freq); + dev_warn(rs->dev, + "%u Hz are too fast to express %u ns delay, clamping at %u ns\n", + rs->freq, rsd_nsecs, CR0_RSD_MAX * 1000000000U / rs->freq); } rs->rsd = rsd; } From 6c510eac1528d8939bad8b6df72c7b23ffec8c25 Mon Sep 17 00:00:00 2001 From: Dragan Simic Date: Thu, 26 Sep 2024 10:38:13 +0200 Subject: [PATCH 16/58] spi: rockchip-sfc: Perform trivial code cleanups Perform a couple of trivial code cleanups, to avoid unnecessary line wrapping by using the 100-column width a bit better, and to drop a stray empty line. No intended functional changes are introduced by these code cleanups. Signed-off-by: Dragan Simic Reviewed-by: Heiko Stuebner Link: https://patch.msgid.link/251242bfc9c4fdc01d930f093022ce0c9481d58e.1727337732.git.dsimic@manjaro.org Signed-off-by: Mark Brown --- drivers/spi/spi-rockchip-sfc.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/drivers/spi/spi-rockchip-sfc.c b/drivers/spi/spi-rockchip-sfc.c index 0d7fadcd4ed3..505d5089bf03 100644 --- a/drivers/spi/spi-rockchip-sfc.c +++ b/drivers/spi/spi-rockchip-sfc.c @@ -591,8 +591,7 @@ static int rockchip_sfc_probe(struct platform_device *pdev) return PTR_ERR(sfc->hclk); } - sfc->use_dma = !of_property_read_bool(sfc->dev->of_node, - "rockchip,sfc-no-dma"); + sfc->use_dma = !of_property_read_bool(sfc->dev->of_node, "rockchip,sfc-no-dma"); if (sfc->use_dma) { ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32)); @@ -602,8 +601,7 @@ static int rockchip_sfc_probe(struct platform_device *pdev) } sfc->buffer = dmam_alloc_coherent(dev, SFC_MAX_IOSIZE_VER3, - &sfc->dma_buffer, - GFP_KERNEL); + &sfc->dma_buffer, GFP_KERNEL); if (!sfc->buffer) return -ENOMEM; } @@ -629,7 +627,6 @@ static int rockchip_sfc_probe(struct platform_device *pdev) 0, pdev->name, sfc); if (ret) { dev_err(dev, "Failed to request irq\n"); - goto err_irq; } From 1482c40b440fa58f956bc3e1ef3426e0cdbc09e0 Mon Sep 17 00:00:00 2001 From: Dragan Simic Date: Thu, 26 Sep 2024 10:38:16 +0200 Subject: [PATCH 17/58] spi: rockchip-sfc: Use dev_err_probe() in the probe path Use function dev_err_probe() in the probe path instead of dev_err() where appropriate, to make the code a bit more uniform and compact. Signed-off-by: Dragan Simic Reviewed-by: Heiko Stuebner Link: https://patch.msgid.link/8f65c1ec7737af7f2a538fcae3618756a53ba3fa.1727337732.git.dsimic@manjaro.org Signed-off-by: Mark Brown --- drivers/spi/spi-rockchip-sfc.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/drivers/spi/spi-rockchip-sfc.c b/drivers/spi/spi-rockchip-sfc.c index 505d5089bf03..7e0fb4944a34 100644 --- a/drivers/spi/spi-rockchip-sfc.c +++ b/drivers/spi/spi-rockchip-sfc.c @@ -580,16 +580,14 @@ static int rockchip_sfc_probe(struct platform_device *pdev) return PTR_ERR(sfc->regbase); sfc->clk = devm_clk_get(&pdev->dev, "clk_sfc"); - if (IS_ERR(sfc->clk)) { - dev_err(&pdev->dev, "Failed to get sfc interface clk\n"); - return PTR_ERR(sfc->clk); - } + if (IS_ERR(sfc->clk)) + return dev_err_probe(&pdev->dev, PTR_ERR(sfc->clk), + "Failed to get sfc interface clk\n"); sfc->hclk = devm_clk_get(&pdev->dev, "hclk_sfc"); - if (IS_ERR(sfc->hclk)) { - dev_err(&pdev->dev, "Failed to get sfc ahb clk\n"); - return PTR_ERR(sfc->hclk); - } + if (IS_ERR(sfc->hclk)) + return dev_err_probe(&pdev->dev, PTR_ERR(sfc->hclk), + "Failed to get sfc ahb clk\n"); sfc->use_dma = !of_property_read_bool(sfc->dev->of_node, "rockchip,sfc-no-dma"); From 89980d3a34655d99c599f6acf877fd48775a29ad Mon Sep 17 00:00:00 2001 From: Yan Zhen Date: Sat, 14 Sep 2024 17:52:13 +0800 Subject: [PATCH 18/58] spi: fix typo in the comment Correctly spelled comments make it easier for the reader to understand the code. Replace 'progrom' with 'program' in the comment & replace 'Recevie' with 'Receive' in the comment & replace 'receieved' with 'received' in the comment & replace 'ajacent' with 'adjacent' in the comment & replace 'trasaction' with 'transaction' in the comment & replace 'pecularity' with 'peculiarity' in the comment & replace 'resiter' with 'register' in the comment & replace 'tansmition' with 'transmission' in the comment & replace 'Deufult' with 'Default' in the comment & replace 'tansfer' with 'transfer' in the comment & replace 'settign' with 'setting' in the comment. Signed-off-by: Yan Zhen Reviewed-by: Andi Shyti Link: https://patch.msgid.link/20240914095213.298256-1-yanzhen@vivo.com Signed-off-by: Mark Brown --- drivers/spi/spi-hisi-sfc-v3xx.c | 2 +- drivers/spi/spi-lantiq-ssc.c | 2 +- drivers/spi/spi-mpc52xx-psc.c | 4 ++-- drivers/spi/spi-pic32-sqi.c | 2 +- drivers/spi/spi-pl022.c | 2 +- drivers/spi/spi-rockchip-sfc.c | 2 +- drivers/spi/spi-rockchip.c | 2 +- drivers/spi/spi-s3c64xx.c | 2 +- drivers/spi/spi-sprd.c | 2 +- drivers/spi/spi-tegra20-slink.c | 2 +- 10 files changed, 11 insertions(+), 11 deletions(-) diff --git a/drivers/spi/spi-hisi-sfc-v3xx.c b/drivers/spi/spi-hisi-sfc-v3xx.c index 1301d14483d4..b2af2eed197f 100644 --- a/drivers/spi/spi-hisi-sfc-v3xx.c +++ b/drivers/spi/spi-hisi-sfc-v3xx.c @@ -40,7 +40,7 @@ /* Common definition of interrupt bit masks */ #define HISI_SFC_V3XX_INT_MASK_ALL (0x1ff) /* all the masks */ #define HISI_SFC_V3XX_INT_MASK_CPLT BIT(0) /* command execution complete */ -#define HISI_SFC_V3XX_INT_MASK_PP_ERR BIT(2) /* page progrom error */ +#define HISI_SFC_V3XX_INT_MASK_PP_ERR BIT(2) /* page program error */ #define HISI_SFC_V3XX_INT_MASK_IACCES BIT(5) /* error visiting inaccessible/ * protected address */ diff --git a/drivers/spi/spi-lantiq-ssc.c b/drivers/spi/spi-lantiq-ssc.c index 18a46569ba46..a1eb7f296f55 100644 --- a/drivers/spi/spi-lantiq-ssc.c +++ b/drivers/spi/spi-lantiq-ssc.c @@ -139,7 +139,7 @@ #define LTQ_SPI_FGPO_CLROUTN_S 0 #define LTQ_SPI_RXREQ_RXCNT_M 0xFFFF /* Receive count value */ -#define LTQ_SPI_RXCNT_TODO_M 0xFFFF /* Recevie to-do value */ +#define LTQ_SPI_RXCNT_TODO_M 0xFFFF /* Receive to-do value */ #define LTQ_SPI_IRNEN_TFI BIT(4) /* TX finished interrupt */ #define LTQ_SPI_IRNEN_F BIT(3) /* Frame end interrupt request */ diff --git a/drivers/spi/spi-mpc52xx-psc.c b/drivers/spi/spi-mpc52xx-psc.c index 28f06122edac..3bbeb8d5bfb8 100644 --- a/drivers/spi/spi-mpc52xx-psc.c +++ b/drivers/spi/spi-mpc52xx-psc.c @@ -107,7 +107,7 @@ static int mpc52xx_psc_spi_transfer_rxtx(struct spi_device *spi, struct mpc52xx_psc_spi *mps = spi_controller_get_devdata(spi->controller); struct mpc52xx_psc __iomem *psc = mps->psc; struct mpc52xx_psc_fifo __iomem *fifo = mps->fifo; - unsigned rb = 0; /* number of bytes receieved */ + unsigned rb = 0; /* number of bytes received */ unsigned sb = 0; /* number of bytes sent */ unsigned char *rx_buf = (unsigned char *)t->rx_buf; unsigned char *tx_buf = (unsigned char *)t->tx_buf; @@ -325,7 +325,7 @@ static int mpc52xx_psc_spi_of_probe(struct platform_device *pdev) if (IS_ERR(mps->psc)) return dev_err_probe(dev, PTR_ERR(mps->psc), "could not ioremap I/O port range\n"); - /* On the 5200, fifo regs are immediately ajacent to the psc regs */ + /* On the 5200, fifo regs are immediately adjacent to the psc regs */ mps->fifo = ((void __iomem *)mps->psc) + sizeof(struct mpc52xx_psc); mps->irq = platform_get_irq(pdev, 0); diff --git a/drivers/spi/spi-pic32-sqi.c b/drivers/spi/spi-pic32-sqi.c index 0031063a7e25..762b1c5c6f75 100644 --- a/drivers/spi/spi-pic32-sqi.c +++ b/drivers/spi/spi-pic32-sqi.c @@ -226,7 +226,7 @@ static irqreturn_t pic32_sqi_isr(int irq, void *dev_id) if (status & PESQI_PKTCOMP) { /* mask all interrupts */ enable = 0; - /* complete trasaction */ + /* complete transaction */ complete(&sqi->xfer_done); } diff --git a/drivers/spi/spi-pl022.c b/drivers/spi/spi-pl022.c index de63cf0557ce..dd87cf4f70dd 100644 --- a/drivers/spi/spi-pl022.c +++ b/drivers/spi/spi-pl022.c @@ -899,7 +899,7 @@ static int configure_dma(struct pl022 *pl022) break; } - /* SPI pecularity: we need to read and write the same width */ + /* SPI peculiarity: we need to read and write the same width */ if (rx_conf.src_addr_width == DMA_SLAVE_BUSWIDTH_UNDEFINED) rx_conf.src_addr_width = tx_conf.dst_addr_width; if (tx_conf.dst_addr_width == DMA_SLAVE_BUSWIDTH_UNDEFINED) diff --git a/drivers/spi/spi-rockchip-sfc.c b/drivers/spi/spi-rockchip-sfc.c index 0d7fadcd4ed3..04b9377a2802 100644 --- a/drivers/spi/spi-rockchip-sfc.c +++ b/drivers/spi/spi-rockchip-sfc.c @@ -111,7 +111,7 @@ #define SFC_VER_4 0x4 #define SFC_VER_5 0x5 -/* Delay line controller resiter */ +/* Delay line controller register */ #define SFC_DLL_CTRL0 0x3C #define SFC_DLL_CTRL0_SCLK_SMP_DLL BIT(15) #define SFC_DLL_CTRL0_DLL_MAX_VER4 0xFFU diff --git a/drivers/spi/spi-rockchip.c b/drivers/spi/spi-rockchip.c index 0bb33c43b1b4..f1e0c16e8136 100644 --- a/drivers/spi/spi-rockchip.c +++ b/drivers/spi/spi-rockchip.c @@ -192,7 +192,7 @@ struct rockchip_spi { u8 rsd; bool target_abort; - bool cs_inactive; /* spi target tansmition stop when cs inactive */ + bool cs_inactive; /* spi target transmission stop when cs inactive */ bool cs_high_supported; /* native CS supports active-high polarity */ struct spi_transfer *xfer; /* Store xfer temporarily */ diff --git a/drivers/spi/spi-s3c64xx.c b/drivers/spi/spi-s3c64xx.c index 51a002b3f518..2771fe1397e4 100644 --- a/drivers/spi/spi-s3c64xx.c +++ b/drivers/spi/spi-s3c64xx.c @@ -1353,7 +1353,7 @@ static int s3c64xx_spi_probe(struct platform_device *pdev) pm_runtime_enable(&pdev->dev); pm_runtime_get_sync(&pdev->dev); - /* Setup Deufult Mode */ + /* Setup Default Mode */ s3c64xx_spi_hwinit(sdd); spin_lock_init(&sdd->lock); diff --git a/drivers/spi/spi-sprd.c b/drivers/spi/spi-sprd.c index 831ebae10fe0..233ebfb8df5e 100644 --- a/drivers/spi/spi-sprd.c +++ b/drivers/spi/spi-sprd.c @@ -728,7 +728,7 @@ static int sprd_spi_setup_transfer(struct spi_device *sdev, if (ret) return ret; - /* Set tansfer speed and valid bits */ + /* Set transfer speed and valid bits */ sprd_spi_set_speed(ss, t->speed_hz); sprd_spi_set_transfer_bits(ss, bits_per_word); diff --git a/drivers/spi/spi-tegra20-slink.c b/drivers/spi/spi-tegra20-slink.c index ed1393d159ae..04838b036e24 100644 --- a/drivers/spi/spi-tegra20-slink.c +++ b/drivers/spi/spi-tegra20-slink.c @@ -542,7 +542,7 @@ static int tegra_slink_start_dma_based_transfer( if (tspi->is_packed) { val |= SLINK_PACKED; tegra_slink_writel(tspi, val, SLINK_DMA_CTL); - /* HW need small delay after settign Packed mode */ + /* HW need small delay after setting Packed mode */ udelay(1); } tspi->dma_control_reg = val; From 003c7e01916c5e2af95add9b0cbda2e6163873e8 Mon Sep 17 00:00:00 2001 From: Jinjie Ruan Date: Fri, 6 Sep 2024 10:28:28 +0800 Subject: [PATCH 19/58] spi: spi-fsl-lpspi: Use IRQF_NO_AUTOEN flag in request_irq() disable_irq() after request_irq() still has a time gap in which interrupts can come. request_irq() with IRQF_NO_AUTOEN flag will disable IRQ auto-enable when request IRQ. Fixes: 9728fb3ce117 ("spi: lpspi: disable lpspi module irq in DMA mode") Signed-off-by: Jinjie Ruan Link: https://patch.msgid.link/20240906022828.891812-1-ruanjinjie@huawei.com Signed-off-by: Mark Brown --- drivers/spi/spi-fsl-lpspi.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/drivers/spi/spi-fsl-lpspi.c b/drivers/spi/spi-fsl-lpspi.c index 977e8b55c82b..9573b8fa4fbf 100644 --- a/drivers/spi/spi-fsl-lpspi.c +++ b/drivers/spi/spi-fsl-lpspi.c @@ -891,7 +891,7 @@ static int fsl_lpspi_probe(struct platform_device *pdev) return ret; } - ret = devm_request_irq(&pdev->dev, irq, fsl_lpspi_isr, 0, + ret = devm_request_irq(&pdev->dev, irq, fsl_lpspi_isr, IRQF_NO_AUTOEN, dev_name(&pdev->dev), fsl_lpspi); if (ret) { dev_err(&pdev->dev, "can't get irq%d: %d\n", irq, ret); @@ -948,14 +948,10 @@ static int fsl_lpspi_probe(struct platform_device *pdev) ret = fsl_lpspi_dma_init(&pdev->dev, fsl_lpspi, controller); if (ret == -EPROBE_DEFER) goto out_pm_get; - if (ret < 0) + if (ret < 0) { dev_warn(&pdev->dev, "dma setup error %d, use pio\n", ret); - else - /* - * disable LPSPI module IRQ when enable DMA mode successfully, - * to prevent the unexpected LPSPI module IRQ events. - */ - disable_irq(irq); + enable_irq(irq); + } ret = devm_spi_register_controller(&pdev->dev, controller); if (ret < 0) { From 610442f85c12ff662e3dec50c53d92f7a8e5a783 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Tue, 24 Sep 2024 20:47:29 +0200 Subject: [PATCH 20/58] spi: slave-mt27xx: Call clk_disable_unprepare() only once in mtk_spi_slave_probe() A clk_disable_unprepare(mdata->spi_clk) call was immediately used after a return value check for a devm_spi_register_controller() call in this function implementation. Thus call such a function only once instead directly before the check. This issue was transformed by using the Coccinelle software. Signed-off-by: Markus Elfring Link: https://patch.msgid.link/9e736d33-b07f-40a0-8fb6-8c3212593b77@web.de Signed-off-by: Mark Brown --- drivers/spi/spi-slave-mt27xx.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/spi/spi-slave-mt27xx.c b/drivers/spi/spi-slave-mt27xx.c index 4a91b7bae3c6..40e1e7de0742 100644 --- a/drivers/spi/spi-slave-mt27xx.c +++ b/drivers/spi/spi-slave-mt27xx.c @@ -455,15 +455,13 @@ static int mtk_spi_slave_probe(struct platform_device *pdev) pm_runtime_enable(&pdev->dev); ret = devm_spi_register_controller(&pdev->dev, ctlr); + clk_disable_unprepare(mdata->spi_clk); if (ret) { dev_err(&pdev->dev, "failed to register slave controller(%d)\n", ret); - clk_disable_unprepare(mdata->spi_clk); goto err_disable_runtime_pm; } - clk_disable_unprepare(mdata->spi_clk); - return 0; err_disable_runtime_pm: From 494c3dc467768782f93f1433650c56b08feb54ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Wed, 25 Sep 2024 13:35:00 +0200 Subject: [PATCH 21/58] spi: Switch back to struct platform_driver::remove() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit After commit 0edb555a65d1 ("platform: Make platform_driver::remove() return void") .remove() is (again) the right callback to implement for platform drivers. Convert all platform drivers below drivers/spi to use .remove(), with the eventual goal to drop struct platform_driver::remove_new(). As .remove() and .remove_new() have the same prototypes, conversion is done by just changing the structure member name in the driver initializer. The change for the spi-npcm-fiu stands out in the diffstat because the inconsistent formatting style of the platform_driver initializer is fixed to match the other struct initializer in the file. Signed-off-by: Uwe Kleine-König Link: https://patch.msgid.link/20240925113501.25208-2-u.kleine-koenig@baylibre.com Signed-off-by: Mark Brown --- drivers/spi/atmel-quadspi.c | 2 +- drivers/spi/spi-ar934x.c | 2 +- drivers/spi/spi-aspeed-smc.c | 2 +- drivers/spi/spi-at91-usart.c | 2 +- drivers/spi/spi-ath79.c | 2 +- drivers/spi/spi-atmel.c | 2 +- drivers/spi/spi-au1550.c | 2 +- drivers/spi/spi-bcm2835.c | 2 +- drivers/spi/spi-bcm2835aux.c | 2 +- drivers/spi/spi-bcm63xx-hsspi.c | 2 +- drivers/spi/spi-bcm63xx.c | 2 +- drivers/spi/spi-bcmbca-hsspi.c | 2 +- drivers/spi/spi-brcmstb-qspi.c | 2 +- drivers/spi/spi-cadence-quadspi.c | 2 +- drivers/spi/spi-cadence.c | 2 +- drivers/spi/spi-cavium-octeon.c | 2 +- drivers/spi/spi-coldfire-qspi.c | 2 +- drivers/spi/spi-davinci.c | 2 +- drivers/spi/spi-dln2.c | 2 +- drivers/spi/spi-dw-bt1.c | 2 +- drivers/spi/spi-dw-mmio.c | 2 +- drivers/spi/spi-ep93xx.c | 2 +- drivers/spi/spi-fsl-dspi.c | 2 +- drivers/spi/spi-fsl-espi.c | 2 +- drivers/spi/spi-fsl-lpspi.c | 2 +- drivers/spi/spi-fsl-qspi.c | 2 +- drivers/spi/spi-fsl-spi.c | 4 ++-- drivers/spi/spi-hisi-kunpeng.c | 2 +- drivers/spi/spi-img-spfi.c | 2 +- drivers/spi/spi-imx.c | 2 +- drivers/spi/spi-iproc-qspi.c | 2 +- drivers/spi/spi-lantiq-ssc.c | 2 +- drivers/spi/spi-meson-spicc.c | 2 +- drivers/spi/spi-meson-spifc.c | 2 +- drivers/spi/spi-microchip-core-qspi.c | 2 +- drivers/spi/spi-microchip-core.c | 2 +- drivers/spi/spi-mpc52xx.c | 2 +- drivers/spi/spi-mt65xx.c | 2 +- drivers/spi/spi-mtk-nor.c | 2 +- drivers/spi/spi-mtk-snfi.c | 2 +- drivers/spi/spi-mxic.c | 2 +- drivers/spi/spi-mxs.c | 2 +- drivers/spi/spi-npcm-fiu.c | 8 ++++---- drivers/spi/spi-npcm-pspi.c | 2 +- drivers/spi/spi-nxp-fspi.c | 2 +- drivers/spi/spi-oc-tiny.c | 2 +- drivers/spi/spi-omap-uwire.c | 2 +- drivers/spi/spi-omap2-mcspi.c | 2 +- drivers/spi/spi-orion.c | 2 +- drivers/spi/spi-pic32-sqi.c | 2 +- drivers/spi/spi-pic32.c | 2 +- drivers/spi/spi-ppc4xx.c | 2 +- drivers/spi/spi-pxa2xx-platform.c | 2 +- drivers/spi/spi-qcom-qspi.c | 2 +- drivers/spi/spi-qup.c | 2 +- drivers/spi/spi-rb4xx.c | 2 +- drivers/spi/spi-rockchip-sfc.c | 2 +- drivers/spi/spi-rockchip.c | 2 +- drivers/spi/spi-rpc-if.c | 2 +- drivers/spi/spi-rspi.c | 2 +- drivers/spi/spi-rzv2m-csi.c | 2 +- drivers/spi/spi-s3c64xx.c | 2 +- drivers/spi/spi-sh-hspi.c | 2 +- drivers/spi/spi-sh-msiof.c | 2 +- drivers/spi/spi-sh-sci.c | 2 +- drivers/spi/spi-sh.c | 2 +- drivers/spi/spi-sifive.c | 2 +- drivers/spi/spi-slave-mt27xx.c | 2 +- drivers/spi/spi-sn-f-ospi.c | 2 +- drivers/spi/spi-sprd.c | 2 +- drivers/spi/spi-st-ssc4.c | 2 +- drivers/spi/spi-stm32-qspi.c | 2 +- drivers/spi/spi-stm32.c | 2 +- drivers/spi/spi-sun4i.c | 2 +- drivers/spi/spi-sun6i.c | 2 +- drivers/spi/spi-sunplus-sp7021.c | 2 +- drivers/spi/spi-synquacer.c | 2 +- drivers/spi/spi-tegra114.c | 2 +- drivers/spi/spi-tegra20-sflash.c | 2 +- drivers/spi/spi-tegra20-slink.c | 2 +- drivers/spi/spi-tegra210-quad.c | 2 +- drivers/spi/spi-ti-qspi.c | 2 +- drivers/spi/spi-topcliff-pch.c | 2 +- drivers/spi/spi-uniphier.c | 2 +- drivers/spi/spi-xilinx.c | 2 +- drivers/spi/spi-xtensa-xtfpga.c | 2 +- drivers/spi/spi-zynq-qspi.c | 2 +- drivers/spi/spi-zynqmp-gqspi.c | 2 +- 88 files changed, 92 insertions(+), 92 deletions(-) diff --git a/drivers/spi/atmel-quadspi.c b/drivers/spi/atmel-quadspi.c index 4f288f07e38f..20ee227dead2 100644 --- a/drivers/spi/atmel-quadspi.c +++ b/drivers/spi/atmel-quadspi.c @@ -840,7 +840,7 @@ static struct platform_driver atmel_qspi_driver = { .pm = pm_ptr(&atmel_qspi_pm_ops), }, .probe = atmel_qspi_probe, - .remove_new = atmel_qspi_remove, + .remove = atmel_qspi_remove, }; module_platform_driver(atmel_qspi_driver); diff --git a/drivers/spi/spi-ar934x.c b/drivers/spi/spi-ar934x.c index 5ba988720851..86c54fff9d6e 100644 --- a/drivers/spi/spi-ar934x.c +++ b/drivers/spi/spi-ar934x.c @@ -223,7 +223,7 @@ static struct platform_driver ar934x_spi_driver = { .of_match_table = ar934x_spi_match, }, .probe = ar934x_spi_probe, - .remove_new = ar934x_spi_remove, + .remove = ar934x_spi_remove, }; module_platform_driver(ar934x_spi_driver); diff --git a/drivers/spi/spi-aspeed-smc.c b/drivers/spi/spi-aspeed-smc.c index bbd417c55e7f..8eb843ddb25f 100644 --- a/drivers/spi/spi-aspeed-smc.c +++ b/drivers/spi/spi-aspeed-smc.c @@ -1189,7 +1189,7 @@ MODULE_DEVICE_TABLE(of, aspeed_spi_matches); static struct platform_driver aspeed_spi_driver = { .probe = aspeed_spi_probe, - .remove_new = aspeed_spi_remove, + .remove = aspeed_spi_remove, .driver = { .name = DEVICE_NAME, .of_match_table = aspeed_spi_matches, diff --git a/drivers/spi/spi-at91-usart.c b/drivers/spi/spi-at91-usart.c index 1cea8e159344..bbe97ce89a2f 100644 --- a/drivers/spi/spi-at91-usart.c +++ b/drivers/spi/spi-at91-usart.c @@ -650,7 +650,7 @@ static struct platform_driver at91_usart_spi_driver = { .pm = &at91_usart_spi_pm_ops, }, .probe = at91_usart_spi_probe, - .remove_new = at91_usart_spi_remove, + .remove = at91_usart_spi_remove, }; module_platform_driver(at91_usart_spi_driver); diff --git a/drivers/spi/spi-ath79.c b/drivers/spi/spi-ath79.c index d78762d4db98..9a705a9fddd2 100644 --- a/drivers/spi/spi-ath79.c +++ b/drivers/spi/spi-ath79.c @@ -253,7 +253,7 @@ MODULE_DEVICE_TABLE(of, ath79_spi_of_match); static struct platform_driver ath79_spi_driver = { .probe = ath79_spi_probe, - .remove_new = ath79_spi_remove, + .remove = ath79_spi_remove, .shutdown = ath79_spi_shutdown, .driver = { .name = DRV_NAME, diff --git a/drivers/spi/spi-atmel.c b/drivers/spi/spi-atmel.c index b62f57390d8f..89a6b46cd319 100644 --- a/drivers/spi/spi-atmel.c +++ b/drivers/spi/spi-atmel.c @@ -1781,7 +1781,7 @@ static struct platform_driver atmel_spi_driver = { .of_match_table = atmel_spi_dt_ids, }, .probe = atmel_spi_probe, - .remove_new = atmel_spi_remove, + .remove = atmel_spi_remove, }; module_platform_driver(atmel_spi_driver); diff --git a/drivers/spi/spi-au1550.c b/drivers/spi/spi-au1550.c index 16f200bb3d17..b65798ccc679 100644 --- a/drivers/spi/spi-au1550.c +++ b/drivers/spi/spi-au1550.c @@ -940,7 +940,7 @@ MODULE_ALIAS("platform:au1550-spi"); static struct platform_driver au1550_spi_drv = { .probe = au1550_spi_probe, - .remove_new = au1550_spi_remove, + .remove = au1550_spi_remove, .driver = { .name = "au1550-spi", }, diff --git a/drivers/spi/spi-bcm2835.c b/drivers/spi/spi-bcm2835.c index e1b9b1235787..0d1aa6592484 100644 --- a/drivers/spi/spi-bcm2835.c +++ b/drivers/spi/spi-bcm2835.c @@ -1435,7 +1435,7 @@ static struct platform_driver bcm2835_spi_driver = { .of_match_table = bcm2835_spi_match, }, .probe = bcm2835_spi_probe, - .remove_new = bcm2835_spi_remove, + .remove = bcm2835_spi_remove, .shutdown = bcm2835_spi_remove, }; module_platform_driver(bcm2835_spi_driver); diff --git a/drivers/spi/spi-bcm2835aux.c b/drivers/spi/spi-bcm2835aux.c index 06fe155a70c9..90698d7d809d 100644 --- a/drivers/spi/spi-bcm2835aux.c +++ b/drivers/spi/spi-bcm2835aux.c @@ -577,7 +577,7 @@ static struct platform_driver bcm2835aux_spi_driver = { .of_match_table = bcm2835aux_spi_match, }, .probe = bcm2835aux_spi_probe, - .remove_new = bcm2835aux_spi_remove, + .remove = bcm2835aux_spi_remove, }; module_platform_driver(bcm2835aux_spi_driver); diff --git a/drivers/spi/spi-bcm63xx-hsspi.c b/drivers/spi/spi-bcm63xx-hsspi.c index 1ca857c2a4aa..644b44d2aef2 100644 --- a/drivers/spi/spi-bcm63xx-hsspi.c +++ b/drivers/spi/spi-bcm63xx-hsspi.c @@ -944,7 +944,7 @@ static struct platform_driver bcm63xx_hsspi_driver = { .of_match_table = bcm63xx_hsspi_of_match, }, .probe = bcm63xx_hsspi_probe, - .remove_new = bcm63xx_hsspi_remove, + .remove = bcm63xx_hsspi_remove, }; module_platform_driver(bcm63xx_hsspi_driver); diff --git a/drivers/spi/spi-bcm63xx.c b/drivers/spi/spi-bcm63xx.c index ef3a7226db12..c8f64ec69344 100644 --- a/drivers/spi/spi-bcm63xx.c +++ b/drivers/spi/spi-bcm63xx.c @@ -656,7 +656,7 @@ static struct platform_driver bcm63xx_spi_driver = { }, .id_table = bcm63xx_spi_dev_match, .probe = bcm63xx_spi_probe, - .remove_new = bcm63xx_spi_remove, + .remove = bcm63xx_spi_remove, }; module_platform_driver(bcm63xx_spi_driver); diff --git a/drivers/spi/spi-bcmbca-hsspi.c b/drivers/spi/spi-bcmbca-hsspi.c index d936104a41ec..f16298b75236 100644 --- a/drivers/spi/spi-bcmbca-hsspi.c +++ b/drivers/spi/spi-bcmbca-hsspi.c @@ -633,7 +633,7 @@ static struct platform_driver bcmbca_hsspi_driver = { .of_match_table = bcmbca_hsspi_of_match, }, .probe = bcmbca_hsspi_probe, - .remove_new = bcmbca_hsspi_remove, + .remove = bcmbca_hsspi_remove, }; module_platform_driver(bcmbca_hsspi_driver); diff --git a/drivers/spi/spi-brcmstb-qspi.c b/drivers/spi/spi-brcmstb-qspi.c index e1b137419f5c..7a33b479c1f7 100644 --- a/drivers/spi/spi-brcmstb-qspi.c +++ b/drivers/spi/spi-brcmstb-qspi.c @@ -28,7 +28,7 @@ static void brcmstb_qspi_remove(struct platform_device *pdev) static struct platform_driver brcmstb_qspi_driver = { .probe = brcmstb_qspi_probe, - .remove_new = brcmstb_qspi_remove, + .remove = brcmstb_qspi_remove, .driver = { .name = "brcmstb_qspi", .pm = &bcm_qspi_pm_ops, diff --git a/drivers/spi/spi-cadence-quadspi.c b/drivers/spi/spi-cadence-quadspi.c index 1755ca026f08..0b45b7b2b3ab 100644 --- a/drivers/spi/spi-cadence-quadspi.c +++ b/drivers/spi/spi-cadence-quadspi.c @@ -2112,7 +2112,7 @@ MODULE_DEVICE_TABLE(of, cqspi_dt_ids); static struct platform_driver cqspi_platform_driver = { .probe = cqspi_probe, - .remove_new = cqspi_remove, + .remove = cqspi_remove, .driver = { .name = CQSPI_NAME, .pm = pm_ptr(&cqspi_dev_pm_ops), diff --git a/drivers/spi/spi-cadence.c b/drivers/spi/spi-cadence.c index e07e081de5ea..223939a7a657 100644 --- a/drivers/spi/spi-cadence.c +++ b/drivers/spi/spi-cadence.c @@ -804,7 +804,7 @@ MODULE_DEVICE_TABLE(of, cdns_spi_of_match); /* cdns_spi_driver - This structure defines the SPI subsystem platform driver */ static struct platform_driver cdns_spi_driver = { .probe = cdns_spi_probe, - .remove_new = cdns_spi_remove, + .remove = cdns_spi_remove, .driver = { .name = CDNS_SPI_NAME, .of_match_table = cdns_spi_of_match, diff --git a/drivers/spi/spi-cavium-octeon.c b/drivers/spi/spi-cavium-octeon.c index 4511c3b31223..a5ad90d66ec0 100644 --- a/drivers/spi/spi-cavium-octeon.c +++ b/drivers/spi/spi-cavium-octeon.c @@ -90,7 +90,7 @@ static struct platform_driver octeon_spi_driver = { .of_match_table = octeon_spi_match, }, .probe = octeon_spi_probe, - .remove_new = octeon_spi_remove, + .remove = octeon_spi_remove, }; module_platform_driver(octeon_spi_driver); diff --git a/drivers/spi/spi-coldfire-qspi.c b/drivers/spi/spi-coldfire-qspi.c index e83cd0510f20..fdf37636cb9f 100644 --- a/drivers/spi/spi-coldfire-qspi.c +++ b/drivers/spi/spi-coldfire-qspi.c @@ -502,7 +502,7 @@ static struct platform_driver mcfqspi_driver = { .driver.name = DRIVER_NAME, .driver.pm = &mcfqspi_pm, .probe = mcfqspi_probe, - .remove_new = mcfqspi_remove, + .remove = mcfqspi_remove, }; module_platform_driver(mcfqspi_driver); diff --git a/drivers/spi/spi-davinci.c b/drivers/spi/spi-davinci.c index ad26c8409733..a29934422356 100644 --- a/drivers/spi/spi-davinci.c +++ b/drivers/spi/spi-davinci.c @@ -1039,7 +1039,7 @@ static struct platform_driver davinci_spi_driver = { .of_match_table = of_match_ptr(davinci_spi_of_match), }, .probe = davinci_spi_probe, - .remove_new = davinci_spi_remove, + .remove = davinci_spi_remove, }; module_platform_driver(davinci_spi_driver); diff --git a/drivers/spi/spi-dln2.c b/drivers/spi/spi-dln2.c index d319dc357fef..3e925d106dc9 100644 --- a/drivers/spi/spi-dln2.c +++ b/drivers/spi/spi-dln2.c @@ -871,7 +871,7 @@ static struct platform_driver spi_dln2_driver = { .pm = &dln2_spi_pm, }, .probe = dln2_spi_probe, - .remove_new = dln2_spi_remove, + .remove = dln2_spi_remove, }; module_platform_driver(spi_dln2_driver); diff --git a/drivers/spi/spi-dw-bt1.c b/drivers/spi/spi-dw-bt1.c index 4577e8096cd9..abe6410f0e99 100644 --- a/drivers/spi/spi-dw-bt1.c +++ b/drivers/spi/spi-dw-bt1.c @@ -317,7 +317,7 @@ MODULE_DEVICE_TABLE(of, dw_spi_bt1_of_match); static struct platform_driver dw_spi_bt1_driver = { .probe = dw_spi_bt1_probe, - .remove_new = dw_spi_bt1_remove, + .remove = dw_spi_bt1_remove, .driver = { .name = "bt1-sys-ssi", .of_match_table = dw_spi_bt1_of_match, diff --git a/drivers/spi/spi-dw-mmio.c b/drivers/spi/spi-dw-mmio.c index 819907e332c4..863040cf5db7 100644 --- a/drivers/spi/spi-dw-mmio.c +++ b/drivers/spi/spi-dw-mmio.c @@ -433,7 +433,7 @@ MODULE_DEVICE_TABLE(acpi, dw_spi_mmio_acpi_match); static struct platform_driver dw_spi_mmio_driver = { .probe = dw_spi_mmio_probe, - .remove_new = dw_spi_mmio_remove, + .remove = dw_spi_mmio_remove, .driver = { .name = DRIVER_NAME, .of_match_table = dw_spi_mmio_of_match, diff --git a/drivers/spi/spi-ep93xx.c b/drivers/spi/spi-ep93xx.c index dc6bdc74643d..e1d097091925 100644 --- a/drivers/spi/spi-ep93xx.c +++ b/drivers/spi/spi-ep93xx.c @@ -729,7 +729,7 @@ static struct platform_driver ep93xx_spi_driver = { .of_match_table = ep93xx_spi_of_ids, }, .probe = ep93xx_spi_probe, - .remove_new = ep93xx_spi_remove, + .remove = ep93xx_spi_remove, }; module_platform_driver(ep93xx_spi_driver); diff --git a/drivers/spi/spi-fsl-dspi.c b/drivers/spi/spi-fsl-dspi.c index 191de1917f83..72044d76d736 100644 --- a/drivers/spi/spi-fsl-dspi.c +++ b/drivers/spi/spi-fsl-dspi.c @@ -1469,7 +1469,7 @@ static struct platform_driver fsl_dspi_driver = { .driver.of_match_table = fsl_dspi_dt_ids, .driver.pm = &dspi_pm, .probe = dspi_probe, - .remove_new = dspi_remove, + .remove = dspi_remove, .shutdown = dspi_shutdown, }; module_platform_driver(fsl_dspi_driver); diff --git a/drivers/spi/spi-fsl-espi.c b/drivers/spi/spi-fsl-espi.c index ea647ee94da8..6a73eaa34cf7 100644 --- a/drivers/spi/spi-fsl-espi.c +++ b/drivers/spi/spi-fsl-espi.c @@ -835,7 +835,7 @@ static struct platform_driver fsl_espi_driver = { .pm = &espi_pm, }, .probe = of_fsl_espi_probe, - .remove_new = of_fsl_espi_remove, + .remove = of_fsl_espi_remove, }; module_platform_driver(fsl_espi_driver); diff --git a/drivers/spi/spi-fsl-lpspi.c b/drivers/spi/spi-fsl-lpspi.c index 9573b8fa4fbf..9edcaf2fdc56 100644 --- a/drivers/spi/spi-fsl-lpspi.c +++ b/drivers/spi/spi-fsl-lpspi.c @@ -1020,7 +1020,7 @@ static struct platform_driver fsl_lpspi_driver = { .pm = pm_ptr(&fsl_lpspi_pm_ops), }, .probe = fsl_lpspi_probe, - .remove_new = fsl_lpspi_remove, + .remove = fsl_lpspi_remove, }; module_platform_driver(fsl_lpspi_driver); diff --git a/drivers/spi/spi-fsl-qspi.c b/drivers/spi/spi-fsl-qspi.c index 79bac30e79af..9ec53bf0dda8 100644 --- a/drivers/spi/spi-fsl-qspi.c +++ b/drivers/spi/spi-fsl-qspi.c @@ -997,7 +997,7 @@ static struct platform_driver fsl_qspi_driver = { .pm = &fsl_qspi_pm_ops, }, .probe = fsl_qspi_probe, - .remove_new = fsl_qspi_remove, + .remove = fsl_qspi_remove, }; module_platform_driver(fsl_qspi_driver); diff --git a/drivers/spi/spi-fsl-spi.c b/drivers/spi/spi-fsl-spi.c index 997e07c0a24a..856a4a9def66 100644 --- a/drivers/spi/spi-fsl-spi.c +++ b/drivers/spi/spi-fsl-spi.c @@ -714,7 +714,7 @@ static struct platform_driver of_fsl_spi_driver = { .of_match_table = of_fsl_spi_match, }, .probe = of_fsl_spi_probe, - .remove_new = of_fsl_spi_remove, + .remove = of_fsl_spi_remove, }; #ifdef CONFIG_MPC832x_RDB @@ -757,7 +757,7 @@ static void plat_mpc8xxx_spi_remove(struct platform_device *pdev) MODULE_ALIAS("platform:mpc8xxx_spi"); static struct platform_driver mpc8xxx_spi_driver = { .probe = plat_mpc8xxx_spi_probe, - .remove_new = plat_mpc8xxx_spi_remove, + .remove = plat_mpc8xxx_spi_remove, .driver = { .name = "mpc8xxx_spi", }, diff --git a/drivers/spi/spi-hisi-kunpeng.c b/drivers/spi/spi-hisi-kunpeng.c index 16054695bdb0..dadf558dd9c0 100644 --- a/drivers/spi/spi-hisi-kunpeng.c +++ b/drivers/spi/spi-hisi-kunpeng.c @@ -542,7 +542,7 @@ MODULE_DEVICE_TABLE(acpi, hisi_spi_acpi_match); static struct platform_driver hisi_spi_driver = { .probe = hisi_spi_probe, - .remove_new = hisi_spi_remove, + .remove = hisi_spi_remove, .driver = { .name = "hisi-kunpeng-spi", .acpi_match_table = hisi_spi_acpi_match, diff --git a/drivers/spi/spi-img-spfi.c b/drivers/spi/spi-img-spfi.c index d8360f94d3b7..168ccf51f6d4 100644 --- a/drivers/spi/spi-img-spfi.c +++ b/drivers/spi/spi-img-spfi.c @@ -756,7 +756,7 @@ static struct platform_driver img_spfi_driver = { .of_match_table = of_match_ptr(img_spfi_of_match), }, .probe = img_spfi_probe, - .remove_new = img_spfi_remove, + .remove = img_spfi_remove, }; module_platform_driver(img_spfi_driver); diff --git a/drivers/spi/spi-imx.c b/drivers/spi/spi-imx.c index 85bd1a82a34e..bd83e4dc63bc 100644 --- a/drivers/spi/spi-imx.c +++ b/drivers/spi/spi-imx.c @@ -1956,7 +1956,7 @@ static struct platform_driver spi_imx_driver = { .pm = pm_ptr(&imx_spi_pm), }, .probe = spi_imx_probe, - .remove_new = spi_imx_remove, + .remove = spi_imx_remove, }; module_platform_driver(spi_imx_driver); diff --git a/drivers/spi/spi-iproc-qspi.c b/drivers/spi/spi-iproc-qspi.c index 39ee2b43a516..392acc4026ab 100644 --- a/drivers/spi/spi-iproc-qspi.c +++ b/drivers/spi/spi-iproc-qspi.c @@ -138,7 +138,7 @@ MODULE_DEVICE_TABLE(of, bcm_iproc_of_match); static struct platform_driver bcm_iproc_driver = { .probe = bcm_iproc_probe, - .remove_new = bcm_iproc_remove, + .remove = bcm_iproc_remove, .driver = { .name = "bcm_iproc", .pm = &bcm_qspi_pm_ops, diff --git a/drivers/spi/spi-lantiq-ssc.c b/drivers/spi/spi-lantiq-ssc.c index a1eb7f296f55..60849e07f674 100644 --- a/drivers/spi/spi-lantiq-ssc.c +++ b/drivers/spi/spi-lantiq-ssc.c @@ -1029,7 +1029,7 @@ static void lantiq_ssc_remove(struct platform_device *pdev) static struct platform_driver lantiq_ssc_driver = { .probe = lantiq_ssc_probe, - .remove_new = lantiq_ssc_remove, + .remove = lantiq_ssc_remove, .driver = { .name = "spi-lantiq-ssc", .of_match_table = lantiq_ssc_match, diff --git a/drivers/spi/spi-meson-spicc.c b/drivers/spi/spi-meson-spicc.c index 1d05590a7434..df74ad5060f8 100644 --- a/drivers/spi/spi-meson-spicc.c +++ b/drivers/spi/spi-meson-spicc.c @@ -949,7 +949,7 @@ MODULE_DEVICE_TABLE(of, meson_spicc_of_match); static struct platform_driver meson_spicc_driver = { .probe = meson_spicc_probe, - .remove_new = meson_spicc_remove, + .remove = meson_spicc_remove, .driver = { .name = "meson-spicc", .of_match_table = of_match_ptr(meson_spicc_of_match), diff --git a/drivers/spi/spi-meson-spifc.c b/drivers/spi/spi-meson-spifc.c index fd8b26dd4a79..ef7efeaeee97 100644 --- a/drivers/spi/spi-meson-spifc.c +++ b/drivers/spi/spi-meson-spifc.c @@ -429,7 +429,7 @@ MODULE_DEVICE_TABLE(of, meson_spifc_dt_match); static struct platform_driver meson_spifc_driver = { .probe = meson_spifc_probe, - .remove_new = meson_spifc_remove, + .remove = meson_spifc_remove, .driver = { .name = "meson-spifc", .of_match_table = of_match_ptr(meson_spifc_dt_match), diff --git a/drivers/spi/spi-microchip-core-qspi.c b/drivers/spi/spi-microchip-core-qspi.c index 09f16471c537..ad2b5ffa6153 100644 --- a/drivers/spi/spi-microchip-core-qspi.c +++ b/drivers/spi/spi-microchip-core-qspi.c @@ -575,7 +575,7 @@ static struct platform_driver mchp_coreqspi_driver = { .name = "microchip,coreqspi", .of_match_table = mchp_coreqspi_of_match, }, - .remove_new = mchp_coreqspi_remove, + .remove = mchp_coreqspi_remove, }; module_platform_driver(mchp_coreqspi_driver); diff --git a/drivers/spi/spi-microchip-core.c b/drivers/spi/spi-microchip-core.c index 7c1a9a985373..5b6af55855ef 100644 --- a/drivers/spi/spi-microchip-core.c +++ b/drivers/spi/spi-microchip-core.c @@ -622,7 +622,7 @@ static struct platform_driver mchp_corespi_driver = { .pm = MICROCHIP_SPI_PM_OPS, .of_match_table = of_match_ptr(mchp_corespi_dt_ids), }, - .remove_new = mchp_corespi_remove, + .remove = mchp_corespi_remove, }; module_platform_driver(mchp_corespi_driver); MODULE_DESCRIPTION("Microchip coreSPI SPI controller driver"); diff --git a/drivers/spi/spi-mpc52xx.c b/drivers/spi/spi-mpc52xx.c index d5ac60c135c2..036bfb7bf189 100644 --- a/drivers/spi/spi-mpc52xx.c +++ b/drivers/spi/spi-mpc52xx.c @@ -544,6 +544,6 @@ static struct platform_driver mpc52xx_spi_of_driver = { .of_match_table = mpc52xx_spi_match, }, .probe = mpc52xx_spi_probe, - .remove_new = mpc52xx_spi_remove, + .remove = mpc52xx_spi_remove, }; module_platform_driver(mpc52xx_spi_of_driver); diff --git a/drivers/spi/spi-mt65xx.c b/drivers/spi/spi-mt65xx.c index dfee244fc317..85f3bafc975d 100644 --- a/drivers/spi/spi-mt65xx.c +++ b/drivers/spi/spi-mt65xx.c @@ -1432,7 +1432,7 @@ static struct platform_driver mtk_spi_driver = { .of_match_table = mtk_spi_of_match, }, .probe = mtk_spi_probe, - .remove_new = mtk_spi_remove, + .remove = mtk_spi_remove, }; module_platform_driver(mtk_spi_driver); diff --git a/drivers/spi/spi-mtk-nor.c b/drivers/spi/spi-mtk-nor.c index 62b1c8995fa4..85ab5ce96c4d 100644 --- a/drivers/spi/spi-mtk-nor.c +++ b/drivers/spi/spi-mtk-nor.c @@ -998,7 +998,7 @@ static struct platform_driver mtk_nor_driver = { .pm = &mtk_nor_pm_ops, }, .probe = mtk_nor_probe, - .remove_new = mtk_nor_remove, + .remove = mtk_nor_remove, }; module_platform_driver(mtk_nor_driver); diff --git a/drivers/spi/spi-mtk-snfi.c b/drivers/spi/spi-mtk-snfi.c index ddd98ddb7913..debe0e3c1c8b 100644 --- a/drivers/spi/spi-mtk-snfi.c +++ b/drivers/spi/spi-mtk-snfi.c @@ -1477,7 +1477,7 @@ static void mtk_snand_remove(struct platform_device *pdev) static struct platform_driver mtk_snand_driver = { .probe = mtk_snand_probe, - .remove_new = mtk_snand_remove, + .remove = mtk_snand_remove, .driver = { .name = "mtk-snand", .of_match_table = mtk_snand_ids, diff --git a/drivers/spi/spi-mxic.c b/drivers/spi/spi-mxic.c index 6156d691630a..71edeb8dfc5f 100644 --- a/drivers/spi/spi-mxic.c +++ b/drivers/spi/spi-mxic.c @@ -836,7 +836,7 @@ MODULE_DEVICE_TABLE(of, mxic_spi_of_ids); static struct platform_driver mxic_spi_driver = { .probe = mxic_spi_probe, - .remove_new = mxic_spi_remove, + .remove = mxic_spi_remove, .driver = { .name = "mxic-spi", .of_match_table = mxic_spi_of_ids, diff --git a/drivers/spi/spi-mxs.c b/drivers/spi/spi-mxs.c index 3e341d1ff3b6..e6d955d964f4 100644 --- a/drivers/spi/spi-mxs.c +++ b/drivers/spi/spi-mxs.c @@ -657,7 +657,7 @@ static void mxs_spi_remove(struct platform_device *pdev) static struct platform_driver mxs_spi_driver = { .probe = mxs_spi_probe, - .remove_new = mxs_spi_remove, + .remove = mxs_spi_remove, .driver = { .name = DRIVER_NAME, .of_match_table = mxs_spi_dt_ids, diff --git a/drivers/spi/spi-npcm-fiu.c b/drivers/spi/spi-npcm-fiu.c index f3bb8bbc192f..958bab27a081 100644 --- a/drivers/spi/spi-npcm-fiu.c +++ b/drivers/spi/spi-npcm-fiu.c @@ -766,12 +766,12 @@ MODULE_DEVICE_TABLE(of, npcm_fiu_dt_ids); static struct platform_driver npcm_fiu_driver = { .driver = { - .name = "NPCM-FIU", - .bus = &platform_bus_type, + .name = "NPCM-FIU", + .bus = &platform_bus_type, .of_match_table = npcm_fiu_dt_ids, }, - .probe = npcm_fiu_probe, - .remove_new = npcm_fiu_remove, + .probe = npcm_fiu_probe, + .remove = npcm_fiu_remove, }; module_platform_driver(npcm_fiu_driver); diff --git a/drivers/spi/spi-npcm-pspi.c b/drivers/spi/spi-npcm-pspi.c index a7feb20b06ee..e4c291e653c8 100644 --- a/drivers/spi/spi-npcm-pspi.c +++ b/drivers/spi/spi-npcm-pspi.c @@ -452,7 +452,7 @@ static struct platform_driver npcm_pspi_driver = { .of_match_table = npcm_pspi_match, }, .probe = npcm_pspi_probe, - .remove_new = npcm_pspi_remove, + .remove = npcm_pspi_remove, }; module_platform_driver(npcm_pspi_driver); diff --git a/drivers/spi/spi-nxp-fspi.c b/drivers/spi/spi-nxp-fspi.c index 5a1e55a01c52..1161b9e5a4dc 100644 --- a/drivers/spi/spi-nxp-fspi.c +++ b/drivers/spi/spi-nxp-fspi.c @@ -1331,7 +1331,7 @@ static struct platform_driver nxp_fspi_driver = { .pm = &nxp_fspi_pm_ops, }, .probe = nxp_fspi_probe, - .remove_new = nxp_fspi_remove, + .remove = nxp_fspi_remove, }; module_platform_driver(nxp_fspi_driver); diff --git a/drivers/spi/spi-oc-tiny.c b/drivers/spi/spi-oc-tiny.c index 7d8c5cd680d1..cba229920357 100644 --- a/drivers/spi/spi-oc-tiny.c +++ b/drivers/spi/spi-oc-tiny.c @@ -288,7 +288,7 @@ MODULE_DEVICE_TABLE(of, tiny_spi_match); static struct platform_driver tiny_spi_driver = { .probe = tiny_spi_probe, - .remove_new = tiny_spi_remove, + .remove = tiny_spi_remove, .driver = { .name = DRV_NAME, .pm = NULL, diff --git a/drivers/spi/spi-omap-uwire.c b/drivers/spi/spi-omap-uwire.c index 03b820e85651..b9a91dbfeaef 100644 --- a/drivers/spi/spi-omap-uwire.c +++ b/drivers/spi/spi-omap-uwire.c @@ -523,7 +523,7 @@ static struct platform_driver uwire_driver = { .name = "omap_uwire", }, .probe = uwire_probe, - .remove_new = uwire_remove, + .remove = uwire_remove, // suspend ... unuse ck // resume ... use ck }; diff --git a/drivers/spi/spi-omap2-mcspi.c b/drivers/spi/spi-omap2-mcspi.c index 2c043817c66a..e2400a067a95 100644 --- a/drivers/spi/spi-omap2-mcspi.c +++ b/drivers/spi/spi-omap2-mcspi.c @@ -1654,7 +1654,7 @@ static struct platform_driver omap2_mcspi_driver = { .of_match_table = omap_mcspi_of_match, }, .probe = omap2_mcspi_probe, - .remove_new = omap2_mcspi_remove, + .remove = omap2_mcspi_remove, }; module_platform_driver(omap2_mcspi_driver); diff --git a/drivers/spi/spi-orion.c b/drivers/spi/spi-orion.c index eee9ff4bfa5b..6ff42475f851 100644 --- a/drivers/spi/spi-orion.c +++ b/drivers/spi/spi-orion.c @@ -846,7 +846,7 @@ static struct platform_driver orion_spi_driver = { .of_match_table = of_match_ptr(orion_spi_of_match_table), }, .probe = orion_spi_probe, - .remove_new = orion_spi_remove, + .remove = orion_spi_remove, }; module_platform_driver(orion_spi_driver); diff --git a/drivers/spi/spi-pic32-sqi.c b/drivers/spi/spi-pic32-sqi.c index 762b1c5c6f75..fa0c1ee84532 100644 --- a/drivers/spi/spi-pic32-sqi.c +++ b/drivers/spi/spi-pic32-sqi.c @@ -682,7 +682,7 @@ static struct platform_driver pic32_sqi_driver = { .of_match_table = of_match_ptr(pic32_sqi_of_ids), }, .probe = pic32_sqi_probe, - .remove_new = pic32_sqi_remove, + .remove = pic32_sqi_remove, }; module_platform_driver(pic32_sqi_driver); diff --git a/drivers/spi/spi-pic32.c b/drivers/spi/spi-pic32.c index b8bcc220e96d..369850d14313 100644 --- a/drivers/spi/spi-pic32.c +++ b/drivers/spi/spi-pic32.c @@ -859,7 +859,7 @@ static struct platform_driver pic32_spi_driver = { .of_match_table = of_match_ptr(pic32_spi_of_match), }, .probe = pic32_spi_probe, - .remove_new = pic32_spi_remove, + .remove = pic32_spi_remove, }; module_platform_driver(pic32_spi_driver); diff --git a/drivers/spi/spi-ppc4xx.c b/drivers/spi/spi-ppc4xx.c index 4a64ea0f596f..688cabcfbc52 100644 --- a/drivers/spi/spi-ppc4xx.c +++ b/drivers/spi/spi-ppc4xx.c @@ -484,7 +484,7 @@ MODULE_DEVICE_TABLE(of, spi_ppc4xx_of_match); static struct platform_driver spi_ppc4xx_of_driver = { .probe = spi_ppc4xx_of_probe, - .remove_new = spi_ppc4xx_of_remove, + .remove = spi_ppc4xx_of_remove, .driver = { .name = DRIVER_NAME, .of_match_table = spi_ppc4xx_of_match, diff --git a/drivers/spi/spi-pxa2xx-platform.c b/drivers/spi/spi-pxa2xx-platform.c index 595af9fa4e0f..b88b7de7a005 100644 --- a/drivers/spi/spi-pxa2xx-platform.c +++ b/drivers/spi/spi-pxa2xx-platform.c @@ -207,7 +207,7 @@ static struct platform_driver driver = { .of_match_table = pxa2xx_spi_of_match, }, .probe = pxa2xx_spi_platform_probe, - .remove_new = pxa2xx_spi_platform_remove, + .remove = pxa2xx_spi_platform_remove, }; static int __init pxa2xx_spi_init(void) diff --git a/drivers/spi/spi-qcom-qspi.c b/drivers/spi/spi-qcom-qspi.c index 49b775134485..056f02677376 100644 --- a/drivers/spi/spi-qcom-qspi.c +++ b/drivers/spi/spi-qcom-qspi.c @@ -908,7 +908,7 @@ static struct platform_driver qcom_qspi_driver = { .of_match_table = qcom_qspi_dt_match, }, .probe = qcom_qspi_probe, - .remove_new = qcom_qspi_remove, + .remove = qcom_qspi_remove, }; module_platform_driver(qcom_qspi_driver); diff --git a/drivers/spi/spi-qup.c b/drivers/spi/spi-qup.c index 1a2f9cd92b3c..7d647edf6bc3 100644 --- a/drivers/spi/spi-qup.c +++ b/drivers/spi/spi-qup.c @@ -1364,7 +1364,7 @@ static struct platform_driver spi_qup_driver = { .of_match_table = spi_qup_dt_match, }, .probe = spi_qup_probe, - .remove_new = spi_qup_remove, + .remove = spi_qup_remove, }; module_platform_driver(spi_qup_driver); diff --git a/drivers/spi/spi-rb4xx.c b/drivers/spi/spi-rb4xx.c index 225f75550780..e71d3805b150 100644 --- a/drivers/spi/spi-rb4xx.c +++ b/drivers/spi/spi-rb4xx.c @@ -196,7 +196,7 @@ MODULE_DEVICE_TABLE(of, rb4xx_spi_dt_match); static struct platform_driver rb4xx_spi_drv = { .probe = rb4xx_spi_probe, - .remove_new = rb4xx_spi_remove, + .remove = rb4xx_spi_remove, .driver = { .name = "rb4xx-spi", .of_match_table = of_match_ptr(rb4xx_spi_dt_match), diff --git a/drivers/spi/spi-rockchip-sfc.c b/drivers/spi/spi-rockchip-sfc.c index 04b9377a2802..5c0554e9d24d 100644 --- a/drivers/spi/spi-rockchip-sfc.c +++ b/drivers/spi/spi-rockchip-sfc.c @@ -677,7 +677,7 @@ static struct platform_driver rockchip_sfc_driver = { .of_match_table = rockchip_sfc_dt_ids, }, .probe = rockchip_sfc_probe, - .remove_new = rockchip_sfc_remove, + .remove = rockchip_sfc_remove, }; module_platform_driver(rockchip_sfc_driver); diff --git a/drivers/spi/spi-rockchip.c b/drivers/spi/spi-rockchip.c index f1e0c16e8136..22b97dffc7fd 100644 --- a/drivers/spi/spi-rockchip.c +++ b/drivers/spi/spi-rockchip.c @@ -1036,7 +1036,7 @@ static struct platform_driver rockchip_spi_driver = { .of_match_table = of_match_ptr(rockchip_spi_dt_match), }, .probe = rockchip_spi_probe, - .remove_new = rockchip_spi_remove, + .remove = rockchip_spi_remove, }; module_platform_driver(rockchip_spi_driver); diff --git a/drivers/spi/spi-rpc-if.c b/drivers/spi/spi-rpc-if.c index b468a95972bf..118ec54cc64f 100644 --- a/drivers/spi/spi-rpc-if.c +++ b/drivers/spi/spi-rpc-if.c @@ -206,7 +206,7 @@ MODULE_DEVICE_TABLE(platform, rpc_if_spi_id_table); static struct platform_driver rpcif_spi_driver = { .probe = rpcif_spi_probe, - .remove_new = rpcif_spi_remove, + .remove = rpcif_spi_remove, .id_table = rpc_if_spi_id_table, .driver = { .name = "rpc-if-spi", diff --git a/drivers/spi/spi-rspi.c b/drivers/spi/spi-rspi.c index 7f95d22fb1ac..92faaf614f8e 100644 --- a/drivers/spi/spi-rspi.c +++ b/drivers/spi/spi-rspi.c @@ -1427,7 +1427,7 @@ static SIMPLE_DEV_PM_OPS(rspi_pm_ops, rspi_suspend, rspi_resume); static struct platform_driver rspi_driver = { .probe = rspi_probe, - .remove_new = rspi_remove, + .remove = rspi_remove, .id_table = spi_driver_ids, .driver = { .name = "renesas_spi", diff --git a/drivers/spi/spi-rzv2m-csi.c b/drivers/spi/spi-rzv2m-csi.c index 741e0f44c49c..7c0442883ac0 100644 --- a/drivers/spi/spi-rzv2m-csi.c +++ b/drivers/spi/spi-rzv2m-csi.c @@ -683,7 +683,7 @@ MODULE_DEVICE_TABLE(of, rzv2m_csi_match); static struct platform_driver rzv2m_csi_drv = { .probe = rzv2m_csi_probe, - .remove_new = rzv2m_csi_remove, + .remove = rzv2m_csi_remove, .driver = { .name = "rzv2m_csi", .of_match_table = rzv2m_csi_match, diff --git a/drivers/spi/spi-s3c64xx.c b/drivers/spi/spi-s3c64xx.c index 2771fe1397e4..5c07a8326933 100644 --- a/drivers/spi/spi-s3c64xx.c +++ b/drivers/spi/spi-s3c64xx.c @@ -1681,7 +1681,7 @@ static struct platform_driver s3c64xx_spi_driver = { .of_match_table = of_match_ptr(s3c64xx_spi_dt_match), }, .probe = s3c64xx_spi_probe, - .remove_new = s3c64xx_spi_remove, + .remove = s3c64xx_spi_remove, .id_table = s3c64xx_spi_driver_ids, }; MODULE_ALIAS("platform:s3c64xx-spi"); diff --git a/drivers/spi/spi-sh-hspi.c b/drivers/spi/spi-sh-hspi.c index 5d63aa1d28e2..93017faeb7b5 100644 --- a/drivers/spi/spi-sh-hspi.c +++ b/drivers/spi/spi-sh-hspi.c @@ -293,7 +293,7 @@ MODULE_DEVICE_TABLE(of, hspi_of_match); static struct platform_driver hspi_driver = { .probe = hspi_probe, - .remove_new = hspi_remove, + .remove = hspi_remove, .driver = { .name = "sh-hspi", .of_match_table = hspi_of_match, diff --git a/drivers/spi/spi-sh-msiof.c b/drivers/spi/spi-sh-msiof.c index 6f12e4fb2e2e..4ed6613b8188 100644 --- a/drivers/spi/spi-sh-msiof.c +++ b/drivers/spi/spi-sh-msiof.c @@ -1429,7 +1429,7 @@ static SIMPLE_DEV_PM_OPS(sh_msiof_spi_pm_ops, sh_msiof_spi_suspend, static struct platform_driver sh_msiof_spi_drv = { .probe = sh_msiof_spi_probe, - .remove_new = sh_msiof_spi_remove, + .remove = sh_msiof_spi_remove, .id_table = spi_driver_ids, .driver = { .name = "spi_sh_msiof", diff --git a/drivers/spi/spi-sh-sci.c b/drivers/spi/spi-sh-sci.c index 3d560b154ad3..f66efaabcaca 100644 --- a/drivers/spi/spi-sh-sci.c +++ b/drivers/spi/spi-sh-sci.c @@ -183,7 +183,7 @@ static void sh_sci_spi_remove(struct platform_device *dev) static struct platform_driver sh_sci_spi_drv = { .probe = sh_sci_spi_probe, - .remove_new = sh_sci_spi_remove, + .remove = sh_sci_spi_remove, .driver = { .name = "spi_sh_sci", }, diff --git a/drivers/spi/spi-sh.c b/drivers/spi/spi-sh.c index 4b873d9a7602..130d7fc452fa 100644 --- a/drivers/spi/spi-sh.c +++ b/drivers/spi/spi-sh.c @@ -459,7 +459,7 @@ static int spi_sh_probe(struct platform_device *pdev) static struct platform_driver spi_sh_driver = { .probe = spi_sh_probe, - .remove_new = spi_sh_remove, + .remove = spi_sh_remove, .driver = { .name = "sh_spi", }, diff --git a/drivers/spi/spi-sifive.c b/drivers/spi/spi-sifive.c index cfd17bbb2202..87bde2a207a3 100644 --- a/drivers/spi/spi-sifive.c +++ b/drivers/spi/spi-sifive.c @@ -471,7 +471,7 @@ MODULE_DEVICE_TABLE(of, sifive_spi_of_match); static struct platform_driver sifive_spi_driver = { .probe = sifive_spi_probe, - .remove_new = sifive_spi_remove, + .remove = sifive_spi_remove, .driver = { .name = SIFIVE_SPI_DRIVER_NAME, .pm = &sifive_spi_pm_ops, diff --git a/drivers/spi/spi-slave-mt27xx.c b/drivers/spi/spi-slave-mt27xx.c index 40e1e7de0742..9846f025dd4c 100644 --- a/drivers/spi/spi-slave-mt27xx.c +++ b/drivers/spi/spi-slave-mt27xx.c @@ -556,7 +556,7 @@ static struct platform_driver mtk_spi_slave_driver = { .of_match_table = mtk_spi_slave_of_match, }, .probe = mtk_spi_slave_probe, - .remove_new = mtk_spi_slave_remove, + .remove = mtk_spi_slave_remove, }; module_platform_driver(mtk_spi_slave_driver); diff --git a/drivers/spi/spi-sn-f-ospi.c b/drivers/spi/spi-sn-f-ospi.c index a7c3b3923b4a..adac645732fe 100644 --- a/drivers/spi/spi-sn-f-ospi.c +++ b/drivers/spi/spi-sn-f-ospi.c @@ -680,7 +680,7 @@ static struct platform_driver f_ospi_driver = { .of_match_table = f_ospi_dt_ids, }, .probe = f_ospi_probe, - .remove_new = f_ospi_remove, + .remove = f_ospi_remove, }; module_platform_driver(f_ospi_driver); diff --git a/drivers/spi/spi-sprd.c b/drivers/spi/spi-sprd.c index 233ebfb8df5e..ae794058b381 100644 --- a/drivers/spi/spi-sprd.c +++ b/drivers/spi/spi-sprd.c @@ -1072,7 +1072,7 @@ static struct platform_driver sprd_spi_driver = { .pm = &sprd_spi_pm_ops, }, .probe = sprd_spi_probe, - .remove_new = sprd_spi_remove, + .remove = sprd_spi_remove, }; module_platform_driver(sprd_spi_driver); diff --git a/drivers/spi/spi-st-ssc4.c b/drivers/spi/spi-st-ssc4.c index e064025e2fd6..4cff976ab16f 100644 --- a/drivers/spi/spi-st-ssc4.c +++ b/drivers/spi/spi-st-ssc4.c @@ -449,7 +449,7 @@ static struct platform_driver spi_st_driver = { .of_match_table = of_match_ptr(stm_spi_match), }, .probe = spi_st_probe, - .remove_new = spi_st_remove, + .remove = spi_st_remove, }; module_platform_driver(spi_st_driver); diff --git a/drivers/spi/spi-stm32-qspi.c b/drivers/spi/spi-stm32-qspi.c index 955c920c4b63..540b6948b24d 100644 --- a/drivers/spi/spi-stm32-qspi.c +++ b/drivers/spi/spi-stm32-qspi.c @@ -963,7 +963,7 @@ MODULE_DEVICE_TABLE(of, stm32_qspi_match); static struct platform_driver stm32_qspi_driver = { .probe = stm32_qspi_probe, - .remove_new = stm32_qspi_remove, + .remove = stm32_qspi_remove, .driver = { .name = "stm32-qspi", .of_match_table = stm32_qspi_match, diff --git a/drivers/spi/spi-stm32.c b/drivers/spi/spi-stm32.c index 4c4ff074e3f6..f2dd8ab12df8 100644 --- a/drivers/spi/spi-stm32.c +++ b/drivers/spi/spi-stm32.c @@ -2355,7 +2355,7 @@ static const struct dev_pm_ops stm32_spi_pm_ops = { static struct platform_driver stm32_spi_driver = { .probe = stm32_spi_probe, - .remove_new = stm32_spi_remove, + .remove = stm32_spi_remove, .driver = { .name = DRIVER_NAME, .pm = &stm32_spi_pm_ops, diff --git a/drivers/spi/spi-sun4i.c b/drivers/spi/spi-sun4i.c index 2ee6755b43f5..fcbe864c9b7d 100644 --- a/drivers/spi/spi-sun4i.c +++ b/drivers/spi/spi-sun4i.c @@ -535,7 +535,7 @@ static const struct dev_pm_ops sun4i_spi_pm_ops = { static struct platform_driver sun4i_spi_driver = { .probe = sun4i_spi_probe, - .remove_new = sun4i_spi_remove, + .remove = sun4i_spi_remove, .driver = { .name = "sun4i-spi", .of_match_table = sun4i_spi_match, diff --git a/drivers/spi/spi-sun6i.c b/drivers/spi/spi-sun6i.c index 5c26bf056293..871dfd3e77be 100644 --- a/drivers/spi/spi-sun6i.c +++ b/drivers/spi/spi-sun6i.c @@ -810,7 +810,7 @@ static const struct dev_pm_ops sun6i_spi_pm_ops = { static struct platform_driver sun6i_spi_driver = { .probe = sun6i_spi_probe, - .remove_new = sun6i_spi_remove, + .remove = sun6i_spi_remove, .driver = { .name = "sun6i-spi", .of_match_table = sun6i_spi_match, diff --git a/drivers/spi/spi-sunplus-sp7021.c b/drivers/spi/spi-sunplus-sp7021.c index 4e481380c259..7fd4cc6f74c2 100644 --- a/drivers/spi/spi-sunplus-sp7021.c +++ b/drivers/spi/spi-sunplus-sp7021.c @@ -563,7 +563,7 @@ MODULE_DEVICE_TABLE(of, sp7021_spi_controller_ids); static struct platform_driver sp7021_spi_controller_driver = { .probe = sp7021_spi_controller_probe, - .remove_new = sp7021_spi_controller_remove, + .remove = sp7021_spi_controller_remove, .driver = { .name = "sunplus,sp7021-spi-controller", .of_match_table = sp7021_spi_controller_ids, diff --git a/drivers/spi/spi-synquacer.c b/drivers/spi/spi-synquacer.c index 7cb4301a6fb2..eaf560487591 100644 --- a/drivers/spi/spi-synquacer.c +++ b/drivers/spi/spi-synquacer.c @@ -818,7 +818,7 @@ static struct platform_driver synquacer_spi_driver = { .acpi_match_table = ACPI_PTR(synquacer_hsspi_acpi_ids), }, .probe = synquacer_spi_probe, - .remove_new = synquacer_spi_remove, + .remove = synquacer_spi_remove, }; module_platform_driver(synquacer_spi_driver); diff --git a/drivers/spi/spi-tegra114.c b/drivers/spi/spi-tegra114.c index bc7cc4088eea..3822d7c8d8ed 100644 --- a/drivers/spi/spi-tegra114.c +++ b/drivers/spi/spi-tegra114.c @@ -1518,7 +1518,7 @@ static struct platform_driver tegra_spi_driver = { .of_match_table = tegra_spi_of_match, }, .probe = tegra_spi_probe, - .remove_new = tegra_spi_remove, + .remove = tegra_spi_remove, }; module_platform_driver(tegra_spi_driver); diff --git a/drivers/spi/spi-tegra20-sflash.c b/drivers/spi/spi-tegra20-sflash.c index 9f6b9f89be5b..d5c8ee20b8e5 100644 --- a/drivers/spi/spi-tegra20-sflash.c +++ b/drivers/spi/spi-tegra20-sflash.c @@ -600,7 +600,7 @@ static struct platform_driver tegra_sflash_driver = { .of_match_table = tegra_sflash_of_match, }, .probe = tegra_sflash_probe, - .remove_new = tegra_sflash_remove, + .remove = tegra_sflash_remove, }; module_platform_driver(tegra_sflash_driver); diff --git a/drivers/spi/spi-tegra20-slink.c b/drivers/spi/spi-tegra20-slink.c index 04838b036e24..fe452d03c1ee 100644 --- a/drivers/spi/spi-tegra20-slink.c +++ b/drivers/spi/spi-tegra20-slink.c @@ -1214,7 +1214,7 @@ static struct platform_driver tegra_slink_driver = { .of_match_table = tegra_slink_of_match, }, .probe = tegra_slink_probe, - .remove_new = tegra_slink_remove, + .remove = tegra_slink_remove, }; module_platform_driver(tegra_slink_driver); diff --git a/drivers/spi/spi-tegra210-quad.c b/drivers/spi/spi-tegra210-quad.c index afbd64a217eb..40f2afad1899 100644 --- a/drivers/spi/spi-tegra210-quad.c +++ b/drivers/spi/spi-tegra210-quad.c @@ -1724,7 +1724,7 @@ static struct platform_driver tegra_qspi_driver = { .acpi_match_table = ACPI_PTR(tegra_qspi_acpi_match), }, .probe = tegra_qspi_probe, - .remove_new = tegra_qspi_remove, + .remove = tegra_qspi_remove, }; module_platform_driver(tegra_qspi_driver); diff --git a/drivers/spi/spi-ti-qspi.c b/drivers/spi/spi-ti-qspi.c index 0fe6899e78dd..0b8f496c6bf4 100644 --- a/drivers/spi/spi-ti-qspi.c +++ b/drivers/spi/spi-ti-qspi.c @@ -931,7 +931,7 @@ static const struct dev_pm_ops ti_qspi_pm_ops = { static struct platform_driver ti_qspi_driver = { .probe = ti_qspi_probe, - .remove_new = ti_qspi_remove, + .remove = ti_qspi_remove, .driver = { .name = "ti-qspi", .pm = &ti_qspi_pm_ops, diff --git a/drivers/spi/spi-topcliff-pch.c b/drivers/spi/spi-topcliff-pch.c index 271f3e7f834b..60fce5c73031 100644 --- a/drivers/spi/spi-topcliff-pch.c +++ b/drivers/spi/spi-topcliff-pch.c @@ -1514,7 +1514,7 @@ static struct platform_driver pch_spi_pd_driver = { .name = "pch-spi", }, .probe = pch_spi_pd_probe, - .remove_new = pch_spi_pd_remove, + .remove = pch_spi_pd_remove, .suspend = pch_spi_pd_suspend, .resume = pch_spi_pd_resume }; diff --git a/drivers/spi/spi-uniphier.c b/drivers/spi/spi-uniphier.c index 4a18cf896194..15f76855bea4 100644 --- a/drivers/spi/spi-uniphier.c +++ b/drivers/spi/spi-uniphier.c @@ -796,7 +796,7 @@ MODULE_DEVICE_TABLE(of, uniphier_spi_match); static struct platform_driver uniphier_spi_driver = { .probe = uniphier_spi_probe, - .remove_new = uniphier_spi_remove, + .remove = uniphier_spi_remove, .driver = { .name = "uniphier-spi", .of_match_table = uniphier_spi_match, diff --git a/drivers/spi/spi-xilinx.c b/drivers/spi/spi-xilinx.c index 7795328427a6..ded709b2b459 100644 --- a/drivers/spi/spi-xilinx.c +++ b/drivers/spi/spi-xilinx.c @@ -524,7 +524,7 @@ MODULE_ALIAS("platform:" XILINX_SPI_NAME); static struct platform_driver xilinx_spi_driver = { .probe = xilinx_spi_probe, - .remove_new = xilinx_spi_remove, + .remove = xilinx_spi_remove, .driver = { .name = XILINX_SPI_NAME, .of_match_table = xilinx_spi_of_match, diff --git a/drivers/spi/spi-xtensa-xtfpga.c b/drivers/spi/spi-xtensa-xtfpga.c index 3c2cda315397..1b54d8f9f5ec 100644 --- a/drivers/spi/spi-xtensa-xtfpga.c +++ b/drivers/spi/spi-xtensa-xtfpga.c @@ -138,7 +138,7 @@ MODULE_DEVICE_TABLE(of, xtfpga_spi_of_match); static struct platform_driver xtfpga_spi_driver = { .probe = xtfpga_spi_probe, - .remove_new = xtfpga_spi_remove, + .remove = xtfpga_spi_remove, .driver = { .name = XTFPGA_SPI_NAME, .of_match_table = of_match_ptr(xtfpga_spi_of_match), diff --git a/drivers/spi/spi-zynq-qspi.c b/drivers/spi/spi-zynq-qspi.c index b67455bda972..dee9c339a35e 100644 --- a/drivers/spi/spi-zynq-qspi.c +++ b/drivers/spi/spi-zynq-qspi.c @@ -763,7 +763,7 @@ MODULE_DEVICE_TABLE(of, zynq_qspi_of_match); */ static struct platform_driver zynq_qspi_driver = { .probe = zynq_qspi_probe, - .remove_new = zynq_qspi_remove, + .remove = zynq_qspi_remove, .driver = { .name = "zynq-qspi", .of_match_table = zynq_qspi_of_match, diff --git a/drivers/spi/spi-zynqmp-gqspi.c b/drivers/spi/spi-zynqmp-gqspi.c index fcd0ca996684..84cce78e4f2e 100644 --- a/drivers/spi/spi-zynqmp-gqspi.c +++ b/drivers/spi/spi-zynqmp-gqspi.c @@ -1389,7 +1389,7 @@ MODULE_DEVICE_TABLE(of, zynqmp_qspi_of_match); static struct platform_driver zynqmp_qspi_driver = { .probe = zynqmp_qspi_probe, - .remove_new = zynqmp_qspi_remove, + .remove = zynqmp_qspi_remove, .driver = { .name = "zynqmp-qspi", .of_match_table = zynqmp_qspi_of_match, From 759541d78eb8d6ac12dab7df14d4434cf5756e14 Mon Sep 17 00:00:00 2001 From: Amit Kumar Mahapatra Date: Wed, 25 Sep 2024 17:12:03 +0530 Subject: [PATCH 22/58] dt-bindings: spi: zynqmp-qspi: Include two 'reg' properties only for the Zynq UltraScale QSPI Linear mode is only supported by the Zynq UltraScale QSPI controller, so update the bindings to include two 'reg' properties only for the Zynq UltraScale QSPI controller. Signed-off-by: Amit Kumar Mahapatra Reviewed-by: Krzysztof Kozlowski Link: https://patch.msgid.link/20240925114203.2234735-1-amit.kumar-mahapatra@amd.com Signed-off-by: Mark Brown --- .../bindings/spi/spi-zynqmp-qspi.yaml | 22 ++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/Documentation/devicetree/bindings/spi/spi-zynqmp-qspi.yaml b/Documentation/devicetree/bindings/spi/spi-zynqmp-qspi.yaml index e5199b109dad..04d4d3b4916d 100644 --- a/Documentation/devicetree/bindings/spi/spi-zynqmp-qspi.yaml +++ b/Documentation/devicetree/bindings/spi/spi-zynqmp-qspi.yaml @@ -9,9 +9,6 @@ title: Xilinx Zynq UltraScale+ MPSoC GQSPI controller maintainers: - Michal Simek -allOf: - - $ref: spi-controller.yaml# - properties: compatible: enum: @@ -19,6 +16,7 @@ properties: - xlnx,zynqmp-qspi-1.0 reg: + minItems: 1 maxItems: 2 interrupts: @@ -47,6 +45,24 @@ required: unevaluatedProperties: false +allOf: + - $ref: spi-controller.yaml# + + - if: + properties: + compatible: + contains: + const: xlnx,zynqmp-qspi-1.0 + then: + properties: + reg: + minItems: 2 + + else: + properties: + reg: + maxItems: 1 + examples: - | #include From 7a4b3ebf1d60349587fee21872536e7bd6a4cf39 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Sun, 22 Sep 2024 19:38:30 +0200 Subject: [PATCH 23/58] spi: airoha: do not keep {tx,rx} dma buffer always mapped DMA map txrx_buf on demand in airoha_snand_dirmap_read and airoha_snand_dirmap_write routines and do not keep it always mapped. This patch is not fixing any bug or introducing any functional change to the driver, it just simplifies the code and improve code readability without introducing any performance degradation according to the results obtained from the mtd_speedtest kernel module test. root@OpenWrt:# insmod mtd_test.ko root@OpenWrt:# insmod mtd_speedtest.ko dev=5 [ 49.849869] ================================================= [ 49.855659] mtd_speedtest: MTD device: 5 [ 49.859583] mtd_speedtest: MTD device size 8388608, eraseblock size 131072, page size 2048, count of eraseblocks 64, pages per eraseblock 64, OOB size 128 [ 49.874622] mtd_test: scanning for bad eraseblocks [ 49.879433] mtd_test: scanned 64 eraseblocks, 0 are bad [ 50.106372] mtd_speedtest: testing eraseblock write speed [ 53.083380] mtd_speedtest: eraseblock write speed is 2756 KiB/s [ 53.089322] mtd_speedtest: testing eraseblock read speed [ 54.143360] mtd_speedtest: eraseblock read speed is 7811 KiB/s [ 54.370365] mtd_speedtest: testing page write speed [ 57.349480] mtd_speedtest: page write speed is 2754 KiB/s [ 57.354895] mtd_speedtest: testing page read speed [ 58.410431] mtd_speedtest: page read speed is 7796 KiB/s [ 58.636805] mtd_speedtest: testing 2 page write speed [ 61.612427] mtd_speedtest: 2 page write speed is 2757 KiB/s [ 61.618021] mtd_speedtest: testing 2 page read speed [ 62.672653] mtd_speedtest: 2 page read speed is 7804 KiB/s [ 62.678159] mtd_speedtest: Testing erase speed [ 62.903617] mtd_speedtest: erase speed is 37063 KiB/s [ 62.908678] mtd_speedtest: Testing 2x multi-block erase speed [ 63.134083] mtd_speedtest: 2x multi-block erase speed is 37292 KiB/s [ 63.140442] mtd_speedtest: Testing 4x multi-block erase speed [ 63.364262] mtd_speedtest: 4x multi-block erase speed is 37566 KiB/s [ 63.370632] mtd_speedtest: Testing 8x multi-block erase speed [ 63.595740] mtd_speedtest: 8x multi-block erase speed is 37344 KiB/s [ 63.602089] mtd_speedtest: Testing 16x multi-block erase speed [ 63.827426] mtd_speedtest: 16x multi-block erase speed is 37320 KiB/s [ 63.833860] mtd_speedtest: Testing 32x multi-block erase speed [ 64.059389] mtd_speedtest: 32x multi-block erase speed is 37288 KiB/s [ 64.065833] mtd_speedtest: Testing 64x multi-block erase speed [ 64.290609] mtd_speedtest: 64x multi-block erase speed is 37415 KiB/s [ 64.297063] mtd_speedtest: finished [ 64.300555] ================================================= Tested-by: Christian Marangi Signed-off-by: Lorenzo Bianconi Link: https://patch.msgid.link/20240922-airoha-spi-fixes-v3-1-f958802b3d68@kernel.org Signed-off-by: Mark Brown --- drivers/spi/spi-airoha-snfi.c | 154 ++++++++++++++++------------------ 1 file changed, 71 insertions(+), 83 deletions(-) diff --git a/drivers/spi/spi-airoha-snfi.c b/drivers/spi/spi-airoha-snfi.c index 94458df53eae..ec7a71b347df 100644 --- a/drivers/spi/spi-airoha-snfi.c +++ b/drivers/spi/spi-airoha-snfi.c @@ -206,13 +206,6 @@ enum airoha_snand_cs { SPI_CHIP_SEL_LOW, }; -struct airoha_snand_dev { - size_t buf_len; - - u8 *txrx_buf; - dma_addr_t dma_addr; -}; - struct airoha_snand_ctrl { struct device *dev; struct regmap *regmap_ctrl; @@ -617,9 +610,9 @@ static bool airoha_snand_supports_op(struct spi_mem *mem, static int airoha_snand_dirmap_create(struct spi_mem_dirmap_desc *desc) { - struct airoha_snand_dev *as_dev = spi_get_ctldata(desc->mem->spi); + u8 *txrx_buf = spi_get_ctldata(desc->mem->spi); - if (!as_dev->txrx_buf) + if (!txrx_buf) return -EINVAL; if (desc->info.offset + desc->info.length > U32_MAX) @@ -634,10 +627,11 @@ static int airoha_snand_dirmap_create(struct spi_mem_dirmap_desc *desc) static ssize_t airoha_snand_dirmap_read(struct spi_mem_dirmap_desc *desc, u64 offs, size_t len, void *buf) { - struct spi_device *spi = desc->mem->spi; - struct airoha_snand_dev *as_dev = spi_get_ctldata(spi); struct spi_mem_op *op = &desc->info.op_tmpl; + struct spi_device *spi = desc->mem->spi; struct airoha_snand_ctrl *as_ctrl; + u8 *txrx_buf = spi_get_ctldata(spi); + dma_addr_t dma_addr; u32 val, rd_mode; int err; @@ -662,14 +656,17 @@ static ssize_t airoha_snand_dirmap_read(struct spi_mem_dirmap_desc *desc, if (err) return err; - dma_sync_single_for_device(as_ctrl->dev, as_dev->dma_addr, - as_dev->buf_len, DMA_BIDIRECTIONAL); + dma_addr = dma_map_single(as_ctrl->dev, txrx_buf, SPI_NAND_CACHE_SIZE, + DMA_FROM_DEVICE); + err = dma_mapping_error(as_ctrl->dev, dma_addr); + if (err) + return err; /* set dma addr */ err = regmap_write(as_ctrl->regmap_nfi, REG_SPI_NFI_STRADDR, - as_dev->dma_addr); + dma_addr); if (err) - return err; + goto error_dma_unmap; /* set cust sec size */ val = as_ctrl->nfi_cfg.sec_size * as_ctrl->nfi_cfg.sec_num; @@ -678,58 +675,58 @@ static ssize_t airoha_snand_dirmap_read(struct spi_mem_dirmap_desc *desc, REG_SPI_NFI_SNF_MISC_CTL2, SPI_NFI_READ_DATA_BYTE_NUM, val); if (err) - return err; + goto error_dma_unmap; /* set read command */ err = regmap_write(as_ctrl->regmap_nfi, REG_SPI_NFI_RD_CTL2, op->cmd.opcode); if (err) - return err; + goto error_dma_unmap; /* set read mode */ err = regmap_write(as_ctrl->regmap_nfi, REG_SPI_NFI_SNF_MISC_CTL, FIELD_PREP(SPI_NFI_DATA_READ_WR_MODE, rd_mode)); if (err) - return err; + goto error_dma_unmap; /* set read addr */ err = regmap_write(as_ctrl->regmap_nfi, REG_SPI_NFI_RD_CTL3, 0x0); if (err) - return err; + goto error_dma_unmap; /* set nfi read */ err = regmap_update_bits(as_ctrl->regmap_nfi, REG_SPI_NFI_CNFG, SPI_NFI_OPMODE, FIELD_PREP(SPI_NFI_OPMODE, 6)); if (err) - return err; + goto error_dma_unmap; err = regmap_set_bits(as_ctrl->regmap_nfi, REG_SPI_NFI_CNFG, SPI_NFI_READ_MODE | SPI_NFI_DMA_MODE); if (err) - return err; + goto error_dma_unmap; err = regmap_write(as_ctrl->regmap_nfi, REG_SPI_NFI_CMD, 0x0); if (err) - return err; + goto error_dma_unmap; /* trigger dma start read */ err = regmap_clear_bits(as_ctrl->regmap_nfi, REG_SPI_NFI_CON, SPI_NFI_RD_TRIG); if (err) - return err; + goto error_dma_unmap; err = regmap_set_bits(as_ctrl->regmap_nfi, REG_SPI_NFI_CON, SPI_NFI_RD_TRIG); if (err) - return err; + goto error_dma_unmap; err = regmap_read_poll_timeout(as_ctrl->regmap_nfi, REG_SPI_NFI_SNF_STA_CTL1, val, (val & SPI_NFI_READ_FROM_CACHE_DONE), 0, 1 * USEC_PER_SEC); if (err) - return err; + goto error_dma_unmap; /* * SPI_NFI_READ_FROM_CACHE_DONE bit must be written at the end @@ -739,35 +736,41 @@ static ssize_t airoha_snand_dirmap_read(struct spi_mem_dirmap_desc *desc, SPI_NFI_READ_FROM_CACHE_DONE, SPI_NFI_READ_FROM_CACHE_DONE); if (err) - return err; + goto error_dma_unmap; err = regmap_read_poll_timeout(as_ctrl->regmap_nfi, REG_SPI_NFI_INTR, val, (val & SPI_NFI_AHB_DONE), 0, 1 * USEC_PER_SEC); if (err) - return err; + goto error_dma_unmap; /* DMA read need delay for data ready from controller to DRAM */ udelay(1); - dma_sync_single_for_cpu(as_ctrl->dev, as_dev->dma_addr, - as_dev->buf_len, DMA_BIDIRECTIONAL); + dma_unmap_single(as_ctrl->dev, dma_addr, SPI_NAND_CACHE_SIZE, + DMA_FROM_DEVICE); err = airoha_snand_set_mode(as_ctrl, SPI_MODE_MANUAL); if (err < 0) return err; - memcpy(buf, as_dev->txrx_buf + offs, len); + memcpy(buf, txrx_buf + offs, len); return len; + +error_dma_unmap: + dma_unmap_single(as_ctrl->dev, dma_addr, SPI_NAND_CACHE_SIZE, + DMA_FROM_DEVICE); + return err; } static ssize_t airoha_snand_dirmap_write(struct spi_mem_dirmap_desc *desc, u64 offs, size_t len, const void *buf) { - struct spi_device *spi = desc->mem->spi; - struct airoha_snand_dev *as_dev = spi_get_ctldata(spi); struct spi_mem_op *op = &desc->info.op_tmpl; + struct spi_device *spi = desc->mem->spi; + u8 *txrx_buf = spi_get_ctldata(spi); struct airoha_snand_ctrl *as_ctrl; + dma_addr_t dma_addr; u32 wr_mode, val; int err; @@ -776,19 +779,20 @@ static ssize_t airoha_snand_dirmap_write(struct spi_mem_dirmap_desc *desc, if (err < 0) return err; - dma_sync_single_for_cpu(as_ctrl->dev, as_dev->dma_addr, - as_dev->buf_len, DMA_BIDIRECTIONAL); - memcpy(as_dev->txrx_buf + offs, buf, len); - dma_sync_single_for_device(as_ctrl->dev, as_dev->dma_addr, - as_dev->buf_len, DMA_BIDIRECTIONAL); + memcpy(txrx_buf + offs, buf, len); + dma_addr = dma_map_single(as_ctrl->dev, txrx_buf, SPI_NAND_CACHE_SIZE, + DMA_TO_DEVICE); + err = dma_mapping_error(as_ctrl->dev, dma_addr); + if (err) + return err; err = airoha_snand_set_mode(as_ctrl, SPI_MODE_DMA); if (err < 0) - return err; + goto error_dma_unmap; err = airoha_snand_nfi_config(as_ctrl); if (err) - return err; + goto error_dma_unmap; if (op->cmd.opcode == SPI_NAND_OP_PROGRAM_LOAD_QUAD || op->cmd.opcode == SPI_NAND_OP_PROGRAM_LOAD_RAMDON_QUAD) @@ -797,9 +801,9 @@ static ssize_t airoha_snand_dirmap_write(struct spi_mem_dirmap_desc *desc, wr_mode = 0; err = regmap_write(as_ctrl->regmap_nfi, REG_SPI_NFI_STRADDR, - as_dev->dma_addr); + dma_addr); if (err) - return err; + goto error_dma_unmap; val = FIELD_PREP(SPI_NFI_PROG_LOAD_BYTE_NUM, as_ctrl->nfi_cfg.sec_size * as_ctrl->nfi_cfg.sec_num); @@ -807,65 +811,65 @@ static ssize_t airoha_snand_dirmap_write(struct spi_mem_dirmap_desc *desc, REG_SPI_NFI_SNF_MISC_CTL2, SPI_NFI_PROG_LOAD_BYTE_NUM, val); if (err) - return err; + goto error_dma_unmap; err = regmap_write(as_ctrl->regmap_nfi, REG_SPI_NFI_PG_CTL1, FIELD_PREP(SPI_NFI_PG_LOAD_CMD, op->cmd.opcode)); if (err) - return err; + goto error_dma_unmap; err = regmap_write(as_ctrl->regmap_nfi, REG_SPI_NFI_SNF_MISC_CTL, FIELD_PREP(SPI_NFI_DATA_READ_WR_MODE, wr_mode)); if (err) - return err; + goto error_dma_unmap; err = regmap_write(as_ctrl->regmap_nfi, REG_SPI_NFI_PG_CTL2, 0x0); if (err) - return err; + goto error_dma_unmap; err = regmap_clear_bits(as_ctrl->regmap_nfi, REG_SPI_NFI_CNFG, SPI_NFI_READ_MODE); if (err) - return err; + goto error_dma_unmap; err = regmap_update_bits(as_ctrl->regmap_nfi, REG_SPI_NFI_CNFG, SPI_NFI_OPMODE, FIELD_PREP(SPI_NFI_OPMODE, 3)); if (err) - return err; + goto error_dma_unmap; err = regmap_set_bits(as_ctrl->regmap_nfi, REG_SPI_NFI_CNFG, SPI_NFI_DMA_MODE); if (err) - return err; + goto error_dma_unmap; err = regmap_write(as_ctrl->regmap_nfi, REG_SPI_NFI_CMD, 0x80); if (err) - return err; + goto error_dma_unmap; err = regmap_clear_bits(as_ctrl->regmap_nfi, REG_SPI_NFI_CON, SPI_NFI_WR_TRIG); if (err) - return err; + goto error_dma_unmap; err = regmap_set_bits(as_ctrl->regmap_nfi, REG_SPI_NFI_CON, SPI_NFI_WR_TRIG); if (err) - return err; + goto error_dma_unmap; err = regmap_read_poll_timeout(as_ctrl->regmap_nfi, REG_SPI_NFI_INTR, val, (val & SPI_NFI_AHB_DONE), 0, 1 * USEC_PER_SEC); if (err) - return err; + goto error_dma_unmap; err = regmap_read_poll_timeout(as_ctrl->regmap_nfi, REG_SPI_NFI_SNF_STA_CTL1, val, (val & SPI_NFI_LOAD_TO_CACHE_DONE), 0, 1 * USEC_PER_SEC); if (err) - return err; + goto error_dma_unmap; /* * SPI_NFI_LOAD_TO_CACHE_DONE bit must be written at the end @@ -875,13 +879,20 @@ static ssize_t airoha_snand_dirmap_write(struct spi_mem_dirmap_desc *desc, SPI_NFI_LOAD_TO_CACHE_DONE, SPI_NFI_LOAD_TO_CACHE_DONE); if (err) - return err; + goto error_dma_unmap; + dma_unmap_single(as_ctrl->dev, dma_addr, SPI_NAND_CACHE_SIZE, + DMA_TO_DEVICE); err = airoha_snand_set_mode(as_ctrl, SPI_MODE_MANUAL); if (err < 0) return err; return len; + +error_dma_unmap: + dma_unmap_single(as_ctrl->dev, dma_addr, SPI_NAND_CACHE_SIZE, + DMA_TO_DEVICE); + return err; } static int airoha_snand_exec_op(struct spi_mem *mem, @@ -956,42 +967,20 @@ static const struct spi_controller_mem_ops airoha_snand_mem_ops = { static int airoha_snand_setup(struct spi_device *spi) { struct airoha_snand_ctrl *as_ctrl; - struct airoha_snand_dev *as_dev; - - as_ctrl = spi_controller_get_devdata(spi->controller); - - as_dev = devm_kzalloc(as_ctrl->dev, sizeof(*as_dev), GFP_KERNEL); - if (!as_dev) - return -ENOMEM; + u8 *txrx_buf; /* prepare device buffer */ - as_dev->buf_len = SPI_NAND_CACHE_SIZE; - as_dev->txrx_buf = devm_kzalloc(as_ctrl->dev, as_dev->buf_len, - GFP_KERNEL); - if (!as_dev->txrx_buf) + as_ctrl = spi_controller_get_devdata(spi->controller); + txrx_buf = devm_kzalloc(as_ctrl->dev, SPI_NAND_CACHE_SIZE, + GFP_KERNEL); + if (!txrx_buf) return -ENOMEM; - as_dev->dma_addr = dma_map_single(as_ctrl->dev, as_dev->txrx_buf, - as_dev->buf_len, DMA_BIDIRECTIONAL); - if (dma_mapping_error(as_ctrl->dev, as_dev->dma_addr)) - return -ENOMEM; - - spi_set_ctldata(spi, as_dev); + spi_set_ctldata(spi, txrx_buf); return 0; } -static void airoha_snand_cleanup(struct spi_device *spi) -{ - struct airoha_snand_dev *as_dev = spi_get_ctldata(spi); - struct airoha_snand_ctrl *as_ctrl; - - as_ctrl = spi_controller_get_devdata(spi->controller); - dma_unmap_single(as_ctrl->dev, as_dev->dma_addr, - as_dev->buf_len, DMA_BIDIRECTIONAL); - spi_set_ctldata(spi, NULL); -} - static int airoha_snand_nfi_setup(struct airoha_snand_ctrl *as_ctrl) { u32 val, sec_size, sec_num; @@ -1093,7 +1082,6 @@ static int airoha_snand_probe(struct platform_device *pdev) ctrl->bits_per_word_mask = SPI_BPW_MASK(8); ctrl->mode_bits = SPI_RX_DUAL; ctrl->setup = airoha_snand_setup; - ctrl->cleanup = airoha_snand_cleanup; device_set_node(&ctrl->dev, dev_fwnode(dev)); err = airoha_snand_nfi_setup(as_ctrl); From 625de1881b5aee6a42a3130004e47dbd632429f8 Mon Sep 17 00:00:00 2001 From: Alexander Dahl Date: Wed, 18 Sep 2024 10:27:44 +0200 Subject: [PATCH 24/58] spi: atmel-quadspi: Add cs_hold and cs_inactive setting support spi-cs-inactive-delay-ns in dts is cs_inactive in spi core, and it maps to DLYCS (Minimum Inactive QCS Delay) in QSPI Mode Register (QSPI_MR). spi-cs-hold-delay-ns in dts is cs_hold in spi core, and it maps to DLYBCT (Delay Between Consecutive Transfers) in QSPI_MR. That one can be set to other values than 0 only if the chip is not in Serial Memory Mode (SMM), it must be written to '0' however when in SMM. Tested on SAM9X60 based board with FPGA implementing custom SPI Memory protocol. Signed-off-by: Alexander Dahl Link: https://patch.msgid.link/20240918082744.379610-3-ada@thorsis.com Signed-off-by: Mark Brown --- drivers/spi/atmel-quadspi.c | 36 ++++++++++++++++++++++++++++++++---- 1 file changed, 32 insertions(+), 4 deletions(-) diff --git a/drivers/spi/atmel-quadspi.c b/drivers/spi/atmel-quadspi.c index 20ee227dead2..b32807629189 100644 --- a/drivers/spi/atmel-quadspi.c +++ b/drivers/spi/atmel-quadspi.c @@ -516,21 +516,45 @@ static int atmel_qspi_set_cs_timing(struct spi_device *spi) struct spi_controller *ctrl = spi->controller; struct atmel_qspi *aq = spi_controller_get_devdata(ctrl); unsigned long clk_rate; + u32 cs_inactive; u32 cs_setup; + u32 cs_hold; int delay; int ret; - delay = spi_delay_to_ns(&spi->cs_setup, NULL); - if (delay <= 0) - return delay; - clk_rate = clk_get_rate(aq->pclk); if (!clk_rate) return -EINVAL; + /* hold */ + delay = spi_delay_to_ns(&spi->cs_hold, NULL); + if (aq->mr & QSPI_MR_SMM) { + if (delay > 0) + dev_warn(&aq->pdev->dev, + "Ignoring cs_hold, must be 0 in Serial Memory Mode.\n"); + cs_hold = 0; + } else { + delay = spi_delay_to_ns(&spi->cs_hold, NULL); + if (delay < 0) + return delay; + + cs_hold = DIV_ROUND_UP((delay * DIV_ROUND_UP(clk_rate, 1000000)), 32000); + } + + /* setup */ + delay = spi_delay_to_ns(&spi->cs_setup, NULL); + if (delay < 0) + return delay; + cs_setup = DIV_ROUND_UP((delay * DIV_ROUND_UP(clk_rate, 1000000)), 1000); + /* inactive */ + delay = spi_delay_to_ns(&spi->cs_inactive, NULL); + if (delay < 0) + return delay; + cs_inactive = DIV_ROUND_UP((delay * DIV_ROUND_UP(clk_rate, 1000000)), 1000); + ret = pm_runtime_resume_and_get(ctrl->dev.parent); if (ret < 0) return ret; @@ -539,6 +563,10 @@ static int atmel_qspi_set_cs_timing(struct spi_device *spi) aq->scr |= QSPI_SCR_DLYBS(cs_setup); atmel_qspi_write(aq->scr, aq, QSPI_SCR); + aq->mr &= ~(QSPI_MR_DLYBCT_MASK | QSPI_MR_DLYCS_MASK); + aq->mr |= QSPI_MR_DLYBCT(cs_hold) | QSPI_MR_DLYCS(cs_inactive); + atmel_qspi_write(aq->mr, aq, QSPI_MR); + pm_runtime_mark_last_busy(ctrl->dev.parent); pm_runtime_put_autosuspend(ctrl->dev.parent); From fa8ecda9876ac1e7b29257aa82af1fd0695496e2 Mon Sep 17 00:00:00 2001 From: Stefan Wahren Date: Mon, 30 Sep 2024 11:30:54 +0200 Subject: [PATCH 25/58] spi: spi-fsl-lpspi: Adjust type of scldiv The target value of scldiv is just a byte, but its calculation in fsl_lpspi_set_bitrate could be negative. So use an adequate type to store the result and avoid overflows. After that this needs range check adjustments, but this should make the code less opaque. Signed-off-by: Stefan Wahren Reviewed-by: Frank Li Link: https://patch.msgid.link/20240930093056.93418-2-wahrenst@gmx.net Signed-off-by: Mark Brown --- drivers/spi/spi-fsl-lpspi.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/spi/spi-fsl-lpspi.c b/drivers/spi/spi-fsl-lpspi.c index 977e8b55c82b..196cc68f2057 100644 --- a/drivers/spi/spi-fsl-lpspi.c +++ b/drivers/spi/spi-fsl-lpspi.c @@ -315,9 +315,10 @@ static void fsl_lpspi_set_watermark(struct fsl_lpspi_data *fsl_lpspi) static int fsl_lpspi_set_bitrate(struct fsl_lpspi_data *fsl_lpspi) { struct lpspi_config config = fsl_lpspi->config; - unsigned int perclk_rate, scldiv, div; + unsigned int perclk_rate, div; u8 prescale_max; u8 prescale; + int scldiv; perclk_rate = clk_get_rate(fsl_lpspi->clk_per); prescale_max = fsl_lpspi->devtype_data->prescale_max; @@ -338,13 +339,13 @@ static int fsl_lpspi_set_bitrate(struct fsl_lpspi_data *fsl_lpspi) for (prescale = 0; prescale <= prescale_max; prescale++) { scldiv = div / (1 << prescale) - 2; - if (scldiv < 256) { + if (scldiv >= 0 && scldiv < 256) { fsl_lpspi->config.prescale = prescale; break; } } - if (scldiv >= 256) + if (scldiv < 0 || scldiv >= 256) return -EINVAL; writel(scldiv | (scldiv << 8) | ((scldiv >> 1) << 16), From 7086f49dc442837996c08350a4d590e790b499db Mon Sep 17 00:00:00 2001 From: Stefan Wahren Date: Mon, 30 Sep 2024 11:30:55 +0200 Subject: [PATCH 26/58] spi: spi-fsl-lpspi: Fix specifiers in fsl_lpspi_set_bitrate Most of the parameters are unsigned, so fix the used format specifiers in the debug message in fsl_lpspi_set_bitrate. Signed-off-by: Stefan Wahren Reviewed-by: Frank Li Link: https://patch.msgid.link/20240930093056.93418-3-wahrenst@gmx.net Signed-off-by: Mark Brown --- drivers/spi/spi-fsl-lpspi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/spi/spi-fsl-lpspi.c b/drivers/spi/spi-fsl-lpspi.c index 196cc68f2057..3b5aa91079ae 100644 --- a/drivers/spi/spi-fsl-lpspi.c +++ b/drivers/spi/spi-fsl-lpspi.c @@ -351,7 +351,7 @@ static int fsl_lpspi_set_bitrate(struct fsl_lpspi_data *fsl_lpspi) writel(scldiv | (scldiv << 8) | ((scldiv >> 1) << 16), fsl_lpspi->base + IMX7ULP_CCR); - dev_dbg(fsl_lpspi->dev, "perclk=%d, speed=%d, prescale=%d, scldiv=%d\n", + dev_dbg(fsl_lpspi->dev, "perclk=%u, speed=%u, prescale=%u, scldiv=%d\n", perclk_rate, config.speed_hz, prescale, scldiv); return 0; From 667b5e803a94f1ce48ac85b3fef94891a8d40ccf Mon Sep 17 00:00:00 2001 From: Stefan Wahren Date: Mon, 30 Sep 2024 11:30:56 +0200 Subject: [PATCH 27/58] spi: spi-fsl-lpspi: support effective_speed_hz Setting spi_transfer->effective_speed_hz in transfer_one so that SPI client driver can use it. Signed-off-by: Stefan Wahren Reviewed-by: Frank Li Link: https://patch.msgid.link/20240930093056.93418-4-wahrenst@gmx.net Signed-off-by: Mark Brown --- drivers/spi/spi-fsl-lpspi.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/spi/spi-fsl-lpspi.c b/drivers/spi/spi-fsl-lpspi.c index 3b5aa91079ae..5d55ef4d4ba6 100644 --- a/drivers/spi/spi-fsl-lpspi.c +++ b/drivers/spi/spi-fsl-lpspi.c @@ -92,6 +92,7 @@ struct lpspi_config { u8 prescale; u16 mode; u32 speed_hz; + u32 effective_speed_hz; }; struct fsl_lpspi_data { @@ -351,6 +352,9 @@ static int fsl_lpspi_set_bitrate(struct fsl_lpspi_data *fsl_lpspi) writel(scldiv | (scldiv << 8) | ((scldiv >> 1) << 16), fsl_lpspi->base + IMX7ULP_CCR); + fsl_lpspi->config.effective_speed_hz = perclk_rate / (scldiv + 2) * + (1 << prescale); + dev_dbg(fsl_lpspi->dev, "perclk=%u, speed=%u, prescale=%u, scldiv=%d\n", perclk_rate, config.speed_hz, prescale, scldiv); @@ -750,6 +754,8 @@ static int fsl_lpspi_transfer_one(struct spi_controller *controller, if (ret < 0) return ret; + t->effective_speed_hz = fsl_lpspi->config.effective_speed_hz; + fsl_lpspi_set_cmd(fsl_lpspi); fsl_lpspi->is_first_byte = false; From 46854574fd76c711c890423f8ac60df4fb726559 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Wed, 2 Oct 2024 17:26:52 +0100 Subject: [PATCH 28/58] spi: spi-ti-qspi: remove redundant assignment to variable ret Variable ret is being assigned a value but it is never read, instead the variable is being reassigned later in the exit path via label no_dma. Remove the redundant assignment. Signed-off-by: Colin Ian King Link: https://patch.msgid.link/20241002162652.957102-1-colin.i.king@gmail.com Signed-off-by: Mark Brown --- drivers/spi/spi-ti-qspi.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/spi/spi-ti-qspi.c b/drivers/spi/spi-ti-qspi.c index 0b8f496c6bf4..dfd4a7948c03 100644 --- a/drivers/spi/spi-ti-qspi.c +++ b/drivers/spi/spi-ti-qspi.c @@ -863,7 +863,6 @@ static int ti_qspi_probe(struct platform_device *pdev) dev_err(qspi->dev, "No Rx DMA available, trying mmap mode\n"); qspi->rx_chan = NULL; - ret = 0; goto no_dma; } qspi->rx_bb_addr = dma_alloc_coherent(qspi->dev, From eb6c65049a274c37f9b6fdf632843b609a0b8fa8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Fri, 4 Oct 2024 11:42:32 +0200 Subject: [PATCH 29/58] spi: Provide defer reason if getting irq during probe fails MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Using dev_err_probe() in spi_probe() improves the kernel output from spi spi0.0: deferred probe pending: (reason unknown) to spi spi0.0: deferred probe pending: ad7124: Failed to get irq... for my current quest to make a certain spi device work. Signed-off-by: Uwe Kleine-König Link: https://patch.msgid.link/20241004094234.268301-2-u.kleine-koenig@baylibre.com Signed-off-by: Mark Brown --- drivers/spi/spi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index 073ffae97767..7c5e76b15421 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -419,7 +419,7 @@ static int spi_probe(struct device *dev) if (dev->of_node) { spi->irq = of_irq_get(dev->of_node, 0); if (spi->irq == -EPROBE_DEFER) - return -EPROBE_DEFER; + return dev_err_probe(dev, -EPROBE_DEFER, "Failed to get irq\n"); if (spi->irq < 0) spi->irq = 0; } From 66c1c4175bbdfcf1cb1411b1ea62e7e0b5571594 Mon Sep 17 00:00:00 2001 From: Hardevsinh Palaniya Date: Tue, 8 Oct 2024 11:25:45 +0530 Subject: [PATCH 30/58] spi: spi-fsl-dspi: Fix casting warnings Sparse warnings: drivers/spi/spi-fsl-dspi.c:283:17: warning: incorrect type in assignment (different base types) drivers/spi/spi-fsl-dspi.c:283:17: expected unsigned int [usertype] drivers/spi/spi-fsl-dspi.c:283:17: got restricted __be32 [usertype] drivers/spi/spi-fsl-dspi.c:289:28: warning: cast to restricted __be32 drivers/spi/spi-fsl-dspi.c:289:28: warning: cast to restricted __be32 drivers/spi/spi-fsl-dspi.c:289:28: warning: cast to restricted __be32 drivers/spi/spi-fsl-dspi.c:289:28: warning: cast to restricted __be32 drivers/spi/spi-fsl-dspi.c:289:28: warning: cast to restricted __be32 drivers/spi/spi-fsl-dspi.c:289:28: warning: cast to restricted __be32 drivers/spi/spi-fsl-dspi.c:295:17: warning: incorrect type in assignment (different base types) drivers/spi/spi-fsl-dspi.c:295:17: expected unsigned int [usertype] drivers/spi/spi-fsl-dspi.c:295:17: got restricted __be16 [usertype] drivers/spi/spi-fsl-dspi.c:301:28: warning: cast to restricted __be16 drivers/spi/spi-fsl-dspi.c:301:28: warning: cast to restricted __be16 drivers/spi/spi-fsl-dspi.c:301:28: warning: cast to restricted __be16 drivers/spi/spi-fsl-dspi.c:301:28: warning: cast to restricted __be16 Signed-off-by: Hardevsinh Palaniya Reviewed-by: Vladimir Oltean Tested-by: Vladimir Oltean Link: https://patch.msgid.link/20241008055644.4900-2-hardevsinh.palaniya@siliconsignals.io Signed-off-by: Mark Brown --- drivers/spi/spi-fsl-dspi.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/spi/spi-fsl-dspi.c b/drivers/spi/spi-fsl-dspi.c index 72044d76d736..b52950a0f5f9 100644 --- a/drivers/spi/spi-fsl-dspi.c +++ b/drivers/spi/spi-fsl-dspi.c @@ -280,25 +280,25 @@ static void dspi_native_dev_to_host(struct fsl_dspi *dspi, u32 rxdata) static void dspi_8on32_host_to_dev(struct fsl_dspi *dspi, u32 *txdata) { - *txdata = cpu_to_be32(*(u32 *)dspi->tx); + *txdata = (__force u32)cpu_to_be32(*(u32 *)dspi->tx); dspi->tx += sizeof(u32); } static void dspi_8on32_dev_to_host(struct fsl_dspi *dspi, u32 rxdata) { - *(u32 *)dspi->rx = be32_to_cpu(rxdata); + *(u32 *)dspi->rx = be32_to_cpu((__force __be32)rxdata); dspi->rx += sizeof(u32); } static void dspi_8on16_host_to_dev(struct fsl_dspi *dspi, u32 *txdata) { - *txdata = cpu_to_be16(*(u16 *)dspi->tx); + *txdata = (__force u32)cpu_to_be16(*(u16 *)dspi->tx); dspi->tx += sizeof(u16); } static void dspi_8on16_dev_to_host(struct fsl_dspi *dspi, u32 rxdata) { - *(u16 *)dspi->rx = be16_to_cpu(rxdata); + *(u16 *)dspi->rx = be16_to_cpu((__force __be16)rxdata); dspi->rx += sizeof(u16); } From f3a59ab98cfc18c7b2fb1d8164bedbb1569a7e76 Mon Sep 17 00:00:00 2001 From: Hardevsinh Palaniya Date: Tue, 8 Oct 2024 11:25:46 +0530 Subject: [PATCH 31/58] spi: spi-imx: Fix casting warnings Sparse warnings: drivers/spi/spi-imx.c:410:19: warning: cast to restricted __be32 drivers/spi/spi-imx.c:410:19: warning: cast to restricted __be32 drivers/spi/spi-imx.c:410:19: warning: cast to restricted __be32 drivers/spi/spi-imx.c:410:19: warning: cast to restricted __be32 drivers/spi/spi-imx.c:410:19: warning: cast to restricted __be32 drivers/spi/spi-imx.c:410:19: warning: cast to restricted __be32 drivers/spi/spi-imx.c:439:21: warning: incorrect type in assignment (different base types) drivers/spi/spi-imx.c:439:21: expected unsigned int [addressable] [usertype] val drivers/spi/spi-imx.c:439:21: got restricted __be32 [usertype] Signed-off-by: Hardevsinh Palaniya Reviewed-by: Frank Li Link: https://patch.msgid.link/20241008055644.4900-3-hardevsinh.palaniya@siliconsignals.io Signed-off-by: Mark Brown --- drivers/spi/spi-imx.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/spi/spi-imx.c b/drivers/spi/spi-imx.c index adfd7d74a984..84c3da1a1e22 100644 --- a/drivers/spi/spi-imx.c +++ b/drivers/spi/spi-imx.c @@ -407,7 +407,7 @@ static void spi_imx_buf_tx_swap(struct spi_imx_data *spi_imx) static void mx53_ecspi_rx_target(struct spi_imx_data *spi_imx) { - u32 val = be32_to_cpu(readl(spi_imx->base + MXC_CSPIRXDATA)); + u32 val = ioread32be(spi_imx->base + MXC_CSPIRXDATA); if (spi_imx->rx_buf) { int n_bytes = spi_imx->target_burst % sizeof(val); @@ -436,13 +436,12 @@ static void mx53_ecspi_tx_target(struct spi_imx_data *spi_imx) if (spi_imx->tx_buf) { memcpy(((u8 *)&val) + sizeof(val) - n_bytes, spi_imx->tx_buf, n_bytes); - val = cpu_to_be32(val); spi_imx->tx_buf += n_bytes; } spi_imx->count -= n_bytes; - writel(val, spi_imx->base + MXC_CSPITXDATA); + iowrite32be(val, spi_imx->base + MXC_CSPITXDATA); } /* MX51 eCSPI */ From f7bc15211fc6946203dd7e57c123f1e387d7225b Mon Sep 17 00:00:00 2001 From: Dragan Simic Date: Sun, 29 Sep 2024 11:21:13 +0200 Subject: [PATCH 32/58] spi: rockchip: Perform trivial code cleanups Perform a few trivial code cleanups, to obey the reverse Christmas tree rule, to avoid unnecessary line wrapping by using the 100-column width better, to actually obey the 100-column width in one case, and to make the way a couple of wrapped function arguments are indented a bit more readable. No intended functional changes are introduced by these code cleanups. Reviewed-by: Heiko Stuebner Signed-off-by: Dragan Simic Link: https://patch.msgid.link/1b55380a0b9f0e8fe1a09611636b30e232b95d08.1727601608.git.dsimic@manjaro.org Signed-off-by: Mark Brown --- drivers/spi/spi-rockchip.c | 29 +++++++++++++---------------- 1 file changed, 13 insertions(+), 16 deletions(-) diff --git a/drivers/spi/spi-rockchip.c b/drivers/spi/spi-rockchip.c index 0bb33c43b1b4..81046f7b7591 100644 --- a/drivers/spi/spi-rockchip.c +++ b/drivers/spi/spi-rockchip.c @@ -742,22 +742,20 @@ static int rockchip_spi_setup(struct spi_device *spi) static int rockchip_spi_probe(struct platform_device *pdev) { - int ret; - struct rockchip_spi *rs; - struct spi_controller *ctlr; - struct resource *mem; struct device_node *np = pdev->dev.of_node; + struct spi_controller *ctlr; + struct rockchip_spi *rs; + struct resource *mem; u32 rsd_nsecs, num_cs; bool target_mode; + int ret; target_mode = of_property_read_bool(np, "spi-slave"); if (target_mode) - ctlr = spi_alloc_target(&pdev->dev, - sizeof(struct rockchip_spi)); + ctlr = spi_alloc_target(&pdev->dev, sizeof(struct rockchip_spi)); else - ctlr = spi_alloc_host(&pdev->dev, - sizeof(struct rockchip_spi)); + ctlr = spi_alloc_host(&pdev->dev, sizeof(struct rockchip_spi)); if (!ctlr) return -ENOMEM; @@ -769,7 +767,7 @@ static int rockchip_spi_probe(struct platform_device *pdev) /* Get basic io resource and map it */ rs->regs = devm_platform_get_and_ioremap_resource(pdev, 0, &mem); if (IS_ERR(rs->regs)) { - ret = PTR_ERR(rs->regs); + ret = PTR_ERR(rs->regs); goto err_put_ctlr; } @@ -794,7 +792,7 @@ static int rockchip_spi_probe(struct platform_device *pdev) goto err_put_ctlr; ret = devm_request_threaded_irq(&pdev->dev, ret, rockchip_spi_isr, NULL, - IRQF_ONESHOT, dev_name(&pdev->dev), ctlr); + IRQF_ONESHOT, dev_name(&pdev->dev), ctlr); if (ret) goto err_put_ctlr; @@ -804,16 +802,15 @@ static int rockchip_spi_probe(struct platform_device *pdev) if (!of_property_read_u32(pdev->dev.of_node, "rx-sample-delay-ns", &rsd_nsecs)) { /* rx sample delay is expressed in parent clock cycles (max 3) */ - u32 rsd = DIV_ROUND_CLOSEST(rsd_nsecs * (rs->freq >> 8), - 1000000000 >> 8); + u32 rsd = DIV_ROUND_CLOSEST(rsd_nsecs * (rs->freq >> 8), 1000000000 >> 8); if (!rsd) { dev_warn(rs->dev, "%u Hz are too slow to express %u ns delay\n", - rs->freq, rsd_nsecs); + rs->freq, rsd_nsecs); } else if (rsd > CR0_RSD_MAX) { rsd = CR0_RSD_MAX; - dev_warn(rs->dev, "%u Hz are too fast to express %u ns delay, clamping at %u ns\n", - rs->freq, rsd_nsecs, - CR0_RSD_MAX * 1000000000U / rs->freq); + dev_warn(rs->dev, + "%u Hz are too fast to express %u ns delay, clamping at %u ns\n", + rs->freq, rsd_nsecs, CR0_RSD_MAX * 1000000000U / rs->freq); } rs->rsd = rsd; } From cb91287b3b6d42e66f948fbc304f771792c2852f Mon Sep 17 00:00:00 2001 From: Dragan Simic Date: Sun, 29 Sep 2024 11:21:14 +0200 Subject: [PATCH 33/58] spi: rockchip-sfc: Perform trivial code cleanups Perform a couple of trivial code cleanups, to avoid unnecessary line wrapping by using the 100-column width a bit better, and to drop a stray empty line. No intended functional changes are introduced by these code cleanups. Reviewed-by: Heiko Stuebner Signed-off-by: Dragan Simic Link: https://patch.msgid.link/4dcd5d9cc4a20c9c6ad504d945475b767399b32f.1727601608.git.dsimic@manjaro.org Signed-off-by: Mark Brown --- drivers/spi/spi-rockchip-sfc.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/drivers/spi/spi-rockchip-sfc.c b/drivers/spi/spi-rockchip-sfc.c index 0d7fadcd4ed3..505d5089bf03 100644 --- a/drivers/spi/spi-rockchip-sfc.c +++ b/drivers/spi/spi-rockchip-sfc.c @@ -591,8 +591,7 @@ static int rockchip_sfc_probe(struct platform_device *pdev) return PTR_ERR(sfc->hclk); } - sfc->use_dma = !of_property_read_bool(sfc->dev->of_node, - "rockchip,sfc-no-dma"); + sfc->use_dma = !of_property_read_bool(sfc->dev->of_node, "rockchip,sfc-no-dma"); if (sfc->use_dma) { ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32)); @@ -602,8 +601,7 @@ static int rockchip_sfc_probe(struct platform_device *pdev) } sfc->buffer = dmam_alloc_coherent(dev, SFC_MAX_IOSIZE_VER3, - &sfc->dma_buffer, - GFP_KERNEL); + &sfc->dma_buffer, GFP_KERNEL); if (!sfc->buffer) return -ENOMEM; } @@ -629,7 +627,6 @@ static int rockchip_sfc_probe(struct platform_device *pdev) 0, pdev->name, sfc); if (ret) { dev_err(dev, "Failed to request irq\n"); - goto err_irq; } From 7d46b8d8d78338a2ad986eec0790ddb22fad23a8 Mon Sep 17 00:00:00 2001 From: Dragan Simic Date: Sun, 29 Sep 2024 11:21:15 +0200 Subject: [PATCH 34/58] spi: rockchip-sfc: Use dev_err_probe() in the probe path Use function dev_err_probe() in the probe path instead of dev_err() where appropriate, to make the code a bit more uniform and compact. Reviewed-by: Heiko Stuebner Signed-off-by: Dragan Simic Link: https://patch.msgid.link/398229ef316e64dc0c27944ea793dcddef1ead4e.1727601608.git.dsimic@manjaro.org Signed-off-by: Mark Brown --- drivers/spi/spi-rockchip-sfc.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/drivers/spi/spi-rockchip-sfc.c b/drivers/spi/spi-rockchip-sfc.c index 505d5089bf03..7e0fb4944a34 100644 --- a/drivers/spi/spi-rockchip-sfc.c +++ b/drivers/spi/spi-rockchip-sfc.c @@ -580,16 +580,14 @@ static int rockchip_sfc_probe(struct platform_device *pdev) return PTR_ERR(sfc->regbase); sfc->clk = devm_clk_get(&pdev->dev, "clk_sfc"); - if (IS_ERR(sfc->clk)) { - dev_err(&pdev->dev, "Failed to get sfc interface clk\n"); - return PTR_ERR(sfc->clk); - } + if (IS_ERR(sfc->clk)) + return dev_err_probe(&pdev->dev, PTR_ERR(sfc->clk), + "Failed to get sfc interface clk\n"); sfc->hclk = devm_clk_get(&pdev->dev, "hclk_sfc"); - if (IS_ERR(sfc->hclk)) { - dev_err(&pdev->dev, "Failed to get sfc ahb clk\n"); - return PTR_ERR(sfc->hclk); - } + if (IS_ERR(sfc->hclk)) + return dev_err_probe(&pdev->dev, PTR_ERR(sfc->hclk), + "Failed to get sfc ahb clk\n"); sfc->use_dma = !of_property_read_bool(sfc->dev->of_node, "rockchip,sfc-no-dma"); From 36e69b160705b65bf136c2fb6a1194447eeb8478 Mon Sep 17 00:00:00 2001 From: Dragan Simic Date: Sun, 29 Sep 2024 11:21:16 +0200 Subject: [PATCH 35/58] driver core: Add device probe log helper dev_warn_probe() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Some drivers can still provide their functionality to a certain extent even when some of their resource acquisitions eventually fail. In such cases, emitting errors isn't the desired action, but warnings should be emitted instead. To solve this, introduce dev_warn_probe() as a new device probe log helper, which behaves identically as the already existing dev_err_probe(), while it produces warnings instead of errors. The intended use is with the resources that are actually optional for a particular driver. While there, copyedit the kerneldoc for dev_err_probe() a bit, to simplify its wording a bit, and reuse it as the kerneldoc for dev_warn_probe(), with the necessary wording adjustments, of course. Signed-off-by: Dragan Simic Tested-by: Hélène Vulquin Acked-by: Greg Kroah-Hartman Link: https://patch.msgid.link/2be0a28538bb2a3d1bcc91e2ca1f2d0dc09146d9.1727601608.git.dsimic@manjaro.org Signed-off-by: Mark Brown --- drivers/base/core.c | 131 +++++++++++++++++++++++++++++-------- include/linux/dev_printk.h | 1 + 2 files changed, 103 insertions(+), 29 deletions(-) diff --git a/drivers/base/core.c b/drivers/base/core.c index a4c853411a6b..a84a7b952cfd 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -4980,6 +4980,49 @@ define_dev_printk_level(_dev_info, KERN_INFO); #endif +static void __dev_probe_failed(const struct device *dev, int err, bool fatal, + const char *fmt, va_list vargsp) +{ + struct va_format vaf; + va_list vargs; + + /* + * On x86_64 and possibly on other architectures, va_list is actually a + * size-1 array containing a structure. As a result, function parameter + * vargsp decays from T[1] to T*, and &vargsp has type T** rather than + * T(*)[1], which is expected by its assignment to vaf.va below. + * + * One standard way to solve this mess is by creating a copy in a local + * variable of type va_list and then using a pointer to that local copy + * instead, which is the approach employed here. + */ + va_copy(vargs, vargsp); + + vaf.fmt = fmt; + vaf.va = &vargs; + + switch (err) { + case -EPROBE_DEFER: + device_set_deferred_probe_reason(dev, &vaf); + dev_dbg(dev, "error %pe: %pV", ERR_PTR(err), &vaf); + break; + + case -ENOMEM: + /* Don't print anything on -ENOMEM, there's already enough output */ + break; + + default: + /* Log fatal final failures as errors, otherwise produce warnings */ + if (fatal) + dev_err(dev, "error %pe: %pV", ERR_PTR(err), &vaf); + else + dev_warn(dev, "error %pe: %pV", ERR_PTR(err), &vaf); + break; + } + + va_end(vargs); +} + /** * dev_err_probe - probe error check and log helper * @dev: the pointer to the struct device @@ -4992,7 +5035,7 @@ define_dev_printk_level(_dev_info, KERN_INFO); * -EPROBE_DEFER and propagate error upwards. * In case of -EPROBE_DEFER it sets also defer probe reason, which can be * checked later by reading devices_deferred debugfs attribute. - * It replaces code sequence:: + * It replaces the following code sequence:: * * if (err != -EPROBE_DEFER) * dev_err(dev, ...); @@ -5004,48 +5047,78 @@ define_dev_printk_level(_dev_info, KERN_INFO); * * return dev_err_probe(dev, err, ...); * - * Using this helper in your probe function is totally fine even if @err is - * known to never be -EPROBE_DEFER. + * Using this helper in your probe function is totally fine even if @err + * is known to never be -EPROBE_DEFER. * The benefit compared to a normal dev_err() is the standardized format - * of the error code, it being emitted symbolically (i.e. you get "EAGAIN" - * instead of "-35") and the fact that the error code is returned which allows - * more compact error paths. + * of the error code, which is emitted symbolically (i.e. you get "EAGAIN" + * instead of "-35"), and having the error code returned allows more + * compact error paths. * * Returns @err. */ int dev_err_probe(const struct device *dev, int err, const char *fmt, ...) { - struct va_format vaf; - va_list args; + va_list vargs; - va_start(args, fmt); - vaf.fmt = fmt; - vaf.va = &args; + va_start(vargs, fmt); - switch (err) { - case -EPROBE_DEFER: - device_set_deferred_probe_reason(dev, &vaf); - dev_dbg(dev, "error %pe: %pV", ERR_PTR(err), &vaf); - break; + /* Use dev_err() for logging when err doesn't equal -EPROBE_DEFER */ + __dev_probe_failed(dev, err, true, fmt, vargs); - case -ENOMEM: - /* - * We don't print anything on -ENOMEM, there is already enough - * output. - */ - break; - - default: - dev_err(dev, "error %pe: %pV", ERR_PTR(err), &vaf); - break; - } - - va_end(args); + va_end(vargs); return err; } EXPORT_SYMBOL_GPL(dev_err_probe); +/** + * dev_warn_probe - probe error check and log helper + * @dev: the pointer to the struct device + * @err: error value to test + * @fmt: printf-style format string + * @...: arguments as specified in the format string + * + * This helper implements common pattern present in probe functions for error + * checking: print debug or warning message depending if the error value is + * -EPROBE_DEFER and propagate error upwards. + * In case of -EPROBE_DEFER it sets also defer probe reason, which can be + * checked later by reading devices_deferred debugfs attribute. + * It replaces the following code sequence:: + * + * if (err != -EPROBE_DEFER) + * dev_warn(dev, ...); + * else + * dev_dbg(dev, ...); + * return err; + * + * with:: + * + * return dev_warn_probe(dev, err, ...); + * + * Using this helper in your probe function is totally fine even if @err + * is known to never be -EPROBE_DEFER. + * The benefit compared to a normal dev_warn() is the standardized format + * of the error code, which is emitted symbolically (i.e. you get "EAGAIN" + * instead of "-35"), and having the error code returned allows more + * compact error paths. + * + * Returns @err. + */ +int dev_warn_probe(const struct device *dev, int err, const char *fmt, ...) +{ + va_list vargs; + + va_start(vargs, fmt); + + /* Use dev_warn() for logging when err doesn't equal -EPROBE_DEFER */ + __dev_probe_failed(dev, err, false, fmt, vargs); + + va_end(vargs); + + return err; +} +EXPORT_SYMBOL_GPL(dev_warn_probe); + static inline bool fwnode_is_primary(struct fwnode_handle *fwnode) { return fwnode && !IS_ERR(fwnode->secondary); diff --git a/include/linux/dev_printk.h b/include/linux/dev_printk.h index ca32b5bb28eb..eb2094e43050 100644 --- a/include/linux/dev_printk.h +++ b/include/linux/dev_printk.h @@ -276,6 +276,7 @@ do { \ dev_driver_string(dev), dev_name(dev), ## arg) __printf(3, 4) int dev_err_probe(const struct device *dev, int err, const char *fmt, ...); +__printf(3, 4) int dev_warn_probe(const struct device *dev, int err, const char *fmt, ...); /* Simple helper for dev_err_probe() when ERR_PTR() is to be returned. */ #define dev_err_ptr_probe(dev, ___err, fmt, ...) \ From e2fc05873905f2ee96b38a116ae86f45fe7d8e49 Mon Sep 17 00:00:00 2001 From: Dragan Simic Date: Sun, 29 Sep 2024 11:21:17 +0200 Subject: [PATCH 36/58] spi: rockchip: Use dev_{err,warn}_probe() in the probe path MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use function dev_err_probe() in the probe path instead of dev_err() where appropriate, to make the code a bit more uniform and compact. Use the new function dev_warn_probe() to improve error handling for the TX and RX DMA channel requests, which are actually optional, and tweak the logged warnings a bit to additionally describe their optional nature. Previously, deferred requests for the TX and RX DMA channels produced no debug messages, and the final error messages didn't include the error codes, which are all highly useful when debugging permanently failed DMA channel requests, such as when the required drivers aren't enabled. Suggested-by: Hélene Vulquin Signed-off-by: Dragan Simic Tested-by: Hélène Vulquin Link: https://patch.msgid.link/5b6bd142dab3ab93d7039db3e2fdcfea6bee2217.1727601608.git.dsimic@manjaro.org Signed-off-by: Mark Brown --- drivers/spi/spi-rockchip.c | 28 +++++++++++++--------------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/drivers/spi/spi-rockchip.c b/drivers/spi/spi-rockchip.c index 81046f7b7591..5b1857b25d31 100644 --- a/drivers/spi/spi-rockchip.c +++ b/drivers/spi/spi-rockchip.c @@ -773,15 +773,15 @@ static int rockchip_spi_probe(struct platform_device *pdev) rs->apb_pclk = devm_clk_get_enabled(&pdev->dev, "apb_pclk"); if (IS_ERR(rs->apb_pclk)) { - dev_err(&pdev->dev, "Failed to get apb_pclk\n"); - ret = PTR_ERR(rs->apb_pclk); + ret = dev_err_probe(&pdev->dev, PTR_ERR(rs->apb_pclk), + "Failed to get apb_pclk\n"); goto err_put_ctlr; } rs->spiclk = devm_clk_get_enabled(&pdev->dev, "spiclk"); if (IS_ERR(rs->spiclk)) { - dev_err(&pdev->dev, "Failed to get spi_pclk\n"); - ret = PTR_ERR(rs->spiclk); + ret = dev_err_probe(&pdev->dev, PTR_ERR(rs->spiclk), + "Failed to get spi_pclk\n"); goto err_put_ctlr; } @@ -817,8 +817,7 @@ static int rockchip_spi_probe(struct platform_device *pdev) rs->fifo_len = get_fifo_len(rs); if (!rs->fifo_len) { - dev_err(&pdev->dev, "Failed to get fifo length\n"); - ret = -EINVAL; + ret = dev_err_probe(&pdev->dev, -EINVAL, "Failed to get fifo length\n"); goto err_put_ctlr; } @@ -858,22 +857,21 @@ static int rockchip_spi_probe(struct platform_device *pdev) ctlr->dma_tx = dma_request_chan(rs->dev, "tx"); if (IS_ERR(ctlr->dma_tx)) { - /* Check tx to see if we need defer probing driver */ - if (PTR_ERR(ctlr->dma_tx) == -EPROBE_DEFER) { - ret = -EPROBE_DEFER; + /* Check tx to see if we need to defer driver probing */ + ret = dev_warn_probe(rs->dev, PTR_ERR(ctlr->dma_tx), + "Failed to request optional TX DMA channel\n"); + if (ret == -EPROBE_DEFER) goto err_disable_pm_runtime; - } - dev_warn(rs->dev, "Failed to request TX DMA channel\n"); ctlr->dma_tx = NULL; } ctlr->dma_rx = dma_request_chan(rs->dev, "rx"); if (IS_ERR(ctlr->dma_rx)) { - if (PTR_ERR(ctlr->dma_rx) == -EPROBE_DEFER) { - ret = -EPROBE_DEFER; + /* Check rx to see if we need to defer driver probing */ + ret = dev_warn_probe(rs->dev, PTR_ERR(ctlr->dma_rx), + "Failed to request optional RX DMA channel\n"); + if (ret == -EPROBE_DEFER) goto err_free_dma_tx; - } - dev_warn(rs->dev, "Failed to request RX DMA channel\n"); ctlr->dma_rx = NULL; } From b1258105f9ce5203f48a47fd2f2cec8c38c41841 Mon Sep 17 00:00:00 2001 From: Alexander Usyskin Date: Wed, 9 Oct 2024 09:22:44 +0300 Subject: [PATCH 37/58] spi: intel: Add protected and locked attributes The manufacturing access to the PCH/SoC SPI device is traditionally performed via userspace driver accessing registers via /dev/mem but due to security concerns /dev/mem access is being much restricted, hence the reason for utilizing dedicated Intel PCH/SoC SPI controller driver, which is already implemented in the Linux kernel. Intel PCH/SoC SPI controller protects the flash storage via two mechanisms one is the via region protection registers and second via BIOS lock. The BIOS locks only the BIOS regions usually 0 and/or 6. The device always boots with BIOS lock set, but during manufacturing the BIOS lock has to be lifted in order to enable the write access. This can be done by passing "writeable=1" in the command line when the driver is loaded. This "locked" state is exposed through new sysfs attributes (intel_spi_locked, intel_spi_bios_locked). Second, also the region protection status is exposed via sysfs attribute (intel_spi_protected) as the manufacturing will need the both files in order to validate that the device is properly sealed. Includes code written by Tamar Mashiah. Signed-off-by: Alexander Usyskin Co-developed-by: Tomas Winkler Signed-off-by: Tomas Winkler Reviewed-by: Andy Shevchenko Signed-off-by: Mika Westerberg Link: https://patch.msgid.link/20241009062244.2436793-1-mika.westerberg@linux.intel.com Signed-off-by: Mark Brown --- .../ABI/testing/sysfs-driver-spi-intel | 20 ++++++ drivers/spi/spi-intel-pci.c | 1 + drivers/spi/spi-intel-platform.c | 1 + drivers/spi/spi-intel.c | 64 +++++++++++++++++-- drivers/spi/spi-intel.h | 2 + 5 files changed, 83 insertions(+), 5 deletions(-) create mode 100644 Documentation/ABI/testing/sysfs-driver-spi-intel diff --git a/Documentation/ABI/testing/sysfs-driver-spi-intel b/Documentation/ABI/testing/sysfs-driver-spi-intel new file mode 100644 index 000000000000..d7c9139ddbf3 --- /dev/null +++ b/Documentation/ABI/testing/sysfs-driver-spi-intel @@ -0,0 +1,20 @@ +What: /sys/devices/.../intel_spi_protected +Date: Feb 2025 +KernelVersion: 6.13 +Contact: Alexander Usyskin +Description: This attribute allows the userspace to check if the + Intel SPI flash controller is write protected from the host. + +What: /sys/devices/.../intel_spi_locked +Date: Feb 2025 +KernelVersion: 6.13 +Contact: Alexander Usyskin +Description: This attribute allows the user space to check if the + Intel SPI flash controller locks supported opcodes. + +What: /sys/devices/.../intel_spi_bios_locked +Date: Feb 2025 +KernelVersion: 6.13 +Contact: Alexander Usyskin +Description: This attribute allows the user space to check if the + Intel SPI flash controller BIOS region is locked for writes. diff --git a/drivers/spi/spi-intel-pci.c b/drivers/spi/spi-intel-pci.c index 4337ca51d7aa..c3b54928143d 100644 --- a/drivers/spi/spi-intel-pci.c +++ b/drivers/spi/spi-intel-pci.c @@ -94,6 +94,7 @@ static struct pci_driver intel_spi_pci_driver = { .name = "intel-spi", .id_table = intel_spi_pci_ids, .probe = intel_spi_pci_probe, + .dev_groups = intel_spi_groups, }; module_pci_driver(intel_spi_pci_driver); diff --git a/drivers/spi/spi-intel-platform.c b/drivers/spi/spi-intel-platform.c index 2ef09fa35661..0974cca83a5d 100644 --- a/drivers/spi/spi-intel-platform.c +++ b/drivers/spi/spi-intel-platform.c @@ -28,6 +28,7 @@ static struct platform_driver intel_spi_platform_driver = { .probe = intel_spi_platform_probe, .driver = { .name = "intel-spi", + .dev_groups = intel_spi_groups, }, }; diff --git a/drivers/spi/spi-intel.c b/drivers/spi/spi-intel.c index 795b7e72baea..b0dcdb6fb8fa 100644 --- a/drivers/spi/spi-intel.c +++ b/drivers/spi/spi-intel.c @@ -148,6 +148,8 @@ * @pr_num: Maximum number of protected range registers * @chip0_size: Size of the first flash chip in bytes * @locked: Is SPI setting locked + * @protected: Whether the regions are write protected + * @bios_locked: Is BIOS region locked * @swseq_reg: Use SW sequencer in register reads/writes * @swseq_erase: Use SW sequencer in erase operation * @atomic_preopcode: Holds preopcode when atomic sequence is requested @@ -166,6 +168,8 @@ struct intel_spi { size_t pr_num; size_t chip0_size; bool locked; + bool protected; + bool bios_locked; bool swseq_reg; bool swseq_erase; u8 atomic_preopcode; @@ -1109,10 +1113,13 @@ static int intel_spi_init(struct intel_spi *ispi) return -EINVAL; } - /* Try to disable write protection if user asked to do so */ - if (writeable && !intel_spi_set_writeable(ispi)) { - dev_warn(ispi->dev, "can't disable chip write protection\n"); - writeable = false; + ispi->bios_locked = true; + /* Try to disable BIOS write protection if user asked to do so */ + if (writeable) { + if (intel_spi_set_writeable(ispi)) + ispi->bios_locked = false; + else + dev_warn(ispi->dev, "can't disable chip write protection\n"); } /* Disable #SMI generation from HW sequencer */ @@ -1247,8 +1254,10 @@ static void intel_spi_fill_partition(struct intel_spi *ispi, * Also if the user did not ask the chip to be writeable * mask the bit too. */ - if (!writeable || intel_spi_is_protected(ispi, base, limit)) + if (!writeable || intel_spi_is_protected(ispi, base, limit)) { part->mask_flags |= MTD_WRITEABLE; + ispi->protected = true; + } end = (limit << 12) + 4096; if (end > part->size) @@ -1411,6 +1420,50 @@ static int intel_spi_populate_chip(struct intel_spi *ispi) return 0; } +static ssize_t intel_spi_protected_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct intel_spi *ispi = dev_get_drvdata(dev); + + return sysfs_emit(buf, "%d\n", ispi->protected); +} +static DEVICE_ATTR_ADMIN_RO(intel_spi_protected); + +static ssize_t intel_spi_locked_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct intel_spi *ispi = dev_get_drvdata(dev); + + return sysfs_emit(buf, "%d\n", ispi->locked); +} +static DEVICE_ATTR_ADMIN_RO(intel_spi_locked); + +static ssize_t intel_spi_bios_locked_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct intel_spi *ispi = dev_get_drvdata(dev); + + return sysfs_emit(buf, "%d\n", ispi->bios_locked); +} +static DEVICE_ATTR_ADMIN_RO(intel_spi_bios_locked); + +static struct attribute *intel_spi_attrs[] = { + &dev_attr_intel_spi_protected.attr, + &dev_attr_intel_spi_locked.attr, + &dev_attr_intel_spi_bios_locked.attr, + NULL +}; + +static const struct attribute_group intel_spi_attr_group = { + .attrs = intel_spi_attrs, +}; + +const struct attribute_group *intel_spi_groups[] = { + &intel_spi_attr_group, + NULL +}; +EXPORT_SYMBOL_GPL(intel_spi_groups); + /** * intel_spi_probe() - Probe the Intel SPI flash controller * @dev: Pointer to the parent device @@ -1451,6 +1504,7 @@ int intel_spi_probe(struct device *dev, struct resource *mem, if (ret) return ret; + dev_set_drvdata(dev, ispi); return intel_spi_populate_chip(ispi); } EXPORT_SYMBOL_GPL(intel_spi_probe); diff --git a/drivers/spi/spi-intel.h b/drivers/spi/spi-intel.h index a4f0327a46ff..c5f35060dd63 100644 --- a/drivers/spi/spi-intel.h +++ b/drivers/spi/spi-intel.h @@ -13,6 +13,8 @@ struct resource; +extern const struct attribute_group *intel_spi_groups[]; + int intel_spi_probe(struct device *dev, struct resource *mem, const struct intel_spi_boardinfo *info); From 941584e2f3ddde26e4d71941ebc0836ece181594 Mon Sep 17 00:00:00 2001 From: Alain Volmat Date: Thu, 10 Oct 2024 15:33:03 +0200 Subject: [PATCH 38/58] spi: stm32: fix missing device mode capability in stm32mp25 The STM32MP25 SOC has capability to behave in device mode however missing .has_device_mode within its stm32mp25_spi_cfg structure leads to not being able to enable the device mode. Fixes: f6cd66231aa5 ("spi: stm32: add st,stm32mp25-spi compatible supporting STM32MP25 soc") Cc: stable@vger.kernel.org Signed-off-by: Alain Volmat Link: https://patch.msgid.link/20241010-spi-mp25-device-fix-v2-1-d13920de473d@foss.st.com Signed-off-by: Mark Brown --- drivers/spi/spi-stm32.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/spi/spi-stm32.c b/drivers/spi/spi-stm32.c index f2dd8ab12df8..da3517d7102d 100644 --- a/drivers/spi/spi-stm32.c +++ b/drivers/spi/spi-stm32.c @@ -2044,6 +2044,7 @@ static const struct stm32_spi_cfg stm32mp25_spi_cfg = { .baud_rate_div_max = STM32H7_SPI_MBR_DIV_MAX, .has_fifo = true, .prevent_dma_burst = true, + .has_device_mode = true, }; static const struct of_device_id stm32_spi_of_match[] = { From 4de1cdb3c299bb98d70198c1fa20c71f0893835c Mon Sep 17 00:00:00 2001 From: Karan Sanghavi Date: Thu, 17 Oct 2024 15:02:16 +0000 Subject: [PATCH 39/58] spi: dt-bindings: brcm,bcm2835-aux-spi: Convert to dtschema Convert bcm2835-aux-spi binding to Dt schema Signed-off-by: Karan Sanghavi Reviewed-by: Krzysztof Kozlowski Link: https://patch.msgid.link/ZxEm-H-PjlQyXeOH@Emma Signed-off-by: Mark Brown --- .../bindings/spi/brcm,bcm2835-aux-spi.txt | 38 ------------- .../bindings/spi/brcm,bcm2835-aux-spi.yaml | 53 +++++++++++++++++++ 2 files changed, 53 insertions(+), 38 deletions(-) delete mode 100644 Documentation/devicetree/bindings/spi/brcm,bcm2835-aux-spi.txt create mode 100644 Documentation/devicetree/bindings/spi/brcm,bcm2835-aux-spi.yaml diff --git a/Documentation/devicetree/bindings/spi/brcm,bcm2835-aux-spi.txt b/Documentation/devicetree/bindings/spi/brcm,bcm2835-aux-spi.txt deleted file mode 100644 index d7668f41b03b..000000000000 --- a/Documentation/devicetree/bindings/spi/brcm,bcm2835-aux-spi.txt +++ /dev/null @@ -1,38 +0,0 @@ -Broadcom BCM2835 auxiliary SPI1/2 controller - -The BCM2835 contains two forms of SPI master controller, one known simply as -SPI0, and the other known as the "Universal SPI Master"; part of the -auxiliary block. This binding applies to the SPI1/2 controller. - -Required properties: -- compatible: Should be "brcm,bcm2835-aux-spi". -- reg: Should contain register location and length for the spi block -- interrupts: Should contain shared interrupt of the aux block -- clocks: The clock feeding the SPI controller - needs to - point to the auxiliary clock driver of the bcm2835, - as this clock will enable the output gate for the specific - clock. -- cs-gpios: the cs-gpios (native cs is NOT supported) - see also spi-bus.txt - -Example: - -spi1@7e215080 { - compatible = "brcm,bcm2835-aux-spi"; - reg = <0x7e215080 0x40>; - interrupts = <1 29>; - clocks = <&aux_clocks BCM2835_AUX_CLOCK_SPI1>; - #address-cells = <1>; - #size-cells = <0>; - cs-gpios = <&gpio 18>, <&gpio 17>, <&gpio 16>; -}; - -spi2@7e2150c0 { - compatible = "brcm,bcm2835-aux-spi"; - reg = <0x7e2150c0 0x40>; - interrupts = <1 29>; - clocks = <&aux_clocks BCM2835_AUX_CLOCK_SPI2>; - #address-cells = <1>; - #size-cells = <0>; - cs-gpios = <&gpio 43>, <&gpio 44>, <&gpio 45>; -}; diff --git a/Documentation/devicetree/bindings/spi/brcm,bcm2835-aux-spi.yaml b/Documentation/devicetree/bindings/spi/brcm,bcm2835-aux-spi.yaml new file mode 100644 index 000000000000..561319544ee3 --- /dev/null +++ b/Documentation/devicetree/bindings/spi/brcm,bcm2835-aux-spi.yaml @@ -0,0 +1,53 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/spi/brcm,bcm2835-aux-spi.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Broadcom BCM2835 Auxiliary SPI1/2 Controller + +maintainers: + - Karan Sanghavi + +description: + The BCM2835 contains two forms of SPI master controller. One is known simply + as SPI0, and the other as the "Universal SPI Master," which is part of the + auxiliary block. This binding applies to the SPI1 and SPI2 auxiliary + controllers. + +allOf: + - $ref: spi-controller.yaml# + +properties: + compatible: + enum: + - brcm,bcm2835-aux-spi + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + clocks: + maxItems: 1 + +required: + - compatible + - reg + - interrupts + - clocks + +unevaluatedProperties: false + +examples: + - | + #include + spi@7e215080 { + compatible = "brcm,bcm2835-aux-spi"; + reg = <0x7e215080 0x40>; + interrupts = <1 29>; + clocks = <&aux_clocks BCM2835_AUX_CLOCK_SPI1>; + #address-cells = <1>; + #size-cells = <0>; + }; From 36dbe4521a381fd4d2561a90200ae4a2a3efb222 Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Fri, 18 Oct 2024 14:24:37 +0200 Subject: [PATCH 40/58] spi: make class structs const The two instances of struct class are only used here in functions that take const pointers and so can too be made constant. Signed-off-by: Bartosz Golaszewski Link: https://patch.msgid.link/20241018122437.64275-1-brgl@bgdev.pl Signed-off-by: Mark Brown --- drivers/spi/spi.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index 7c5e76b15421..5528c46edd0e 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -2926,7 +2926,7 @@ static void spi_controller_release(struct device *dev) kfree(ctlr); } -static struct class spi_master_class = { +static const struct class spi_master_class = { .name = "spi_master", .dev_release = spi_controller_release, .dev_groups = spi_master_groups, @@ -3016,7 +3016,7 @@ static const struct attribute_group *spi_slave_groups[] = { NULL, }; -static struct class spi_slave_class = { +static const struct class spi_slave_class = { .name = "spi_slave", .dev_release = spi_controller_release, .dev_groups = spi_slave_groups, From eef26f1c6179eee5b622362b324a0a72dafb5c16 Mon Sep 17 00:00:00 2001 From: Chris Packham Date: Wed, 16 Oct 2024 11:54:32 +1300 Subject: [PATCH 41/58] dt-bindings: spi: Add realtek,rtl9301-snand Add a dtschema for the SPI-NAND controller on the RTL9300 SoCs. The controller supports * Serial/Dual/Quad data with * PIO and DMA data read/write operation * Configurable flash access timing Signed-off-by: Chris Packham Reviewed-by: Krzysztof Kozlowski Link: https://patch.msgid.link/20241015225434.3970360-2-chris.packham@alliedtelesis.co.nz Signed-off-by: Mark Brown --- .../bindings/spi/realtek,rtl9301-snand.yaml | 62 +++++++++++++++++++ 1 file changed, 62 insertions(+) create mode 100644 Documentation/devicetree/bindings/spi/realtek,rtl9301-snand.yaml diff --git a/Documentation/devicetree/bindings/spi/realtek,rtl9301-snand.yaml b/Documentation/devicetree/bindings/spi/realtek,rtl9301-snand.yaml new file mode 100644 index 000000000000..36d79a90552b --- /dev/null +++ b/Documentation/devicetree/bindings/spi/realtek,rtl9301-snand.yaml @@ -0,0 +1,62 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/spi/realtek,rtl9301-snand.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: SPI-NAND Flash Controller for Realtek RTL9300 SoCs + +maintainers: + - Chris Packham + +description: + The Realtek RTL9300 SoCs have a built in SPI-NAND controller. It supports + typical SPI-NAND page cache operations in single, dual or quad IO mode. + +properties: + compatible: + oneOf: + - items: + - enum: + - realtek,rtl9302b-snand + - realtek,rtl9302c-snand + - realtek,rtl9303-snand + - const: realtek,rtl9301-snand + - const: realtek,rtl9301-snand + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + clocks: + maxItems: 1 + +required: + - compatible + - reg + - interrupts + - clocks + +allOf: + - $ref: /schemas/spi/spi-controller.yaml# + +unevaluatedProperties: false + +examples: + - | + spi@1a400 { + compatible = "realtek,rtl9302c-snand", "realtek,rtl9301-snand"; + reg = <0x1a400 0x44>; + interrupt-parent = <&intc>; + interrupts = <19>; + clocks = <&lx_clk>; + #address-cells = <1>; + #size-cells = <0>; + + flash@0 { + compatible = "spi-nand"; + reg = <0>; + }; + }; From 42d20a6a61b8fccbb57d80df1ccde7dd82d5bbd6 Mon Sep 17 00:00:00 2001 From: Chris Packham Date: Wed, 16 Oct 2024 11:54:34 +1300 Subject: [PATCH 42/58] spi: spi-mem: Add Realtek SPI-NAND controller Add a driver for the SPI-NAND controller on the RTL9300 family of devices. The controller supports * Serial/Dual/Quad data with * PIO and DMA data read/write operation * Configurable flash access timing There is a separate ECC controller on the RTL9300 which isn't currently supported (instead we rely on the on-die ECC supported by most SPI-NAND chips). Signed-off-by: Chris Packham Link: https://patch.msgid.link/20241015225434.3970360-4-chris.packham@alliedtelesis.co.nz Signed-off-by: Mark Brown --- MAINTAINERS | 6 + drivers/spi/Kconfig | 11 + drivers/spi/Makefile | 1 + drivers/spi/spi-realtek-rtl-snand.c | 405 ++++++++++++++++++++++++++++ 4 files changed, 423 insertions(+) create mode 100644 drivers/spi/spi-realtek-rtl-snand.c diff --git a/MAINTAINERS b/MAINTAINERS index a097afd76ded..174cbe46cac3 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -19538,6 +19538,12 @@ S: Maintained F: Documentation/devicetree/bindings/net/dsa/realtek.yaml F: drivers/net/dsa/realtek/* +REALTEK SPI-NAND +M: Chris Packham +S: Maintained +F: Documentation/devicetree/bindings/spi/realtek,rtl9301-snand.yaml +F: drivers/spi/spi-realtek-rtl-snand.c + REALTEK WIRELESS DRIVER (rtlwifi family) M: Ping-Ke Shih L: linux-wireless@vger.kernel.org diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index 823797217404..7133bb72d1c8 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -843,6 +843,17 @@ config SPI_PXA2XX config SPI_PXA2XX_PCI def_tristate SPI_PXA2XX && PCI && COMMON_CLK +config SPI_REALTEK_SNAND + tristate "Realtek SPI-NAND Flash Controller" + depends on MACH_REALTEK_RTL || COMPILE_TEST + select REGMAP + help + This enables support for the SPI-NAND Flash controller on + Realtek SoCs. + + This driver does not support generic SPI. The implementation + only supports the spi-mem interface. + config SPI_ROCKCHIP tristate "Rockchip SPI controller driver" depends on ARCH_ROCKCHIP || COMPILE_TEST diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile index a9b1bc259b68..9a3338236645 100644 --- a/drivers/spi/Makefile +++ b/drivers/spi/Makefile @@ -119,6 +119,7 @@ obj-$(CONFIG_SPI_ROCKCHIP) += spi-rockchip.o obj-$(CONFIG_SPI_ROCKCHIP_SFC) += spi-rockchip-sfc.o obj-$(CONFIG_SPI_RB4XX) += spi-rb4xx.o obj-$(CONFIG_MACH_REALTEK_RTL) += spi-realtek-rtl.o +obj-$(CONFIG_SPI_REALTEK_SNAND) += spi-realtek-rtl-snand.o obj-$(CONFIG_SPI_RPCIF) += spi-rpc-if.o obj-$(CONFIG_SPI_RSPI) += spi-rspi.o obj-$(CONFIG_SPI_RZV2M_CSI) += spi-rzv2m-csi.o diff --git a/drivers/spi/spi-realtek-rtl-snand.c b/drivers/spi/spi-realtek-rtl-snand.c new file mode 100644 index 000000000000..23c42c8469e4 --- /dev/null +++ b/drivers/spi/spi-realtek-rtl-snand.c @@ -0,0 +1,405 @@ +// SPDX-License-Identifier: GPL-2.0-only + +#include +#include +#include +#include +#include +#include +#include +#include + +#define SNAFCFR 0x00 +#define SNAFCFR_DMA_IE BIT(20) +#define SNAFCCR 0x04 +#define SNAFWCMR 0x08 +#define SNAFRCMR 0x0c +#define SNAFRDR 0x10 +#define SNAFWDR 0x14 +#define SNAFDTR 0x18 +#define SNAFDRSAR 0x1c +#define SNAFDIR 0x20 +#define SNAFDIR_DMA_IP BIT(0) +#define SNAFDLR 0x24 +#define SNAFSR 0x40 +#define SNAFSR_NFCOS BIT(3) +#define SNAFSR_NFDRS BIT(2) +#define SNAFSR_NFDWS BIT(1) + +#define CMR_LEN(len) ((len) - 1) +#define CMR_WID(width) (((width) >> 1) << 28) + +struct rtl_snand { + struct device *dev; + struct regmap *regmap; + struct completion comp; +}; + +static irqreturn_t rtl_snand_irq(int irq, void *data) +{ + struct rtl_snand *snand = data; + u32 val = 0; + + regmap_read(snand->regmap, SNAFSR, &val); + if (val & (SNAFSR_NFCOS | SNAFSR_NFDRS | SNAFSR_NFDWS)) + return IRQ_NONE; + + regmap_write(snand->regmap, SNAFDIR, SNAFDIR_DMA_IP); + complete(&snand->comp); + + return IRQ_HANDLED; +} + +static bool rtl_snand_supports_op(struct spi_mem *mem, + const struct spi_mem_op *op) +{ + if (!spi_mem_default_supports_op(mem, op)) + return false; + if (op->cmd.nbytes != 1 || op->cmd.buswidth != 1) + return false; + return true; +} + +static void rtl_snand_set_cs(struct rtl_snand *snand, int cs, bool active) +{ + u32 val; + + if (active) + val = ~(1 << (4 * cs)); + else + val = ~0; + + regmap_write(snand->regmap, SNAFCCR, val); +} + +static int rtl_snand_wait_ready(struct rtl_snand *snand) +{ + u32 val; + + return regmap_read_poll_timeout(snand->regmap, SNAFSR, val, !(val & SNAFSR_NFCOS), + 0, 2 * USEC_PER_MSEC); +} + +static int rtl_snand_xfer_head(struct rtl_snand *snand, int cs, const struct spi_mem_op *op) +{ + int ret; + u32 val, len = 0; + + rtl_snand_set_cs(snand, cs, true); + + val = op->cmd.opcode << 24; + len = 1; + if (op->addr.nbytes && op->addr.buswidth == 1) { + val |= op->addr.val << ((3 - op->addr.nbytes) * 8); + len += op->addr.nbytes; + } + + ret = rtl_snand_wait_ready(snand); + if (ret) + return ret; + + ret = regmap_write(snand->regmap, SNAFWCMR, CMR_LEN(len)); + if (ret) + return ret; + + ret = regmap_write(snand->regmap, SNAFWDR, val); + if (ret) + return ret; + + ret = rtl_snand_wait_ready(snand); + if (ret) + return ret; + + if (op->addr.buswidth > 1) { + val = op->addr.val << ((3 - op->addr.nbytes) * 8); + len = op->addr.nbytes; + + ret = regmap_write(snand->regmap, SNAFWCMR, + CMR_WID(op->addr.buswidth) | CMR_LEN(len)); + if (ret) + return ret; + + ret = regmap_write(snand->regmap, SNAFWDR, val); + if (ret) + return ret; + + ret = rtl_snand_wait_ready(snand); + if (ret) + return ret; + } + + if (op->dummy.nbytes) { + val = 0; + + ret = regmap_write(snand->regmap, SNAFWCMR, + CMR_WID(op->dummy.buswidth) | CMR_LEN(op->dummy.nbytes)); + if (ret) + return ret; + + ret = regmap_write(snand->regmap, SNAFWDR, val); + if (ret) + return ret; + + ret = rtl_snand_wait_ready(snand); + if (ret) + return ret; + } + + return 0; +} + +static void rtl_snand_xfer_tail(struct rtl_snand *snand, int cs) +{ + rtl_snand_set_cs(snand, cs, false); +} + +static int rtl_snand_xfer(struct rtl_snand *snand, int cs, const struct spi_mem_op *op) +{ + unsigned int pos, nbytes; + int ret; + u32 val, len = 0; + + ret = rtl_snand_xfer_head(snand, cs, op); + if (ret) + goto out_deselect; + + if (op->data.dir == SPI_MEM_DATA_IN) { + pos = 0; + len = op->data.nbytes; + + while (pos < len) { + nbytes = len - pos; + if (nbytes > 4) + nbytes = 4; + + ret = rtl_snand_wait_ready(snand); + if (ret) + goto out_deselect; + + ret = regmap_write(snand->regmap, SNAFRCMR, + CMR_WID(op->data.buswidth) | CMR_LEN(nbytes)); + if (ret) + goto out_deselect; + + ret = rtl_snand_wait_ready(snand); + if (ret) + goto out_deselect; + + ret = regmap_read(snand->regmap, SNAFRDR, &val); + if (ret) + goto out_deselect; + + memcpy(op->data.buf.in + pos, &val, nbytes); + + pos += nbytes; + } + } else if (op->data.dir == SPI_MEM_DATA_OUT) { + pos = 0; + len = op->data.nbytes; + + while (pos < len) { + nbytes = len - pos; + if (nbytes > 4) + nbytes = 4; + + memcpy(&val, op->data.buf.out + pos, nbytes); + + pos += nbytes; + + ret = regmap_write(snand->regmap, SNAFWCMR, CMR_LEN(nbytes)); + if (ret) + goto out_deselect; + + ret = regmap_write(snand->regmap, SNAFWDR, val); + if (ret) + goto out_deselect; + + ret = rtl_snand_wait_ready(snand); + if (ret) + goto out_deselect; + } + } + +out_deselect: + rtl_snand_xfer_tail(snand, cs); + + if (ret) + dev_err(snand->dev, "transfer failed %d\n", ret); + + return ret; +} + +static int rtl_snand_dma_xfer(struct rtl_snand *snand, int cs, const struct spi_mem_op *op) +{ + int ret; + dma_addr_t buf_dma; + enum dma_data_direction dir; + u32 trig; + + ret = rtl_snand_xfer_head(snand, cs, op); + if (ret) + goto out_deselect; + + if (op->data.dir == SPI_MEM_DATA_IN) { + dir = DMA_FROM_DEVICE; + trig = 0; + } else if (op->data.dir == SPI_MEM_DATA_OUT) { + dir = DMA_TO_DEVICE; + trig = 1; + } else { + ret = -EOPNOTSUPP; + goto out_deselect; + } + + buf_dma = dma_map_single(snand->dev, op->data.buf.in, op->data.nbytes, dir); + ret = dma_mapping_error(snand->dev, buf_dma); + if (ret) + goto out_deselect; + + ret = regmap_write(snand->regmap, SNAFDIR, SNAFDIR_DMA_IP); + if (ret) + goto out_unmap; + + ret = regmap_update_bits(snand->regmap, SNAFCFR, SNAFCFR_DMA_IE, SNAFCFR_DMA_IE); + if (ret) + goto out_unmap; + + reinit_completion(&snand->comp); + + ret = regmap_write(snand->regmap, SNAFDRSAR, buf_dma); + if (ret) + goto out_disable_int; + + ret = regmap_write(snand->regmap, SNAFDLR, + CMR_WID(op->data.buswidth) | (op->data.nbytes & 0xffff)); + if (ret) + goto out_disable_int; + + ret = regmap_write(snand->regmap, SNAFDTR, trig); + if (ret) + goto out_disable_int; + + if (!wait_for_completion_timeout(&snand->comp, usecs_to_jiffies(20000))) + ret = -ETIMEDOUT; + + if (ret) + goto out_disable_int; + +out_disable_int: + regmap_update_bits(snand->regmap, SNAFCFR, SNAFCFR_DMA_IE, 0); +out_unmap: + dma_unmap_single(snand->dev, buf_dma, op->data.nbytes, dir); +out_deselect: + rtl_snand_xfer_tail(snand, cs); + + if (ret) + dev_err(snand->dev, "transfer failed %d\n", ret); + + return ret; +} + +static bool rtl_snand_dma_op(const struct spi_mem_op *op) +{ + switch (op->data.dir) { + case SPI_MEM_DATA_IN: + case SPI_MEM_DATA_OUT: + return op->data.nbytes > 32; + default: + return false; + } +} + +static int rtl_snand_exec_op(struct spi_mem *mem, const struct spi_mem_op *op) +{ + struct rtl_snand *snand = spi_controller_get_devdata(mem->spi->controller); + int cs = spi_get_chipselect(mem->spi, 0); + + dev_dbg(snand->dev, "cs %d op cmd %02x %d:%d, dummy %d:%d, addr %08llx@%d:%d, data %d:%d\n", + cs, op->cmd.opcode, + op->cmd.buswidth, op->cmd.nbytes, op->dummy.buswidth, + op->dummy.nbytes, op->addr.val, op->addr.buswidth, + op->addr.nbytes, op->data.buswidth, op->data.nbytes); + + if (rtl_snand_dma_op(op)) + return rtl_snand_dma_xfer(snand, cs, op); + else + return rtl_snand_xfer(snand, cs, op); +} + +static const struct spi_controller_mem_ops rtl_snand_mem_ops = { + .supports_op = rtl_snand_supports_op, + .exec_op = rtl_snand_exec_op, +}; + +static const struct of_device_id rtl_snand_match[] = { + { .compatible = "realtek,rtl9301-snand" }, + { .compatible = "realtek,rtl9302b-snand" }, + { .compatible = "realtek,rtl9302c-snand" }, + { .compatible = "realtek,rtl9303-snand" }, + {}, +}; +MODULE_DEVICE_TABLE(of, rtl_snand_match); + +static int rtl_snand_probe(struct platform_device *pdev) +{ + struct rtl_snand *snand; + struct device *dev = &pdev->dev; + struct spi_controller *ctrl; + void __iomem *base; + const struct regmap_config rc = { + .reg_bits = 32, + .val_bits = 32, + .reg_stride = 4, + .cache_type = REGCACHE_NONE, + }; + int irq, ret; + + ctrl = devm_spi_alloc_host(dev, sizeof(*snand)); + if (!ctrl) + return -ENOMEM; + + snand = spi_controller_get_devdata(ctrl); + snand->dev = dev; + + base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(base)) + return PTR_ERR(base); + + snand->regmap = devm_regmap_init_mmio(dev, base, &rc); + if (IS_ERR(snand->regmap)) + return PTR_ERR(snand->regmap); + + init_completion(&snand->comp); + + irq = platform_get_irq(pdev, 0); + if (irq < 0) + return irq; + + ret = dma_set_mask(snand->dev, DMA_BIT_MASK(32)); + if (ret) + return dev_err_probe(dev, ret, "failed to set DMA mask\n"); + + ret = devm_request_irq(dev, irq, rtl_snand_irq, 0, "rtl-snand", snand); + if (ret) + return dev_err_probe(dev, ret, "failed to request irq\n"); + + ctrl->num_chipselect = 2; + ctrl->mem_ops = &rtl_snand_mem_ops; + ctrl->bits_per_word_mask = SPI_BPW_MASK(8); + ctrl->mode_bits = SPI_RX_DUAL | SPI_RX_QUAD | SPI_TX_DUAL | SPI_TX_QUAD; + device_set_node(&ctrl->dev, dev_fwnode(dev)); + + return devm_spi_register_controller(dev, ctrl); +} + +static struct platform_driver rtl_snand_driver = { + .driver = { + .name = "realtek-rtl-snand", + .of_match_table = rtl_snand_match, + }, + .probe = rtl_snand_probe, +}; +module_platform_driver(rtl_snand_driver); + +MODULE_DESCRIPTION("Realtek SPI-NAND Flash Controller Driver"); +MODULE_LICENSE("GPL"); From f45a4399c1b582c6ddc179cc940aed73907b9453 Mon Sep 17 00:00:00 2001 From: Ivaylo Ivanov Date: Sun, 20 Oct 2024 21:21:17 +0300 Subject: [PATCH 43/58] spi: dt-bindings: samsung: Add a compatible for samsung,exynos8895-spi According to the vendor kernel, the Exynos8895 SoC has an SPI configuration that matches with the Exynos850 one. SPI FIFO depth is 64 bytes for all SPI blocks. All blocks have DIV_4 as the default internal clock divider, and an internal loopback mode to run a loopback test. Reuse the samsung,exynos850-spi compatible. Signed-off-by: Ivaylo Ivanov Reviewed-by: Krzysztof Kozlowski Link: https://patch.msgid.link/20241020182121.377969-3-ivo.ivanov.ivanov1@gmail.com Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/spi/samsung,spi.yaml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Documentation/devicetree/bindings/spi/samsung,spi.yaml b/Documentation/devicetree/bindings/spi/samsung,spi.yaml index f681372da81f..3c206a64d60a 100644 --- a/Documentation/devicetree/bindings/spi/samsung,spi.yaml +++ b/Documentation/devicetree/bindings/spi/samsung,spi.yaml @@ -26,6 +26,10 @@ properties: - samsung,exynos850-spi - samsung,exynosautov9-spi - tesla,fsd-spi + - items: + - enum: + - samsung,exynos8895-spi + - const: samsung,exynos850-spi - const: samsung,exynos7-spi deprecated: true From a992197bfcbb14e5a027796e06f86226c4444955 Mon Sep 17 00:00:00 2001 From: Philipp Stanner Date: Thu, 24 Oct 2024 16:04:27 +0200 Subject: [PATCH 44/58] spi: Replace deprecated PCI functions pcim_iomap_table() and pcim_request_regions() have been deprecated in commit e354bb84a4c1 ("PCI: Deprecate pcim_iomap_table(), pcim_iomap_regions_request_all()"). Replace these functions with pcim_iomap_region(). Signed-off-by: Philipp Stanner Link: https://patch.msgid.link/20241024140426.157444-2-pstanner@redhat.com Signed-off-by: Mark Brown --- drivers/spi/spi-dw-pci.c | 9 ++++----- drivers/spi/spi-loongson-pci.c | 5 ++--- drivers/spi/spi-pxa2xx-pci.c | 8 +++----- 3 files changed, 9 insertions(+), 13 deletions(-) diff --git a/drivers/spi/spi-dw-pci.c b/drivers/spi/spi-dw-pci.c index 7c8279d13f31..6b8cc26e06f8 100644 --- a/drivers/spi/spi-dw-pci.c +++ b/drivers/spi/spi-dw-pci.c @@ -98,15 +98,14 @@ static int dw_spi_pci_probe(struct pci_dev *pdev, const struct pci_device_id *en dws->paddr = pci_resource_start(pdev, pci_bar); pci_set_master(pdev); - ret = pcim_iomap_regions(pdev, 1 << pci_bar, pci_name(pdev)); - if (ret) - return ret; - ret = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_ALL_TYPES); if (ret < 0) return ret; - dws->regs = pcim_iomap_table(pdev)[pci_bar]; + dws->regs = pcim_iomap_region(pdev, pci_bar, pci_name(pdev)); + if (IS_ERR(dws->regs)) + return PTR_ERR(dws->regs); + dws->irq = pci_irq_vector(pdev, 0); /* diff --git a/drivers/spi/spi-loongson-pci.c b/drivers/spi/spi-loongson-pci.c index 134cda0c13a5..892cf1eba1cf 100644 --- a/drivers/spi/spi-loongson-pci.c +++ b/drivers/spi/spi-loongson-pci.c @@ -19,12 +19,11 @@ static int loongson_spi_pci_register(struct pci_dev *pdev, if (ret < 0) return dev_err_probe(dev, ret, "cannot enable pci device\n"); - ret = pcim_iomap_regions(pdev, BIT(pci_bar), pci_name(pdev)); + reg_base = pcim_iomap_region(pdev, pci_bar, pci_name(pdev)); + ret = PTR_ERR_OR_ZERO(reg_base); if (ret) return dev_err_probe(dev, ret, "failed to request and remap memory\n"); - reg_base = pcim_iomap_table(pdev)[pci_bar]; - ret = loongson_spi_init_controller(dev, reg_base); if (ret) return dev_err_probe(dev, ret, "failed to initialize controller\n"); diff --git a/drivers/spi/spi-pxa2xx-pci.c b/drivers/spi/spi-pxa2xx-pci.c index cc8dcf782399..e51c1b492283 100644 --- a/drivers/spi/spi-pxa2xx-pci.c +++ b/drivers/spi/spi-pxa2xx-pci.c @@ -273,10 +273,6 @@ static int pxa2xx_spi_pci_probe(struct pci_dev *dev, if (ret) return ret; - ret = pcim_iomap_regions(dev, 1 << 0, "PXA2xx SPI"); - if (ret) - return ret; - pdata = devm_kzalloc(&dev->dev, sizeof(*pdata), GFP_KERNEL); if (!pdata) return -ENOMEM; @@ -284,7 +280,9 @@ static int pxa2xx_spi_pci_probe(struct pci_dev *dev, ssp = &pdata->ssp; ssp->dev = &dev->dev; ssp->phys_base = pci_resource_start(dev, 0); - ssp->mmio_base = pcim_iomap_table(dev)[0]; + ssp->mmio_base = pcim_iomap_region(dev, 0, "PXA2xx SPI"); + if (IS_ERR(ssp->mmio_base)) + return PTR_ERR(ssp->mmio_base); info = (struct pxa_spi_info *)ent->driver_data; ret = info->setup(dev, pdata); From 8a9c132389bbd162336fcbe6725692455151bd7e Mon Sep 17 00:00:00 2001 From: Stanislav Jakubek Date: Wed, 30 Oct 2024 10:02:55 +0100 Subject: [PATCH 45/58] dt-bindings: spi: sprd,sc9860-spi: convert to YAML Convert the Spreadtrum SC9860 SPI controller bindings to DT schema. Adjust filename to match compatible. Signed-off-by: Stanislav Jakubek Reviewed-by: Krzysztof Kozlowski Link: https://patch.msgid.link/ZyH2P3FlneLtGxXo@standask-GA-A55M-S2HP Signed-off-by: Mark Brown --- .../devicetree/bindings/spi/spi-sprd.txt | 33 --------- .../bindings/spi/sprd,sc9860-spi.yaml | 72 +++++++++++++++++++ 2 files changed, 72 insertions(+), 33 deletions(-) delete mode 100644 Documentation/devicetree/bindings/spi/spi-sprd.txt create mode 100644 Documentation/devicetree/bindings/spi/sprd,sc9860-spi.yaml diff --git a/Documentation/devicetree/bindings/spi/spi-sprd.txt b/Documentation/devicetree/bindings/spi/spi-sprd.txt deleted file mode 100644 index 3c7eacce0ee3..000000000000 --- a/Documentation/devicetree/bindings/spi/spi-sprd.txt +++ /dev/null @@ -1,33 +0,0 @@ -Spreadtrum SPI Controller - -Required properties: -- compatible: Should be "sprd,sc9860-spi". -- reg: Offset and length of SPI controller register space. -- interrupts: Should contain SPI interrupt. -- clock-names: Should contain following entries: - "spi" for SPI clock, - "source" for SPI source (parent) clock, - "enable" for SPI module enable clock. -- clocks: List of clock input name strings sorted in the same order - as the clock-names property. -- #address-cells: The number of cells required to define a chip select - address on the SPI bus. Should be set to 1. -- #size-cells: Should be set to 0. - -Optional properties: -dma-names: Should contain names of the SPI used DMA channel. -dmas: Should contain DMA channels and DMA slave ids which the SPI used - sorted in the same order as the dma-names property. - -Example: -spi0: spi@70a00000{ - compatible = "sprd,sc9860-spi"; - reg = <0 0x70a00000 0 0x1000>; - interrupts = ; - clock-names = "spi", "source","enable"; - clocks = <&clk_spi0>, <&ext_26m>, <&clk_ap_apb_gates 5>; - dma-names = "rx_chn", "tx_chn"; - dmas = <&apdma 11 11>, <&apdma 12 12>; - #address-cells = <1>; - #size-cells = <0>; -}; diff --git a/Documentation/devicetree/bindings/spi/sprd,sc9860-spi.yaml b/Documentation/devicetree/bindings/spi/sprd,sc9860-spi.yaml new file mode 100644 index 000000000000..d55c01e9a038 --- /dev/null +++ b/Documentation/devicetree/bindings/spi/sprd,sc9860-spi.yaml @@ -0,0 +1,72 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/spi/sprd,sc9860-spi.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Spreadtrum SC9860 SPI Controller + +maintainers: + - Orson Zhai + - Baolin Wang + - Chunyan Zhang + +properties: + compatible: + const: sprd,sc9860-spi + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + clocks: + items: + - description: SPI clock + - description: SPI source (parent) clock + - description: SPI module enable clock + + clock-names: + items: + - const: spi + - const: source + - const: enable + + dmas: + maxItems: 2 + + dma-names: + items: + - const: rx_chn + - const: tx_chn + +required: + - compatible + - reg + - interrupts + - clocks + - clock-names + +allOf: + - $ref: spi-controller.yaml# + +unevaluatedProperties: false + +examples: + - | + #include + #include + + spi@70a00000 { + compatible = "sprd,sc9860-spi"; + reg = <0x70a00000 0x1000>; + interrupts = ; + clocks = <&clk_spi0>, <&ext_26m>, <&clk_ap_apb_gates 5>; + clock-names = "spi", "source", "enable"; + dmas = <&apdma 11 11>, <&apdma 12 12>; + dma-names = "rx_chn", "tx_chn"; + #address-cells = <1>; + #size-cells = <0>; + }; +... From e36eba413b8e841e9e36e93188d82674ec7c79d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Thu, 31 Oct 2024 12:16:45 +0100 Subject: [PATCH 46/58] spi: axi-spi-engine: Emit trace events for spi transfers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As this spi host controller driver implements the .transfer_one_message() callback, it has to care about these traces it-self. With the transfers being compiled it's difficult to determine where handling of one transfer ends and the next begins, so just generate the start events in batch before the hardware fifo is fed and the end events when their completion triggered. Signed-off-by: Uwe Kleine-König Reviewed-by: David Lechner Link: https://patch.msgid.link/20241031111646.747692-2-u.kleine-koenig@baylibre.com Signed-off-by: Mark Brown --- drivers/spi/spi-axi-spi-engine.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/drivers/spi/spi-axi-spi-engine.c b/drivers/spi/spi-axi-spi-engine.c index 2dff95d2b3f5..7c252126b33e 100644 --- a/drivers/spi/spi-axi-spi-engine.c +++ b/drivers/spi/spi-axi-spi-engine.c @@ -15,6 +15,7 @@ #include #include #include +#include #define SPI_ENGINE_REG_RESET 0x40 @@ -590,6 +591,13 @@ static int spi_engine_transfer_one_message(struct spi_controller *host, reinit_completion(&spi_engine->msg_complete); + if (trace_spi_transfer_start_enabled()) { + struct spi_transfer *xfer; + + list_for_each_entry(xfer, &msg->transfers, transfer_list) + trace_spi_transfer_start(msg, xfer); + } + spin_lock_irqsave(&spi_engine->lock, flags); if (spi_engine_write_cmd_fifo(spi_engine, msg)) @@ -617,6 +625,13 @@ static int spi_engine_transfer_one_message(struct spi_controller *host, msg->status = -ETIMEDOUT; } + if (trace_spi_transfer_stop_enabled()) { + struct spi_transfer *xfer; + + list_for_each_entry(xfer, &msg->transfers, transfer_list) + trace_spi_transfer_stop(msg, xfer); + } + spi_finalize_current_message(host); return msg->status; From f399051ec1ff02e74ae5c2517aed2cc486fd005b Mon Sep 17 00:00:00 2001 From: Breno Leitao Date: Fri, 4 Oct 2024 05:53:59 -0700 Subject: [PATCH 47/58] spi: tegra210-quad: Avoid shift-out-of-bounds A shift-out-of-bounds issue was identified by UBSAN in the tegra_qspi_fill_tx_fifo_from_client_txbuf() function. UBSAN: shift-out-of-bounds in drivers/spi/spi-tegra210-quad.c:345:27 shift exponent 32 is too large for 32-bit type 'u32' (aka 'unsigned int') Call trace: tegra_qspi_start_cpu_based_transfer The problem arises when shifting the contents of tx_buf left by 8 times the value of i, which can exceed 4 and result in an exponent larger than 32 bits. Resolve this by restrict the value of i to be less than 4, preventing the shift operation from overflowing. Signed-off-by: Breno Leitao Fixes: 921fc1838fb0 ("spi: tegra210-quad: Add support for Tegra210 QSPI controller") Link: https://patch.msgid.link/20241004125400.1791089-1-leitao@debian.org Signed-off-by: Mark Brown --- drivers/spi/spi-tegra210-quad.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/spi/spi-tegra210-quad.c b/drivers/spi/spi-tegra210-quad.c index 40f2afad1899..08e49a876894 100644 --- a/drivers/spi/spi-tegra210-quad.c +++ b/drivers/spi/spi-tegra210-quad.c @@ -341,7 +341,7 @@ tegra_qspi_fill_tx_fifo_from_client_txbuf(struct tegra_qspi *tqspi, struct spi_t for (count = 0; count < max_n_32bit; count++) { u32 x = 0; - for (i = 0; len && (i < bytes_per_word); i++, len--) + for (i = 0; len && (i < min(4, bytes_per_word)); i++, len--) x |= (u32)(*tx_buf++) << (i * 8); tegra_qspi_writel(tqspi, x, QSPI_TX_FIFO); } From 25d284715845a465a1a3693a09cf8b6ab8bd9caf Mon Sep 17 00:00:00 2001 From: Chris Packham Date: Thu, 31 Oct 2024 08:49:20 +1300 Subject: [PATCH 48/58] spi: spi-mem: rtl-snand: Correctly handle DMA transfers The RTL9300 has some limitations on the maximum DMA transfers possible. For reads this is 2080 bytes (520*4) for writes this is 520 bytes. Deal with this by splitting transfers into appropriately sized parts. Fixes: 42d20a6a61b8 ("spi: spi-mem: Add Realtek SPI-NAND controller") Signed-off-by: Chris Packham Link: https://patch.msgid.link/20241030194920.3202282-1-chris.packham@alliedtelesis.co.nz Signed-off-by: Mark Brown --- drivers/spi/spi-realtek-rtl-snand.c | 46 +++++++++++++++++++---------- 1 file changed, 30 insertions(+), 16 deletions(-) diff --git a/drivers/spi/spi-realtek-rtl-snand.c b/drivers/spi/spi-realtek-rtl-snand.c index 23c42c8469e4..cd0484041147 100644 --- a/drivers/spi/spi-realtek-rtl-snand.c +++ b/drivers/spi/spi-realtek-rtl-snand.c @@ -231,19 +231,22 @@ static int rtl_snand_xfer(struct rtl_snand *snand, int cs, const struct spi_mem_ static int rtl_snand_dma_xfer(struct rtl_snand *snand, int cs, const struct spi_mem_op *op) { + unsigned int pos, nbytes; int ret; dma_addr_t buf_dma; enum dma_data_direction dir; - u32 trig; + u32 trig, len, maxlen; ret = rtl_snand_xfer_head(snand, cs, op); if (ret) goto out_deselect; if (op->data.dir == SPI_MEM_DATA_IN) { + maxlen = 2080; dir = DMA_FROM_DEVICE; trig = 0; } else if (op->data.dir == SPI_MEM_DATA_OUT) { + maxlen = 520; dir = DMA_TO_DEVICE; trig = 1; } else { @@ -264,26 +267,37 @@ static int rtl_snand_dma_xfer(struct rtl_snand *snand, int cs, const struct spi_ if (ret) goto out_unmap; - reinit_completion(&snand->comp); + pos = 0; + len = op->data.nbytes; - ret = regmap_write(snand->regmap, SNAFDRSAR, buf_dma); - if (ret) - goto out_disable_int; + while (pos < len) { + nbytes = len - pos; + if (nbytes > maxlen) + nbytes = maxlen; - ret = regmap_write(snand->regmap, SNAFDLR, - CMR_WID(op->data.buswidth) | (op->data.nbytes & 0xffff)); - if (ret) - goto out_disable_int; + reinit_completion(&snand->comp); - ret = regmap_write(snand->regmap, SNAFDTR, trig); - if (ret) - goto out_disable_int; + ret = regmap_write(snand->regmap, SNAFDRSAR, buf_dma + pos); + if (ret) + goto out_disable_int; - if (!wait_for_completion_timeout(&snand->comp, usecs_to_jiffies(20000))) - ret = -ETIMEDOUT; + pos += nbytes; - if (ret) - goto out_disable_int; + ret = regmap_write(snand->regmap, SNAFDLR, + CMR_WID(op->data.buswidth) | nbytes); + if (ret) + goto out_disable_int; + + ret = regmap_write(snand->regmap, SNAFDTR, trig); + if (ret) + goto out_disable_int; + + if (!wait_for_completion_timeout(&snand->comp, usecs_to_jiffies(20000))) + ret = -ETIMEDOUT; + + if (ret) + goto out_disable_int; + } out_disable_int: regmap_update_bits(snand->regmap, SNAFCFR, SNAFCFR_DMA_IE, 0); From 2219576883e709737f3100aa9ded84976be49bd7 Mon Sep 17 00:00:00 2001 From: Jinjie Ruan Date: Fri, 20 Sep 2024 17:11:35 +0800 Subject: [PATCH 49/58] =?UTF-8?q?spi:=20zynqmp-gqspi:=20Undo=20runtime=20P?= =?UTF-8?q?M=20changes=20at=20driver=20exit=20time=E2=80=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It's important to undo pm_runtime_use_autosuspend() with pm_runtime_dont_use_autosuspend() at driver exit time. So, call pm_runtime_dont_use_autosuspend() at driver exit time to fix it. Fixes: 9e3a000362ae ("spi: zynqmp: Add pm runtime support") Signed-off-by: Jinjie Ruan Link: https://patch.msgid.link/20240920091135.2741574-1-ruanjinjie@huawei.com Signed-off-by: Mark Brown --- drivers/spi/spi-zynqmp-gqspi.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/spi/spi-zynqmp-gqspi.c b/drivers/spi/spi-zynqmp-gqspi.c index 84cce78e4f2e..549a6e0c9654 100644 --- a/drivers/spi/spi-zynqmp-gqspi.c +++ b/drivers/spi/spi-zynqmp-gqspi.c @@ -1351,6 +1351,7 @@ static int zynqmp_qspi_probe(struct platform_device *pdev) clk_dis_all: pm_runtime_disable(&pdev->dev); + pm_runtime_dont_use_autosuspend(&pdev->dev); pm_runtime_put_noidle(&pdev->dev); pm_runtime_set_suspended(&pdev->dev); clk_disable_unprepare(xqspi->refclk); @@ -1379,6 +1380,7 @@ static void zynqmp_qspi_remove(struct platform_device *pdev) zynqmp_gqspi_write(xqspi, GQSPI_EN_OFST, 0x0); pm_runtime_disable(&pdev->dev); + pm_runtime_dont_use_autosuspend(&pdev->dev); pm_runtime_put_noidle(&pdev->dev); pm_runtime_set_suspended(&pdev->dev); clk_disable_unprepare(xqspi->refclk); From 270ddc23914ed79aa117373f4b3413c34cdabf12 Mon Sep 17 00:00:00 2001 From: "Rob Herring (Arm)" Date: Mon, 4 Nov 2024 13:07:59 -0600 Subject: [PATCH 50/58] spi: Use of_property_present() for non-boolean properties The use of of_property_read_bool() for non-boolean properties is deprecated in favor of of_property_present() when testing for property presence. Signed-off-by: Rob Herring (Arm) Link: https://patch.msgid.link/20241104190759.277184-2-robh@kernel.org Signed-off-by: Mark Brown --- drivers/spi/spi-qcom-qspi.c | 2 +- drivers/spi/spi-ti-qspi.c | 2 +- drivers/spi/spi.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/spi/spi-qcom-qspi.c b/drivers/spi/spi-qcom-qspi.c index 056f02677376..3aeddada58e1 100644 --- a/drivers/spi/spi-qcom-qspi.c +++ b/drivers/spi/spi-qcom-qspi.c @@ -771,7 +771,7 @@ static int qcom_qspi_probe(struct platform_device *pdev) host->prepare_message = qcom_qspi_prepare_message; host->transfer_one = qcom_qspi_transfer_one; host->handle_err = qcom_qspi_handle_err; - if (of_property_read_bool(pdev->dev.of_node, "iommus")) + if (of_property_present(pdev->dev.of_node, "iommus")) host->can_dma = qcom_qspi_can_dma; host->auto_runtime_pm = true; host->mem_ops = &qcom_qspi_mem_ops; diff --git a/drivers/spi/spi-ti-qspi.c b/drivers/spi/spi-ti-qspi.c index dfd4a7948c03..9122350402b5 100644 --- a/drivers/spi/spi-ti-qspi.c +++ b/drivers/spi/spi-ti-qspi.c @@ -824,7 +824,7 @@ static int ti_qspi_probe(struct platform_device *pdev) } - if (of_property_read_bool(np, "syscon-chipselects")) { + if (of_property_present(np, "syscon-chipselects")) { qspi->ctrl_base = syscon_regmap_lookup_by_phandle(np, "syscon-chipselects"); diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index 5528c46edd0e..74e04a4b0f19 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -2454,7 +2454,7 @@ static int of_spi_parse_dt(struct spi_controller *ctlr, struct spi_device *spi, nc, rc); return rc; } - if ((of_property_read_bool(nc, "parallel-memories")) && + if ((of_property_present(nc, "parallel-memories")) && (!(ctlr->flags & SPI_CONTROLLER_MULTI_CS))) { dev_err(&ctlr->dev, "SPI controller doesn't support multi CS\n"); return -EINVAL; From 18096d339206de6cdb48500b2c3ad5ad0b48aad7 Mon Sep 17 00:00:00 2001 From: Hector Martin Date: Wed, 6 Nov 2024 08:54:00 +0100 Subject: [PATCH 51/58] spi: dt-bindings: apple,spi: Add binding for Apple SPI controllers The Apple SPI controller is present in SoCs such as the M1 (t8103) and M1 Pro/Max (t600x). This controller uses one IRQ and one clock, and doesn't need any special properties, so the binding is trivial. Signed-off-by: Hector Martin Reviewed-by: Rob Herring Acked-by: Nick Chan Reviewed-by: Conor Dooley Signed-off-by: Janne Grunau Reviewed-by: Mark Kettenis Link: https://patch.msgid.link/20241106-asahi-spi-v5-1-e81a4f3a8e19@jannau.net Signed-off-by: Mark Brown --- .../devicetree/bindings/spi/apple,spi.yaml | 62 +++++++++++++++++++ 1 file changed, 62 insertions(+) create mode 100644 Documentation/devicetree/bindings/spi/apple,spi.yaml diff --git a/Documentation/devicetree/bindings/spi/apple,spi.yaml b/Documentation/devicetree/bindings/spi/apple,spi.yaml new file mode 100644 index 000000000000..7bef605a2963 --- /dev/null +++ b/Documentation/devicetree/bindings/spi/apple,spi.yaml @@ -0,0 +1,62 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/spi/apple,spi.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Apple ARM SoC SPI controller + +allOf: + - $ref: spi-controller.yaml# + +maintainers: + - Hector Martin + +properties: + compatible: + items: + - enum: + - apple,t8103-spi + - apple,t8112-spi + - apple,t6000-spi + - const: apple,spi + + reg: + maxItems: 1 + + clocks: + maxItems: 1 + + interrupts: + maxItems: 1 + + power-domains: + maxItems: 1 + +required: + - compatible + - reg + - clocks + - interrupts + +unevaluatedProperties: false + +examples: + - | + #include + #include + + soc { + #address-cells = <2>; + #size-cells = <2>; + + spi@39b104000 { + compatible = "apple,t6000-spi", "apple,spi"; + reg = <0x3 0x9b104000 0x0 0x4000>; + interrupt-parent = <&aic>; + interrupts = ; + #address-cells = <1>; + #size-cells = <0>; + clocks = <&clk>; + }; + }; From c36212b2610d09eb42142beb0d5613c70206c658 Mon Sep 17 00:00:00 2001 From: Hector Martin Date: Wed, 6 Nov 2024 08:54:01 +0100 Subject: [PATCH 52/58] spi: apple: Add driver for Apple SPI controller This SPI controller is present in Apple SoCs such as the M1 (t8103) and M1 Pro/Max (t600x). It is a relatively straightforward design with two 16-entry FIFOs, arbitrary transfer sizes (up to 2**32 - 1) and fully configurable word size up to 32 bits. It supports one hardware CS line which can also be driven via the pinctrl/GPIO driver instead, if desired. TX and RX can be independently enabled. There are a surprising number of knobs for tweaking details of the transfer, most of which we do not use right now. Hardware CS control is available, but we haven't found a way to make it stay low across multiple logical transfers, so we just use software CS control for now. There is also a shared DMA offload coprocessor that can be used to handle larger transfers without requiring an IRQ every 8-16 words, but that feature depends on a bunch of scaffolding that isn't ready to be upstreamed yet, so leave it for later. The hardware shares some register bit definitions with spi-s3c24xx which suggests it has a shared legacy with Samsung SoCs, but it is too different to warrant sharing a driver. Signed-off-by: Hector Martin Signed-off-by: Janne Grunau Link: https://patch.msgid.link/20241106-asahi-spi-v5-2-e81a4f3a8e19@jannau.net Signed-off-by: Mark Brown --- drivers/spi/Kconfig | 11 + drivers/spi/Makefile | 1 + drivers/spi/spi-apple.c | 530 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 542 insertions(+) create mode 100644 drivers/spi/spi-apple.c diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index 7133bb72d1c8..f51f9466e518 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -96,6 +96,17 @@ config SPI_AMLOGIC_SPIFC_A1 This enables master mode support for the SPIFC (SPI flash controller) available in Amlogic A1 (A113L SoC). +config SPI_APPLE + tristate "Apple SoC SPI Controller platform driver" + depends on ARCH_APPLE || COMPILE_TEST + help + This enables support for the SPI controller present on + many Apple SoCs, including the t8103 (M1), t8112 (M2) + and t600x (M1 Pro/Max/Ultra). Multiple SPI controller + instances are present on the SoC and each connects usually + to a single device like spi-nor (nvram), input device controller + or fingerprint sensor. + config SPI_AR934X tristate "Qualcomm Atheros AR934X/QCA95XX SPI controller driver" depends on ATH79 || COMPILE_TEST diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile index 9a3338236645..aea5e54de195 100644 --- a/drivers/spi/Makefile +++ b/drivers/spi/Makefile @@ -19,6 +19,7 @@ obj-$(CONFIG_SPI_ALTERA) += spi-altera-platform.o obj-$(CONFIG_SPI_ALTERA_CORE) += spi-altera-core.o obj-$(CONFIG_SPI_ALTERA_DFL) += spi-altera-dfl.o obj-$(CONFIG_SPI_AMLOGIC_SPIFC_A1) += spi-amlogic-spifc-a1.o +obj-$(CONFIG_SPI_APPLE) += spi-apple.o obj-$(CONFIG_SPI_AR934X) += spi-ar934x.o obj-$(CONFIG_SPI_ARMADA_3700) += spi-armada-3700.o obj-$(CONFIG_SPI_ASPEED_SMC) += spi-aspeed-smc.o diff --git a/drivers/spi/spi-apple.c b/drivers/spi/spi-apple.c new file mode 100644 index 000000000000..1ce91cea89be --- /dev/null +++ b/drivers/spi/spi-apple.c @@ -0,0 +1,530 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Apple SoC SPI device driver +// +// Copyright The Asahi Linux Contributors +// +// Based on spi-sifive.c, Copyright 2018 SiFive, Inc. + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define APPLE_SPI_CTRL 0x000 +#define APPLE_SPI_CTRL_RUN BIT(0) +#define APPLE_SPI_CTRL_TX_RESET BIT(2) +#define APPLE_SPI_CTRL_RX_RESET BIT(3) + +#define APPLE_SPI_CFG 0x004 +#define APPLE_SPI_CFG_CPHA BIT(1) +#define APPLE_SPI_CFG_CPOL BIT(2) +#define APPLE_SPI_CFG_MODE GENMASK(6, 5) +#define APPLE_SPI_CFG_MODE_POLLED 0 +#define APPLE_SPI_CFG_MODE_IRQ 1 +#define APPLE_SPI_CFG_MODE_DMA 2 +#define APPLE_SPI_CFG_IE_RXCOMPLETE BIT(7) +#define APPLE_SPI_CFG_IE_TXRXTHRESH BIT(8) +#define APPLE_SPI_CFG_LSB_FIRST BIT(13) +#define APPLE_SPI_CFG_WORD_SIZE GENMASK(16, 15) +#define APPLE_SPI_CFG_WORD_SIZE_8B 0 +#define APPLE_SPI_CFG_WORD_SIZE_16B 1 +#define APPLE_SPI_CFG_WORD_SIZE_32B 2 +#define APPLE_SPI_CFG_FIFO_THRESH GENMASK(18, 17) +#define APPLE_SPI_CFG_FIFO_THRESH_8B 0 +#define APPLE_SPI_CFG_FIFO_THRESH_4B 1 +#define APPLE_SPI_CFG_FIFO_THRESH_1B 2 +#define APPLE_SPI_CFG_IE_TXCOMPLETE BIT(21) + +#define APPLE_SPI_STATUS 0x008 +#define APPLE_SPI_STATUS_RXCOMPLETE BIT(0) +#define APPLE_SPI_STATUS_TXRXTHRESH BIT(1) +#define APPLE_SPI_STATUS_TXCOMPLETE BIT(2) + +#define APPLE_SPI_PIN 0x00c +#define APPLE_SPI_PIN_KEEP_MOSI BIT(0) +#define APPLE_SPI_PIN_CS BIT(1) + +#define APPLE_SPI_TXDATA 0x010 +#define APPLE_SPI_RXDATA 0x020 +#define APPLE_SPI_CLKDIV 0x030 +#define APPLE_SPI_CLKDIV_MAX 0x7ff +#define APPLE_SPI_RXCNT 0x034 +#define APPLE_SPI_WORD_DELAY 0x038 +#define APPLE_SPI_TXCNT 0x04c + +#define APPLE_SPI_FIFOSTAT 0x10c +#define APPLE_SPI_FIFOSTAT_TXFULL BIT(4) +#define APPLE_SPI_FIFOSTAT_LEVEL_TX GENMASK(15, 8) +#define APPLE_SPI_FIFOSTAT_RXEMPTY BIT(20) +#define APPLE_SPI_FIFOSTAT_LEVEL_RX GENMASK(31, 24) + +#define APPLE_SPI_IE_XFER 0x130 +#define APPLE_SPI_IF_XFER 0x134 +#define APPLE_SPI_XFER_RXCOMPLETE BIT(0) +#define APPLE_SPI_XFER_TXCOMPLETE BIT(1) + +#define APPLE_SPI_IE_FIFO 0x138 +#define APPLE_SPI_IF_FIFO 0x13c +#define APPLE_SPI_FIFO_RXTHRESH BIT(4) +#define APPLE_SPI_FIFO_TXTHRESH BIT(5) +#define APPLE_SPI_FIFO_RXFULL BIT(8) +#define APPLE_SPI_FIFO_TXEMPTY BIT(9) +#define APPLE_SPI_FIFO_RXUNDERRUN BIT(16) +#define APPLE_SPI_FIFO_TXOVERFLOW BIT(17) + +#define APPLE_SPI_SHIFTCFG 0x150 +#define APPLE_SPI_SHIFTCFG_CLK_ENABLE BIT(0) +#define APPLE_SPI_SHIFTCFG_CS_ENABLE BIT(1) +#define APPLE_SPI_SHIFTCFG_AND_CLK_DATA BIT(8) +#define APPLE_SPI_SHIFTCFG_CS_AS_DATA BIT(9) +#define APPLE_SPI_SHIFTCFG_TX_ENABLE BIT(10) +#define APPLE_SPI_SHIFTCFG_RX_ENABLE BIT(11) +#define APPLE_SPI_SHIFTCFG_BITS GENMASK(21, 16) +#define APPLE_SPI_SHIFTCFG_OVERRIDE_CS BIT(24) + +#define APPLE_SPI_PINCFG 0x154 +#define APPLE_SPI_PINCFG_KEEP_CLK BIT(0) +#define APPLE_SPI_PINCFG_KEEP_CS BIT(1) +#define APPLE_SPI_PINCFG_KEEP_MOSI BIT(2) +#define APPLE_SPI_PINCFG_CLK_IDLE_VAL BIT(8) +#define APPLE_SPI_PINCFG_CS_IDLE_VAL BIT(9) +#define APPLE_SPI_PINCFG_MOSI_IDLE_VAL BIT(10) + +#define APPLE_SPI_DELAY_PRE 0x160 +#define APPLE_SPI_DELAY_POST 0x168 +#define APPLE_SPI_DELAY_ENABLE BIT(0) +#define APPLE_SPI_DELAY_NO_INTERBYTE BIT(1) +#define APPLE_SPI_DELAY_SET_SCK BIT(4) +#define APPLE_SPI_DELAY_SET_MOSI BIT(6) +#define APPLE_SPI_DELAY_SCK_VAL BIT(8) +#define APPLE_SPI_DELAY_MOSI_VAL BIT(12) + +#define APPLE_SPI_FIFO_DEPTH 16 + +/* + * The slowest refclock available is 24MHz, the highest divider is 0x7ff, + * the largest word size is 32 bits, the FIFO depth is 16, the maximum + * intra-word delay is 0xffff refclocks. So the maximum time a transfer + * cycle can take is: + * + * (0x7ff * 32 + 0xffff) * 16 / 24e6 Hz ~= 87ms + * + * Double it and round it up to 200ms for good measure. + */ +#define APPLE_SPI_TIMEOUT_MS 200 + +struct apple_spi { + void __iomem *regs; /* MMIO register address */ + struct clk *clk; /* bus clock */ + struct completion done; /* wake-up from interrupt */ +}; + +static inline void reg_write(struct apple_spi *spi, int offset, u32 value) +{ + writel_relaxed(value, spi->regs + offset); +} + +static inline u32 reg_read(struct apple_spi *spi, int offset) +{ + return readl_relaxed(spi->regs + offset); +} + +static inline void reg_mask(struct apple_spi *spi, int offset, u32 clear, u32 set) +{ + u32 val = reg_read(spi, offset); + + val &= ~clear; + val |= set; + reg_write(spi, offset, val); +} + +static void apple_spi_init(struct apple_spi *spi) +{ + /* Set CS high (inactive) and disable override and auto-CS */ + reg_write(spi, APPLE_SPI_PIN, APPLE_SPI_PIN_CS); + reg_mask(spi, APPLE_SPI_SHIFTCFG, APPLE_SPI_SHIFTCFG_OVERRIDE_CS, 0); + reg_mask(spi, APPLE_SPI_PINCFG, APPLE_SPI_PINCFG_CS_IDLE_VAL, APPLE_SPI_PINCFG_KEEP_CS); + + /* Reset FIFOs */ + reg_write(spi, APPLE_SPI_CTRL, APPLE_SPI_CTRL_RX_RESET | APPLE_SPI_CTRL_TX_RESET); + + /* Configure defaults */ + reg_write(spi, APPLE_SPI_CFG, + FIELD_PREP(APPLE_SPI_CFG_FIFO_THRESH, APPLE_SPI_CFG_FIFO_THRESH_8B) | + FIELD_PREP(APPLE_SPI_CFG_MODE, APPLE_SPI_CFG_MODE_IRQ) | + FIELD_PREP(APPLE_SPI_CFG_WORD_SIZE, APPLE_SPI_CFG_WORD_SIZE_8B)); + + /* Disable IRQs */ + reg_write(spi, APPLE_SPI_IE_FIFO, 0); + reg_write(spi, APPLE_SPI_IE_XFER, 0); + + /* Disable delays */ + reg_write(spi, APPLE_SPI_DELAY_PRE, 0); + reg_write(spi, APPLE_SPI_DELAY_POST, 0); +} + +static int apple_spi_prepare_message(struct spi_controller *ctlr, struct spi_message *msg) +{ + struct apple_spi *spi = spi_controller_get_devdata(ctlr); + struct spi_device *device = msg->spi; + + u32 cfg = ((device->mode & SPI_CPHA ? APPLE_SPI_CFG_CPHA : 0) | + (device->mode & SPI_CPOL ? APPLE_SPI_CFG_CPOL : 0) | + (device->mode & SPI_LSB_FIRST ? APPLE_SPI_CFG_LSB_FIRST : 0)); + + /* Update core config */ + reg_mask(spi, APPLE_SPI_CFG, + APPLE_SPI_CFG_CPHA | APPLE_SPI_CFG_CPOL | APPLE_SPI_CFG_LSB_FIRST, cfg); + + return 0; +} + +static void apple_spi_set_cs(struct spi_device *device, bool is_high) +{ + struct apple_spi *spi = spi_controller_get_devdata(device->controller); + + reg_mask(spi, APPLE_SPI_PIN, APPLE_SPI_PIN_CS, is_high ? APPLE_SPI_PIN_CS : 0); +} + +static bool apple_spi_prep_transfer(struct apple_spi *spi, struct spi_transfer *t) +{ + u32 cr, fifo_threshold; + + /* Calculate and program the clock rate */ + cr = DIV_ROUND_UP(clk_get_rate(spi->clk), t->speed_hz); + reg_write(spi, APPLE_SPI_CLKDIV, min_t(u32, cr, APPLE_SPI_CLKDIV_MAX)); + + /* Update bits per word */ + reg_mask(spi, APPLE_SPI_SHIFTCFG, APPLE_SPI_SHIFTCFG_BITS, + FIELD_PREP(APPLE_SPI_SHIFTCFG_BITS, t->bits_per_word)); + + /* We will want to poll if the time we need to wait is + * less than the context switching time. + * Let's call that threshold 5us. The operation will take: + * bits_per_word * fifo_threshold / hz <= 5 * 10^-6 + * 200000 * bits_per_word * fifo_threshold <= hz + */ + fifo_threshold = APPLE_SPI_FIFO_DEPTH / 2; + return (200000 * t->bits_per_word * fifo_threshold) <= t->speed_hz; +} + +static irqreturn_t apple_spi_irq(int irq, void *dev_id) +{ + struct apple_spi *spi = dev_id; + u32 fifo = reg_read(spi, APPLE_SPI_IF_FIFO) & reg_read(spi, APPLE_SPI_IE_FIFO); + u32 xfer = reg_read(spi, APPLE_SPI_IF_XFER) & reg_read(spi, APPLE_SPI_IE_XFER); + + if (fifo || xfer) { + /* Disable interrupts until next transfer */ + reg_write(spi, APPLE_SPI_IE_XFER, 0); + reg_write(spi, APPLE_SPI_IE_FIFO, 0); + complete(&spi->done); + return IRQ_HANDLED; + } + + return IRQ_NONE; +} + +static int apple_spi_wait(struct apple_spi *spi, u32 fifo_bit, u32 xfer_bit, int poll) +{ + int ret = 0; + + if (poll) { + u32 fifo, xfer; + unsigned long timeout = jiffies + APPLE_SPI_TIMEOUT_MS * HZ / 1000; + + do { + fifo = reg_read(spi, APPLE_SPI_IF_FIFO); + xfer = reg_read(spi, APPLE_SPI_IF_XFER); + if (time_after(jiffies, timeout)) { + ret = -ETIMEDOUT; + break; + } + } while (!((fifo & fifo_bit) || (xfer & xfer_bit))); + } else { + reinit_completion(&spi->done); + reg_write(spi, APPLE_SPI_IE_XFER, xfer_bit); + reg_write(spi, APPLE_SPI_IE_FIFO, fifo_bit); + + if (!wait_for_completion_timeout(&spi->done, + msecs_to_jiffies(APPLE_SPI_TIMEOUT_MS))) + ret = -ETIMEDOUT; + + reg_write(spi, APPLE_SPI_IE_XFER, 0); + reg_write(spi, APPLE_SPI_IE_FIFO, 0); + } + + return ret; +} + +static void apple_spi_tx(struct apple_spi *spi, const void **tx_ptr, u32 *left, + unsigned int bytes_per_word) +{ + u32 inuse, words, wrote; + + if (!*tx_ptr) + return; + + inuse = FIELD_GET(APPLE_SPI_FIFOSTAT_LEVEL_TX, reg_read(spi, APPLE_SPI_FIFOSTAT)); + words = wrote = min_t(u32, *left, APPLE_SPI_FIFO_DEPTH - inuse); + + if (!words) + return; + + *left -= words; + + switch (bytes_per_word) { + case 1: { + const u8 *p = *tx_ptr; + + while (words--) + reg_write(spi, APPLE_SPI_TXDATA, *p++); + break; + } + case 2: { + const u16 *p = *tx_ptr; + + while (words--) + reg_write(spi, APPLE_SPI_TXDATA, *p++); + break; + } + case 4: { + const u32 *p = *tx_ptr; + + while (words--) + reg_write(spi, APPLE_SPI_TXDATA, *p++); + break; + } + default: + WARN_ON(1); + } + + *tx_ptr = ((u8 *)*tx_ptr) + bytes_per_word * wrote; +} + +static void apple_spi_rx(struct apple_spi *spi, void **rx_ptr, u32 *left, + unsigned int bytes_per_word) +{ + u32 words, read; + + if (!*rx_ptr) + return; + + words = read = FIELD_GET(APPLE_SPI_FIFOSTAT_LEVEL_RX, reg_read(spi, APPLE_SPI_FIFOSTAT)); + WARN_ON(words > *left); + + if (!words) + return; + + *left -= min_t(u32, *left, words); + + switch (bytes_per_word) { + case 1: { + u8 *p = *rx_ptr; + + while (words--) + *p++ = reg_read(spi, APPLE_SPI_RXDATA); + break; + } + case 2: { + u16 *p = *rx_ptr; + + while (words--) + *p++ = reg_read(spi, APPLE_SPI_RXDATA); + break; + } + case 4: { + u32 *p = *rx_ptr; + + while (words--) + *p++ = reg_read(spi, APPLE_SPI_RXDATA); + break; + } + default: + WARN_ON(1); + } + + *rx_ptr = ((u8 *)*rx_ptr) + bytes_per_word * read; +} + +static int apple_spi_transfer_one(struct spi_controller *ctlr, struct spi_device *device, + struct spi_transfer *t) +{ + struct apple_spi *spi = spi_controller_get_devdata(ctlr); + bool poll = apple_spi_prep_transfer(spi, t); + const void *tx_ptr = t->tx_buf; + void *rx_ptr = t->rx_buf; + unsigned int bytes_per_word; + u32 words, remaining_tx, remaining_rx; + u32 xfer_flags = 0; + u32 fifo_flags; + int retries = 100; + int ret = 0; + + if (t->bits_per_word > 16) + bytes_per_word = 4; + else if (t->bits_per_word > 8) + bytes_per_word = 2; + else + bytes_per_word = 1; + + words = t->len / bytes_per_word; + remaining_tx = tx_ptr ? words : 0; + remaining_rx = rx_ptr ? words : 0; + + /* Reset FIFOs */ + reg_write(spi, APPLE_SPI_CTRL, APPLE_SPI_CTRL_RX_RESET | APPLE_SPI_CTRL_TX_RESET); + + /* Clear IRQ flags */ + reg_write(spi, APPLE_SPI_IF_XFER, ~0); + reg_write(spi, APPLE_SPI_IF_FIFO, ~0); + + /* Determine transfer completion flags we wait for */ + if (tx_ptr) + xfer_flags |= APPLE_SPI_XFER_TXCOMPLETE; + if (rx_ptr) + xfer_flags |= APPLE_SPI_XFER_RXCOMPLETE; + + /* Set transfer length */ + reg_write(spi, APPLE_SPI_TXCNT, remaining_tx); + reg_write(spi, APPLE_SPI_RXCNT, remaining_rx); + + /* Prime transmit FIFO */ + apple_spi_tx(spi, &tx_ptr, &remaining_tx, bytes_per_word); + + /* Start transfer */ + reg_write(spi, APPLE_SPI_CTRL, APPLE_SPI_CTRL_RUN); + + /* TX again since a few words get popped off immediately */ + apple_spi_tx(spi, &tx_ptr, &remaining_tx, bytes_per_word); + + while (xfer_flags) { + fifo_flags = 0; + + if (remaining_tx) + fifo_flags |= APPLE_SPI_FIFO_TXTHRESH; + if (remaining_rx) + fifo_flags |= APPLE_SPI_FIFO_RXTHRESH; + + /* Wait for anything to happen */ + ret = apple_spi_wait(spi, fifo_flags, xfer_flags, poll); + if (ret) { + dev_err(&ctlr->dev, "transfer timed out (remaining %d tx, %d rx)\n", + remaining_tx, remaining_rx); + goto err; + } + + /* Stop waiting on transfer halves once they complete */ + xfer_flags &= ~reg_read(spi, APPLE_SPI_IF_XFER); + + /* Transmit and receive everything we can */ + apple_spi_tx(spi, &tx_ptr, &remaining_tx, bytes_per_word); + apple_spi_rx(spi, &rx_ptr, &remaining_rx, bytes_per_word); + } + + /* + * Sometimes the transfer completes before the last word is in the RX FIFO. + * Normally one retry is all it takes to get the last word out. + */ + while (remaining_rx && retries--) + apple_spi_rx(spi, &rx_ptr, &remaining_rx, bytes_per_word); + + if (remaining_tx) + dev_err(&ctlr->dev, "transfer completed with %d words left to transmit\n", + remaining_tx); + if (remaining_rx) + dev_err(&ctlr->dev, "transfer completed with %d words left to receive\n", + remaining_rx); + +err: + fifo_flags = reg_read(spi, APPLE_SPI_IF_FIFO); + WARN_ON(fifo_flags & APPLE_SPI_FIFO_TXOVERFLOW); + WARN_ON(fifo_flags & APPLE_SPI_FIFO_RXUNDERRUN); + + /* Stop transfer */ + reg_write(spi, APPLE_SPI_CTRL, 0); + + return ret; +} + +static int apple_spi_probe(struct platform_device *pdev) +{ + struct apple_spi *spi; + int ret, irq; + struct spi_controller *ctlr; + + ctlr = devm_spi_alloc_host(&pdev->dev, sizeof(struct apple_spi)); + if (!ctlr) + return -ENOMEM; + + spi = spi_controller_get_devdata(ctlr); + init_completion(&spi->done); + + spi->regs = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(spi->regs)) + return PTR_ERR(spi->regs); + + spi->clk = devm_clk_get_enabled(&pdev->dev, NULL); + if (IS_ERR(spi->clk)) + return dev_err_probe(&pdev->dev, PTR_ERR(spi->clk), + "Unable to find or enable bus clock\n"); + + irq = platform_get_irq(pdev, 0); + if (irq < 0) + return irq; + + ret = devm_request_irq(&pdev->dev, irq, apple_spi_irq, 0, + dev_name(&pdev->dev), spi); + if (ret) + return dev_err_probe(&pdev->dev, ret, "Unable to bind to interrupt\n"); + + ctlr->dev.of_node = pdev->dev.of_node; + ctlr->bus_num = pdev->id; + ctlr->num_chipselect = 1; + ctlr->mode_bits = SPI_CPHA | SPI_CPOL | SPI_LSB_FIRST; + ctlr->bits_per_word_mask = SPI_BPW_RANGE_MASK(1, 32); + ctlr->prepare_message = apple_spi_prepare_message; + ctlr->set_cs = apple_spi_set_cs; + ctlr->transfer_one = apple_spi_transfer_one; + ctlr->auto_runtime_pm = true; + + pm_runtime_set_active(&pdev->dev); + ret = devm_pm_runtime_enable(&pdev->dev); + if (ret < 0) + return ret; + + apple_spi_init(spi); + + ret = devm_spi_register_controller(&pdev->dev, ctlr); + if (ret < 0) + return dev_err_probe(&pdev->dev, ret, "devm_spi_register_controller failed\n"); + + return 0; +} + +static const struct of_device_id apple_spi_of_match[] = { + { .compatible = "apple,spi", }, + {} +}; +MODULE_DEVICE_TABLE(of, apple_spi_of_match); + +static struct platform_driver apple_spi_driver = { + .probe = apple_spi_probe, + .driver = { + .name = "apple-spi", + .owner = THIS_MODULE, + .of_match_table = apple_spi_of_match, + }, +}; +module_platform_driver(apple_spi_driver); + +MODULE_AUTHOR("Hector Martin "); +MODULE_DESCRIPTION("Apple SoC SPI driver"); +MODULE_LICENSE("GPL"); From 3ec83a377a995559c18880ff780a6873df9cc5d3 Mon Sep 17 00:00:00 2001 From: Jonas Rebmann Date: Thu, 7 Nov 2024 16:07:31 +0100 Subject: [PATCH 53/58] spi: spidev_test: add support for word delay Support setting the word delay using the -w/--word-delay command line parameter. Note that spidev exposes word delay only as an u8, allowing for a maximum of 255us of delay to be inserted. Signed-off-by: Jonas Rebmann Link: https://patch.msgid.link/20241107-spidev-test-word-delay-v1-1-d4bba5569e39@pengutronix.de Signed-off-by: Mark Brown --- tools/spi/spidev_test.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/tools/spi/spidev_test.c b/tools/spi/spidev_test.c index 9179942d7f15..f2135d619a0b 100644 --- a/tools/spi/spidev_test.c +++ b/tools/spi/spidev_test.c @@ -42,6 +42,7 @@ static char *input_file; static char *output_file; static uint32_t speed = 500000; static uint16_t delay; +static uint16_t word_delay; static int verbose; static int transfer_size; static int iterations; @@ -124,6 +125,7 @@ static void transfer(int fd, uint8_t const *tx, uint8_t const *rx, size_t len) .rx_buf = (unsigned long)rx, .len = len, .delay_usecs = delay, + .word_delay_usecs = word_delay, .speed_hz = speed, .bits_per_word = bits, }; @@ -172,11 +174,12 @@ static void transfer(int fd, uint8_t const *tx, uint8_t const *rx, size_t len) static void print_usage(const char *prog) { - printf("Usage: %s [-2348CDFHILMNORSZbdilopsv]\n", prog); + printf("Usage: %s [-2348CDFHILMNORSZbdilopsvw]\n", prog); puts("general device settings:\n" " -D --device device to use (default /dev/spidev1.1)\n" " -s --speed max speed (Hz)\n" " -d --delay delay (usec)\n" + " -w --word-delay word delay (usec)\n" " -l --loop loopback\n" "spi mode:\n" " -H --cpha clock phase\n" @@ -213,6 +216,7 @@ static void parse_opts(int argc, char *argv[]) { "device", 1, 0, 'D' }, { "speed", 1, 0, 's' }, { "delay", 1, 0, 'd' }, + { "word-delay", 1, 0, 'w' }, { "loop", 0, 0, 'l' }, { "cpha", 0, 0, 'H' }, { "cpol", 0, 0, 'O' }, @@ -237,7 +241,7 @@ static void parse_opts(int argc, char *argv[]) }; int c; - c = getopt_long(argc, argv, "D:s:d:b:i:o:lHOLC3ZFMNR248p:vS:I:", + c = getopt_long(argc, argv, "D:s:d:w:b:i:o:lHOLC3ZFMNR248p:vS:I:", lopts, NULL); if (c == -1) @@ -253,6 +257,9 @@ static void parse_opts(int argc, char *argv[]) case 'd': delay = atoi(optarg); break; + case 'w': + word_delay = atoi(optarg); + break; case 'b': bits = atoi(optarg); break; From c6d0529fb70c14e3ea67ac70211ed4359bbac99d Mon Sep 17 00:00:00 2001 From: Jiapeng Chong Date: Mon, 11 Nov 2024 14:54:25 +0800 Subject: [PATCH 54/58] spi: apple: Remove unnecessary .owner for apple_spi_driver Remove .owner field if calls are used which set it automatically. ./drivers/spi/spi-apple.c:522:3-8: No need to set .owner here. The core will do it. Reported-by: Abaci Robot Closes: https://bugzilla.openanolis.cn/show_bug.cgi?id=11799 Signed-off-by: Jiapeng Chong Link: https://patch.msgid.link/20241111065425.103645-1-jiapeng.chong@linux.alibaba.com Signed-off-by: Mark Brown --- drivers/spi/spi-apple.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/spi/spi-apple.c b/drivers/spi/spi-apple.c index 1ce91cea89be..d4b126c8701a 100644 --- a/drivers/spi/spi-apple.c +++ b/drivers/spi/spi-apple.c @@ -519,7 +519,6 @@ static struct platform_driver apple_spi_driver = { .probe = apple_spi_probe, .driver = { .name = "apple-spi", - .owner = THIS_MODULE, .of_match_table = apple_spi_of_match, }, }; From b1e7828cf9343e1da6c575f3ebaa0f511d8b8cbd Mon Sep 17 00:00:00 2001 From: zhang jiao Date: Tue, 12 Nov 2024 16:16:37 +0800 Subject: [PATCH 55/58] spi: Delete useless checks Since "res" will never be null, just delete this check. Signed-off-by: zhang jiao Link: https://patch.msgid.link/20241112081637.40962-1-zhangjiao2@cmss.chinamobile.com Signed-off-by: Mark Brown --- drivers/spi/spi.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index 74e04a4b0f19..460a49d9a0de 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -984,9 +984,6 @@ static void spi_res_free(void *res) { struct spi_res *sres = container_of(res, struct spi_res, data); - if (!res) - return; - WARN_ON(!list_empty(&sres->entry)); kfree(sres); } From f3c605147741e0ad8f1c51a7decef2040debfd16 Mon Sep 17 00:00:00 2001 From: Simon Trimmer Date: Tue, 12 Nov 2024 13:14:34 +0000 Subject: [PATCH 56/58] spi: cs42l43: Add GPIO speaker id support to the bridge configuration OEMs can use the spk-id-gpios ACPI property to indicate the type of speakers fitted to a device. Attempt to read a spk-id value using the GPIO method when a usable spk-id value is not obtained from the 01fa-spk-id-val ACPI property. Obtaining the spk-id value has been moved earlier in the function to the other sidecar block, so that an -EPROBE_DEFER from a GPIO driver is handled more efficiently. Signed-off-by: Simon Trimmer Signed-off-by: Charles Keepax Link: https://patch.msgid.link/20241112131434.678882-1-ckeepax@opensource.cirrus.com Signed-off-by: Mark Brown --- drivers/spi/spi-cs42l43.c | 46 ++++++++++++++++++++++++++++++++++----- 1 file changed, 41 insertions(+), 5 deletions(-) diff --git a/drivers/spi/spi-cs42l43.c b/drivers/spi/spi-cs42l43.c index 5b8ed65f8094..d0b55a26c31b 100644 --- a/drivers/spi/spi-cs42l43.c +++ b/drivers/spi/spi-cs42l43.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -229,6 +230,33 @@ static size_t cs42l43_spi_max_length(struct spi_device *spi) return CS42L43_SPI_MAX_LENGTH; } +static int cs42l43_get_speaker_id_gpios(struct cs42l43_spi *priv, int *result) +{ + struct gpio_descs *descs; + u32 spkid; + int i, ret; + + descs = gpiod_get_array_optional(priv->dev, "spk-id", GPIOD_IN); + if (IS_ERR_OR_NULL(descs)) + return PTR_ERR(descs); + + spkid = 0; + for (i = 0; i < descs->ndescs; i++) { + ret = gpiod_get_value_cansleep(descs->desc[i]); + if (ret < 0) + goto err; + + spkid |= (ret << i); + } + + dev_dbg(priv->dev, "spk-id-gpios = %d\n", spkid); + *result = spkid; +err: + gpiod_put_array(descs); + + return ret; +} + static struct fwnode_handle *cs42l43_find_xu_node(struct fwnode_handle *fwnode) { static const u32 func_smart_amp = 0x1; @@ -306,6 +334,7 @@ static int cs42l43_spi_probe(struct platform_device *pdev) struct fwnode_handle *fwnode = dev_fwnode(cs42l43->dev); struct fwnode_handle *xu_fwnode __free(fwnode_handle) = cs42l43_find_xu_node(fwnode); int nsidecars = 0; + int spkid = -EINVAL; int ret; priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); @@ -360,6 +389,18 @@ static int cs42l43_spi_probe(struct platform_device *pdev) fwnode_property_read_u32(xu_fwnode, "01fa-sidecar-instances", &nsidecars); if (nsidecars) { + ret = fwnode_property_read_u32(xu_fwnode, "01fa-spk-id-val", &spkid); + if (!ret) { + dev_dbg(priv->dev, "01fa-spk-id-val = %d\n", spkid); + } else if (ret != -EINVAL) { + return dev_err_probe(priv->dev, ret, "Failed to get spk-id-val\n"); + } else { + ret = cs42l43_get_speaker_id_gpios(priv, &spkid); + if (ret < 0) + return dev_err_probe(priv->dev, ret, + "Failed to get spk-id-gpios\n"); + } + ret = software_node_register(&cs42l43_gpiochip_swnode); if (ret) return dev_err_probe(priv->dev, ret, @@ -385,11 +426,6 @@ static int cs42l43_spi_probe(struct platform_device *pdev) if (nsidecars) { struct spi_board_info *ampl_info; struct spi_board_info *ampr_info; - int spkid = -EINVAL; - - fwnode_property_read_u32(xu_fwnode, "01fa-spk-id-val", &spkid); - - dev_dbg(priv->dev, "Found speaker ID %d\n", spkid); ampl_info = cs42l43_create_bridge_amp(priv, "cs35l56-left", 0, spkid); if (!ampl_info) From 7b94af24a7a4d12a76183f1b2f0d363d2c9ced43 Mon Sep 17 00:00:00 2001 From: Jonas Rebmann Date: Wed, 13 Nov 2024 13:18:31 +0100 Subject: [PATCH 57/58] spi: imx: pass struct spi_transfer to prepare_transfer() In an upcoming patch, mx51_ecspi_prepare_transfer() needs access to the word_delay parameter. To enable controller-specific handling of such per-transfer parameters, extend the prepare_transfer() function of the spi_imx_devtype_data interface to take a struct spi_transfer argument, update all controller-specific implementations accordingly. Signed-off-by: Jonas Rebmann Reviewed-by: Frank Li Link: https://patch.msgid.link/20241113-imx-spi-word-delay-v2-1-2b65b737bf29@pengutronix.de Signed-off-by: Mark Brown --- drivers/spi/spi-imx.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/drivers/spi/spi-imx.c b/drivers/spi/spi-imx.c index 84c3da1a1e22..a43b6a81d89e 100644 --- a/drivers/spi/spi-imx.c +++ b/drivers/spi/spi-imx.c @@ -71,7 +71,8 @@ struct spi_imx_data; struct spi_imx_devtype_data { void (*intctrl)(struct spi_imx_data *spi_imx, int enable); int (*prepare_message)(struct spi_imx_data *spi_imx, struct spi_message *msg); - int (*prepare_transfer)(struct spi_imx_data *spi_imx, struct spi_device *spi); + int (*prepare_transfer)(struct spi_imx_data *spi_imx, struct spi_device *spi, + struct spi_transfer *t); void (*trigger)(struct spi_imx_data *spi_imx); int (*rx_available)(struct spi_imx_data *spi_imx); void (*reset)(struct spi_imx_data *spi_imx); @@ -648,7 +649,7 @@ static void mx51_configure_cpha(struct spi_imx_data *spi_imx, } static int mx51_ecspi_prepare_transfer(struct spi_imx_data *spi_imx, - struct spi_device *spi) + struct spi_device *spi, struct spi_transfer *t) { u32 ctrl = readl(spi_imx->base + MX51_ECSPI_CTRL); u32 clk; @@ -773,7 +774,7 @@ static int mx31_prepare_message(struct spi_imx_data *spi_imx, } static int mx31_prepare_transfer(struct spi_imx_data *spi_imx, - struct spi_device *spi) + struct spi_device *spi, struct spi_transfer *t) { unsigned int reg = MX31_CSPICTRL_ENABLE | MX31_CSPICTRL_HOST; unsigned int clk; @@ -877,7 +878,7 @@ static int mx21_prepare_message(struct spi_imx_data *spi_imx, } static int mx21_prepare_transfer(struct spi_imx_data *spi_imx, - struct spi_device *spi) + struct spi_device *spi, struct spi_transfer *t) { unsigned int reg = MX21_CSPICTRL_ENABLE | MX21_CSPICTRL_HOST; unsigned int max = is_imx27_cspi(spi_imx) ? 16 : 18; @@ -952,7 +953,7 @@ static int mx1_prepare_message(struct spi_imx_data *spi_imx, } static int mx1_prepare_transfer(struct spi_imx_data *spi_imx, - struct spi_device *spi) + struct spi_device *spi, struct spi_transfer *t) { unsigned int reg = MX1_CSPICTRL_ENABLE | MX1_CSPICTRL_HOST; unsigned int clk; @@ -1303,7 +1304,7 @@ static int spi_imx_setupxfer(struct spi_device *spi, spi_imx->target_burst = t->len; } - spi_imx->devtype_data->prepare_transfer(spi_imx, spi); + spi_imx->devtype_data->prepare_transfer(spi_imx, spi, t); return 0; } From a3bb4e663df318b232746478e7b191bcf6e3af40 Mon Sep 17 00:00:00 2001 From: Jonas Rebmann Date: Wed, 13 Nov 2024 13:18:32 +0100 Subject: [PATCH 58/58] spi: imx: support word delay Implement support for the word delay feature of i.MX51 (and onwards) via the ECSPI interface. Convert the requested delay to SPI cycles and account for an extra inter-word delay inserted by the controller in addition to the requested number of cycles, which was observed when testing this patch. Disable dynamic burst when word delay is set. As the configurable delay period in the controller is inserted after bursts, the burst length must equal the word length. Account for word delay in the transfer time estimation for polling_limit_us. Signed-off-by: Jonas Rebmann Reviewed-by: Frank Li Link: https://patch.msgid.link/20241113-imx-spi-word-delay-v2-2-2b65b737bf29@pengutronix.de Signed-off-by: Mark Brown --- drivers/spi/spi-imx.c | 95 ++++++++++++++++++++++++++++++++++++++----- 1 file changed, 85 insertions(+), 10 deletions(-) diff --git a/drivers/spi/spi-imx.c b/drivers/spi/spi-imx.c index a43b6a81d89e..0b6b0151b3a3 100644 --- a/drivers/spi/spi-imx.c +++ b/drivers/spi/spi-imx.c @@ -3,6 +3,7 @@ // Copyright (C) 2008 Juergen Beisert #include +#include #include #include #include @@ -13,7 +14,10 @@ #include #include #include +#include +#include #include +#include #include #include #include @@ -302,6 +306,18 @@ static bool spi_imx_can_dma(struct spi_controller *controller, struct spi_device #define MX51_ECSPI_STAT 0x18 #define MX51_ECSPI_STAT_RR (1 << 3) +#define MX51_ECSPI_PERIOD 0x1c +#define MX51_ECSPI_PERIOD_MASK 0x7fff +/* + * As measured on the i.MX6, the SPI host controller inserts a 4 SPI-Clock + * (SCLK) delay after each burst if the PERIOD reg is 0x0. This value will be + * called MX51_ECSPI_PERIOD_MIN_DELAY_SCK. + * + * If the PERIOD register is != 0, the controller inserts a delay of + * MX51_ECSPI_PERIOD_MIN_DELAY_SCK + register value + 1 SCLK after each burst. + */ +#define MX51_ECSPI_PERIOD_MIN_DELAY_SCK 4 + #define MX51_ECSPI_TESTREG 0x20 #define MX51_ECSPI_TESTREG_LBC BIT(31) @@ -652,6 +668,7 @@ static int mx51_ecspi_prepare_transfer(struct spi_imx_data *spi_imx, struct spi_device *spi, struct spi_transfer *t) { u32 ctrl = readl(spi_imx->base + MX51_ECSPI_CTRL); + u64 word_delay_sck; u32 clk; /* Clear BL field and set the right value */ @@ -683,6 +700,49 @@ static int mx51_ecspi_prepare_transfer(struct spi_imx_data *spi_imx, writel(ctrl, spi_imx->base + MX51_ECSPI_CTRL); + /* calculate word delay in SPI Clock (SCLK) cycles */ + if (t->word_delay.value == 0) { + word_delay_sck = 0; + } else if (t->word_delay.unit == SPI_DELAY_UNIT_SCK) { + word_delay_sck = t->word_delay.value; + + if (word_delay_sck <= MX51_ECSPI_PERIOD_MIN_DELAY_SCK) + word_delay_sck = 0; + else if (word_delay_sck <= MX51_ECSPI_PERIOD_MIN_DELAY_SCK + 1) + word_delay_sck = 1; + else + word_delay_sck -= MX51_ECSPI_PERIOD_MIN_DELAY_SCK + 1; + } else { + int word_delay_ns; + + word_delay_ns = spi_delay_to_ns(&t->word_delay, t); + if (word_delay_ns < 0) + return word_delay_ns; + + if (word_delay_ns <= mul_u64_u32_div(NSEC_PER_SEC, + MX51_ECSPI_PERIOD_MIN_DELAY_SCK, + spi_imx->spi_bus_clk)) { + word_delay_sck = 0; + } else if (word_delay_ns <= mul_u64_u32_div(NSEC_PER_SEC, + MX51_ECSPI_PERIOD_MIN_DELAY_SCK + 1, + spi_imx->spi_bus_clk)) { + word_delay_sck = 1; + } else { + word_delay_ns -= mul_u64_u32_div(NSEC_PER_SEC, + MX51_ECSPI_PERIOD_MIN_DELAY_SCK + 1, + spi_imx->spi_bus_clk); + + word_delay_sck = DIV_U64_ROUND_UP((u64)word_delay_ns * spi_imx->spi_bus_clk, + NSEC_PER_SEC); + } + } + + if (!FIELD_FIT(MX51_ECSPI_PERIOD_MASK, word_delay_sck)) + return -EINVAL; + + writel(FIELD_PREP(MX51_ECSPI_PERIOD_MASK, word_delay_sck), + spi_imx->base + MX51_ECSPI_PERIOD); + return 0; } @@ -1263,11 +1323,13 @@ static int spi_imx_setupxfer(struct spi_device *spi, /* * Initialize the functions for transfer. To transfer non byte-aligned - * words, we have to use multiple word-size bursts, we can't use - * dynamic_burst in that case. + * words, we have to use multiple word-size bursts. To insert word + * delay, the burst size has to equal the word size. We can't use + * dynamic_burst in these cases. */ if (spi_imx->devtype_data->dynamic_burst && !spi_imx->target_mode && !(spi->mode & SPI_CS_WORD) && + !(t->word_delay.value) && (spi_imx->bits_per_word == 8 || spi_imx->bits_per_word == 16 || spi_imx->bits_per_word == 32)) { @@ -1610,12 +1672,30 @@ static int spi_imx_pio_transfer_target(struct spi_device *spi, return ret; } +static unsigned int spi_imx_transfer_estimate_time_us(struct spi_transfer *transfer) +{ + u64 result; + + result = DIV_U64_ROUND_CLOSEST((u64)USEC_PER_SEC * transfer->len * BITS_PER_BYTE, + transfer->effective_speed_hz); + if (transfer->word_delay.value) { + unsigned int word_delay_us; + unsigned int words; + + words = DIV_ROUND_UP(transfer->len * BITS_PER_BYTE, transfer->bits_per_word); + word_delay_us = DIV_ROUND_CLOSEST(spi_delay_to_ns(&transfer->word_delay, transfer), + NSEC_PER_USEC); + result += words * word_delay_us; + } + + return min(result, U32_MAX); +} + static int spi_imx_transfer_one(struct spi_controller *controller, struct spi_device *spi, struct spi_transfer *transfer) { struct spi_imx_data *spi_imx = spi_controller_get_devdata(spi->controller); - unsigned long hz_per_byte, byte_limit; spi_imx_setupxfer(spi, transfer); transfer->effective_speed_hz = spi_imx->spi_bus_clk; @@ -1634,15 +1714,10 @@ static int spi_imx_transfer_one(struct spi_controller *controller, */ if (spi_imx->usedma) return spi_imx_dma_transfer(spi_imx, transfer); - /* - * Calculate the estimated time in us the transfer runs. Find - * the number of Hz per byte per polling limit. - */ - hz_per_byte = polling_limit_us ? ((8 + 4) * USEC_PER_SEC) / polling_limit_us : 0; - byte_limit = hz_per_byte ? transfer->effective_speed_hz / hz_per_byte : 1; /* run in polling mode for short transfers */ - if (transfer->len < byte_limit) + if (transfer->len == 1 || (polling_limit_us && + spi_imx_transfer_estimate_time_us(transfer) < polling_limit_us)) return spi_imx_poll_transfer(spi, transfer); return spi_imx_pio_transfer(spi, transfer);