From 6cf3c0f84d40847843f86e8ead58c92602b2d80d Mon Sep 17 00:00:00 2001 From: Ji Sheng Teoh Date: Wed, 8 May 2024 13:47:27 +0800 Subject: spi: spi-cadence: Add optional reset control support Add optional reset control support for spi-cadence to properly bring the SPI device into an operating condition. Co-developed-by: Eng Lee Teh Signed-off-by: Eng Lee Teh Co-developed-by: Ley Foon Tan Signed-off-by: Ley Foon Tan Signed-off-by: Ji Sheng Teoh Link: https://msgid.link/r/20240508054728.1751162-2-jisheng.teoh@starfivetech.com Signed-off-by: Mark Brown --- drivers/spi/spi-cadence.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/drivers/spi/spi-cadence.c b/drivers/spi/spi-cadence.c index e5140532071d..4eacf3f6e031 100644 --- a/drivers/spi/spi-cadence.c +++ b/drivers/spi/spi-cadence.c @@ -18,6 +18,7 @@ #include #include #include +#include #include /* Name of this driver */ @@ -111,6 +112,7 @@ * @dev_busy: Device busy flag * @is_decoded_cs: Flag for decoder property set or not * @tx_fifo_depth: Depth of the TX FIFO + * @rstc: Optional reset control for SPI controller */ struct cdns_spi { void __iomem *regs; @@ -125,6 +127,7 @@ struct cdns_spi { u8 dev_busy; u32 is_decoded_cs; unsigned int tx_fifo_depth; + struct reset_control *rstc; }; /* Macros for the SPI controller read/write */ @@ -588,6 +591,16 @@ static int cdns_spi_probe(struct platform_device *pdev) goto remove_ctlr; } + xspi->rstc = devm_reset_control_get_optional_exclusive(&pdev->dev, "spi"); + if (IS_ERR(xspi->rstc)) { + ret = dev_err_probe(&pdev->dev, PTR_ERR(xspi->rstc), + "Cannot get SPI reset.\n"); + goto remove_ctlr; + } + + reset_control_assert(xspi->rstc); + reset_control_deassert(xspi->rstc); + if (!spi_controller_is_target(ctlr)) { xspi->ref_clk = devm_clk_get_enabled(&pdev->dev, "ref_clk"); if (IS_ERR(xspi->ref_clk)) { -- cgit v1.2.3 From 837e53f766fe9423fcb4e0eacbb3b7ff0e33103c Mon Sep 17 00:00:00 2001 From: Ji Sheng Teoh Date: Wed, 8 May 2024 13:47:28 +0800 Subject: spi: dt-bindings: spi-cadence: Add optional reset control Document the optional reset control to SPI. Co-developed-by: Eng Lee Teh Signed-off-by: Eng Lee Teh Co-developed-by: Ley Foon Tan Signed-off-by: Ley Foon Tan Signed-off-by: Ji Sheng Teoh Reviewed-by: Krzysztof Kozlowski Link: https://msgid.link/r/20240508054728.1751162-3-jisheng.teoh@starfivetech.com Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/spi/spi-cadence.yaml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Documentation/devicetree/bindings/spi/spi-cadence.yaml b/Documentation/devicetree/bindings/spi/spi-cadence.yaml index d4b61b0e8301..8de96abe9da1 100644 --- a/Documentation/devicetree/bindings/spi/spi-cadence.yaml +++ b/Documentation/devicetree/bindings/spi/spi-cadence.yaml @@ -55,6 +55,13 @@ properties: label: description: Descriptive name of the SPI controller. + resets: + maxItems: 1 + + reset-names: + items: + - const: spi + required: - compatible - reg -- cgit v1.2.3 From 19a9aa9302276d49a4c4890f656359808d3a0151 Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Wed, 22 May 2024 16:52:52 +0200 Subject: spi: dw: differentiate between unsupported and invalid requests The driver does not support dirmap write operations, return -EOPTNOTSUPP in this case. Most controllers have a maximum linear mapping area. Requests beyond this limit can be considered invalid, rather than unsupported. >From a caller (and reviewer) point of view, distinguising between the two may be helpful because somehow one can be "fixed" while the other will always be refused no matter how hard we try. As part of a wider work to bring spi-nand continuous reads, it was useful to easily catch the upper limit direct mapping boundaries for each controller, with the idea of enlarging this area from a page to an eraseblock, without risking too many regressions. Signed-off-by: Miquel Raynal Link: https://msgid.link/r/20240522145255.995778-2-miquel.raynal@bootlin.com Signed-off-by: Mark Brown --- drivers/spi/spi-dw-bt1.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/spi/spi-dw-bt1.c b/drivers/spi/spi-dw-bt1.c index 5391bcac305c..4577e8096cd9 100644 --- a/drivers/spi/spi-dw-bt1.c +++ b/drivers/spi/spi-dw-bt1.c @@ -55,13 +55,15 @@ static int dw_spi_bt1_dirmap_create(struct spi_mem_dirmap_desc *desc) !dwsbt1->dws.mem_ops.supports_op(desc->mem, &desc->info.op_tmpl)) return -EOPNOTSUPP; + if (desc->info.op_tmpl.data.dir != SPI_MEM_DATA_IN) + return -EOPNOTSUPP; + /* * Make sure the requested region doesn't go out of the physically - * mapped flash memory bounds and the operation is read-only. + * mapped flash memory bounds. */ - if (desc->info.offset + desc->info.length > dwsbt1->map_len || - desc->info.op_tmpl.data.dir != SPI_MEM_DATA_IN) - return -EOPNOTSUPP; + if (desc->info.offset + desc->info.length > dwsbt1->map_len) + return -EINVAL; return 0; } -- cgit v1.2.3 From 5e657a8e660c0fcafa83527d3a7f4f447f4a9364 Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Wed, 22 May 2024 16:52:53 +0200 Subject: spi: mxic: differentiate between unsupported and invalid requests If the request is out of range, returning -EINVAL seems sensible. However if there is no direct mapping available (which is a possible case), no direct mapping will ever be allowed, hence -EOPNOTSUP is probably more relevant in this case. >From a caller (and reviewer) point of view, distinguising between the two may be helpful because somehow one can be "fixed" while the other will always be refused no matter how hard we try. As part of a wider work to bring spi-nand continuous reads, it was useful to easily catch the upper limit direct mapping boundaries for each controller, with the idea of enlarging this area from a page to an eraseblock, without risking too many regressions. Signed-off-by: Miquel Raynal Link: https://msgid.link/r/20240522145255.995778-3-miquel.raynal@bootlin.com Signed-off-by: Mark Brown --- drivers/spi/spi-mxic.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/spi/spi-mxic.c b/drivers/spi/spi-mxic.c index 60c9f3048ac9..6156d691630a 100644 --- a/drivers/spi/spi-mxic.c +++ b/drivers/spi/spi-mxic.c @@ -496,7 +496,7 @@ static int mxic_spi_mem_dirmap_create(struct spi_mem_dirmap_desc *desc) struct mxic_spi *mxic = spi_controller_get_devdata(desc->mem->spi->controller); if (!mxic->linear.map) - return -EINVAL; + return -EOPNOTSUPP; if (desc->info.offset + desc->info.length > U32_MAX) return -EINVAL; -- cgit v1.2.3 From 615725a9a8c8aa0976a1469b88a1e5d696e25eb0 Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Wed, 22 May 2024 16:52:54 +0200 Subject: spi: rpc-if: differentiate between unsupported and invalid requests If the request is out of range, returning -EINVAL seems a better pick than -ENOTSUPP. >From a caller (and reviewer) point of view, distinguising between the two may be helpful because somehow one can be "fixed" while the other will always be refused no matter how hard we try. As part of a wider work to bring spi-nand continuous reads, it was useful to easily catch the upper limit direct mapping boundaries for each controller, with the idea of enlarging this area from a page to an eraseblock, without risking too many regressions. In all other cases, as part of a wider work towards using -EOPNOTSUP rather than -ENOTSUPP (which is not a SUSV4 code), let's change the error code to be uniform across spi-mem controller drivers. Finally, reword a little bit the conditions to clarify what is intended (ie. checking for the presence of a direct mapping, and also ensuring we create a dirmap only on DATA_IN flows). Signed-off-by: Miquel Raynal Link: https://msgid.link/r/20240522145255.995778-4-miquel.raynal@bootlin.com Signed-off-by: Mark Brown --- drivers/spi/spi-rpc-if.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/spi/spi-rpc-if.c b/drivers/spi/spi-rpc-if.c index e11146932828..d3f07fd719bd 100644 --- a/drivers/spi/spi-rpc-if.c +++ b/drivers/spi/spi-rpc-if.c @@ -95,16 +95,16 @@ static int rpcif_spi_mem_dirmap_create(struct spi_mem_dirmap_desc *desc) spi_controller_get_devdata(desc->mem->spi->controller); if (desc->info.offset + desc->info.length > U32_MAX) - return -ENOTSUPP; + return -EINVAL; if (!rpcif_spi_mem_supports_op(desc->mem, &desc->info.op_tmpl)) - return -ENOTSUPP; + return -EOPNOTSUPP; - if (!rpc->dirmap && desc->info.op_tmpl.data.dir == SPI_MEM_DATA_IN) - return -ENOTSUPP; + if (!rpc->dirmap) + return -EOPNOTSUPP; - if (desc->info.op_tmpl.data.dir == SPI_MEM_DATA_OUT) - return -ENOTSUPP; + if (desc->info.op_tmpl.data.dir != SPI_MEM_DATA_IN) + return -EOPNOTSUPP; return 0; } -- cgit v1.2.3 From 41b86b1455079600fa2b13e59f7c6f256d1d3131 Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Wed, 22 May 2024 16:52:55 +0200 Subject: spi: wpcm-fiu: differentiate between unsupported and invalid requests When the requested dirmap accesses are outside of the window, it is probably more sensible to return -EINVAL rather than an "unsupported" error code. If however the operation in itself is not supported, then -EOPNOTSUP is likely going to be preferred as it is a standard error code. >From a caller (and reviewer) point of view, distinguising between the two may be helpful because somehow one can be "fixed" while the other will always be refused no matter how hard we try. As part of a wider work to bring spi-nand continuous reads, it was useful to easily catch the upper limit direct mapping boundaries for each controller, with the idea of enlarging this area from a page to an eraseblock, without risking too many regressions. Signed-off-by: Miquel Raynal Link: https://msgid.link/r/20240522145255.995778-5-miquel.raynal@bootlin.com Signed-off-by: Mark Brown --- drivers/spi/spi-wpcm-fiu.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/spi/spi-wpcm-fiu.c b/drivers/spi/spi-wpcm-fiu.c index 6b16a22cc3a4..886d6d7771d4 100644 --- a/drivers/spi/spi-wpcm-fiu.c +++ b/drivers/spi/spi-wpcm-fiu.c @@ -378,7 +378,7 @@ static int wpcm_fiu_dirmap_create(struct spi_mem_dirmap_desc *desc) int cs = spi_get_chipselect(desc->mem->spi, 0); if (desc->info.op_tmpl.data.dir != SPI_MEM_DATA_IN) - return -ENOTSUPP; + return -EOPNOTSUPP; /* * Unfortunately, FIU only supports a 16 MiB direct mapping window (per @@ -387,11 +387,11 @@ static int wpcm_fiu_dirmap_create(struct spi_mem_dirmap_desc *desc) * flashes that are bigger than 16 MiB. */ if (desc->info.offset + desc->info.length > MAX_MEMORY_SIZE_PER_CS) - return -ENOTSUPP; + return -EINVAL; /* Don't read past the memory window */ if (cs * MAX_MEMORY_SIZE_PER_CS + desc->info.offset + desc->info.length > fiu->memory_size) - return -ENOTSUPP; + return -EINVAL; return 0; } -- cgit v1.2.3 From 3b4c0fbc19930af0904fb5995ed4e7b6ffe0b237 Mon Sep 17 00:00:00 2001 From: Prajna Rajendra Kumar Date: Tue, 14 May 2024 11:45:06 +0100 Subject: spi: dt-bindings: Add num-cs property for mpfs-spi The PolarFire SoC SPI "hard" controller supports eight CS lines, out of which only one CS line is physically wired. The default value of 'num-cs' was never set and it did not didn't impose a maximum value. To reflect this hardware limitation in the device tree, the binding enforces that the 'num-cs' property cannot exceed 1 unless additional CS lines are explicitly defined using GPIO descriptors. Fixes: 2da187304e55 ("spi: add bindings for microchip mpfs spi") Signed-off-by: Prajna Rajendra Kumar Link: https://msgid.link/r/20240514104508.938448-2-prajna.rajendrakumar@microchip.com Reviewed-by: Conor Dooley Signed-off-by: Mark Brown --- .../bindings/spi/microchip,mpfs-spi.yaml | 29 +++++++++++++++++++--- 1 file changed, 26 insertions(+), 3 deletions(-) diff --git a/Documentation/devicetree/bindings/spi/microchip,mpfs-spi.yaml b/Documentation/devicetree/bindings/spi/microchip,mpfs-spi.yaml index 74a817cc7d94..ffa8d1b48f8b 100644 --- a/Documentation/devicetree/bindings/spi/microchip,mpfs-spi.yaml +++ b/Documentation/devicetree/bindings/spi/microchip,mpfs-spi.yaml @@ -13,9 +13,6 @@ description: maintainers: - Conor Dooley -allOf: - - $ref: spi-controller.yaml# - properties: compatible: oneOf: @@ -43,6 +40,32 @@ required: - interrupts - clocks +allOf: + - $ref: spi-controller.yaml# + + - if: + properties: + compatible: + contains: + const: microchip,mpfs-spi + then: + properties: + num-cs: + default: 1 + + - if: + properties: + compatible: + contains: + const: microchip,mpfs-spi + not: + required: + - cs-gpios + then: + properties: + num-cs: + maximum: 1 + unevaluatedProperties: false examples: -- cgit v1.2.3 From a7ed3a11202d90939a3d00ffcc8cf50703cb7b35 Mon Sep 17 00:00:00 2001 From: Prajna Rajendra Kumar Date: Tue, 14 May 2024 11:45:07 +0100 Subject: spi: spi-microchip-core: Fix the number of chip selects supported The SPI "hard" controller in PolarFire SoC has eight CS lines, but only one CS line is wired. When the 'num-cs' property is not specified in the device tree, the driver defaults to the MAX_CS value, which has been fixed to 1 to match the hardware configuration; however, when the 'num-cs' property is explicitly defined in the device tree, it overrides the default value. Fixes: 9ac8d17694b6 ("spi: add support for microchip fpga spi controllers") Signed-off-by: Prajna Rajendra Kumar Reviewed-by: Conor Dooley Link: https://msgid.link/r/20240514104508.938448-3-prajna.rajendrakumar@microchip.com Signed-off-by: Mark Brown --- drivers/spi/spi-microchip-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/spi/spi-microchip-core.c b/drivers/spi/spi-microchip-core.c index 634364c7cfe6..c10de45aa472 100644 --- a/drivers/spi/spi-microchip-core.c +++ b/drivers/spi/spi-microchip-core.c @@ -21,7 +21,7 @@ #include #define MAX_LEN (0xffff) -#define MAX_CS (8) +#define MAX_CS (1) #define DEFAULT_FRAMESIZE (8) #define FIFO_DEPTH (32) #define CLK_GEN_MODE1_MAX (255) -- cgit v1.2.3 From 9c84429324ea2b5bc537ef8ec7d3727579d37116 Mon Sep 17 00:00:00 2001 From: Prajna Rajendra Kumar Date: Tue, 14 May 2024 11:45:08 +0100 Subject: spi: spi-microchip-core: Add support for GPIO based CS The SPI "hard" controller within the PolarFire SoC is capable of handling eight CS lines, but only one CS line is wired. Therefore, use GPIO descriptors to configure additional CS lines. Signed-off-by: Prajna Rajendra Kumar Link: https://msgid.link/r/20240514104508.938448-4-prajna.rajendrakumar@microchip.com Acked-by: Conor Dooley Signed-off-by: Mark Brown --- drivers/spi/spi-microchip-core.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/spi/spi-microchip-core.c b/drivers/spi/spi-microchip-core.c index c10de45aa472..6246254e1dff 100644 --- a/drivers/spi/spi-microchip-core.c +++ b/drivers/spi/spi-microchip-core.c @@ -258,6 +258,9 @@ static int mchp_corespi_setup(struct spi_device *spi) struct mchp_corespi *corespi = spi_controller_get_devdata(spi->controller); u32 reg; + if (spi_is_csgpiod(spi)) + return 0; + /* * Active high targets need to be specifically set to their inactive * states during probe by adding them to the "control group" & thus @@ -516,6 +519,7 @@ static int mchp_corespi_probe(struct platform_device *pdev) host->num_chipselect = num_cs; host->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH; + host->use_gpio_descriptors = true; host->setup = mchp_corespi_setup; host->bits_per_word_mask = SPI_BPW_MASK(8); host->transfer_one = mchp_corespi_transfer_one; -- cgit v1.2.3 From f261172d39f358dcecce13c310690d3937e0cca6 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 17 May 2024 22:40:20 +0300 Subject: spi: bitbang: Use typedef for txrx_*() callbacks With a typedef for the txrx_*() callbacks the code looks neater. Note that typedef for a function is okay to have. Signed-off-by: Andy Shevchenko Link: https://msgid.link/r/20240517194104.747328-2-andriy.shevchenko@linux.intel.com Signed-off-by: Mark Brown --- drivers/spi/spi-bitbang.c | 31 +++++++++---------------------- include/linux/spi/spi_bitbang.h | 7 ++++--- 2 files changed, 13 insertions(+), 25 deletions(-) diff --git a/drivers/spi/spi-bitbang.c b/drivers/spi/spi-bitbang.c index ca5cc67555c5..d88110acdc5f 100644 --- a/drivers/spi/spi-bitbang.c +++ b/drivers/spi/spi-bitbang.c @@ -38,26 +38,19 @@ * working quickly, or testing for differences that aren't speed related. */ +typedef unsigned int (*spi_bb_txrx_bufs_fn)(struct spi_device *, spi_bb_txrx_word_fn, + unsigned int, struct spi_transfer *, + unsigned int); + struct spi_bitbang_cs { unsigned nsecs; /* (clock cycle time)/2 */ - u32 (*txrx_word)(struct spi_device *spi, unsigned nsecs, - u32 word, u8 bits, unsigned flags); - unsigned (*txrx_bufs)(struct spi_device *, - u32 (*txrx_word)( - struct spi_device *spi, - unsigned nsecs, - u32 word, u8 bits, - unsigned flags), - unsigned, struct spi_transfer *, - unsigned); + spi_bb_txrx_word_fn txrx_word; + spi_bb_txrx_bufs_fn txrx_bufs; }; static unsigned bitbang_txrx_8( struct spi_device *spi, - u32 (*txrx_word)(struct spi_device *spi, - unsigned nsecs, - u32 word, u8 bits, - unsigned flags), + spi_bb_txrx_word_fn txrx_word, unsigned ns, struct spi_transfer *t, unsigned flags @@ -83,10 +76,7 @@ static unsigned bitbang_txrx_8( static unsigned bitbang_txrx_16( struct spi_device *spi, - u32 (*txrx_word)(struct spi_device *spi, - unsigned nsecs, - u32 word, u8 bits, - unsigned flags), + spi_bb_txrx_word_fn txrx_word, unsigned ns, struct spi_transfer *t, unsigned flags @@ -112,10 +102,7 @@ static unsigned bitbang_txrx_16( static unsigned bitbang_txrx_32( struct spi_device *spi, - u32 (*txrx_word)(struct spi_device *spi, - unsigned nsecs, - u32 word, u8 bits, - unsigned flags), + spi_bb_txrx_word_fn txrx_word, unsigned ns, struct spi_transfer *t, unsigned flags diff --git a/include/linux/spi/spi_bitbang.h b/include/linux/spi/spi_bitbang.h index b930eca2ef7b..7ca08b430ed5 100644 --- a/include/linux/spi/spi_bitbang.h +++ b/include/linux/spi/spi_bitbang.h @@ -4,6 +4,8 @@ #include +typedef u32 (*spi_bb_txrx_word_fn)(struct spi_device *, unsigned int, u32, u8, unsigned int); + struct spi_bitbang { struct mutex lock; u8 busy; @@ -28,9 +30,8 @@ struct spi_bitbang { int (*txrx_bufs)(struct spi_device *spi, struct spi_transfer *t); /* txrx_word[SPI_MODE_*]() just looks like a shift register */ - u32 (*txrx_word[4])(struct spi_device *spi, - unsigned nsecs, - u32 word, u8 bits, unsigned flags); + spi_bb_txrx_word_fn txrx_word[4]; + int (*set_line_direction)(struct spi_device *spi, bool output); }; -- cgit v1.2.3 From c3358a746e078d0f9048732c90fdab4f37c00e0d Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 17 May 2024 22:40:21 +0300 Subject: spi: bitbang: Convert unsigned to unsigned int Simple type conversion with no functional change implied. While at it, adjust indentation where it makes sense. Signed-off-by: Andy Shevchenko Link: https://msgid.link/r/20240517194104.747328-3-andriy.shevchenko@linux.intel.com Signed-off-by: Mark Brown --- drivers/spi/spi-bitbang.c | 42 ++++++++++++++++++------------------------ 1 file changed, 18 insertions(+), 24 deletions(-) diff --git a/drivers/spi/spi-bitbang.c b/drivers/spi/spi-bitbang.c index d88110acdc5f..afb1b1105ec2 100644 --- a/drivers/spi/spi-bitbang.c +++ b/drivers/spi/spi-bitbang.c @@ -43,21 +43,19 @@ typedef unsigned int (*spi_bb_txrx_bufs_fn)(struct spi_device *, spi_bb_txrx_wor unsigned int); struct spi_bitbang_cs { - unsigned nsecs; /* (clock cycle time)/2 */ + unsigned int nsecs; /* (clock cycle time) / 2 */ spi_bb_txrx_word_fn txrx_word; spi_bb_txrx_bufs_fn txrx_bufs; }; -static unsigned bitbang_txrx_8( - struct spi_device *spi, +static unsigned int bitbang_txrx_8(struct spi_device *spi, spi_bb_txrx_word_fn txrx_word, - unsigned ns, + unsigned int ns, struct spi_transfer *t, - unsigned flags -) + unsigned int flags) { - unsigned bits = t->bits_per_word; - unsigned count = t->len; + unsigned int bits = t->bits_per_word; + unsigned int count = t->len; const u8 *tx = t->tx_buf; u8 *rx = t->rx_buf; @@ -74,16 +72,14 @@ static unsigned bitbang_txrx_8( return t->len - count; } -static unsigned bitbang_txrx_16( - struct spi_device *spi, +static unsigned int bitbang_txrx_16(struct spi_device *spi, spi_bb_txrx_word_fn txrx_word, - unsigned ns, + unsigned int ns, struct spi_transfer *t, - unsigned flags -) + unsigned int flags) { - unsigned bits = t->bits_per_word; - unsigned count = t->len; + unsigned int bits = t->bits_per_word; + unsigned int count = t->len; const u16 *tx = t->tx_buf; u16 *rx = t->rx_buf; @@ -100,16 +96,14 @@ static unsigned bitbang_txrx_16( return t->len - count; } -static unsigned bitbang_txrx_32( - struct spi_device *spi, +static unsigned int bitbang_txrx_32(struct spi_device *spi, spi_bb_txrx_word_fn txrx_word, - unsigned ns, + unsigned int ns, struct spi_transfer *t, - unsigned flags -) + unsigned int flags) { - unsigned bits = t->bits_per_word; - unsigned count = t->len; + unsigned int bits = t->bits_per_word; + unsigned int count = t->len; const u32 *tx = t->tx_buf; u32 *rx = t->rx_buf; @@ -221,7 +215,7 @@ EXPORT_SYMBOL_GPL(spi_bitbang_cleanup); static int spi_bitbang_bufs(struct spi_device *spi, struct spi_transfer *t) { struct spi_bitbang_cs *cs = spi->controller_state; - unsigned nsecs = cs->nsecs; + unsigned int nsecs = cs->nsecs; struct spi_bitbang *bitbang; bitbang = spi_controller_get_devdata(spi->controller); @@ -234,7 +228,7 @@ static int spi_bitbang_bufs(struct spi_device *spi, struct spi_transfer *t) } if (spi->mode & SPI_3WIRE) { - unsigned flags; + unsigned int flags; flags = t->tx_buf ? SPI_CONTROLLER_NO_RX : SPI_CONTROLLER_NO_TX; return cs->txrx_bufs(spi, cs->txrx_word, nsecs, t, flags); -- cgit v1.2.3 From b90cc232e2ce8c959b19dc4b183e23e7aec137ab Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 17 May 2024 22:40:22 +0300 Subject: spi: bitbang: Replace hard coded number of SPI modes Instead of using hard coded number of modes, replace it with SPI_MODE_X_MASK + 1 to show relation to the SPI modes. Signed-off-by: Andy Shevchenko Link: https://msgid.link/r/20240517194104.747328-4-andriy.shevchenko@linux.intel.com Signed-off-by: Mark Brown --- include/linux/spi/spi_bitbang.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linux/spi/spi_bitbang.h b/include/linux/spi/spi_bitbang.h index 7ca08b430ed5..d4cb83195f7a 100644 --- a/include/linux/spi/spi_bitbang.h +++ b/include/linux/spi/spi_bitbang.h @@ -30,7 +30,7 @@ struct spi_bitbang { int (*txrx_bufs)(struct spi_device *spi, struct spi_transfer *t); /* txrx_word[SPI_MODE_*]() just looks like a shift register */ - spi_bb_txrx_word_fn txrx_word[4]; + spi_bb_txrx_word_fn txrx_word[SPI_MODE_X_MASK + 1]; int (*set_line_direction)(struct spi_device *spi, bool output); }; -- cgit v1.2.3 From 04518cd88776721960aff724049138a8bd929c59 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 17 May 2024 22:42:01 +0300 Subject: spi: gpio: Make use of device properties Convert the module to be property provider agnostic and allow it to be used on non-OF platforms. Include mod_devicetable.h explicitly to replace the dropped of.h which included mod_devicetable.h indirectly. Signed-off-by: Andy Shevchenko Link: https://msgid.link/r/20240517194246.747427-2-andriy.shevchenko@linux.intel.com Signed-off-by: Mark Brown --- drivers/spi/spi-gpio.c | 51 ++++++++++++++++++-------------------------------- 1 file changed, 18 insertions(+), 33 deletions(-) diff --git a/drivers/spi/spi-gpio.c b/drivers/spi/spi-gpio.c index 909cce109bba..abf426711c22 100644 --- a/drivers/spi/spi-gpio.c +++ b/drivers/spi/spi-gpio.c @@ -5,17 +5,17 @@ * Copyright (C) 2006,2008 David Brownell * Copyright (C) 2017 Linus Walleij */ +#include #include +#include #include #include -#include -#include +#include #include #include #include - /* * This bitbanging SPI host driver should help make systems usable * when a native hardware SPI engine is not available, perhaps because @@ -326,29 +326,6 @@ static int spi_gpio_request(struct device *dev, struct spi_gpio *spi_gpio) return PTR_ERR_OR_ZERO(spi_gpio->sck); } -#ifdef CONFIG_OF -static const struct of_device_id spi_gpio_dt_ids[] = { - { .compatible = "spi-gpio" }, - {} -}; -MODULE_DEVICE_TABLE(of, spi_gpio_dt_ids); - -static int spi_gpio_probe_dt(struct platform_device *pdev, - struct spi_controller *host) -{ - host->dev.of_node = pdev->dev.of_node; - host->use_gpio_descriptors = true; - - return 0; -} -#else -static inline int spi_gpio_probe_dt(struct platform_device *pdev, - struct spi_controller *host) -{ - return 0; -} -#endif - static int spi_gpio_probe_pdata(struct platform_device *pdev, struct spi_controller *host) { @@ -389,19 +366,21 @@ static int spi_gpio_probe(struct platform_device *pdev) struct spi_controller *host; struct spi_gpio *spi_gpio; struct device *dev = &pdev->dev; + struct fwnode_handle *fwnode = dev_fwnode(dev); struct spi_bitbang *bb; host = devm_spi_alloc_host(dev, sizeof(*spi_gpio)); if (!host) return -ENOMEM; - if (pdev->dev.of_node) - status = spi_gpio_probe_dt(pdev, host); - else + if (fwnode) { + device_set_node(&host->dev, fwnode); + host->use_gpio_descriptors = true; + } else { status = spi_gpio_probe_pdata(pdev, host); - - if (status) - return status; + if (status) + return status; + } spi_gpio = spi_controller_get_devdata(host); @@ -459,10 +438,16 @@ static int spi_gpio_probe(struct platform_device *pdev) MODULE_ALIAS("platform:" DRIVER_NAME); +static const struct of_device_id spi_gpio_dt_ids[] = { + { .compatible = "spi-gpio" }, + {} +}; +MODULE_DEVICE_TABLE(of, spi_gpio_dt_ids); + static struct platform_driver spi_gpio_driver = { .driver = { .name = DRIVER_NAME, - .of_match_table = of_match_ptr(spi_gpio_dt_ids), + .of_match_table = spi_gpio_dt_ids, }, .probe = spi_gpio_probe, }; -- cgit v1.2.3 From 196bf3e7fe2267ed7c1a193338d0aacecb9f9ff8 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 17 May 2024 22:42:02 +0300 Subject: spi: gpio: Use traditional pattern when checking error codes Instead of 'if (!ret)' switch to "check for the error first" rule. Signed-off-by: Andy Shevchenko Link: https://msgid.link/r/20240517194246.747427-3-andriy.shevchenko@linux.intel.com Signed-off-by: Mark Brown --- drivers/spi/spi-gpio.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/drivers/spi/spi-gpio.c b/drivers/spi/spi-gpio.c index abf426711c22..36c587be9e28 100644 --- a/drivers/spi/spi-gpio.c +++ b/drivers/spi/spi-gpio.c @@ -239,8 +239,8 @@ static void spi_gpio_chipselect(struct spi_device *spi, int is_active) static int spi_gpio_setup(struct spi_device *spi) { struct gpio_desc *cs; - int status = 0; struct spi_gpio *spi_gpio = spi_to_spi_gpio(spi); + int ret; /* * The CS GPIOs have already been @@ -248,15 +248,14 @@ static int spi_gpio_setup(struct spi_device *spi) */ if (spi_gpio->cs_gpios) { cs = spi_gpio->cs_gpios[spi_get_chipselect(spi, 0)]; - if (!spi->controller_state && cs) - status = gpiod_direction_output(cs, - !(spi->mode & SPI_CS_HIGH)); + if (!spi->controller_state && cs) { + ret = gpiod_direction_output(cs, !(spi->mode & SPI_CS_HIGH)); + if (ret) + return ret; + } } - if (!status) - status = spi_bitbang_setup(spi); - - return status; + return spi_bitbang_setup(spi); } static int spi_gpio_set_direction(struct spi_device *spi, bool output) -- cgit v1.2.3 From 6ecdb0aa4dca62d236a659426e11e6cf302e8f18 Mon Sep 17 00:00:00 2001 From: David Lechner Date: Wed, 8 May 2024 11:06:53 -0500 Subject: spi: axi-spi-engine: Add SPI_CS_HIGH support The AXI SPI Engine IP core v1.2 added support for SPI_CS_HIGH. This provides the driver implementation to make use of this feature when supported hardware is detected. Signed-off-by: David Lechner Link: https://msgid.link/r/20240508-spi-axi-spi-engine-add-spi_cs_high-support-v1-1-695dd8e45f00@baylibre.com Signed-off-by: Mark Brown --- drivers/spi/spi-axi-spi-engine.c | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/drivers/spi/spi-axi-spi-engine.c b/drivers/spi/spi-axi-spi-engine.c index e358ac5b4509..3231f67ae265 100644 --- a/drivers/spi/spi-axi-spi-engine.c +++ b/drivers/spi/spi-axi-spi-engine.c @@ -46,6 +46,7 @@ #define SPI_ENGINE_INST_ASSERT 0x1 #define SPI_ENGINE_INST_WRITE 0x2 #define SPI_ENGINE_INST_MISC 0x3 +#define SPI_ENGINE_INST_CS_INV 0x4 #define SPI_ENGINE_CMD_REG_CLK_DIV 0x0 #define SPI_ENGINE_CMD_REG_CONFIG 0x1 @@ -73,6 +74,8 @@ SPI_ENGINE_CMD(SPI_ENGINE_INST_MISC, SPI_ENGINE_MISC_SLEEP, (delay)) #define SPI_ENGINE_CMD_SYNC(id) \ SPI_ENGINE_CMD(SPI_ENGINE_INST_MISC, SPI_ENGINE_MISC_SYNC, (id)) +#define SPI_ENGINE_CMD_CS_INV(flags) \ + SPI_ENGINE_CMD(SPI_ENGINE_INST_CS_INV, 0, (flags)) struct spi_engine_program { unsigned int length; @@ -111,6 +114,8 @@ struct spi_engine { struct spi_engine_message_state msg_state; struct completion msg_complete; unsigned int int_enable; + /* shadows hardware CS inversion flag state */ + u8 cs_inv; }; static void spi_engine_program_add_cmd(struct spi_engine_program *p, @@ -530,6 +535,29 @@ static int spi_engine_unoptimize_message(struct spi_message *msg) return 0; } +static int spi_engine_setup(struct spi_device *device) +{ + struct spi_controller *host = device->controller; + struct spi_engine *spi_engine = spi_controller_get_devdata(host); + + if (device->mode & SPI_CS_HIGH) + spi_engine->cs_inv |= BIT(spi_get_chipselect(device, 0)); + else + spi_engine->cs_inv &= ~BIT(spi_get_chipselect(device, 0)); + + writel_relaxed(SPI_ENGINE_CMD_CS_INV(spi_engine->cs_inv), + spi_engine->base + SPI_ENGINE_REG_CMD_FIFO); + + /* + * In addition to setting the flags, we have to do a CS assert command + * to make the new setting actually take effect. + */ + writel_relaxed(SPI_ENGINE_CMD_ASSERT(0, 0xff), + spi_engine->base + SPI_ENGINE_REG_CMD_FIFO); + + return 0; +} + static int spi_engine_transfer_one_message(struct spi_controller *host, struct spi_message *msg) { @@ -653,6 +681,12 @@ static int spi_engine_probe(struct platform_device *pdev) host->unoptimize_message = spi_engine_unoptimize_message; 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 (host->max_speed_hz == 0) return dev_err_probe(&pdev->dev, -EINVAL, "spi_clk rate is 0"); -- cgit v1.2.3 From 5bcbbaf0747cfe510814f40f36bbda49b851c956 Mon Sep 17 00:00:00 2001 From: "Rob Herring (Arm)" Date: Wed, 22 May 2024 08:28:58 -0500 Subject: spi: dt-bindings: marvell,mmp2-ssp: Merge PXA SSP into schema The Marvell PXA SSP block is the same or similiar to the MMP2 variant. The only difference in the binding is the PXA version supports DMA (and that's probably a binding difference rather than an actual h/w difference). The old binding didn't belong under 'serial' as it is not a UART. The SSP block also supports audio devices, so 'spi' is not a perfect fit either. As the existing schema for MMP2 is there, just leave things as-is. The examples in the old text binding were pretty out of sync with reality. 'clock-names' and 'ssp-id' aren't documented nor used. Cc: Andy Shevchenko Signed-off-by: Rob Herring (Arm) Link: https://msgid.link/r/20240522132859.3146335-1-robh@kernel.org Signed-off-by: Mark Brown --- .../devicetree/bindings/serial/mrvl,pxa-ssp.txt | 64 ---------------------- .../devicetree/bindings/spi/marvell,mmp2-ssp.yaml | 35 ++++++++++-- 2 files changed, 31 insertions(+), 68 deletions(-) delete mode 100644 Documentation/devicetree/bindings/serial/mrvl,pxa-ssp.txt diff --git a/Documentation/devicetree/bindings/serial/mrvl,pxa-ssp.txt b/Documentation/devicetree/bindings/serial/mrvl,pxa-ssp.txt deleted file mode 100644 index d10cc06c0c37..000000000000 --- a/Documentation/devicetree/bindings/serial/mrvl,pxa-ssp.txt +++ /dev/null @@ -1,64 +0,0 @@ -Device tree bindings for Marvell PXA SSP ports - -Required properties: - - - compatible: Must be one of - mrvl,pxa25x-ssp - mvrl,pxa25x-nssp - mrvl,pxa27x-ssp - mrvl,pxa3xx-ssp - mvrl,pxa168-ssp - mrvl,pxa910-ssp - mrvl,ce4100-ssp - - - reg: The memory base - - dmas: Two dma phandles, one for rx, one for tx - - dma-names: Must be "rx", "tx" - - -Example for PXA3xx: - - ssp0: ssp@41000000 { - compatible = "mrvl,pxa3xx-ssp"; - reg = <0x41000000 0x40>; - ssp-id = <1>; - interrupts = <24>; - clock-names = "pxa27x-ssp.0"; - dmas = <&dma 13 - &dma 14>; - dma-names = "rx", "tx"; - }; - - ssp1: ssp@41700000 { - compatible = "mrvl,pxa3xx-ssp"; - reg = <0x41700000 0x40>; - ssp-id = <2>; - interrupts = <16>; - clock-names = "pxa27x-ssp.1"; - dmas = <&dma 15 - &dma 16>; - dma-names = "rx", "tx"; - }; - - ssp2: ssp@41900000 { - compatibl3 = "mrvl,pxa3xx-ssp"; - reg = <0x41900000 0x40>; - ssp-id = <3>; - interrupts = <0>; - clock-names = "pxa27x-ssp.2"; - dmas = <&dma 66 - &dma 67>; - dma-names = "rx", "tx"; - }; - - ssp3: ssp@41a00000 { - compatible = "mrvl,pxa3xx-ssp"; - reg = <0x41a00000 0x40>; - ssp-id = <4>; - interrupts = <13>; - clock-names = "pxa27x-ssp.3"; - dmas = <&dma 2 - &dma 3>; - dma-names = "rx", "tx"; - }; - diff --git a/Documentation/devicetree/bindings/spi/marvell,mmp2-ssp.yaml b/Documentation/devicetree/bindings/spi/marvell,mmp2-ssp.yaml index 5f4f6b5615d0..0a1bada8f800 100644 --- a/Documentation/devicetree/bindings/spi/marvell,mmp2-ssp.yaml +++ b/Documentation/devicetree/bindings/spi/marvell,mmp2-ssp.yaml @@ -10,12 +10,17 @@ title: PXA2xx SSP SPI Controller maintainers: - Lubomir Rintel -allOf: - - $ref: spi-controller.yaml# - properties: compatible: - const: marvell,mmp2-ssp + enum: + - marvell,mmp2-ssp + - mrvl,ce4100-ssp + - mvrl,pxa168-ssp + - mrvl,pxa25x-ssp + - mvrl,pxa25x-nssp + - mrvl,pxa27x-ssp + - mrvl,pxa3xx-ssp + - mrvl,pxa910-ssp interrupts: maxItems: 1 @@ -26,6 +31,16 @@ properties: clocks: maxItems: 1 + dmas: + items: + - description: Receive DMA + - description: Transmit DMA + + dma-names: + items: + - const: rx + - const: tx + ready-gpios: description: | GPIO used to signal a SPI master that the FIFO is filled and we're @@ -41,6 +56,18 @@ required: dependencies: ready-gpios: [ spi-slave ] +allOf: + - $ref: spi-controller.yaml# + - if: + properties: + compatible: + contains: + const: marvell,mmp2-ssp + then: + properties: + dmas: false + dma-names: false + unevaluatedProperties: false examples: -- cgit v1.2.3 From 61cabbd5ef7625fe5ece4aa16ccc21c91bc2fc8f Mon Sep 17 00:00:00 2001 From: Martin Kaiser Date: Mon, 20 May 2024 18:59:06 +0200 Subject: spi: imx: remove empty cleanup function Remove the empty spi_imx_cleanup function. It's ok if a driver does not set the controller->cleanup pointer, the caller does a NULL check. Signed-off-by: Martin Kaiser Link: https://msgid.link/r/20240520165906.164906-1-martin@kaiser.cx Signed-off-by: Mark Brown --- drivers/spi/spi-imx.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/drivers/spi/spi-imx.c b/drivers/spi/spi-imx.c index f4006c82f867..cf0cb52946d2 100644 --- a/drivers/spi/spi-imx.c +++ b/drivers/spi/spi-imx.c @@ -1666,10 +1666,6 @@ static int spi_imx_setup(struct spi_device *spi) return 0; } -static void spi_imx_cleanup(struct spi_device *spi) -{ -} - static int spi_imx_prepare_message(struct spi_controller *controller, struct spi_message *msg) { @@ -1766,7 +1762,6 @@ static int spi_imx_probe(struct platform_device *pdev) controller->transfer_one = spi_imx_transfer_one; controller->setup = spi_imx_setup; - controller->cleanup = spi_imx_cleanup; controller->prepare_message = spi_imx_prepare_message; controller->unprepare_message = spi_imx_unprepare_message; controller->target_abort = spi_imx_target_abort; -- cgit v1.2.3 From ef901b38d3a4610c4067cd306c1a209f32e7ca31 Mon Sep 17 00:00:00 2001 From: Chen Ni Date: Wed, 15 May 2024 16:40:28 +0800 Subject: spi: atmel-quadspi: Add missing check for clk_prepare Add check for the return value of clk_prepare() and return the error if it fails in order to catch the error. Fixes: 4a2f83b7f780 ("spi: atmel-quadspi: add runtime pm support") Signed-off-by: Chen Ni Link: https://msgid.link/r/20240515084028.3210406-1-nichen@iscas.ac.cn Signed-off-by: Mark Brown --- drivers/spi/atmel-quadspi.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/drivers/spi/atmel-quadspi.c b/drivers/spi/atmel-quadspi.c index 370c4d1572ed..5aaff3bee1b7 100644 --- a/drivers/spi/atmel-quadspi.c +++ b/drivers/spi/atmel-quadspi.c @@ -756,8 +756,15 @@ static int __maybe_unused atmel_qspi_resume(struct device *dev) struct atmel_qspi *aq = spi_controller_get_devdata(ctrl); int ret; - clk_prepare(aq->pclk); - clk_prepare(aq->qspick); + ret = clk_prepare(aq->pclk); + if (ret) + return ret; + + ret = clk_prepare(aq->qspick); + if (ret) { + clk_unprepare(aq->pclk); + return ret; + } ret = pm_runtime_force_resume(dev); if (ret < 0) -- cgit v1.2.3 From 2d19ea9e8840a1a77b1d464b06e62dd9b0f21e0d Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 10 May 2024 23:49:52 +0300 Subject: spi: Replace custom code with device_match_acpi_handle() Since driver core provides a generic device_match_acpi_handle() we may replace the custom code with it. Signed-off-by: Andy Shevchenko Link: https://msgid.link/r/20240510204952.2582093-1-andriy.shevchenko@linux.intel.com Signed-off-by: Mark Brown --- drivers/spi/spi.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index f94420858c22..26ef4e147681 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -2729,7 +2729,7 @@ static int acpi_spi_add_resource(struct acpi_resource *ares, void *data) return -ENODEV; if (ctlr) { - if (ACPI_HANDLE(ctlr->dev.parent) != parent_handle) + if (!device_match_acpi_handle(ctlr->dev.parent, parent_handle)) return -ENODEV; } else { struct acpi_device *adev; @@ -2828,7 +2828,7 @@ struct spi_device *acpi_spi_device_alloc(struct spi_controller *ctlr, if (!lookup.max_speed_hz && ACPI_SUCCESS(acpi_get_parent(adev->handle, &parent_handle)) && - ACPI_HANDLE(lookup.ctlr->dev.parent) == parent_handle) { + device_match_acpi_handle(lookup.ctlr->dev.parent, parent_handle)) { /* Apple does not use _CRS but nested devices for SPI slaves */ acpi_spi_parse_apple_properties(adev, &lookup); } -- cgit v1.2.3 From 85ce0dc28ffd4861d91b96f488d31878d8901e49 Mon Sep 17 00:00:00 2001 From: Kanak Shilledar Date: Tue, 14 May 2024 12:30:47 +0530 Subject: spi: dt-bindings: brcm,bcm2835-spi: convert to dtschema Convert the Broadcom BCM2835 SPI0 controller to newer DT schema. Created DT schema based on the .txt file which had `comaptible`, `reg`, `interrupts`, `clocks` as required properties. Added GPL-2.0 OR BSD-2-Clause License Signed-off-by: Kanak Shilledar Reviewed-by: Conor Dooley Link: https://msgid.link/r/20240514070051.2959-1-kanakshilledar111@protonmail.com Signed-off-by: Mark Brown --- .../devicetree/bindings/spi/brcm,bcm2835-spi.txt | 23 ---------- .../devicetree/bindings/spi/brcm,bcm2835-spi.yaml | 50 ++++++++++++++++++++++ 2 files changed, 50 insertions(+), 23 deletions(-) delete mode 100644 Documentation/devicetree/bindings/spi/brcm,bcm2835-spi.txt create mode 100644 Documentation/devicetree/bindings/spi/brcm,bcm2835-spi.yaml diff --git a/Documentation/devicetree/bindings/spi/brcm,bcm2835-spi.txt b/Documentation/devicetree/bindings/spi/brcm,bcm2835-spi.txt deleted file mode 100644 index 3d55dd64b1be..000000000000 --- a/Documentation/devicetree/bindings/spi/brcm,bcm2835-spi.txt +++ /dev/null @@ -1,23 +0,0 @@ -Broadcom BCM2835 SPI0 controller - -The BCM2835 contains two forms of SPI master controller, one known simply as -SPI0, and the other known as the "Universal SPI Master"; part of the -auxiliary block. This binding applies to the SPI0 controller. - -Required properties: -- compatible: Should be one of "brcm,bcm2835-spi" for BCM2835/2836/2837 or - "brcm,bcm2711-spi" for BCM2711 or "brcm,bcm7211-spi" for BCM7211. -- reg: Should contain register location and length. -- interrupts: Should contain interrupt. -- clocks: The clock feeding the SPI controller. - -Example: - -spi@20204000 { - compatible = "brcm,bcm2835-spi"; - reg = <0x7e204000 0x1000>; - interrupts = <2 22>; - clocks = <&clk_spi>; - #address-cells = <1>; - #size-cells = <0>; -}; diff --git a/Documentation/devicetree/bindings/spi/brcm,bcm2835-spi.yaml b/Documentation/devicetree/bindings/spi/brcm,bcm2835-spi.yaml new file mode 100644 index 000000000000..94da68792194 --- /dev/null +++ b/Documentation/devicetree/bindings/spi/brcm,bcm2835-spi.yaml @@ -0,0 +1,50 @@ +# SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/spi/brcm,bcm2835-spi.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Broadcom BCM2835 SPI0 controller + +maintainers: + - Florian Fainelli + - Kanak Shilledar + - Stefan Wahren + +allOf: + - $ref: spi-controller.yaml# + +properties: + compatible: + enum: + - brcm,bcm2835-spi + - brcm,bcm2711-spi + - brcm,bcm7211-spi + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + clocks: + maxItems: 1 + +required: + - compatible + - reg + - interrupts + - clocks + +unevaluatedProperties: false + +examples: + - | + spi@20204000 { + compatible = "brcm,bcm2835-spi"; + reg = <0x7e204000 0x1000>; + interrupts = <2 22>; + clocks = <&clk_spi>; + #address-cells = <1>; + #size-cells = <0>; + }; -- cgit v1.2.3 From a71b7845c0e417f2787a8e2ac77e571fce7dc72c Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 10 May 2024 23:49:45 +0300 Subject: spi: Refactor spi_stop_queue() The refactoring makes code less verbose and easier to read. Besides that the binary size is also reduced, which sounds like a win-win case: add/remove: 0/1 grow/shrink: 2/2 up/down: 210/-226 (-16) Function old new delta spi_destroy_queue 42 156 +114 spi_controller_suspend 101 197 +96 spi_unregister_controller 346 319 -27 spi_register_controller 1834 1794 -40 spi_stop_queue 159 - -159 Total: Before=49230, After=49214, chg -0.03% Signed-off-by: Andy Shevchenko Link: https://msgid.link/r/20240510204945.2581944-1-andriy.shevchenko@linux.intel.com Signed-off-by: Mark Brown --- drivers/spi/spi.c | 25 ++++++++++--------------- 1 file changed, 10 insertions(+), 15 deletions(-) diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index 26ef4e147681..cc8bb7d5ba1a 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -2219,11 +2219,8 @@ static int spi_start_queue(struct spi_controller *ctlr) static int spi_stop_queue(struct spi_controller *ctlr) { + unsigned int limit = 500; unsigned long flags; - unsigned limit = 500; - int ret = 0; - - spin_lock_irqsave(&ctlr->queue_lock, flags); /* * This is a bit lame, but is optimized for the common execution path. @@ -2231,20 +2228,18 @@ static int spi_stop_queue(struct spi_controller *ctlr) * execution path (pump_messages) would be required to call wake_up or * friends on every SPI message. Do this instead. */ - while ((!list_empty(&ctlr->queue) || ctlr->busy) && limit--) { + do { + spin_lock_irqsave(&ctlr->queue_lock, flags); + if (list_empty(&ctlr->queue) && !ctlr->busy) { + ctlr->running = false; + spin_unlock_irqrestore(&ctlr->queue_lock, flags); + return 0; + } spin_unlock_irqrestore(&ctlr->queue_lock, flags); usleep_range(10000, 11000); - spin_lock_irqsave(&ctlr->queue_lock, flags); - } - - if (!list_empty(&ctlr->queue) || ctlr->busy) - ret = -EBUSY; - else - ctlr->running = false; + } while (--limit); - spin_unlock_irqrestore(&ctlr->queue_lock, flags); - - return ret; + return -EBUSY; } static int spi_destroy_queue(struct spi_controller *ctlr) -- cgit v1.2.3 From 060bbd65dd4b4bcd519f6c470ec71fc58f9a6190 Mon Sep 17 00:00:00 2001 From: Eddie James Date: Tue, 14 May 2024 14:26:30 -0500 Subject: spi: dt-bindings: Document the IBM FSI-attached SPI controller IBM Power processors have a SPI controller that can be accessed over FSI from a service processor. Document it. Signed-off-by: Eddie James Reviewed-by: Krzysztof Kozlowski Link: https://msgid.link/r/20240514192630.152747-1-eajames@linux.ibm.com Signed-off-by: Mark Brown --- .../devicetree/bindings/spi/ibm,spi-fsi.yaml | 55 ++++++++++++++++++++++ 1 file changed, 55 insertions(+) create mode 100644 Documentation/devicetree/bindings/spi/ibm,spi-fsi.yaml diff --git a/Documentation/devicetree/bindings/spi/ibm,spi-fsi.yaml b/Documentation/devicetree/bindings/spi/ibm,spi-fsi.yaml new file mode 100644 index 000000000000..d7fec4c3a801 --- /dev/null +++ b/Documentation/devicetree/bindings/spi/ibm,spi-fsi.yaml @@ -0,0 +1,55 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/spi/ibm,spi-fsi.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: IBM FSI-attached SPI Controller + +maintainers: + - Eddie James + +description: + A SPI controller found on IBM Power processors, accessed over FSI from a + service processor. This node will always be a child node of an ibm,fsi2spi + node. + +properties: + compatible: + enum: + - ibm,spi-fsi + + reg: + maxItems: 1 + +required: + - compatible + - reg + +allOf: + - $ref: spi-controller.yaml# + +unevaluatedProperties: false + +examples: + - | + fsi { + #address-cells = <1>; + #size-cells = <0>; + + spi@0 { + compatible = "ibm,spi-fsi"; + reg = <0>; + #address-cells = <1>; + #size-cells = <0>; + + eeprom@0 { + compatible = "atmel,at25"; + reg = <0>; + size = <0x80000>; + address-width = <24>; + pagesize = <256>; + spi-max-frequency = <1000000>; + }; + }; + }; -- cgit v1.2.3 From a2fca8f2e242b3cdfed2a15084e733348ef68509 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 30 May 2024 18:09:57 +0300 Subject: spi: pxa2xx: Wrap pxa_ssp_request() to be device managed resource In the error path or remove path the reference counter in PXA SSP driver may be dropped before the other resources, that were allocated after bumbing the reference counter. This breaks reversed order of freeing and might have an undesired side effects. Prevent this from happening by wrapping pxa_ssp_request() to be device managed resource. Signed-off-by: Andy Shevchenko Link: https://msgid.link/r/20240530151117.1130792-2-andriy.shevchenko@linux.intel.com Signed-off-by: Mark Brown --- drivers/spi/spi-pxa2xx.c | 50 +++++++++++++++++++++++++++++++----------------- 1 file changed, 32 insertions(+), 18 deletions(-) diff --git a/drivers/spi/spi-pxa2xx.c b/drivers/spi/spi-pxa2xx.c index efe76d0c21bb..820a3702447a 100644 --- a/drivers/spi/spi-pxa2xx.c +++ b/drivers/spi/spi-pxa2xx.c @@ -1304,6 +1304,27 @@ pxa2xx_spi_init_ssp(struct platform_device *pdev, struct ssp_device *ssp, enum p return 0; } +static void pxa2xx_spi_ssp_release(void *ssp) +{ + pxa_ssp_free(ssp); +} + +static struct ssp_device *pxa2xx_spi_ssp_request(struct platform_device *pdev) +{ + struct ssp_device *ssp; + int status; + + ssp = pxa_ssp_request(pdev->id, pdev->name); + if (!ssp) + return ssp; + + status = devm_add_action_or_reset(&pdev->dev, pxa2xx_spi_ssp_release, ssp); + if (status) + return ERR_PTR(status); + + return ssp; +} + static struct pxa2xx_spi_controller * pxa2xx_spi_init_pdata(struct platform_device *pdev) { @@ -1331,11 +1352,11 @@ pxa2xx_spi_init_pdata(struct platform_device *pdev) type = (enum pxa_ssp_type)value; } else { - ssp = pxa_ssp_request(pdev->id, pdev->name); - if (ssp) { + ssp = pxa2xx_spi_ssp_request(pdev); + if (IS_ERR(ssp)) + return ERR_CAST(ssp); + if (ssp) type = ssp->type; - pxa_ssp_free(ssp); - } } /* Validate the SSP type correctness */ @@ -1420,7 +1441,9 @@ static int pxa2xx_spi_probe(struct platform_device *pdev) } dev_dbg(dev, "DMA burst size set to %u\n", platform_info->dma_burst_size); - ssp = pxa_ssp_request(pdev->id, pdev->name); + ssp = pxa2xx_spi_ssp_request(pdev); + if (IS_ERR(ssp)) + return PTR_ERR(ssp); if (!ssp) ssp = &platform_info->ssp; @@ -1431,11 +1454,9 @@ static int pxa2xx_spi_probe(struct platform_device *pdev) controller = devm_spi_alloc_target(dev, sizeof(*drv_data)); else controller = devm_spi_alloc_host(dev, sizeof(*drv_data)); + if (!controller) + return dev_err_probe(dev, -ENOMEM, "cannot alloc spi_controller\n"); - if (!controller) { - status = dev_err_probe(dev, -ENOMEM, "cannot alloc spi_controller\n"); - goto out_error_controller_alloc; - } drv_data = spi_controller_get_devdata(controller); drv_data->controller = controller; drv_data->controller_info = platform_info; @@ -1486,10 +1507,8 @@ static int pxa2xx_spi_probe(struct platform_device *pdev) status = request_irq(ssp->irq, ssp_int, IRQF_SHARED, dev_name(dev), drv_data); - if (status < 0) { - dev_err_probe(dev, status, "cannot get IRQ %d\n", ssp->irq); - goto out_error_controller_alloc; - } + if (status < 0) + return dev_err_probe(dev, status, "cannot get IRQ %d\n", ssp->irq); /* Setup DMA if requested */ if (platform_info->enable_dma) { @@ -1619,8 +1638,6 @@ out_error_dma_irq_alloc: pxa2xx_spi_dma_release(drv_data); free_irq(ssp->irq, drv_data); -out_error_controller_alloc: - pxa_ssp_free(ssp); return status; } @@ -1646,9 +1663,6 @@ static void pxa2xx_spi_remove(struct platform_device *pdev) /* Release IRQ */ free_irq(ssp->irq, drv_data); - - /* Release SSP */ - pxa_ssp_free(ssp); } static int pxa2xx_spi_suspend(struct device *dev) -- cgit v1.2.3 From 8aa5062e26054b8c081d5bba930baac4faadd1b0 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 30 May 2024 18:09:58 +0300 Subject: spi: pxa2xx: Reorganize the SSP type retrieval The old Intel platforms, such as Intel Braswell, also provide the property of SSP type. Reorganize the pxa2xx_spi_init_pdata() to take that into account. Signed-off-by: Andy Shevchenko Link: https://msgid.link/r/20240530151117.1130792-3-andriy.shevchenko@linux.intel.com Signed-off-by: Mark Brown --- drivers/spi/spi-pxa2xx.c | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/drivers/spi/spi-pxa2xx.c b/drivers/spi/spi-pxa2xx.c index 820a3702447a..f4dc113768cd 100644 --- a/drivers/spi/spi-pxa2xx.c +++ b/drivers/spi/spi-pxa2xx.c @@ -1331,19 +1331,21 @@ pxa2xx_spi_init_pdata(struct platform_device *pdev) struct pxa2xx_spi_controller *pdata; struct device *dev = &pdev->dev; struct device *parent = dev->parent; + const void *match = device_get_match_data(dev); enum pxa_ssp_type type = SSP_UNDEFINED; - struct ssp_device *ssp = NULL; - const void *match; + struct ssp_device *ssp; bool is_lpss_priv; u32 num_cs = 1; int status; - is_lpss_priv = platform_get_resource_byname(pdev, IORESOURCE_MEM, "lpss_priv"); - - match = device_get_match_data(dev); - if (match) - type = (uintptr_t)match; - else if (is_lpss_priv) { + ssp = pxa2xx_spi_ssp_request(pdev); + if (IS_ERR(ssp)) + return ERR_CAST(ssp); + if (ssp) { + type = ssp->type; + } else if (match) { + type = (enum pxa_ssp_type)(uintptr_t)match; + } else { u32 value; status = device_property_read_u32(dev, "intel,spi-pxa2xx-type", &value); @@ -1351,12 +1353,6 @@ pxa2xx_spi_init_pdata(struct platform_device *pdev) return ERR_PTR(status); type = (enum pxa_ssp_type)value; - } else { - ssp = pxa2xx_spi_ssp_request(pdev); - if (IS_ERR(ssp)) - return ERR_CAST(ssp); - if (ssp) - type = ssp->type; } /* Validate the SSP type correctness */ @@ -1368,6 +1364,7 @@ pxa2xx_spi_init_pdata(struct platform_device *pdev) return ERR_PTR(-ENOMEM); /* Platforms with iDMA 64-bit */ + is_lpss_priv = platform_get_resource_byname(pdev, IORESOURCE_MEM, "lpss_priv"); if (is_lpss_priv) { pdata->tx_param = parent; pdata->rx_param = parent; -- cgit v1.2.3 From 7b0f2c1050643c4793e6eae0246a8de3b22c950a Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 30 May 2024 18:09:59 +0300 Subject: spi: pxa2xx: Remove no more needed driver data Since the ACPI enumerated devices provide a property with SSP type, there is no more necessity to bear the copy of them in the ID table. Drop the driver data in ACPI ID table. Signed-off-by: Andy Shevchenko Link: https://msgid.link/r/20240530151117.1130792-4-andriy.shevchenko@linux.intel.com Signed-off-by: Mark Brown --- drivers/spi/spi-pxa2xx.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/spi/spi-pxa2xx.c b/drivers/spi/spi-pxa2xx.c index f4dc113768cd..b62a613378e0 100644 --- a/drivers/spi/spi-pxa2xx.c +++ b/drivers/spi/spi-pxa2xx.c @@ -1718,12 +1718,12 @@ static const struct dev_pm_ops pxa2xx_spi_pm_ops = { }; static const struct acpi_device_id pxa2xx_spi_acpi_match[] = { - { "80860F0E", LPSS_BYT_SSP }, - { "8086228E", LPSS_BSW_SSP }, - { "INT33C0", LPSS_LPT_SSP }, - { "INT33C1", LPSS_LPT_SSP }, - { "INT3430", LPSS_LPT_SSP }, - { "INT3431", LPSS_LPT_SSP }, + { "80860F0E" }, + { "8086228E" }, + { "INT33C0" }, + { "INT33C1" }, + { "INT3430" }, + { "INT3431" }, {} }; MODULE_DEVICE_TABLE(acpi, pxa2xx_spi_acpi_match); -- cgit v1.2.3 From c1b93986dfb2a31b0528fe929d574843801089f5 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 30 May 2024 18:10:00 +0300 Subject: spi: pxa2xx: Remove hard coded number of chip select pins Remove hard coded number of chip select pins for Intel Braswell. This comes via property. Signed-off-by: Andy Shevchenko Link: https://msgid.link/r/20240530151117.1130792-5-andriy.shevchenko@linux.intel.com Signed-off-by: Mark Brown --- drivers/spi/spi-pxa2xx.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/spi/spi-pxa2xx.c b/drivers/spi/spi-pxa2xx.c index b62a613378e0..53815aab41aa 100644 --- a/drivers/spi/spi-pxa2xx.c +++ b/drivers/spi/spi-pxa2xx.c @@ -99,7 +99,6 @@ struct lpss_config { /* Chip select control */ unsigned cs_sel_shift; unsigned cs_sel_mask; - unsigned cs_num; /* Quirks */ unsigned cs_clk_stays_gated : 1; }; @@ -137,7 +136,6 @@ static const struct lpss_config lpss_platforms[] = { .tx_threshold_hi = 224, .cs_sel_shift = 2, .cs_sel_mask = 1 << 2, - .cs_num = 2, }, { /* LPSS_SPT_SSP */ .offset = 0x200, @@ -1594,8 +1592,6 @@ static int pxa2xx_spi_probe(struct platform_device *pdev) tmp &= LPSS_CAPS_CS_EN_MASK; tmp >>= LPSS_CAPS_CS_EN_SHIFT; platform_info->num_chipselect = ffz(tmp); - } else if (config->cs_num) { - platform_info->num_chipselect = config->cs_num; } } controller->num_chipselect = platform_info->num_chipselect; -- cgit v1.2.3 From c65174fdb2f7fe83ee515966c08de9a990e722f9 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 30 May 2024 18:10:01 +0300 Subject: spi: pxa2xx: Utilise temporary variable for struct device We have a temporary variable to keep a pointer to struct device. Utilise it where it makes sense. Signed-off-by: Andy Shevchenko Link: https://msgid.link/r/20240530151117.1130792-6-andriy.shevchenko@linux.intel.com Signed-off-by: Mark Brown --- drivers/spi/spi-pxa2xx.c | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/drivers/spi/spi-pxa2xx.c b/drivers/spi/spi-pxa2xx.c index 53815aab41aa..19ee7739f4bd 100644 --- a/drivers/spi/spi-pxa2xx.c +++ b/drivers/spi/spi-pxa2xx.c @@ -1606,13 +1606,13 @@ static int pxa2xx_spi_probe(struct platform_device *pdev) } } - pm_runtime_set_autosuspend_delay(&pdev->dev, 50); - pm_runtime_use_autosuspend(&pdev->dev); - pm_runtime_set_active(&pdev->dev); - pm_runtime_enable(&pdev->dev); + pm_runtime_set_autosuspend_delay(dev, 50); + pm_runtime_use_autosuspend(dev); + pm_runtime_set_active(dev); + pm_runtime_enable(dev); /* Register with the SPI framework */ - platform_set_drvdata(pdev, drv_data); + dev_set_drvdata(dev, drv_data); status = spi_register_controller(controller); if (status) { dev_err_probe(dev, status, "problem registering SPI controller\n"); @@ -1622,7 +1622,7 @@ static int pxa2xx_spi_probe(struct platform_device *pdev) return status; out_error_pm_runtime_enabled: - pm_runtime_disable(&pdev->dev); + pm_runtime_disable(dev); out_error_clock_enabled: clk_disable_unprepare(ssp->clk); @@ -1636,10 +1636,11 @@ out_error_dma_irq_alloc: static void pxa2xx_spi_remove(struct platform_device *pdev) { - struct driver_data *drv_data = platform_get_drvdata(pdev); + struct device *dev = &pdev->dev; + struct driver_data *drv_data = dev_get_drvdata(dev); struct ssp_device *ssp = drv_data->ssp; - pm_runtime_get_sync(&pdev->dev); + pm_runtime_get_sync(dev); spi_unregister_controller(drv_data->controller); @@ -1651,8 +1652,8 @@ static void pxa2xx_spi_remove(struct platform_device *pdev) if (drv_data->controller_info->enable_dma) pxa2xx_spi_dma_release(drv_data); - pm_runtime_put_noidle(&pdev->dev); - pm_runtime_disable(&pdev->dev); + pm_runtime_put_noidle(dev); + pm_runtime_disable(dev); /* Release IRQ */ free_irq(ssp->irq, drv_data); -- cgit v1.2.3 From 9b328f5f5c921ec83e1765075b82e6cc05e576b9 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 30 May 2024 18:10:02 +0300 Subject: spi: pxa2xx: Print DMA burst size only when DMA is enabled Print DMA burst size only when DMA is enabled to avoid making a false impression that DMA is enabled when it may be not. Signed-off-by: Andy Shevchenko Link: https://msgid.link/r/20240530151117.1130792-7-andriy.shevchenko@linux.intel.com Signed-off-by: Mark Brown --- drivers/spi/spi-pxa2xx.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/spi/spi-pxa2xx.c b/drivers/spi/spi-pxa2xx.c index 19ee7739f4bd..30a829b74a22 100644 --- a/drivers/spi/spi-pxa2xx.c +++ b/drivers/spi/spi-pxa2xx.c @@ -1434,7 +1434,6 @@ static int pxa2xx_spi_probe(struct platform_device *pdev) if (IS_ERR(platform_info)) return dev_err_probe(dev, PTR_ERR(platform_info), "missing platform data\n"); } - dev_dbg(dev, "DMA burst size set to %u\n", platform_info->dma_burst_size); ssp = pxa2xx_spi_ssp_request(pdev); if (IS_ERR(ssp)) @@ -1516,6 +1515,8 @@ static int pxa2xx_spi_probe(struct platform_device *pdev) controller->max_dma_len = MAX_DMA_LEN; controller->max_transfer_size = pxa2xx_spi_max_dma_transfer_size; + + dev_dbg(dev, "DMA burst size set to %u\n", platform_info->dma_burst_size); } } -- cgit v1.2.3 From 560fb06df2fd250004a1cac079717dbe7f863ff2 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 30 May 2024 18:10:03 +0300 Subject: spi: pxa2xx: Remove duplicate check The mmio_base can't be NULL at this point. It's either checked in both pxa_ssp_probe() and pxa2xx_spi_init_ssp() or correctly provided by PCI core. Hence, remove duplicate check which is a dead code. Signed-off-by: Andy Shevchenko Link: https://msgid.link/r/20240530151117.1130792-8-andriy.shevchenko@linux.intel.com Signed-off-by: Mark Brown --- drivers/spi/spi-pxa2xx.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/spi/spi-pxa2xx.c b/drivers/spi/spi-pxa2xx.c index 30a829b74a22..9724d9455837 100644 --- a/drivers/spi/spi-pxa2xx.c +++ b/drivers/spi/spi-pxa2xx.c @@ -1441,9 +1441,6 @@ static int pxa2xx_spi_probe(struct platform_device *pdev) if (!ssp) ssp = &platform_info->ssp; - if (!ssp->mmio_base) - return dev_err_probe(dev, -ENODEV, "failed to get SSP\n"); - if (platform_info->is_target) controller = devm_spi_alloc_target(dev, sizeof(*drv_data)); else -- cgit v1.2.3 From 75bfdccaecf96189318b29100b880c416d89ed46 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 30 May 2024 18:10:04 +0300 Subject: spi: pxa2xx: Remove superflous check for Intel Atom SoCs pxa2xx_spi_fw_translate_cs() checks for the ACPI companion device presence along with the SSP type. But the SSP type is uniquely determines the case. Hence remove the superflous check. Signed-off-by: Andy Shevchenko Link: https://msgid.link/r/20240530151117.1130792-9-andriy.shevchenko@linux.intel.com Signed-off-by: Mark Brown --- drivers/spi/spi-pxa2xx.c | 26 +++++++++++--------------- 1 file changed, 11 insertions(+), 15 deletions(-) diff --git a/drivers/spi/spi-pxa2xx.c b/drivers/spi/spi-pxa2xx.c index 9724d9455837..3c03a8cd9ee6 100644 --- a/drivers/spi/spi-pxa2xx.c +++ b/drivers/spi/spi-pxa2xx.c @@ -1393,23 +1393,19 @@ static int pxa2xx_spi_fw_translate_cs(struct spi_controller *controller, { struct driver_data *drv_data = spi_controller_get_devdata(controller); - if (has_acpi_companion(drv_data->ssp->dev)) { - switch (drv_data->ssp_type) { - /* - * For Atoms the ACPI DeviceSelection used by the Windows - * driver starts from 1 instead of 0 so translate it here - * to match what Linux expects. - */ - case LPSS_BYT_SSP: - case LPSS_BSW_SSP: - return cs - 1; + switch (drv_data->ssp_type) { + /* + * For some of Intel Atoms the ACPI DeviceSelection used by the Windows + * driver starts from 1 instead of 0 so translate it here to match what + * Linux expects. + */ + case LPSS_BYT_SSP: + case LPSS_BSW_SSP: + return cs - 1; - default: - break; - } + default: + return cs; } - - return cs; } static size_t pxa2xx_spi_max_dma_transfer_size(struct spi_device *spi) -- cgit v1.2.3 From 20ade9b9771c80eb58eb42ccd0a48ba24bdc3c4f Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 30 May 2024 18:10:05 +0300 Subject: spi: pxa2xx: Extract pxa2xx_spi_platform_*() callbacks In preparation of the extracting platform driver from spi-pxa2xx.c split the probe and remove functions so we have bus independent and platform device ones. Signed-off-by: Andy Shevchenko Link: https://msgid.link/r/20240530151117.1130792-10-andriy.shevchenko@linux.intel.com Signed-off-by: Mark Brown --- drivers/spi/spi-pxa2xx.c | 52 ++++++++++++++++++++++++++++++------------------ 1 file changed, 33 insertions(+), 19 deletions(-) diff --git a/drivers/spi/spi-pxa2xx.c b/drivers/spi/spi-pxa2xx.c index 3c03a8cd9ee6..74f242e652df 100644 --- a/drivers/spi/spi-pxa2xx.c +++ b/drivers/spi/spi-pxa2xx.c @@ -1413,30 +1413,16 @@ static size_t pxa2xx_spi_max_dma_transfer_size(struct spi_device *spi) return MAX_DMA_LEN; } -static int pxa2xx_spi_probe(struct platform_device *pdev) +static int pxa2xx_spi_probe(struct device *dev, struct ssp_device *ssp) { - struct device *dev = &pdev->dev; struct pxa2xx_spi_controller *platform_info; struct spi_controller *controller; struct driver_data *drv_data; - struct ssp_device *ssp; const struct lpss_config *config; int status; u32 tmp; platform_info = dev_get_platdata(dev); - if (!platform_info) { - platform_info = pxa2xx_spi_init_pdata(pdev); - if (IS_ERR(platform_info)) - return dev_err_probe(dev, PTR_ERR(platform_info), "missing platform data\n"); - } - - ssp = pxa2xx_spi_ssp_request(pdev); - if (IS_ERR(ssp)) - return PTR_ERR(ssp); - if (!ssp) - ssp = &platform_info->ssp; - if (platform_info->is_target) controller = devm_spi_alloc_target(dev, sizeof(*drv_data)); else @@ -1628,9 +1614,8 @@ out_error_dma_irq_alloc: return status; } -static void pxa2xx_spi_remove(struct platform_device *pdev) +static void pxa2xx_spi_remove(struct device *dev) { - struct device *dev = &pdev->dev; struct driver_data *drv_data = dev_get_drvdata(dev); struct ssp_device *ssp = drv_data->ssp; @@ -1708,6 +1693,35 @@ static const struct dev_pm_ops pxa2xx_spi_pm_ops = { RUNTIME_PM_OPS(pxa2xx_spi_runtime_suspend, pxa2xx_spi_runtime_resume, NULL) }; +static int pxa2xx_spi_platform_probe(struct platform_device *pdev) +{ + struct pxa2xx_spi_controller *platform_info; + struct device *dev = &pdev->dev; + struct ssp_device *ssp; + + platform_info = dev_get_platdata(dev); + if (!platform_info) { + platform_info = pxa2xx_spi_init_pdata(pdev); + if (IS_ERR(platform_info)) + return dev_err_probe(dev, PTR_ERR(platform_info), "missing platform data\n"); + + dev->platform_data = platform_info; + } + + ssp = pxa2xx_spi_ssp_request(pdev); + if (IS_ERR(ssp)) + return PTR_ERR(ssp); + if (!ssp) + ssp = &platform_info->ssp; + + return pxa2xx_spi_probe(dev, ssp); +} + +static void pxa2xx_spi_platform_remove(struct platform_device *pdev) +{ + pxa2xx_spi_remove(&pdev->dev); +} + static const struct acpi_device_id pxa2xx_spi_acpi_match[] = { { "80860F0E" }, { "8086228E" }, @@ -1732,8 +1746,8 @@ static struct platform_driver driver = { .acpi_match_table = pxa2xx_spi_acpi_match, .of_match_table = pxa2xx_spi_of_match, }, - .probe = pxa2xx_spi_probe, - .remove_new = pxa2xx_spi_remove, + .probe = pxa2xx_spi_platform_probe, + .remove_new = pxa2xx_spi_platform_remove, }; static int __init pxa2xx_spi_init(void) -- cgit v1.2.3 From 3d8f037fbcab53e03ab2ef18a66f202be3653d50 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 30 May 2024 18:10:06 +0300 Subject: spi: pxa2xx: Move platform driver to a separate file The spi-pxa2xx.c is bloated with a platform driver code while pretending to provide a core functionality. Make it real core library by splitting out the platform driver to a separate file. Signed-off-by: Andy Shevchenko Link: https://msgid.link/r/20240530151117.1130792-11-andriy.shevchenko@linux.intel.com Signed-off-by: Mark Brown --- drivers/spi/Makefile | 3 +- drivers/spi/spi-pxa2xx-platform.c | 214 +++++++++++++++++++++++++++++++++++++ drivers/spi/spi-pxa2xx.c | 215 ++------------------------------------ drivers/spi/spi-pxa2xx.h | 6 ++ 4 files changed, 230 insertions(+), 208 deletions(-) create mode 100644 drivers/spi/spi-pxa2xx-platform.c diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile index e694254dec04..bcfb6efd88e0 100644 --- a/drivers/spi/Makefile +++ b/drivers/spi/Makefile @@ -107,7 +107,8 @@ obj-$(CONFIG_SPI_PIC32) += spi-pic32.o obj-$(CONFIG_SPI_PIC32_SQI) += spi-pic32-sqi.o obj-$(CONFIG_SPI_PL022) += spi-pl022.o obj-$(CONFIG_SPI_PPC4xx) += spi-ppc4xx.o -spi-pxa2xx-platform-objs := spi-pxa2xx.o spi-pxa2xx-dma.o +obj-$(CONFIG_SPI_PXA2XX) += spi-pxa2xx-core.o +spi-pxa2xx-core-y := spi-pxa2xx.o spi-pxa2xx-dma.o obj-$(CONFIG_SPI_PXA2XX) += spi-pxa2xx-platform.o obj-$(CONFIG_SPI_PXA2XX_PCI) += spi-pxa2xx-pci.o obj-$(CONFIG_SPI_QCOM_GENI) += spi-geni-qcom.o diff --git a/drivers/spi/spi-pxa2xx-platform.c b/drivers/spi/spi-pxa2xx-platform.c new file mode 100644 index 000000000000..98a8ceb7db6f --- /dev/null +++ b/drivers/spi/spi-pxa2xx-platform.c @@ -0,0 +1,214 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "spi-pxa2xx.h" + +static bool pxa2xx_spi_idma_filter(struct dma_chan *chan, void *param) +{ + return param == chan->device->dev; +} + +static int +pxa2xx_spi_init_ssp(struct platform_device *pdev, struct ssp_device *ssp, enum pxa_ssp_type type) +{ + struct device *dev = &pdev->dev; + struct resource *res; + int status; + u64 uid; + + ssp->mmio_base = devm_platform_get_and_ioremap_resource(pdev, 0, &res); + if (IS_ERR(ssp->mmio_base)) + return PTR_ERR(ssp->mmio_base); + + ssp->phys_base = res->start; + + ssp->clk = devm_clk_get(dev, NULL); + if (IS_ERR(ssp->clk)) + return PTR_ERR(ssp->clk); + + ssp->irq = platform_get_irq(pdev, 0); + if (ssp->irq < 0) + return ssp->irq; + + ssp->type = type; + ssp->dev = dev; + + status = acpi_dev_uid_to_integer(ACPI_COMPANION(dev), &uid); + if (status) + ssp->port_id = -1; + else + ssp->port_id = uid; + + return 0; +} + +static void pxa2xx_spi_ssp_release(void *ssp) +{ + pxa_ssp_free(ssp); +} + +static struct ssp_device *pxa2xx_spi_ssp_request(struct platform_device *pdev) +{ + struct ssp_device *ssp; + int status; + + ssp = pxa_ssp_request(pdev->id, pdev->name); + if (!ssp) + return ssp; + + status = devm_add_action_or_reset(&pdev->dev, pxa2xx_spi_ssp_release, ssp); + if (status) + return ERR_PTR(status); + + return ssp; +} + +static struct pxa2xx_spi_controller * +pxa2xx_spi_init_pdata(struct platform_device *pdev) +{ + struct pxa2xx_spi_controller *pdata; + struct device *dev = &pdev->dev; + struct device *parent = dev->parent; + const void *match = device_get_match_data(dev); + enum pxa_ssp_type type = SSP_UNDEFINED; + struct ssp_device *ssp; + bool is_lpss_priv; + u32 num_cs = 1; + int status; + + ssp = pxa2xx_spi_ssp_request(pdev); + if (IS_ERR(ssp)) + return ERR_CAST(ssp); + if (ssp) { + type = ssp->type; + } else if (match) { + type = (enum pxa_ssp_type)(uintptr_t)match; + } else { + u32 value; + + status = device_property_read_u32(dev, "intel,spi-pxa2xx-type", &value); + if (status) + return ERR_PTR(status); + + type = (enum pxa_ssp_type)value; + } + + /* Validate the SSP type correctness */ + if (!(type > SSP_UNDEFINED && type < SSP_MAX)) + return ERR_PTR(-EINVAL); + + pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); + if (!pdata) + return ERR_PTR(-ENOMEM); + + /* Platforms with iDMA 64-bit */ + is_lpss_priv = platform_get_resource_byname(pdev, IORESOURCE_MEM, "lpss_priv"); + if (is_lpss_priv) { + pdata->tx_param = parent; + pdata->rx_param = parent; + pdata->dma_filter = pxa2xx_spi_idma_filter; + } + + /* Read number of chip select pins, if provided */ + device_property_read_u32(dev, "num-cs", &num_cs); + + pdata->num_chipselect = num_cs; + pdata->is_target = device_property_read_bool(dev, "spi-slave"); + pdata->enable_dma = true; + pdata->dma_burst_size = 1; + + /* If SSP has been already enumerated, use it */ + if (ssp) + return pdata; + + status = pxa2xx_spi_init_ssp(pdev, &pdata->ssp, type); + if (status) + return ERR_PTR(status); + + return pdata; +} + +static int pxa2xx_spi_platform_probe(struct platform_device *pdev) +{ + struct pxa2xx_spi_controller *platform_info; + struct device *dev = &pdev->dev; + struct ssp_device *ssp; + + platform_info = dev_get_platdata(dev); + if (!platform_info) { + platform_info = pxa2xx_spi_init_pdata(pdev); + if (IS_ERR(platform_info)) + return dev_err_probe(dev, PTR_ERR(platform_info), "missing platform data\n"); + + dev->platform_data = platform_info; + } + + ssp = pxa2xx_spi_ssp_request(pdev); + if (IS_ERR(ssp)) + return PTR_ERR(ssp); + if (!ssp) + ssp = &platform_info->ssp; + + return pxa2xx_spi_probe(dev, ssp); +} + +static void pxa2xx_spi_platform_remove(struct platform_device *pdev) +{ + pxa2xx_spi_remove(&pdev->dev); +} + +static const struct acpi_device_id pxa2xx_spi_acpi_match[] = { + { "80860F0E" }, + { "8086228E" }, + { "INT33C0" }, + { "INT33C1" }, + { "INT3430" }, + { "INT3431" }, + {} +}; +MODULE_DEVICE_TABLE(acpi, pxa2xx_spi_acpi_match); + +static const struct of_device_id pxa2xx_spi_of_match[] = { + { .compatible = "marvell,mmp2-ssp", .data = (void *)MMP2_SSP }, + {} +}; +MODULE_DEVICE_TABLE(of, pxa2xx_spi_of_match); + +static struct platform_driver driver = { + .driver = { + .name = "pxa2xx-spi", + .pm = pm_ptr(&pxa2xx_spi_pm_ops), + .acpi_match_table = pxa2xx_spi_acpi_match, + .of_match_table = pxa2xx_spi_of_match, + }, + .probe = pxa2xx_spi_platform_probe, + .remove_new = pxa2xx_spi_platform_remove, +}; + +static int __init pxa2xx_spi_init(void) +{ + return platform_driver_register(&driver); +} +subsys_initcall(pxa2xx_spi_init); + +static void __exit pxa2xx_spi_exit(void) +{ + platform_driver_unregister(&driver); +} +module_exit(pxa2xx_spi_exit); + +MODULE_AUTHOR("Stephen Street"); +MODULE_DESCRIPTION("PXA2xx SSP SPI Controller platform driver"); +MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(SPI_PXA2xx); +MODULE_ALIAS("platform:pxa2xx-spi"); +MODULE_SOFTDEP("pre: dw_dmac"); diff --git a/drivers/spi/spi-pxa2xx.c b/drivers/spi/spi-pxa2xx.c index 74f242e652df..1fb30201459f 100644 --- a/drivers/spi/spi-pxa2xx.c +++ b/drivers/spi/spi-pxa2xx.c @@ -4,7 +4,6 @@ * Copyright (C) 2013, 2021 Intel Corporation */ -#include #include #include #include @@ -14,15 +13,12 @@ #include #include #include -#include #include #include #include #include #include -#include #include -#include #include #include #include @@ -32,11 +28,6 @@ #include "spi-pxa2xx.h" -MODULE_AUTHOR("Stephen Street"); -MODULE_DESCRIPTION("PXA2xx SSP SPI Controller"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:pxa2xx-spi"); - #define TIMOUT_DFLT 1000 /* @@ -1263,131 +1254,6 @@ static void cleanup(struct spi_device *spi) kfree(chip); } -static bool pxa2xx_spi_idma_filter(struct dma_chan *chan, void *param) -{ - return param == chan->device->dev; -} - -static int -pxa2xx_spi_init_ssp(struct platform_device *pdev, struct ssp_device *ssp, enum pxa_ssp_type type) -{ - struct device *dev = &pdev->dev; - struct resource *res; - int status; - u64 uid; - - ssp->mmio_base = devm_platform_get_and_ioremap_resource(pdev, 0, &res); - if (IS_ERR(ssp->mmio_base)) - return PTR_ERR(ssp->mmio_base); - - ssp->phys_base = res->start; - - ssp->clk = devm_clk_get(dev, NULL); - if (IS_ERR(ssp->clk)) - return PTR_ERR(ssp->clk); - - ssp->irq = platform_get_irq(pdev, 0); - if (ssp->irq < 0) - return ssp->irq; - - ssp->type = type; - ssp->dev = dev; - - status = acpi_dev_uid_to_integer(ACPI_COMPANION(dev), &uid); - if (status) - ssp->port_id = -1; - else - ssp->port_id = uid; - - return 0; -} - -static void pxa2xx_spi_ssp_release(void *ssp) -{ - pxa_ssp_free(ssp); -} - -static struct ssp_device *pxa2xx_spi_ssp_request(struct platform_device *pdev) -{ - struct ssp_device *ssp; - int status; - - ssp = pxa_ssp_request(pdev->id, pdev->name); - if (!ssp) - return ssp; - - status = devm_add_action_or_reset(&pdev->dev, pxa2xx_spi_ssp_release, ssp); - if (status) - return ERR_PTR(status); - - return ssp; -} - -static struct pxa2xx_spi_controller * -pxa2xx_spi_init_pdata(struct platform_device *pdev) -{ - struct pxa2xx_spi_controller *pdata; - struct device *dev = &pdev->dev; - struct device *parent = dev->parent; - const void *match = device_get_match_data(dev); - enum pxa_ssp_type type = SSP_UNDEFINED; - struct ssp_device *ssp; - bool is_lpss_priv; - u32 num_cs = 1; - int status; - - ssp = pxa2xx_spi_ssp_request(pdev); - if (IS_ERR(ssp)) - return ERR_CAST(ssp); - if (ssp) { - type = ssp->type; - } else if (match) { - type = (enum pxa_ssp_type)(uintptr_t)match; - } else { - u32 value; - - status = device_property_read_u32(dev, "intel,spi-pxa2xx-type", &value); - if (status) - return ERR_PTR(status); - - type = (enum pxa_ssp_type)value; - } - - /* Validate the SSP type correctness */ - if (!(type > SSP_UNDEFINED && type < SSP_MAX)) - return ERR_PTR(-EINVAL); - - pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); - if (!pdata) - return ERR_PTR(-ENOMEM); - - /* Platforms with iDMA 64-bit */ - is_lpss_priv = platform_get_resource_byname(pdev, IORESOURCE_MEM, "lpss_priv"); - if (is_lpss_priv) { - pdata->tx_param = parent; - pdata->rx_param = parent; - pdata->dma_filter = pxa2xx_spi_idma_filter; - } - - /* Read number of chip select pins, if provided */ - device_property_read_u32(dev, "num-cs", &num_cs); - - pdata->num_chipselect = num_cs; - pdata->is_target = device_property_read_bool(dev, "spi-slave"); - pdata->enable_dma = true; - pdata->dma_burst_size = 1; - - /* If SSP has been already enumerated, use it */ - if (ssp) - return pdata; - - status = pxa2xx_spi_init_ssp(pdev, &pdata->ssp, type); - if (status) - return ERR_PTR(status); - - return pdata; -} - static int pxa2xx_spi_fw_translate_cs(struct spi_controller *controller, unsigned int cs) { @@ -1413,7 +1279,7 @@ static size_t pxa2xx_spi_max_dma_transfer_size(struct spi_device *spi) return MAX_DMA_LEN; } -static int pxa2xx_spi_probe(struct device *dev, struct ssp_device *ssp) +int pxa2xx_spi_probe(struct device *dev, struct ssp_device *ssp) { struct pxa2xx_spi_controller *platform_info; struct spi_controller *controller; @@ -1613,8 +1479,9 @@ out_error_dma_irq_alloc: return status; } +EXPORT_SYMBOL_NS_GPL(pxa2xx_spi_probe, SPI_PXA2xx); -static void pxa2xx_spi_remove(struct device *dev) +void pxa2xx_spi_remove(struct device *dev) { struct driver_data *drv_data = dev_get_drvdata(dev); struct ssp_device *ssp = drv_data->ssp; @@ -1637,6 +1504,7 @@ static void pxa2xx_spi_remove(struct device *dev) /* Release IRQ */ free_irq(ssp->irq, drv_data); } +EXPORT_SYMBOL_NS_GPL(pxa2xx_spi_remove, SPI_PXA2xx); static int pxa2xx_spi_suspend(struct device *dev) { @@ -1688,78 +1556,11 @@ static int pxa2xx_spi_runtime_resume(struct device *dev) return clk_prepare_enable(drv_data->ssp->clk); } -static const struct dev_pm_ops pxa2xx_spi_pm_ops = { +EXPORT_NS_GPL_DEV_PM_OPS(pxa2xx_spi_pm_ops, SPI_PXA2xx) = { SYSTEM_SLEEP_PM_OPS(pxa2xx_spi_suspend, pxa2xx_spi_resume) RUNTIME_PM_OPS(pxa2xx_spi_runtime_suspend, pxa2xx_spi_runtime_resume, NULL) }; -static int pxa2xx_spi_platform_probe(struct platform_device *pdev) -{ - struct pxa2xx_spi_controller *platform_info; - struct device *dev = &pdev->dev; - struct ssp_device *ssp; - - platform_info = dev_get_platdata(dev); - if (!platform_info) { - platform_info = pxa2xx_spi_init_pdata(pdev); - if (IS_ERR(platform_info)) - return dev_err_probe(dev, PTR_ERR(platform_info), "missing platform data\n"); - - dev->platform_data = platform_info; - } - - ssp = pxa2xx_spi_ssp_request(pdev); - if (IS_ERR(ssp)) - return PTR_ERR(ssp); - if (!ssp) - ssp = &platform_info->ssp; - - return pxa2xx_spi_probe(dev, ssp); -} - -static void pxa2xx_spi_platform_remove(struct platform_device *pdev) -{ - pxa2xx_spi_remove(&pdev->dev); -} - -static const struct acpi_device_id pxa2xx_spi_acpi_match[] = { - { "80860F0E" }, - { "8086228E" }, - { "INT33C0" }, - { "INT33C1" }, - { "INT3430" }, - { "INT3431" }, - {} -}; -MODULE_DEVICE_TABLE(acpi, pxa2xx_spi_acpi_match); - -static const struct of_device_id pxa2xx_spi_of_match[] = { - { .compatible = "marvell,mmp2-ssp", .data = (void *)MMP2_SSP }, - {} -}; -MODULE_DEVICE_TABLE(of, pxa2xx_spi_of_match); - -static struct platform_driver driver = { - .driver = { - .name = "pxa2xx-spi", - .pm = pm_ptr(&pxa2xx_spi_pm_ops), - .acpi_match_table = pxa2xx_spi_acpi_match, - .of_match_table = pxa2xx_spi_of_match, - }, - .probe = pxa2xx_spi_platform_probe, - .remove_new = pxa2xx_spi_platform_remove, -}; - -static int __init pxa2xx_spi_init(void) -{ - return platform_driver_register(&driver); -} -subsys_initcall(pxa2xx_spi_init); - -static void __exit pxa2xx_spi_exit(void) -{ - platform_driver_unregister(&driver); -} -module_exit(pxa2xx_spi_exit); - -MODULE_SOFTDEP("pre: dw_dmac"); +MODULE_AUTHOR("Stephen Street"); +MODULE_DESCRIPTION("PXA2xx SSP SPI Controller core driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/spi/spi-pxa2xx.h b/drivers/spi/spi-pxa2xx.h index 93e1e471e1c6..a470d3d634d3 100644 --- a/drivers/spi/spi-pxa2xx.h +++ b/drivers/spi/spi-pxa2xx.h @@ -14,6 +14,7 @@ #include +struct device; struct gpio_desc; /* @@ -131,4 +132,9 @@ extern void pxa2xx_spi_dma_stop(struct driver_data *drv_data); extern int pxa2xx_spi_dma_setup(struct driver_data *drv_data); extern void pxa2xx_spi_dma_release(struct driver_data *drv_data); +int pxa2xx_spi_probe(struct device *dev, struct ssp_device *ssp); +void pxa2xx_spi_remove(struct device *dev); + +extern const struct dev_pm_ops pxa2xx_spi_pm_ops; + #endif /* SPI_PXA2XX_H */ -- cgit v1.2.3 From cc160697a576150975280a4b5394fe9c70700503 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 30 May 2024 18:10:07 +0300 Subject: spi: pxa2xx: Convert PCI driver to use spi-pxa2xx code directly PCI driver has an additional device layer for enumeration. Remove that layer and use spi-pxa2xx code directly. Signed-off-by: Andy Shevchenko Link: https://msgid.link/r/20240530151117.1130792-12-andriy.shevchenko@linux.intel.com Signed-off-by: Mark Brown --- drivers/spi/spi-pxa2xx-pci.c | 39 +++++++++++++-------------------------- 1 file changed, 13 insertions(+), 26 deletions(-) diff --git a/drivers/spi/spi-pxa2xx-pci.c b/drivers/spi/spi-pxa2xx-pci.c index 6d2efdb0e95f..616d032f1a89 100644 --- a/drivers/spi/spi-pxa2xx-pci.c +++ b/drivers/spi/spi-pxa2xx-pci.c @@ -10,8 +10,7 @@ #include #include #include -#include -#include +#include #include #include #include @@ -265,10 +264,8 @@ static int pxa2xx_spi_pci_probe(struct pci_dev *dev, const struct pci_device_id *ent) { const struct pxa_spi_info *info; - struct platform_device_info pi; int ret; - struct platform_device *pdev; - struct pxa2xx_spi_controller spi_pdata; + struct pxa2xx_spi_controller *pdata; struct ssp_device *ssp; ret = pcim_enable_device(dev); @@ -279,15 +276,17 @@ static int pxa2xx_spi_pci_probe(struct pci_dev *dev, if (ret) return ret; - memset(&spi_pdata, 0, sizeof(spi_pdata)); + pdata = devm_kzalloc(&dev->dev, sizeof(*pdata), GFP_KERNEL); + if (!pdata) + return -ENOMEM; - ssp = &spi_pdata.ssp; + ssp = &pdata->ssp; ssp->dev = &dev->dev; ssp->phys_base = pci_resource_start(dev, 0); ssp->mmio_base = pcim_iomap_table(dev)[0]; info = (struct pxa_spi_info *)ent->driver_data; - ret = info->setup(dev, &spi_pdata); + ret = info->setup(dev, pdata); if (ret) return ret; @@ -298,28 +297,12 @@ static int pxa2xx_spi_pci_probe(struct pci_dev *dev, return ret; ssp->irq = pci_irq_vector(dev, 0); - memset(&pi, 0, sizeof(pi)); - pi.fwnode = dev_fwnode(&dev->dev); - pi.parent = &dev->dev; - pi.name = "pxa2xx-spi"; - pi.id = ssp->port_id; - pi.data = &spi_pdata; - pi.size_data = sizeof(spi_pdata); - - pdev = platform_device_register_full(&pi); - if (IS_ERR(pdev)) - return PTR_ERR(pdev); - - pci_set_drvdata(dev, pdev); - - return 0; + return pxa2xx_spi_probe(&dev->dev, ssp); } static void pxa2xx_spi_pci_remove(struct pci_dev *dev) { - struct platform_device *pdev = pci_get_drvdata(dev); - - platform_device_unregister(pdev); + pxa2xx_spi_remove(&dev->dev); } static const struct pci_device_id pxa2xx_spi_pci_devices[] = { @@ -341,6 +324,9 @@ MODULE_DEVICE_TABLE(pci, pxa2xx_spi_pci_devices); static struct pci_driver pxa2xx_spi_pci_driver = { .name = "pxa2xx_spi_pci", .id_table = pxa2xx_spi_pci_devices, + .driver = { + .pm = pm_ptr(&pxa2xx_spi_pm_ops), + }, .probe = pxa2xx_spi_pci_probe, .remove = pxa2xx_spi_pci_remove, }; @@ -349,4 +335,5 @@ module_pci_driver(pxa2xx_spi_pci_driver); MODULE_DESCRIPTION("CE4100/LPSS PCI-SPI glue code for PXA's driver"); MODULE_LICENSE("GPL v2"); +MODULE_IMPORT_NS(SPI_PXA2xx); MODULE_AUTHOR("Sebastian Andrzej Siewior "); -- cgit v1.2.3 From 3b0d6a32115c88618794406123ef8466f0327898 Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Wed, 5 Jun 2024 11:37:45 +0200 Subject: dt-bindings: spi: amlogic,a1-spifc: add missing power-domains On the Amlogic A1, the SPI FC controller can require a power-domain to operate, add it as optional. Signed-off-by: Neil Armstrong Acked-by: Conor Dooley Link: https://msgid.link/r/20240605-topic-amlogic-upstream-bindings-fixes-power-domains-spifc-v1-1-380f29ba4a16@linaro.org Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/spi/amlogic,a1-spifc.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Documentation/devicetree/bindings/spi/amlogic,a1-spifc.yaml b/Documentation/devicetree/bindings/spi/amlogic,a1-spifc.yaml index ea47d30eef43..043879b434ac 100644 --- a/Documentation/devicetree/bindings/spi/amlogic,a1-spifc.yaml +++ b/Documentation/devicetree/bindings/spi/amlogic,a1-spifc.yaml @@ -23,6 +23,9 @@ properties: clocks: maxItems: 1 + power-domains: + maxItems: 1 + required: - compatible - reg -- cgit v1.2.3 From d4ea1d504d2701ba04412f98dc00d45a104c52ab Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 5 Jun 2024 23:53:15 +0300 Subject: regmap: spi: Fix potential off-by-one when calculating reserved size If we ever meet a hardware that uses weird register bits and padding, we may end up in off-by-one error since x/8 + y/8 might not be equal to (x + y)/8 in some cases. bits pad x/8+y/8 (x+y)/8 4..7 0..3 0 0 // x + y from 4 up to 7 4..7 4..7 0 1 // x + y from 8 up to 11 4..7 8..11 1 1 // x + y from 12 up to 15 8..15 0..7 1 1 // x + y from 8 up to 15 8..15 8..15 2 2 // x + y from 16 up to 23 Fix this by using (x+y)/8. Signed-off-by: Andy Shevchenko Link: https://msgid.link/r/20240605205315.19132-1-andy.shevchenko@gmail.com Signed-off-by: Mark Brown --- drivers/base/regmap/regmap-spi.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/base/regmap/regmap-spi.c b/drivers/base/regmap/regmap-spi.c index 094cf2a2ca3c..14b1d88997cb 100644 --- a/drivers/base/regmap/regmap-spi.c +++ b/drivers/base/regmap/regmap-spi.c @@ -122,8 +122,7 @@ static const struct regmap_bus *regmap_get_spi_bus(struct spi_device *spi, return ERR_PTR(-ENOMEM); max_msg_size = spi_max_message_size(spi); - reg_reserve_size = config->reg_bits / BITS_PER_BYTE - + config->pad_bits / BITS_PER_BYTE; + reg_reserve_size = (config->reg_bits + config->pad_bits) / BITS_PER_BYTE; if (max_size + reg_reserve_size > max_msg_size) max_size -= reg_reserve_size; -- cgit v1.2.3 From 0535cf64e4b1ead224fbbe1c25c81221a298c5e4 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 31 May 2024 22:42:33 +0300 Subject: spi: Introduce internal spi_xfer_is_dma_mapped() helper MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There are few drivers that use the same pattern to check if the transfer is DMA mapped or not. Provide a helper. Signed-off-by: Andy Shevchenko Tested-by: Neil Armstrong # on SM8650-QRD Link: https://lore.kernel.org/r/20240531194723.1761567-2-andriy.shevchenko@linux.intel.com Reviewed-by: Bryan O'Donoghue Reviewed-by: Serge Semin Tested-by: Nícolas F. R. A. Prado Signed-off-by: Mark Brown --- drivers/spi/internals.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/spi/internals.h b/drivers/spi/internals.h index 4a28a8395552..47a87c2a6979 100644 --- a/drivers/spi/internals.h +++ b/drivers/spi/internals.h @@ -40,4 +40,12 @@ static inline void spi_unmap_buf(struct spi_controller *ctlr, } #endif /* CONFIG_HAS_DMA */ +static inline bool spi_xfer_is_dma_mapped(struct spi_controller *ctlr, + struct spi_device *spi, + struct spi_transfer *xfer) +{ + return ctlr->can_dma && ctlr->can_dma(ctlr, spi, xfer) && + ctlr->cur_msg_mapped; +} + #endif /* __LINUX_SPI_INTERNALS_H */ -- cgit v1.2.3 From 0fb66b81dbf91a60fa4acbf7de26a1958410ef0a Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 31 May 2024 22:42:34 +0300 Subject: spi: dw: Use new spi_xfer_is_dma_mapped() helper MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace a few lines of code by calling a spi_xfer_is_dma_mapped() helper. Signed-off-by: Andy Shevchenko Reviewed-by: Serge Semin Tested-by: Neil Armstrong # on SM8650-QRD Link: https://lore.kernel.org/r/20240531194723.1761567-3-andriy.shevchenko@linux.intel.com Tested-by: Nícolas F. R. A. Prado Signed-off-by: Mark Brown --- drivers/spi/spi-dw-core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/spi/spi-dw-core.c b/drivers/spi/spi-dw-core.c index ddfdb903047a..431788dd848c 100644 --- a/drivers/spi/spi-dw-core.c +++ b/drivers/spi/spi-dw-core.c @@ -19,6 +19,7 @@ #include #include +#include "internals.h" #include "spi-dw.h" #ifdef CONFIG_DEBUG_FS @@ -438,8 +439,7 @@ static int dw_spi_transfer_one(struct spi_controller *host, transfer->effective_speed_hz = dws->current_freq; /* Check if current transfer is a DMA transaction */ - if (host->can_dma && host->can_dma(host, spi, transfer)) - dws->dma_mapped = host->cur_msg_mapped; + dws->dma_mapped = spi_xfer_is_dma_mapped(host, spi, transfer); /* For poll mode just disable all interrupts */ dw_spi_mask_intr(dws, 0xff); -- cgit v1.2.3 From 54c5a9db2899c1dd5059584c6817c50810186325 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 31 May 2024 22:42:35 +0300 Subject: spi: ingenic: Use new spi_xfer_is_dma_mapped() helper MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace a few lines of code by calling a spi_xfer_is_dma_mapped() helper. Signed-off-by: Andy Shevchenko Tested-by: Neil Armstrong # on SM8650-QRD Link: https://lore.kernel.org/r/20240531194723.1761567-4-andriy.shevchenko@linux.intel.com Reviewed-by: Serge Semin Tested-by: Nícolas F. R. A. Prado Signed-off-by: Mark Brown --- drivers/spi/spi-ingenic.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/spi/spi-ingenic.c b/drivers/spi/spi-ingenic.c index 003a6d21c4c3..318b0768701e 100644 --- a/drivers/spi/spi-ingenic.c +++ b/drivers/spi/spi-ingenic.c @@ -16,6 +16,7 @@ #include #include #include +#include "internals.h" #define REG_SSIDR 0x0 #define REG_SSICR0 0x4 @@ -242,11 +243,10 @@ static int spi_ingenic_transfer_one(struct spi_controller *ctlr, { struct ingenic_spi *priv = spi_controller_get_devdata(ctlr); unsigned int bits = xfer->bits_per_word ?: spi->bits_per_word; - bool can_dma = ctlr->can_dma && ctlr->can_dma(ctlr, spi, xfer); spi_ingenic_prepare_transfer(priv, spi, xfer); - if (ctlr->cur_msg_mapped && can_dma) + if (spi_xfer_is_dma_mapped(ctlr, spi, xfer)) return spi_ingenic_dma_tx(ctlr, xfer, bits); if (bits > 16) -- cgit v1.2.3 From 6361b4e4f7a43dd5d8e3f2d2ece8148f30b55cb3 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 31 May 2024 22:42:36 +0300 Subject: spi: omap2-mcspi: Use new spi_xfer_is_dma_mapped() helper MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace a few lines of code by calling a spi_xfer_is_dma_mapped() helper. Signed-off-by: Andy Shevchenko Tested-by: Neil Armstrong # on SM8650-QRD Link: https://lore.kernel.org/r/20240531194723.1761567-5-andriy.shevchenko@linux.intel.com Reviewed-by: Serge Semin Tested-by: Nícolas F. R. A. Prado Signed-off-by: Mark Brown --- drivers/spi/spi-omap2-mcspi.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/spi/spi-omap2-mcspi.c b/drivers/spi/spi-omap2-mcspi.c index 7e3083b83534..b624cc472857 100644 --- a/drivers/spi/spi-omap2-mcspi.c +++ b/drivers/spi/spi-omap2-mcspi.c @@ -27,6 +27,8 @@ #include +#include "internals.h" + #include #define OMAP2_MCSPI_MAX_FREQ 48000000 @@ -1208,8 +1210,7 @@ static int omap2_mcspi_transfer_one(struct spi_controller *ctlr, unsigned count; if ((mcspi_dma->dma_rx && mcspi_dma->dma_tx) && - ctlr->cur_msg_mapped && - ctlr->can_dma(ctlr, spi, t)) + spi_xfer_is_dma_mapped(ctlr, spi, t)) omap2_mcspi_set_fifo(spi, t, 1); omap2_mcspi_set_enable(spi, 1); @@ -1220,8 +1221,7 @@ static int omap2_mcspi_transfer_one(struct spi_controller *ctlr, + OMAP2_MCSPI_TX0); if ((mcspi_dma->dma_rx && mcspi_dma->dma_tx) && - ctlr->cur_msg_mapped && - ctlr->can_dma(ctlr, spi, t)) + spi_xfer_is_dma_mapped(ctlr, spi, t)) count = omap2_mcspi_txrx_dma(spi, t); else count = omap2_mcspi_txrx_pio(spi, t); -- cgit v1.2.3 From e47f92308031ebc29327494b1ab70d18bfa96a5d Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 31 May 2024 22:42:37 +0300 Subject: spi: pxa2xx: Use new spi_xfer_is_dma_mapped() helper MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace a few lines of code by calling a spi_xfer_is_dma_mapped() helper. Signed-off-by: Andy Shevchenko Tested-by: Neil Armstrong # on SM8650-QRD Link: https://lore.kernel.org/r/20240531194723.1761567-6-andriy.shevchenko@linux.intel.com Reviewed-by: Serge Semin Tested-by: Nícolas F. R. A. Prado Signed-off-by: Mark Brown --- drivers/spi/spi-pxa2xx.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/spi/spi-pxa2xx.c b/drivers/spi/spi-pxa2xx.c index 1fb30201459f..16b96eb176cd 100644 --- a/drivers/spi/spi-pxa2xx.c +++ b/drivers/spi/spi-pxa2xx.c @@ -26,6 +26,7 @@ #include +#include "internals.h" #include "spi-pxa2xx.h" #define TIMOUT_DFLT 1000 @@ -993,11 +994,8 @@ static int pxa2xx_spi_transfer_one(struct spi_controller *controller, } dma_thresh = SSCR1_RxTresh(RX_THRESH_DFLT) | SSCR1_TxTresh(TX_THRESH_DFLT); - dma_mapped = controller->can_dma && - controller->can_dma(controller, spi, transfer) && - controller->cur_msg_mapped; + dma_mapped = spi_xfer_is_dma_mapped(controller, spi, transfer); if (dma_mapped) { - /* Ensure we have the correct interrupt handler */ drv_data->transfer_handler = pxa2xx_spi_dma_transfer; -- cgit v1.2.3 From 2f9485adfbd8af088684f43c6391fa02e334d349 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 31 May 2024 22:42:38 +0300 Subject: spi: pci1xxxx: Use new spi_xfer_is_dma_mapped() helper MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace a few lines of code by calling a spi_xfer_is_dma_mapped() helper. Signed-off-by: Andy Shevchenko Tested-by: Neil Armstrong # on SM8650-QRD Link: https://lore.kernel.org/r/20240531194723.1761567-7-andriy.shevchenko@linux.intel.com Reviewed-by: Serge Semin Tested-by: Nícolas F. R. A. Prado Signed-off-by: Mark Brown --- drivers/spi/spi-pci1xxxx.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/spi/spi-pci1xxxx.c b/drivers/spi/spi-pci1xxxx.c index cc18d320370f..fc98979eba48 100644 --- a/drivers/spi/spi-pci1xxxx.c +++ b/drivers/spi/spi-pci1xxxx.c @@ -6,6 +6,7 @@ #include +#include #include #include #include @@ -15,7 +16,7 @@ #include #include #include -#include +#include "internals.h" #define DRV_NAME "spi-pci1xxxx" @@ -567,7 +568,7 @@ error: static int pci1xxxx_spi_transfer_one(struct spi_controller *spi_ctlr, struct spi_device *spi, struct spi_transfer *xfer) { - if (spi_ctlr->can_dma(spi_ctlr, spi, xfer) && spi_ctlr->cur_msg_mapped) + if (spi_xfer_is_dma_mapped(spi_ctlr, spi, xfer)) return pci1xxxx_spi_transfer_with_dma(spi_ctlr, spi, xfer); else return pci1xxxx_spi_transfer_with_io(spi_ctlr, spi, xfer); -- cgit v1.2.3 From bd1886661b14345ed3c7b261550bcca6cd76840a Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 31 May 2024 22:42:39 +0300 Subject: spi: qup: Use new spi_xfer_is_dma_mapped() helper MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace a few lines of code by calling a spi_xfer_is_dma_mapped() helper. Signed-off-by: Andy Shevchenko Tested-by: Neil Armstrong # on SM8650-QRD Link: https://lore.kernel.org/r/20240531194723.1761567-8-andriy.shevchenko@linux.intel.com Reviewed-by: Bryan O'Donoghue Reviewed-by: Serge Semin Tested-by: Nícolas F. R. A. Prado Signed-off-by: Mark Brown --- drivers/spi/spi-qup.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/spi/spi-qup.c b/drivers/spi/spi-qup.c index 2af63040ac6e..06da4aa7eeb7 100644 --- a/drivers/spi/spi-qup.c +++ b/drivers/spi/spi-qup.c @@ -5,6 +5,8 @@ #include #include +#include +#include #include #include #include @@ -16,8 +18,7 @@ #include #include #include -#include -#include +#include "internals.h" #define QUP_CONFIG 0x0000 #define QUP_STATE 0x0004 @@ -709,9 +710,7 @@ static int spi_qup_io_prep(struct spi_device *spi, struct spi_transfer *xfer) if (controller->n_words <= (controller->in_fifo_sz / sizeof(u32))) controller->mode = QUP_IO_M_MODE_FIFO; - else if (spi->controller->can_dma && - spi->controller->can_dma(spi->controller, spi, xfer) && - spi->controller->cur_msg_mapped) + else if (spi_xfer_is_dma_mapped(spi->controller, spi, xfer)) controller->mode = QUP_IO_M_MODE_BAM; else controller->mode = QUP_IO_M_MODE_BLOCK; -- cgit v1.2.3 From e289df82344fecc104ad8326b9ab6da612b9c899 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 31 May 2024 22:42:40 +0300 Subject: spi: Rework per message DMA mapped flag to be per transfer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The granularity of DMA mappings is transfer and moreover, the direction is also important as it can be unidirect. The current cur_msg_mapped flag doesn't fit well the DMA mapping and syncing calls and we have tons of checks around on top of it. So, instead of doing that rework the code to use per transfer per direction flag to show if it's DMA mapped or not. Signed-off-by: Andy Shevchenko Tested-by: Neil Armstrong # on SM8650-QRD Link: https://lore.kernel.org/r/20240531194723.1761567-9-andriy.shevchenko@linux.intel.com Reviewed-by: Serge Semin Tested-by: Nícolas F. R. A. Prado Signed-off-by: Mark Brown --- drivers/spi/internals.h | 2 +- drivers/spi/spi.c | 73 ++++++++++++++++++------------------------------- include/linux/spi/spi.h | 11 +++++--- 3 files changed, 35 insertions(+), 51 deletions(-) diff --git a/drivers/spi/internals.h b/drivers/spi/internals.h index 47a87c2a6979..1f459b895891 100644 --- a/drivers/spi/internals.h +++ b/drivers/spi/internals.h @@ -45,7 +45,7 @@ static inline bool spi_xfer_is_dma_mapped(struct spi_controller *ctlr, struct spi_transfer *xfer) { return ctlr->can_dma && ctlr->can_dma(ctlr, spi, xfer) && - ctlr->cur_msg_mapped; + (xfer->tx_sg_mapped || xfer->rx_sg_mapped); } #endif /* __LINUX_SPI_INTERNALS_H */ diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index c1e8cde426e5..9721adf048b5 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -1220,11 +1220,6 @@ void spi_unmap_buf(struct spi_controller *ctlr, struct device *dev, spi_unmap_buf_attrs(ctlr, dev, sgt, dir, 0); } -/* Dummy SG for unidirect transfers */ -static struct scatterlist dummy_sg = { - .page_link = SG_END, -}; - static int __spi_map_msg(struct spi_controller *ctlr, struct spi_message *msg) { struct device *tx_dev, *rx_dev; @@ -1263,8 +1258,8 @@ static int __spi_map_msg(struct spi_controller *ctlr, struct spi_message *msg) attrs); if (ret != 0) return ret; - } else { - xfer->tx_sg.sgl = &dummy_sg; + + xfer->tx_sg_mapped = true; } if (xfer->rx_buf != NULL) { @@ -1278,8 +1273,8 @@ static int __spi_map_msg(struct spi_controller *ctlr, struct spi_message *msg) return ret; } - } else { - xfer->rx_sg.sgl = &dummy_sg; + + xfer->rx_sg_mapped = true; } } /* No transfer has been mapped, bail out with success */ @@ -1288,7 +1283,6 @@ static int __spi_map_msg(struct spi_controller *ctlr, struct spi_message *msg) ctlr->cur_rx_dma_dev = rx_dev; ctlr->cur_tx_dma_dev = tx_dev; - ctlr->cur_msg_mapped = true; return 0; } @@ -1299,57 +1293,46 @@ static int __spi_unmap_msg(struct spi_controller *ctlr, struct spi_message *msg) struct device *tx_dev = ctlr->cur_tx_dma_dev; struct spi_transfer *xfer; - if (!ctlr->cur_msg_mapped || !ctlr->can_dma) - return 0; - list_for_each_entry(xfer, &msg->transfers, transfer_list) { /* The sync has already been done after each transfer. */ unsigned long attrs = DMA_ATTR_SKIP_CPU_SYNC; - if (!ctlr->can_dma(ctlr, msg->spi, xfer)) - continue; + if (xfer->rx_sg_mapped) + spi_unmap_buf_attrs(ctlr, rx_dev, &xfer->rx_sg, + DMA_FROM_DEVICE, attrs); + xfer->rx_sg_mapped = false; - spi_unmap_buf_attrs(ctlr, rx_dev, &xfer->rx_sg, - DMA_FROM_DEVICE, attrs); - spi_unmap_buf_attrs(ctlr, tx_dev, &xfer->tx_sg, - DMA_TO_DEVICE, attrs); + if (xfer->tx_sg_mapped) + spi_unmap_buf_attrs(ctlr, tx_dev, &xfer->tx_sg, + DMA_TO_DEVICE, attrs); + xfer->tx_sg_mapped = false; } - ctlr->cur_msg_mapped = false; - return 0; } -static void spi_dma_sync_for_device(struct spi_controller *ctlr, struct spi_message *msg, +static void spi_dma_sync_for_device(struct spi_controller *ctlr, struct spi_transfer *xfer) { struct device *rx_dev = ctlr->cur_rx_dma_dev; struct device *tx_dev = ctlr->cur_tx_dma_dev; - if (!ctlr->cur_msg_mapped) - return; - - if (!ctlr->can_dma(ctlr, msg->spi, xfer)) - return; - - dma_sync_sgtable_for_device(tx_dev, &xfer->tx_sg, DMA_TO_DEVICE); - dma_sync_sgtable_for_device(rx_dev, &xfer->rx_sg, DMA_FROM_DEVICE); + if (xfer->tx_sg_mapped) + dma_sync_sgtable_for_device(tx_dev, &xfer->tx_sg, DMA_TO_DEVICE); + if (xfer->rx_sg_mapped) + dma_sync_sgtable_for_device(rx_dev, &xfer->rx_sg, DMA_FROM_DEVICE); } -static void spi_dma_sync_for_cpu(struct spi_controller *ctlr, struct spi_message *msg, +static void spi_dma_sync_for_cpu(struct spi_controller *ctlr, struct spi_transfer *xfer) { struct device *rx_dev = ctlr->cur_rx_dma_dev; struct device *tx_dev = ctlr->cur_tx_dma_dev; - if (!ctlr->cur_msg_mapped) - return; - - if (!ctlr->can_dma(ctlr, msg->spi, xfer)) - return; - - dma_sync_sgtable_for_cpu(rx_dev, &xfer->rx_sg, DMA_FROM_DEVICE); - dma_sync_sgtable_for_cpu(tx_dev, &xfer->tx_sg, DMA_TO_DEVICE); + if (xfer->rx_sg_mapped) + dma_sync_sgtable_for_cpu(rx_dev, &xfer->rx_sg, DMA_FROM_DEVICE); + if (xfer->tx_sg_mapped) + dma_sync_sgtable_for_cpu(tx_dev, &xfer->tx_sg, DMA_TO_DEVICE); } #else /* !CONFIG_HAS_DMA */ static inline int __spi_map_msg(struct spi_controller *ctlr, @@ -1365,13 +1348,11 @@ static inline int __spi_unmap_msg(struct spi_controller *ctlr, } static void spi_dma_sync_for_device(struct spi_controller *ctrl, - struct spi_message *msg, struct spi_transfer *xfer) { } static void spi_dma_sync_for_cpu(struct spi_controller *ctrl, - struct spi_message *msg, struct spi_transfer *xfer) { } @@ -1643,13 +1624,13 @@ static int spi_transfer_one_message(struct spi_controller *ctlr, reinit_completion(&ctlr->xfer_completion); fallback_pio: - spi_dma_sync_for_device(ctlr, msg, xfer); + spi_dma_sync_for_device(ctlr, xfer); ret = ctlr->transfer_one(ctlr, msg->spi, xfer); if (ret < 0) { - spi_dma_sync_for_cpu(ctlr, msg, xfer); + spi_dma_sync_for_cpu(ctlr, xfer); - if (ctlr->cur_msg_mapped && - (xfer->error & SPI_TRANS_FAIL_NO_START)) { + if ((xfer->tx_sg_mapped || xfer->rx_sg_mapped) && + (xfer->error & SPI_TRANS_FAIL_NO_START)) { __spi_unmap_msg(ctlr, msg); ctlr->fallback = true; xfer->error &= ~SPI_TRANS_FAIL_NO_START; @@ -1671,7 +1652,7 @@ fallback_pio: msg->status = ret; } - spi_dma_sync_for_cpu(ctlr, msg, xfer); + spi_dma_sync_for_cpu(ctlr, xfer); } else { if (xfer->len) dev_err(&msg->spi->dev, diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h index e8e1e798924f..b4a89db4c855 100644 --- a/include/linux/spi/spi.h +++ b/include/linux/spi/spi.h @@ -447,7 +447,6 @@ extern struct spi_device *spi_new_ancillary_device(struct spi_device *spi, u8 ch * @cur_msg_need_completion: Flag used internally to opportunistically skip * the @cur_msg_completion. This flag is used to signal the context that * is running spi_finalize_current_message() that it needs to complete() - * @cur_msg_mapped: message has been mapped for DMA * @fallback: fallback to PIO if DMA transfer return failure with * SPI_TRANS_FAIL_NO_START. * @last_cs_mode_high: was (mode & SPI_CS_HIGH) true on the last call to set_cs. @@ -708,7 +707,6 @@ struct spi_controller { bool running; bool rt; bool auto_runtime_pm; - bool cur_msg_mapped; bool fallback; bool last_cs_mode_high; s8 last_cs[SPI_CS_CNT_MAX]; @@ -981,6 +979,8 @@ struct spi_res { * transfer this transfer. Set to 0 if the SPI bus driver does * not support it. * @transfer_list: transfers are sequenced through @spi_message.transfers + * @tx_sg_mapped: If true, the @tx_sg is mapped for DMA + * @rx_sg_mapped: If true, the @rx_sg is mapped for DMA * @tx_sg: Scatterlist for transmit, currently not for client use * @rx_sg: Scatterlist for receive, currently not for client use * @ptp_sts_word_pre: The word (subject to bits_per_word semantics) offset @@ -1077,10 +1077,13 @@ struct spi_transfer { #define SPI_TRANS_FAIL_IO BIT(1) u16 error; - dma_addr_t tx_dma; - dma_addr_t rx_dma; + bool tx_sg_mapped; + bool rx_sg_mapped; + struct sg_table tx_sg; struct sg_table rx_sg; + dma_addr_t tx_dma; + dma_addr_t rx_dma; unsigned dummy_data:1; unsigned cs_off:1; -- cgit v1.2.3 From 022bd9c520d8f9dd51f29326eb369b8ec958f687 Mon Sep 17 00:00:00 2001 From: Xianwei Zhao Date: Fri, 24 May 2024 14:35:09 +0800 Subject: spi: meson-spicc: set SPI clock flag CLK_SET_RATE_PARENT Add SPI clock flag CLK_SET_RATE_PARENT for using pclk as parent clock. This gives SPI more flexibility in frequency selection. Signed-off-by: Xianwei Zhao Signed-off-by: Sunny Luo Link: https://lore.kernel.org/r/20240524-spi_pclk_setparent-v1-1-99e0ce70b66f@amlogic.com Signed-off-by: Mark Brown --- drivers/spi/spi-meson-spicc.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/drivers/spi/spi-meson-spicc.c b/drivers/spi/spi-meson-spicc.c index fc75492e50ff..8a4a8ba9dfed 100644 --- a/drivers/spi/spi-meson-spicc.c +++ b/drivers/spi/spi-meson-spicc.c @@ -644,11 +644,13 @@ static int meson_spicc_pow2_clk_init(struct meson_spicc_device *spicc) snprintf(name, sizeof(name), "%s#pow2_fixed_div", dev_name(dev)); init.name = name; init.ops = &clk_fixed_factor_ops; - init.flags = 0; - if (spicc->data->has_pclk) + if (spicc->data->has_pclk) { + init.flags = CLK_SET_RATE_PARENT; parent_data[0].hw = __clk_get_hw(spicc->pclk); - else + } else { + init.flags = 0; parent_data[0].hw = __clk_get_hw(spicc->core); + } init.num_parents = 1; pow2_fixed_div->mult = 1, @@ -708,11 +710,13 @@ static int meson_spicc_enh_clk_init(struct meson_spicc_device *spicc) snprintf(name, sizeof(name), "%s#enh_fixed_div", dev_name(dev)); init.name = name; init.ops = &clk_fixed_factor_ops; - init.flags = 0; - if (spicc->data->has_pclk) + if (spicc->data->has_pclk) { + init.flags = CLK_SET_RATE_PARENT; parent_data[0].hw = __clk_get_hw(spicc->pclk); - else + } else { + init.flags = 0; parent_data[0].hw = __clk_get_hw(spicc->core); + } init.num_parents = 1; enh_fixed_div->mult = 1, -- cgit v1.2.3 From 8a71710bb4797174733a16df2bcb8683fbe7caea Mon Sep 17 00:00:00 2001 From: Jeff Johnson Date: Sun, 9 Jun 2024 15:18:58 -0700 Subject: spi: add missing MODULE_DESCRIPTION() macros make allmodconfig && make W=1 C=1 reports: WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/spi/spi-altera-core.o WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/spi/spi-fsl-lib.o WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/spi/spi-omap2-mcspi.o WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/spi/spi-qup.o Add the missing invocations of the MODULE_DESCRIPTION() macro. Signed-off-by: Jeff Johnson Link: https://lore.kernel.org/r/20240609-md-drivers-spi-v1-1-1c7444f53cde@quicinc.com Signed-off-by: Mark Brown --- drivers/spi/spi-altera-core.c | 1 + drivers/spi/spi-fsl-cpm.c | 1 + drivers/spi/spi-fsl-lib.c | 1 + drivers/spi/spi-omap-uwire.c | 1 + drivers/spi/spi-omap2-mcspi.c | 1 + drivers/spi/spi-qup.c | 1 + 6 files changed, 6 insertions(+) diff --git a/drivers/spi/spi-altera-core.c b/drivers/spi/spi-altera-core.c index 87e37f48f196..7af097929116 100644 --- a/drivers/spi/spi-altera-core.c +++ b/drivers/spi/spi-altera-core.c @@ -219,4 +219,5 @@ void altera_spi_init_host(struct spi_controller *host) } EXPORT_SYMBOL_GPL(altera_spi_init_host); +MODULE_DESCRIPTION("Altera SPI Controller driver core"); MODULE_LICENSE("GPL"); diff --git a/drivers/spi/spi-fsl-cpm.c b/drivers/spi/spi-fsl-cpm.c index e335132080bf..23ad1249f121 100644 --- a/drivers/spi/spi-fsl-cpm.c +++ b/drivers/spi/spi-fsl-cpm.c @@ -415,4 +415,5 @@ void fsl_spi_cpm_free(struct mpc8xxx_spi *mspi) } EXPORT_SYMBOL_GPL(fsl_spi_cpm_free); +MODULE_DESCRIPTION("Freescale SPI controller driver CPM functions"); MODULE_LICENSE("GPL"); diff --git a/drivers/spi/spi-fsl-lib.c b/drivers/spi/spi-fsl-lib.c index 4fc2c56555b5..bb7a625db5b0 100644 --- a/drivers/spi/spi-fsl-lib.c +++ b/drivers/spi/spi-fsl-lib.c @@ -158,4 +158,5 @@ int of_mpc8xxx_spi_probe(struct platform_device *ofdev) } EXPORT_SYMBOL_GPL(of_mpc8xxx_spi_probe); +MODULE_DESCRIPTION("Freescale SPI/eSPI controller driver library"); MODULE_LICENSE("GPL"); diff --git a/drivers/spi/spi-omap-uwire.c b/drivers/spi/spi-omap-uwire.c index 210a98d903fa..03b820e85651 100644 --- a/drivers/spi/spi-omap-uwire.c +++ b/drivers/spi/spi-omap-uwire.c @@ -541,5 +541,6 @@ static void __exit omap_uwire_exit(void) subsys_initcall(omap_uwire_init); module_exit(omap_uwire_exit); +MODULE_DESCRIPTION("MicroWire interface driver for OMAP"); MODULE_LICENSE("GPL"); diff --git a/drivers/spi/spi-omap2-mcspi.c b/drivers/spi/spi-omap2-mcspi.c index 7e3083b83534..b428990f6931 100644 --- a/drivers/spi/spi-omap2-mcspi.c +++ b/drivers/spi/spi-omap2-mcspi.c @@ -1671,4 +1671,5 @@ static struct platform_driver omap2_mcspi_driver = { }; module_platform_driver(omap2_mcspi_driver); +MODULE_DESCRIPTION("OMAP2 McSPI controller driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/spi/spi-qup.c b/drivers/spi/spi-qup.c index 2af63040ac6e..1e335cd961a4 100644 --- a/drivers/spi/spi-qup.c +++ b/drivers/spi/spi-qup.c @@ -1369,5 +1369,6 @@ static struct platform_driver spi_qup_driver = { }; module_platform_driver(spi_qup_driver); +MODULE_DESCRIPTION("Qualcomm SPI controller with QUP interface"); MODULE_LICENSE("GPL v2"); MODULE_ALIAS("platform:spi_qup"); -- cgit v1.2.3 From 313d2c9d1252185721cad4f8c57099840d6c9958 Mon Sep 17 00:00:00 2001 From: Xianwei Zhao Date: Wed, 12 Jun 2024 17:44:50 +0800 Subject: spi: meson-spicc: add spicc loopback mode Add spicc loopback mode for debugging convenience. Signed-off-by: Sunny Luo Signed-off-by: Xianwei Zhao Reviewed-by: Neil Armstrong Link: https://lore.kernel.org/r/20240612-spi_lbc-v1-1-d52e8c8011bd@amlogic.com Signed-off-by: Mark Brown --- drivers/spi/spi-meson-spicc.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/spi/spi-meson-spicc.c b/drivers/spi/spi-meson-spicc.c index 8a4a8ba9dfed..8838a98b04c2 100644 --- a/drivers/spi/spi-meson-spicc.c +++ b/drivers/spi/spi-meson-spicc.c @@ -514,7 +514,9 @@ static int meson_spicc_prepare_message(struct spi_controller *host, /* Setup no wait cycles by default */ writel_relaxed(0, spicc->base + SPICC_PERIODREG); - writel_bits_relaxed(SPICC_LBC_W1, 0, spicc->base + SPICC_TESTREG); + writel_bits_relaxed(SPICC_LBC_W1, + spi->mode & SPI_LOOP ? SPICC_LBC_W1 : 0, + spicc->base + SPICC_TESTREG); return 0; } @@ -850,7 +852,7 @@ static int meson_spicc_probe(struct platform_device *pdev) host->num_chipselect = 4; host->dev.of_node = pdev->dev.of_node; - host->mode_bits = SPI_CPHA | SPI_CPOL | SPI_CS_HIGH; + host->mode_bits = SPI_CPHA | SPI_CPOL | SPI_CS_HIGH | SPI_LOOP; host->bits_per_word_mask = SPI_BPW_MASK(32) | SPI_BPW_MASK(24) | SPI_BPW_MASK(16) | -- cgit v1.2.3 From 6914ee9cd1b0c91bd2fb4dbe204947c3c31259e1 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Tue, 11 Jun 2024 14:25:54 +0100 Subject: spi: cs42l43: Refactor accessing the SDCA extension properties Refactor accessing the SDCA extension properties to make it easier to access multiple properties to assist with future features. Return the node itself and allow the caller to read the actual properties. Signed-off-by: Charles Keepax Link: https://msgid.link/r/20240611132556.1557075-1-ckeepax@opensource.cirrus.com Signed-off-by: Mark Brown --- drivers/spi/spi-cs42l43.c | 25 +++++++++---------------- 1 file changed, 9 insertions(+), 16 deletions(-) diff --git a/drivers/spi/spi-cs42l43.c b/drivers/spi/spi-cs42l43.c index 9d747ea69926..0993ee20f035 100644 --- a/drivers/spi/spi-cs42l43.c +++ b/drivers/spi/spi-cs42l43.c @@ -246,11 +246,10 @@ static size_t cs42l43_spi_max_length(struct spi_device *spi) return CS42L43_SPI_MAX_LENGTH; } -static bool cs42l43_has_sidecar(struct fwnode_handle *fwnode) +static struct fwnode_handle *cs42l43_find_xu_node(struct fwnode_handle *fwnode) { static const u32 func_smart_amp = 0x1; struct fwnode_handle *child_fwnode, *ext_fwnode; - unsigned int val; u32 function; int ret; @@ -266,21 +265,12 @@ static bool cs42l43_has_sidecar(struct fwnode_handle *fwnode) if (!ext_fwnode) continue; - ret = fwnode_property_read_u32(ext_fwnode, - "01fa-sidecar-instances", - &val); - - fwnode_handle_put(ext_fwnode); - - if (ret) - continue; - fwnode_handle_put(child_fwnode); - return !!val; + return ext_fwnode; } - return false; + return NULL; } static void cs42l43_release_of_node(void *data) @@ -298,7 +288,8 @@ static int cs42l43_spi_probe(struct platform_device *pdev) struct cs42l43 *cs42l43 = dev_get_drvdata(pdev->dev.parent); struct cs42l43_spi *priv; struct fwnode_handle *fwnode = dev_fwnode(cs42l43->dev); - bool has_sidecar = cs42l43_has_sidecar(fwnode); + struct fwnode_handle *xu_fwnode __free(fwnode_handle) = cs42l43_find_xu_node(fwnode); + int nsidecars = 0; int ret; priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); @@ -350,7 +341,9 @@ static int cs42l43_spi_probe(struct platform_device *pdev) return ret; } - if (has_sidecar) { + fwnode_property_read_u32(xu_fwnode, "01fa-sidecar-instances", &nsidecars); + + if (nsidecars) { ret = software_node_register(&cs42l43_gpiochip_swnode); if (ret) return dev_err_probe(priv->dev, ret, @@ -373,7 +366,7 @@ static int cs42l43_spi_probe(struct platform_device *pdev) return dev_err_probe(priv->dev, ret, "Failed to register SPI controller\n"); - if (has_sidecar) { + if (nsidecars) { if (!spi_new_device(priv->ctlr, &l_info)) return dev_err_probe(priv->dev, -ENODEV, "Failed to create left amp slave\n"); -- cgit v1.2.3 From 78b05172b42d14a4c6fc6b75b31590b8977900dc Mon Sep 17 00:00:00 2001 From: Amit Kumar Mahapatra Date: Mon, 17 Jun 2024 21:08:37 +0530 Subject: spi: spi-cadence: Enable spi refclk in slave mode When spi-cadence is configured as a slave, it requires the SPI refclk to detect the synchronization start condition while communicating with the master. However, the spi-cadence driver never enables the SPI refclk in slave mode, causing the refclk to remain disabled if the "clk_ignore_unused" kernel parameter is not passed through bootargs. As a result, the slave cannot detect data sent by the master, leading to communication failure. Update driver to enable the SPI refclk in both master and slave configurations. Fixes: b1b90514eaa3 ("spi: spi-cadence: Add support for Slave mode") Signed-off-by: Amit Kumar Mahapatra Link: https://msgid.link/r/20240617153837.29861-1-amit.kumar-mahapatra@amd.com Signed-off-by: Mark Brown --- drivers/spi/spi-cadence.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/spi/spi-cadence.c b/drivers/spi/spi-cadence.c index 4eacf3f6e031..e07e081de5ea 100644 --- a/drivers/spi/spi-cadence.c +++ b/drivers/spi/spi-cadence.c @@ -601,14 +601,14 @@ static int cdns_spi_probe(struct platform_device *pdev) reset_control_assert(xspi->rstc); reset_control_deassert(xspi->rstc); - if (!spi_controller_is_target(ctlr)) { - xspi->ref_clk = devm_clk_get_enabled(&pdev->dev, "ref_clk"); - if (IS_ERR(xspi->ref_clk)) { - dev_err(&pdev->dev, "ref_clk clock not found.\n"); - ret = PTR_ERR(xspi->ref_clk); - goto remove_ctlr; - } + xspi->ref_clk = devm_clk_get_enabled(&pdev->dev, "ref_clk"); + if (IS_ERR(xspi->ref_clk)) { + dev_err(&pdev->dev, "ref_clk clock not found.\n"); + ret = PTR_ERR(xspi->ref_clk); + goto remove_ctlr; + } + if (!spi_controller_is_target(ctlr)) { pm_runtime_use_autosuspend(&pdev->dev); pm_runtime_set_autosuspend_delay(&pdev->dev, SPI_AUTOSUSPEND_TIMEOUT); pm_runtime_get_noresume(&pdev->dev); -- cgit v1.2.3 From cc169cf869fdac34531fd4d0e7317f0576883228 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Wed, 19 Jun 2024 13:17:02 +0100 Subject: spi: cs42l43: Refactor accessing the SDCA extension properties Refactor accessing the SDCA extension properties to make it easier to access multiple properties to assist with future features. Return the node itself and allow the caller to read the actual properties. Signed-off-by: Charles Keepax Link: https://patch.msgid.link/20240619121703.3411989-1-ckeepax@opensource.cirrus.com Signed-off-by: Mark Brown --- drivers/spi/spi-cs42l43.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/spi/spi-cs42l43.c b/drivers/spi/spi-cs42l43.c index 0a4475ae931b..7b6fc6158a3b 100644 --- a/drivers/spi/spi-cs42l43.c +++ b/drivers/spi/spi-cs42l43.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include -- cgit v1.2.3 From 0ca645ab5b1528666f6662a0e620140355b5aea3 Mon Sep 17 00:00:00 2001 From: Simon Trimmer Date: Wed, 19 Jun 2024 13:17:03 +0100 Subject: spi: cs42l43: Add speaker id support to the bridge configuration OEMs can connect a number of types of speakers to the sidecar cs35l56 amplifiers and a different speaker requires a different firmware configuration. When the cs42l43 ACPI includes a property indicating a particular type of speaker has been installed this should be passed to the cs35l56 driver instances as a device property. Signed-off-by: Simon Trimmer Signed-off-by: Charles Keepax Link: https://patch.msgid.link/20240619121703.3411989-2-ckeepax@opensource.cirrus.com Signed-off-by: Mark Brown --- drivers/spi/spi-cs42l43.c | 73 +++++++++++++++++++++++++++++++++-------------- 1 file changed, 52 insertions(+), 21 deletions(-) diff --git a/drivers/spi/spi-cs42l43.c b/drivers/spi/spi-cs42l43.c index 7b6fc6158a3b..5b8ed65f8094 100644 --- a/drivers/spi/spi-cs42l43.c +++ b/drivers/spi/spi-cs42l43.c @@ -45,28 +45,10 @@ static const unsigned int cs42l43_clock_divs[] = { 2, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30 }; -static const struct software_node ampl = { - .name = "cs35l56-left", -}; - -static const struct software_node ampr = { - .name = "cs35l56-right", -}; - -static struct spi_board_info ampl_info = { +static struct spi_board_info amp_info_template = { .modalias = "cs35l56", .max_speed_hz = 11 * HZ_PER_MHZ, - .chip_select = 0, .mode = SPI_MODE_0, - .swnode = &l, -}; - -static struct spi_board_info ampr_info = { - .modalias = "cs35l56", - .max_speed_hz = 11 * HZ_PER_MHZ, - .chip_select = 1, - .mode = SPI_MODE_0, - .swnode = &r, }; static const struct software_node cs42l43_gpiochip_swnode = { @@ -274,6 +256,39 @@ static struct fwnode_handle *cs42l43_find_xu_node(struct fwnode_handle *fwnode) return NULL; } +static struct spi_board_info *cs42l43_create_bridge_amp(struct cs42l43_spi *priv, + const char * const name, + int cs, int spkid) +{ + struct property_entry *props = NULL; + struct software_node *swnode; + struct spi_board_info *info; + + if (spkid >= 0) { + props = devm_kmalloc(priv->dev, sizeof(*props), GFP_KERNEL); + if (!props) + return NULL; + + *props = PROPERTY_ENTRY_U32("cirrus,speaker-id", spkid); + } + + swnode = devm_kmalloc(priv->dev, sizeof(*swnode), GFP_KERNEL); + if (!swnode) + return NULL; + + *swnode = SOFTWARE_NODE(name, props, NULL); + + info = devm_kmemdup(priv->dev, &_info_template, + sizeof(amp_info_template), GFP_KERNEL); + if (!info) + return NULL; + + info->chip_select = cs; + info->swnode = swnode; + + return info; +} + static void cs42l43_release_of_node(void *data) { fwnode_handle_put(data); @@ -368,11 +383,27 @@ static int cs42l43_spi_probe(struct platform_device *pdev) "Failed to register SPI controller\n"); if (nsidecars) { - if (!spi_new_device(priv->ctlr, &l_info)) + struct spi_board_info *ampl_info; + struct spi_board_info *ampr_info; + int spkid = -EINVAL; + + fwnode_property_read_u32(xu_fwnode, "01fa-spk-id-val", &spkid); + + dev_dbg(priv->dev, "Found speaker ID %d\n", spkid); + + ampl_info = cs42l43_create_bridge_amp(priv, "cs35l56-left", 0, spkid); + if (!ampl_info) + return -ENOMEM; + + ampr_info = cs42l43_create_bridge_amp(priv, "cs35l56-right", 1, spkid); + if (!ampr_info) + return -ENOMEM; + + if (!spi_new_device(priv->ctlr, ampl_info)) return dev_err_probe(priv->dev, -ENODEV, "Failed to create left amp slave\n"); - if (!spi_new_device(priv->ctlr, &r_info)) + if (!spi_new_device(priv->ctlr, ampr_info)) return dev_err_probe(priv->dev, -ENODEV, "Failed to create right amp slave\n"); } -- cgit v1.2.3 From 5d0c35feea339e4a3a9c9e99731e4d49ad5ee329 Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Wed, 8 May 2024 11:56:10 +0200 Subject: spi: imx: Don't expect DMA for i.MX{25,35,50,51,53} cspi devices MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit While in commit 2dd33f9cec90 ("spi: imx: support DMA for imx35") it was claimed that DMA works on i.MX25, i.MX31 and i.MX35 the respective device trees don't add DMA channels. The Reference manuals of i.MX31 and i.MX25 also don't mention the CSPI core being DMA capable. (I didn't check the others.) Since commit e267a5b3ec59 ("spi: spi-imx: Use dev_err_probe for failed DMA channel requests") this results in an error message spi_imx 43fa4000.spi: error -ENODEV: can't get the TX DMA channel! during boot. However that isn't fatal and the driver gets loaded just fine, just without using DMA. Signed-off-by: Uwe Kleine-König Link: https://patch.msgid.link/20240508095610.2146640-2-u.kleine-koenig@pengutronix.de Signed-off-by: Mark Brown --- drivers/spi/spi-imx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/spi/spi-imx.c b/drivers/spi/spi-imx.c index 6f1cd3453c97..d9434fde6de6 100644 --- a/drivers/spi/spi-imx.c +++ b/drivers/spi/spi-imx.c @@ -1050,7 +1050,7 @@ static struct spi_imx_devtype_data imx35_cspi_devtype_data = { .rx_available = mx31_rx_available, .reset = mx31_reset, .fifo_size = 8, - .has_dmamode = true, + .has_dmamode = false, .dynamic_burst = false, .has_targetmode = false, .devtype = IMX35_CSPI, -- cgit v1.2.3 From 9b894d65e9788ece0d51e76d2c184524900f5ec9 Mon Sep 17 00:00:00 2001 From: David Lechner Date: Fri, 21 Jun 2024 15:51:30 -0500 Subject: Documentation: devres: add missing SPI helpers A few SPI devm_* helpers were missing from the devres documentation. This patch adds them. Signed-off-by: David Lechner Link: https://patch.msgid.link/20240621-devm_spi_optimize_message-v1-1-3f9dcba6e95e@baylibre.com Signed-off-by: Mark Brown --- Documentation/driver-api/driver-model/devres.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Documentation/driver-api/driver-model/devres.rst b/Documentation/driver-api/driver-model/devres.rst index 18caebad7376..a1c17bcae68d 100644 --- a/Documentation/driver-api/driver-model/devres.rst +++ b/Documentation/driver-api/driver-model/devres.rst @@ -465,6 +465,8 @@ SPI devm_spi_alloc_master() devm_spi_alloc_slave() devm_spi_register_controller() + devm_spi_register_host() + devm_spi_register_target() WATCHDOG devm_watchdog_register_device() -- cgit v1.2.3 From d4a0055fdc22381fa256e345095e88d134e354c5 Mon Sep 17 00:00:00 2001 From: David Lechner Date: Fri, 21 Jun 2024 15:51:31 -0500 Subject: spi: add devm_spi_optimize_message() helper This adds a new helper function devm_spi_optimize_message() that automatically registers spi_unoptimize_message() to be called when the device is removed. Signed-off-by: David Lechner Link: https://patch.msgid.link/20240621-devm_spi_optimize_message-v1-2-3f9dcba6e95e@baylibre.com Signed-off-by: Mark Brown --- Documentation/driver-api/driver-model/devres.rst | 1 + drivers/spi/spi.c | 27 ++++++++++++++++++++++++ include/linux/spi/spi.h | 2 ++ 3 files changed, 30 insertions(+) diff --git a/Documentation/driver-api/driver-model/devres.rst b/Documentation/driver-api/driver-model/devres.rst index a1c17bcae68d..ac9ee7441887 100644 --- a/Documentation/driver-api/driver-model/devres.rst +++ b/Documentation/driver-api/driver-model/devres.rst @@ -464,6 +464,7 @@ SLAVE DMA ENGINE SPI devm_spi_alloc_master() devm_spi_alloc_slave() + devm_spi_optimize_message() devm_spi_register_controller() devm_spi_register_host() devm_spi_register_target() diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index 9bc9fd10d538..32d2a4f3dfca 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -4378,6 +4378,33 @@ static int __spi_async(struct spi_device *spi, struct spi_message *message) return ctlr->transfer(spi, message); } +static void devm_spi_unoptimize_message(void *msg) +{ + spi_unoptimize_message(msg); +} + +/** + * devm_spi_optimize_message - managed version of spi_optimize_message() + * @dev: the device that manages @msg (usually @spi->dev) + * @spi: the device that will be used for the message + * @msg: the message to optimize + * Return: zero on success, else a negative error code + * + * spi_unoptimize_message() will automatically be called when the device is + * removed. + */ +int devm_spi_optimize_message(struct device *dev, struct spi_device *spi, + struct spi_message *msg) +{ + int ret; + + ret = spi_optimize_message(spi, msg); + if (ret) + return ret; + + return devm_add_action_or_reset(dev, devm_spi_unoptimize_message, msg); +} + /** * spi_async - asynchronous SPI transfer * @spi: device with which data will be exchanged diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h index e8e1e798924f..e6e5978f7564 100644 --- a/include/linux/spi/spi.h +++ b/include/linux/spi/spi.h @@ -1268,6 +1268,8 @@ static inline void spi_message_free(struct spi_message *m) extern int spi_optimize_message(struct spi_device *spi, struct spi_message *msg); extern void spi_unoptimize_message(struct spi_message *msg); +extern int devm_spi_optimize_message(struct device *dev, struct spi_device *spi, + struct spi_message *msg); extern int spi_setup(struct spi_device *spi); extern int spi_async(struct spi_device *spi, struct spi_message *message); -- cgit v1.2.3 From 7e74a45c7afdd8a9f82d14fd79ae0383bbaaed1e Mon Sep 17 00:00:00 2001 From: David Lechner Date: Mon, 24 Jun 2024 15:10:30 -0500 Subject: spi: add EXPORT_SYMBOL_GPL(devm_spi_optimize_message) devm_spi_optimize_message() is a public function and needs EXPORT_SYMBOL_GPL. Reported-by: Jonathan Cameron Closes: https://lore.kernel.org/linux-iio/20240624204424.6a91a5e4@jic23-huawei/ Fixes: d4a0055fdc22 ("spi: add devm_spi_optimize_message() helper") Signed-off-by: David Lechner Link: https://patch.msgid.link/20240624-devm_spi_optimize_message-v2-1-58155c0180c2@baylibre.com Signed-off-by: Mark Brown --- drivers/spi/spi.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index 32d2a4f3dfca..93f59ebb5b79 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -4404,6 +4404,7 @@ int devm_spi_optimize_message(struct device *dev, struct spi_device *spi, return devm_add_action_or_reset(dev, devm_spi_unoptimize_message, msg); } +EXPORT_SYMBOL_GPL(devm_spi_optimize_message); /** * spi_async - asynchronous SPI transfer -- cgit v1.2.3 From a93f089ccf823dcb9cf678969e127047762a1473 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Mon, 24 Jun 2024 21:20:22 -0300 Subject: spi: spi-imx: Switch to RUNTIME_PM_OPS/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 notation from the runtime suspend/resume() functions. Signed-off-by: Fabio Estevam Link: https://patch.msgid.link/20240625002023.228235-1-festevam@gmail.com Signed-off-by: Mark Brown --- drivers/spi/spi-imx.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/drivers/spi/spi-imx.c b/drivers/spi/spi-imx.c index d9434fde6de6..35f5eafc1c38 100644 --- a/drivers/spi/spi-imx.c +++ b/drivers/spi/spi-imx.c @@ -1898,7 +1898,7 @@ static void spi_imx_remove(struct platform_device *pdev) spi_imx_sdma_exit(spi_imx); } -static int __maybe_unused spi_imx_runtime_resume(struct device *dev) +static int spi_imx_runtime_resume(struct device *dev) { struct spi_controller *controller = dev_get_drvdata(dev); struct spi_imx_data *spi_imx; @@ -1919,7 +1919,7 @@ static int __maybe_unused spi_imx_runtime_resume(struct device *dev) return 0; } -static int __maybe_unused spi_imx_runtime_suspend(struct device *dev) +static int spi_imx_runtime_suspend(struct device *dev) { struct spi_controller *controller = dev_get_drvdata(dev); struct spi_imx_data *spi_imx; @@ -1932,22 +1932,21 @@ static int __maybe_unused spi_imx_runtime_suspend(struct device *dev) return 0; } -static int __maybe_unused spi_imx_suspend(struct device *dev) +static int spi_imx_suspend(struct device *dev) { pinctrl_pm_select_sleep_state(dev); return 0; } -static int __maybe_unused spi_imx_resume(struct device *dev) +static int spi_imx_resume(struct device *dev) { pinctrl_pm_select_default_state(dev); return 0; } static const struct dev_pm_ops imx_spi_pm = { - SET_RUNTIME_PM_OPS(spi_imx_runtime_suspend, - spi_imx_runtime_resume, NULL) - SET_SYSTEM_SLEEP_PM_OPS(spi_imx_suspend, spi_imx_resume) + RUNTIME_PM_OPS(spi_imx_runtime_suspend, spi_imx_runtime_resume, NULL) + SYSTEM_SLEEP_PM_OPS(spi_imx_suspend, spi_imx_resume) }; static struct platform_driver spi_imx_driver = { -- cgit v1.2.3 From 6765e859fac9acdc1265b6f16ed33f42317ed30e Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Mon, 24 Jun 2024 21:20:23 -0300 Subject: spi: spi-fsl-lpspi: Switch to SYSTEM_SLEEP_PM_OPS() Replace SET_SYSTEM_SLEEP_PM_OPS with its modern SYSTEM_SLEEP_PM_OPS() alternative. The combined usage of pm_ptr() and 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 notation from the runtime suspend/resume() functions. Signed-off-by: Fabio Estevam Link: https://patch.msgid.link/20240625002023.228235-2-festevam@gmail.com Signed-off-by: Mark Brown --- drivers/spi/spi-fsl-lpspi.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/spi/spi-fsl-lpspi.c b/drivers/spi/spi-fsl-lpspi.c index aa5ed254be46..2908a5532482 100644 --- a/drivers/spi/spi-fsl-lpspi.c +++ b/drivers/spi/spi-fsl-lpspi.c @@ -960,13 +960,13 @@ static void fsl_lpspi_remove(struct platform_device *pdev) pm_runtime_disable(fsl_lpspi->dev); } -static int __maybe_unused fsl_lpspi_suspend(struct device *dev) +static int fsl_lpspi_suspend(struct device *dev) { pinctrl_pm_select_sleep_state(dev); return pm_runtime_force_suspend(dev); } -static int __maybe_unused fsl_lpspi_resume(struct device *dev) +static int fsl_lpspi_resume(struct device *dev) { int ret; @@ -984,7 +984,7 @@ static int __maybe_unused fsl_lpspi_resume(struct device *dev) static const struct dev_pm_ops fsl_lpspi_pm_ops = { SET_RUNTIME_PM_OPS(fsl_lpspi_runtime_suspend, fsl_lpspi_runtime_resume, NULL) - SET_SYSTEM_SLEEP_PM_OPS(fsl_lpspi_suspend, fsl_lpspi_resume) + SYSTEM_SLEEP_PM_OPS(fsl_lpspi_suspend, fsl_lpspi_resume) }; static struct platform_driver fsl_lpspi_driver = { -- cgit v1.2.3 From 2d4e40dcdc5590550704681f1b147c3dadfdbf31 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Tue, 25 Jun 2024 15:39:18 -0300 Subject: spi: spi-imx: Pass pm_ptr() After coverting to RUNTIME_PM_OPS/SYSTEM_SLEEP_PM_OPS, it is necessary to pass pm_ptr() to the PM operations. Fix it accordingly. Fixes: a93f089ccf82 ("spi: spi-imx: Switch to RUNTIME_PM_OPS/SYSTEM_SLEEP_PM_OPS()") Signed-off-by: Fabio Estevam Link: https://patch.msgid.link/20240625183919.368770-1-festevam@gmail.com Signed-off-by: Mark Brown --- drivers/spi/spi-imx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/spi/spi-imx.c b/drivers/spi/spi-imx.c index 35f5eafc1c38..85bd1a82a34e 100644 --- a/drivers/spi/spi-imx.c +++ b/drivers/spi/spi-imx.c @@ -1953,7 +1953,7 @@ static struct platform_driver spi_imx_driver = { .driver = { .name = DRIVER_NAME, .of_match_table = spi_imx_dt_ids, - .pm = &imx_spi_pm, + .pm = pm_ptr(&imx_spi_pm), }, .probe = spi_imx_probe, .remove_new = spi_imx_remove, -- cgit v1.2.3 From 14201399457ce5314224c2898c936bfaa5849fcb Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Tue, 25 Jun 2024 15:39:19 -0300 Subject: spi: spi-fsl-lpspi: Pass pm_ptr() After coverting to SYSTEM_SLEEP_PM_OPS, it is necessary to pass pm_ptr() to the PM operations. Fix it accordingly. Fixes: 6765e859fac9 ("spi: spi-fsl-lpspi: Switch to SYSTEM_SLEEP_PM_OPS()") Signed-off-by: Fabio Estevam Link: https://patch.msgid.link/20240625183919.368770-2-festevam@gmail.com Signed-off-by: Mark Brown --- drivers/spi/spi-fsl-lpspi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/spi/spi-fsl-lpspi.c b/drivers/spi/spi-fsl-lpspi.c index 2908a5532482..32baa14dfd83 100644 --- a/drivers/spi/spi-fsl-lpspi.c +++ b/drivers/spi/spi-fsl-lpspi.c @@ -991,7 +991,7 @@ static struct platform_driver fsl_lpspi_driver = { .driver = { .name = DRIVER_NAME, .of_match_table = fsl_lpspi_dt_ids, - .pm = &fsl_lpspi_pm_ops, + .pm = pm_ptr(&fsl_lpspi_pm_ops), }, .probe = fsl_lpspi_probe, .remove_new = fsl_lpspi_remove, -- cgit v1.2.3 From 89c2657429c4822a2697077bbb3a8d126d826ced Mon Sep 17 00:00:00 2001 From: David Lechner Date: Wed, 26 Jun 2024 14:45:17 -0500 Subject: spi: axi-spi-engine: remove platform_set_drvdata() platform_get_drvdata() is never called in the AXI SPI Engine driver, so platform_set_drvdata() is not needed. Remove it. This also lets us avoid the final error check in the probe function. Signed-off-by: David Lechner Reviewed-by: Nuno Sa Link: https://patch.msgid.link/20240626-spi-axi-spi-engine-remove-drvdata-v1-1-1752e372dd5d@baylibre.com Signed-off-by: Mark Brown --- drivers/spi/spi-axi-spi-engine.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/drivers/spi/spi-axi-spi-engine.c b/drivers/spi/spi-axi-spi-engine.c index 3231f67ae265..03588fac9215 100644 --- a/drivers/spi/spi-axi-spi-engine.c +++ b/drivers/spi/spi-axi-spi-engine.c @@ -690,13 +690,7 @@ static int spi_engine_probe(struct platform_device *pdev) if (host->max_speed_hz == 0) return dev_err_probe(&pdev->dev, -EINVAL, "spi_clk rate is 0"); - ret = devm_spi_register_controller(&pdev->dev, host); - if (ret) - return ret; - - platform_set_drvdata(pdev, host); - - return 0; + return devm_spi_register_controller(&pdev->dev, host); } static const struct of_device_id spi_engine_match_table[] = { -- cgit v1.2.3 From 52e78777b6bfd4bc47448791a99d5f97c82ff81c Mon Sep 17 00:00:00 2001 From: Frank Li Date: Mon, 24 Jun 2024 14:55:27 -0400 Subject: spi: fsl-dspi: use common proptery 'spi-cs-setup(hold)-delay-ns' Use SPI common DT binding properties 'spi-cs-setup-delay-ns' and 'spi-cs-hold-delay-ns'. If these properties do not exist, fall back to legacy 'fsl,spi-cs-sck-delay' and 'fsl,spi-sck-cs-delay'. Signed-off-by: Frank Li Reviewed-by: Vladimir Oltean Link: https://patch.msgid.link/20240624-ls_qspi-v4-1-3d1c6f5005bf@nxp.com Signed-off-by: Mark Brown --- drivers/spi/spi-fsl-dspi.c | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/drivers/spi/spi-fsl-dspi.c b/drivers/spi/spi-fsl-dspi.c index 0a2730cd07c6..191de1917f83 100644 --- a/drivers/spi/spi-fsl-dspi.c +++ b/drivers/spi/spi-fsl-dspi.c @@ -1006,6 +1006,7 @@ static int dspi_setup(struct spi_device *spi) struct chip_data *chip; unsigned long clkrate; bool cs = true; + int val; /* Only alloc on first setup */ chip = spi_get_ctldata(spi); @@ -1018,11 +1019,19 @@ static int dspi_setup(struct spi_device *spi) pdata = dev_get_platdata(&dspi->pdev->dev); if (!pdata) { - of_property_read_u32(spi->dev.of_node, "fsl,spi-cs-sck-delay", - &cs_sck_delay); - - of_property_read_u32(spi->dev.of_node, "fsl,spi-sck-cs-delay", - &sck_cs_delay); + val = spi_delay_to_ns(&spi->cs_setup, NULL); + cs_sck_delay = val >= 0 ? val : 0; + if (!cs_sck_delay) + of_property_read_u32(spi->dev.of_node, + "fsl,spi-cs-sck-delay", + &cs_sck_delay); + + val = spi_delay_to_ns(&spi->cs_hold, NULL); + sck_cs_delay = val >= 0 ? val : 0; + if (!sck_cs_delay) + of_property_read_u32(spi->dev.of_node, + "fsl,spi-sck-cs-delay", + &sck_cs_delay); } else { cs_sck_delay = pdata->cs_sck_delay; sck_cs_delay = pdata->sck_cs_delay; -- cgit v1.2.3 From 94f19d076218a193d170da6d5ab2a87c080cc69c Mon Sep 17 00:00:00 2001 From: Frank Li Date: Mon, 24 Jun 2024 14:55:28 -0400 Subject: spi: dt-bindings: fsl-dspi: Convert to yaml format Convert dt-binding spi-fsl-dspi.txt to yaml format. Use part Vladimir Oltean's work at of https://lore.kernel.org/linux-spi/20221111224651.577729-1-vladimir.oltean@nxp.com/ Additional changes during convert: - compatible string "fsl,ls1028a-dspi" can be followed by fsl,ls1021a-v1.0-dspi. - Change "dspi0@4002c000" to "spi@4002c000" in example. - Reorder properties in example. - Use GIC include in example. - Deprecated fsl,spi-cs-sck-delay and fsl,spi-sck-cs-delay by use common SPI property. - Use compatible string 'jedec,spi-nor' in example. - Split peripheral part to fsl,dspi-peripheral-props.yaml. - Remove 'interrupts' and 'pinctrl' from required list. - Update 'bus-num' description. - Update 'spi-num-chipselects' description by add "cs-gpios don't count against this number". - Remove 'big-endian' description. Co-developed-by: Kuldeep Singh Signed-off-by: Kuldeep Singh Co-developed-by: Vladimir Oltean Signed-off-by: Vladimir Oltean Signed-off-by: Frank Li Reviewed-by: Vladimir Oltean Reviewed-by: Rob Herring (Arm) Link: https://patch.msgid.link/20240624-ls_qspi-v4-2-3d1c6f5005bf@nxp.com Signed-off-by: Mark Brown --- .../bindings/spi/fsl,dspi-peripheral-props.yaml | 30 ++++++ .../devicetree/bindings/spi/fsl,dspi.yaml | 103 +++++++++++++++++++++ .../devicetree/bindings/spi/spi-fsl-dspi.txt | 65 ------------- .../bindings/spi/spi-peripheral-props.yaml | 1 + MAINTAINERS | 2 +- 5 files changed, 135 insertions(+), 66 deletions(-) create mode 100644 Documentation/devicetree/bindings/spi/fsl,dspi-peripheral-props.yaml create mode 100644 Documentation/devicetree/bindings/spi/fsl,dspi.yaml delete mode 100644 Documentation/devicetree/bindings/spi/spi-fsl-dspi.txt diff --git a/Documentation/devicetree/bindings/spi/fsl,dspi-peripheral-props.yaml b/Documentation/devicetree/bindings/spi/fsl,dspi-peripheral-props.yaml new file mode 100644 index 000000000000..9b62b75e17a7 --- /dev/null +++ b/Documentation/devicetree/bindings/spi/fsl,dspi-peripheral-props.yaml @@ -0,0 +1,30 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/spi/fsl,dspi-peripheral-props.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Peripheral-specific properties for Freescale DSPI controller + +maintainers: + - Vladimir Oltean + +description: + See spi-peripheral-props.yaml for more info. + +properties: + fsl,spi-cs-sck-delay: + deprecated: true + description: + Delay in nanoseconds between activating chip select and the start of + clock signal, at the start of a transfer. + $ref: /schemas/types.yaml#/definitions/uint32 + + fsl,spi-sck-cs-delay: + deprecated: true + description: + Delay in nanoseconds between stopping the clock signal and + deactivating chip select, at the end of a transfer. + $ref: /schemas/types.yaml#/definitions/uint32 + +additionalProperties: true diff --git a/Documentation/devicetree/bindings/spi/fsl,dspi.yaml b/Documentation/devicetree/bindings/spi/fsl,dspi.yaml new file mode 100644 index 000000000000..bd28335a6ac8 --- /dev/null +++ b/Documentation/devicetree/bindings/spi/fsl,dspi.yaml @@ -0,0 +1,103 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/spi/fsl,dspi.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: ARM Freescale DSPI controller + +maintainers: + - Frank Li + +properties: + compatible: + oneOf: + - enum: + - fsl,vf610-dspi + - fsl,ls1021a-v1.0-dspi + - fsl,ls1012a-dspi + - fsl,ls1028a-dspi + - fsl,ls1043a-dspi + - fsl,ls1046a-dspi + - fsl,ls1088a-dspi + - fsl,ls2080a-dspi + - fsl,ls2085a-dspi + - fsl,lx2160a-dspi + - items: + - enum: + - fsl,ls1012a-dspi + - fsl,ls1028a-dspi + - fsl,ls1043a-dspi + - fsl,ls1046a-dspi + - fsl,ls1088a-dspi + - const: fsl,ls1021a-v1.0-dspi + - items: + - const: fsl,ls2080a-dspi + - const: fsl,ls2085a-dspi + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + clocks: + maxItems: 1 + + clock-names: + items: + - const: dspi + + spi-num-chipselects: + $ref: /schemas/types.yaml#/definitions/uint32 + description: + The number of the chip native chipselect signals. + cs-gpios don't count against this number. + + big-endian: true + + bus-num: + $ref: /schemas/types.yaml#/definitions/uint32 + description: SoC-specific identifier for the SPI controller. + +required: + - compatible + - reg + - clocks + - clock-names + - spi-num-chipselects + +allOf: + - $ref: spi-controller.yaml# + +unevaluatedProperties: false + +examples: + - | + #include + #include + + spi@4002c000 { + compatible = "fsl,vf610-dspi"; + reg = <0x4002c000 0x1000>; + #address-cells = <1>; + #size-cells = <0>; + interrupts = ; + clocks = <&clks VF610_CLK_DSPI0>; + clock-names = "dspi"; + spi-num-chipselects = <5>; + bus-num = <0>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_dspi0_1>; + big-endian; + + flash@0 { + compatible = "jedec,spi-nor"; + reg = <0>; + spi-max-frequency = <16000000>; + spi-cpol; + spi-cpha; + spi-cs-setup-delay-ns = <100>; + spi-cs-hold-delay-ns = <50>; + }; + }; diff --git a/Documentation/devicetree/bindings/spi/spi-fsl-dspi.txt b/Documentation/devicetree/bindings/spi/spi-fsl-dspi.txt deleted file mode 100644 index 30a79da9c039..000000000000 --- a/Documentation/devicetree/bindings/spi/spi-fsl-dspi.txt +++ /dev/null @@ -1,65 +0,0 @@ -ARM Freescale DSPI controller - -Required properties: -- compatible : must be one of: - "fsl,vf610-dspi", - "fsl,ls1021a-v1.0-dspi", - "fsl,ls1012a-dspi" (optionally followed by "fsl,ls1021a-v1.0-dspi"), - "fsl,ls1028a-dspi", - "fsl,ls1043a-dspi" (optionally followed by "fsl,ls1021a-v1.0-dspi"), - "fsl,ls1046a-dspi" (optionally followed by "fsl,ls1021a-v1.0-dspi"), - "fsl,ls1088a-dspi" (optionally followed by "fsl,ls1021a-v1.0-dspi"), - "fsl,ls2080a-dspi" (optionally followed by "fsl,ls2085a-dspi"), - "fsl,ls2085a-dspi", - "fsl,lx2160a-dspi", -- reg : Offset and length of the register set for the device -- interrupts : Should contain SPI controller interrupt -- clocks: from common clock binding: handle to dspi clock. -- clock-names: from common clock binding: Shall be "dspi". -- pinctrl-0: pin control group to be used for this controller. -- pinctrl-names: must contain a "default" entry. -- spi-num-chipselects : the number of the chipselect signals. - -Optional property: -- big-endian: If present the dspi device's registers are implemented - in big endian mode. -- bus-num : the slave chip chipselect signal number. - -Optional SPI slave node properties: -- fsl,spi-cs-sck-delay: a delay in nanoseconds between activating chip - select and the start of clock signal, at the start of a transfer. -- fsl,spi-sck-cs-delay: a delay in nanoseconds between stopping the clock - signal and deactivating chip select, at the end of a transfer. - -Example: - -dspi0@4002c000 { - #address-cells = <1>; - #size-cells = <0>; - compatible = "fsl,vf610-dspi"; - reg = <0x4002c000 0x1000>; - interrupts = <0 67 0x04>; - clocks = <&clks VF610_CLK_DSPI0>; - clock-names = "dspi"; - spi-num-chipselects = <5>; - bus-num = <0>; - pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_dspi0_1>; - big-endian; - - sflash: at26df081a@0 { - #address-cells = <1>; - #size-cells = <1>; - compatible = "atmel,at26df081a"; - spi-max-frequency = <16000000>; - spi-cpol; - spi-cpha; - reg = <0>; - linux,modalias = "m25p80"; - modal = "at26df081a"; - fsl,spi-cs-sck-delay = <100>; - fsl,spi-sck-cs-delay = <50>; - }; -}; - - diff --git a/Documentation/devicetree/bindings/spi/spi-peripheral-props.yaml b/Documentation/devicetree/bindings/spi/spi-peripheral-props.yaml index 15938f81fdce..0bb443b8decd 100644 --- a/Documentation/devicetree/bindings/spi/spi-peripheral-props.yaml +++ b/Documentation/devicetree/bindings/spi/spi-peripheral-props.yaml @@ -122,6 +122,7 @@ properties: allOf: - $ref: arm,pl022-peripheral-props.yaml# - $ref: cdns,qspi-nor-peripheral-props.yaml# + - $ref: fsl,dspi-peripheral-props.yaml# - $ref: samsung,spi-peripheral-props.yaml# - $ref: nvidia,tegra210-quad-peripheral-props.yaml# diff --git a/MAINTAINERS b/MAINTAINERS index cf9c9221c388..763b79fd7fdb 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -8708,7 +8708,7 @@ FREESCALE DSPI DRIVER M: Vladimir Oltean L: linux-spi@vger.kernel.org S: Maintained -F: Documentation/devicetree/bindings/spi/spi-fsl-dspi.txt +F: Documentation/devicetree/bindings/spi/fsl,dspi*.yaml F: drivers/spi/spi-fsl-dspi.c F: include/linux/spi/spi-fsl-dspi.h -- cgit v1.2.3 From 6c387fb263363347185bd7a213ad175c174d35dc Mon Sep 17 00:00:00 2001 From: Kanak Shilledar Date: Mon, 1 Jul 2024 17:43:52 +0530 Subject: spi: dt-bindings: snps,dw-apb-ssi.yaml: update compatible property updated compatible property to include "thead,th1520-spi" for the TH1520 SoC SPI Controller. Signed-off-by: Kanak Shilledar Acked-by: Conor Dooley Link: https://patch.msgid.link/20240701121355.262259-3-kanakshilledar@gmail.com Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/spi/snps,dw-apb-ssi.yaml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Documentation/devicetree/bindings/spi/snps,dw-apb-ssi.yaml b/Documentation/devicetree/bindings/spi/snps,dw-apb-ssi.yaml index fde3776a558b..bccd00a1ddd0 100644 --- a/Documentation/devicetree/bindings/spi/snps,dw-apb-ssi.yaml +++ b/Documentation/devicetree/bindings/spi/snps,dw-apb-ssi.yaml @@ -88,6 +88,10 @@ properties: - renesas,r9a06g032-spi # RZ/N1D - renesas,r9a06g033-spi # RZ/N1S - const: renesas,rzn1-spi # RZ/N1 + - description: T-HEAD TH1520 SoC SPI Controller + items: + - const: thead,th1520-spi + - const: snps,dw-apb-ssi reg: minItems: 1 -- cgit v1.2.3 From 5211070c3309bb3679f4522c77b900f551db5739 Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Fri, 5 Jul 2024 17:12:39 +0200 Subject: spi: xcomm: add gpiochip support The hardware can expose one pin as a GPO. Hence, register a simple gpiochip to support it. Signed-off-by: Michael Hennerich Co-developed-by: Nuno Sa Signed-off-by: Nuno Sa Link: https://patch.msgid.link/20240705-dev-spi-xcomm-gpiochip-v2-1-b10842fc9636@analog.com Signed-off-by: Mark Brown --- drivers/spi/spi-xcomm.c | 42 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 41 insertions(+), 1 deletion(-) diff --git a/drivers/spi/spi-xcomm.c b/drivers/spi/spi-xcomm.c index 63354dd3110f..063ce75af650 100644 --- a/drivers/spi/spi-xcomm.c +++ b/drivers/spi/spi-xcomm.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include @@ -26,12 +27,15 @@ #define SPI_XCOMM_CMD_UPDATE_CONFIG 0x03 #define SPI_XCOMM_CMD_WRITE 0x04 +#define SPI_XCOMM_CMD_GPIO_SET 0x05 #define SPI_XCOMM_CLOCK 48000000 struct spi_xcomm { struct i2c_client *i2c; + struct gpio_chip gc; + uint16_t settings; uint16_t chipselect; @@ -40,6 +44,42 @@ struct spi_xcomm { uint8_t buf[63]; }; +static void spi_xcomm_gpio_set_value(struct gpio_chip *chip, + unsigned int offset, int val) +{ + struct spi_xcomm *spi_xcomm = gpiochip_get_data(chip); + unsigned char buf[2]; + + buf[0] = SPI_XCOMM_CMD_GPIO_SET; + buf[1] = !!val; + + i2c_master_send(spi_xcomm->i2c, buf, 2); +} + +static int spi_xcomm_gpio_get_direction(struct gpio_chip *chip, + unsigned int offset) +{ + return GPIO_LINE_DIRECTION_OUT; +} + +static int spi_xcomm_gpio_add(struct spi_xcomm *spi_xcomm) +{ + struct device *dev = &spi_xcomm->i2c->dev; + + if (!IS_ENABLED(CONFIG_GPIOLIB)) + return 0; + + spi_xcomm->gc.get_direction = spi_xcomm_gpio_get_direction; + spi_xcomm->gc.set = spi_xcomm_gpio_set_value; + spi_xcomm->gc.can_sleep = 1; + spi_xcomm->gc.base = -1; + spi_xcomm->gc.ngpio = 1; + spi_xcomm->gc.label = spi_xcomm->i2c->name; + spi_xcomm->gc.owner = THIS_MODULE; + + return devm_gpiochip_add_data(dev, &spi_xcomm->gc, spi_xcomm); +} + static int spi_xcomm_sync_config(struct spi_xcomm *spi_xcomm, unsigned int len) { uint16_t settings; @@ -227,7 +267,7 @@ static int spi_xcomm_probe(struct i2c_client *i2c) if (ret < 0) spi_controller_put(host); - return ret; + return spi_xcomm_gpio_add(spi_xcomm); } static const struct i2c_device_id spi_xcomm_ids[] = { -- cgit v1.2.3 From e8ba259764c745e7de20ec517ae920ecd491b687 Mon Sep 17 00:00:00 2001 From: Nuno Sa Date: Fri, 5 Jul 2024 17:12:40 +0200 Subject: spi: xcomm: make use of 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: Nuno Sa Link: https://patch.msgid.link/20240705-dev-spi-xcomm-gpiochip-v2-2-b10842fc9636@analog.com Signed-off-by: Mark Brown --- drivers/spi/spi-xcomm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/spi/spi-xcomm.c b/drivers/spi/spi-xcomm.c index 063ce75af650..5bbc250bc053 100644 --- a/drivers/spi/spi-xcomm.c +++ b/drivers/spi/spi-xcomm.c @@ -248,7 +248,7 @@ static int spi_xcomm_probe(struct i2c_client *i2c) struct spi_controller *host; int ret; - host = spi_alloc_host(&i2c->dev, sizeof(*spi_xcomm)); + host = devm_spi_alloc_host(&i2c->dev, sizeof(*spi_xcomm)); if (!host) return -ENOMEM; @@ -265,7 +265,7 @@ static int spi_xcomm_probe(struct i2c_client *i2c) ret = devm_spi_register_controller(&i2c->dev, host); if (ret < 0) - spi_controller_put(host); + return ret; return spi_xcomm_gpio_add(spi_xcomm); } -- cgit v1.2.3 From 5e7d4755c58a347b4fe7663cef9b169b0965d09d Mon Sep 17 00:00:00 2001 From: Nuno Sa Date: Fri, 5 Jul 2024 17:12:41 +0200 Subject: spi: xcomm: remove i2c_set_clientdata() i2c_get_clientdata() is not being called anywhere so that we do not need to set clientdata. Signed-off-by: Nuno Sa Link: https://patch.msgid.link/20240705-dev-spi-xcomm-gpiochip-v2-3-b10842fc9636@analog.com Signed-off-by: Mark Brown --- drivers/spi/spi-xcomm.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/spi/spi-xcomm.c b/drivers/spi/spi-xcomm.c index 5bbc250bc053..1cd7d2b9e11c 100644 --- a/drivers/spi/spi-xcomm.c +++ b/drivers/spi/spi-xcomm.c @@ -261,7 +261,6 @@ static int spi_xcomm_probe(struct i2c_client *i2c) host->flags = SPI_CONTROLLER_HALF_DUPLEX; host->transfer_one_message = spi_xcomm_transfer_one; host->dev.of_node = i2c->dev.of_node; - i2c_set_clientdata(i2c, host); ret = devm_spi_register_controller(&i2c->dev, host); if (ret < 0) -- cgit v1.2.3 From e2e89f96308add00fed632ecb416d84c9313f6aa Mon Sep 17 00:00:00 2001 From: Nuno Sa Date: Fri, 5 Jul 2024 17:12:42 +0200 Subject: spi: xcomm: fix coding style Just cosmetics. No functional change intended. While at it, removed a couple of redundant else if() statements. Signed-off-by: Nuno Sa Link: https://patch.msgid.link/20240705-dev-spi-xcomm-gpiochip-v2-4-b10842fc9636@analog.com Signed-off-by: Mark Brown --- drivers/spi/spi-xcomm.c | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/drivers/spi/spi-xcomm.c b/drivers/spi/spi-xcomm.c index 1cd7d2b9e11c..846f00e23b71 100644 --- a/drivers/spi/spi-xcomm.c +++ b/drivers/spi/spi-xcomm.c @@ -36,12 +36,12 @@ struct spi_xcomm { struct gpio_chip gc; - uint16_t settings; - uint16_t chipselect; + u16 settings; + u16 chipselect; unsigned int current_speed; - uint8_t buf[63]; + u8 buf[63]; }; static void spi_xcomm_gpio_set_value(struct gpio_chip *chip, @@ -82,8 +82,8 @@ static int spi_xcomm_gpio_add(struct spi_xcomm *spi_xcomm) static int spi_xcomm_sync_config(struct spi_xcomm *spi_xcomm, unsigned int len) { - uint16_t settings; - uint8_t *buf = spi_xcomm->buf; + u16 settings; + u8 *buf = spi_xcomm->buf; settings = spi_xcomm->settings; settings |= len << SPI_XCOMM_SETTINGS_LEN_OFFSET; @@ -96,10 +96,10 @@ static int spi_xcomm_sync_config(struct spi_xcomm *spi_xcomm, unsigned int len) } static void spi_xcomm_chipselect(struct spi_xcomm *spi_xcomm, - struct spi_device *spi, int is_active) + struct spi_device *spi, int is_active) { unsigned long cs = spi_get_chipselect(spi, 0); - uint16_t chipselect = spi_xcomm->chipselect; + u16 chipselect = spi_xcomm->chipselect; if (is_active) chipselect |= BIT(cs); @@ -110,7 +110,8 @@ static void spi_xcomm_chipselect(struct spi_xcomm *spi_xcomm, } static int spi_xcomm_setup_transfer(struct spi_xcomm *spi_xcomm, - struct spi_device *spi, struct spi_transfer *t, unsigned int *settings) + struct spi_device *spi, struct spi_transfer *t, + unsigned int *settings) { if (t->len > 62) return -EINVAL; @@ -148,7 +149,7 @@ static int spi_xcomm_setup_transfer(struct spi_xcomm *spi_xcomm, } static int spi_xcomm_txrx_bufs(struct spi_xcomm *spi_xcomm, - struct spi_device *spi, struct spi_transfer *t) + struct spi_device *spi, struct spi_transfer *t) { int ret; @@ -159,13 +160,13 @@ static int spi_xcomm_txrx_bufs(struct spi_xcomm *spi_xcomm, ret = i2c_master_send(spi_xcomm->i2c, spi_xcomm->buf, t->len + 1); if (ret < 0) return ret; - else if (ret != t->len + 1) + if (ret != t->len + 1) return -EIO; } else if (t->rx_buf) { ret = i2c_master_recv(spi_xcomm->i2c, t->rx_buf, t->len); if (ret < 0) return ret; - else if (ret != t->len) + if (ret != t->len) return -EIO; } @@ -173,12 +174,12 @@ static int spi_xcomm_txrx_bufs(struct spi_xcomm *spi_xcomm, } static int spi_xcomm_transfer_one(struct spi_controller *host, - struct spi_message *msg) + struct spi_message *msg) { struct spi_xcomm *spi_xcomm = spi_controller_get_devdata(host); unsigned int settings = spi_xcomm->settings; struct spi_device *spi = msg->spi; - unsigned cs_change = 0; + unsigned int cs_change = 0; struct spi_transfer *t; bool is_first = true; int status = 0; @@ -187,7 +188,6 @@ static int spi_xcomm_transfer_one(struct spi_controller *host, spi_xcomm_chipselect(spi_xcomm, spi, true); list_for_each_entry(t, &msg->transfers, transfer_list) { - if (!t->tx_buf && !t->rx_buf && t->len) { status = -EINVAL; break; -- cgit v1.2.3 From 0f2ecc3f6136a922f9d54499c80004bae6c42348 Mon Sep 17 00:00:00 2001 From: Li zeming Date: Mon, 8 Jul 2024 11:53:20 +0800 Subject: spi: spi: Remove unnecessary ‘0’ values from rc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit rc is assigned first, so it does not need to initialize the assignment. Signed-off-by: Li zeming Link: https://patch.msgid.link/20240708035320.14241-1-zeming@nfschina.com Signed-off-by: Mark Brown --- drivers/spi/spi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index 814d66fc9753..10f4faf0720f 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -2570,7 +2570,7 @@ struct spi_device *spi_new_ancillary_device(struct spi_device *spi, { struct spi_controller *ctlr = spi->controller; struct spi_device *ancillary; - int rc = 0; + int rc; /* Alloc an spi_device */ ancillary = spi_alloc_device(ctlr); -- cgit v1.2.3 From 3bca1a3808a9674c410dcae2ca07fb3fbd74e614 Mon Sep 17 00:00:00 2001 From: Li zeming Date: Mon, 8 Jul 2024 12:14:11 +0800 Subject: spi: spi: Remove unnecessary ‘0’ values from status MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit status is assigned first, so it does not need to initialize the assignment. Signed-off-by: Li zeming Link: https://patch.msgid.link/20240708041411.14424-1-zeming@nfschina.com Signed-off-by: Mark Brown --- drivers/spi/spi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index 10f4faf0720f..5e715a640237 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -3901,7 +3901,7 @@ static int spi_set_cs_timing(struct spi_device *spi) int spi_setup(struct spi_device *spi) { unsigned bad_bits, ugly_bits; - int status = 0; + int status; /* * Check mode to prevent that any two of DUAL, QUAD and NO_MOSI/MISO -- cgit v1.2.3 From 2de9ae2044c4f6490dbbfb8d93fe6b8cc60c91d1 Mon Sep 17 00:00:00 2001 From: Frank Li Date: Wed, 3 Jul 2024 12:59:30 -0400 Subject: spi: dt-bindings: fsl-dspi: add dmas and dma-names properties Add dmas and dma-names properties because dspi support dma transfer. Fix below warnings: arch/arm64/boot/dts/freescale/fsl-ls1028a-kontron-sl28-var1.dtb: spi@2120000: Unevaluated properties are not allowed ('dma-names', 'dmas', 'little-endian' were unexpected) from schema $id: http://devicetree.org/schemas/spi/fsl,dspi.yaml# Reviewed-by: Krzysztof Kozlowski Signed-off-by: Frank Li Reviewed-by: Vladimir Oltean Link: https://patch.msgid.link/20240703165931.2325807-1-Frank.Li@nxp.com Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/spi/fsl,dspi.yaml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/Documentation/devicetree/bindings/spi/fsl,dspi.yaml b/Documentation/devicetree/bindings/spi/fsl,dspi.yaml index bd28335a6ac8..f16ac2229145 100644 --- a/Documentation/devicetree/bindings/spi/fsl,dspi.yaml +++ b/Documentation/devicetree/bindings/spi/fsl,dspi.yaml @@ -48,6 +48,16 @@ properties: items: - const: dspi + dmas: + items: + - description: DMA controller phandle and request line for TX + - description: DMA controller phandle and request line for RX + + dma-names: + items: + - const: tx + - const: rx + spi-num-chipselects: $ref: /schemas/types.yaml#/definitions/uint32 description: -- cgit v1.2.3 From 0f17a12787573dda66d2528fff27cd7362b34bfd Mon Sep 17 00:00:00 2001 From: Frank Li Date: Wed, 3 Jul 2024 12:59:31 -0400 Subject: spi: dt-bindings: fsl-dspi: add compatible string 'fsl,lx2160a-dspi' Add compatible string 'fsl,lx2160a-dspi' and allow fall back to 'fsl,ls2085a-dspi'. Fix below CHECK_DTBS warning. arch/arm64/boot/dts/freescale/fsl-lx2160a-bluebox3.dtb: spi@2100000: compatible: 'oneOf' conditional failed, one must be fixed: ['fsl,lx2160a-dspi', 'fsl,ls2085a-dspi'] is too long Signed-off-by: Frank Li Link: https://patch.msgid.link/20240703165931.2325807-2-Frank.Li@nxp.com Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/spi/fsl,dspi.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Documentation/devicetree/bindings/spi/fsl,dspi.yaml b/Documentation/devicetree/bindings/spi/fsl,dspi.yaml index f16ac2229145..7ca8fceda717 100644 --- a/Documentation/devicetree/bindings/spi/fsl,dspi.yaml +++ b/Documentation/devicetree/bindings/spi/fsl,dspi.yaml @@ -34,6 +34,9 @@ properties: - items: - const: fsl,ls2080a-dspi - const: fsl,ls2085a-dspi + - items: + - const: fsl,lx2160a-dspi + - const: fsl,ls2085a-dspi reg: maxItems: 1 -- cgit v1.2.3 From 8846739f52afa07e63395c80227dc544f54bd7b1 Mon Sep 17 00:00:00 2001 From: Johannes Thumshirn Date: Mon, 8 Jul 2024 17:49:28 +0200 Subject: spi: add ch341a usb2spi driver Add a driver for the QiHeng Electronics ch341a USB-to-SPI adapter. This driver is loosely based on the ch341a module from the flashrom project. Signed-off-by: Johannes Thumshirn Link: https://patch.msgid.link/20240708-spi-ch341a-v3-1-cf7f9b2c1e31@kernel.org Signed-off-by: Mark Brown --- drivers/spi/Kconfig | 6 ++ drivers/spi/Makefile | 1 + drivers/spi/spi-ch341.c | 241 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 248 insertions(+) create mode 100644 drivers/spi/spi-ch341.c diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index a2c99ff33e0a..ec1550c698d5 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -277,6 +277,12 @@ config SPI_CADENCE_XSPI device with a Cadence XSPI controller and want to access the Flash as an MTD device. +config SPI_CH341 + tristate "CH341 USB2SPI adapter" + depends on SPI_MASTER && USB + help + Enables the SPI controller on the CH341a USB to serial chip + config SPI_CLPS711X tristate "CLPS711X host SPI controller" depends on ARCH_CLPS711X || COMPILE_TEST diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile index bcfb6efd88e0..a9b1bc259b68 100644 --- a/drivers/spi/Makefile +++ b/drivers/spi/Makefile @@ -39,6 +39,7 @@ obj-$(CONFIG_SPI_BUTTERFLY) += spi-butterfly.o obj-$(CONFIG_SPI_CADENCE) += spi-cadence.o obj-$(CONFIG_SPI_CADENCE_QUADSPI) += spi-cadence-quadspi.o obj-$(CONFIG_SPI_CADENCE_XSPI) += spi-cadence-xspi.o +obj-$(CONFIG_SPI_CH341) += spi-ch341.o obj-$(CONFIG_SPI_CLPS711X) += spi-clps711x.o obj-$(CONFIG_SPI_COLDFIRE_QSPI) += spi-coldfire-qspi.o obj-$(CONFIG_SPI_CS42L43) += spi-cs42l43.o diff --git a/drivers/spi/spi-ch341.c b/drivers/spi/spi-ch341.c new file mode 100644 index 000000000000..d2351812d310 --- /dev/null +++ b/drivers/spi/spi-ch341.c @@ -0,0 +1,241 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// QiHeng Electronics ch341a USB-to-SPI adapter driver +// +// Copyright (C) 2024 Johannes Thumshirn +// +// Based on ch341a_spi.c from the flashrom project. + +#include +#include +#include + +#define CH341_PACKET_LENGTH 32 +#define CH341_DEFAULT_TIMEOUT 1000 + +#define CH341A_CMD_UIO_STREAM 0xab + +#define CH341A_CMD_UIO_STM_END 0x20 +#define CH341A_CMD_UIO_STM_DIR 0x40 +#define CH341A_CMD_UIO_STM_OUT 0x80 + +#define CH341A_CMD_I2C_STREAM 0xaa +#define CH341A_CMD_I2C_STM_SET 0x60 +#define CH341A_CMD_I2C_STM_END 0x00 + +#define CH341A_CMD_SPI_STREAM 0xa8 + +#define CH341A_STM_I2C_100K 0x01 + +struct ch341_spi_dev { + struct spi_controller *ctrl; + struct usb_device *udev; + unsigned int write_pipe; + unsigned int read_pipe; + int rx_len; + void *rx_buf; + u8 *tx_buf; + struct urb *rx_urb; + struct spi_device *spidev; +}; + +static void ch341_set_cs(struct spi_device *spi, bool is_high) +{ + struct ch341_spi_dev *ch341 = + spi_controller_get_devdata(spi->controller); + int err; + + memset(ch341->tx_buf, 0, CH341_PACKET_LENGTH); + ch341->tx_buf[0] = CH341A_CMD_UIO_STREAM; + ch341->tx_buf[1] = CH341A_CMD_UIO_STM_OUT | (is_high ? 0x36 : 0x37); + + if (is_high) { + ch341->tx_buf[2] = CH341A_CMD_UIO_STM_DIR | 0x3f; + ch341->tx_buf[3] = CH341A_CMD_UIO_STM_END; + } else { + ch341->tx_buf[2] = CH341A_CMD_UIO_STM_END; + } + + err = usb_bulk_msg(ch341->udev, ch341->write_pipe, ch341->tx_buf, + (is_high ? 4 : 3), NULL, CH341_DEFAULT_TIMEOUT); + if (err) + dev_err(&spi->dev, + "error sending USB message for setting CS (%d)\n", err); +} + +static int ch341_transfer_one(struct spi_controller *host, + struct spi_device *spi, + struct spi_transfer *trans) +{ + struct ch341_spi_dev *ch341 = + spi_controller_get_devdata(spi->controller); + int len; + int ret; + + len = min(CH341_PACKET_LENGTH, trans->len + 1); + + memset(ch341->tx_buf, 0, CH341_PACKET_LENGTH); + + ch341->tx_buf[0] = CH341A_CMD_SPI_STREAM; + + memcpy(ch341->tx_buf + 1, trans->tx_buf, len); + + ret = usb_bulk_msg(ch341->udev, ch341->write_pipe, ch341->tx_buf, len, + NULL, CH341_DEFAULT_TIMEOUT); + if (ret) + return ret; + + return usb_bulk_msg(ch341->udev, ch341->read_pipe, trans->rx_buf, + len - 1, NULL, CH341_DEFAULT_TIMEOUT); +} + +static void ch341_recv(struct urb *urb) +{ + struct ch341_spi_dev *ch341 = urb->context; + struct usb_device *udev = ch341->udev; + + switch (urb->status) { + case 0: + /* success */ + break; + case -ENOENT: + case -ECONNRESET: + case -EPIPE: + case -ESHUTDOWN: + dev_dbg(&udev->dev, "rx urb terminated with status: %d\n", + urb->status); + return; + default: + dev_dbg(&udev->dev, "rx urb error: %d\n", urb->status); + break; + } +} + +static int ch341_config_stream(struct ch341_spi_dev *ch341) +{ + memset(ch341->tx_buf, 0, CH341_PACKET_LENGTH); + ch341->tx_buf[0] = CH341A_CMD_I2C_STREAM; + ch341->tx_buf[1] = CH341A_CMD_I2C_STM_SET | CH341A_STM_I2C_100K; + ch341->tx_buf[2] = CH341A_CMD_I2C_STM_END; + + return usb_bulk_msg(ch341->udev, ch341->write_pipe, ch341->tx_buf, 3, + NULL, CH341_DEFAULT_TIMEOUT); +} + +static int ch341_enable_pins(struct ch341_spi_dev *ch341, bool enable) +{ + memset(ch341->tx_buf, 0, CH341_PACKET_LENGTH); + ch341->tx_buf[0] = CH341A_CMD_UIO_STREAM; + ch341->tx_buf[1] = CH341A_CMD_UIO_STM_OUT | 0x37; + ch341->tx_buf[2] = CH341A_CMD_UIO_STM_DIR | (enable ? 0x3f : 0x00); + ch341->tx_buf[3] = CH341A_CMD_UIO_STM_END; + + return usb_bulk_msg(ch341->udev, ch341->write_pipe, ch341->tx_buf, 4, + NULL, CH341_DEFAULT_TIMEOUT); +} + +static struct spi_board_info chip = { + .modalias = "spi-ch341a", +}; + +static int ch341_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + struct usb_device *udev = interface_to_usbdev(intf); + struct usb_endpoint_descriptor *in, *out; + struct ch341_spi_dev *ch341; + struct spi_controller *ctrl; + int ret; + + ret = usb_find_common_endpoints(intf->cur_altsetting, &in, &out, NULL, + NULL); + if (ret) + return ret; + + ctrl = devm_spi_alloc_master(&udev->dev, sizeof(struct ch341_spi_dev)); + if (!ctrl) + return -ENOMEM; + + ch341 = spi_controller_get_devdata(ctrl); + ch341->ctrl = ctrl; + ch341->udev = udev; + ch341->write_pipe = usb_sndbulkpipe(udev, usb_endpoint_num(out)); + ch341->read_pipe = usb_rcvbulkpipe(udev, usb_endpoint_num(in)); + + ch341->rx_len = usb_endpoint_maxp(in); + ch341->rx_buf = devm_kzalloc(&udev->dev, ch341->rx_len, GFP_KERNEL); + if (!ch341->rx_buf) + return -ENOMEM; + + ch341->rx_urb = usb_alloc_urb(0, GFP_KERNEL); + if (!ch341->rx_urb) + return -ENOMEM; + + ch341->tx_buf = + devm_kzalloc(&udev->dev, CH341_PACKET_LENGTH, GFP_KERNEL); + if (!ch341->tx_buf) + return -ENOMEM; + + usb_fill_bulk_urb(ch341->rx_urb, udev, ch341->read_pipe, ch341->rx_buf, + ch341->rx_len, ch341_recv, ch341); + + ret = usb_submit_urb(ch341->rx_urb, GFP_KERNEL); + if (ret) { + usb_free_urb(ch341->rx_urb); + return -ENOMEM; + } + + ctrl->bus_num = -1; + ctrl->mode_bits = SPI_CPHA; + ctrl->transfer_one = ch341_transfer_one; + ctrl->set_cs = ch341_set_cs; + ctrl->auto_runtime_pm = false; + + usb_set_intfdata(intf, ch341); + + ret = ch341_config_stream(ch341); + if (ret) + return ret; + + ret = ch341_enable_pins(ch341, true); + if (ret) + return ret; + + ret = spi_register_controller(ctrl); + if (ret) + return ret; + + ch341->spidev = spi_new_device(ctrl, &chip); + if (!ch341->spidev) + return -ENOMEM; + + return 0; +} + +static void ch341_disconnect(struct usb_interface *intf) +{ + struct ch341_spi_dev *ch341 = usb_get_intfdata(intf); + + spi_unregister_device(ch341->spidev); + spi_unregister_controller(ch341->ctrl); + ch341_enable_pins(ch341, false); + usb_free_urb(ch341->rx_urb); +} + +static const struct usb_device_id ch341_id_table[] = { + { USB_DEVICE(0x1a86, 0x5512) }, + { } +}; +MODULE_DEVICE_TABLE(usb, ch341_id_table); + +static struct usb_driver ch341a_usb_driver = { + .name = "spi-ch341", + .probe = ch341_probe, + .disconnect = ch341_disconnect, + .id_table = ch341_id_table, +}; +module_usb_driver(ch341a_usb_driver); + +MODULE_AUTHOR("Johannes Thumshirn "); +MODULE_DESCRIPTION("QiHeng Electronics ch341 USB2SPI"); +MODULE_LICENSE("GPL v2"); -- cgit v1.2.3 From 3048dc8ba46b7ba11581f2a7e06849af0df13136 Mon Sep 17 00:00:00 2001 From: Nicolas Ferre Date: Thu, 11 Jul 2024 18:54:02 +0200 Subject: spi: dt-bindings: at91: Add sama7d65 compatible string Add compatible string for sama7d65. Like sam9x60 and sam9x7, it requires to bind to "atmel,at91rm9200-spi". Group these three under the same enum, sorted alphanumerically, and remove previously added item. Signed-off-by: Nicolas Ferre Acked-by: Rob Herring (Arm) Link: https://patch.msgid.link/20240711165402.373634-1-nicolas.ferre@microchip.com Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/spi/atmel,at91rm9200-spi.yaml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Documentation/devicetree/bindings/spi/atmel,at91rm9200-spi.yaml b/Documentation/devicetree/bindings/spi/atmel,at91rm9200-spi.yaml index 32e7c14033c2..d29772994cf5 100644 --- a/Documentation/devicetree/bindings/spi/atmel,at91rm9200-spi.yaml +++ b/Documentation/devicetree/bindings/spi/atmel,at91rm9200-spi.yaml @@ -18,10 +18,10 @@ properties: oneOf: - const: atmel,at91rm9200-spi - items: - - const: microchip,sam9x60-spi - - const: atmel,at91rm9200-spi - - items: - - const: microchip,sam9x7-spi + - enum: + - microchip,sam9x60-spi + - microchip,sam9x7-spi + - microchip,sama7d65-spi - const: atmel,at91rm9200-spi reg: -- cgit v1.2.3