From 49f63e6a89e94a757ef86340ec531668d26ecc30 Mon Sep 17 00:00:00 2001 From: Witold Sadowski Date: Wed, 24 Jul 2024 08:47:31 -0700 Subject: [PATCH 01/65] spi: dt-bindings: cadence: Add Marvell overlay bindings documentation for Cadence XSPI Add new bindings for the v2 Marvell xSPI overlay: marvell,cn10-xspi-nor compatible string. This new compatible string distinguishes between the original and modified xSPI block. Also add an optional base for the xfer register set with an additional reg field to allocate the xSPI Marvell overlay XFER block. Signed-off-by: Witold Sadowski Reviewed-by: Krzysztof Kozlowski Link: https://patch.msgid.link/20240724154739.582367-2-wsadowski@marvell.com Signed-off-by: Mark Brown --- .../devicetree/bindings/spi/cdns,xspi.yaml | 32 ++++++++++++++++--- 1 file changed, 28 insertions(+), 4 deletions(-) diff --git a/Documentation/devicetree/bindings/spi/cdns,xspi.yaml b/Documentation/devicetree/bindings/spi/cdns,xspi.yaml index eb0f92468185..38a5795589de 100644 --- a/Documentation/devicetree/bindings/spi/cdns,xspi.yaml +++ b/Documentation/devicetree/bindings/spi/cdns,xspi.yaml @@ -15,24 +15,27 @@ description: | single, dual, quad or octal wire transmission modes for read/write access to slaves such as SPI-NOR flash. -allOf: - - $ref: spi-controller.yaml# - properties: compatible: - const: cdns,xspi-nor + enum: + - cdns,xspi-nor + - marvell,cn10-xspi-nor reg: items: - description: address and length of the controller register set - description: address and length of the Slave DMA data port - description: address and length of the auxiliary registers + - description: address and length of the xfer registers + minItems: 3 reg-names: items: - const: io - const: sdma - const: aux + - const: xfer + minItems: 3 interrupts: maxItems: 1 @@ -42,6 +45,27 @@ required: - reg - interrupts +allOf: + - $ref: spi-controller.yaml# + - if: + properties: + compatible: + contains: + enum: + - marvell,cn10-xspi-nor + then: + properties: + reg: + minItems: 4 + reg-names: + minItems: 4 + else: + properties: + reg: + maxItems: 3 + reg-names: + maxItems: 3 + unevaluatedProperties: false examples: From b0d06169a7153f78b5356ca9e15cd836e43408dd Mon Sep 17 00:00:00 2001 From: Witold Sadowski Date: Wed, 24 Jul 2024 08:47:32 -0700 Subject: [PATCH 02/65] spi: cadence: Add static PHY configuration in Marvell overlay This commit adds support for static PHY configuration of Cadence xSPI block. Configuration will be applied only if Marvell overlay compatible string will be detected. Configuration is static over the whole frequency range. Signed-off-by: Witold Sadowski Link: https://patch.msgid.link/20240724154739.582367-3-wsadowski@marvell.com Signed-off-by: Mark Brown --- drivers/spi/spi-cadence-xspi.c | 113 ++++++++++++++++++++++++++++++++- 1 file changed, 112 insertions(+), 1 deletion(-) diff --git a/drivers/spi/spi-cadence-xspi.c b/drivers/spi/spi-cadence-xspi.c index 2e3eacd46b72..70b1b4a0ff13 100644 --- a/drivers/spi/spi-cadence-xspi.c +++ b/drivers/spi/spi-cadence-xspi.c @@ -193,6 +193,30 @@ ((op)->data.dir == SPI_MEM_DATA_IN) ? \ CDNS_XSPI_STIG_CMD_DIR_READ : CDNS_XSPI_STIG_CMD_DIR_WRITE)) +/* Marvell PHY default values */ +#define MARVELL_REGS_DLL_PHY_CTRL 0x00000707 +#define MARVELL_CTB_RFILE_PHY_CTRL 0x00004000 +#define MARVELL_RFILE_PHY_TSEL 0x00000000 +#define MARVELL_RFILE_PHY_DQ_TIMING 0x00000101 +#define MARVELL_RFILE_PHY_DQS_TIMING 0x00700404 +#define MARVELL_RFILE_PHY_GATE_LPBK_CTRL 0x00200030 +#define MARVELL_RFILE_PHY_DLL_MASTER_CTRL 0x00800000 +#define MARVELL_RFILE_PHY_DLL_SLAVE_CTRL 0x0000ff01 + +/* PHY config registers */ +#define CDNS_XSPI_RF_MINICTRL_REGS_DLL_PHY_CTRL 0x1034 +#define CDNS_XSPI_PHY_CTB_RFILE_PHY_CTRL 0x0080 +#define CDNS_XSPI_PHY_CTB_RFILE_PHY_TSEL 0x0084 +#define CDNS_XSPI_PHY_DATASLICE_RFILE_PHY_DQ_TIMING 0x0000 +#define CDNS_XSPI_PHY_DATASLICE_RFILE_PHY_DQS_TIMING 0x0004 +#define CDNS_XSPI_PHY_DATASLICE_RFILE_PHY_GATE_LPBK_CTRL 0x0008 +#define CDNS_XSPI_PHY_DATASLICE_RFILE_PHY_DLL_MASTER_CTRL 0x000c +#define CDNS_XSPI_PHY_DATASLICE_RFILE_PHY_DLL_SLAVE_CTRL 0x0010 +#define CDNS_XSPI_DATASLICE_RFILE_PHY_DLL_OBS_REG_0 0x001c + +#define CDNS_XSPI_DLL_RST_N BIT(24) +#define CDNS_XSPI_DLL_LOCK BIT(0) + enum cdns_xspi_stig_instr_type { CDNS_XSPI_STIG_INSTR_TYPE_0, CDNS_XSPI_STIG_INSTR_TYPE_1, @@ -209,6 +233,34 @@ enum cdns_xspi_stig_cmd_dir { CDNS_XSPI_STIG_CMD_DIR_WRITE, }; +struct cdns_xspi_driver_data { + bool mrvl_hw_overlay; + u32 dll_phy_ctrl; + u32 ctb_rfile_phy_ctrl; + u32 rfile_phy_tsel; + u32 rfile_phy_dq_timing; + u32 rfile_phy_dqs_timing; + u32 rfile_phy_gate_lpbk_ctrl; + u32 rfile_phy_dll_master_ctrl; + u32 rfile_phy_dll_slave_ctrl; +}; + +static struct cdns_xspi_driver_data marvell_driver_data = { + .mrvl_hw_overlay = true, + .dll_phy_ctrl = MARVELL_REGS_DLL_PHY_CTRL, + .ctb_rfile_phy_ctrl = MARVELL_CTB_RFILE_PHY_CTRL, + .rfile_phy_tsel = MARVELL_RFILE_PHY_TSEL, + .rfile_phy_dq_timing = MARVELL_RFILE_PHY_DQ_TIMING, + .rfile_phy_dqs_timing = MARVELL_RFILE_PHY_DQS_TIMING, + .rfile_phy_gate_lpbk_ctrl = MARVELL_RFILE_PHY_GATE_LPBK_CTRL, + .rfile_phy_dll_master_ctrl = MARVELL_RFILE_PHY_DLL_MASTER_CTRL, + .rfile_phy_dll_slave_ctrl = MARVELL_RFILE_PHY_DLL_SLAVE_CTRL, +}; + +static struct cdns_xspi_driver_data cdns_driver_data = { + .mrvl_hw_overlay = false, +}; + struct cdns_xspi_dev { struct platform_device *pdev; struct device *dev; @@ -230,8 +282,55 @@ struct cdns_xspi_dev { const void *out_buffer; u8 hw_num_banks; + + const struct cdns_xspi_driver_data *driver_data; }; +static void cdns_xspi_reset_dll(struct cdns_xspi_dev *cdns_xspi) +{ + u32 dll_cntrl = readl(cdns_xspi->iobase + + CDNS_XSPI_RF_MINICTRL_REGS_DLL_PHY_CTRL); + + /* Reset DLL */ + dll_cntrl |= CDNS_XSPI_DLL_RST_N; + writel(dll_cntrl, cdns_xspi->iobase + + CDNS_XSPI_RF_MINICTRL_REGS_DLL_PHY_CTRL); +} + +static bool cdns_xspi_is_dll_locked(struct cdns_xspi_dev *cdns_xspi) +{ + u32 dll_lock; + + return !readl_relaxed_poll_timeout(cdns_xspi->iobase + + CDNS_XSPI_INTR_STATUS_REG, + dll_lock, ((dll_lock & CDNS_XSPI_DLL_LOCK) == 1), 10, 10000); +} + +/* Static configuration of PHY */ +static bool cdns_xspi_configure_phy(struct cdns_xspi_dev *cdns_xspi) +{ + writel(cdns_xspi->driver_data->dll_phy_ctrl, + cdns_xspi->iobase + CDNS_XSPI_RF_MINICTRL_REGS_DLL_PHY_CTRL); + writel(cdns_xspi->driver_data->ctb_rfile_phy_ctrl, + cdns_xspi->auxbase + CDNS_XSPI_PHY_CTB_RFILE_PHY_CTRL); + writel(cdns_xspi->driver_data->rfile_phy_tsel, + cdns_xspi->auxbase + CDNS_XSPI_PHY_CTB_RFILE_PHY_TSEL); + writel(cdns_xspi->driver_data->rfile_phy_dq_timing, + cdns_xspi->auxbase + CDNS_XSPI_PHY_DATASLICE_RFILE_PHY_DQ_TIMING); + writel(cdns_xspi->driver_data->rfile_phy_dqs_timing, + cdns_xspi->auxbase + CDNS_XSPI_PHY_DATASLICE_RFILE_PHY_DQS_TIMING); + writel(cdns_xspi->driver_data->rfile_phy_gate_lpbk_ctrl, + cdns_xspi->auxbase + CDNS_XSPI_PHY_DATASLICE_RFILE_PHY_GATE_LPBK_CTRL); + writel(cdns_xspi->driver_data->rfile_phy_dll_master_ctrl, + cdns_xspi->auxbase + CDNS_XSPI_PHY_DATASLICE_RFILE_PHY_DLL_MASTER_CTRL); + writel(cdns_xspi->driver_data->rfile_phy_dll_slave_ctrl, + cdns_xspi->auxbase + CDNS_XSPI_PHY_DATASLICE_RFILE_PHY_DLL_SLAVE_CTRL); + + cdns_xspi_reset_dll(cdns_xspi); + + return cdns_xspi_is_dll_locked(cdns_xspi); +} + static int cdns_xspi_wait_for_controller_idle(struct cdns_xspi_dev *cdns_xspi) { u32 ctrl_stat; @@ -544,13 +643,17 @@ static int cdns_xspi_probe(struct platform_device *pdev) SPI_RX_DUAL | SPI_RX_QUAD | SPI_TX_OCTAL | SPI_RX_OCTAL | SPI_MODE_0 | SPI_MODE_3; + cdns_xspi = spi_controller_get_devdata(host); + cdns_xspi->driver_data = of_device_get_match_data(dev); + if (!cdns_xspi->driver_data) + return -ENODEV; + host->mem_ops = &cadence_xspi_mem_ops; host->dev.of_node = pdev->dev.of_node; host->bus_num = -1; platform_set_drvdata(pdev, host); - cdns_xspi = spi_controller_get_devdata(host); cdns_xspi->pdev = pdev; cdns_xspi->dev = &pdev->dev; cdns_xspi->cur_cs = 0; @@ -592,6 +695,9 @@ static int cdns_xspi_probe(struct platform_device *pdev) return ret; } + if (cdns_xspi->driver_data->mrvl_hw_overlay) + cdns_xspi_configure_phy(cdns_xspi); + cdns_xspi_print_phy_config(cdns_xspi); ret = cdns_xspi_controller_init(cdns_xspi); @@ -616,6 +722,11 @@ static int cdns_xspi_probe(struct platform_device *pdev) static const struct of_device_id cdns_xspi_of_match[] = { { .compatible = "cdns,xspi-nor", + .data = &cdns_driver_data, + }, + { + .compatible = "marvell,cn10-xspi-nor", + .data = &marvell_driver_data, }, { /* end of table */} }; From 26d34fdc49712ddbd42b11102f5d9d78a0f42097 Mon Sep 17 00:00:00 2001 From: Witold Sadowski Date: Wed, 24 Jul 2024 08:47:33 -0700 Subject: [PATCH 03/65] spi: cadence: Add clock configuration for Marvell xSPI overlay Add support for clock divider. Divider block can disable, enable and divide clock signal. Only 14 different divide ratios are avalible, from 6.25 up to 200MHz. For calculations use default Marvell system clock value(800MHz). Signed-off-by: Witold Sadowski Link: https://patch.msgid.link/20240724154739.582367-4-wsadowski@marvell.com Signed-off-by: Mark Brown --- drivers/spi/spi-cadence-xspi.c | 97 +++++++++++++++++++++++++++++++++- 1 file changed, 95 insertions(+), 2 deletions(-) diff --git a/drivers/spi/spi-cadence-xspi.c b/drivers/spi/spi-cadence-xspi.c index 70b1b4a0ff13..d0222284c507 100644 --- a/drivers/spi/spi-cadence-xspi.c +++ b/drivers/spi/spi-cadence-xspi.c @@ -217,6 +217,15 @@ #define CDNS_XSPI_DLL_RST_N BIT(24) #define CDNS_XSPI_DLL_LOCK BIT(0) +/* Marvell overlay registers - clock */ +#define MRVL_XSPI_CLK_CTRL_AUX_REG 0x2020 +#define MRVL_XSPI_CLK_ENABLE BIT(0) +#define MRVL_XSPI_CLK_DIV GENMASK(4, 1) +#define MRVL_XSPI_IRQ_ENABLE BIT(6) +#define MRVL_XSPI_CLOCK_IO_HZ 800000000 +#define MRVL_XSPI_CLOCK_DIVIDED(div) ((MRVL_XSPI_CLOCK_IO_HZ) / (div)) +#define MRVL_DEFAULT_CLK 25000000 + enum cdns_xspi_stig_instr_type { CDNS_XSPI_STIG_INSTR_TYPE_0, CDNS_XSPI_STIG_INSTR_TYPE_1, @@ -261,6 +270,23 @@ static struct cdns_xspi_driver_data cdns_driver_data = { .mrvl_hw_overlay = false, }; +const int cdns_mrvl_xspi_clk_div_list[] = { + 4, //0x0 = Divide by 4. SPI clock is 200 MHz. + 6, //0x1 = Divide by 6. SPI clock is 133.33 MHz. + 8, //0x2 = Divide by 8. SPI clock is 100 MHz. + 10, //0x3 = Divide by 10. SPI clock is 80 MHz. + 12, //0x4 = Divide by 12. SPI clock is 66.666 MHz. + 16, //0x5 = Divide by 16. SPI clock is 50 MHz. + 18, //0x6 = Divide by 18. SPI clock is 44.44 MHz. + 20, //0x7 = Divide by 20. SPI clock is 40 MHz. + 24, //0x8 = Divide by 24. SPI clock is 33.33 MHz. + 32, //0x9 = Divide by 32. SPI clock is 25 MHz. + 40, //0xA = Divide by 40. SPI clock is 20 MHz. + 50, //0xB = Divide by 50. SPI clock is 16 MHz. + 64, //0xC = Divide by 64. SPI clock is 12.5 MHz. + 128 //0xD = Divide by 128. SPI clock is 6.25 MHz. +}; + struct cdns_xspi_dev { struct platform_device *pdev; struct device *dev; @@ -331,6 +357,48 @@ static bool cdns_xspi_configure_phy(struct cdns_xspi_dev *cdns_xspi) return cdns_xspi_is_dll_locked(cdns_xspi); } +static bool cdns_mrvl_xspi_setup_clock(struct cdns_xspi_dev *cdns_xspi, + int requested_clk) +{ + int i = 0; + int clk_val; + u32 clk_reg; + bool update_clk = false; + + while (i < ARRAY_SIZE(cdns_mrvl_xspi_clk_div_list)) { + clk_val = MRVL_XSPI_CLOCK_DIVIDED( + cdns_mrvl_xspi_clk_div_list[i]); + if (clk_val <= requested_clk) + break; + i++; + } + + dev_dbg(cdns_xspi->dev, "Found clk div: %d, clk val: %d\n", + cdns_mrvl_xspi_clk_div_list[i], + MRVL_XSPI_CLOCK_DIVIDED( + cdns_mrvl_xspi_clk_div_list[i])); + + clk_reg = readl(cdns_xspi->auxbase + MRVL_XSPI_CLK_CTRL_AUX_REG); + + if (FIELD_GET(MRVL_XSPI_CLK_DIV, clk_reg) != i) { + clk_reg &= ~MRVL_XSPI_CLK_ENABLE; + writel(clk_reg, + cdns_xspi->auxbase + MRVL_XSPI_CLK_CTRL_AUX_REG); + clk_reg = FIELD_PREP(MRVL_XSPI_CLK_DIV, i); + clk_reg &= ~MRVL_XSPI_CLK_DIV; + clk_reg |= FIELD_PREP(MRVL_XSPI_CLK_DIV, i); + clk_reg |= MRVL_XSPI_CLK_ENABLE; + clk_reg |= MRVL_XSPI_IRQ_ENABLE; + update_clk = true; + } + + if (update_clk) + writel(clk_reg, + cdns_xspi->auxbase + MRVL_XSPI_CLK_CTRL_AUX_REG); + + return update_clk; +} + static int cdns_xspi_wait_for_controller_idle(struct cdns_xspi_dev *cdns_xspi) { u32 ctrl_stat; @@ -536,6 +604,21 @@ static int cdns_xspi_mem_op_execute(struct spi_mem *mem, return ret; } +static int marvell_xspi_mem_op_execute(struct spi_mem *mem, + const struct spi_mem_op *op) +{ + struct cdns_xspi_dev *cdns_xspi = + spi_controller_get_devdata(mem->spi->controller); + int ret = 0; + + cdns_mrvl_xspi_setup_clock(cdns_xspi, mem->spi->max_speed_hz); + + ret = cdns_xspi_mem_op(cdns_xspi, mem, op); + + return ret; +} + + static int cdns_xspi_adjust_mem_op_size(struct spi_mem *mem, struct spi_mem_op *op) { struct cdns_xspi_dev *cdns_xspi = @@ -551,6 +634,11 @@ static const struct spi_controller_mem_ops cadence_xspi_mem_ops = { .adjust_op_size = cdns_xspi_adjust_mem_op_size, }; +static const struct spi_controller_mem_ops marvell_xspi_mem_ops = { + .exec_op = marvell_xspi_mem_op_execute, + .adjust_op_size = cdns_xspi_adjust_mem_op_size, +}; + static irqreturn_t cdns_xspi_irq_handler(int this_irq, void *dev) { struct cdns_xspi_dev *cdns_xspi = dev; @@ -648,7 +736,10 @@ static int cdns_xspi_probe(struct platform_device *pdev) if (!cdns_xspi->driver_data) return -ENODEV; - host->mem_ops = &cadence_xspi_mem_ops; + if (cdns_xspi->driver_data->mrvl_hw_overlay) + host->mem_ops = &marvell_xspi_mem_ops; + else + host->mem_ops = &cadence_xspi_mem_ops; host->dev.of_node = pdev->dev.of_node; host->bus_num = -1; @@ -695,8 +786,10 @@ static int cdns_xspi_probe(struct platform_device *pdev) return ret; } - if (cdns_xspi->driver_data->mrvl_hw_overlay) + if (cdns_xspi->driver_data->mrvl_hw_overlay) { + cdns_mrvl_xspi_setup_clock(cdns_xspi, MRVL_DEFAULT_CLK); cdns_xspi_configure_phy(cdns_xspi); + } cdns_xspi_print_phy_config(cdns_xspi); From 75128e2a14a9f443e8debdd30445f5934b5a7c83 Mon Sep 17 00:00:00 2001 From: Witold Sadowski Date: Wed, 24 Jul 2024 08:47:34 -0700 Subject: [PATCH 04/65] spi: cadence: Add Marvell SDMA operations In Marvell xSPI implementation any access to SDMA register will result in 8 byte SPI data transfer. Reading less data(eg. 1B) will result in losing remaining bytes. To avoid that read/write 8 bytes into temporary buffer, and read/write whole temporary buffer into SDMA. Signed-off-by: Witold Sadowski Link: https://patch.msgid.link/20240724154739.582367-5-wsadowski@marvell.com Signed-off-by: Mark Brown --- drivers/spi/spi-cadence-xspi.c | 82 ++++++++++++++++++++++++++++++++-- 1 file changed, 79 insertions(+), 3 deletions(-) diff --git a/drivers/spi/spi-cadence-xspi.c b/drivers/spi/spi-cadence-xspi.c index d0222284c507..c177bf4ba536 100644 --- a/drivers/spi/spi-cadence-xspi.c +++ b/drivers/spi/spi-cadence-xspi.c @@ -310,6 +310,7 @@ struct cdns_xspi_dev { u8 hw_num_banks; const struct cdns_xspi_driver_data *driver_data; + void (*sdma_handler)(struct cdns_xspi_dev *cdns_xspi); }; static void cdns_xspi_reset_dll(struct cdns_xspi_dev *cdns_xspi) @@ -515,6 +516,78 @@ static void cdns_xspi_sdma_handle(struct cdns_xspi_dev *cdns_xspi) } } +static void m_ioreadq(void __iomem *addr, void *buf, int len) +{ + if (IS_ALIGNED((long)buf, 8) && len >= 8) { + u64 full_ops = len / 8; + u64 *buffer = buf; + + len -= full_ops * 8; + buf += full_ops * 8; + + do { + u64 b = readq(addr); + *buffer++ = b; + } while (--full_ops); + } + + + while (len) { + u64 tmp_buf; + + tmp_buf = readq(addr); + memcpy(buf, &tmp_buf, min(len, 8)); + len = len > 8 ? len - 8 : 0; + buf += 8; + } +} + +static void m_iowriteq(void __iomem *addr, const void *buf, int len) +{ + if (IS_ALIGNED((long)buf, 8) && len >= 8) { + u64 full_ops = len / 8; + const u64 *buffer = buf; + + len -= full_ops * 8; + buf += full_ops * 8; + + do { + writeq(*buffer++, addr); + } while (--full_ops); + } + + while (len) { + u64 tmp_buf; + + memcpy(&tmp_buf, buf, min(len, 8)); + writeq(tmp_buf, addr); + len = len > 8 ? len - 8 : 0; + buf += 8; + } +} + +static void marvell_xspi_sdma_handle(struct cdns_xspi_dev *cdns_xspi) +{ + u32 sdma_size, sdma_trd_info; + u8 sdma_dir; + + sdma_size = readl(cdns_xspi->iobase + CDNS_XSPI_SDMA_SIZE_REG); + sdma_trd_info = readl(cdns_xspi->iobase + CDNS_XSPI_SDMA_TRD_INFO_REG); + sdma_dir = FIELD_GET(CDNS_XSPI_SDMA_DIR, sdma_trd_info); + + switch (sdma_dir) { + case CDNS_XSPI_SDMA_DIR_READ: + m_ioreadq(cdns_xspi->sdmabase, + cdns_xspi->in_buffer, sdma_size); + break; + + case CDNS_XSPI_SDMA_DIR_WRITE: + m_iowriteq(cdns_xspi->sdmabase, + cdns_xspi->out_buffer, sdma_size); + break; + } +} + static int cdns_xspi_send_stig_command(struct cdns_xspi_dev *cdns_xspi, const struct spi_mem_op *op, bool data_phase) @@ -566,7 +639,7 @@ static int cdns_xspi_send_stig_command(struct cdns_xspi_dev *cdns_xspi, cdns_xspi_set_interrupts(cdns_xspi, false); return -EIO; } - cdns_xspi_sdma_handle(cdns_xspi); + cdns_xspi->sdma_handler(cdns_xspi); } wait_for_completion(&cdns_xspi->cmd_complete); @@ -736,10 +809,13 @@ static int cdns_xspi_probe(struct platform_device *pdev) if (!cdns_xspi->driver_data) return -ENODEV; - if (cdns_xspi->driver_data->mrvl_hw_overlay) + if (cdns_xspi->driver_data->mrvl_hw_overlay) { host->mem_ops = &marvell_xspi_mem_ops; - else + cdns_xspi->sdma_handler = &marvell_xspi_sdma_handle; + } else { host->mem_ops = &cadence_xspi_mem_ops; + cdns_xspi->sdma_handler = &cdns_xspi_sdma_handle; + } host->dev.of_node = pdev->dev.of_node; host->bus_num = -1; From fa7279acef673f17550202d662f592672be26247 Mon Sep 17 00:00:00 2001 From: Witold Sadowski Date: Wed, 24 Jul 2024 08:47:35 -0700 Subject: [PATCH 05/65] spi: cadence: Add Marvell xSPI interrupt changes It is possible that before enabling interrupt, interrupt bit will be set. It might cause improper IRQ handler behaviour. To fix it, clear interrupt bit before enabling interrupts. That behaviour is specific to Marvell xSPI implementation. In addition in Marvell xSPI interrupt must be cleared in two places - xSPI itself, and Marvell overlay. Signed-off-by: Witold Sadowski Link: https://patch.msgid.link/20240724154739.582367-6-wsadowski@marvell.com Signed-off-by: Mark Brown --- drivers/spi/spi-cadence-xspi.c | 28 ++++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/drivers/spi/spi-cadence-xspi.c b/drivers/spi/spi-cadence-xspi.c index c177bf4ba536..84a320186aaf 100644 --- a/drivers/spi/spi-cadence-xspi.c +++ b/drivers/spi/spi-cadence-xspi.c @@ -311,6 +311,7 @@ struct cdns_xspi_dev { const struct cdns_xspi_driver_data *driver_data; void (*sdma_handler)(struct cdns_xspi_dev *cdns_xspi); + void (*set_interrupts_handler)(struct cdns_xspi_dev *cdns_xspi, bool enabled); }; static void cdns_xspi_reset_dll(struct cdns_xspi_dev *cdns_xspi) @@ -472,6 +473,23 @@ static void cdns_xspi_set_interrupts(struct cdns_xspi_dev *cdns_xspi, writel(intr_enable, cdns_xspi->iobase + CDNS_XSPI_INTR_ENABLE_REG); } +static void marvell_xspi_set_interrupts(struct cdns_xspi_dev *cdns_xspi, + bool enabled) +{ + u32 intr_enable; + u32 irq_status; + + irq_status = readl(cdns_xspi->iobase + CDNS_XSPI_INTR_STATUS_REG); + writel(irq_status, cdns_xspi->iobase + CDNS_XSPI_INTR_STATUS_REG); + + intr_enable = readl(cdns_xspi->iobase + CDNS_XSPI_INTR_ENABLE_REG); + if (enabled) + intr_enable |= CDNS_XSPI_INTR_MASK; + else + intr_enable &= ~CDNS_XSPI_INTR_MASK; + writel(intr_enable, cdns_xspi->iobase + CDNS_XSPI_INTR_ENABLE_REG); +} + static int cdns_xspi_controller_init(struct cdns_xspi_dev *cdns_xspi) { u32 ctrl_ver; @@ -489,7 +507,7 @@ static int cdns_xspi_controller_init(struct cdns_xspi_dev *cdns_xspi) ctrl_features = readl(cdns_xspi->iobase + CDNS_XSPI_CTRL_FEATURES_REG); cdns_xspi->hw_num_banks = FIELD_GET(CDNS_XSPI_NUM_BANKS, ctrl_features); - cdns_xspi_set_interrupts(cdns_xspi, false); + cdns_xspi->set_interrupts_handler(cdns_xspi, false); return 0; } @@ -604,7 +622,7 @@ static int cdns_xspi_send_stig_command(struct cdns_xspi_dev *cdns_xspi, writel(FIELD_PREP(CDNS_XSPI_CTRL_WORK_MODE, CDNS_XSPI_WORK_MODE_STIG), cdns_xspi->iobase + CDNS_XSPI_CTRL_CONFIG_REG); - cdns_xspi_set_interrupts(cdns_xspi, true); + cdns_xspi->set_interrupts_handler(cdns_xspi, true); cdns_xspi->sdma_error = false; memset(cmd_regs, 0, sizeof(cmd_regs)); @@ -636,14 +654,14 @@ static int cdns_xspi_send_stig_command(struct cdns_xspi_dev *cdns_xspi, wait_for_completion(&cdns_xspi->sdma_complete); if (cdns_xspi->sdma_error) { - cdns_xspi_set_interrupts(cdns_xspi, false); + cdns_xspi->set_interrupts_handler(cdns_xspi, false); return -EIO; } cdns_xspi->sdma_handler(cdns_xspi); } wait_for_completion(&cdns_xspi->cmd_complete); - cdns_xspi_set_interrupts(cdns_xspi, false); + cdns_xspi->set_interrupts_handler(cdns_xspi, false); cmd_status = cdns_xspi_check_command_status(cdns_xspi); if (cmd_status) @@ -812,9 +830,11 @@ static int cdns_xspi_probe(struct platform_device *pdev) if (cdns_xspi->driver_data->mrvl_hw_overlay) { host->mem_ops = &marvell_xspi_mem_ops; cdns_xspi->sdma_handler = &marvell_xspi_sdma_handle; + cdns_xspi->set_interrupts_handler = &marvell_xspi_set_interrupts; } else { host->mem_ops = &cadence_xspi_mem_ops; cdns_xspi->sdma_handler = &cdns_xspi_sdma_handle; + cdns_xspi->set_interrupts_handler = &cdns_xspi_set_interrupts; } host->dev.of_node = pdev->dev.of_node; host->bus_num = -1; From 931e389ded0f1411cbf07ad50074dc2bcd49e1a8 Mon Sep 17 00:00:00 2001 From: Witold Sadowski Date: Wed, 24 Jul 2024 08:47:36 -0700 Subject: [PATCH 06/65] spi: cadence: Add Marvell xfer operation support Marvell Xfer overlay extends xSPI capabilities to support non-memory SPI operations. The Marvell overlay, combined with a generic command, allows for full-duplex SPI transactions. It also enables transactions with undetermined lengths using the cs_hold parameter and the ability to extend CS signal assertion, even if the xSPI block requests CS signal de-assertion. Marvell overlay is using part of xSPI for writing data into device, and additional hardware block to read data from the device. To do that xSPI will trigger 1 byte generic command followed by data sequence. In same time overlay block will monitor MISO pin to read data from the device. Due to that SDMA data start will be shifted by 1 byte. Signed-off-by: Witold Sadowski Link: https://patch.msgid.link/20240724154739.582367-7-wsadowski@marvell.com Signed-off-by: Mark Brown --- drivers/spi/spi-cadence-xspi.c | 272 +++++++++++++++++++++++++++++++++ 1 file changed, 272 insertions(+) diff --git a/drivers/spi/spi-cadence-xspi.c b/drivers/spi/spi-cadence-xspi.c index 84a320186aaf..69c08bae7628 100644 --- a/drivers/spi/spi-cadence-xspi.c +++ b/drivers/spi/spi-cadence-xspi.c @@ -19,6 +19,7 @@ #include #include #include +#include #define CDNS_XSPI_MAGIC_NUM_VALUE 0x6522 #define CDNS_XSPI_MAX_BANKS 8 @@ -193,6 +194,34 @@ ((op)->data.dir == SPI_MEM_DATA_IN) ? \ CDNS_XSPI_STIG_CMD_DIR_READ : CDNS_XSPI_STIG_CMD_DIR_WRITE)) +/* Helper macros for GENERIC and GENERIC-DSEQ instruction type */ +#define CMD_REG_LEN (6*4) +#define INSTRUCTION_TYPE_GENERIC 96 +#define CDNS_XSPI_CMD_FLD_P1_GENERIC_CMD (\ + FIELD_PREP(CDNS_XSPI_CMD_INSTR_TYPE, INSTRUCTION_TYPE_GENERIC)) + +#define GENERIC_NUM_OF_BYTES GENMASK(27, 24) +#define CDNS_XSPI_CMD_FLD_P3_GENERIC_CMD(len) (\ + FIELD_PREP(GENERIC_NUM_OF_BYTES, len)) + +#define GENERIC_BANK_NUM GENMASK(14, 12) +#define GENERIC_GLUE_CMD BIT(28) +#define CDNS_XSPI_CMD_FLD_P4_GENERIC_CMD(cs, glue) (\ + FIELD_PREP(GENERIC_BANK_NUM, cs) | FIELD_PREP(GENERIC_GLUE_CMD, glue)) + +#define CDNS_XSPI_CMD_FLD_GENERIC_DSEQ_CMD_1 (\ + FIELD_PREP(CDNS_XSPI_CMD_INSTR_TYPE, CDNS_XSPI_STIG_INSTR_TYPE_DATA_SEQ)) + +#define CDNS_XSPI_CMD_FLD_GENERIC_DSEQ_CMD_2(nbytes) (\ + FIELD_PREP(CDNS_XSPI_CMD_DSEQ_R2_DCNT_L, nbytes & 0xffff)) + +#define CDNS_XSPI_CMD_FLD_GENERIC_DSEQ_CMD_3(nbytes) ( \ + FIELD_PREP(CDNS_XSPI_CMD_DSEQ_R3_DCNT_H, (nbytes >> 16) & 0xffff)) + +#define CDNS_XSPI_CMD_FLD_GENERIC_DSEQ_CMD_4(dir, chipsel) ( \ + FIELD_PREP(CDNS_XSPI_CMD_DSEQ_R4_BANK, chipsel) | \ + FIELD_PREP(CDNS_XSPI_CMD_DSEQ_R4_DIR, dir)) + /* Marvell PHY default values */ #define MARVELL_REGS_DLL_PHY_CTRL 0x00000707 #define MARVELL_CTB_RFILE_PHY_CTRL 0x00004000 @@ -226,6 +255,37 @@ #define MRVL_XSPI_CLOCK_DIVIDED(div) ((MRVL_XSPI_CLOCK_IO_HZ) / (div)) #define MRVL_DEFAULT_CLK 25000000 +/* Marvell overlay registers - xfer */ +#define MRVL_XFER_FUNC_CTRL 0x210 +#define MRVL_XFER_FUNC_CTRL_READ_DATA(i) (0x000 + 8 * (i)) +#define MRVL_XFER_SOFT_RESET BIT(11) +#define MRVL_XFER_CS_N_HOLD GENMASK(9, 6) +#define MRVL_XFER_RECEIVE_ENABLE BIT(4) +#define MRVL_XFER_FUNC_ENABLE BIT(3) +#define MRVL_XFER_CLK_CAPTURE_POL BIT(2) +#define MRVL_XFER_CLK_DRIVE_POL BIT(1) +#define MRVL_XFER_FUNC_START BIT(0) +#define MRVL_XFER_QWORD_COUNT 32 +#define MRVL_XFER_QWORD_BYTECOUNT 8 + +#define MRVL_XSPI_POLL_TIMEOUT_US 1000 +#define MRVL_XSPI_POLL_DELAY_US 10 + +/* Macros for calculating data bits in generic command + * Up to 10 bytes can be fit into cmd_registers + * least significant is placed in cmd_reg[1] + * Other bits are inserted after it in cmd_reg[1,2,3] register + */ +#define GENERIC_CMD_DATA_REG_3_COUNT(len) (len >= 10 ? 2 : len - 8) +#define GENERIC_CMD_DATA_REG_2_COUNT(len) (len >= 7 ? 3 : len - 4) +#define GENERIC_CMD_DATA_REG_1_COUNT(len) (len >= 3 ? 2 : len - 1) +#define GENERIC_CMD_DATA_3_OFFSET(position) (8*(position)) +#define GENERIC_CMD_DATA_2_OFFSET(position) (8*(position)) +#define GENERIC_CMD_DATA_1_OFFSET(position) (8 + 8*(position)) +#define GENERIC_CMD_DATA_INSERT(data, pos) ((data) << (pos)) +#define GENERIC_CMD_REG_3_NEEDED(len) (len > 7) +#define GENERIC_CMD_REG_2_NEEDED(len) (len > 3) + enum cdns_xspi_stig_instr_type { CDNS_XSPI_STIG_INSTR_TYPE_0, CDNS_XSPI_STIG_INSTR_TYPE_1, @@ -294,6 +354,7 @@ struct cdns_xspi_dev { void __iomem *iobase; void __iomem *auxbase; void __iomem *sdmabase; + void __iomem *xferbase; int irq; int cur_cs; @@ -312,6 +373,9 @@ struct cdns_xspi_dev { const struct cdns_xspi_driver_data *driver_data; void (*sdma_handler)(struct cdns_xspi_dev *cdns_xspi); void (*set_interrupts_handler)(struct cdns_xspi_dev *cdns_xspi, bool enabled); + + bool xfer_in_progress; + int current_xfer_qword; }; static void cdns_xspi_reset_dll(struct cdns_xspi_dev *cdns_xspi) @@ -806,6 +870,204 @@ static void cdns_xspi_print_phy_config(struct cdns_xspi_dev *cdns_xspi) readl(cdns_xspi->auxbase + CDNS_XSPI_CCP_PHY_DLL_SLAVE_CTRL)); } +static int cdns_xspi_prepare_generic(int cs, const void *dout, int len, int glue, u32 *cmd_regs) +{ + u8 *data = (u8 *)dout; + int i; + int data_counter = 0; + + memset(cmd_regs, 0x00, CMD_REG_LEN); + + if (GENERIC_CMD_REG_3_NEEDED(len)) { + for (i = GENERIC_CMD_DATA_REG_3_COUNT(len); i >= 0 ; i--) + cmd_regs[3] |= GENERIC_CMD_DATA_INSERT(data[data_counter++], + GENERIC_CMD_DATA_3_OFFSET(i)); + } + if (GENERIC_CMD_REG_2_NEEDED(len)) { + for (i = GENERIC_CMD_DATA_REG_2_COUNT(len); i >= 0; i--) + cmd_regs[2] |= GENERIC_CMD_DATA_INSERT(data[data_counter++], + GENERIC_CMD_DATA_2_OFFSET(i)); + } + for (i = GENERIC_CMD_DATA_REG_1_COUNT(len); i >= 0 ; i--) + cmd_regs[1] |= GENERIC_CMD_DATA_INSERT(data[data_counter++], + GENERIC_CMD_DATA_1_OFFSET(i)); + + cmd_regs[1] |= CDNS_XSPI_CMD_FLD_P1_GENERIC_CMD; + cmd_regs[3] |= CDNS_XSPI_CMD_FLD_P3_GENERIC_CMD(len); + cmd_regs[4] |= CDNS_XSPI_CMD_FLD_P4_GENERIC_CMD(cs, glue); + + return 0; +} + +static void marvell_xspi_read_single_qword(struct cdns_xspi_dev *cdns_xspi, u8 **buffer) +{ + u64 d = readq(cdns_xspi->xferbase + + MRVL_XFER_FUNC_CTRL_READ_DATA(cdns_xspi->current_xfer_qword)); + u8 *ptr = (u8 *)&d; + int k; + + for (k = 0; k < 8; k++) { + u8 val = bitrev8((ptr[k])); + **buffer = val; + *buffer = *buffer + 1; + } + + cdns_xspi->current_xfer_qword++; + cdns_xspi->current_xfer_qword %= MRVL_XFER_QWORD_COUNT; +} + +static void cdns_xspi_finish_read(struct cdns_xspi_dev *cdns_xspi, u8 **buffer, u32 data_count) +{ + u64 d = readq(cdns_xspi->xferbase + + MRVL_XFER_FUNC_CTRL_READ_DATA(cdns_xspi->current_xfer_qword)); + u8 *ptr = (u8 *)&d; + int k; + + for (k = 0; k < data_count % MRVL_XFER_QWORD_BYTECOUNT; k++) { + u8 val = bitrev8((ptr[k])); + **buffer = val; + *buffer = *buffer + 1; + } + + cdns_xspi->current_xfer_qword++; + cdns_xspi->current_xfer_qword %= MRVL_XFER_QWORD_COUNT; +} + +static int cdns_xspi_prepare_transfer(int cs, int dir, int len, u32 *cmd_regs) +{ + memset(cmd_regs, 0x00, CMD_REG_LEN); + + cmd_regs[1] |= CDNS_XSPI_CMD_FLD_GENERIC_DSEQ_CMD_1; + cmd_regs[2] |= CDNS_XSPI_CMD_FLD_GENERIC_DSEQ_CMD_2(len); + cmd_regs[4] |= CDNS_XSPI_CMD_FLD_GENERIC_DSEQ_CMD_4(dir, cs); + + return 0; +} + +static bool cdns_xspi_is_stig_ready(struct cdns_xspi_dev *cdns_xspi, bool sleep) +{ + u32 ctrl_stat; + + return !readl_relaxed_poll_timeout + (cdns_xspi->iobase + CDNS_XSPI_CTRL_STATUS_REG, + ctrl_stat, + ((ctrl_stat & BIT(3)) == 0), + sleep ? MRVL_XSPI_POLL_DELAY_US : 0, + sleep ? MRVL_XSPI_POLL_TIMEOUT_US : 0); +} + +static bool cdns_xspi_is_sdma_ready(struct cdns_xspi_dev *cdns_xspi, bool sleep) +{ + u32 ctrl_stat; + + return !readl_relaxed_poll_timeout + (cdns_xspi->iobase + CDNS_XSPI_INTR_STATUS_REG, + ctrl_stat, + (ctrl_stat & CDNS_XSPI_SDMA_TRIGGER), + sleep ? MRVL_XSPI_POLL_DELAY_US : 0, + sleep ? MRVL_XSPI_POLL_TIMEOUT_US : 0); +} + +static int cdns_xspi_transfer_one_message_b0(struct spi_controller *controller, + struct spi_message *m) +{ + struct cdns_xspi_dev *cdns_xspi = spi_controller_get_devdata(controller); + struct spi_device *spi = m->spi; + struct spi_transfer *t = NULL; + + const unsigned int max_len = MRVL_XFER_QWORD_BYTECOUNT * MRVL_XFER_QWORD_COUNT; + int current_transfer_len; + int cs = spi_get_chipselect(spi, 0); + int cs_change = 0; + + /* Enable xfer state machine */ + if (!cdns_xspi->xfer_in_progress) { + u32 xfer_control = readl(cdns_xspi->xferbase + MRVL_XFER_FUNC_CTRL); + + cdns_xspi->current_xfer_qword = 0; + cdns_xspi->xfer_in_progress = true; + xfer_control |= (MRVL_XFER_RECEIVE_ENABLE | + MRVL_XFER_CLK_CAPTURE_POL | + MRVL_XFER_FUNC_START | + MRVL_XFER_SOFT_RESET | + FIELD_PREP(MRVL_XFER_CS_N_HOLD, (1 << cs))); + xfer_control &= ~(MRVL_XFER_FUNC_ENABLE | MRVL_XFER_CLK_DRIVE_POL); + writel(xfer_control, cdns_xspi->xferbase + MRVL_XFER_FUNC_CTRL); + } + + list_for_each_entry(t, &m->transfers, transfer_list) { + u8 *txd = (u8 *) t->tx_buf; + u8 *rxd = (u8 *) t->rx_buf; + u8 data[10]; + u32 cmd_regs[6]; + + if (!txd) + txd = data; + + cdns_xspi->in_buffer = txd + 1; + cdns_xspi->out_buffer = txd + 1; + + while (t->len) { + + current_transfer_len = min(max_len, t->len); + + if (current_transfer_len < 10) { + cdns_xspi_prepare_generic(cs, txd, current_transfer_len, + false, cmd_regs); + cdns_xspi_trigger_command(cdns_xspi, cmd_regs); + if (!cdns_xspi_is_stig_ready(cdns_xspi, true)) + return -EIO; + } else { + cdns_xspi_prepare_generic(cs, txd, 1, true, cmd_regs); + cdns_xspi_trigger_command(cdns_xspi, cmd_regs); + cdns_xspi_prepare_transfer(cs, 1, current_transfer_len - 1, + cmd_regs); + cdns_xspi_trigger_command(cdns_xspi, cmd_regs); + if (!cdns_xspi_is_sdma_ready(cdns_xspi, true)) + return -EIO; + cdns_xspi->sdma_handler(cdns_xspi); + if (!cdns_xspi_is_stig_ready(cdns_xspi, true)) + return -EIO; + + cdns_xspi->in_buffer += current_transfer_len; + cdns_xspi->out_buffer += current_transfer_len; + } + + if (rxd) { + int j; + + for (j = 0; j < current_transfer_len / 8; j++) + marvell_xspi_read_single_qword(cdns_xspi, &rxd); + cdns_xspi_finish_read(cdns_xspi, &rxd, current_transfer_len); + } else { + cdns_xspi->current_xfer_qword += current_transfer_len / + MRVL_XFER_QWORD_BYTECOUNT; + if (current_transfer_len % MRVL_XFER_QWORD_BYTECOUNT) + cdns_xspi->current_xfer_qword++; + + cdns_xspi->current_xfer_qword %= MRVL_XFER_QWORD_COUNT; + } + cs_change = t->cs_change; + t->len -= current_transfer_len; + } + spi_transfer_delay_exec(t); + } + + if (!cs_change) { + u32 xfer_control = readl(cdns_xspi->xferbase + MRVL_XFER_FUNC_CTRL); + + xfer_control &= ~(MRVL_XFER_RECEIVE_ENABLE | + MRVL_XFER_SOFT_RESET); + writel(xfer_control, cdns_xspi->xferbase + MRVL_XFER_FUNC_CTRL); + cdns_xspi->xfer_in_progress = false; + } + + m->status = 0; + spi_finalize_current_message(controller); + + return 0; +} + static int cdns_xspi_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -829,6 +1091,7 @@ static int cdns_xspi_probe(struct platform_device *pdev) if (cdns_xspi->driver_data->mrvl_hw_overlay) { host->mem_ops = &marvell_xspi_mem_ops; + host->transfer_one_message = cdns_xspi_transfer_one_message_b0; cdns_xspi->sdma_handler = &marvell_xspi_sdma_handle; cdns_xspi->set_interrupts_handler = &marvell_xspi_set_interrupts; } else { @@ -871,6 +1134,15 @@ static int cdns_xspi_probe(struct platform_device *pdev) return PTR_ERR(cdns_xspi->auxbase); } + if (cdns_xspi->driver_data->mrvl_hw_overlay) { + cdns_xspi->xferbase = devm_platform_ioremap_resource_byname(pdev, "xfer"); + if (IS_ERR(cdns_xspi->xferbase)) { + dev_info(dev, "XFER register base not found, set it\n"); + // For compatibility with older firmware + cdns_xspi->xferbase = cdns_xspi->iobase + 0x8000; + } + } + cdns_xspi->irq = platform_get_irq(pdev, 0); if (cdns_xspi->irq < 0) return -ENXIO; From 4b8cb7dcd8acd7a05354f0b458aca02e4497f2a6 Mon Sep 17 00:00:00 2001 From: Witold Sadowski Date: Wed, 24 Jul 2024 08:47:37 -0700 Subject: [PATCH 07/65] spi: cadence: Change resource mapping If mapping resource by name will fail try to map resource by number. Such situation can occur in ACPI case. Signed-off-by: Witold Sadowski Signed-off-by: Piyush Malgujar Link: https://patch.msgid.link/20240724154739.582367-8-wsadowski@marvell.com Signed-off-by: Mark Brown --- drivers/spi/spi-cadence-xspi.c | 31 ++++++++++++++++++++++--------- 1 file changed, 22 insertions(+), 9 deletions(-) diff --git a/drivers/spi/spi-cadence-xspi.c b/drivers/spi/spi-cadence-xspi.c index 69c08bae7628..a129f33bfd38 100644 --- a/drivers/spi/spi-cadence-xspi.c +++ b/drivers/spi/spi-cadence-xspi.c @@ -1118,28 +1118,41 @@ static int cdns_xspi_probe(struct platform_device *pdev) cdns_xspi->iobase = devm_platform_ioremap_resource_byname(pdev, "io"); if (IS_ERR(cdns_xspi->iobase)) { - dev_err(dev, "Failed to remap controller base address\n"); - return PTR_ERR(cdns_xspi->iobase); + cdns_xspi->iobase = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(cdns_xspi->iobase)) { + dev_err(dev, "Failed to remap controller base address\n"); + return PTR_ERR(cdns_xspi->iobase); + } } res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "sdma"); cdns_xspi->sdmabase = devm_ioremap_resource(dev, res); - if (IS_ERR(cdns_xspi->sdmabase)) - return PTR_ERR(cdns_xspi->sdmabase); + if (IS_ERR(cdns_xspi->sdmabase)) { + res = platform_get_resource(pdev, IORESOURCE_MEM, 1); + cdns_xspi->sdmabase = devm_ioremap_resource(dev, res); + if (IS_ERR(cdns_xspi->sdmabase)) + return PTR_ERR(cdns_xspi->sdmabase); + } cdns_xspi->sdmasize = resource_size(res); cdns_xspi->auxbase = devm_platform_ioremap_resource_byname(pdev, "aux"); if (IS_ERR(cdns_xspi->auxbase)) { - dev_err(dev, "Failed to remap AUX address\n"); - return PTR_ERR(cdns_xspi->auxbase); + cdns_xspi->auxbase = devm_platform_ioremap_resource(pdev, 2); + if (IS_ERR(cdns_xspi->auxbase)) { + dev_err(dev, "Failed to remap AUX address\n"); + return PTR_ERR(cdns_xspi->auxbase); + } } if (cdns_xspi->driver_data->mrvl_hw_overlay) { cdns_xspi->xferbase = devm_platform_ioremap_resource_byname(pdev, "xfer"); if (IS_ERR(cdns_xspi->xferbase)) { - dev_info(dev, "XFER register base not found, set it\n"); - // For compatibility with older firmware - cdns_xspi->xferbase = cdns_xspi->iobase + 0x8000; + cdns_xspi->xferbase = devm_platform_ioremap_resource(pdev, 3); + if (IS_ERR(cdns_xspi->xferbase)) { + dev_info(dev, "XFER register base not found, set it\n"); + // For compatibility with older firmware + cdns_xspi->xferbase = cdns_xspi->iobase + 0x8000; + } } } From 8232f1e2584ac1eadd3282b035c306ebde87d8b4 Mon Sep 17 00:00:00 2001 From: Witold Sadowski Date: Wed, 24 Jul 2024 08:47:38 -0700 Subject: [PATCH 08/65] spi: cadence: Change cs property reading. In current implementation cs property can be read only from device-tree(for_each_available_child_of_node_scoped). Change it to fwnode based read to allow property reading in ACPI case too. Signed-off-by: Witold Sadowski Signed-off-by: Piyush Malgujar Link: https://patch.msgid.link/20240724154739.582367-9-wsadowski@marvell.com Signed-off-by: Mark Brown --- drivers/spi/spi-cadence-xspi.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/drivers/spi/spi-cadence-xspi.c b/drivers/spi/spi-cadence-xspi.c index a129f33bfd38..28c1aea01743 100644 --- a/drivers/spi/spi-cadence-xspi.c +++ b/drivers/spi/spi-cadence-xspi.c @@ -837,15 +837,20 @@ static irqreturn_t cdns_xspi_irq_handler(int this_irq, void *dev) static int cdns_xspi_of_get_plat_data(struct platform_device *pdev) { - struct device_node *node_prop = pdev->dev.of_node; + struct fwnode_handle *fwnode_child; unsigned int cs; - for_each_available_child_of_node_scoped(node_prop, node_child) { - if (of_property_read_u32(node_child, "reg", &cs)) { + device_for_each_child_node(&pdev->dev, fwnode_child) { + if (!fwnode_device_is_available(fwnode_child)) + continue; + + if (fwnode_property_read_u32(fwnode_child, "reg", &cs)) { dev_err(&pdev->dev, "Couldn't get memory chip select\n"); + fwnode_handle_put(fwnode_child); return -ENXIO; } else if (cs >= CDNS_XSPI_MAX_BANKS) { dev_err(&pdev->dev, "reg (cs) parameter value too large\n"); + fwnode_handle_put(fwnode_child); return -ENXIO; } } From 9cabf4a487cd4035844b4928881a314334f348fe Mon Sep 17 00:00:00 2001 From: Witold Sadowski Date: Wed, 24 Jul 2024 08:47:39 -0700 Subject: [PATCH 09/65] spi: cadence: Try to read spi-tx/rx-bus width property using ACPI Try to read bus width property using acpi_dev_get_property function, do not rely on spi_mem_default_supports_op function only. If of_device_get_match_data() will fail, retry with acpi_device_get_match_data() to handle ACPI properly. Signed-off-by: Witold Sadowski Signed-off-by: Piyush Malgujar Link: https://patch.msgid.link/20240724154739.582367-10-wsadowski@marvell.com Signed-off-by: Mark Brown --- drivers/spi/spi-cadence-xspi.c | 74 +++++++++++++++++++++++++++++++++- 1 file changed, 72 insertions(+), 2 deletions(-) diff --git a/drivers/spi/spi-cadence-xspi.c b/drivers/spi/spi-cadence-xspi.c index 28c1aea01743..695a9bc1969a 100644 --- a/drivers/spi/spi-cadence-xspi.c +++ b/drivers/spi/spi-cadence-xspi.c @@ -2,6 +2,7 @@ // Cadence XSPI flash controller driver // Copyright (C) 2020-21 Cadence +#include #include #include #include @@ -773,6 +774,66 @@ static int marvell_xspi_mem_op_execute(struct spi_mem *mem, return ret; } +#ifdef CONFIG_ACPI +static bool cdns_xspi_supports_op(struct spi_mem *mem, + const struct spi_mem_op *op) +{ + struct spi_device *spi = mem->spi; + const union acpi_object *obj; + struct acpi_device *adev; + + adev = ACPI_COMPANION(&spi->dev); + + if (!acpi_dev_get_property(adev, "spi-tx-bus-width", ACPI_TYPE_INTEGER, + &obj)) { + switch (obj->integer.value) { + case 1: + break; + case 2: + spi->mode |= SPI_TX_DUAL; + break; + case 4: + spi->mode |= SPI_TX_QUAD; + break; + case 8: + spi->mode |= SPI_TX_OCTAL; + break; + default: + dev_warn(&spi->dev, + "spi-tx-bus-width %lld not supported\n", + obj->integer.value); + break; + } + } + + if (!acpi_dev_get_property(adev, "spi-rx-bus-width", ACPI_TYPE_INTEGER, + &obj)) { + switch (obj->integer.value) { + case 1: + break; + case 2: + spi->mode |= SPI_RX_DUAL; + break; + case 4: + spi->mode |= SPI_RX_QUAD; + break; + case 8: + spi->mode |= SPI_RX_OCTAL; + break; + default: + dev_warn(&spi->dev, + "spi-rx-bus-width %lld not supported\n", + obj->integer.value); + break; + } + } + + if (!spi_mem_default_supports_op(mem, op)) + return false; + + return true; +} +#endif static int cdns_xspi_adjust_mem_op_size(struct spi_mem *mem, struct spi_mem_op *op) { @@ -785,11 +846,17 @@ static int cdns_xspi_adjust_mem_op_size(struct spi_mem *mem, struct spi_mem_op * } static const struct spi_controller_mem_ops cadence_xspi_mem_ops = { +#ifdef CONFIG_ACPI + .supports_op = cdns_xspi_supports_op, +#endif .exec_op = cdns_xspi_mem_op_execute, .adjust_op_size = cdns_xspi_adjust_mem_op_size, }; static const struct spi_controller_mem_ops marvell_xspi_mem_ops = { +#ifdef CONFIG_ACPI + .supports_op = cdns_xspi_supports_op, +#endif .exec_op = marvell_xspi_mem_op_execute, .adjust_op_size = cdns_xspi_adjust_mem_op_size, }; @@ -1091,8 +1158,11 @@ static int cdns_xspi_probe(struct platform_device *pdev) cdns_xspi = spi_controller_get_devdata(host); cdns_xspi->driver_data = of_device_get_match_data(dev); - if (!cdns_xspi->driver_data) - return -ENODEV; + if (!cdns_xspi->driver_data) { + cdns_xspi->driver_data = acpi_device_get_match_data(dev); + if (!cdns_xspi->driver_data) + return -ENODEV; + } if (cdns_xspi->driver_data->mrvl_hw_overlay) { host->mem_ops = &marvell_xspi_mem_ops; From f58872f45c36ded048bccc22701b0986019c24d8 Mon Sep 17 00:00:00 2001 From: Marcelo Schmitt Date: Fri, 12 Jul 2024 16:20:36 -0300 Subject: [PATCH 10/65] spi: Enable controllers to extend the SPI protocol with MOSI idle configuration The behavior of an SPI controller data output line (SDO or MOSI or COPI (Controller Output Peripheral Input) for disambiguation) is usually not specified when the controller is not clocking out data on SCLK edges. However, there do exist SPI peripherals that require specific MOSI line state when data is not being clocked out of the controller. Conventional SPI controllers may set the MOSI line on SCLK edges then bring it low when no data is going out or leave the line the state of the last transfer bit. More elaborated controllers are capable to set the MOSI idle state according to different configurable levels and thus are more suitable for interfacing with demanding peripherals. Add SPI mode bits to allow peripherals to request explicit MOSI idle state when needed. When supporting a particular MOSI idle configuration, the data output line state is expected to remain at the configured level when the controller is not clocking out data. When a device that needs a specific MOSI idle state is identified, its driver should request the MOSI idle configuration by setting the proper SPI mode bit. Acked-by: Nuno Sa Reviewed-by: Jonathan Cameron Reviewed-by: David Lechner Tested-by: David Lechner Signed-off-by: Marcelo Schmitt Link: https://patch.msgid.link/9802160b5e5baed7f83ee43ac819cb757a19be55.1720810545.git.marcelo.schmitt@analog.com Signed-off-by: Mark Brown --- Documentation/spi/spi-summary.rst | 83 +++++++++++++++++++++++++++++++ drivers/spi/spi.c | 6 +++ include/uapi/linux/spi/spi.h | 5 +- 3 files changed, 92 insertions(+), 2 deletions(-) diff --git a/Documentation/spi/spi-summary.rst b/Documentation/spi/spi-summary.rst index 7f8accfae6f9..6e21e6f86912 100644 --- a/Documentation/spi/spi-summary.rst +++ b/Documentation/spi/spi-summary.rst @@ -614,6 +614,89 @@ queue, and then start some asynchronous transfer engine (unless it's already running). +Extensions to the SPI protocol +------------------------------ +The fact that SPI doesn't have a formal specification or standard permits chip +manufacturers to implement the SPI protocol in slightly different ways. In most +cases, SPI protocol implementations from different vendors are compatible among +each other. For example, in SPI mode 0 (CPOL=0, CPHA=0) the bus lines may behave +like the following: + +:: + + nCSx ___ ___ + \_________________________________________________________________/ + • • + • • + SCLK ___ ___ ___ ___ ___ ___ ___ ___ + _______/ \___/ \___/ \___/ \___/ \___/ \___/ \___/ \_____ + • : ; : ; : ; : ; : ; : ; : ; : ; • + • : ; : ; : ; : ; : ; : ; : ; : ; • + MOSI XXX__________ _______ _______ ________XXX + 0xA5 XXX__/ 1 \_0_____/ 1 \_0_______0_____/ 1 \_0_____/ 1 \_XXX + • ; ; ; ; ; ; ; ; • + • ; ; ; ; ; ; ; ; • + MISO XXX__________ _______________________ _______ XXX + 0xBA XXX__/ 1 \_____0_/ 1 1 1 \_____0__/ 1 \____0__XXX + +Legend:: + + • marks the start/end of transmission; + : marks when data is clocked into the peripheral; + ; marks when data is clocked into the controller; + X marks when line states are not specified. + +In some few cases, chips extend the SPI protocol by specifying line behaviors +that other SPI protocols don't (e.g. data line state for when CS is not +asserted). Those distinct SPI protocols, modes, and configurations are supported +by different SPI mode flags. + +MOSI idle state configuration +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Common SPI protocol implementations don't specify any state or behavior for the +MOSI line when the controller is not clocking out data. However, there do exist +peripherals that require specific MOSI line state when data is not being clocked +out. For example, if the peripheral expects the MOSI line to be high when the +controller is not clocking out data (``SPI_MOSI_IDLE_HIGH``), then a transfer in +SPI mode 0 would look like the following: + +:: + + nCSx ___ ___ + \_________________________________________________________________/ + • • + • • + SCLK ___ ___ ___ ___ ___ ___ ___ ___ + _______/ \___/ \___/ \___/ \___/ \___/ \___/ \___/ \_____ + • : ; : ; : ; : ; : ; : ; : ; : ; • + • : ; : ; : ; : ; : ; : ; : ; : ; • + MOSI _____ _______ _______ _______________ ___ + 0x56 \_0_____/ 1 \_0_____/ 1 \_0_____/ 1 1 \_0_____/ + • ; ; ; ; ; ; ; ; • + • ; ; ; ; ; ; ; ; • + MISO XXX__________ _______________________ _______ XXX + 0xBA XXX__/ 1 \_____0_/ 1 1 1 \_____0__/ 1 \____0__XXX + +Legend:: + + • marks the start/end of transmission; + : marks when data is clocked into the peripheral; + ; marks when data is clocked into the controller; + X marks when line states are not specified. + +In this extension to the usual SPI protocol, the MOSI line state is specified to +be kept high when CS is asserted but the controller is not clocking out data to +the peripheral and also when CS is not asserted. + +Peripherals that require this extension must request it by setting the +``SPI_MOSI_IDLE_HIGH`` bit into the mode attribute of their ``struct +spi_device`` and call spi_setup(). Controllers that support this extension +should indicate it by setting ``SPI_MOSI_IDLE_HIGH`` in the mode_bits attribute +of their ``struct spi_controller``. The configuration to idle MOSI low is +analogous but uses the ``SPI_MOSI_IDLE_LOW`` mode bit. + + THANKS TO --------- Contributors to Linux-SPI discussions include (in alphabetical order, diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index 6ebe5dd9bbb1..60a2b5a0c85d 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -3921,6 +3921,12 @@ int spi_setup(struct spi_device *spi) (SPI_TX_DUAL | SPI_TX_QUAD | SPI_TX_OCTAL | SPI_RX_DUAL | SPI_RX_QUAD | SPI_RX_OCTAL))) return -EINVAL; + /* Check against conflicting MOSI idle configuration */ + if ((spi->mode & SPI_MOSI_IDLE_LOW) && (spi->mode & SPI_MOSI_IDLE_HIGH)) { + dev_err(&spi->dev, + "setup: MOSI configured to idle low and high at the same time.\n"); + return -EINVAL; + } /* * Help drivers fail *cleanly* when they need options * that aren't supported with their current controller. diff --git a/include/uapi/linux/spi/spi.h b/include/uapi/linux/spi/spi.h index ca56e477d161..ee4ac812b8f8 100644 --- a/include/uapi/linux/spi/spi.h +++ b/include/uapi/linux/spi/spi.h @@ -28,7 +28,8 @@ #define SPI_RX_OCTAL _BITUL(14) /* receive with 8 wires */ #define SPI_3WIRE_HIZ _BITUL(15) /* high impedance turnaround */ #define SPI_RX_CPHA_FLIP _BITUL(16) /* flip CPHA on Rx only xfer */ -#define SPI_MOSI_IDLE_LOW _BITUL(17) /* leave mosi line low when idle */ +#define SPI_MOSI_IDLE_LOW _BITUL(17) /* leave MOSI line low when idle */ +#define SPI_MOSI_IDLE_HIGH _BITUL(18) /* leave MOSI line high when idle */ /* * All the bits defined above should be covered by SPI_MODE_USER_MASK. @@ -38,6 +39,6 @@ * These bits must not overlap. A static assert check should make sure of that. * If adding extra bits, make sure to increase the bit index below as well. */ -#define SPI_MODE_USER_MASK (_BITUL(18) - 1) +#define SPI_MODE_USER_MASK (_BITUL(19) - 1) #endif /* _UAPI_SPI_H */ From 320f6693097bf89d67f9cabad24a2b911e23073f Mon Sep 17 00:00:00 2001 From: Marcelo Schmitt Date: Fri, 12 Jul 2024 16:21:03 -0300 Subject: [PATCH 11/65] spi: bitbang: Implement support for MOSI idle state configuration Some SPI peripherals may require strict MOSI line state when the controller is not clocking out data. Implement support for MOSI idle state configuration (low or high) by setting the data output line level on controller setup and after transfers. Bitbang operations now call controller specific set_mosi_idle() callback to set MOSI to its idle state. The MOSI line is kept at its idle state if no tx buffer is provided. Acked-by: Nuno Sa Reviewed-by: David Lechner Reviewed-by: Jonathan Cameron Signed-off-by: Marcelo Schmitt Link: https://patch.msgid.link/de61a600b56ed9cb714d5ea87afa88948e70041e.1720810545.git.marcelo.schmitt@analog.com Signed-off-by: Mark Brown --- drivers/spi/spi-bitbang.c | 24 ++++++++++++++++++++++++ include/linux/spi/spi_bitbang.h | 1 + 2 files changed, 25 insertions(+) diff --git a/drivers/spi/spi-bitbang.c b/drivers/spi/spi-bitbang.c index afb1b1105ec2..ebe18f0b5d23 100644 --- a/drivers/spi/spi-bitbang.c +++ b/drivers/spi/spi-bitbang.c @@ -54,21 +54,28 @@ static unsigned int bitbang_txrx_8(struct spi_device *spi, struct spi_transfer *t, unsigned int flags) { + struct spi_bitbang *bitbang; unsigned int bits = t->bits_per_word; unsigned int count = t->len; const u8 *tx = t->tx_buf; u8 *rx = t->rx_buf; + bitbang = spi_controller_get_devdata(spi->controller); while (likely(count > 0)) { u8 word = 0; if (tx) word = *tx++; + else + word = spi->mode & SPI_MOSI_IDLE_HIGH ? 0xFF : 0; word = txrx_word(spi, ns, word, bits, flags); if (rx) *rx++ = word; count -= 1; } + if (bitbang->set_mosi_idle) + bitbang->set_mosi_idle(spi); + return t->len - count; } @@ -78,21 +85,28 @@ static unsigned int bitbang_txrx_16(struct spi_device *spi, struct spi_transfer *t, unsigned int flags) { + struct spi_bitbang *bitbang; unsigned int bits = t->bits_per_word; unsigned int count = t->len; const u16 *tx = t->tx_buf; u16 *rx = t->rx_buf; + bitbang = spi_controller_get_devdata(spi->controller); while (likely(count > 1)) { u16 word = 0; if (tx) word = *tx++; + else + word = spi->mode & SPI_MOSI_IDLE_HIGH ? 0xFFFF : 0; word = txrx_word(spi, ns, word, bits, flags); if (rx) *rx++ = word; count -= 2; } + if (bitbang->set_mosi_idle) + bitbang->set_mosi_idle(spi); + return t->len - count; } @@ -102,21 +116,28 @@ static unsigned int bitbang_txrx_32(struct spi_device *spi, struct spi_transfer *t, unsigned int flags) { + struct spi_bitbang *bitbang; unsigned int bits = t->bits_per_word; unsigned int count = t->len; const u32 *tx = t->tx_buf; u32 *rx = t->rx_buf; + bitbang = spi_controller_get_devdata(spi->controller); while (likely(count > 3)) { u32 word = 0; if (tx) word = *tx++; + else + word = spi->mode & SPI_MOSI_IDLE_HIGH ? 0xFFFFFFFF : 0; word = txrx_word(spi, ns, word, bits, flags); if (rx) *rx++ = word; count -= 4; } + if (bitbang->set_mosi_idle) + bitbang->set_mosi_idle(spi); + return t->len - count; } @@ -192,6 +213,9 @@ int spi_bitbang_setup(struct spi_device *spi) goto err_free; } + if (bitbang->set_mosi_idle) + bitbang->set_mosi_idle(spi); + dev_dbg(&spi->dev, "%s, %u nsec/bit\n", __func__, 2 * cs->nsecs); return 0; diff --git a/include/linux/spi/spi_bitbang.h b/include/linux/spi/spi_bitbang.h index d4cb83195f7a..c92cd43a47f4 100644 --- a/include/linux/spi/spi_bitbang.h +++ b/include/linux/spi/spi_bitbang.h @@ -24,6 +24,7 @@ struct spi_bitbang { #define BITBANG_CS_ACTIVE 1 /* normally nCS, active low */ #define BITBANG_CS_INACTIVE 0 + void (*set_mosi_idle)(struct spi_device *spi); /* txrx_bufs() may handle dma mapping for transfers that don't * already have one (transfer.{tx,rx}_dma is zero), or use PIO */ From 927d382c7efbcc2206c31fa2f672fa264c0f1d5b Mon Sep 17 00:00:00 2001 From: Marcelo Schmitt Date: Fri, 12 Jul 2024 16:21:23 -0300 Subject: [PATCH 12/65] spi: spi-gpio: Add support for MOSI idle state configuration Implement MOSI idle low and MOSI idle high to better support peripherals that request specific MOSI behavior. Acked-by: Nuno Sa Reviewed-by: David Lechner Reviewed-by: Jonathan Cameron Signed-off-by: Marcelo Schmitt Link: https://patch.msgid.link/629c55a10005ba26825c3a6a19184372ef81b3e1.1720810545.git.marcelo.schmitt@analog.com Signed-off-by: Mark Brown --- drivers/spi/spi-gpio.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/drivers/spi/spi-gpio.c b/drivers/spi/spi-gpio.c index 36c587be9e28..4f192e013cd6 100644 --- a/drivers/spi/spi-gpio.c +++ b/drivers/spi/spi-gpio.c @@ -236,6 +236,14 @@ static void spi_gpio_chipselect(struct spi_device *spi, int is_active) } } +static void spi_gpio_set_mosi_idle(struct spi_device *spi) +{ + struct spi_gpio *spi_gpio = spi_to_spi_gpio(spi); + + gpiod_set_value_cansleep(spi_gpio->mosi, + !!(spi->mode & SPI_MOSI_IDLE_HIGH)); +} + static int spi_gpio_setup(struct spi_device *spi) { struct gpio_desc *cs; @@ -389,7 +397,8 @@ static int spi_gpio_probe(struct platform_device *pdev) host->bits_per_word_mask = SPI_BPW_RANGE_MASK(1, 32); host->mode_bits = SPI_3WIRE | SPI_3WIRE_HIZ | SPI_CPHA | SPI_CPOL | - SPI_CS_HIGH | SPI_LSB_FIRST; + SPI_CS_HIGH | SPI_LSB_FIRST | SPI_MOSI_IDLE_LOW | + SPI_MOSI_IDLE_HIGH; if (!spi_gpio->mosi) { /* HW configuration without MOSI pin * @@ -414,6 +423,7 @@ static int spi_gpio_probe(struct platform_device *pdev) host->flags |= SPI_CONTROLLER_GPIO_SS; bb->chipselect = spi_gpio_chipselect; bb->set_line_direction = spi_gpio_set_direction; + bb->set_mosi_idle = spi_gpio_set_mosi_idle; if (host->flags & SPI_CONTROLLER_NO_TX) { bb->txrx_word[SPI_MODE_0] = spi_gpio_spec_txrx_word_mode0; From a62073f4b2164028fc7c5ae45ceba10c9326cd91 Mon Sep 17 00:00:00 2001 From: Marcelo Schmitt Date: Fri, 12 Jul 2024 16:21:47 -0300 Subject: [PATCH 13/65] spi: spi-axi-spi-engine: Add support for MOSI idle configuration Implement MOSI idle low and MOSI idle high to better support peripherals that request specific MOSI behavior. Acked-by: Nuno Sa Reviewed-by: David Lechner Signed-off-by: Marcelo Schmitt Link: https://patch.msgid.link/f237166c7bbe0a1cdabce243b97484bf2f428143.1720810545.git.marcelo.schmitt@analog.com Signed-off-by: Mark Brown --- drivers/spi/spi-axi-spi-engine.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/drivers/spi/spi-axi-spi-engine.c b/drivers/spi/spi-axi-spi-engine.c index 447e5a962dee..8ad86f53ca50 100644 --- a/drivers/spi/spi-axi-spi-engine.c +++ b/drivers/spi/spi-axi-spi-engine.c @@ -41,6 +41,7 @@ #define SPI_ENGINE_CONFIG_CPHA BIT(0) #define SPI_ENGINE_CONFIG_CPOL BIT(1) #define SPI_ENGINE_CONFIG_3WIRE BIT(2) +#define SPI_ENGINE_CONFIG_SDO_IDLE_HIGH BIT(3) #define SPI_ENGINE_INST_TRANSFER 0x0 #define SPI_ENGINE_INST_ASSERT 0x1 @@ -137,6 +138,10 @@ static unsigned int spi_engine_get_config(struct spi_device *spi) config |= SPI_ENGINE_CONFIG_CPHA; if (spi->mode & SPI_3WIRE) config |= SPI_ENGINE_CONFIG_3WIRE; + if (spi->mode & SPI_MOSI_IDLE_HIGH) + config |= SPI_ENGINE_CONFIG_SDO_IDLE_HIGH; + if (spi->mode & SPI_MOSI_IDLE_LOW) + config &= ~SPI_ENGINE_CONFIG_SDO_IDLE_HIGH; return config; } @@ -692,9 +697,13 @@ static int spi_engine_probe(struct platform_device *pdev) host->num_chipselect = 8; /* Some features depend of the IP core version. */ - if (ADI_AXI_PCORE_VER_MINOR(version) >= 2) { - host->mode_bits |= SPI_CS_HIGH; - host->setup = spi_engine_setup; + if (ADI_AXI_PCORE_VER_MAJOR(version) >= 1) { + if (ADI_AXI_PCORE_VER_MINOR(version) >= 2) { + host->mode_bits |= SPI_CS_HIGH; + host->setup = spi_engine_setup; + } + if (ADI_AXI_PCORE_VER_MINOR(version) >= 3) + host->mode_bits |= SPI_MOSI_IDLE_LOW | SPI_MOSI_IDLE_HIGH; } if (host->max_speed_hz == 0) From 96472f18a4affdaff5013a836c48375f1eddb4a4 Mon Sep 17 00:00:00 2001 From: Marcelo Schmitt Date: Fri, 12 Jul 2024 16:22:00 -0300 Subject: [PATCH 14/65] dt-bindings: iio: adc: Add AD4000 Add device tree documentation for AD4000 series of ADC devices. Reviewed-by: Conor Dooley Signed-off-by: Marcelo Schmitt Reviewed-by: David Lechner Link: https://patch.msgid.link/98c82e0a2a868a1578989fe69527347aa92083d7.1720810545.git.marcelo.schmitt@analog.com Signed-off-by: Mark Brown --- .../bindings/iio/adc/adi,ad4000.yaml | 197 ++++++++++++++++++ MAINTAINERS | 7 + 2 files changed, 204 insertions(+) create mode 100644 Documentation/devicetree/bindings/iio/adc/adi,ad4000.yaml diff --git a/Documentation/devicetree/bindings/iio/adc/adi,ad4000.yaml b/Documentation/devicetree/bindings/iio/adc/adi,ad4000.yaml new file mode 100644 index 000000000000..e413a9d8d2a2 --- /dev/null +++ b/Documentation/devicetree/bindings/iio/adc/adi,ad4000.yaml @@ -0,0 +1,197 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/iio/adc/adi,ad4000.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Analog Devices AD4000 and similar Analog to Digital Converters + +maintainers: + - Marcelo Schmitt + +description: | + Analog Devices AD4000 family of Analog to Digital Converters with SPI support. + Specifications can be found at: + https://www.analog.com/media/en/technical-documentation/data-sheets/ad4000-4004-4008.pdf + https://www.analog.com/media/en/technical-documentation/data-sheets/ad4001-4005.pdf + https://www.analog.com/media/en/technical-documentation/data-sheets/ad4002-4006-4010.pdf + https://www.analog.com/media/en/technical-documentation/data-sheets/ad4003-4007-4011.pdf + https://www.analog.com/media/en/technical-documentation/data-sheets/ad4020-4021-4022.pdf + https://www.analog.com/media/en/technical-documentation/data-sheets/adaq4001.pdf + https://www.analog.com/media/en/technical-documentation/data-sheets/adaq4003.pdf + +$ref: /schemas/spi/spi-peripheral-props.yaml# + +properties: + compatible: + oneOf: + - const: adi,ad4000 + - items: + - enum: + - adi,ad4004 + - adi,ad4008 + - const: adi,ad4000 + + - const: adi,ad4001 + - items: + - enum: + - adi,ad4005 + - const: adi,ad4001 + + - const: adi,ad4002 + - items: + - enum: + - adi,ad4006 + - adi,ad4010 + - const: adi,ad4002 + + - const: adi,ad4003 + - items: + - enum: + - adi,ad4007 + - adi,ad4011 + - const: adi,ad4003 + + - const: adi,ad4020 + - items: + - enum: + - adi,ad4021 + - adi,ad4022 + - const: adi,ad4020 + + - const: adi,adaq4001 + + - const: adi,adaq4003 + + reg: + maxItems: 1 + + spi-max-frequency: + maximum: 102040816 # for VIO > 2.7 V, 81300813 for VIO > 1.7 V + + adi,sdi-pin: + $ref: /schemas/types.yaml#/definitions/string + enum: [ high, low, cs, sdi ] + default: sdi + description: + Describes how the ADC SDI pin is wired. A value of "sdi" indicates that + the ADC SDI is connected to host SDO. "high" indicates that the ADC SDI + pin is hard-wired to logic high (VIO). "low" indicates that it is + hard-wired low (GND). "cs" indicates that the ADC SDI pin is connected to + the host CS line. + + '#daisy-chained-devices': true + + vdd-supply: + description: A 1.8V supply that powers the chip (VDD). + + vio-supply: + description: + A 1.8V to 5.5V supply for the digital inputs and outputs (VIO). + + ref-supply: + description: + A 2.5 to 5V supply for the external reference voltage (REF). + + cnv-gpios: + description: + When provided, this property indicates the GPIO that is connected to the + CNV pin. + maxItems: 1 + + adi,high-z-input: + type: boolean + description: + High-Z mode allows the amplifier and RC filter in front of the ADC to be + chosen based on the signal bandwidth of interest, rather than the settling + requirements of the switched capacitor SAR ADC inputs. + + adi,gain-milli: + description: | + The hardware gain applied to the ADC input (in milli units). + The gain provided by the ADC input scaler is defined by the hardware + connections between chip pins OUT+, R1K-, R1K1-, R1K+, R1K1+, and OUT-. + If not present, default to 1000 (no actual gain applied). + $ref: /schemas/types.yaml#/definitions/uint16 + enum: [454, 909, 1000, 1900] + default: 1000 + + interrupts: + description: + The SDO pin can also function as a busy indicator. This node should be + connected to an interrupt that is triggered when the SDO line goes low + while the SDI line is high and the CNV line is low ("3-wire" mode) or the + SDI line is low and the CNV line is high ("4-wire" mode); or when the SDO + line goes high while the SDI and CNV lines are high (chain mode), + maxItems: 1 + +required: + - compatible + - reg + - vdd-supply + - vio-supply + - ref-supply + +allOf: + # The configuration register can only be accessed if SDI is connected to MOSI + - if: + required: + - adi,sdi-pin + then: + properties: + adi,high-z-input: false + # chain mode has lower SCLK max rate + - if: + required: + - '#daisy-chained-devices' + then: + properties: + spi-max-frequency: + maximum: 50000000 # for VIO > 2.7 V, 40000000 for VIO > 1.7 V + # Gain property only applies to ADAQ devices + - if: + properties: + compatible: + not: + contains: + enum: + - adi,adaq4001 + - adi,adaq4003 + then: + properties: + adi,gain-milli: false + +unevaluatedProperties: false + +examples: + - | + #include + spi { + #address-cells = <1>; + #size-cells = <0>; + adc@0 { + compatible = "adi,ad4020"; + reg = <0>; + spi-max-frequency = <71000000>; + vdd-supply = <&supply_1_8V>; + vio-supply = <&supply_1_8V>; + ref-supply = <&supply_5V>; + adi,sdi-pin = "cs"; + cnv-gpios = <&gpio0 88 GPIO_ACTIVE_HIGH>; + }; + }; + - | + spi { + #address-cells = <1>; + #size-cells = <0>; + adc@0 { + compatible = "adi,adaq4003"; + reg = <0>; + spi-max-frequency = <80000000>; + vdd-supply = <&supply_1_8V>; + vio-supply = <&supply_1_8V>; + ref-supply = <&supply_5V>; + adi,high-z-input; + adi,gain-milli = /bits/ 16 <454>; + }; + }; diff --git a/MAINTAINERS b/MAINTAINERS index 42decde38320..bc5d242deb29 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1202,6 +1202,13 @@ W: https://ez.analog.com/linux-software-drivers F: Documentation/devicetree/bindings/iio/dac/adi,ad3552r.yaml F: drivers/iio/dac/ad3552r.c +ANALOG DEVICES INC AD4000 DRIVER +M: Marcelo Schmitt +L: linux-iio@vger.kernel.org +S: Supported +W: https://ez.analog.com/linux-software-drivers +F: Documentation/devicetree/bindings/iio/adc/adi,ad4000.yaml + ANALOG DEVICES INC AD4130 DRIVER M: Cosmin Tanislav L: linux-iio@vger.kernel.org From f8918ef1267edab4d9b2154c22a912c87cc66f66 Mon Sep 17 00:00:00 2001 From: David Lechner Date: Tue, 23 Jul 2024 13:36:47 -0500 Subject: [PATCH 15/65] spi: axi-spi-engine: don't emit XFER_BITS for empty xfer This adds a check on xfer->len to avoid emitting an XFER_BITS instruction for empty transfers in the AXI SPI Engine driver. This avoids unnecessary delays caused by executing an instruction that has no effect on the actual SPI transfer. Signed-off-by: David Lechner Reviewed-by: Nuno Sa Link: https://patch.msgid.link/20240723-spi-axi-spi-engine-opt-bpw-v1-1-2625ba4c4387@baylibre.com Signed-off-by: Mark Brown --- drivers/spi/spi-axi-spi-engine.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/spi/spi-axi-spi-engine.c b/drivers/spi/spi-axi-spi-engine.c index 447e5a962dee..cb3fdcbca2be 100644 --- a/drivers/spi/spi-axi-spi-engine.c +++ b/drivers/spi/spi-axi-spi-engine.c @@ -258,7 +258,7 @@ static void spi_engine_compile_message(struct spi_message *msg, bool dry, clk_div - 1)); } - if (bits_per_word != xfer->bits_per_word) { + if (bits_per_word != xfer->bits_per_word && xfer->len) { bits_per_word = xfer->bits_per_word; spi_engine_program_add_cmd(p, dry, SPI_ENGINE_CMD_WRITE(SPI_ENGINE_CMD_REG_XFER_BITS, From 158678bea637020dd6fc521536c5b07701447777 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Sat, 27 Jul 2024 13:48:27 +0200 Subject: [PATCH 16/65] spi: dt-bindings: mediatek,spi-mt65xx: add compatible for MT7981 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit MT7981 has SPI controllers based on IPM design Signed-off-by: Rafał Miłecki Acked-by: Krzysztof Kozlowski Link: https://patch.msgid.link/20240727114828.29558-1-zajec5@gmail.com Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/spi/mediatek,spi-mt65xx.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/spi/mediatek,spi-mt65xx.yaml b/Documentation/devicetree/bindings/spi/mediatek,spi-mt65xx.yaml index b6249880c3f9..e1f5bfa4433c 100644 --- a/Documentation/devicetree/bindings/spi/mediatek,spi-mt65xx.yaml +++ b/Documentation/devicetree/bindings/spi/mediatek,spi-mt65xx.yaml @@ -33,6 +33,7 @@ properties: - const: mediatek,mt6765-spi - items: - enum: + - mediatek,mt7981-spi-ipm - mediatek,mt7986-spi-ipm - mediatek,mt8188-spi-ipm - const: mediatek,spi-ipm From 0f245463b01ea254ae90e1d0389e90b0e7d8dc75 Mon Sep 17 00:00:00 2001 From: Ma Ke Date: Wed, 24 Jul 2024 16:40:47 +0800 Subject: [PATCH 17/65] spi: ppc4xx: handle irq_of_parse_and_map() errors Zero and negative number is not a valid IRQ for in-kernel code and the irq_of_parse_and_map() function returns zero on error. So this check for valid IRQs should only accept values > 0. Fixes: 44dab88e7cc9 ("spi: add spi_ppc4xx driver") Signed-off-by: Ma Ke Link: https://patch.msgid.link/20240724084047.1506084-1-make24@iscas.ac.cn Signed-off-by: Mark Brown --- drivers/spi/spi-ppc4xx.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/spi/spi-ppc4xx.c b/drivers/spi/spi-ppc4xx.c index 942c3117ab3a..01fdecbf132d 100644 --- a/drivers/spi/spi-ppc4xx.c +++ b/drivers/spi/spi-ppc4xx.c @@ -413,6 +413,9 @@ static int spi_ppc4xx_of_probe(struct platform_device *op) /* Request IRQ */ hw->irqnum = irq_of_parse_and_map(np, 0); + if (hw->irqnum <= 0) + goto free_host; + ret = request_irq(hw->irqnum, spi_ppc4xx_int, 0, "spi_ppc4xx_of", (void *)hw); if (ret) { From dc58d15ae7f247f642ea4751a276914eefa31865 Mon Sep 17 00:00:00 2001 From: Chen Ni Date: Tue, 16 Jul 2024 17:11:51 +0800 Subject: [PATCH 18/65] spi: meson-spicc: convert comma to semicolon Replace a comma between expression statements by a semicolon. Fixes: 3e0cf4d3fc29 ("spi: meson-spicc: add a linear clock divider support") Signed-off-by: Chen Ni Reviewed-by: Neil Armstrong Link: https://patch.msgid.link/20240716091151.1434450-1-nichen@iscas.ac.cn Signed-off-by: Mark Brown --- drivers/spi/spi-meson-spicc.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/drivers/spi/spi-meson-spicc.c b/drivers/spi/spi-meson-spicc.c index 8838a98b04c2..1d05590a7434 100644 --- a/drivers/spi/spi-meson-spicc.c +++ b/drivers/spi/spi-meson-spicc.c @@ -655,8 +655,8 @@ static int meson_spicc_pow2_clk_init(struct meson_spicc_device *spicc) } init.num_parents = 1; - pow2_fixed_div->mult = 1, - pow2_fixed_div->div = 4, + pow2_fixed_div->mult = 1; + pow2_fixed_div->div = 4; pow2_fixed_div->hw.init = &init; clk = devm_clk_register(dev, &pow2_fixed_div->hw); @@ -674,9 +674,9 @@ static int meson_spicc_pow2_clk_init(struct meson_spicc_device *spicc) parent_data[0].hw = &pow2_fixed_div->hw; init.num_parents = 1; - spicc->pow2_div.shift = 16, - spicc->pow2_div.width = 3, - spicc->pow2_div.flags = CLK_DIVIDER_POWER_OF_TWO, + spicc->pow2_div.shift = 16; + spicc->pow2_div.width = 3; + spicc->pow2_div.flags = CLK_DIVIDER_POWER_OF_TWO; spicc->pow2_div.reg = spicc->base + SPICC_CONREG; spicc->pow2_div.hw.init = &init; @@ -721,8 +721,8 @@ static int meson_spicc_enh_clk_init(struct meson_spicc_device *spicc) } init.num_parents = 1; - enh_fixed_div->mult = 1, - enh_fixed_div->div = 2, + enh_fixed_div->mult = 1; + enh_fixed_div->div = 2; enh_fixed_div->hw.init = &init; clk = devm_clk_register(dev, &enh_fixed_div->hw); @@ -740,8 +740,8 @@ static int meson_spicc_enh_clk_init(struct meson_spicc_device *spicc) parent_data[0].hw = &enh_fixed_div->hw; init.num_parents = 1; - enh_div->shift = 16, - enh_div->width = 8, + enh_div->shift = 16; + enh_div->width = 8; enh_div->reg = spicc->base + SPICC_ENH_CTL0; enh_div->hw.init = &init; @@ -761,8 +761,8 @@ static int meson_spicc_enh_clk_init(struct meson_spicc_device *spicc) init.num_parents = 2; init.flags = CLK_SET_RATE_PARENT; - mux->mask = 0x1, - mux->shift = 24, + mux->mask = 0x1; + mux->shift = 24; mux->reg = spicc->base + SPICC_ENH_CTL0; mux->hw.init = &init; From 5972eb05ca322bb1efe44d32808bc7a331e7aee4 Mon Sep 17 00:00:00 2001 From: AngeloGioacchino Del Regno Date: Fri, 26 Jul 2024 13:47:21 +0200 Subject: [PATCH 19/65] spi: spi-mt65xx: Use threaded interrupt for non-SPIMEM transfer In order to avoid blocking for an excessive amount of time, eventually impacting on system responsiveness, interrupt handlers should finish executing in as little time as possible. Use threaded interrupt and move the SPI transfer handling (both CPU and DMA) for the non-spimem case to an interrupt thread instead. For SPI-MEM (IPM) controllers, handling is kept in the blocking interrupt as it simply consists in signalling completion. Signed-off-by: AngeloGioacchino Del Regno Link: https://patch.msgid.link/20240726114721.142196-1-angelogioacchino.delregno@collabora.com Signed-off-by: Mark Brown --- drivers/spi/spi-mt65xx.c | 40 +++++++++++++++++++++++++--------------- 1 file changed, 25 insertions(+), 15 deletions(-) diff --git a/drivers/spi/spi-mt65xx.c b/drivers/spi/spi-mt65xx.c index 36c2f52cd6b8..dfee244fc317 100644 --- a/drivers/spi/spi-mt65xx.c +++ b/drivers/spi/spi-mt65xx.c @@ -743,25 +743,13 @@ static int mtk_spi_setup(struct spi_device *spi) return 0; } -static irqreturn_t mtk_spi_interrupt(int irq, void *dev_id) +static irqreturn_t mtk_spi_interrupt_thread(int irq, void *dev_id) { u32 cmd, reg_val, cnt, remainder, len; struct spi_controller *host = dev_id; struct mtk_spi *mdata = spi_controller_get_devdata(host); struct spi_transfer *xfer = mdata->cur_transfer; - reg_val = readl(mdata->base + SPI_STATUS0_REG); - if (reg_val & MTK_SPI_PAUSE_INT_STATUS) - mdata->state = MTK_SPI_PAUSED; - else - mdata->state = MTK_SPI_IDLE; - - /* SPI-MEM ops */ - if (mdata->use_spimem) { - complete(&mdata->spimem_done); - return IRQ_HANDLED; - } - if (!host->can_dma(host, NULL, xfer)) { if (xfer->rx_buf) { cnt = mdata->xfer_len / 4; @@ -845,6 +833,27 @@ static irqreturn_t mtk_spi_interrupt(int irq, void *dev_id) return IRQ_HANDLED; } +static irqreturn_t mtk_spi_interrupt(int irq, void *dev_id) +{ + struct spi_controller *host = dev_id; + struct mtk_spi *mdata = spi_controller_get_devdata(host); + u32 reg_val; + + reg_val = readl(mdata->base + SPI_STATUS0_REG); + if (reg_val & MTK_SPI_PAUSE_INT_STATUS) + mdata->state = MTK_SPI_PAUSED; + else + mdata->state = MTK_SPI_IDLE; + + /* SPI-MEM ops */ + if (mdata->use_spimem) { + complete(&mdata->spimem_done); + return IRQ_HANDLED; + } + + return IRQ_WAKE_THREAD; +} + static int mtk_spi_mem_adjust_op_size(struct spi_mem *mem, struct spi_mem_op *op) { @@ -1255,8 +1264,9 @@ static int mtk_spi_probe(struct platform_device *pdev) dev_notice(dev, "SPI dma_set_mask(%d) failed, ret:%d\n", addr_bits, ret); - ret = devm_request_irq(dev, irq, mtk_spi_interrupt, - IRQF_TRIGGER_NONE, dev_name(dev), host); + ret = devm_request_threaded_irq(dev, irq, mtk_spi_interrupt, + mtk_spi_interrupt_thread, + IRQF_TRIGGER_NONE, dev_name(dev), host); if (ret) return dev_err_probe(dev, ret, "failed to register irq\n"); From d58ecc54bb09e3dfc0b43a82a6e1602a44bbebce Mon Sep 17 00:00:00 2001 From: Witold Sadowski Date: Tue, 30 Jul 2024 06:16:26 -0700 Subject: [PATCH 20/65] spi: cadence: Add 64BIT Kconfig dependency xSPI block requires 64 bit operation for proper Marvell SDMA handling. Disallow bulding on targets without 64 bit support. Signed-off-by: Witold Sadowski Link: https://patch.msgid.link/20240730131627.1874257-1-wsadowski@marvell.com Signed-off-by: Mark Brown --- drivers/spi/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index ec1550c698d5..823797217404 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -267,7 +267,7 @@ config SPI_CADENCE_QUADSPI config SPI_CADENCE_XSPI tristate "Cadence XSPI controller" - depends on OF && HAS_IOMEM + depends on OF && HAS_IOMEM && 64BIT depends on SPI_MEM help Enable support for the Cadence XSPI Flash controller. From 0880f669436028c5499901e5acd8f4b4ea0e0c6a Mon Sep 17 00:00:00 2001 From: Biju Das Date: Wed, 31 Jul 2024 08:29:53 +0100 Subject: [PATCH 21/65] spi: rpc-if: Add missing MODULE_DEVICE_TABLE Add missing MODULE_DEVICE_TABLE definition for automatic loading of the driver when it is built as a module. Fixes: eb8d6d464a27 ("spi: add Renesas RPC-IF driver") Signed-off-by: Biju Das Reviewed-by: Geert Uytterhoeven Link: https://patch.msgid.link/20240731072955.224125-1-biju.das.jz@bp.renesas.com Signed-off-by: Mark Brown --- drivers/spi/spi-rpc-if.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/spi/spi-rpc-if.c b/drivers/spi/spi-rpc-if.c index d3f07fd719bd..b468a95972bf 100644 --- a/drivers/spi/spi-rpc-if.c +++ b/drivers/spi/spi-rpc-if.c @@ -198,9 +198,16 @@ static int __maybe_unused rpcif_spi_resume(struct device *dev) static SIMPLE_DEV_PM_OPS(rpcif_spi_pm_ops, rpcif_spi_suspend, rpcif_spi_resume); +static const struct platform_device_id rpc_if_spi_id_table[] = { + { .name = "rpc-if-spi" }, + { /* sentinel */ } +}; +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, + .id_table = rpc_if_spi_id_table, .driver = { .name = "rpc-if-spi", #ifdef CONFIG_PM_SLEEP From 1c4d834e4e81637995b079fdb64fad4c32af15c8 Mon Sep 17 00:00:00 2001 From: Frank Li Date: Tue, 13 Aug 2024 11:44:43 -0400 Subject: [PATCH 22/65] spi: dt-bindings: convert spi-sc18is602.txt to yaml format Convert binding doc spi-sc18is602.txt (I2C to SPI bridge) to yaml. Additional change: - ref spi-controller.yaml Fix below warning: arch/arm64/boot/dts/freescale/fsl-lx2160a-bluebox3.dtb: /soc/i2c@2000000/i2c-mux@77/i2c@7/i2c-mux@75/i2c@0/spi@28: failed to match any schema with compatible: ['nxp,sc18is602b'] Reviewed-by: Rob Herring (Arm) Signed-off-by: Frank Li Link: https://patch.msgid.link/20240813154444.3886690-1-Frank.Li@nxp.com Signed-off-by: Mark Brown --- .../devicetree/bindings/spi/nxp,sc18is.yaml | 51 +++++++++++++++++++ .../devicetree/bindings/spi/spi-sc18is602.txt | 23 --------- 2 files changed, 51 insertions(+), 23 deletions(-) create mode 100644 Documentation/devicetree/bindings/spi/nxp,sc18is.yaml delete mode 100644 Documentation/devicetree/bindings/spi/spi-sc18is602.txt diff --git a/Documentation/devicetree/bindings/spi/nxp,sc18is.yaml b/Documentation/devicetree/bindings/spi/nxp,sc18is.yaml new file mode 100644 index 000000000000..43753a94837c --- /dev/null +++ b/Documentation/devicetree/bindings/spi/nxp,sc18is.yaml @@ -0,0 +1,51 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/spi/nxp,sc18is.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: NXP SC18IS602/SC18IS603 I2C to SPI bridge + +maintainers: + - Frank Li + +properties: + compatible: + enum: + - nxp,sc18is602 + - nxp,sc18is602b + - nxp,sc18is603 + + reg: + maxItems: 1 + + clock-frequency: + $ref: /schemas/types.yaml#/definitions/uint32 + default: 7372000 + description: + external oscillator clock frequency. The clock-frequency property is + relevant and needed only if the chip has an external oscillator + (SC18IS603). + +allOf: + - $ref: spi-controller.yaml# + +unevaluatedProperties: false + +required: + - compatible + - reg + +examples: + - | + i2c { + #address-cells = <1>; + #size-cells = <0>; + + spi@28 { + compatible = "nxp,sc18is603"; + reg = <0x28>; + clock-frequency = <14744000>; + }; + }; + diff --git a/Documentation/devicetree/bindings/spi/spi-sc18is602.txt b/Documentation/devicetree/bindings/spi/spi-sc18is602.txt deleted file mode 100644 index 02f9033270a2..000000000000 --- a/Documentation/devicetree/bindings/spi/spi-sc18is602.txt +++ /dev/null @@ -1,23 +0,0 @@ -NXP SC18IS602/SCIS603 - -Required properties: - - compatible : Should be one of - "nxp,sc18is602" - "nxp,sc18is602b" - "nxp,sc18is603" - - reg: I2C bus address - -Optional properties: - - clock-frequency : external oscillator clock frequency. If not - specified, the SC18IS602 default frequency (7372000) will be used. - -The clock-frequency property is relevant and needed only if the chip has an -external oscillator (SC18IS603). - -Example: - - sc18is603@28 { - compatible = "nxp,sc18is603"; - reg = <0x28>; - clock-frequency = <14744000>; - } From f1011ba20b83da3ee70dcb4a6d9d282a718916fa Mon Sep 17 00:00:00 2001 From: Ma Ke Date: Mon, 22 Jul 2024 22:18:22 +0800 Subject: [PATCH 23/65] spi: ppc4xx: handle irq_of_parse_and_map() errors Zero and negative number is not a valid IRQ for in-kernel code and the irq_of_parse_and_map() function returns zero on error. So this check for valid IRQs should only accept values > 0. Fixes: 44dab88e7cc9 ("spi: add spi_ppc4xx driver") Signed-off-by: Ma Ke Link: https://patch.msgid.link/20240722141822.1052370-1-make24@iscas.ac.cn Signed-off-by: Mark Brown --- drivers/spi/spi-ppc4xx.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/spi/spi-ppc4xx.c b/drivers/spi/spi-ppc4xx.c index 01fdecbf132d..599c29a31269 100644 --- a/drivers/spi/spi-ppc4xx.c +++ b/drivers/spi/spi-ppc4xx.c @@ -416,6 +416,9 @@ static int spi_ppc4xx_of_probe(struct platform_device *op) if (hw->irqnum <= 0) goto free_host; + if (hw->irqnum <= 0) + goto free_host; + ret = request_irq(hw->irqnum, spi_ppc4xx_int, 0, "spi_ppc4xx_of", (void *)hw); if (ret) { From 7781f1d120fec8624fc654eda900fc8748262082 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 14 Aug 2024 17:45:12 +0300 Subject: [PATCH 24/65] spi: ppc4xx: Avoid returning 0 when failed to parse and map IRQ 0 is incorrect error code when failed to parse and map IRQ. Replace OF specific old API for IRQ retrieval with a generic one to fix this issue. Fixes: 0f245463b01e ("spi: ppc4xx: handle irq_of_parse_and_map() errors") Signed-off-by: Andy Shevchenko Link: https://patch.msgid.link/20240814144525.2648450-1-andriy.shevchenko@linux.intel.com Signed-off-by: Mark Brown --- drivers/spi/spi-ppc4xx.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/spi/spi-ppc4xx.c b/drivers/spi/spi-ppc4xx.c index 599c29a31269..6071f83dd9c8 100644 --- a/drivers/spi/spi-ppc4xx.c +++ b/drivers/spi/spi-ppc4xx.c @@ -27,7 +27,6 @@ #include #include #include -#include #include #include #include @@ -412,9 +411,10 @@ static int spi_ppc4xx_of_probe(struct platform_device *op) } /* Request IRQ */ - hw->irqnum = irq_of_parse_and_map(np, 0); - if (hw->irqnum <= 0) + ret = platform_get_irq(op, 0); + if (ret < 0) goto free_host; + hw->irqnum = ret; if (hw->irqnum <= 0) goto free_host; From 6a2ab229abdd9fb2177d0af72289eabcc971d985 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 14 Aug 2024 16:38:05 +0200 Subject: [PATCH 25/65] spi: cadence-quadspi: Simplify with scoped for each OF child loop Use scoped for_each_available_child_of_node_scoped() when iterating over device nodes to make code a bit simpler. Signed-off-by: Krzysztof Kozlowski Link: https://patch.msgid.link/20240814143805.98874-1-krzysztof.kozlowski@linaro.org Signed-off-by: Mark Brown --- drivers/spi/spi-cadence-quadspi.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/drivers/spi/spi-cadence-quadspi.c b/drivers/spi/spi-cadence-quadspi.c index 05ebb03d319f..9c0a4fa5128a 100644 --- a/drivers/spi/spi-cadence-quadspi.c +++ b/drivers/spi/spi-cadence-quadspi.c @@ -1662,23 +1662,20 @@ static int cqspi_setup_flash(struct cqspi_st *cqspi) unsigned int max_cs = cqspi->num_chipselect - 1; struct platform_device *pdev = cqspi->pdev; struct device *dev = &pdev->dev; - struct device_node *np = dev->of_node; struct cqspi_flash_pdata *f_pdata; unsigned int cs; int ret; /* Get flash device data */ - for_each_available_child_of_node(dev->of_node, np) { + for_each_available_child_of_node_scoped(dev->of_node, np) { ret = of_property_read_u32(np, "reg", &cs); if (ret) { dev_err(dev, "Couldn't determine chip select.\n"); - of_node_put(np); return ret; } if (cs >= cqspi->num_chipselect) { dev_err(dev, "Chip select %d out of range.\n", cs); - of_node_put(np); return -EINVAL; } else if (cs < max_cs) { max_cs = cs; @@ -1689,10 +1686,8 @@ static int cqspi_setup_flash(struct cqspi_st *cqspi) f_pdata->cs = cs; ret = cqspi_of_get_flash_pdata(pdev, f_pdata, np); - if (ret) { - of_node_put(np); + if (ret) return ret; - } } cqspi->num_chipselect = max_cs + 1; From d6d0af1b9efff4e83ecd5eb2585b6e5f75df7495 Mon Sep 17 00:00:00 2001 From: Pierre-Henry Moussay Date: Thu, 25 Jul 2024 13:15:56 +0100 Subject: [PATCH 26/65] dt-bindings: spi: add PIC64GX SPI/QSPI compatibility to MPFS SPI/QSPI bindings PIC64GX SPI/QSPI are compatible with MPFS SPI/QSPI driver, we just use fallback mechanism Signed-off-by: Pierre-Henry Moussay Link: https://patch.msgid.link/20240725121609.13101-5-pierre-henry.moussay@microchip.com Signed-off-by: Mark Brown --- .../devicetree/bindings/spi/microchip,mpfs-spi.yaml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/spi/microchip,mpfs-spi.yaml b/Documentation/devicetree/bindings/spi/microchip,mpfs-spi.yaml index ffa8d1b48f8b..62a568bdbfa0 100644 --- a/Documentation/devicetree/bindings/spi/microchip,mpfs-spi.yaml +++ b/Documentation/devicetree/bindings/spi/microchip,mpfs-spi.yaml @@ -17,9 +17,14 @@ properties: compatible: oneOf: - items: - - const: microchip,mpfs-qspi + - enum: + - microchip,mpfs-qspi + - microchip,pic64gx-qspi - const: microchip,coreqspi-rtl-v2 - const: microchip,coreqspi-rtl-v2 # FPGA QSPI + - items: + - const: microchip,pic64gx-spi + - const: microchip,mpfs-spi - const: microchip,mpfs-spi reg: From 802df33076cabfcb32b2c5b066c3af07f68e40fa Mon Sep 17 00:00:00 2001 From: Jinjie Ruan Date: Mon, 19 Aug 2024 20:00:31 +0800 Subject: [PATCH 27/65] spi: cadence: Make cdns_mrvl_xspi_clk_div_list static The sparse tool complains as follows: drivers/spi/spi-cadence-xspi.c:334:11: warning: symbol 'cdns_mrvl_xspi_clk_div_list' was not declared. Should it be static? This symbol is not used outside spi-cadence-xspi.c, so marks it static. Signed-off-by: Jinjie Ruan Link: https://patch.msgid.link/20240819120031.3884913-1-ruanjinjie@huawei.com Signed-off-by: Mark Brown --- drivers/spi/spi-cadence-xspi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/spi/spi-cadence-xspi.c b/drivers/spi/spi-cadence-xspi.c index 695a9bc1969a..aed98ab14334 100644 --- a/drivers/spi/spi-cadence-xspi.c +++ b/drivers/spi/spi-cadence-xspi.c @@ -331,7 +331,7 @@ static struct cdns_xspi_driver_data cdns_driver_data = { .mrvl_hw_overlay = false, }; -const int cdns_mrvl_xspi_clk_div_list[] = { +static const int cdns_mrvl_xspi_clk_div_list[] = { 4, //0x0 = Divide by 4. SPI clock is 200 MHz. 6, //0x1 = Divide by 6. SPI clock is 133.33 MHz. 8, //0x2 = Divide by 8. SPI clock is 100 MHz. From aa6e8296a7ff55c7c40a616b87c521b2a7e96395 Mon Sep 17 00:00:00 2001 From: Jinjie Ruan Date: Mon, 19 Aug 2024 12:05:23 +0800 Subject: [PATCH 28/65] spi: s3c64xx: Fix module autoloading Add MODULE_DEVICE_TABLE(), so modules could be properly autoloaded based on the alias from of_device_id table. Signed-off-by: Jinjie Ruan Reviewed-by: Krzysztof Kozlowski Link: https://patch.msgid.link/20240819040523.2801461-1-ruanjinjie@huawei.com Signed-off-by: Mark Brown --- drivers/spi/spi-s3c64xx.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/spi/spi-s3c64xx.c b/drivers/spi/spi-s3c64xx.c index 833c58c88e40..51a002b3f518 100644 --- a/drivers/spi/spi-s3c64xx.c +++ b/drivers/spi/spi-s3c64xx.c @@ -1637,6 +1637,7 @@ static const struct platform_device_id s3c64xx_spi_driver_ids[] = { }, { }, }; +MODULE_DEVICE_TABLE(platform, s3c64xx_spi_driver_ids); static const struct of_device_id s3c64xx_spi_dt_match[] = { { .compatible = "google,gs101-spi", From 909f34f2462a99bf876f64c5c61c653213e32fce Mon Sep 17 00:00:00 2001 From: Jinjie Ruan Date: Mon, 19 Aug 2024 20:33:48 +0800 Subject: [PATCH 29/65] spi: bcm63xx: Fix module autoloading Add MODULE_DEVICE_TABLE(), so modules could be properly autoloaded based on the alias from platform_device_id table. Fixes: 44d8fb30941d ("spi/bcm63xx: move register definitions into the driver") Cc: stable@vger.kernel.org Signed-off-by: Jinjie Ruan Reviewed-by: Jonas Gorski Link: https://patch.msgid.link/20240819123349.4020472-2-ruanjinjie@huawei.com Signed-off-by: Mark Brown --- drivers/spi/spi-bcm63xx.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/spi/spi-bcm63xx.c b/drivers/spi/spi-bcm63xx.c index aac41bd05f98..289f8a94980b 100644 --- a/drivers/spi/spi-bcm63xx.c +++ b/drivers/spi/spi-bcm63xx.c @@ -466,6 +466,7 @@ static const struct platform_device_id bcm63xx_spi_dev_match[] = { { }, }; +MODULE_DEVICE_TABLE(platform, bcm63xx_spi_dev_match); static const struct of_device_id bcm63xx_spi_of_match[] = { { .compatible = "brcm,bcm6348-spi", .data = &bcm6348_spi_reg_offsets }, From 265697288ec2160ca84707565d6641d46f69b0ff Mon Sep 17 00:00:00 2001 From: Jinjie Ruan Date: Mon, 19 Aug 2024 20:33:49 +0800 Subject: [PATCH 30/65] spi: bcm63xx: Fix missing pm_runtime_disable() The pm_runtime_disable() is missing in the remove function, fix it by using devm_pm_runtime_enable(), so the pm_runtime_disable() in the probe error path can also be removed. Fixes: 2d13f2ff6073 ("spi: bcm63xx-spi: fix pm_runtime") Cc: stable@vger.kernel.org # v5.13+ Signed-off-by: Jinjie Ruan Suggested-by: Jonas Gorski Link: https://patch.msgid.link/20240819123349.4020472-3-ruanjinjie@huawei.com Signed-off-by: Mark Brown --- drivers/spi/spi-bcm63xx.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/spi/spi-bcm63xx.c b/drivers/spi/spi-bcm63xx.c index 289f8a94980b..2fb79701a525 100644 --- a/drivers/spi/spi-bcm63xx.c +++ b/drivers/spi/spi-bcm63xx.c @@ -583,13 +583,15 @@ static int bcm63xx_spi_probe(struct platform_device *pdev) bcm_spi_writeb(bs, SPI_INTR_CLEAR_ALL, SPI_INT_STATUS); - pm_runtime_enable(&pdev->dev); + ret = devm_pm_runtime_enable(&pdev->dev); + if (ret) + goto out_clk_disable; /* register and we are done */ ret = devm_spi_register_controller(dev, host); if (ret) { dev_err(dev, "spi register failed\n"); - goto out_pm_disable; + goto out_clk_disable; } dev_info(dev, "at %pr (irq %d, FIFOs size %d)\n", @@ -597,8 +599,6 @@ static int bcm63xx_spi_probe(struct platform_device *pdev) return 0; -out_pm_disable: - pm_runtime_disable(&pdev->dev); out_clk_disable: clk_disable_unprepare(clk); out_err: From 3bf2a5359b0bde22418705ec862ac5077312e4c2 Mon Sep 17 00:00:00 2001 From: Jinjie Ruan Date: Tue, 20 Aug 2024 20:35:18 +0800 Subject: [PATCH 31/65] spi: wpcm-fiu: Use devm_platform_ioremap_resource_byname() Use the devm_platform_ioremap_resource_byname() helper instead of calling platform_get_resource_byname() and devm_ioremap_resource() separately. Signed-off-by: Jinjie Ruan Link: https://patch.msgid.link/20240820123518.1788294-1-ruanjinjie@huawei.com Signed-off-by: Mark Brown --- drivers/spi/spi-wpcm-fiu.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/spi/spi-wpcm-fiu.c b/drivers/spi/spi-wpcm-fiu.c index 886d6d7771d4..47e485fd8f84 100644 --- a/drivers/spi/spi-wpcm-fiu.c +++ b/drivers/spi/spi-wpcm-fiu.c @@ -448,8 +448,7 @@ static int wpcm_fiu_probe(struct platform_device *pdev) fiu = spi_controller_get_devdata(ctrl); fiu->dev = dev; - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "control"); - fiu->regs = devm_ioremap_resource(dev, res); + fiu->regs = devm_platform_ioremap_resource_byname(pdev, "control"); if (IS_ERR(fiu->regs)) { dev_err(dev, "Failed to map registers\n"); return PTR_ERR(fiu->regs); @@ -459,8 +458,7 @@ static int wpcm_fiu_probe(struct platform_device *pdev) if (IS_ERR(fiu->clk)) return PTR_ERR(fiu->clk); - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "memory"); - fiu->memory = devm_ioremap_resource(dev, res); + fiu->memory = devm_platform_ioremap_resource_byname(pdev, "memory"); fiu->memory_size = min_t(size_t, resource_size(res), MAX_MEMORY_SIZE_TOTAL); if (IS_ERR(fiu->memory)) { dev_err(dev, "Failed to map flash memory window\n"); From 3ccea1dedef39b8fc1adb13dd38c6e0b69e728af Mon Sep 17 00:00:00 2001 From: Jinjie Ruan Date: Tue, 20 Aug 2024 20:38:18 +0800 Subject: [PATCH 32/65] spi: atmel-quadspi: Simpify resource lookup Use the devm_platform_ioremap_resource_byname() helper instead of calling platform_get_resource_byname() and devm_ioremap_resource() separately. Signed-off-by: Jinjie Ruan Link: https://patch.msgid.link/20240820123818.1788432-1-ruanjinjie@huawei.com Signed-off-by: Mark Brown --- drivers/spi/atmel-quadspi.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/spi/atmel-quadspi.c b/drivers/spi/atmel-quadspi.c index 5aaff3bee1b7..2b5c72176711 100644 --- a/drivers/spi/atmel-quadspi.c +++ b/drivers/spi/atmel-quadspi.c @@ -601,16 +601,14 @@ static int atmel_qspi_probe(struct platform_device *pdev) aq->pdev = pdev; /* Map the registers */ - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "qspi_base"); - aq->regs = devm_ioremap_resource(&pdev->dev, res); + aq->regs = devm_platform_ioremap_resource_byname(pdev, "qspi_base"); if (IS_ERR(aq->regs)) { dev_err(&pdev->dev, "missing registers\n"); return PTR_ERR(aq->regs); } /* Map the AHB memory */ - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "qspi_mmap"); - aq->mem = devm_ioremap_resource(&pdev->dev, res); + aq->mem = devm_platform_ioremap_resource_byname(pdev, "qspi_mmap"); if (IS_ERR(aq->mem)) { dev_err(&pdev->dev, "missing AHB memory\n"); return PTR_ERR(aq->mem); From 91232b00b1a5d2486770c72c51a752a77c7601b2 Mon Sep 17 00:00:00 2001 From: Jinjie Ruan Date: Tue, 20 Aug 2024 20:40:11 +0800 Subject: [PATCH 33/65] spi: bcmbca-hsspi: Simpify resource lookup Instead of calling platform_get_resource_byname() and devm_ioremap_resource(), simplify the code by simply calling devm_platform_ioremap_resource_byname(). Signed-off-by: Jinjie Ruan Link: https://patch.msgid.link/20240820124011.1788479-1-ruanjinjie@huawei.com Signed-off-by: Mark Brown --- drivers/spi/spi-bcmbca-hsspi.c | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/drivers/spi/spi-bcmbca-hsspi.c b/drivers/spi/spi-bcmbca-hsspi.c index 9f64afd8164e..e48a56c68ce7 100644 --- a/drivers/spi/spi-bcmbca-hsspi.c +++ b/drivers/spi/spi-bcmbca-hsspi.c @@ -433,7 +433,6 @@ static int bcmbca_hsspi_probe(struct platform_device *pdev) { struct spi_controller *host; struct bcmbca_hsspi *bs; - struct resource *res_mem; void __iomem *spim_ctrl; void __iomem *regs; struct device *dev = &pdev->dev; @@ -445,17 +444,11 @@ static int bcmbca_hsspi_probe(struct platform_device *pdev) if (irq < 0) return irq; - res_mem = platform_get_resource_byname(pdev, IORESOURCE_MEM, "hsspi"); - if (!res_mem) - return -EINVAL; - regs = devm_ioremap_resource(dev, res_mem); + regs = devm_platform_ioremap_resource_byname(pdev, "hsspi"); if (IS_ERR(regs)) return PTR_ERR(regs); - res_mem = platform_get_resource_byname(pdev, IORESOURCE_MEM, "spim-ctrl"); - if (!res_mem) - return -EINVAL; - spim_ctrl = devm_ioremap_resource(dev, res_mem); + spim_ctrl = devm_platform_ioremap_resource_byname(pdev, "spim-ctrl"); if (IS_ERR(spim_ctrl)) return PTR_ERR(spim_ctrl); From 2fe6102bf01a5f4f48f211c2e5c8a274342fccb1 Mon Sep 17 00:00:00 2001 From: Bastien Curutchet Date: Wed, 28 Aug 2024 08:31:31 +0200 Subject: [PATCH 34/65] spi: davinci: Adapt transfer's timeout to transfer's length The timeout used when waiting for transfer's completion is always set to HZ. This isn't enough if a transfer is too large or if the bus speed is too low. Use the bus speed and the transfer length to calculate an appropriate timeout Signed-off-by: Bastien Curutchet Link: https://patch.msgid.link/20240828063131.10507-1-bastien.curutchet@bootlin.com Signed-off-by: Mark Brown --- drivers/spi/spi-davinci.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/spi/spi-davinci.c b/drivers/spi/spi-davinci.c index f7e8b5efa50e..ad26c8409733 100644 --- a/drivers/spi/spi-davinci.c +++ b/drivers/spi/spi-davinci.c @@ -570,6 +570,7 @@ static int davinci_spi_bufs(struct spi_device *spi, struct spi_transfer *t) u32 errors = 0; struct davinci_spi_config *spicfg; struct davinci_spi_platform_data *pdata; + unsigned long timeout; dspi = spi_controller_get_devdata(spi->controller); pdata = &dspi->pdata; @@ -661,7 +662,12 @@ static int davinci_spi_bufs(struct spi_device *spi, struct spi_transfer *t) /* Wait for the transfer to complete */ if (spicfg->io_type != SPI_IO_TYPE_POLL) { - if (wait_for_completion_timeout(&dspi->done, HZ) == 0) + timeout = DIV_ROUND_UP(t->speed_hz, MSEC_PER_SEC); + timeout = DIV_ROUND_UP(t->len * 8, timeout); + /* Assume we are at most 2x slower than the nominal bus speed */ + timeout = 2 * msecs_to_jiffies(timeout); + + if (wait_for_completion_timeout(&dspi->done, timeout) == 0) errors = SPIFLG_TIMEOUT_MASK; } else { while (dspi->rcount > 0 || dspi->wcount > 0) { From 4439a2e92cb89028b22c5d7ba1b99e75d7d889f6 Mon Sep 17 00:00:00 2001 From: Jinjie Ruan Date: Mon, 26 Aug 2024 20:49:02 +0800 Subject: [PATCH 35/65] spi: bcmbca-hsspi: Fix missing pm_runtime_disable() The pm_runtime_disable() is missing in remove function, use devm_pm_runtime_enable() to fix it. So the pm_runtime_disable() in the probe error path can also be removed. Fixes: a38a2233f23b ("spi: bcmbca-hsspi: Add driver for newer HSSPI controller") Signed-off-by: Jinjie Ruan Reviewed-by: William Zhang Link: https://patch.msgid.link/20240826124903.3429235-2-ruanjinjie@huawei.com Signed-off-by: Mark Brown --- drivers/spi/spi-bcmbca-hsspi.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/spi/spi-bcmbca-hsspi.c b/drivers/spi/spi-bcmbca-hsspi.c index e48a56c68ce7..f465daa473d0 100644 --- a/drivers/spi/spi-bcmbca-hsspi.c +++ b/drivers/spi/spi-bcmbca-hsspi.c @@ -539,12 +539,14 @@ static int bcmbca_hsspi_probe(struct platform_device *pdev) goto out_put_host; } - pm_runtime_enable(&pdev->dev); + ret = devm_pm_runtime_enable(&pdev->dev); + if (ret) + goto out_put_host; ret = sysfs_create_group(&pdev->dev.kobj, &bcmbca_hsspi_group); if (ret) { dev_err(&pdev->dev, "couldn't register sysfs group\n"); - goto out_pm_disable; + goto out_put_host; } /* register and we are done */ @@ -558,8 +560,6 @@ static int bcmbca_hsspi_probe(struct platform_device *pdev) out_sysgroup_disable: sysfs_remove_group(&pdev->dev.kobj, &bcmbca_hsspi_group); -out_pm_disable: - pm_runtime_disable(&pdev->dev); out_put_host: spi_controller_put(host); out_disable_pll_clk: From deb269e0394f2c75e1735132e29fa2f5181e107a Mon Sep 17 00:00:00 2001 From: Jinjie Ruan Date: Mon, 26 Aug 2024 20:49:03 +0800 Subject: [PATCH 36/65] spi: bcmbca-hsspi: Use devm_spi_alloc_host() Use devm_spi_alloc_host() so that there's no need to call spi_controller_put() in the error path. Signed-off-by: Jinjie Ruan Reviewed-by: William Zhang Link: https://patch.msgid.link/20240826124903.3429235-3-ruanjinjie@huawei.com Signed-off-by: Mark Brown --- drivers/spi/spi-bcmbca-hsspi.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/drivers/spi/spi-bcmbca-hsspi.c b/drivers/spi/spi-bcmbca-hsspi.c index f465daa473d0..d936104a41ec 100644 --- a/drivers/spi/spi-bcmbca-hsspi.c +++ b/drivers/spi/spi-bcmbca-hsspi.c @@ -480,7 +480,7 @@ static int bcmbca_hsspi_probe(struct platform_device *pdev) } } - host = spi_alloc_host(&pdev->dev, sizeof(*bs)); + host = devm_spi_alloc_host(&pdev->dev, sizeof(*bs)); if (!host) { ret = -ENOMEM; goto out_disable_pll_clk; @@ -536,17 +536,17 @@ static int bcmbca_hsspi_probe(struct platform_device *pdev) ret = devm_request_irq(dev, irq, bcmbca_hsspi_interrupt, IRQF_SHARED, pdev->name, bs); if (ret) - goto out_put_host; + goto out_disable_pll_clk; } ret = devm_pm_runtime_enable(&pdev->dev); if (ret) - goto out_put_host; + goto out_disable_pll_clk; ret = sysfs_create_group(&pdev->dev.kobj, &bcmbca_hsspi_group); if (ret) { dev_err(&pdev->dev, "couldn't register sysfs group\n"); - goto out_put_host; + goto out_disable_pll_clk; } /* register and we are done */ @@ -560,8 +560,6 @@ static int bcmbca_hsspi_probe(struct platform_device *pdev) out_sysgroup_disable: sysfs_remove_group(&pdev->dev.kobj, &bcmbca_hsspi_group); -out_put_host: - spi_controller_put(host); out_disable_pll_clk: clk_disable_unprepare(pll_clk); out_disable_clk: From c2ea9b8a536bd18b7632d4d998c20e1af9319c32 Mon Sep 17 00:00:00 2001 From: Jinjie Ruan Date: Mon, 26 Aug 2024 20:59:12 +0800 Subject: [PATCH 37/65] spi: atmel-quadspi: Fix uninitialized res The second platform_get_resource_byname() can not be replaced with devm_platform_ioremap_resource_byname(), because the intermediate "res" is used to assign for "aq->mmap_size". Fixes: 3ccea1dedef3 ("spi: atmel-quadspi: Simpify resource lookup") Signed-off-by: Jinjie Ruan Acked-by: Hari Prasath Gujulan Elango Link: https://patch.msgid.link/20240826125913.3434305-2-ruanjinjie@huawei.com Signed-off-by: Mark Brown --- drivers/spi/atmel-quadspi.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/spi/atmel-quadspi.c b/drivers/spi/atmel-quadspi.c index 2b5c72176711..56dd8dcb86cb 100644 --- a/drivers/spi/atmel-quadspi.c +++ b/drivers/spi/atmel-quadspi.c @@ -608,7 +608,8 @@ static int atmel_qspi_probe(struct platform_device *pdev) } /* Map the AHB memory */ - aq->mem = devm_platform_ioremap_resource_byname(pdev, "qspi_mmap"); + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "qspi_mmap"); + aq->mem = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(aq->mem)) { dev_err(&pdev->dev, "missing AHB memory\n"); return PTR_ERR(aq->mem); From 2d3e6351a25de0ceef69aae415cb1e082f0382c7 Mon Sep 17 00:00:00 2001 From: Jinjie Ruan Date: Mon, 26 Aug 2024 20:59:13 +0800 Subject: [PATCH 38/65] spi: atmel-quadspi: Simplify with dev_err_probe() Use the dev_err_probe() helper to simplify error handling during probe. This also handle scenario, when EDEFER is returned and useless error is printed. Signed-off-by: Jinjie Ruan Link: https://patch.msgid.link/20240826125913.3434305-3-ruanjinjie@huawei.com Signed-off-by: Mark Brown --- drivers/spi/atmel-quadspi.c | 28 ++++++++++++---------------- 1 file changed, 12 insertions(+), 16 deletions(-) diff --git a/drivers/spi/atmel-quadspi.c b/drivers/spi/atmel-quadspi.c index 56dd8dcb86cb..936d57869493 100644 --- a/drivers/spi/atmel-quadspi.c +++ b/drivers/spi/atmel-quadspi.c @@ -602,18 +602,16 @@ static int atmel_qspi_probe(struct platform_device *pdev) /* Map the registers */ aq->regs = devm_platform_ioremap_resource_byname(pdev, "qspi_base"); - if (IS_ERR(aq->regs)) { - dev_err(&pdev->dev, "missing registers\n"); - return PTR_ERR(aq->regs); - } + if (IS_ERR(aq->regs)) + return dev_err_probe(&pdev->dev, PTR_ERR(aq->regs), + "missing registers\n"); /* Map the AHB memory */ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "qspi_mmap"); aq->mem = devm_ioremap_resource(&pdev->dev, res); - if (IS_ERR(aq->mem)) { - dev_err(&pdev->dev, "missing AHB memory\n"); - return PTR_ERR(aq->mem); - } + if (IS_ERR(aq->mem)) + return dev_err_probe(&pdev->dev, PTR_ERR(aq->mem), + "missing AHB memory\n"); aq->mmap_size = resource_size(res); @@ -622,17 +620,15 @@ static int atmel_qspi_probe(struct platform_device *pdev) if (IS_ERR(aq->pclk)) aq->pclk = devm_clk_get(&pdev->dev, NULL); - if (IS_ERR(aq->pclk)) { - dev_err(&pdev->dev, "missing peripheral clock\n"); - return PTR_ERR(aq->pclk); - } + if (IS_ERR(aq->pclk)) + return dev_err_probe(&pdev->dev, PTR_ERR(aq->pclk), + "missing peripheral clock\n"); /* Enable the peripheral clock */ err = clk_prepare_enable(aq->pclk); - if (err) { - dev_err(&pdev->dev, "failed to enable the peripheral clock\n"); - return err; - } + if (err) + return dev_err_probe(&pdev->dev, err, + "failed to enable the peripheral clock\n"); aq->caps = of_device_get_match_data(&pdev->dev); if (!aq->caps) { From 0f2cf3bc4727fd07e3a1c8acb9f83e462b455986 Mon Sep 17 00:00:00 2001 From: Jinjie Ruan Date: Mon, 26 Aug 2024 21:25:43 +0800 Subject: [PATCH 39/65] spi: wpcm-fiu: Fix uninitialized res The second platform_get_resource_byname() can not be replaced with devm_platform_ioremap_resource_byname(), because the intermediate "res" is used by resource_size() later. Fixes: 3bf2a5359b0b ("spi: wpcm-fiu: Use devm_platform_ioremap_resource_byname()") Signed-off-by: Jinjie Ruan Link: https://patch.msgid.link/20240826132544.3463616-2-ruanjinjie@huawei.com Signed-off-by: Mark Brown --- drivers/spi/spi-wpcm-fiu.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/spi/spi-wpcm-fiu.c b/drivers/spi/spi-wpcm-fiu.c index 47e485fd8f84..05c10b3e6515 100644 --- a/drivers/spi/spi-wpcm-fiu.c +++ b/drivers/spi/spi-wpcm-fiu.c @@ -458,7 +458,8 @@ static int wpcm_fiu_probe(struct platform_device *pdev) if (IS_ERR(fiu->clk)) return PTR_ERR(fiu->clk); - fiu->memory = devm_platform_ioremap_resource_byname(pdev, "memory"); + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "memory"); + fiu->memory = devm_ioremap_resource(dev, res); fiu->memory_size = min_t(size_t, resource_size(res), MAX_MEMORY_SIZE_TOTAL); if (IS_ERR(fiu->memory)) { dev_err(dev, "Failed to map flash memory window\n"); From 196d34e2c8cfec7b94e44e75d0b1bc9176acf6f8 Mon Sep 17 00:00:00 2001 From: Jinjie Ruan Date: Mon, 26 Aug 2024 21:25:44 +0800 Subject: [PATCH 40/65] spi: wpcm-fiu: Simplify with dev_err_probe() Use the dev_err_probe() helper to simplify error handling during probe. This also handle scenario, when EDEFER is returned and useless error is printed. Signed-off-by: Jinjie Ruan Link: https://patch.msgid.link/20240826132544.3463616-3-ruanjinjie@huawei.com Signed-off-by: Mark Brown --- drivers/spi/spi-wpcm-fiu.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/drivers/spi/spi-wpcm-fiu.c b/drivers/spi/spi-wpcm-fiu.c index 05c10b3e6515..a9aee2a6c7dc 100644 --- a/drivers/spi/spi-wpcm-fiu.c +++ b/drivers/spi/spi-wpcm-fiu.c @@ -449,10 +449,9 @@ static int wpcm_fiu_probe(struct platform_device *pdev) fiu->dev = dev; fiu->regs = devm_platform_ioremap_resource_byname(pdev, "control"); - if (IS_ERR(fiu->regs)) { - dev_err(dev, "Failed to map registers\n"); - return PTR_ERR(fiu->regs); - } + if (IS_ERR(fiu->regs)) + return dev_err_probe(dev, PTR_ERR(fiu->regs), + "Failed to map registers\n"); fiu->clk = devm_clk_get_enabled(dev, NULL); if (IS_ERR(fiu->clk)) @@ -461,10 +460,9 @@ static int wpcm_fiu_probe(struct platform_device *pdev) res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "memory"); fiu->memory = devm_ioremap_resource(dev, res); fiu->memory_size = min_t(size_t, resource_size(res), MAX_MEMORY_SIZE_TOTAL); - if (IS_ERR(fiu->memory)) { - dev_err(dev, "Failed to map flash memory window\n"); - return PTR_ERR(fiu->memory); - } + if (IS_ERR(fiu->memory)) + return dev_err_probe(dev, PTR_ERR(fiu->memory), + "Failed to map flash memory window\n"); fiu->shm_regmap = syscon_regmap_lookup_by_phandle_optional(dev->of_node, "nuvoton,shm"); From 8a0ec8c2d736961ff556e9d331decda9048fe0f1 Mon Sep 17 00:00:00 2001 From: Yang Ruibin <11162571@vivo.com> Date: Thu, 29 Aug 2024 11:35:11 +0800 Subject: [PATCH 41/65] spi: Insert the missing pci_dev_put()before return Increase the reference count by calling pci_get_slot(), and remember to decrement the reference count by calling pci_dev_put(). Signed-off-by: Yang Ruibin <11162571@vivo.com> Link: https://patch.msgid.link/20240829033511.1917015-1-11162571@vivo.com Signed-off-by: Mark Brown --- drivers/spi/spi-pxa2xx-pci.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/spi/spi-pxa2xx-pci.c b/drivers/spi/spi-pxa2xx-pci.c index 616d032f1a89..d49d8fef4088 100644 --- a/drivers/spi/spi-pxa2xx-pci.c +++ b/drivers/spi/spi-pxa2xx-pci.c @@ -145,8 +145,10 @@ static int lpss_spi_setup(struct pci_dev *dev, struct pxa2xx_spi_controller *c) c->num_chipselect = 1; ret = pxa2xx_spi_pci_clk_register(dev, ssp, 50000000); - if (ret) + if (ret) { + pci_dev_put(dma_dev); return ret; + } dma_dev = pci_get_slot(dev->bus, PCI_DEVFN(PCI_SLOT(dev->devfn), 0)); ret = devm_add_action_or_reset(&dev->dev, lpss_dma_put_device, dma_dev); @@ -221,8 +223,10 @@ static int mrfld_spi_setup(struct pci_dev *dev, struct pxa2xx_spi_controller *c) } ret = pxa2xx_spi_pci_clk_register(dev, ssp, 25000000); - if (ret) + if (ret) { + pci_dev_put(dma_dev); return ret; + } dma_dev = pci_get_slot(dev->bus, PCI_DEVFN(21, 0)); ret = devm_add_action_or_reset(&dev->dev, lpss_dma_put_device, dma_dev); From ac7ee784fd00e90542411f113650222c82f86bfd Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Thu, 29 Aug 2024 08:31:56 -0300 Subject: [PATCH 42/65] dt-bindings: trivial-devices: Document elgin,jg10309-01 The rv1108-elgin-r1 board has an LCD controlled via SPI in userspace. The marking on the LCD is JG10309-01. Add an entry for the "elgin,jg10309-01" compatible string. Signed-off-by: Fabio Estevam Acked-by: Conor Dooley Acked-by: Heiko Stuebner Link: https://patch.msgid.link/20240829113158.3324928-1-festevam@gmail.com Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/trivial-devices.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Documentation/devicetree/bindings/trivial-devices.yaml b/Documentation/devicetree/bindings/trivial-devices.yaml index 7913ca9b6b54..516d50b01090 100644 --- a/Documentation/devicetree/bindings/trivial-devices.yaml +++ b/Documentation/devicetree/bindings/trivial-devices.yaml @@ -110,6 +110,8 @@ properties: - domintech,dmard09 # DMARD10: 3-axis Accelerometer - domintech,dmard10 + # Elgin SPI-controlled LCD + - elgin,jg10309-01 # MMA7660FC: 3-Axis Orientation/Motion Detection Sensor - fsl,mma7660 # MMA8450Q: Xtrinsic Low-power, 3-axis Xtrinsic Accelerometer From ab3f6e159204864f2bc208599d4652d10a4824ac Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Thu, 29 Aug 2024 08:31:57 -0300 Subject: [PATCH 43/65] spi: spidev: Add an entry for elgin,jg10309-01 The rv1108-elgin-r1 board has an LCD controlled via SPI in userspace. The marking on the LCD is JG10309-01. Add the "elgin,jg10309-01" compatible string. Signed-off-by: Fabio Estevam Reviewed-by: Heiko Stuebner Link: https://patch.msgid.link/20240829113158.3324928-2-festevam@gmail.com Signed-off-by: Mark Brown --- drivers/spi/spidev.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/spi/spidev.c b/drivers/spi/spidev.c index 05e6d007f9a7..1927175c8095 100644 --- a/drivers/spi/spidev.c +++ b/drivers/spi/spidev.c @@ -730,6 +730,7 @@ static int spidev_of_check(struct device *dev) static const struct of_device_id spidev_dt_ids[] = { { .compatible = "cisco,spi-petra", .data = &spidev_of_check }, { .compatible = "dh,dhcom-board", .data = &spidev_of_check }, + { .compatible = "elgin,jg10309-01", .data = &spidev_of_check }, { .compatible = "lineartechnology,ltc2488", .data = &spidev_of_check }, { .compatible = "lwn,bk4", .data = &spidev_of_check }, { .compatible = "menlo,m53cpld", .data = &spidev_of_check }, From 3959d1f0f8d6682aa896a8f78a9f5ebfd2b6f6c8 Mon Sep 17 00:00:00 2001 From: Yan Zhen Date: Tue, 27 Aug 2024 21:12:03 +0800 Subject: [PATCH 44/65] spi: nxp-fspi: Use max macro When the original file is guaranteed to contain the minmax.h header file and compile correctly, using the real macro is usually more intuitive and readable. Signed-off-by: Yan Zhen Link: https://patch.msgid.link/20240827131203.3918516-1-yanzhen@vivo.com Signed-off-by: Mark Brown --- drivers/spi/spi-nxp-fspi.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/spi/spi-nxp-fspi.c b/drivers/spi/spi-nxp-fspi.c index 88397f712a3b..fd1816befcd8 100644 --- a/drivers/spi/spi-nxp-fspi.c +++ b/drivers/spi/spi-nxp-fspi.c @@ -756,8 +756,7 @@ static int nxp_fspi_read_ahb(struct nxp_fspi *f, const struct spi_mem_op *op) iounmap(f->ahb_addr); f->memmap_start = start; - f->memmap_len = len > NXP_FSPI_MIN_IOMAP ? - len : NXP_FSPI_MIN_IOMAP; + f->memmap_len = max_t(u32, len, NXP_FSPI_MIN_IOMAP); f->ahb_addr = ioremap(f->memmap_phy + f->memmap_start, f->memmap_len); From e3de1d8deb9f6429356eb81118aa1601c8a5a1b6 Mon Sep 17 00:00:00 2001 From: Hongbo Li Date: Fri, 30 Aug 2024 15:58:00 +0800 Subject: [PATCH 45/65] spi: spi-ppc4xx: Remove duplicate included header file linux/platform_device.h The header file linux/platform_device.h is included twice. Remove the last one. Signed-off-by: Hongbo Li Link: https://patch.msgid.link/20240830075800.3541646-1-lihongbo22@huawei.com Signed-off-by: Mark Brown --- drivers/spi/spi-ppc4xx.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/spi/spi-ppc4xx.c b/drivers/spi/spi-ppc4xx.c index 6071f83dd9c8..36722fa6c8bf 100644 --- a/drivers/spi/spi-ppc4xx.c +++ b/drivers/spi/spi-ppc4xx.c @@ -30,7 +30,6 @@ #include #include #include -#include #include #include From 64640f6c972e80f52196416a8d4dc3c0ffcbc82d Mon Sep 17 00:00:00 2001 From: Jinjie Ruan Date: Mon, 26 Aug 2024 20:14:20 +0800 Subject: [PATCH 46/65] spi: zynqmp-gqspi: Use devm_spi_alloc_host() Use devm_spi_alloc_host() so that there's no need to call spi_controller_put() in the error path. Signed-off-by: Jinjie Ruan Acked-by: Michal Simek Link: https://patch.msgid.link/20240826121421.3384792-2-ruanjinjie@huawei.com Signed-off-by: Mark Brown --- drivers/spi/spi-zynqmp-gqspi.c | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/drivers/spi/spi-zynqmp-gqspi.c b/drivers/spi/spi-zynqmp-gqspi.c index 99524a3c9f38..0448bcb2b45c 100644 --- a/drivers/spi/spi-zynqmp-gqspi.c +++ b/drivers/spi/spi-zynqmp-gqspi.c @@ -1224,7 +1224,7 @@ static int zynqmp_qspi_probe(struct platform_device *pdev) u32 num_cs; const struct qspi_platform_data *p_data; - ctlr = spi_alloc_host(&pdev->dev, sizeof(*xqspi)); + ctlr = devm_spi_alloc_host(&pdev->dev, sizeof(*xqspi)); if (!ctlr) return -ENOMEM; @@ -1238,29 +1238,25 @@ static int zynqmp_qspi_probe(struct platform_device *pdev) xqspi->has_tapdelay = true; xqspi->regs = devm_platform_ioremap_resource(pdev, 0); - if (IS_ERR(xqspi->regs)) { - ret = PTR_ERR(xqspi->regs); - goto remove_ctlr; - } + if (IS_ERR(xqspi->regs)) + return PTR_ERR(xqspi->regs); xqspi->pclk = devm_clk_get(&pdev->dev, "pclk"); if (IS_ERR(xqspi->pclk)) { dev_err(dev, "pclk clock not found.\n"); - ret = PTR_ERR(xqspi->pclk); - goto remove_ctlr; + return PTR_ERR(xqspi->pclk); } xqspi->refclk = devm_clk_get(&pdev->dev, "ref_clk"); if (IS_ERR(xqspi->refclk)) { dev_err(dev, "ref_clk clock not found.\n"); - ret = PTR_ERR(xqspi->refclk); - goto remove_ctlr; + return PTR_ERR(xqspi->refclk); } ret = clk_prepare_enable(xqspi->pclk); if (ret) { dev_err(dev, "Unable to enable APB clock.\n"); - goto remove_ctlr; + return ret; } ret = clk_prepare_enable(xqspi->refclk); @@ -1346,8 +1342,6 @@ clk_dis_all: clk_disable_unprepare(xqspi->refclk); clk_dis_pclk: clk_disable_unprepare(xqspi->pclk); -remove_ctlr: - spi_controller_put(ctlr); return ret; } From d814fd0f046c2a6b1a919e1a529550bdfe9f9f9b Mon Sep 17 00:00:00 2001 From: Jinjie Ruan Date: Mon, 26 Aug 2024 20:14:21 +0800 Subject: [PATCH 47/65] spi: zynqmp-gqspi: Simplify with dev_err_probe() Use the dev_err_probe() helper to simplify error handling during probe. This also handle scenario, when EDEFER is returned and useless error is printed. Signed-off-by: Jinjie Ruan Acked-by: Michal Simek Link: https://patch.msgid.link/20240826121421.3384792-3-ruanjinjie@huawei.com Signed-off-by: Mark Brown --- drivers/spi/spi-zynqmp-gqspi.c | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/drivers/spi/spi-zynqmp-gqspi.c b/drivers/spi/spi-zynqmp-gqspi.c index 0448bcb2b45c..e8963e0a6d9a 100644 --- a/drivers/spi/spi-zynqmp-gqspi.c +++ b/drivers/spi/spi-zynqmp-gqspi.c @@ -1242,22 +1242,18 @@ static int zynqmp_qspi_probe(struct platform_device *pdev) return PTR_ERR(xqspi->regs); xqspi->pclk = devm_clk_get(&pdev->dev, "pclk"); - if (IS_ERR(xqspi->pclk)) { - dev_err(dev, "pclk clock not found.\n"); - return PTR_ERR(xqspi->pclk); - } + if (IS_ERR(xqspi->pclk)) + return dev_err_probe(dev, PTR_ERR(xqspi->pclk), + "pclk clock not found.\n"); xqspi->refclk = devm_clk_get(&pdev->dev, "ref_clk"); - if (IS_ERR(xqspi->refclk)) { - dev_err(dev, "ref_clk clock not found.\n"); - return PTR_ERR(xqspi->refclk); - } + if (IS_ERR(xqspi->refclk)) + return dev_err_probe(dev, PTR_ERR(xqspi->refclk), + "ref_clk clock not found.\n"); ret = clk_prepare_enable(xqspi->pclk); - if (ret) { - dev_err(dev, "Unable to enable APB clock.\n"); - return ret; - } + if (ret) + return dev_err_probe(dev, ret, "Unable to enable APB clock.\n"); ret = clk_prepare_enable(xqspi->refclk); if (ret) { From 7f9f8c5939b1d729470a15480a4ffb0512d39d3a Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 2 Sep 2024 13:28:26 +0300 Subject: [PATCH 48/65] spi: ppc4xx: Revert "handle irq_of_parse_and_map() errors" The commit had been applied twice as 0f245463b01e ("spi: ppc4xx: handle irq_of_parse_and_map() errors") and f1011ba20b83 ("spi: ppc4xx: handle irq_of_parse_and_map() errors") This reverts commit f1011ba20b83da3ee70dcb4a6d9d282a718916fa. Fixes: f1011ba20b83 ("spi: ppc4xx: handle irq_of_parse_and_map() errors") Signed-off-by: Andy Shevchenko Link: https://patch.msgid.link/20240902102853.2476165-1-andriy.shevchenko@linux.intel.com Signed-off-by: Mark Brown --- drivers/spi/spi-ppc4xx.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/spi/spi-ppc4xx.c b/drivers/spi/spi-ppc4xx.c index 36722fa6c8bf..2c43b498432f 100644 --- a/drivers/spi/spi-ppc4xx.c +++ b/drivers/spi/spi-ppc4xx.c @@ -415,9 +415,6 @@ static int spi_ppc4xx_of_probe(struct platform_device *op) goto free_host; hw->irqnum = ret; - if (hw->irqnum <= 0) - goto free_host; - ret = request_irq(hw->irqnum, spi_ppc4xx_int, 0, "spi_ppc4xx_of", (void *)hw); if (ret) { From e86836883a8a624680f247c7ac200538c6a5ebaa Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 2 Sep 2024 13:30:41 +0300 Subject: [PATCH 49/65] spi: ppc4xx: Sort headers Sort the headers in alphabetic order in order to ease the maintenance for this part. Signed-off-by: Andy Shevchenko Link: https://patch.msgid.link/20240902103203.2476576-1-andriy.shevchenko@linux.intel.com Signed-off-by: Mark Brown --- drivers/spi/spi-ppc4xx.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/spi/spi-ppc4xx.c b/drivers/spi/spi-ppc4xx.c index 2c43b498432f..4a64ea0f596f 100644 --- a/drivers/spi/spi-ppc4xx.c +++ b/drivers/spi/spi-ppc4xx.c @@ -20,21 +20,21 @@ * during SPI transfers by setting max_speed_hz via the device tree. */ -#include -#include -#include +#include #include -#include -#include +#include +#include +#include #include #include -#include -#include +#include +#include +#include +#include #include #include -#include #include #include From f626a0cd07ddb13f146e52adb4b534da40bb1ff7 Mon Sep 17 00:00:00 2001 From: Kuan-Wei Chiu Date: Thu, 15 Aug 2024 03:28:39 +0800 Subject: [PATCH 50/65] spi: zynq-qspi: Replace kzalloc with kmalloc for buffer allocation In zynq_qspi_exec_mem_op(), the temporary buffer is allocated with kzalloc and then immediately initialized using memset to 0xff. To optimize this, replace kzalloc with kmalloc, as the zeroing operation is redundant and unnecessary. Signed-off-by: Kuan-Wei Chiu Reviewed-by: Michal Simek Link: https://patch.msgid.link/20240814192839.345523-1-visitorckw@gmail.com Signed-off-by: Mark Brown --- drivers/spi/spi-zynq-qspi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/spi/spi-zynq-qspi.c b/drivers/spi/spi-zynq-qspi.c index d6325c6be3d4..b67455bda972 100644 --- a/drivers/spi/spi-zynq-qspi.c +++ b/drivers/spi/spi-zynq-qspi.c @@ -569,7 +569,7 @@ static int zynq_qspi_exec_mem_op(struct spi_mem *mem, } if (op->dummy.nbytes) { - tmpbuf = kzalloc(op->dummy.nbytes, GFP_KERNEL); + tmpbuf = kmalloc(op->dummy.nbytes, GFP_KERNEL); if (!tmpbuf) return -ENOMEM; From bf62a8c7908ee8e0ef61d27d9ff65bf12f41fb0a Mon Sep 17 00:00:00 2001 From: Nathan Chancellor Date: Mon, 2 Sep 2024 17:43:06 -0700 Subject: [PATCH 51/65] spi: Revert "spi: Insert the missing pci_dev_put()before return" Commit 8a0ec8c2d736 ("spi: Insert the missing pci_dev_put()before return") added two uses of pci_dev_put() with an uninitialized dma_dev, resulting in the following compiler warnings (or errors with CONFIG_WERROR) when building with clang: drivers/spi/spi-pxa2xx-pci.c:150:15: error: variable 'dma_dev' is uninitialized when used here [-Werror,-Wuninitialized] 150 | pci_dev_put(dma_dev); | ^~~~~~~ drivers/spi/spi-pxa2xx-pci.c:228:15: error: variable 'dma_dev' is uninitialized when used here [-Werror,-Wuninitialized] 228 | pci_dev_put(dma_dev); | ^~~~~~~ Commit 609d7ffdc421 ("spi: pxa2xx-pci: Balance reference count for PCI DMA device") added a call to pci_dev_put() via devm_add_action_or_reset() in case of failures, so the recent change was incorrect for multiple reasons. Revert it altogether. Fixes: 8a0ec8c2d736 ("spi: Insert the missing pci_dev_put()before return") Reported-by: Geert Uytterhoeven Closes: https://lore.kernel.org/CAMuHMdWNjo69_W6f+R9QJJOf8uF0htg2XazeS-yjugJv3UM+kg@mail.gmail.com/ Signed-off-by: Nathan Chancellor Link: https://patch.msgid.link/20240902-spi-revert-8a0ec8c2d736-v1-1-928b829fed2b@kernel.org Signed-off-by: Mark Brown --- drivers/spi/spi-pxa2xx-pci.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/drivers/spi/spi-pxa2xx-pci.c b/drivers/spi/spi-pxa2xx-pci.c index d49d8fef4088..616d032f1a89 100644 --- a/drivers/spi/spi-pxa2xx-pci.c +++ b/drivers/spi/spi-pxa2xx-pci.c @@ -145,10 +145,8 @@ static int lpss_spi_setup(struct pci_dev *dev, struct pxa2xx_spi_controller *c) c->num_chipselect = 1; ret = pxa2xx_spi_pci_clk_register(dev, ssp, 50000000); - if (ret) { - pci_dev_put(dma_dev); + if (ret) return ret; - } dma_dev = pci_get_slot(dev->bus, PCI_DEVFN(PCI_SLOT(dev->devfn), 0)); ret = devm_add_action_or_reset(&dev->dev, lpss_dma_put_device, dma_dev); @@ -223,10 +221,8 @@ static int mrfld_spi_setup(struct pci_dev *dev, struct pxa2xx_spi_controller *c) } ret = pxa2xx_spi_pci_clk_register(dev, ssp, 25000000); - if (ret) { - pci_dev_put(dma_dev); + if (ret) return ret; - } dma_dev = pci_get_slot(dev->bus, PCI_DEVFN(21, 0)); ret = devm_add_action_or_reset(&dev->dev, lpss_dma_put_device, dma_dev); From b0cdf9cc089525da330919d1bcd3b92655aaa621 Mon Sep 17 00:00:00 2001 From: Detlev Casanova Date: Tue, 3 Sep 2024 11:22:37 -0400 Subject: [PATCH 52/65] spi: dt-bindings: Add rockchip,rk3576-spi compatible It is compatible with the rockchip,rk3066-spi SPI core. Signed-off-by: Detlev Casanova Acked-by: Krzysztof Kozlowski Link: https://patch.msgid.link/20240903152308.13565-8-detlev.casanova@collabora.com Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/spi/spi-rockchip.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/spi/spi-rockchip.yaml b/Documentation/devicetree/bindings/spi/spi-rockchip.yaml index e4941e9212d1..46d9d6ee0923 100644 --- a/Documentation/devicetree/bindings/spi/spi-rockchip.yaml +++ b/Documentation/devicetree/bindings/spi/spi-rockchip.yaml @@ -35,6 +35,7 @@ properties: - rockchip,rk3368-spi - rockchip,rk3399-spi - rockchip,rk3568-spi + - rockchip,rk3576-spi - rockchip,rk3588-spi - rockchip,rv1126-spi - const: rockchip,rk3066-spi From 02774b14439dd5a8982335e779b62628d85eb76b Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Mon, 2 Sep 2024 15:46:55 -0300 Subject: [PATCH 53/65] spi: mxs: Switch to RUNTIME/SYSTEM_SLEEP_PM_OPS() Replace SET_RUNTIME_PM_OPS()/SET SYSTEM_SLEEP_PM_OPS() with their modern RUNTIME_PM_OPS() and SYSTEM_SLEEP_PM_OPS() alternatives. The combined usage of pm_ptr() and RUNTIME_PM_OPS/SYSTEM_SLEEP_PM_OPS() allows the compiler to evaluate if the runtime suspend/resume() functions are used at build time or are simply dead code. This allows removing the __maybe_unused annotations from the suspend/resume() functions. Signed-off-by: Fabio Estevam Link: https://patch.msgid.link/20240902184655.932699-1-festevam@gmail.com Signed-off-by: Mark Brown --- drivers/spi/spi-mxs.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/drivers/spi/spi-mxs.c b/drivers/spi/spi-mxs.c index 88cbe4f00cc3..3e341d1ff3b6 100644 --- a/drivers/spi/spi-mxs.c +++ b/drivers/spi/spi-mxs.c @@ -477,7 +477,7 @@ static int mxs_spi_runtime_resume(struct device *dev) return ret; } -static int __maybe_unused mxs_spi_suspend(struct device *dev) +static int mxs_spi_suspend(struct device *dev) { struct spi_controller *host = dev_get_drvdata(dev); int ret; @@ -492,7 +492,7 @@ static int __maybe_unused mxs_spi_suspend(struct device *dev) return 0; } -static int __maybe_unused mxs_spi_resume(struct device *dev) +static int mxs_spi_resume(struct device *dev) { struct spi_controller *host = dev_get_drvdata(dev); int ret; @@ -512,9 +512,8 @@ static int __maybe_unused mxs_spi_resume(struct device *dev) } static const struct dev_pm_ops mxs_spi_pm = { - SET_RUNTIME_PM_OPS(mxs_spi_runtime_suspend, - mxs_spi_runtime_resume, NULL) - SET_SYSTEM_SLEEP_PM_OPS(mxs_spi_suspend, mxs_spi_resume) + RUNTIME_PM_OPS(mxs_spi_runtime_suspend, mxs_spi_runtime_resume, NULL) + SYSTEM_SLEEP_PM_OPS(mxs_spi_suspend, mxs_spi_resume) }; static const struct of_device_id mxs_spi_dt_ids[] = { @@ -662,7 +661,7 @@ static struct platform_driver mxs_spi_driver = { .driver = { .name = DRIVER_NAME, .of_match_table = mxs_spi_dt_ids, - .pm = &mxs_spi_pm, + .pm = pm_ptr(&mxs_spi_pm), }, }; From dce35dd27684640508ff330b8235c4671159743e Mon Sep 17 00:00:00 2001 From: zhang jiao Date: Wed, 4 Sep 2024 15:35:50 +0800 Subject: [PATCH 54/65] spi: spidev_fdx: Fix the wrong format specifier The unsigned int should use "%u" instead of "%d". Signed-off-by: zhang jiao Link: https://patch.msgid.link/20240904073550.103618-1-zhangjiao2@cmss.chinamobile.com Signed-off-by: Mark Brown --- tools/spi/spidev_fdx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/spi/spidev_fdx.c b/tools/spi/spidev_fdx.c index 7d2a867cd4ae..bc9c4f6c3ba8 100644 --- a/tools/spi/spidev_fdx.c +++ b/tools/spi/spidev_fdx.c @@ -99,7 +99,7 @@ static void dumpstat(const char *name, int fd) return; } - printf("%s: spi mode 0x%x, %d bits %sper word, %d Hz max\n", + printf("%s: spi mode 0x%x, %d bits %sper word, %u Hz max\n", name, mode, bits, lsb ? "(lsb first) " : "", speed); } From 12736adc43b7cd5cb83f274f8f37b0f89d107c97 Mon Sep 17 00:00:00 2001 From: Haibo Chen Date: Thu, 5 Sep 2024 17:43:35 +0800 Subject: [PATCH 55/65] dt-bindings: spi: nxp-fspi: add imx8ulp support The flexspi on imx8ulp only has 16 number of LUTs, it is different with flexspi on other imx SoC which has 32 number of LUTs. Fixes: ef89fd56bdfc ("arm64: dts: imx8ulp: add flexspi node") Cc: stable@kernel.org Acked-by: Krzysztof Kozlowski Signed-off-by: Haibo Chen Reviewed-by: Frank Li Link: https://patch.msgid.link/20240905094338.1986871-2-haibo.chen@nxp.com Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/spi/spi-nxp-fspi.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/spi/spi-nxp-fspi.yaml b/Documentation/devicetree/bindings/spi/spi-nxp-fspi.yaml index 4a5f41bde00f..902db92da832 100644 --- a/Documentation/devicetree/bindings/spi/spi-nxp-fspi.yaml +++ b/Documentation/devicetree/bindings/spi/spi-nxp-fspi.yaml @@ -21,6 +21,7 @@ properties: - nxp,imx8mm-fspi - nxp,imx8mp-fspi - nxp,imx8qxp-fspi + - nxp,imx8ulp-fspi - nxp,lx2160a-fspi - items: - enum: From 190b7e2efb1ed8435fc7431d9c7a2447d05d5066 Mon Sep 17 00:00:00 2001 From: Haibo Chen Date: Thu, 5 Sep 2024 17:43:36 +0800 Subject: [PATCH 56/65] spi: fspi: involve lut_num for struct nxp_fspi_devtype_data The flexspi on different SoCs may have different number of LUTs. So involve lut_num in nxp_fspi_devtype_data to make distinguish. This patch prepare for the adding of imx8ulp. Fixes: ef89fd56bdfc ("arm64: dts: imx8ulp: add flexspi node") Cc: stable@kernel.org Signed-off-by: Haibo Chen Reviewed-by: Frank Li Link: https://patch.msgid.link/20240905094338.1986871-3-haibo.chen@nxp.com Signed-off-by: Mark Brown --- drivers/spi/spi-nxp-fspi.c | 44 ++++++++++++++++++++++---------------- 1 file changed, 25 insertions(+), 19 deletions(-) diff --git a/drivers/spi/spi-nxp-fspi.c b/drivers/spi/spi-nxp-fspi.c index fd1816befcd8..f42c14d80289 100644 --- a/drivers/spi/spi-nxp-fspi.c +++ b/drivers/spi/spi-nxp-fspi.c @@ -57,13 +57,6 @@ #include #include -/* - * The driver only uses one single LUT entry, that is updated on - * each call of exec_op(). Index 0 is preset at boot with a basic - * read operation, so let's use the last entry (31). - */ -#define SEQID_LUT 31 - /* Registers used by the driver */ #define FSPI_MCR0 0x00 #define FSPI_MCR0_AHB_TIMEOUT(x) ((x) << 24) @@ -263,9 +256,6 @@ #define FSPI_TFDR 0x180 #define FSPI_LUT_BASE 0x200 -#define FSPI_LUT_OFFSET (SEQID_LUT * 4 * 4) -#define FSPI_LUT_REG(idx) \ - (FSPI_LUT_BASE + FSPI_LUT_OFFSET + (idx) * 4) /* register map end */ @@ -341,6 +331,7 @@ struct nxp_fspi_devtype_data { unsigned int txfifo; unsigned int ahb_buf_size; unsigned int quirks; + unsigned int lut_num; bool little_endian; }; @@ -349,6 +340,7 @@ static struct nxp_fspi_devtype_data lx2160a_data = { .txfifo = SZ_1K, /* (128 * 64 bits) */ .ahb_buf_size = SZ_2K, /* (256 * 64 bits) */ .quirks = 0, + .lut_num = 32, .little_endian = true, /* little-endian */ }; @@ -357,6 +349,7 @@ static struct nxp_fspi_devtype_data imx8mm_data = { .txfifo = SZ_1K, /* (128 * 64 bits) */ .ahb_buf_size = SZ_2K, /* (256 * 64 bits) */ .quirks = 0, + .lut_num = 32, .little_endian = true, /* little-endian */ }; @@ -365,6 +358,7 @@ static struct nxp_fspi_devtype_data imx8qxp_data = { .txfifo = SZ_1K, /* (128 * 64 bits) */ .ahb_buf_size = SZ_2K, /* (256 * 64 bits) */ .quirks = 0, + .lut_num = 32, .little_endian = true, /* little-endian */ }; @@ -373,6 +367,7 @@ static struct nxp_fspi_devtype_data imx8dxl_data = { .txfifo = SZ_1K, /* (128 * 64 bits) */ .ahb_buf_size = SZ_2K, /* (256 * 64 bits) */ .quirks = FSPI_QUIRK_USE_IP_ONLY, + .lut_num = 32, .little_endian = true, /* little-endian */ }; @@ -544,6 +539,8 @@ static void nxp_fspi_prepare_lut(struct nxp_fspi *f, void __iomem *base = f->iobase; u32 lutval[4] = {}; int lutidx = 1, i; + u32 lut_offset = (f->devtype_data->lut_num - 1) * 4 * 4; + u32 target_lut_reg; /* cmd */ lutval[0] |= LUT_DEF(0, LUT_CMD, LUT_PAD(op->cmd.buswidth), @@ -588,8 +585,10 @@ static void nxp_fspi_prepare_lut(struct nxp_fspi *f, fspi_writel(f, FSPI_LCKER_UNLOCK, f->iobase + FSPI_LCKCR); /* fill LUT */ - for (i = 0; i < ARRAY_SIZE(lutval); i++) - fspi_writel(f, lutval[i], base + FSPI_LUT_REG(i)); + for (i = 0; i < ARRAY_SIZE(lutval); i++) { + target_lut_reg = FSPI_LUT_BASE + lut_offset + i * 4; + fspi_writel(f, lutval[i], base + target_lut_reg); + } dev_dbg(f->dev, "CMD[%02x] lutval[0:%08x 1:%08x 2:%08x 3:%08x], size: 0x%08x\n", op->cmd.opcode, lutval[0], lutval[1], lutval[2], lutval[3], op->data.nbytes); @@ -874,7 +873,7 @@ static int nxp_fspi_do_op(struct nxp_fspi *f, const struct spi_mem_op *op) void __iomem *base = f->iobase; int seqnum = 0; int err = 0; - u32 reg; + u32 reg, seqid_lut; reg = fspi_readl(f, base + FSPI_IPRXFCR); /* invalid RXFIFO first */ @@ -890,8 +889,9 @@ static int nxp_fspi_do_op(struct nxp_fspi *f, const struct spi_mem_op *op) * the LUT at each exec_op() call. And also specify the DATA * length, since it's has not been specified in the LUT. */ + seqid_lut = f->devtype_data->lut_num - 1; fspi_writel(f, op->data.nbytes | - (SEQID_LUT << FSPI_IPCR1_SEQID_SHIFT) | + (seqid_lut << FSPI_IPCR1_SEQID_SHIFT) | (seqnum << FSPI_IPCR1_SEQNUM_SHIFT), base + FSPI_IPCR1); @@ -1015,7 +1015,7 @@ static int nxp_fspi_default_setup(struct nxp_fspi *f) { void __iomem *base = f->iobase; int ret, i; - u32 reg; + u32 reg, seqid_lut; /* disable and unprepare clock to avoid glitch pass to controller */ nxp_fspi_clk_disable_unprep(f); @@ -1090,11 +1090,17 @@ static int nxp_fspi_default_setup(struct nxp_fspi *f) fspi_writel(f, reg, base + FSPI_FLSHB1CR1); fspi_writel(f, reg, base + FSPI_FLSHB2CR1); + /* + * The driver only uses one single LUT entry, that is updated on + * each call of exec_op(). Index 0 is preset at boot with a basic + * read operation, so let's use the last entry. + */ + seqid_lut = f->devtype_data->lut_num - 1; /* AHB Read - Set lut sequence ID for all CS. */ - fspi_writel(f, SEQID_LUT, base + FSPI_FLSHA1CR2); - fspi_writel(f, SEQID_LUT, base + FSPI_FLSHA2CR2); - fspi_writel(f, SEQID_LUT, base + FSPI_FLSHB1CR2); - fspi_writel(f, SEQID_LUT, base + FSPI_FLSHB2CR2); + fspi_writel(f, seqid_lut, base + FSPI_FLSHA1CR2); + fspi_writel(f, seqid_lut, base + FSPI_FLSHA2CR2); + fspi_writel(f, seqid_lut, base + FSPI_FLSHB1CR2); + fspi_writel(f, seqid_lut, base + FSPI_FLSHB2CR2); f->selected = -1; From 9228956a620553d7fd17f703a37a26c91e4d92ab Mon Sep 17 00:00:00 2001 From: Haibo Chen Date: Thu, 5 Sep 2024 17:43:37 +0800 Subject: [PATCH 57/65] spi: fspi: add support for imx8ulp The flexspi on imx8ulp only has 16 LUTs, different with others which have up to 32 LUTs. Add a separate compatible string and nxp_fspi_devtype_data to support flexspi on imx8ulp. Fixes: ef89fd56bdfc ("arm64: dts: imx8ulp: add flexspi node") Cc: stable@kernel.org Signed-off-by: Haibo Chen Reviewed-by: Frank Li Link: https://patch.msgid.link/20240905094338.1986871-4-haibo.chen@nxp.com Signed-off-by: Mark Brown --- drivers/spi/spi-nxp-fspi.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/spi/spi-nxp-fspi.c b/drivers/spi/spi-nxp-fspi.c index f42c14d80289..69e427b1903b 100644 --- a/drivers/spi/spi-nxp-fspi.c +++ b/drivers/spi/spi-nxp-fspi.c @@ -371,6 +371,15 @@ static struct nxp_fspi_devtype_data imx8dxl_data = { .little_endian = true, /* little-endian */ }; +static struct nxp_fspi_devtype_data imx8ulp_data = { + .rxfifo = SZ_512, /* (64 * 64 bits) */ + .txfifo = SZ_1K, /* (128 * 64 bits) */ + .ahb_buf_size = SZ_2K, /* (256 * 64 bits) */ + .quirks = 0, + .lut_num = 16, + .little_endian = true, /* little-endian */ +}; + struct nxp_fspi { void __iomem *iobase; void __iomem *ahb_addr; @@ -1295,6 +1304,7 @@ static const struct of_device_id nxp_fspi_dt_ids[] = { { .compatible = "nxp,imx8mp-fspi", .data = (void *)&imx8mm_data, }, { .compatible = "nxp,imx8qxp-fspi", .data = (void *)&imx8qxp_data, }, { .compatible = "nxp,imx8dxl-fspi", .data = (void *)&imx8dxl_data, }, + { .compatible = "nxp,imx8ulp-fspi", .data = (void *)&imx8ulp_data, }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, nxp_fspi_dt_ids); From 1e0cc8d0a14271fbf6a50e680c8020458121a52b Mon Sep 17 00:00:00 2001 From: Yang Yingliang Date: Tue, 10 Sep 2024 10:26:11 +0800 Subject: [PATCH 58/65] spi: switch to use spi_controller_is_target() Switch to use modern name function spi_controller_is_target(). No functional changed. Signed-off-by: Yang Yingliang Link: https://patch.msgid.link/20240910022618.1397-2-yangyingliang@huaweicloud.com Signed-off-by: Mark Brown --- drivers/spi/spi.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index 60a2b5a0c85d..ea14c33bc831 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -1440,7 +1440,7 @@ static int spi_transfer_wait(struct spi_controller *ctlr, u32 speed_hz = xfer->speed_hz; unsigned long long ms; - if (spi_controller_is_slave(ctlr)) { + if (spi_controller_is_target(ctlr)) { if (wait_for_completion_interruptible(&ctlr->xfer_completion)) { dev_dbg(&msg->spi->dev, "SPI transfer interrupted\n"); return -EINTR; @@ -2425,7 +2425,7 @@ static int of_spi_parse_dt(struct spi_controller *ctlr, struct spi_device *spi, } } - if (spi_controller_is_slave(ctlr)) { + if (spi_controller_is_target(ctlr)) { if (!of_node_name_eq(nc, "slave")) { dev_err(&ctlr->dev, "%pOF is not called 'slave'\n", nc); @@ -3321,7 +3321,7 @@ int spi_register_controller(struct spi_controller *ctlr) */ dev_set_name(&ctlr->dev, "spi%u", ctlr->bus_num); - if (!spi_controller_is_slave(ctlr) && ctlr->use_gpio_descriptors) { + if (!spi_controller_is_target(ctlr) && ctlr->use_gpio_descriptors) { status = spi_get_gpio_descs(ctlr); if (status) goto free_bus_id; @@ -3349,7 +3349,7 @@ int spi_register_controller(struct spi_controller *ctlr) if (status < 0) goto free_bus_id; dev_dbg(dev, "registered %s %s\n", - spi_controller_is_slave(ctlr) ? "slave" : "master", + spi_controller_is_target(ctlr) ? "target" : "host", dev_name(&ctlr->dev)); /* From 6adfdf0780a7a8a8b185af62302317ab20f1d066 Mon Sep 17 00:00:00 2001 From: Yang Yingliang Date: Tue, 10 Sep 2024 10:26:12 +0800 Subject: [PATCH 59/65] spi: slave-time: switch to use spi_target_abort() Switch to use modern name function spi_target_abort(). No functional changed. Signed-off-by: Yang Yingliang Link: https://patch.msgid.link/20240910022618.1397-3-yangyingliang@huaweicloud.com Signed-off-by: Mark Brown --- drivers/spi/spi-slave-time.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/spi/spi-slave-time.c b/drivers/spi/spi-slave-time.c index f56c1afb8534..8bb3070e4b80 100644 --- a/drivers/spi/spi-slave-time.c +++ b/drivers/spi/spi-slave-time.c @@ -110,7 +110,7 @@ static void spi_slave_time_remove(struct spi_device *spi) { struct spi_slave_time_priv *priv = spi_get_drvdata(spi); - spi_slave_abort(spi); + spi_target_abort(spi); wait_for_completion(&priv->finished); } From f4bf5454f852b86d3b4be69f058fd36a61cd81bf Mon Sep 17 00:00:00 2001 From: Yang Yingliang Date: Tue, 10 Sep 2024 10:26:13 +0800 Subject: [PATCH 60/65] spi: slave-system-control: switch to use spi_target_abort() Switch to use modern name function spi_target_abort(). No functional changed. Signed-off-by: Yang Yingliang Link: https://patch.msgid.link/20240910022618.1397-4-yangyingliang@huaweicloud.com Signed-off-by: Mark Brown --- drivers/spi/spi-slave-system-control.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/spi/spi-slave-system-control.c b/drivers/spi/spi-slave-system-control.c index d37cfe995a63..8f5c32b61a5b 100644 --- a/drivers/spi/spi-slave-system-control.c +++ b/drivers/spi/spi-slave-system-control.c @@ -136,7 +136,7 @@ static void spi_slave_system_control_remove(struct spi_device *spi) { struct spi_slave_system_control_priv *priv = spi_get_drvdata(spi); - spi_slave_abort(spi); + spi_target_abort(spi); wait_for_completion(&priv->finished); } From 94628e5a07e71089a61951eb2d2e13685ff82760 Mon Sep 17 00:00:00 2001 From: Yang Yingliang Date: Tue, 10 Sep 2024 10:26:14 +0800 Subject: [PATCH 61/65] spi: spidev: switch to use spi_target_abort() Switch to use modern name function spi_target_abort(). No functional changed. Signed-off-by: Yang Yingliang Link: https://patch.msgid.link/20240910022618.1397-5-yangyingliang@huaweicloud.com Signed-off-by: Mark Brown --- drivers/spi/spidev.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/spi/spidev.c b/drivers/spi/spidev.c index 1927175c8095..d5dbd1a88af9 100644 --- a/drivers/spi/spidev.c +++ b/drivers/spi/spidev.c @@ -666,7 +666,7 @@ static int spidev_release(struct inode *inode, struct file *filp) } #ifdef CONFIG_SPI_SLAVE if (!dofree) - spi_slave_abort(spidev->spi); + spi_target_abort(spidev->spi); #endif mutex_unlock(&device_list_lock); From be03763d247649b39e62ec55efecb1e7499e2e7f Mon Sep 17 00:00:00 2001 From: Yang Yingliang Date: Tue, 10 Sep 2024 10:26:15 +0800 Subject: [PATCH 62/65] spi: slave-mt27xx: switch to use target_abort Switch to use modern name target_abort. No functional changed. Signed-off-by: Yang Yingliang Link: https://patch.msgid.link/20240910022618.1397-6-yangyingliang@huaweicloud.com Signed-off-by: Mark Brown --- drivers/spi/spi-slave-mt27xx.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/spi/spi-slave-mt27xx.c b/drivers/spi/spi-slave-mt27xx.c index f1ddf4c099a3..4a91b7bae3c6 100644 --- a/drivers/spi/spi-slave-mt27xx.c +++ b/drivers/spi/spi-slave-mt27xx.c @@ -69,7 +69,7 @@ struct mtk_spi_slave { struct clk *spi_clk; struct completion xfer_done; struct spi_transfer *cur_transfer; - bool slave_aborted; + bool target_aborted; const struct mtk_spi_compatible *dev_comp; }; @@ -118,7 +118,7 @@ static void mtk_spi_slave_disable_xfer(struct mtk_spi_slave *mdata) static int mtk_spi_slave_wait_for_completion(struct mtk_spi_slave *mdata) { if (wait_for_completion_interruptible(&mdata->xfer_done) || - mdata->slave_aborted) { + mdata->target_aborted) { dev_err(mdata->dev, "interrupted\n"); return -EINTR; } @@ -286,7 +286,7 @@ static int mtk_spi_slave_transfer_one(struct spi_controller *ctlr, struct mtk_spi_slave *mdata = spi_controller_get_devdata(ctlr); reinit_completion(&mdata->xfer_done); - mdata->slave_aborted = false; + mdata->target_aborted = false; mdata->cur_transfer = xfer; if (xfer->len > mdata->dev_comp->max_fifo_size) @@ -314,11 +314,11 @@ static int mtk_spi_slave_setup(struct spi_device *spi) return 0; } -static int mtk_slave_abort(struct spi_controller *ctlr) +static int mtk_target_abort(struct spi_controller *ctlr) { struct mtk_spi_slave *mdata = spi_controller_get_devdata(ctlr); - mdata->slave_aborted = true; + mdata->target_aborted = true; complete(&mdata->xfer_done); return 0; @@ -402,7 +402,7 @@ static int mtk_spi_slave_probe(struct platform_device *pdev) ctlr->prepare_message = mtk_spi_slave_prepare_message; ctlr->transfer_one = mtk_spi_slave_transfer_one; ctlr->setup = mtk_spi_slave_setup; - ctlr->slave_abort = mtk_slave_abort; + ctlr->target_abort = mtk_target_abort; of_id = of_match_node(mtk_spi_slave_of_match, pdev->dev.of_node); if (!of_id) { From 5b2e4d15154cb75e522701c13f66441e29f2caa8 Mon Sep 17 00:00:00 2001 From: Yang Yingliang Date: Tue, 10 Sep 2024 10:26:16 +0800 Subject: [PATCH 63/65] platform/olpc: olpc-xo175-ec: switch to use spi_target_abort(). Switch to use modern name function spi_target_abort(). No functional changed. Signed-off-by: Yang Yingliang Acked-by: Hans de Goede Link: https://patch.msgid.link/20240910022618.1397-7-yangyingliang@huaweicloud.com Signed-off-by: Mark Brown --- drivers/platform/olpc/olpc-xo175-ec.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/platform/olpc/olpc-xo175-ec.c b/drivers/platform/olpc/olpc-xo175-ec.c index 62ccbcb15c74..fa7b3bda688a 100644 --- a/drivers/platform/olpc/olpc-xo175-ec.c +++ b/drivers/platform/olpc/olpc-xo175-ec.c @@ -536,7 +536,7 @@ static int olpc_xo175_ec_cmd(u8 cmd, u8 *inbuf, size_t inlen, u8 *resp, dev_err(dev, "EC cmd error: timeout in STATE %d\n", priv->cmd_state); gpiod_set_value_cansleep(priv->gpio_cmd, 0); - spi_slave_abort(priv->spi); + spi_target_abort(priv->spi); olpc_xo175_ec_read_packet(priv); return -ETIMEDOUT; } @@ -653,7 +653,7 @@ static void olpc_xo175_ec_remove(struct spi_device *spi) if (pm_power_off == olpc_xo175_ec_power_off) pm_power_off = NULL; - spi_slave_abort(spi); + spi_target_abort(spi); platform_device_unregister(olpc_ec); olpc_ec = NULL; From 740c1c84bfa3d8c63bd3b01fb570e7452f51fbd8 Mon Sep 17 00:00:00 2001 From: Yang Yingliang Date: Tue, 10 Sep 2024 10:26:17 +0800 Subject: [PATCH 64/65] spi: remove spi_controller_is_slave() and spi_slave_abort() spi_controller_is_slave() and spi_slave_abort() are all replaced, so they can be removed. No functional changed. Signed-off-by: Yang Yingliang Link: https://patch.msgid.link/20240910022618.1397-8-yangyingliang@huaweicloud.com Signed-off-by: Mark Brown --- drivers/spi/spi.c | 13 +------------ include/linux/spi/spi.h | 12 +----------- 2 files changed, 2 insertions(+), 23 deletions(-) diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index ea14c33bc831..c1dad30a4528 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -2934,21 +2934,10 @@ static struct class spi_master_class = { #ifdef CONFIG_SPI_SLAVE /** - * spi_slave_abort - abort the ongoing transfer request on an SPI slave + * spi_target_abort - abort the ongoing transfer request on an SPI slave * controller * @spi: device used for the current transfer */ -int spi_slave_abort(struct spi_device *spi) -{ - struct spi_controller *ctlr = spi->controller; - - if (spi_controller_is_slave(ctlr) && ctlr->slave_abort) - return ctlr->slave_abort(ctlr); - - return -ENOTSUPP; -} -EXPORT_SYMBOL_GPL(spi_slave_abort); - int spi_target_abort(struct spi_device *spi) { struct spi_controller *ctlr = spi->controller; diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h index d47d5f14ff99..4b95663163e0 100644 --- a/include/linux/spi/spi.h +++ b/include/linux/spi/spi.h @@ -498,7 +498,6 @@ extern struct spi_device *spi_new_ancillary_device(struct spi_device *spi, u8 ch * controller has native support for memory like operations. * @mem_caps: controller capabilities for the handling of memory operations. * @unprepare_message: undo any work done by prepare_message(). - * @slave_abort: abort the ongoing transfer request on an SPI slave controller * @target_abort: abort the ongoing transfer request on an SPI target controller * @cs_gpiods: Array of GPIO descriptors to use as chip select lines; one per CS * number. Any individual value may be NULL for CS lines that @@ -725,10 +724,7 @@ struct spi_controller { struct spi_message *message); int (*unprepare_message)(struct spi_controller *ctlr, struct spi_message *message); - union { - int (*slave_abort)(struct spi_controller *ctlr); - int (*target_abort)(struct spi_controller *ctlr); - }; + int (*target_abort)(struct spi_controller *ctlr); /* * These hooks are for drivers that use a generic implementation @@ -802,11 +798,6 @@ static inline void spi_controller_put(struct spi_controller *ctlr) put_device(&ctlr->dev); } -static inline bool spi_controller_is_slave(struct spi_controller *ctlr) -{ - return IS_ENABLED(CONFIG_SPI_SLAVE) && ctlr->slave; -} - static inline bool spi_controller_is_target(struct spi_controller *ctlr) { return IS_ENABLED(CONFIG_SPI_SLAVE) && ctlr->target; @@ -1296,7 +1287,6 @@ extern int devm_spi_optimize_message(struct device *dev, struct spi_device *spi, extern int spi_setup(struct spi_device *spi); extern int spi_async(struct spi_device *spi, struct spi_message *message); -extern int spi_slave_abort(struct spi_device *spi); extern int spi_target_abort(struct spi_device *spi); static inline size_t From 07f1eb718db281c3e0cdb068ea7d73c30921a81c Mon Sep 17 00:00:00 2001 From: Jinjie Ruan Date: Thu, 12 Sep 2024 17:17:01 +0800 Subject: [PATCH 65/65] spi: geni-qcom: Use devm functions to simplify code Use devm_pm_runtime_enable(), devm_request_irq() and devm_spi_register_controller() to simplify code. And also register a callback spi_geni_release_dma_chan() with devm_add_action_or_reset(), to release dma channel in both error and device detach path, which can make sure the release sequence is consistent with the original one. 1. Unregister spi controller. 2. Free the IRQ. 3. Free DMA chans 4. Disable runtime PM. So the remove function can also be removed. Reviewed-by: Douglas Anderson Suggested-by: Doug Anderson Signed-off-by: Jinjie Ruan Link: https://patch.msgid.link/20240912091701.3720857-1-ruanjinjie@huawei.com Signed-off-by: Mark Brown --- drivers/spi/spi-geni-qcom.c | 63 ++++++++++++++----------------------- 1 file changed, 24 insertions(+), 39 deletions(-) diff --git a/drivers/spi/spi-geni-qcom.c b/drivers/spi/spi-geni-qcom.c index 6f4057330444..f6e40f90418f 100644 --- a/drivers/spi/spi-geni-qcom.c +++ b/drivers/spi/spi-geni-qcom.c @@ -604,6 +604,21 @@ static int spi_geni_prepare_message(struct spi_controller *spi, return -EINVAL; } +static void spi_geni_release_dma_chan(void *data) +{ + struct spi_geni_master *mas = data; + + if (mas->rx) { + dma_release_channel(mas->rx); + mas->rx = NULL; + } + + if (mas->tx) { + dma_release_channel(mas->tx); + mas->tx = NULL; + } +} + static int spi_geni_grab_gpi_chan(struct spi_geni_master *mas) { int ret; @@ -622,6 +637,12 @@ static int spi_geni_grab_gpi_chan(struct spi_geni_master *mas) goto err_rx; } + ret = devm_add_action_or_reset(mas->dev, spi_geni_release_dma_chan, mas); + if (ret) { + dev_err(mas->dev, "Unable to add action.\n"); + return ret; + } + return 0; err_rx: @@ -632,19 +653,6 @@ err_tx: return ret; } -static void spi_geni_release_dma_chan(struct spi_geni_master *mas) -{ - if (mas->rx) { - dma_release_channel(mas->rx); - mas->rx = NULL; - } - - if (mas->tx) { - dma_release_channel(mas->tx); - mas->tx = NULL; - } -} - static int spi_geni_init(struct spi_geni_master *mas) { struct spi_controller *spi = dev_get_drvdata(mas->dev); @@ -1146,33 +1154,11 @@ static int spi_geni_probe(struct platform_device *pdev) if (mas->cur_xfer_mode == GENI_GPI_DMA) spi->flags = SPI_CONTROLLER_MUST_TX; - ret = request_irq(mas->irq, geni_spi_isr, 0, dev_name(dev), spi); + ret = devm_request_irq(dev, mas->irq, geni_spi_isr, 0, dev_name(dev), spi); if (ret) - goto spi_geni_release_dma; + return ret; - ret = spi_register_controller(spi); - if (ret) - goto spi_geni_probe_free_irq; - - return 0; -spi_geni_probe_free_irq: - free_irq(mas->irq, spi); -spi_geni_release_dma: - spi_geni_release_dma_chan(mas); - return ret; -} - -static void spi_geni_remove(struct platform_device *pdev) -{ - struct spi_controller *spi = platform_get_drvdata(pdev); - struct spi_geni_master *mas = spi_controller_get_devdata(spi); - - /* Unregister _before_ disabling pm_runtime() so we stop transfers */ - spi_unregister_controller(spi); - - free_irq(mas->irq, spi); - - spi_geni_release_dma_chan(mas); + return devm_spi_register_controller(dev, spi); } static int __maybe_unused spi_geni_runtime_suspend(struct device *dev) @@ -1254,7 +1240,6 @@ MODULE_DEVICE_TABLE(of, spi_geni_dt_match); static struct platform_driver spi_geni_driver = { .probe = spi_geni_probe, - .remove_new = spi_geni_remove, .driver = { .name = "geni_spi", .pm = &spi_geni_pm_ops,