From 2da187304e556ac59cf2dacb323cc78ded988169 Mon Sep 17 00:00:00 2001 From: Conor Dooley Date: Mon, 17 Jan 2022 11:07:47 +0000 Subject: spi: add bindings for microchip mpfs spi Add device tree bindings for the {q,}spi controller on the Microchip PolarFire SoC. Signed-off-by: Conor Dooley Link: https://lore.kernel.org/r/20220117110755.3433142-7-conor.dooley@microchip.com Signed-off-by: Mark Brown --- .../bindings/spi/microchip,mpfs-spi.yaml | 52 ++++++++++++++++++++++ 1 file changed, 52 insertions(+) create mode 100644 Documentation/devicetree/bindings/spi/microchip,mpfs-spi.yaml diff --git a/Documentation/devicetree/bindings/spi/microchip,mpfs-spi.yaml b/Documentation/devicetree/bindings/spi/microchip,mpfs-spi.yaml new file mode 100644 index 000000000000..ece261b8e963 --- /dev/null +++ b/Documentation/devicetree/bindings/spi/microchip,mpfs-spi.yaml @@ -0,0 +1,52 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/spi/microchip,mpfs-spi.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Microchip MPFS {Q,}SPI Controller Device Tree Bindings + +maintainers: + - Conor Dooley + +allOf: + - $ref: spi-controller.yaml# + +properties: + compatible: + enum: + - microchip,mpfs-spi + - microchip,mpfs-qspi + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + clock-names: + maxItems: 1 + + clocks: + maxItems: 1 + +required: + - compatible + - reg + - interrupts + - clocks + +unevaluatedProperties: false + +examples: + - | + #include "dt-bindings/clock/microchip,mpfs-clock.h" + spi@20108000 { + compatible = "microchip,mpfs-spi"; + reg = <0x20108000 0x1000>; + clocks = <&clkcfg CLK_SPI0>; + interrupt-parent = <&plic>; + interrupts = <54>; + spi-max-frequency = <25000000>; + }; +... -- cgit v1.2.3 From 5b177234e9fde7d4208e8163debc109b86e3f68d Mon Sep 17 00:00:00 2001 From: Guochun Mao Date: Tue, 18 Jan 2022 22:28:18 +0800 Subject: spi: spi-mtk-nor: improve device table for adding more capabilities Define a structure for adding more capabilities. Add a item extra_dummy_bit for new SoCs, due to design changed. Signed-off-by: Guochun Mao Signed-off-by: Zhen Zhang Reviewed-by: AngeloGioacchino Del Regno Link: https://lore.kernel.org/r/20220118142820.2729-3-guochun.mao@mediatek.com Signed-off-by: Mark Brown --- drivers/spi/spi-mtk-nor.c | 48 ++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 39 insertions(+), 9 deletions(-) diff --git a/drivers/spi/spi-mtk-nor.c b/drivers/spi/spi-mtk-nor.c index 5c93730615f8..f5ff01f61f42 100644 --- a/drivers/spi/spi-mtk-nor.c +++ b/drivers/spi/spi-mtk-nor.c @@ -95,6 +95,17 @@ #define CLK_TO_US(sp, clkcnt) DIV_ROUND_UP(clkcnt, sp->spi_freq / 1000000) +struct mtk_nor_caps { + u8 dma_bits; + + /* extra_dummy_bit is adding for the IP of new SoCs. + * Some new SoCs modify the timing of fetching registers' values + * and IDs of nor flash, they need a extra_dummy_bit which can add + * more clock cycles for fetching data. + */ + u8 extra_dummy_bit; +}; + struct mtk_nor { struct spi_controller *ctlr; struct device *dev; @@ -109,6 +120,7 @@ struct mtk_nor { bool has_irq; bool high_dma; struct completion op_done; + const struct mtk_nor_caps *caps; }; static inline void mtk_nor_rmw(struct mtk_nor *sp, u32 reg, u32 set, u32 clr) @@ -554,7 +566,12 @@ static int mtk_nor_spi_mem_prg(struct mtk_nor *sp, const struct spi_mem_op *op) } // trigger op - writel(prg_len * BITS_PER_BYTE, sp->base + MTK_NOR_REG_PRG_CNT); + if (rx_len) + writel(prg_len * BITS_PER_BYTE + sp->caps->extra_dummy_bit, + sp->base + MTK_NOR_REG_PRG_CNT); + else + writel(prg_len * BITS_PER_BYTE, sp->base + MTK_NOR_REG_PRG_CNT); + ret = mtk_nor_cmd_exec(sp, MTK_NOR_CMD_PROGRAM, prg_len * BITS_PER_BYTE); if (ret) @@ -743,9 +760,19 @@ static const struct spi_controller_mem_ops mtk_nor_mem_ops = { .exec_op = mtk_nor_exec_op }; +const struct mtk_nor_caps mtk_nor_caps_mt8173 = { + .dma_bits = 32, + .extra_dummy_bit = 0, +}; + +const struct mtk_nor_caps mtk_nor_caps_mt8192 = { + .dma_bits = 36, + .extra_dummy_bit = 0, +}; + static const struct of_device_id mtk_nor_match[] = { - { .compatible = "mediatek,mt8192-nor", .data = (void *)36 }, - { .compatible = "mediatek,mt8173-nor", .data = (void *)32 }, + { .compatible = "mediatek,mt8173-nor", .data = &mtk_nor_caps_mt8173 }, + { .compatible = "mediatek,mt8192-nor", .data = &mtk_nor_caps_mt8192 }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, mtk_nor_match); @@ -754,10 +781,10 @@ static int mtk_nor_probe(struct platform_device *pdev) { struct spi_controller *ctlr; struct mtk_nor *sp; + struct mtk_nor_caps *caps; void __iomem *base; struct clk *spi_clk, *ctlr_clk, *axi_clk; int ret, irq; - unsigned long dma_bits; base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(base)) @@ -775,10 +802,12 @@ static int mtk_nor_probe(struct platform_device *pdev) if (IS_ERR(axi_clk)) return PTR_ERR(axi_clk); - dma_bits = (unsigned long)of_device_get_match_data(&pdev->dev); - if (dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(dma_bits))) { - dev_err(&pdev->dev, "failed to set dma mask(%lu)\n", dma_bits); - return -EINVAL; + caps = (struct mtk_nor_caps *)of_device_get_match_data(&pdev->dev); + + ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(caps->dma_bits)); + if (ret) { + dev_err(&pdev->dev, "failed to set dma mask(%u)\n", caps->dma_bits); + return ret; } ctlr = devm_spi_alloc_master(&pdev->dev, sizeof(*sp)); @@ -808,7 +837,8 @@ static int mtk_nor_probe(struct platform_device *pdev) sp->spi_clk = spi_clk; sp->ctlr_clk = ctlr_clk; sp->axi_clk = axi_clk; - sp->high_dma = (dma_bits > 32); + sp->caps = caps; + sp->high_dma = caps->dma_bits > 32; sp->buffer = dmam_alloc_coherent(&pdev->dev, MTK_NOR_BOUNCE_BUF_SIZE + MTK_NOR_DMA_ALIGN, &sp->buffer_dma, GFP_KERNEL); -- cgit v1.2.3 From 4e8bfe5cdf77621cb4e7b196448ceeff20d9d6a6 Mon Sep 17 00:00:00 2001 From: Guochun Mao Date: Tue, 18 Jan 2022 22:28:19 +0800 Subject: spi: spi-mtk-nor: add new soc mt8186 support Add compatible mediatek,mt8186-nor implementation. Signed-off-by: Guochun Mao Signed-off-by: Zhen Zhang Reviewed-by: AngeloGioacchino Del Regno Link: https://lore.kernel.org/r/20220118142820.2729-4-guochun.mao@mediatek.com Signed-off-by: Mark Brown --- drivers/spi/spi-mtk-nor.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/spi/spi-mtk-nor.c b/drivers/spi/spi-mtk-nor.c index f5ff01f61f42..e44fdf7c9e4b 100644 --- a/drivers/spi/spi-mtk-nor.c +++ b/drivers/spi/spi-mtk-nor.c @@ -765,6 +765,11 @@ const struct mtk_nor_caps mtk_nor_caps_mt8173 = { .extra_dummy_bit = 0, }; +const struct mtk_nor_caps mtk_nor_caps_mt8186 = { + .dma_bits = 32, + .extra_dummy_bit = 1, +}; + const struct mtk_nor_caps mtk_nor_caps_mt8192 = { .dma_bits = 36, .extra_dummy_bit = 0, @@ -772,6 +777,7 @@ const struct mtk_nor_caps mtk_nor_caps_mt8192 = { static const struct of_device_id mtk_nor_match[] = { { .compatible = "mediatek,mt8173-nor", .data = &mtk_nor_caps_mt8173 }, + { .compatible = "mediatek,mt8186-nor", .data = &mtk_nor_caps_mt8186 }, { .compatible = "mediatek,mt8192-nor", .data = &mtk_nor_caps_mt8192 }, { /* sentinel */ } }; -- cgit v1.2.3 From 58b0a653b8dac40bbeb01a2c8a230aa8f84a7530 Mon Sep 17 00:00:00 2001 From: Guochun Mao Date: Tue, 18 Jan 2022 22:28:20 +0800 Subject: spi: spi-mtk-nor: add axi_s clock for mt8186 MT8186 needs axi_s clock for DMA feature. Signed-off-by: Guochun Mao Signed-off-by: Zhen Zhang Acked-by: AngeloGioacchino Del Regno Link: https://lore.kernel.org/r/20220118142820.2729-5-guochun.mao@mediatek.com Signed-off-by: Mark Brown --- drivers/spi/spi-mtk-nor.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/drivers/spi/spi-mtk-nor.c b/drivers/spi/spi-mtk-nor.c index e44fdf7c9e4b..455b4dcb26e9 100644 --- a/drivers/spi/spi-mtk-nor.c +++ b/drivers/spi/spi-mtk-nor.c @@ -115,6 +115,7 @@ struct mtk_nor { struct clk *spi_clk; struct clk *ctlr_clk; struct clk *axi_clk; + struct clk *axi_s_clk; unsigned int spi_freq; bool wbuf_en; bool has_irq; @@ -691,6 +692,7 @@ static void mtk_nor_disable_clk(struct mtk_nor *sp) clk_disable_unprepare(sp->spi_clk); clk_disable_unprepare(sp->ctlr_clk); clk_disable_unprepare(sp->axi_clk); + clk_disable_unprepare(sp->axi_s_clk); } static int mtk_nor_enable_clk(struct mtk_nor *sp) @@ -714,6 +716,14 @@ static int mtk_nor_enable_clk(struct mtk_nor *sp) return ret; } + ret = clk_prepare_enable(sp->axi_s_clk); + if (ret) { + clk_disable_unprepare(sp->spi_clk); + clk_disable_unprepare(sp->ctlr_clk); + clk_disable_unprepare(sp->axi_clk); + return ret; + } + return 0; } @@ -789,7 +799,7 @@ static int mtk_nor_probe(struct platform_device *pdev) struct mtk_nor *sp; struct mtk_nor_caps *caps; void __iomem *base; - struct clk *spi_clk, *ctlr_clk, *axi_clk; + struct clk *spi_clk, *ctlr_clk, *axi_clk, *axi_s_clk; int ret, irq; base = devm_platform_ioremap_resource(pdev, 0); @@ -808,6 +818,10 @@ static int mtk_nor_probe(struct platform_device *pdev) if (IS_ERR(axi_clk)) return PTR_ERR(axi_clk); + axi_s_clk = devm_clk_get_optional(&pdev->dev, "axi_s"); + if (IS_ERR(axi_s_clk)) + return PTR_ERR(axi_s_clk); + caps = (struct mtk_nor_caps *)of_device_get_match_data(&pdev->dev); ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(caps->dma_bits)); @@ -843,6 +857,7 @@ static int mtk_nor_probe(struct platform_device *pdev) sp->spi_clk = spi_clk; sp->ctlr_clk = ctlr_clk; sp->axi_clk = axi_clk; + sp->axi_s_clk = axi_s_clk; sp->caps = caps; sp->high_dma = caps->dma_bits > 32; sp->buffer = dmam_alloc_coherent(&pdev->dev, -- cgit v1.2.3 From ceab11a3c0d620d9ec2c032fd8014615cf7934ec Mon Sep 17 00:00:00 2001 From: Guochun Mao Date: Tue, 18 Jan 2022 22:28:17 +0800 Subject: spi: add mt8186-nor compatible string Add MT8186 spi-nor controller support. MT8186 needs a new clock name, axi_s, for spi nor axi slave bus clock. Signed-off-by: Guochun Mao Signed-off-by: Zhen Zhang Link: https://lore.kernel.org/r/20220118142820.2729-2-guochun.mao@mediatek.com Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/spi/mediatek,spi-mtk-nor.yaml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Documentation/devicetree/bindings/spi/mediatek,spi-mtk-nor.yaml b/Documentation/devicetree/bindings/spi/mediatek,spi-mtk-nor.yaml index 4e4694e3d539..be3cc7faed53 100644 --- a/Documentation/devicetree/bindings/spi/mediatek,spi-mtk-nor.yaml +++ b/Documentation/devicetree/bindings/spi/mediatek,spi-mtk-nor.yaml @@ -30,6 +30,7 @@ properties: - mediatek,mt7622-nor - mediatek,mt7623-nor - mediatek,mt7629-nor + - mediatek,mt8186-nor - mediatek,mt8192-nor - mediatek,mt8195-nor - enum: @@ -49,6 +50,8 @@ properties: - description: clock used for controller - description: clock used for nor dma bus. this depends on hardware design, so this is optional. + - description: clock used for controller axi slave bus. + this depends on hardware design, so it is optional. clock-names: minItems: 2 @@ -56,6 +59,7 @@ properties: - const: spi - const: sf - const: axi + - const: axi_s required: - compatible -- cgit v1.2.3 From f1ba938e4f98941dc2b77795062e49444ec1fee1 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Wed, 19 Jan 2022 00:09:13 +0100 Subject: spi: s3c64xx: Delete unused boardfile helpers The helpers to use SPI host 1 and 2 are unused in the kernel and taking up space and maintenance hours. New systems should use device tree and not this, so delete the code. Cc: linux-samsung-soc@vger.kernel.org Cc: Krzysztof Kozlowski Cc: Sylwester Nawrocki Signed-off-by: Linus Walleij Reviewed-by: Sam Protsenko Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20220118230915.157797-1-linus.walleij@linaro.org Signed-off-by: Mark Brown --- arch/arm/mach-s3c/Kconfig | 12 ------ arch/arm/mach-s3c/devs.c | 72 ------------------------------- arch/arm/mach-s3c/setup-spi-s3c64xx.c | 9 ---- arch/arm/mach-s3c/spi-core-s3c24xx.h | 6 --- include/linux/platform_data/spi-s3c64xx.h | 8 ---- 5 files changed, 107 deletions(-) diff --git a/arch/arm/mach-s3c/Kconfig b/arch/arm/mach-s3c/Kconfig index 25606e668cf9..1899fc3f44fd 100644 --- a/arch/arm/mach-s3c/Kconfig +++ b/arch/arm/mach-s3c/Kconfig @@ -191,18 +191,6 @@ config S3C64XX_DEV_SPI0 Compile in platform device definitions for S3C64XX's type SPI controller 0 -config S3C64XX_DEV_SPI1 - bool - help - Compile in platform device definitions for S3C64XX's type - SPI controller 1 - -config S3C64XX_DEV_SPI2 - bool - help - Compile in platform device definitions for S3C64XX's type - SPI controller 2 - config SAMSUNG_DEV_TS bool help diff --git a/arch/arm/mach-s3c/devs.c b/arch/arm/mach-s3c/devs.c index 06dec64848f9..9f086aee862b 100644 --- a/arch/arm/mach-s3c/devs.c +++ b/arch/arm/mach-s3c/devs.c @@ -1125,75 +1125,3 @@ void __init s3c64xx_spi0_set_platdata(int (*cfg_gpio)(void), int src_clk_nr, s3c_set_platdata(&pd, sizeof(pd), &s3c64xx_device_spi0); } #endif /* CONFIG_S3C64XX_DEV_SPI0 */ - -#ifdef CONFIG_S3C64XX_DEV_SPI1 -static struct resource s3c64xx_spi1_resource[] = { - [0] = DEFINE_RES_MEM(S3C_PA_SPI1, SZ_256), - [1] = DEFINE_RES_IRQ(IRQ_SPI1), -}; - -struct platform_device s3c64xx_device_spi1 = { - .name = "s3c6410-spi", - .id = 1, - .num_resources = ARRAY_SIZE(s3c64xx_spi1_resource), - .resource = s3c64xx_spi1_resource, - .dev = { - .dma_mask = &samsung_device_dma_mask, - .coherent_dma_mask = DMA_BIT_MASK(32), - }, -}; - -void __init s3c64xx_spi1_set_platdata(int (*cfg_gpio)(void), int src_clk_nr, - int num_cs) -{ - struct s3c64xx_spi_info pd; - - /* Reject invalid configuration */ - if (!num_cs || src_clk_nr < 0) { - pr_err("%s: Invalid SPI configuration\n", __func__); - return; - } - - pd.num_cs = num_cs; - pd.src_clk_nr = src_clk_nr; - pd.cfg_gpio = (cfg_gpio) ? cfg_gpio : s3c64xx_spi1_cfg_gpio; - - s3c_set_platdata(&pd, sizeof(pd), &s3c64xx_device_spi1); -} -#endif /* CONFIG_S3C64XX_DEV_SPI1 */ - -#ifdef CONFIG_S3C64XX_DEV_SPI2 -static struct resource s3c64xx_spi2_resource[] = { - [0] = DEFINE_RES_MEM(S3C_PA_SPI2, SZ_256), - [1] = DEFINE_RES_IRQ(IRQ_SPI2), -}; - -struct platform_device s3c64xx_device_spi2 = { - .name = "s3c6410-spi", - .id = 2, - .num_resources = ARRAY_SIZE(s3c64xx_spi2_resource), - .resource = s3c64xx_spi2_resource, - .dev = { - .dma_mask = &samsung_device_dma_mask, - .coherent_dma_mask = DMA_BIT_MASK(32), - }, -}; - -void __init s3c64xx_spi2_set_platdata(int (*cfg_gpio)(void), int src_clk_nr, - int num_cs) -{ - struct s3c64xx_spi_info pd; - - /* Reject invalid configuration */ - if (!num_cs || src_clk_nr < 0) { - pr_err("%s: Invalid SPI configuration\n", __func__); - return; - } - - pd.num_cs = num_cs; - pd.src_clk_nr = src_clk_nr; - pd.cfg_gpio = (cfg_gpio) ? cfg_gpio : s3c64xx_spi2_cfg_gpio; - - s3c_set_platdata(&pd, sizeof(pd), &s3c64xx_device_spi2); -} -#endif /* CONFIG_S3C64XX_DEV_SPI2 */ diff --git a/arch/arm/mach-s3c/setup-spi-s3c64xx.c b/arch/arm/mach-s3c/setup-spi-s3c64xx.c index efcf78d41585..497aff71c29c 100644 --- a/arch/arm/mach-s3c/setup-spi-s3c64xx.c +++ b/arch/arm/mach-s3c/setup-spi-s3c64xx.c @@ -16,12 +16,3 @@ int s3c64xx_spi0_cfg_gpio(void) return 0; } #endif - -#ifdef CONFIG_S3C64XX_DEV_SPI1 -int s3c64xx_spi1_cfg_gpio(void) -{ - s3c_gpio_cfgall_range(S3C64XX_GPC(4), 3, - S3C_GPIO_SFN(2), S3C_GPIO_PULL_UP); - return 0; -} -#endif diff --git a/arch/arm/mach-s3c/spi-core-s3c24xx.h b/arch/arm/mach-s3c/spi-core-s3c24xx.h index 057667469cc3..919c5fd0c9af 100644 --- a/arch/arm/mach-s3c/spi-core-s3c24xx.h +++ b/arch/arm/mach-s3c/spi-core-s3c24xx.h @@ -16,12 +16,6 @@ static inline void s3c24xx_spi_setname(char *name) #ifdef CONFIG_S3C64XX_DEV_SPI0 s3c64xx_device_spi0.name = name; #endif -#ifdef CONFIG_S3C64XX_DEV_SPI1 - s3c64xx_device_spi1.name = name; -#endif -#ifdef CONFIG_S3C64XX_DEV_SPI2 - s3c64xx_device_spi2.name = name; -#endif } #endif /* __PLAT_S3C_SPI_CORE_S3C24XX_H */ diff --git a/include/linux/platform_data/spi-s3c64xx.h b/include/linux/platform_data/spi-s3c64xx.h index 773daf7915a3..19d690f34670 100644 --- a/include/linux/platform_data/spi-s3c64xx.h +++ b/include/linux/platform_data/spi-s3c64xx.h @@ -52,17 +52,9 @@ struct s3c64xx_spi_info { */ extern void s3c64xx_spi0_set_platdata(int (*cfg_gpio)(void), int src_clk_nr, int num_cs); -extern void s3c64xx_spi1_set_platdata(int (*cfg_gpio)(void), int src_clk_nr, - int num_cs); -extern void s3c64xx_spi2_set_platdata(int (*cfg_gpio)(void), int src_clk_nr, - int num_cs); /* defined by architecture to configure gpio */ extern int s3c64xx_spi0_cfg_gpio(void); -extern int s3c64xx_spi1_cfg_gpio(void); -extern int s3c64xx_spi2_cfg_gpio(void); extern struct s3c64xx_spi_info s3c64xx_spi0_pdata; -extern struct s3c64xx_spi_info s3c64xx_spi1_pdata; -extern struct s3c64xx_spi_info s3c64xx_spi2_pdata; #endif /*__SPI_S3C64XX_H */ -- cgit v1.2.3 From 3b5529ae7f3578da633e8ae2ec0715a55a248f9f Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Wed, 19 Jan 2022 00:09:14 +0100 Subject: spi: s3c64xx: Drop custom gpio setup argument The SPI0 platform population function was taking a custom gpio setup callback but the only user pass NULL as argument so drop this argument. Cc: linux-samsung-soc@vger.kernel.org Cc: Krzysztof Kozlowski Cc: Sylwester Nawrocki Signed-off-by: Linus Walleij Reviewed-by: Krzysztof Kozlowski Reviewed-by: Sam Protsenko Link: https://lore.kernel.org/r/20220118230915.157797-2-linus.walleij@linaro.org Signed-off-by: Mark Brown --- arch/arm/mach-s3c/devs.c | 5 ++--- arch/arm/mach-s3c/mach-crag6410.c | 2 +- include/linux/platform_data/spi-s3c64xx.h | 4 +--- 3 files changed, 4 insertions(+), 7 deletions(-) diff --git a/arch/arm/mach-s3c/devs.c b/arch/arm/mach-s3c/devs.c index 9f086aee862b..1e266fc24f9b 100644 --- a/arch/arm/mach-s3c/devs.c +++ b/arch/arm/mach-s3c/devs.c @@ -1107,8 +1107,7 @@ struct platform_device s3c64xx_device_spi0 = { }, }; -void __init s3c64xx_spi0_set_platdata(int (*cfg_gpio)(void), int src_clk_nr, - int num_cs) +void __init s3c64xx_spi0_set_platdata(int src_clk_nr, int num_cs) { struct s3c64xx_spi_info pd; @@ -1120,7 +1119,7 @@ void __init s3c64xx_spi0_set_platdata(int (*cfg_gpio)(void), int src_clk_nr, pd.num_cs = num_cs; pd.src_clk_nr = src_clk_nr; - pd.cfg_gpio = (cfg_gpio) ? cfg_gpio : s3c64xx_spi0_cfg_gpio; + pd.cfg_gpio = s3c64xx_spi0_cfg_gpio; s3c_set_platdata(&pd, sizeof(pd), &s3c64xx_device_spi0); } diff --git a/arch/arm/mach-s3c/mach-crag6410.c b/arch/arm/mach-s3c/mach-crag6410.c index 4a12c75d407f..41f0aba2d2fd 100644 --- a/arch/arm/mach-s3c/mach-crag6410.c +++ b/arch/arm/mach-s3c/mach-crag6410.c @@ -856,7 +856,7 @@ static void __init crag6410_machine_init(void) i2c_register_board_info(1, i2c_devs1, ARRAY_SIZE(i2c_devs1)); samsung_keypad_set_platdata(&crag6410_keypad_data); - s3c64xx_spi0_set_platdata(NULL, 0, 2); + s3c64xx_spi0_set_platdata(0, 2); pwm_add_table(crag6410_pwm_lookup, ARRAY_SIZE(crag6410_pwm_lookup)); platform_add_devices(crag6410_devices, ARRAY_SIZE(crag6410_devices)); diff --git a/include/linux/platform_data/spi-s3c64xx.h b/include/linux/platform_data/spi-s3c64xx.h index 19d690f34670..10890a4b55b9 100644 --- a/include/linux/platform_data/spi-s3c64xx.h +++ b/include/linux/platform_data/spi-s3c64xx.h @@ -43,15 +43,13 @@ struct s3c64xx_spi_info { /** * s3c64xx_spi_set_platdata - SPI Controller configure callback by the board * initialization code. - * @cfg_gpio: Pointer to gpio setup function. * @src_clk_nr: Clock the SPI controller is to use to generate SPI clocks. * @num_cs: Number of elements in the 'cs' array. * * Call this from machine init code for each SPI Controller that * has some chips attached to it. */ -extern void s3c64xx_spi0_set_platdata(int (*cfg_gpio)(void), int src_clk_nr, - int num_cs); +extern void s3c64xx_spi0_set_platdata(int src_clk_nr, int num_cs); /* defined by architecture to configure gpio */ extern int s3c64xx_spi0_cfg_gpio(void); -- cgit v1.2.3 From a45cf3cc72dd9cfde9db8af32cdf9c431f53f9bc Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Wed, 19 Jan 2022 00:09:15 +0100 Subject: spi: s3c64xx: Convert to use GPIO descriptors Convert the S3C64xx SPI host to use GPIO descriptors. Provide GPIO descriptor tables for the one user with CS 0 and 1. Cc: linux-samsung-soc@vger.kernel.org Cc: Sylwester Nawrocki Reviewed-by: Krzysztof Kozlowski Reviewed-by: Sam Protsenko Signed-off-by: Linus Walleij Link: https://lore.kernel.org/r/20220118230915.157797-3-linus.walleij@linaro.org Signed-off-by: Mark Brown --- arch/arm/mach-s3c/mach-crag6410-module.c | 13 -------- arch/arm/mach-s3c/mach-crag6410.c | 11 +++++++ drivers/spi/spi-s3c64xx.c | 53 ++++++++----------------------- include/linux/platform_data/spi-s3c64xx.h | 2 -- 4 files changed, 24 insertions(+), 55 deletions(-) diff --git a/arch/arm/mach-s3c/mach-crag6410-module.c b/arch/arm/mach-s3c/mach-crag6410-module.c index 407ad493493e..5d1d4b67a4b7 100644 --- a/arch/arm/mach-s3c/mach-crag6410-module.c +++ b/arch/arm/mach-s3c/mach-crag6410-module.c @@ -32,10 +32,6 @@ #include "crag6410.h" -static struct s3c64xx_spi_csinfo wm0010_spi_csinfo = { - .line = S3C64XX_GPC(3), -}; - static struct wm0010_pdata wm0010_pdata = { .gpio_reset = S3C64XX_GPN(6), .reset_active_high = 1, /* Active high for Glenfarclas Rev 2 */ @@ -49,7 +45,6 @@ static struct spi_board_info wm1253_devs[] = { .chip_select = 0, .mode = SPI_MODE_0, .irq = S3C_EINT(4), - .controller_data = &wm0010_spi_csinfo, .platform_data = &wm0010_pdata, }, }; @@ -62,7 +57,6 @@ static struct spi_board_info balblair_devs[] = { .chip_select = 0, .mode = SPI_MODE_0, .irq = S3C_EINT(4), - .controller_data = &wm0010_spi_csinfo, .platform_data = &wm0010_pdata, }, }; @@ -229,10 +223,6 @@ static struct arizona_pdata wm5102_reva_pdata = { }, }; -static struct s3c64xx_spi_csinfo codec_spi_csinfo = { - .line = S3C64XX_GPN(5), -}; - static struct spi_board_info wm5102_reva_spi_devs[] = { [0] = { .modalias = "wm5102", @@ -242,7 +232,6 @@ static struct spi_board_info wm5102_reva_spi_devs[] = { .mode = SPI_MODE_0, .irq = GLENFARCLAS_PMIC_IRQ_BASE + WM831X_IRQ_GPIO_2, - .controller_data = &codec_spi_csinfo, .platform_data = &wm5102_reva_pdata, }, }; @@ -275,7 +264,6 @@ static struct spi_board_info wm5102_spi_devs[] = { .mode = SPI_MODE_0, .irq = GLENFARCLAS_PMIC_IRQ_BASE + WM831X_IRQ_GPIO_2, - .controller_data = &codec_spi_csinfo, .platform_data = &wm5102_pdata, }, }; @@ -298,7 +286,6 @@ static struct spi_board_info wm5110_spi_devs[] = { .mode = SPI_MODE_0, .irq = GLENFARCLAS_PMIC_IRQ_BASE + WM831X_IRQ_GPIO_2, - .controller_data = &codec_spi_csinfo, .platform_data = &wm5102_reva_pdata, }, }; diff --git a/arch/arm/mach-s3c/mach-crag6410.c b/arch/arm/mach-s3c/mach-crag6410.c index 41f0aba2d2fd..e3e0fe897bcc 100644 --- a/arch/arm/mach-s3c/mach-crag6410.c +++ b/arch/arm/mach-s3c/mach-crag6410.c @@ -825,6 +825,15 @@ static const struct gpio_led_platform_data gpio_leds_pdata = { static struct dwc2_hsotg_plat crag6410_hsotg_pdata; +static struct gpiod_lookup_table crag_spi0_gpiod_table = { + .dev_id = "s3c6410-spi.0", + .table = { + GPIO_LOOKUP_IDX("GPIOC", 3, "cs", 0, GPIO_ACTIVE_LOW), + GPIO_LOOKUP_IDX("GPION", 5, "cs", 1, GPIO_ACTIVE_LOW), + { }, + }, +}; + static void __init crag6410_machine_init(void) { /* Open drain IRQs need pullups */ @@ -856,6 +865,8 @@ static void __init crag6410_machine_init(void) i2c_register_board_info(1, i2c_devs1, ARRAY_SIZE(i2c_devs1)); samsung_keypad_set_platdata(&crag6410_keypad_data); + + gpiod_add_lookup_table(&crag_spi0_gpiod_table); s3c64xx_spi0_set_platdata(0, 2); pwm_add_table(crag6410_pwm_lookup, ARRAY_SIZE(crag6410_pwm_lookup)); diff --git a/drivers/spi/spi-s3c64xx.c b/drivers/spi/spi-s3c64xx.c index 8755cd85e83c..3e42cdb19d27 100644 --- a/drivers/spi/spi-s3c64xx.c +++ b/drivers/spi/spi-s3c64xx.c @@ -13,10 +13,8 @@ #include #include #include -#include #include #include -#include #include @@ -656,7 +654,11 @@ static int s3c64xx_spi_prepare_message(struct spi_master *master, struct s3c64xx_spi_csinfo *cs = spi->controller_data; /* Configure feedback delay */ - writel(cs->fb_delay & 0x3, sdd->regs + S3C64XX_SPI_FB_CLK); + if (!cs) + /* No delay if not defined */ + writel(0, sdd->regs + S3C64XX_SPI_FB_CLK); + else + writel(cs->fb_delay & 0x3, sdd->regs + S3C64XX_SPI_FB_CLK); return 0; } @@ -830,34 +832,16 @@ static int s3c64xx_spi_setup(struct spi_device *spi) if (spi->dev.of_node) { cs = s3c64xx_get_slave_ctrldata(spi); spi->controller_data = cs; - } else if (cs) { - /* On non-DT platforms the SPI core will set spi->cs_gpio - * to -ENOENT. The GPIO pin used to drive the chip select - * is defined by using platform data so spi->cs_gpio value - * has to be override to have the proper GPIO pin number. - */ - spi->cs_gpio = cs->line; } - if (IS_ERR_OR_NULL(cs)) { + /* NULL is fine, we just avoid using the FB delay (=0) */ + if (IS_ERR(cs)) { dev_err(&spi->dev, "No CS for SPI(%d)\n", spi->chip_select); return -ENODEV; } - if (!spi_get_ctldata(spi)) { - if (gpio_is_valid(spi->cs_gpio)) { - err = gpio_request_one(spi->cs_gpio, GPIOF_OUT_INIT_HIGH, - dev_name(&spi->dev)); - if (err) { - dev_err(&spi->dev, - "Failed to get /CS gpio [%d]: %d\n", - spi->cs_gpio, err); - goto err_gpio_req; - } - } - + if (!spi_get_ctldata(spi)) spi_set_ctldata(spi, cs); - } pm_runtime_get_sync(&sdd->pdev->dev); @@ -909,11 +893,9 @@ setup_exit: /* setup() returns with device de-selected */ s3c64xx_spi_set_cs(spi, false); - if (gpio_is_valid(spi->cs_gpio)) - gpio_free(spi->cs_gpio); spi_set_ctldata(spi, NULL); -err_gpio_req: + /* This was dynamically allocated on the DT path */ if (spi->dev.of_node) kfree(cs); @@ -924,19 +906,9 @@ static void s3c64xx_spi_cleanup(struct spi_device *spi) { struct s3c64xx_spi_csinfo *cs = spi_get_ctldata(spi); - if (gpio_is_valid(spi->cs_gpio)) { - gpio_free(spi->cs_gpio); - if (spi->dev.of_node) - kfree(cs); - else { - /* On non-DT platforms, the SPI core sets - * spi->cs_gpio to -ENOENT and .setup() - * overrides it with the GPIO pin value - * passed using platform data. - */ - spi->cs_gpio = -ENOENT; - } - } + /* This was dynamically allocated on the DT path */ + if (spi->dev.of_node) + kfree(cs); spi_set_ctldata(spi, NULL); } @@ -1131,6 +1103,7 @@ static int s3c64xx_spi_probe(struct platform_device *pdev) master->prepare_message = s3c64xx_spi_prepare_message; master->transfer_one = s3c64xx_spi_transfer_one; master->num_chipselect = sci->num_cs; + master->use_gpio_descriptors = true; master->dma_alignment = 8; master->bits_per_word_mask = SPI_BPW_MASK(32) | SPI_BPW_MASK(16) | SPI_BPW_MASK(8); diff --git a/include/linux/platform_data/spi-s3c64xx.h b/include/linux/platform_data/spi-s3c64xx.h index 10890a4b55b9..5df1ace6d2c9 100644 --- a/include/linux/platform_data/spi-s3c64xx.h +++ b/include/linux/platform_data/spi-s3c64xx.h @@ -16,7 +16,6 @@ struct platform_device; * struct s3c64xx_spi_csinfo - ChipSelect description * @fb_delay: Slave specific feedback delay. * Refer to FB_CLK_SEL register definition in SPI chapter. - * @line: Custom 'identity' of the CS line. * * This is per SPI-Slave Chipselect information. * Allocate and initialize one in machine init code and make the @@ -24,7 +23,6 @@ struct platform_device; */ struct s3c64xx_spi_csinfo { u8 fb_delay; - unsigned line; }; /** -- cgit v1.2.3 From 7f2a3cf4e6077a1525092f114be7819e505773a1 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Wed, 19 Jan 2022 01:09:14 +0100 Subject: spi: s3c24xx: Convert to GPIO descriptors This driver has a bunch of custom oldstyle GPIO number-passing fields and a custom set-up callback. The good thing is: nothing in the kernel is using it. Convert the driver to use GPIO descriptors with a SPI_MASTER_GPIO_SS flag so that the local CS callback also get invoked as the hardware needs this. New users of this driver can provide GPIO descriptor tables like the other converted drivers. Cc: linux-samsung-soc@vger.kernel.org Cc: Krzysztof Kozlowski Cc: Sylwester Nawrocki Signed-off-by: Linus Walleij Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20220119000914.192553-1-linus.walleij@linaro.org Signed-off-by: Mark Brown --- drivers/spi/spi-s3c24xx.c | 47 +++------------------------------------------ include/linux/spi/s3c24xx.h | 5 ----- 2 files changed, 3 insertions(+), 49 deletions(-) diff --git a/drivers/spi/spi-s3c24xx.c b/drivers/spi/spi-s3c24xx.c index d6f51695ca5b..660aa866af06 100644 --- a/drivers/spi/spi-s3c24xx.c +++ b/drivers/spi/spi-s3c24xx.c @@ -12,7 +12,6 @@ #include #include #include -#include #include #include @@ -62,9 +61,6 @@ struct s3c24xx_spi { unsigned char fiq_inuse; unsigned char fiq_claimed; - void (*set_cs)(struct s3c2410_spi_info *spi, - int cs, int pol); - /* data buffers */ const unsigned char *tx; unsigned char *rx; @@ -84,29 +80,21 @@ static inline struct s3c24xx_spi *to_hw(struct spi_device *sdev) return spi_master_get_devdata(sdev->master); } -static void s3c24xx_spi_gpiocs(struct s3c2410_spi_info *spi, int cs, int pol) -{ - gpio_set_value(spi->pin_cs, pol); -} - static void s3c24xx_spi_chipsel(struct spi_device *spi, int value) { struct s3c24xx_spi_devstate *cs = spi->controller_state; struct s3c24xx_spi *hw = to_hw(spi); - unsigned int cspol = spi->mode & SPI_CS_HIGH ? 1 : 0; /* change the chipselect state and the state of the spi engine clock */ switch (value) { case BITBANG_CS_INACTIVE: - hw->set_cs(hw->pdata, spi->chip_select, cspol^1); writeb(cs->spcon, hw->regs + S3C2410_SPCON); break; case BITBANG_CS_ACTIVE: writeb(cs->spcon | S3C2410_SPCON_ENSCK, hw->regs + S3C2410_SPCON); - hw->set_cs(hw->pdata, spi->chip_select, cspol); break; } } @@ -452,14 +440,6 @@ static void s3c24xx_spi_initialsetup(struct s3c24xx_spi *hw) writeb(0xff, hw->regs + S3C2410_SPPRE); writeb(SPPIN_DEFAULT, hw->regs + S3C2410_SPPIN); writeb(SPCON_DEFAULT, hw->regs + S3C2410_SPCON); - - if (hw->pdata) { - if (hw->set_cs == s3c24xx_spi_gpiocs) - gpio_direction_output(hw->pdata->pin_cs, 1); - - if (hw->pdata->gpio_setup) - hw->pdata->gpio_setup(hw->pdata, 1); - } } static int s3c24xx_spi_probe(struct platform_device *pdev) @@ -502,6 +482,9 @@ static int s3c24xx_spi_probe(struct platform_device *pdev) master->num_chipselect = hw->pdata->num_cs; master->bus_num = pdata->bus_num; master->bits_per_word_mask = SPI_BPW_MASK(8); + /* we need to call the local chipselect callback */ + master->flags = SPI_MASTER_GPIO_SS; + master->use_gpio_descriptors = true; /* setup the state for the bitbang driver */ @@ -541,27 +524,6 @@ static int s3c24xx_spi_probe(struct platform_device *pdev) goto err_no_pdata; } - /* setup any gpio we can */ - - if (!pdata->set_cs) { - if (pdata->pin_cs < 0) { - dev_err(&pdev->dev, "No chipselect pin\n"); - err = -EINVAL; - goto err_register; - } - - err = devm_gpio_request(&pdev->dev, pdata->pin_cs, - dev_name(&pdev->dev)); - if (err) { - dev_err(&pdev->dev, "Failed to get gpio for cs\n"); - goto err_register; - } - - hw->set_cs = s3c24xx_spi_gpiocs; - gpio_direction_output(pdata->pin_cs, 1); - } else - hw->set_cs = pdata->set_cs; - s3c24xx_spi_initialsetup(hw); /* register our spi controller */ @@ -604,9 +566,6 @@ static int s3c24xx_spi_suspend(struct device *dev) if (ret) return ret; - if (hw->pdata && hw->pdata->gpio_setup) - hw->pdata->gpio_setup(hw->pdata, 0); - clk_disable(hw->clk); return 0; } diff --git a/include/linux/spi/s3c24xx.h b/include/linux/spi/s3c24xx.h index 440a71593162..9b8bb22d5b0c 100644 --- a/include/linux/spi/s3c24xx.h +++ b/include/linux/spi/s3c24xx.h @@ -10,14 +10,9 @@ #define __LINUX_SPI_S3C24XX_H __FILE__ struct s3c2410_spi_info { - int pin_cs; /* simple gpio cs */ unsigned int num_cs; /* total chipselects */ int bus_num; /* bus number to use. */ - unsigned int use_fiq:1; /* use fiq */ - - void (*gpio_setup)(struct s3c2410_spi_info *spi, int enable); - void (*set_cs)(struct s3c2410_spi_info *spi, int cs, int pol); }; extern int s3c24xx_set_fiq(unsigned int irq, u32 *ack_ptr, bool on); -- cgit v1.2.3 From f62ca4e2a863033d9b3b5a00a0d897557c9da6c5 Mon Sep 17 00:00:00 2001 From: Li-hao Kuo Date: Tue, 18 Jan 2022 16:42:38 +0800 Subject: spi: Add spi driver for Sunplus SP7021 Add spi driver for Sunplus SP7021. Signed-off-by: Li-hao Kuo Link: https://lore.kernel.org/r/37998e515d561e762ee30d0ac4fca25a948e0c5c.1642494310.git.lhjeff911@gmail.com Signed-off-by: Mark Brown --- MAINTAINERS | 6 + drivers/spi/Kconfig | 11 + drivers/spi/Makefile | 1 + drivers/spi/spi-sunplus-sp7021.c | 602 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 620 insertions(+) create mode 100644 drivers/spi/spi-sunplus-sp7021.c diff --git a/MAINTAINERS b/MAINTAINERS index ea3e6c914384..a517966bc7e8 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -18491,6 +18491,12 @@ S: Maintained F: Documentation/devicetree/bindings/rtc/sunplus,sp7021-rtc.yaml F: drivers/rtc/rtc-sunplus.c +SUNPLUS SPI CONTROLLER INTERFACE DRIVER +M: Li-hao Kuo +L: linux-spi@vger.kernel.org +S: Maintained +F: drivers/spi/spi-sunplus-sp7021.c + SUPERH M: Yoshinori Sato M: Rich Felker diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index b2a8821971e1..203f4ec32119 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -866,6 +866,17 @@ config SPI_SUN6I help This enables using the SPI controller on the Allwinner A31 SoCs. +config SPI_SUNPLUS_SP7021 + tristate "Sunplus SP7021 SPI controller" + depends on SOC_SP7021 || COMPILE_TEST + help + This enables Sunplus SP7021 SPI controller driver on the SP7021 SoCs. + This driver can also be built as a module. If so, the module will be + called as spi-sunplus-sp7021. + + If you have a Sunplus SP7021 platform say Y here. + If unsure, say N. + config SPI_SYNQUACER tristate "Socionext's SynQuacer HighSpeed SPI controller" depends on ARCH_SYNQUACER || COMPILE_TEST diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile index dd7393a6046f..b455eafd5367 100644 --- a/drivers/spi/Makefile +++ b/drivers/spi/Makefile @@ -119,6 +119,7 @@ obj-$(CONFIG_SPI_STM32_QSPI) += spi-stm32-qspi.o obj-$(CONFIG_SPI_ST_SSC4) += spi-st-ssc4.o obj-$(CONFIG_SPI_SUN4I) += spi-sun4i.o obj-$(CONFIG_SPI_SUN6I) += spi-sun6i.o +obj-$(CONFIG_SPI_SUNPLUS_SP7021) += spi-sunplus-sp7021.o obj-$(CONFIG_SPI_SYNQUACER) += spi-synquacer.o obj-$(CONFIG_SPI_TEGRA210_QUAD) += spi-tegra210-quad.o obj-$(CONFIG_SPI_TEGRA114) += spi-tegra114.o diff --git a/drivers/spi/spi-sunplus-sp7021.c b/drivers/spi/spi-sunplus-sp7021.c new file mode 100644 index 000000000000..627b9c3024e9 --- /dev/null +++ b/drivers/spi/spi-sunplus-sp7021.c @@ -0,0 +1,602 @@ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright (c) 2021 Sunplus Inc. +// Author: Li-hao Kuo + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define SP7021_DATA_RDY_REG 0x0044 +#define SP7021_SLAVE_DMA_CTRL_REG 0x0048 +#define SP7021_SLAVE_DMA_LENGTH_REG 0x004c +#define SP7021_SLAVE_DMA_ADDR_REG 0x004c + +#define SP7021_SLAVE_DATA_RDY BIT(0) +#define SP7021_SLAVE_SW_RST BIT(1) +#define SP7021_SLA_DMA_W_INT BIT(8) +#define SP7021_SLAVE_CLR_INT BIT(8) +#define SP7021_SLAVE_DMA_EN BIT(0) +#define SP7021_SLAVE_DMA_RW BIT(6) +#define SP7021_SLAVE_DMA_CMD GENMASK(3, 2) + +#define SP7021_FIFO_REG 0x0034 +#define SP7021_SPI_STATUS_REG 0x0038 +#define SP7021_SPI_CONFIG_REG 0x003c +#define SP7021_INT_BUSY_REG 0x004c +#define SP7021_DMA_CTRL_REG 0x0050 + +#define SP7021_SPI_START_FD BIT(0) +#define SP7021_FD_SW_RST BIT(1) +#define SP7021_TX_EMP_FLAG BIT(2) +#define SP7021_RX_EMP_FLAG BIT(4) +#define SP7021_RX_FULL_FLAG BIT(5) +#define SP7021_FINISH_FLAG BIT(6) + +#define SP7021_TX_CNT_MASK GENMASK(11, 8) +#define SP7021_RX_CNT_MASK GENMASK(15, 12) +#define SP7021_TX_LEN_MASK GENMASK(23, 16) +#define SP7021_GET_LEN_MASK GENMASK(31, 24) +#define SP7021_SET_TX_LEN GENMASK(23, 16) +#define SP7021_SET_XFER_LEN GENMASK(31, 24) + +#define SP7021_CPOL_FD BIT(0) +#define SP7021_CPHA_R BIT(1) +#define SP7021_CPHA_W BIT(2) +#define SP7021_LSB_SEL BIT(4) +#define SP7021_CS_POR BIT(5) +#define SP7021_FD_SEL BIT(6) + +#define SP7021_RX_UNIT GENMASK(8, 7) +#define SP7021_TX_UNIT GENMASK(10, 9) +#define SP7021_TX_EMP_FLAG_MASK BIT(11) +#define SP7021_RX_FULL_FLAG_MASK BIT(14) +#define SP7021_FINISH_FLAG_MASK BIT(15) +#define SP7021_CLEAN_RW_BYTE GENMASK(10, 7) +#define SP7021_CLEAN_FLUG_MASK GENMASK(15, 11) +#define SP7021_CLK_MASK GENMASK(31, 16) + +#define SP7021_INT_BYPASS BIT(3) +#define SP7021_CLR_MASTER_INT BIT(6) + +#define SP7021_SPI_DATA_SIZE (255) +#define SP7021_FIFO_DATA_LEN (16) + +enum SP_SPI_MODE { + SP7021_SLAVE_READ = 0, + SP7021_SLAVE_WRITE = 1, + SP7021_SPI_IDLE = 2, +}; + +enum { + SP7021_MASTER_MODE = 0, + SP7021_SLAVE_MODE = 1, +}; + +struct sp7021_spi_ctlr { + struct device *dev; + struct spi_controller *ctlr; + void __iomem *m_base; + void __iomem *s_base; + u32 xfer_conf; + int mode; + int m_irq; + int s_irq; + struct clk *spi_clk; + struct reset_control *rstc; + // irq spin lock + spinlock_t lock; + // data xfer lock + struct mutex buf_lock; + struct completion isr_done; + struct completion slave_isr; + unsigned int rx_cur_len; + unsigned int tx_cur_len; + unsigned int data_unit; + const u8 *tx_buf; + u8 *rx_buf; +}; + +static irqreturn_t sp7021_spi_slave_irq(int irq, void *dev) +{ + struct sp7021_spi_ctlr *pspim = dev; + unsigned int data_status; + + data_status = readl(pspim->s_base + SP7021_DATA_RDY_REG); + writel(data_status | SP7021_SLAVE_CLR_INT, pspim->s_base + SP7021_DATA_RDY_REG); + complete(&pspim->slave_isr); + return IRQ_HANDLED; +} + +static int sp7021_spi_slave_abort(struct spi_controller *ctlr) +{ + struct sp7021_spi_ctlr *pspim = spi_master_get_devdata(ctlr); + + complete(&pspim->slave_isr); + complete(&pspim->isr_done); + return 0; +} + +int sp7021_spi_slave_tx(struct spi_device *spi, struct spi_transfer *xfer) +{ + struct sp7021_spi_ctlr *pspim = spi_controller_get_devdata(spi->controller); + + reinit_completion(&pspim->slave_isr); + writel(SP7021_SLAVE_DMA_EN | SP7021_SLAVE_DMA_RW | FIELD_PREP(SP7021_SLAVE_DMA_CMD, 3), + pspim->s_base + SP7021_SLAVE_DMA_CTRL_REG); + writel(xfer->len, pspim->s_base + SP7021_SLAVE_DMA_LENGTH_REG); + writel(xfer->tx_dma, pspim->s_base + SP7021_SLAVE_DMA_ADDR_REG); + writel(readl(pspim->s_base + SP7021_DATA_RDY_REG) | SP7021_SLAVE_DATA_RDY, + pspim->s_base + SP7021_DATA_RDY_REG); + if (wait_for_completion_interruptible(&pspim->isr_done)) { + dev_err(&spi->dev, "%s() wait_for_completion err\n", __func__); + return -EINTR; + } + return 0; +} + +int sp7021_spi_slave_rx(struct spi_device *spi, struct spi_transfer *xfer) +{ + struct sp7021_spi_ctlr *pspim = spi_controller_get_devdata(spi->controller); + int ret = 0; + + reinit_completion(&pspim->isr_done); + writel(SP7021_SLAVE_DMA_EN | FIELD_PREP(SP7021_SLAVE_DMA_CMD, 3), + pspim->s_base + SP7021_SLAVE_DMA_CTRL_REG); + writel(xfer->len, pspim->s_base + SP7021_SLAVE_DMA_LENGTH_REG); + writel(xfer->rx_dma, pspim->s_base + SP7021_SLAVE_DMA_ADDR_REG); + if (wait_for_completion_interruptible(&pspim->isr_done)) { + dev_err(&spi->dev, "%s() wait_for_completion err\n", __func__); + return -EINTR; + } + writel(SP7021_SLAVE_SW_RST, pspim->s_base + SP7021_SLAVE_DMA_CTRL_REG); + return ret; +} + +void sp7021_spi_master_rb(struct sp7021_spi_ctlr *pspim, unsigned int len) +{ + int i; + + for (i = 0; i < len; i++) { + pspim->rx_buf[pspim->rx_cur_len] = + readl(pspim->m_base + SP7021_FIFO_REG); + pspim->rx_cur_len++; + } +} + +void sp7021_spi_master_wb(struct sp7021_spi_ctlr *pspim, unsigned int len) +{ + int i; + + for (i = 0; i < len; i++) { + writel(pspim->tx_buf[pspim->tx_cur_len], + pspim->m_base + SP7021_FIFO_REG); + pspim->tx_cur_len++; + } +} + +static irqreturn_t sp7021_spi_master_irq(int irq, void *dev) +{ + struct sp7021_spi_ctlr *pspim = dev; + unsigned int tx_cnt, total_len; + unsigned int tx_len, rx_cnt; + unsigned int fd_status; + unsigned long flags; + bool isrdone = false; + u32 value; + + fd_status = readl(pspim->m_base + SP7021_SPI_STATUS_REG); + tx_cnt = FIELD_GET(SP7021_TX_CNT_MASK, fd_status); + tx_len = FIELD_GET(SP7021_TX_LEN_MASK, fd_status); + total_len = FIELD_GET(SP7021_GET_LEN_MASK, fd_status); + + if ((fd_status & SP7021_TX_EMP_FLAG) && (fd_status & SP7021_RX_EMP_FLAG) && total_len == 0) + return IRQ_NONE; + + if (tx_len == 0 && total_len == 0) + return IRQ_NONE; + + spin_lock_irqsave(&pspim->lock, flags); + + rx_cnt = FIELD_GET(SP7021_RX_CNT_MASK, fd_status); + if (fd_status & SP7021_RX_FULL_FLAG) + rx_cnt = pspim->data_unit; + + tx_cnt = min(tx_len - pspim->tx_cur_len, pspim->data_unit - tx_cnt); + dev_dbg(pspim->dev, "fd_st=0x%x rx_c:%d tx_c:%d tx_l:%d", + fd_status, rx_cnt, tx_cnt, tx_len); + + if (rx_cnt > 0) + sp7021_spi_master_rb(pspim, rx_cnt); + if (tx_cnt > 0) + sp7021_spi_master_wb(pspim, tx_cnt); + + fd_status = readl(pspim->m_base + SP7021_SPI_STATUS_REG); + tx_len = FIELD_GET(SP7021_TX_LEN_MASK, fd_status); + total_len = FIELD_GET(SP7021_GET_LEN_MASK, fd_status); + + if (fd_status & SP7021_FINISH_FLAG || tx_len == pspim->tx_cur_len) { + while (total_len != pspim->rx_cur_len) { + fd_status = readl(pspim->m_base + SP7021_SPI_STATUS_REG); + total_len = FIELD_GET(SP7021_GET_LEN_MASK, fd_status); + if (fd_status & SP7021_RX_FULL_FLAG) + rx_cnt = pspim->data_unit; + else + rx_cnt = FIELD_GET(SP7021_RX_CNT_MASK, fd_status); + + if (rx_cnt > 0) + sp7021_spi_master_rb(pspim, rx_cnt); + } + value = readl(pspim->m_base + SP7021_INT_BUSY_REG); + value |= SP7021_CLR_MASTER_INT; + writel(value, pspim->m_base + SP7021_INT_BUSY_REG); + writel(SP7021_FINISH_FLAG, pspim->m_base + SP7021_SPI_STATUS_REG); + isrdone = true; + } + + if (isrdone) + complete(&pspim->isr_done); + spin_unlock_irqrestore(&pspim->lock, flags); + return IRQ_HANDLED; +} + +static void sp7021_prep_transfer(struct spi_controller *ctlr, struct spi_device *spi) +{ + struct sp7021_spi_ctlr *pspim = spi_master_get_devdata(ctlr); + + pspim->tx_cur_len = 0; + pspim->rx_cur_len = 0; + pspim->data_unit = SP7021_FIFO_DATA_LEN; +} + +// preliminary set CS, CPOL, CPHA and LSB +static int sp7021_spi_controller_prepare_message(struct spi_controller *ctlr, + struct spi_message *msg) +{ + struct sp7021_spi_ctlr *pspim = spi_master_get_devdata(ctlr); + struct spi_device *s = msg->spi; + u32 valus, rs = 0; + + valus = readl(pspim->m_base + SP7021_SPI_STATUS_REG); + valus |= SP7021_FD_SW_RST; + writel(valus, pspim->m_base + SP7021_SPI_STATUS_REG); + rs |= SP7021_FD_SEL; + if (s->mode & SPI_CPOL) + rs |= SP7021_CPOL_FD; + + if (s->mode & SPI_LSB_FIRST) + rs |= SP7021_LSB_SEL; + + if (s->mode & SPI_CS_HIGH) + rs |= SP7021_CS_POR; + + if (s->mode & SPI_CPHA) + rs |= SP7021_CPHA_R; + else + rs |= SP7021_CPHA_W; + + rs |= FIELD_PREP(SP7021_TX_UNIT, 0) | FIELD_PREP(SP7021_RX_UNIT, 0); + pspim->xfer_conf = rs; + if (pspim->xfer_conf & SP7021_CPOL_FD) + writel(pspim->xfer_conf, pspim->m_base + SP7021_SPI_CONFIG_REG); + + return 0; +} + +static void sp7021_spi_setup_clk(struct spi_controller *ctlr, struct spi_transfer *xfer) +{ + struct sp7021_spi_ctlr *pspim = spi_master_get_devdata(ctlr); + u32 clk_rate, clk_sel, div; + + clk_rate = clk_get_rate(pspim->spi_clk); + div = clk_rate / xfer->speed_hz; + if (div < 2) + div = 2; + clk_sel = (div / 2) - 1; + pspim->xfer_conf &= SP7021_CLK_MASK; + pspim->xfer_conf |= FIELD_PREP(SP7021_CLK_MASK, clk_sel); + writel(pspim->xfer_conf, pspim->m_base + SP7021_SPI_CONFIG_REG); +} + +static int sp7021_spi_master_transfer_one(struct spi_controller *ctlr, struct spi_device *spi, + struct spi_transfer *xfer) +{ + struct sp7021_spi_ctlr *pspim = spi_master_get_devdata(ctlr); + unsigned long timeout = msecs_to_jiffies(1000); + unsigned int xfer_cnt, xfer_len, last_len; + unsigned int i, len_temp; + u32 reg_temp; + int ret; + + xfer_cnt = xfer->len / SP7021_SPI_DATA_SIZE; + last_len = xfer->len % SP7021_SPI_DATA_SIZE; + + for (i = 0; i <= xfer_cnt; i++) { + mutex_lock(&pspim->buf_lock); + sp7021_prep_transfer(ctlr, spi); + sp7021_spi_setup_clk(ctlr, xfer); + reinit_completion(&pspim->isr_done); + + if (i == xfer_cnt) + xfer_len = last_len; + else + xfer_len = SP7021_SPI_DATA_SIZE; + + pspim->tx_buf = xfer->tx_buf + i * SP7021_SPI_DATA_SIZE; + pspim->rx_buf = xfer->rx_buf + i * SP7021_SPI_DATA_SIZE; + + if (pspim->tx_cur_len < xfer_len) { + len_temp = min(pspim->data_unit, xfer_len); + sp7021_spi_master_wb(pspim, len_temp); + } + reg_temp = readl(pspim->m_base + SP7021_SPI_CONFIG_REG); + reg_temp &= ~SP7021_CLEAN_RW_BYTE; + reg_temp &= ~SP7021_CLEAN_FLUG_MASK; + reg_temp |= SP7021_FD_SEL | SP7021_FINISH_FLAG_MASK | + SP7021_TX_EMP_FLAG_MASK | SP7021_RX_FULL_FLAG_MASK | + FIELD_PREP(SP7021_TX_UNIT, 0) | FIELD_PREP(SP7021_RX_UNIT, 0); + writel(reg_temp, pspim->m_base + SP7021_SPI_CONFIG_REG); + + reg_temp = FIELD_PREP(SP7021_SET_TX_LEN, xfer_len) | + FIELD_PREP(SP7021_SET_XFER_LEN, xfer_len) | + SP7021_SPI_START_FD; + writel(reg_temp, pspim->m_base + SP7021_SPI_STATUS_REG); + + if (!wait_for_completion_interruptible_timeout(&pspim->isr_done, timeout)) { + dev_err(&spi->dev, "wait_for_completion err\n"); + return -ETIMEDOUT; + } + + reg_temp = readl(pspim->m_base + SP7021_SPI_STATUS_REG); + if (reg_temp & SP7021_FINISH_FLAG) { + writel(SP7021_FINISH_FLAG, pspim->m_base + SP7021_SPI_STATUS_REG); + writel(readl(pspim->m_base + SP7021_SPI_CONFIG_REG) & + SP7021_CLEAN_FLUG_MASK, pspim->m_base + SP7021_SPI_CONFIG_REG); + } + + if (pspim->xfer_conf & SP7021_CPOL_FD) + writel(pspim->xfer_conf, pspim->m_base + SP7021_SPI_CONFIG_REG); + + mutex_unlock(&pspim->buf_lock); + ret = 0; + } + return ret; +} + +static int sp7021_spi_slave_transfer_one(struct spi_controller *ctlr, struct spi_device *spi, + struct spi_transfer *xfer) +{ + struct sp7021_spi_ctlr *pspim = spi_master_get_devdata(ctlr); + struct device *dev = pspim->dev; + int mode, ret = 0; + + mode = SP7021_SPI_IDLE; + if (xfer->tx_buf && xfer->rx_buf) { + dev_dbg(&ctlr->dev, "%s() wrong command\n", __func__); + ret = -EINVAL; + } else if (xfer->tx_buf) { + xfer->tx_dma = dma_map_single(dev, (void *)xfer->tx_buf, + xfer->len, DMA_TO_DEVICE); + if (dma_mapping_error(dev, xfer->tx_dma)) + return -ENOMEM; + mode = SP7021_SLAVE_WRITE; + } else if (xfer->rx_buf) { + xfer->rx_dma = dma_map_single(dev, xfer->rx_buf, xfer->len, + DMA_FROM_DEVICE); + if (dma_mapping_error(dev, xfer->rx_dma)) + return -ENOMEM; + mode = SP7021_SLAVE_READ; + } + + switch (mode) { + case SP7021_SLAVE_WRITE: + ret = sp7021_spi_slave_tx(spi, xfer); + break; + case SP7021_SLAVE_READ: + ret = sp7021_spi_slave_rx(spi, xfer); + break; + default: + break; + } + if (xfer->tx_buf) + dma_unmap_single(dev, xfer->tx_dma, xfer->len, DMA_TO_DEVICE); + if (xfer->rx_buf) + dma_unmap_single(dev, xfer->rx_dma, xfer->len, DMA_FROM_DEVICE); + + spi_finalize_current_transfer(ctlr); + return ret; +} + +static void sp7021_spi_disable_unprepare(void *data) +{ + clk_disable_unprepare(data); +} + +static void sp7021_spi_reset_control_assert(void *data) +{ + reset_control_assert(data); +} + +static int sp7021_spi_controller_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct sp7021_spi_ctlr *pspim; + struct spi_controller *ctlr; + int mode, ret; + + pdev->id = of_alias_get_id(pdev->dev.of_node, "sp_spi"); + + if (device_property_read_bool(dev, "spi-slave")) + mode = SP7021_SLAVE_MODE; + else + mode = SP7021_MASTER_MODE; + + if (mode == SP7021_SLAVE_MODE) + ctlr = devm_spi_alloc_slave(dev, sizeof(*pspim)); + else + ctlr = devm_spi_alloc_master(dev, sizeof(*pspim)); + if (!ctlr) + return -ENOMEM; + device_set_node(&ctlr->dev, pdev->dev.fwnode); + ctlr->bus_num = pdev->id; + ctlr->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LSB_FIRST; + ctlr->auto_runtime_pm = true; + ctlr->prepare_message = sp7021_spi_controller_prepare_message; + if (mode == SP7021_SLAVE_MODE) { + ctlr->transfer_one = sp7021_spi_slave_transfer_one; + ctlr->slave_abort = sp7021_spi_slave_abort; + ctlr->flags = SPI_CONTROLLER_HALF_DUPLEX; + } else { + ctlr->bits_per_word_mask = SPI_BPW_MASK(8); + ctlr->min_speed_hz = 40000; + ctlr->max_speed_hz = 25000000; + ctlr->use_gpio_descriptors = true; + ctlr->flags = SPI_CONTROLLER_MUST_RX | SPI_CONTROLLER_MUST_TX; + ctlr->transfer_one = sp7021_spi_master_transfer_one; + } + platform_set_drvdata(pdev, ctlr); + pspim = spi_controller_get_devdata(ctlr); + pspim->mode = mode; + pspim->ctlr = ctlr; + pspim->dev = dev; + spin_lock_init(&pspim->lock); + mutex_init(&pspim->buf_lock); + init_completion(&pspim->isr_done); + init_completion(&pspim->slave_isr); + + pspim->m_base = devm_platform_ioremap_resource_byname(pdev, "master"); + if (IS_ERR(pspim->m_base)) + return dev_err_probe(dev, PTR_ERR(pspim->m_base), "m_base get fail\n"); + + pspim->s_base = devm_platform_ioremap_resource_byname(pdev, "slave"); + if (IS_ERR(pspim->s_base)) + return dev_err_probe(dev, PTR_ERR(pspim->s_base), "s_base get fail\n"); + + pspim->m_irq = platform_get_irq_byname(pdev, "master_risc"); + if (pspim->m_irq < 0) + return pspim->m_irq; + + pspim->s_irq = platform_get_irq_byname(pdev, "slave_risc"); + if (pspim->s_irq < 0) + return pspim->s_irq; + + ret = devm_request_irq(dev, pspim->m_irq, sp7021_spi_master_irq, + IRQF_TRIGGER_RISING, pdev->name, pspim); + if (ret) + return ret; + + ret = devm_request_irq(dev, pspim->s_irq, sp7021_spi_slave_irq, + IRQF_TRIGGER_RISING, pdev->name, pspim); + if (ret) + return ret; + + pspim->spi_clk = devm_clk_get(dev, NULL); + if (IS_ERR(pspim->spi_clk)) + return dev_err_probe(dev, PTR_ERR(pspim->spi_clk), "clk get fail\n"); + + pspim->rstc = devm_reset_control_get_exclusive(dev, NULL); + if (IS_ERR(pspim->rstc)) + return dev_err_probe(dev, PTR_ERR(pspim->rstc), "rst get fail\n"); + + ret = clk_prepare_enable(pspim->spi_clk); + if (ret) + return dev_err_probe(dev, ret, "failed to enable clk\n"); + + ret = devm_add_action_or_reset(dev, sp7021_spi_disable_unprepare, pspim->spi_clk); + if (ret) + return ret; + + ret = reset_control_deassert(pspim->rstc); + if (ret) + return dev_err_probe(dev, ret, "failed to deassert reset\n"); + + ret = devm_add_action_or_reset(dev, sp7021_spi_reset_control_assert, pspim->rstc); + if (ret) + return ret; + + pm_runtime_enable(dev); + ret = spi_register_controller(ctlr); + if (ret) { + pm_runtime_disable(dev); + return dev_err_probe(dev, ret, "spi_register_master fail\n"); + } + return 0; +} + +static int sp7021_spi_controller_remove(struct platform_device *pdev) +{ + struct spi_controller *ctlr = dev_get_drvdata(&pdev->dev); + + spi_unregister_controller(ctlr); + pm_runtime_disable(&pdev->dev); + pm_runtime_set_suspended(&pdev->dev); + return 0; +} + +static int __maybe_unused sp7021_spi_controller_suspend(struct device *dev) +{ + struct spi_controller *ctlr = dev_get_drvdata(dev); + struct sp7021_spi_ctlr *pspim = spi_master_get_devdata(ctlr); + + return reset_control_assert(pspim->rstc); +} + +static int __maybe_unused sp7021_spi_controller_resume(struct device *dev) +{ + struct spi_controller *ctlr = dev_get_drvdata(dev); + struct sp7021_spi_ctlr *pspim = spi_master_get_devdata(ctlr); + + reset_control_deassert(pspim->rstc); + return clk_prepare_enable(pspim->spi_clk); +} + +static int sp7021_spi_runtime_suspend(struct device *dev) +{ + struct spi_controller *ctlr = dev_get_drvdata(dev); + struct sp7021_spi_ctlr *pspim = spi_master_get_devdata(ctlr); + + return reset_control_assert(pspim->rstc); +} + +static int sp7021_spi_runtime_resume(struct device *dev) +{ + struct spi_controller *ctlr = dev_get_drvdata(dev); + struct sp7021_spi_ctlr *pspim = spi_master_get_devdata(ctlr); + + return reset_control_deassert(pspim->rstc); +} + +static const struct dev_pm_ops sp7021_spi_pm_ops = { + SET_RUNTIME_PM_OPS(sp7021_spi_runtime_suspend, + sp7021_spi_runtime_resume, NULL) + SET_SYSTEM_SLEEP_PM_OPS(sp7021_spi_controller_suspend, + sp7021_spi_controller_resume) +}; + +static const struct of_device_id sp7021_spi_controller_ids[] = { + { .compatible = "sunplus,sp7021-spi" }, + {} +}; +MODULE_DEVICE_TABLE(of, sp7021_spi_controller_ids); + +static struct platform_driver sp7021_spi_controller_driver = { + .probe = sp7021_spi_controller_probe, + .remove = sp7021_spi_controller_remove, + .driver = { + .name = "sunplus,sp7021-spi-controller", + .of_match_table = sp7021_spi_controller_ids, + .pm = &sp7021_spi_pm_ops, + }, +}; +module_platform_driver(sp7021_spi_controller_driver); + +MODULE_AUTHOR("Li-hao Kuo "); +MODULE_DESCRIPTION("Sunplus SPI controller driver"); +MODULE_LICENSE("GPL"); -- cgit v1.2.3 From a708078eeb992799161e794d9c569cf4f725a5b0 Mon Sep 17 00:00:00 2001 From: Li-hao Kuo Date: Tue, 25 Jan 2022 12:14:29 +0000 Subject: spi: Add Sunplus SP7021 schema Add bindings for Sunplus SP7021 spi driver Signed-off-by: Li-hao Kuo Signed-off-by: Mark Brown --- .../bindings/spi/spi-sunplus-sp7021.yaml | 81 ++++++++++++++++++++++ MAINTAINERS | 1 + 2 files changed, 82 insertions(+) create mode 100644 Documentation/devicetree/bindings/spi/spi-sunplus-sp7021.yaml diff --git a/Documentation/devicetree/bindings/spi/spi-sunplus-sp7021.yaml b/Documentation/devicetree/bindings/spi/spi-sunplus-sp7021.yaml new file mode 100644 index 000000000000..24382cdda645 --- /dev/null +++ b/Documentation/devicetree/bindings/spi/spi-sunplus-sp7021.yaml @@ -0,0 +1,81 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +# Copyright (C) Sunplus Co., Ltd. 2021 +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/spi/spi-sunplus-sp7021.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Sunplus sp7021 SPI controller + +allOf: + - $ref: "spi-controller.yaml" + +maintainers: + - Li-hao Kuo + +properties: + compatible: + enum: + - sunplus,sp7021-spi + + reg: + items: + - the SPI master registers + - the SPI slave registers + + reg-names: + items: + - const: master + - const: slave + + interrupt-names: + items: + - const: dma_w + - const: master_risc + - const: slave_risc + + interrupts: + minItems: 3 + + clocks: + maxItems: 1 + + resets: + maxItems: 1 + +required: + - compatible + - reg + - reg-names + - interrupts + - interrupt-names + - clocks + - clocks-names + - resets + - pinctrl-names + - pinctrl-0 + +unevaluatedProperties: false + +examples: + - | + #include + #include + #include + spi@9C002D80 { + compatible = "sunplus,sp7021-spi"; + reg = <0x9C002D80 0x80>, <0x9C002E00 0x80>; + reg-names = "master", "slave"; + interrupt-parent = <&intc>; + interrupt-names = "dma_w", + "master_risc", + "slave_risc"; + interrupts = <144 IRQ_TYPE_LEVEL_HIGH>, + <146 IRQ_TYPE_LEVEL_HIGH>, + <145 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clkc SPI_COMBO_0>; + resets = <&rstc RST_SPI_COMBO_0>; + pinctrl-names = "default"; + pinctrl-0 = <&pins_spi0>; + }; +... diff --git a/MAINTAINERS b/MAINTAINERS index a517966bc7e8..13301adabe6e 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -18495,6 +18495,7 @@ SUNPLUS SPI CONTROLLER INTERFACE DRIVER M: Li-hao Kuo L: linux-spi@vger.kernel.org S: Maintained +F: Documentation/devicetree/bindings/spi/spi-sunplus-sp7021.yaml F: drivers/spi/spi-sunplus-sp7021.c SUPERH -- cgit v1.2.3 From 474fc2e6395d62758e80b9ea65f61339296355fc Mon Sep 17 00:00:00 2001 From: Guochun Mao Date: Wed, 26 Jan 2022 17:11:59 +0800 Subject: spi: spi-mtk-nor: make some internal variables static Variables mtk_nor_caps_mt8173, mtk_nor_caps_mt8186 and mtk_nor_caps_mt8192 are not declared. Make them static. Fixes: 5b177234e9fd ("spi: spi-mtk-nor: improve device table for adding more capabilities") Signed-off-by: Guochun Mao Reported-by: kernel test robot Link: https://lore.kernel.org/r/20220126091159.27513-1-guochun.mao@mediatek.com Signed-off-by: Mark Brown --- drivers/spi/spi-mtk-nor.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/spi/spi-mtk-nor.c b/drivers/spi/spi-mtk-nor.c index 455b4dcb26e9..94fb09696677 100644 --- a/drivers/spi/spi-mtk-nor.c +++ b/drivers/spi/spi-mtk-nor.c @@ -770,17 +770,17 @@ static const struct spi_controller_mem_ops mtk_nor_mem_ops = { .exec_op = mtk_nor_exec_op }; -const struct mtk_nor_caps mtk_nor_caps_mt8173 = { +static const struct mtk_nor_caps mtk_nor_caps_mt8173 = { .dma_bits = 32, .extra_dummy_bit = 0, }; -const struct mtk_nor_caps mtk_nor_caps_mt8186 = { +static const struct mtk_nor_caps mtk_nor_caps_mt8186 = { .dma_bits = 32, .extra_dummy_bit = 1, }; -const struct mtk_nor_caps mtk_nor_caps_mt8192 = { +static const struct mtk_nor_caps mtk_nor_caps_mt8192 = { .dma_bits = 36, .extra_dummy_bit = 0, }; -- cgit v1.2.3 From 20dc69ca1023b7e4c4af3c3495aa5a91e1a9be39 Mon Sep 17 00:00:00 2001 From: Yang Yingliang Date: Thu, 27 Jan 2022 19:58:15 +0800 Subject: spi: Fix missing unlock on error in sp7021_spi_master_transfer_one() Add the missing unlock before return from sp7021_spi_master_transfer_one() in the error handling case. Fixes: f62ca4e2a863 ("spi: Add spi driver for Sunplus SP7021") Reported-by: Hulk Robot Signed-off-by: Yang Yingliang Link: https://lore.kernel.org/r/20220127115815.3148950-1-yangyingliang@huawei.com Signed-off-by: Mark Brown --- drivers/spi/spi-sunplus-sp7021.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/spi/spi-sunplus-sp7021.c b/drivers/spi/spi-sunplus-sp7021.c index 627b9c3024e9..cbbb1664017e 100644 --- a/drivers/spi/spi-sunplus-sp7021.c +++ b/drivers/spi/spi-sunplus-sp7021.c @@ -351,6 +351,7 @@ static int sp7021_spi_master_transfer_one(struct spi_controller *ctlr, struct sp if (!wait_for_completion_interruptible_timeout(&pspim->isr_done, timeout)) { dev_err(&spi->dev, "wait_for_completion err\n"); + mutex_unlock(&pspim->buf_lock); return -ETIMEDOUT; } -- cgit v1.2.3 From 31455bbda2081af83f72bb4636348b12b82c37c1 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Tue, 25 Jan 2022 01:58:36 +0100 Subject: spi: pxa2xx_spi: Convert to use GPIO descriptors This converts the PXA2xx SPI driver to use GPIO descriptors exclusively to retrieve GPIO chip select lines. The device tree and ACPI paths of the driver already use descriptors, hence ->use_gpio_descriptors is already set and this codepath is well tested. Convert all the PXA boards providing chip select GPIOs as platform data and drop the old GPIO chipselect handling in favor of the core managing it exclusively. Cc: Marek Vasut Cc: Daniel Mack Cc: Haojian Zhuang Cc: Robert Jarzmik Cc: linux-arm-kernel@lists.infradead.org Acked-by: Jonathan Cameron Signed-off-by: Linus Walleij Link: https://lore.kernel.org/r/20220125005836.494807-1-linus.walleij@linaro.org Signed-off-by: Mark Brown --- Documentation/spi/pxa2xx.rst | 3 -- arch/arm/mach-pxa/corgi.c | 26 ++++++++--------- arch/arm/mach-pxa/hx4700.c | 10 ++++++- arch/arm/mach-pxa/icontrol.c | 26 +++++++++++++---- arch/arm/mach-pxa/littleton.c | 10 ++++++- arch/arm/mach-pxa/magician.c | 12 ++++++-- arch/arm/mach-pxa/poodle.c | 14 ++++++---- arch/arm/mach-pxa/spitz.c | 26 ++++++++--------- arch/arm/mach-pxa/stargate2.c | 20 ++++++++++++-- arch/arm/mach-pxa/z2.c | 20 ++++++++++++-- drivers/spi/spi-pxa2xx.c | 63 +----------------------------------------- include/linux/spi/pxa2xx_spi.h | 1 - 12 files changed, 117 insertions(+), 114 deletions(-) diff --git a/Documentation/spi/pxa2xx.rst b/Documentation/spi/pxa2xx.rst index 6347580826be..716f65d87d04 100644 --- a/Documentation/spi/pxa2xx.rst +++ b/Documentation/spi/pxa2xx.rst @@ -101,7 +101,6 @@ device. All fields are optional. u8 rx_threshold; u8 dma_burst_size; u32 timeout; - int gpio_cs; }; The "pxa2xx_spi_chip.tx_threshold" and "pxa2xx_spi_chip.rx_threshold" fields are @@ -146,7 +145,6 @@ field. Below is a sample configuration using the PXA255 NSSP. .rx_threshold = 8, /* SSP hardward FIFO threshold */ .dma_burst_size = 8, /* Byte wide transfers used so 8 byte bursts */ .timeout = 235, /* See Intel documentation */ - .gpio_cs = 2, /* Use external chip select */ }; static struct pxa2xx_spi_chip cs8405a_chip_info = { @@ -154,7 +152,6 @@ field. Below is a sample configuration using the PXA255 NSSP. .rx_threshold = 8, /* SSP hardward FIFO threshold */ .dma_burst_size = 8, /* Byte wide transfers used so 8 byte bursts */ .timeout = 235, /* See Intel documentation */ - .gpio_cs = 3, /* Use external chip select */ }; static struct spi_board_info streetracer_spi_board_info[] __initdata = { diff --git a/arch/arm/mach-pxa/corgi.c b/arch/arm/mach-pxa/corgi.c index 593c7f793da5..44659fbc37ba 100644 --- a/arch/arm/mach-pxa/corgi.c +++ b/arch/arm/mach-pxa/corgi.c @@ -530,6 +530,16 @@ static struct pxa2xx_spi_controller corgi_spi_info = { .num_chipselect = 3, }; +static struct gpiod_lookup_table corgi_spi_gpio_table = { + .dev_id = "pxa2xx-spi.1", + .table = { + GPIO_LOOKUP_IDX("gpio-pxa", CORGI_GPIO_ADS7846_CS, "cs", 0, GPIO_ACTIVE_LOW), + GPIO_LOOKUP_IDX("gpio-pxa", CORGI_GPIO_LCDCON_CS, "cs", 1, GPIO_ACTIVE_LOW), + GPIO_LOOKUP_IDX("gpio-pxa", CORGI_GPIO_MAX1111_CS, "cs", 2, GPIO_ACTIVE_LOW), + { }, + }, +}; + static void corgi_wait_for_hsync(void) { while (gpio_get_value(CORGI_GPIO_HSYNC)) @@ -548,10 +558,6 @@ static struct ads7846_platform_data corgi_ads7846_info = { .wait_for_sync = corgi_wait_for_hsync, }; -static struct pxa2xx_spi_chip corgi_ads7846_chip = { - .gpio_cs = CORGI_GPIO_ADS7846_CS, -}; - static void corgi_bl_kick_battery(void) { void (*kick_batt)(void); @@ -580,14 +586,6 @@ static struct corgi_lcd_platform_data corgi_lcdcon_info = { .kick_battery = corgi_bl_kick_battery, }; -static struct pxa2xx_spi_chip corgi_lcdcon_chip = { - .gpio_cs = CORGI_GPIO_LCDCON_CS, -}; - -static struct pxa2xx_spi_chip corgi_max1111_chip = { - .gpio_cs = CORGI_GPIO_MAX1111_CS, -}; - static struct spi_board_info corgi_spi_devices[] = { { .modalias = "ads7846", @@ -595,7 +593,6 @@ static struct spi_board_info corgi_spi_devices[] = { .bus_num = 1, .chip_select = 0, .platform_data = &corgi_ads7846_info, - .controller_data= &corgi_ads7846_chip, .irq = PXA_GPIO_TO_IRQ(CORGI_GPIO_TP_INT), }, { .modalias = "corgi-lcd", @@ -603,18 +600,17 @@ static struct spi_board_info corgi_spi_devices[] = { .bus_num = 1, .chip_select = 1, .platform_data = &corgi_lcdcon_info, - .controller_data= &corgi_lcdcon_chip, }, { .modalias = "max1111", .max_speed_hz = 450000, .bus_num = 1, .chip_select = 2, - .controller_data= &corgi_max1111_chip, }, }; static void __init corgi_init_spi(void) { + gpiod_add_lookup_table(&corgi_spi_gpio_table); pxa2xx_set_spi_info(1, &corgi_spi_info); gpiod_add_lookup_table(&corgi_lcdcon_gpio_table); spi_register_board_info(ARRAY_AND_SIZE(corgi_spi_devices)); diff --git a/arch/arm/mach-pxa/hx4700.c b/arch/arm/mach-pxa/hx4700.c index 1d4c5db54be2..e1870fbb19e7 100644 --- a/arch/arm/mach-pxa/hx4700.c +++ b/arch/arm/mach-pxa/hx4700.c @@ -616,7 +616,6 @@ static struct pxa2xx_spi_chip tsc2046_chip = { .tx_threshold = 1, .rx_threshold = 2, .timeout = 64, - .gpio_cs = GPIO88_HX4700_TSC2046_CS, }; static struct spi_board_info tsc2046_board_info[] __initdata = { @@ -635,6 +634,14 @@ static struct pxa2xx_spi_controller pxa_ssp2_master_info = { .enable_dma = 1, }; +static struct gpiod_lookup_table pxa_ssp2_gpio_table = { + .dev_id = "pxa2xx-spi.2", + .table = { + GPIO_LOOKUP_IDX("gpio-pxa", GPIO88_HX4700_TSC2046_CS, "cs", 0, GPIO_ACTIVE_LOW), + { }, + }, +}; + /* * External power */ @@ -896,6 +903,7 @@ static void __init hx4700_init(void) pxa_set_i2c_info(NULL); i2c_register_board_info(0, ARRAY_AND_SIZE(i2c_board_info)); i2c_register_board_info(1, ARRAY_AND_SIZE(pi2c_board_info)); + gpiod_add_lookup_table(&pxa_ssp2_gpio_table); pxa2xx_set_spi_info(2, &pxa_ssp2_master_info); spi_register_board_info(ARRAY_AND_SIZE(tsc2046_board_info)); diff --git a/arch/arm/mach-pxa/icontrol.c b/arch/arm/mach-pxa/icontrol.c index 04a12523cdee..753fe166ab68 100644 --- a/arch/arm/mach-pxa/icontrol.c +++ b/arch/arm/mach-pxa/icontrol.c @@ -13,7 +13,7 @@ #include #include #include -#include +#include #include #include @@ -42,7 +42,6 @@ static struct pxa2xx_spi_chip mcp251x_chip_info1 = { .rx_threshold = 128, .dma_burst_size = 8, .timeout = 235, - .gpio_cs = ICONTROL_MCP251x_nCS1 }; static struct pxa2xx_spi_chip mcp251x_chip_info2 = { @@ -50,7 +49,6 @@ static struct pxa2xx_spi_chip mcp251x_chip_info2 = { .rx_threshold = 128, .dma_burst_size = 8, .timeout = 235, - .gpio_cs = ICONTROL_MCP251x_nCS2 }; static struct pxa2xx_spi_chip mcp251x_chip_info3 = { @@ -58,7 +56,6 @@ static struct pxa2xx_spi_chip mcp251x_chip_info3 = { .rx_threshold = 128, .dma_burst_size = 8, .timeout = 235, - .gpio_cs = ICONTROL_MCP251x_nCS3 }; static struct pxa2xx_spi_chip mcp251x_chip_info4 = { @@ -66,7 +63,6 @@ static struct pxa2xx_spi_chip mcp251x_chip_info4 = { .rx_threshold = 128, .dma_burst_size = 8, .timeout = 235, - .gpio_cs = ICONTROL_MCP251x_nCS4 }; static const struct property_entry mcp251x_properties[] = { @@ -143,6 +139,24 @@ struct platform_device pxa_spi_ssp4 = { } }; +static struct gpiod_lookup_table pxa_ssp3_gpio_table = { + .dev_id = "pxa2xx-spi.3", + .table = { + GPIO_LOOKUP_IDX("gpio-pxa", ICONTROL_MCP251x_nCS1, "cs", 0, GPIO_ACTIVE_LOW), + GPIO_LOOKUP_IDX("gpio-pxa", ICONTROL_MCP251x_nCS2, "cs", 1, GPIO_ACTIVE_LOW), + { }, + }, +}; + +static struct gpiod_lookup_table pxa_ssp4_gpio_table = { + .dev_id = "pxa2xx-spi.4", + .table = { + GPIO_LOOKUP_IDX("gpio-pxa", ICONTROL_MCP251x_nCS3, "cs", 0, GPIO_ACTIVE_LOW), + GPIO_LOOKUP_IDX("gpio-pxa", ICONTROL_MCP251x_nCS4, "cs", 1, GPIO_ACTIVE_LOW), + { }, + }, +}; + static struct platform_device *icontrol_spi_devices[] __initdata = { &pxa_spi_ssp3, &pxa_spi_ssp4, @@ -175,6 +189,8 @@ static mfp_cfg_t mfp_can_cfg[] __initdata = { static void __init icontrol_can_init(void) { pxa3xx_mfp_config(ARRAY_AND_SIZE(mfp_can_cfg)); + gpiod_add_lookup_table(&pxa_ssp3_gpio_table); + gpiod_add_lookup_table(&pxa_ssp4_gpio_table); platform_add_devices(ARRAY_AND_SIZE(icontrol_spi_devices)); spi_register_board_info(ARRAY_AND_SIZE(mcp251x_board_info)); } diff --git a/arch/arm/mach-pxa/littleton.c b/arch/arm/mach-pxa/littleton.c index 793f61375ee8..73f5953b3bb6 100644 --- a/arch/arm/mach-pxa/littleton.c +++ b/arch/arm/mach-pxa/littleton.c @@ -195,7 +195,6 @@ static struct pxa2xx_spi_controller littleton_spi_info = { static struct pxa2xx_spi_chip littleton_tdo24m_chip = { .rx_threshold = 1, .tx_threshold = 1, - .gpio_cs = LITTLETON_GPIO_LCD_CS, }; static struct spi_board_info littleton_spi_devices[] __initdata = { @@ -208,8 +207,17 @@ static struct spi_board_info littleton_spi_devices[] __initdata = { }, }; +static struct gpiod_lookup_table littleton_spi_gpio_table = { + .dev_id = "pxa2xx-spi.2", + .table = { + GPIO_LOOKUP_IDX("gpio-pxa", LITTLETON_GPIO_LCD_CS, "cs", 0, GPIO_ACTIVE_LOW), + { }, + }, +}; + static void __init littleton_init_spi(void) { + gpiod_add_lookup_table(&littleton_spi_gpio_table); pxa2xx_set_spi_info(2, &littleton_spi_info); spi_register_board_info(ARRAY_AND_SIZE(littleton_spi_devices)); } diff --git a/arch/arm/mach-pxa/magician.c b/arch/arm/mach-pxa/magician.c index cd9fa465b9b2..200fd35168e0 100644 --- a/arch/arm/mach-pxa/magician.c +++ b/arch/arm/mach-pxa/magician.c @@ -938,8 +938,6 @@ struct pxa2xx_spi_chip tsc2046_chip_info = { .tx_threshold = 1, .rx_threshold = 2, .timeout = 64, - /* NOTICE must be GPIO, incompatibility with hw PXA SPI framing */ - .gpio_cs = GPIO14_MAGICIAN_TSC2046_CS, }; static struct pxa2xx_spi_controller magician_spi_info = { @@ -947,6 +945,15 @@ static struct pxa2xx_spi_controller magician_spi_info = { .enable_dma = 1, }; +static struct gpiod_lookup_table magician_spi_gpio_table = { + .dev_id = "pxa2xx-spi.2", + .table = { + /* NOTICE must be GPIO, incompatibility with hw PXA SPI framing */ + GPIO_LOOKUP_IDX("gpio-pxa", GPIO14_MAGICIAN_TSC2046_CS, "cs", 0, GPIO_ACTIVE_LOW), + { }, + }, +}; + static struct spi_board_info ads7846_spi_board_info[] __initdata = { { .modalias = "ads7846", @@ -1031,6 +1038,7 @@ static void __init magician_init(void) } else pr_err("LCD detection: CPLD mapping failed\n"); + gpiod_add_lookup_table(&magician_spi_gpio_table); pxa2xx_set_spi_info(2, &magician_spi_info); spi_register_board_info(ARRAY_AND_SIZE(ads7846_spi_board_info)); diff --git a/arch/arm/mach-pxa/poodle.c b/arch/arm/mach-pxa/poodle.c index 3a4ecc3c8f8b..58cfa434afde 100644 --- a/arch/arm/mach-pxa/poodle.c +++ b/arch/arm/mach-pxa/poodle.c @@ -197,6 +197,14 @@ static struct pxa2xx_spi_controller poodle_spi_info = { .num_chipselect = 1, }; +static struct gpiod_lookup_table poodle_spi_gpio_table = { + .dev_id = "pxa2xx-spi.1", + .table = { + GPIO_LOOKUP_IDX("gpio-pxa", POODLE_GPIO_TP_CS, "cs", 0, GPIO_ACTIVE_LOW), + { }, + }, +}; + static struct ads7846_platform_data poodle_ads7846_info = { .model = 7846, .vref_delay_usecs = 100, @@ -205,23 +213,19 @@ static struct ads7846_platform_data poodle_ads7846_info = { .gpio_pendown = POODLE_GPIO_TP_INT, }; -static struct pxa2xx_spi_chip poodle_ads7846_chip = { - .gpio_cs = POODLE_GPIO_TP_CS, -}; - static struct spi_board_info poodle_spi_devices[] = { { .modalias = "ads7846", .max_speed_hz = 10000, .bus_num = 1, .platform_data = &poodle_ads7846_info, - .controller_data= &poodle_ads7846_chip, .irq = PXA_GPIO_TO_IRQ(POODLE_GPIO_TP_INT), }, }; static void __init poodle_init_spi(void) { + gpiod_add_lookup_table(&poodle_spi_gpio_table); pxa2xx_set_spi_info(1, &poodle_spi_info); spi_register_board_info(ARRAY_AND_SIZE(poodle_spi_devices)); } diff --git a/arch/arm/mach-pxa/spitz.c b/arch/arm/mach-pxa/spitz.c index 371008e9bb02..a648e7094e84 100644 --- a/arch/arm/mach-pxa/spitz.c +++ b/arch/arm/mach-pxa/spitz.c @@ -510,10 +510,6 @@ static struct ads7846_platform_data spitz_ads7846_info = { .wait_for_sync = spitz_ads7846_wait_for_hsync, }; -static struct pxa2xx_spi_chip spitz_ads7846_chip = { - .gpio_cs = SPITZ_GPIO_ADS7846_CS, -}; - static void spitz_bl_kick_battery(void) { void (*kick_batt)(void); @@ -555,14 +551,6 @@ static struct corgi_lcd_platform_data spitz_lcdcon_info = { .kick_battery = spitz_bl_kick_battery, }; -static struct pxa2xx_spi_chip spitz_lcdcon_chip = { - .gpio_cs = SPITZ_GPIO_LCDCON_CS, -}; - -static struct pxa2xx_spi_chip spitz_max1111_chip = { - .gpio_cs = SPITZ_GPIO_MAX1111_CS, -}; - static struct spi_board_info spitz_spi_devices[] = { { .modalias = "ads7846", @@ -570,7 +558,6 @@ static struct spi_board_info spitz_spi_devices[] = { .bus_num = 2, .chip_select = 0, .platform_data = &spitz_ads7846_info, - .controller_data = &spitz_ads7846_chip, .irq = PXA_GPIO_TO_IRQ(SPITZ_GPIO_TP_INT), }, { .modalias = "corgi-lcd", @@ -578,13 +565,11 @@ static struct spi_board_info spitz_spi_devices[] = { .bus_num = 2, .chip_select = 1, .platform_data = &spitz_lcdcon_info, - .controller_data = &spitz_lcdcon_chip, }, { .modalias = "max1111", .max_speed_hz = 450000, .bus_num = 2, .chip_select = 2, - .controller_data = &spitz_max1111_chip, }, }; @@ -592,6 +577,16 @@ static struct pxa2xx_spi_controller spitz_spi_info = { .num_chipselect = 3, }; +static struct gpiod_lookup_table spitz_spi_gpio_table = { + .dev_id = "pxa2xx-spi.2", + .table = { + GPIO_LOOKUP_IDX("gpio-pxa", SPITZ_GPIO_ADS7846_CS, "cs", 0, GPIO_ACTIVE_LOW), + GPIO_LOOKUP_IDX("gpio-pxa", SPITZ_GPIO_LCDCON_CS, "cs", 1, GPIO_ACTIVE_LOW), + GPIO_LOOKUP_IDX("gpio-pxa", SPITZ_GPIO_MAX1111_CS, "cs", 2, GPIO_ACTIVE_LOW), + { }, + }, +}; + static void __init spitz_spi_init(void) { if (machine_is_akita()) @@ -599,6 +594,7 @@ static void __init spitz_spi_init(void) else gpiod_add_lookup_table(&spitz_lcdcon_gpio_table); + gpiod_add_lookup_table(&spitz_spi_gpio_table); pxa2xx_set_spi_info(2, &spitz_spi_info); spi_register_board_info(ARRAY_AND_SIZE(spitz_spi_devices)); } diff --git a/arch/arm/mach-pxa/stargate2.c b/arch/arm/mach-pxa/stargate2.c index 8ca02ec1d44c..b43e2f4536a5 100644 --- a/arch/arm/mach-pxa/stargate2.c +++ b/arch/arm/mach-pxa/stargate2.c @@ -346,6 +346,22 @@ static struct pxa2xx_spi_controller pxa_ssp_master_2_info = { .num_chipselect = 1, }; +static struct gpiod_lookup_table pxa_ssp1_gpio_table = { + .dev_id = "pxa2xx-spi.1", + .table = { + GPIO_LOOKUP_IDX("gpio-pxa", 24, "cs", 0, GPIO_ACTIVE_LOW), + { }, + }, +}; + +static struct gpiod_lookup_table pxa_ssp3_gpio_table = { + .dev_id = "pxa2xx-spi.3", + .table = { + GPIO_LOOKUP_IDX("gpio-pxa", 39, "cs", 0, GPIO_ACTIVE_LOW), + { }, + }, +}; + /* An upcoming kernel change will scrap SFRM usage so these * drivers have been moved to use GPIOs */ static struct pxa2xx_spi_chip staccel_chip_info = { @@ -353,7 +369,6 @@ static struct pxa2xx_spi_chip staccel_chip_info = { .rx_threshold = 8, .dma_burst_size = 8, .timeout = 235, - .gpio_cs = 24, }; static struct pxa2xx_spi_chip cc2420_info = { @@ -361,7 +376,6 @@ static struct pxa2xx_spi_chip cc2420_info = { .rx_threshold = 8, .dma_burst_size = 8, .timeout = 235, - .gpio_cs = 39, }; static struct spi_board_info spi_board_info[] __initdata = { @@ -410,6 +424,8 @@ static void __init imote2_stargate2_init(void) pxa_set_btuart_info(NULL); pxa_set_stuart_info(NULL); + gpiod_add_lookup_table(&pxa_ssp1_gpio_table); + gpiod_add_lookup_table(&pxa_ssp3_gpio_table); pxa2xx_set_spi_info(1, &pxa_ssp_master_0_info); pxa2xx_set_spi_info(2, &pxa_ssp_master_1_info); pxa2xx_set_spi_info(3, &pxa_ssp_master_2_info); diff --git a/arch/arm/mach-pxa/z2.c b/arch/arm/mach-pxa/z2.c index 8e74fbb0a96e..7eaeda269927 100644 --- a/arch/arm/mach-pxa/z2.c +++ b/arch/arm/mach-pxa/z2.c @@ -570,7 +570,6 @@ static struct pxa2xx_spi_chip z2_lbs_chip_info = { .rx_threshold = 8, .tx_threshold = 8, .timeout = 1000, - .gpio_cs = GPIO24_ZIPITZ2_WIFI_CS, }; static struct libertas_spi_platform_data z2_lbs_pdata = { @@ -584,7 +583,6 @@ static struct pxa2xx_spi_chip lms283_chip_info = { .rx_threshold = 1, .tx_threshold = 1, .timeout = 64, - .gpio_cs = GPIO88_ZIPITZ2_LCD_CS, }; static struct gpiod_lookup_table lms283_gpio_table = { @@ -624,8 +622,26 @@ static struct pxa2xx_spi_controller pxa_ssp2_master_info = { .num_chipselect = 1, }; +static struct gpiod_lookup_table pxa_ssp1_gpio_table = { + .dev_id = "pxa2xx-spi.1", + .table = { + GPIO_LOOKUP_IDX("gpio-pxa", GPIO24_ZIPITZ2_WIFI_CS, "cs", 0, GPIO_ACTIVE_LOW), + { }, + }, +}; + +static struct gpiod_lookup_table pxa_ssp2_gpio_table = { + .dev_id = "pxa2xx-spi.2", + .table = { + GPIO_LOOKUP_IDX("gpio-pxa", GPIO88_ZIPITZ2_LCD_CS, "cs", 0, GPIO_ACTIVE_LOW), + { }, + }, +}; + static void __init z2_spi_init(void) { + gpiod_add_lookup_table(&pxa_ssp1_gpio_table); + gpiod_add_lookup_table(&pxa_ssp2_gpio_table); pxa2xx_set_spi_info(1, &pxa_ssp1_master_info); pxa2xx_set_spi_info(2, &pxa_ssp2_master_info); gpiod_add_lookup_table(&lms283_gpio_table); diff --git a/drivers/spi/spi-pxa2xx.c b/drivers/spi/spi-pxa2xx.c index e88f86274eeb..abb9f0ffd377 100644 --- a/drivers/spi/spi-pxa2xx.c +++ b/drivers/spi/spi-pxa2xx.c @@ -13,7 +13,6 @@ #include #include #include -#include #include #include #include @@ -1163,57 +1162,6 @@ static int pxa2xx_spi_unprepare_transfer(struct spi_controller *controller) return 0; } -static void cleanup_cs(struct spi_device *spi) -{ - if (!gpio_is_valid(spi->cs_gpio)) - return; - - gpio_free(spi->cs_gpio); - spi->cs_gpio = -ENOENT; -} - -static int setup_cs(struct spi_device *spi, struct chip_data *chip, - struct pxa2xx_spi_chip *chip_info) -{ - struct driver_data *drv_data = spi_controller_get_devdata(spi->controller); - - if (chip == NULL) - return 0; - - if (chip_info == NULL) - return 0; - - if (drv_data->ssp_type == CE4100_SSP) - return 0; - - /* - * NOTE: setup() can be called multiple times, possibly with - * different chip_info, release previously requested GPIO. - */ - cleanup_cs(spi); - - if (gpio_is_valid(chip_info->gpio_cs)) { - int gpio = chip_info->gpio_cs; - int err; - - err = gpio_request(gpio, "SPI_CS"); - if (err) { - dev_err(&spi->dev, "failed to request chip select GPIO%d\n", gpio); - return err; - } - - err = gpio_direction_output(gpio, !(spi->mode & SPI_CS_HIGH)); - if (err) { - gpio_free(gpio); - return err; - } - - spi->cs_gpio = gpio; - } - - return 0; -} - static int setup(struct spi_device *spi) { struct pxa2xx_spi_chip *chip_info; @@ -1222,7 +1170,6 @@ static int setup(struct spi_device *spi) struct driver_data *drv_data = spi_controller_get_devdata(spi->controller); uint tx_thres, tx_hi_thres, rx_thres; - int err; switch (drv_data->ssp_type) { case QUARK_X1000_SSP: @@ -1365,21 +1312,13 @@ static int setup(struct spi_device *spi) spi_set_ctldata(spi, chip); - if (drv_data->ssp_type == CE4100_SSP) - return 0; - - err = setup_cs(spi, chip, chip_info); - if (err) - kfree(chip); - - return err; + return 0; } static void cleanup(struct spi_device *spi) { struct chip_data *chip = spi_get_ctldata(spi); - cleanup_cs(spi); kfree(chip); } diff --git a/include/linux/spi/pxa2xx_spi.h b/include/linux/spi/pxa2xx_spi.h index ca74dce36706..4658e7801b42 100644 --- a/include/linux/spi/pxa2xx_spi.h +++ b/include/linux/spi/pxa2xx_spi.h @@ -42,7 +42,6 @@ struct pxa2xx_spi_chip { u8 rx_threshold; u8 dma_burst_size; u32 timeout; - int gpio_cs; }; #if defined(CONFIG_ARCH_PXA) || defined(CONFIG_ARCH_MMP) -- cgit v1.2.3 From 1a5a87d541b442293dfcc2253b652bc7b7e02d09 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Sat, 22 Jan 2022 01:33:02 +0100 Subject: spi: mt65xx: Convert to GPIO descriptors The MT65xx driver was already relying on the core to get some GPIO line numbers so it can be (hopefully) trivially converted to use descriptors instead. Cc: Dafna Hirschfeld Cc: Mason Zhang Cc: Guenter Roeck Cc: Peter Hess Cc: Leilk Liu Signed-off-by: Linus Walleij Link: https://lore.kernel.org/r/20220122003302.374304-1-linus.walleij@linaro.org Signed-off-by: Mark Brown --- drivers/spi/spi-mt65xx.c | 23 ++++++----------------- 1 file changed, 6 insertions(+), 17 deletions(-) diff --git a/drivers/spi/spi-mt65xx.c b/drivers/spi/spi-mt65xx.c index a15de10ee286..4f49b2e93ca7 100644 --- a/drivers/spi/spi-mt65xx.c +++ b/drivers/spi/spi-mt65xx.c @@ -12,7 +12,7 @@ #include #include #include -#include +#include #include #include #include @@ -605,8 +605,9 @@ static int mtk_spi_setup(struct spi_device *spi) if (!spi->controller_data) spi->controller_data = (void *)&mtk_default_chip_info; - if (mdata->dev_comp->need_pad_sel && gpio_is_valid(spi->cs_gpio)) - gpio_direction_output(spi->cs_gpio, !(spi->mode & SPI_CS_HIGH)); + if (mdata->dev_comp->need_pad_sel && spi->cs_gpiod) + /* CS de-asserted, gpiolib will handle inversion */ + gpiod_direction_output(spi->cs_gpiod, 0); return 0; } @@ -730,6 +731,7 @@ static int mtk_spi_probe(struct platform_device *pdev) master->can_dma = mtk_spi_can_dma; master->setup = mtk_spi_setup; master->set_cs_timing = mtk_spi_set_hw_cs_timing; + master->use_gpio_descriptors = true; of_id = of_match_node(mtk_spi_of_match, pdev->dev.of_node); if (!of_id) { @@ -853,25 +855,12 @@ static int mtk_spi_probe(struct platform_device *pdev) goto err_disable_runtime_pm; } - if (!master->cs_gpios && master->num_chipselect > 1) { + if (!master->cs_gpiods && master->num_chipselect > 1) { dev_err(&pdev->dev, "cs_gpios not specified and num_chipselect > 1\n"); ret = -EINVAL; goto err_disable_runtime_pm; } - - if (master->cs_gpios) { - for (i = 0; i < master->num_chipselect; i++) { - ret = devm_gpio_request(&pdev->dev, - master->cs_gpios[i], - dev_name(&pdev->dev)); - if (ret) { - dev_err(&pdev->dev, - "can't get CS GPIO %i\n", i); - goto err_disable_runtime_pm; - } - } - } } if (mdata->dev_comp->dma_ext) -- cgit v1.2.3 From 2818824ced4be5abc22c450340d548702f166d9a Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Thu, 20 Jan 2022 01:26:00 +0100 Subject: spi: mpc512x-psc: Convert to use GPIO descriptors MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This driver is already relying on the core to provide valid GPIO numbers in spi->cs_gpio through of_spi_get_gpio_numbers(), so we can switch to letting the core use GPIO descriptors instead. The driver was assigning a local function to the custom chipselect callback, but I chose to just open code the gpiod setting instead, this is easier to read. The only platform that overrides the cs_control callback is the mpc832x_rdb. Cc: Uwe Kleine-König Cc: Anatolij Gustschin Cc: linuxppc-dev@lists.ozlabs.org Signed-off-by: Linus Walleij Link: https://lore.kernel.org/r/20220120002600.216667-1-linus.walleij@linaro.org Signed-off-by: Mark Brown --- drivers/spi/spi-mpc512x-psc.c | 46 +++++++++++++++++-------------------------- 1 file changed, 18 insertions(+), 28 deletions(-) diff --git a/drivers/spi/spi-mpc512x-psc.c b/drivers/spi/spi-mpc512x-psc.c index 78a9bca8cc68..8a488d8e4c1b 100644 --- a/drivers/spi/spi-mpc512x-psc.c +++ b/drivers/spi/spi-mpc512x-psc.c @@ -23,7 +23,6 @@ #include #include #include -#include #include enum { @@ -128,17 +127,28 @@ static void mpc512x_psc_spi_activate_cs(struct spi_device *spi) out_be32(psc_addr(mps, ccr), ccr); mps->bits_per_word = cs->bits_per_word; - if (mps->cs_control && gpio_is_valid(spi->cs_gpio)) - mps->cs_control(spi, (spi->mode & SPI_CS_HIGH) ? 1 : 0); + if (cs->gpiod) { + if (mps->cs_control) + /* boardfile override */ + mps->cs_control(spi, (spi->mode & SPI_CS_HIGH) ? 1 : 0); + else + /* gpiolib will deal with the inversion */ + gpiod_set_value(spi->cs_gpiod, 1); + } } static void mpc512x_psc_spi_deactivate_cs(struct spi_device *spi) { struct mpc512x_psc_spi *mps = spi_master_get_devdata(spi->master); - if (mps->cs_control && gpio_is_valid(spi->cs_gpio)) - mps->cs_control(spi, (spi->mode & SPI_CS_HIGH) ? 0 : 1); - + if (spi->cs_gpiod) { + if (mps->cs_control) + /* boardfile override */ + mps->cs_control(spi, (spi->mode & SPI_CS_HIGH) ? 0 : 1); + else + /* gpiolib will deal with the inversion */ + gpiod_set_value(spi->cs_gpiod, 0); + } } /* extract and scale size field in txsz or rxsz */ @@ -373,18 +383,6 @@ static int mpc512x_psc_spi_setup(struct spi_device *spi) if (!cs) return -ENOMEM; - if (gpio_is_valid(spi->cs_gpio)) { - ret = gpio_request(spi->cs_gpio, dev_name(&spi->dev)); - if (ret) { - dev_err(&spi->dev, "can't get CS gpio: %d\n", - ret); - kfree(cs); - return ret; - } - gpio_direction_output(spi->cs_gpio, - spi->mode & SPI_CS_HIGH ? 0 : 1); - } - spi->controller_state = cs; } @@ -396,8 +394,6 @@ static int mpc512x_psc_spi_setup(struct spi_device *spi) static void mpc512x_psc_spi_cleanup(struct spi_device *spi) { - if (gpio_is_valid(spi->cs_gpio)) - gpio_free(spi->cs_gpio); kfree(spi->controller_state); } @@ -476,11 +472,6 @@ static irqreturn_t mpc512x_psc_spi_isr(int irq, void *dev_id) return IRQ_NONE; } -static void mpc512x_spi_cs_control(struct spi_device *spi, bool onoff) -{ - gpio_set_value(spi->cs_gpio, onoff); -} - static int mpc512x_psc_spi_do_probe(struct device *dev, u32 regaddr, u32 size, unsigned int irq) { @@ -500,9 +491,7 @@ static int mpc512x_psc_spi_do_probe(struct device *dev, u32 regaddr, mps->type = (int)of_device_get_match_data(dev); mps->irq = irq; - if (pdata == NULL) { - mps->cs_control = mpc512x_spi_cs_control; - } else { + if (pdata) { mps->cs_control = pdata->cs_control; master->bus_num = pdata->bus_num; master->num_chipselect = pdata->max_chipselect; @@ -513,6 +502,7 @@ static int mpc512x_psc_spi_do_probe(struct device *dev, u32 regaddr, master->prepare_transfer_hardware = mpc512x_psc_spi_prep_xfer_hw; master->transfer_one_message = mpc512x_psc_spi_msg_xfer; master->unprepare_transfer_hardware = mpc512x_psc_spi_unprep_xfer_hw; + master->use_gpio_descriptors = true; master->cleanup = mpc512x_psc_spi_cleanup; master->dev.of_node = dev->of_node; -- cgit v1.2.3 From 99407f11b5657cd66625c6b55a73d38b67803a8c Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Sat, 22 Jan 2022 01:48:46 +0100 Subject: spi: pic32: Convert to use GPIO descriptors The driver already relies on the core looking up GPIO lines from the core, so this is trivial to switch over to using GPIO descriptors. Cc: Purna Chandra Mandal Signed-off-by: Linus Walleij Link: https://lore.kernel.org/r/20220122004846.374930-1-linus.walleij@linaro.org Signed-off-by: Mark Brown --- drivers/spi/spi-pic32.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/spi/spi-pic32.c b/drivers/spi/spi-pic32.c index f86433b29260..7e5c09a7d489 100644 --- a/drivers/spi/spi-pic32.c +++ b/drivers/spi/spi-pic32.c @@ -591,18 +591,16 @@ static int pic32_spi_setup(struct spi_device *spi) * unreliable/erroneous SPI transactions. * To avoid that we will always handle /CS by toggling GPIO. */ - if (!gpio_is_valid(spi->cs_gpio)) + if (!spi->cs_gpiod) return -EINVAL; - gpio_direction_output(spi->cs_gpio, !(spi->mode & SPI_CS_HIGH)); - return 0; } static void pic32_spi_cleanup(struct spi_device *spi) { - /* de-activate cs-gpio */ - gpio_direction_output(spi->cs_gpio, !(spi->mode & SPI_CS_HIGH)); + /* de-activate cs-gpio, gpiolib will handle inversion */ + gpiod_direction_output(spi->cs_gpiod, 0); } static int pic32_spi_dma_prep(struct pic32_spi *pic32s, struct device *dev) @@ -784,6 +782,7 @@ static int pic32_spi_probe(struct platform_device *pdev) master->unprepare_message = pic32_spi_unprepare_message; master->prepare_transfer_hardware = pic32_spi_prepare_hardware; master->unprepare_transfer_hardware = pic32_spi_unprepare_hardware; + master->use_gpio_descriptors = true; /* optional DMA support */ ret = pic32_spi_dma_prep(pic32s, &pdev->dev); -- cgit v1.2.3 From 6938e02f8658734209fc1f68dc3a6cd355f4f737 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=83=AD=E5=8A=9B=E8=B1=AA?= Date: Fri, 28 Jan 2022 22:47:41 +0800 Subject: spi: sp7201: Fix compiler warnings Fix compiler warming for kernel test Fixes: f62ca4e2a863 ("spi: Add spi driver for Sunplus SP7021") Signed-off-by: Li-hao Kuo Link: https://lore.kernel.org/r/CAGcXWkzM6wbhNFLbYoijq7iS_76nYVod1ySFEDu-BRgnBokEQA@mail.gmail.com Signed-off-by: Mark Brown --- drivers/spi/spi-sunplus-sp7021.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/spi/spi-sunplus-sp7021.c b/drivers/spi/spi-sunplus-sp7021.c index cbbb1664017e..e5bdeb3eba45 100644 --- a/drivers/spi/spi-sunplus-sp7021.c +++ b/drivers/spi/spi-sunplus-sp7021.c @@ -124,7 +124,7 @@ static int sp7021_spi_slave_abort(struct spi_controller *ctlr) return 0; } -int sp7021_spi_slave_tx(struct spi_device *spi, struct spi_transfer *xfer) +static int sp7021_spi_slave_tx(struct spi_device *spi, struct spi_transfer *xfer) { struct sp7021_spi_ctlr *pspim = spi_controller_get_devdata(spi->controller); @@ -142,7 +142,7 @@ int sp7021_spi_slave_tx(struct spi_device *spi, struct spi_transfer *xfer) return 0; } -int sp7021_spi_slave_rx(struct spi_device *spi, struct spi_transfer *xfer) +static int sp7021_spi_slave_rx(struct spi_device *spi, struct spi_transfer *xfer) { struct sp7021_spi_ctlr *pspim = spi_controller_get_devdata(spi->controller); int ret = 0; @@ -160,7 +160,7 @@ int sp7021_spi_slave_rx(struct spi_device *spi, struct spi_transfer *xfer) return ret; } -void sp7021_spi_master_rb(struct sp7021_spi_ctlr *pspim, unsigned int len) +static void sp7021_spi_master_rb(struct sp7021_spi_ctlr *pspim, unsigned int len) { int i; @@ -171,7 +171,7 @@ void sp7021_spi_master_rb(struct sp7021_spi_ctlr *pspim, unsigned int len) } } -void sp7021_spi_master_wb(struct sp7021_spi_ctlr *pspim, unsigned int len) +static void sp7021_spi_master_wb(struct sp7021_spi_ctlr *pspim, unsigned int len) { int i; @@ -558,6 +558,7 @@ static int __maybe_unused sp7021_spi_controller_resume(struct device *dev) return clk_prepare_enable(pspim->spi_clk); } +#ifdef CONFIG_PM static int sp7021_spi_runtime_suspend(struct device *dev) { struct spi_controller *ctlr = dev_get_drvdata(dev); @@ -573,6 +574,7 @@ static int sp7021_spi_runtime_resume(struct device *dev) return reset_control_deassert(pspim->rstc); } +#endif static const struct dev_pm_ops sp7021_spi_pm_ops = { SET_RUNTIME_PM_OPS(sp7021_spi_runtime_suspend, -- cgit v1.2.3 From 321599693213c81b2ce8530abb27e39528e969f9 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Tue, 1 Feb 2022 02:26:54 +0100 Subject: spi: st-ssc4: Covert to use GPIO descriptors This switches the ST SSC SPI controller to use GPIO descriptors from the core instead of GPIO numbers. It is already using the core parsing of GPIO numbers so the switch is pretty straight-forward. Cc: Lee Jones Signed-off-by: Linus Walleij Link: https://lore.kernel.org/r/20220201012654.562578-1-linus.walleij@linaro.org Signed-off-by: Mark Brown --- drivers/spi/spi-st-ssc4.c | 31 ++++--------------------------- 1 file changed, 4 insertions(+), 27 deletions(-) diff --git a/drivers/spi/spi-st-ssc4.c b/drivers/spi/spi-st-ssc4.c index 6c44dda9ee8c..843be803696b 100644 --- a/drivers/spi/spi-st-ssc4.c +++ b/drivers/spi/spi-st-ssc4.c @@ -17,7 +17,6 @@ #include #include #include -#include #include #include #include @@ -171,11 +170,6 @@ static int spi_st_transfer_one(struct spi_master *master, return t->len; } -static void spi_st_cleanup(struct spi_device *spi) -{ - gpio_free(spi->cs_gpio); -} - /* the spi->mode bits understood by this driver: */ #define MODEBITS (SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST | SPI_LOOP | SPI_CS_HIGH) static int spi_st_setup(struct spi_device *spi) @@ -183,29 +177,17 @@ static int spi_st_setup(struct spi_device *spi) struct spi_st *spi_st = spi_master_get_devdata(spi->master); u32 spi_st_clk, sscbrg, var; u32 hz = spi->max_speed_hz; - int cs = spi->cs_gpio; - int ret; if (!hz) { dev_err(&spi->dev, "max_speed_hz unspecified\n"); return -EINVAL; } - if (!gpio_is_valid(cs)) { - dev_err(&spi->dev, "%d is not a valid gpio\n", cs); + if (!spi->cs_gpiod) { + dev_err(&spi->dev, "no valid gpio assigned\n"); return -EINVAL; } - ret = gpio_request(cs, dev_name(&spi->dev)); - if (ret) { - dev_err(&spi->dev, "could not request gpio:%d\n", cs); - return ret; - } - - ret = gpio_direction_output(cs, spi->mode & SPI_CS_HIGH); - if (ret) - goto out_free_gpio; - spi_st_clk = clk_get_rate(spi_st->clk); /* Set SSC_BRF */ @@ -213,8 +195,7 @@ static int spi_st_setup(struct spi_device *spi) if (sscbrg < 0x07 || sscbrg > BIT(16)) { dev_err(&spi->dev, "baudrate %d outside valid range %d\n", sscbrg, hz); - ret = -EINVAL; - goto out_free_gpio; + return -EINVAL; } spi_st->baud = spi_st_clk / (2 * sscbrg); @@ -263,10 +244,6 @@ static int spi_st_setup(struct spi_device *spi) readl_relaxed(spi_st->base + SSC_RBUF); return 0; - -out_free_gpio: - gpio_free(cs); - return ret; } /* Interrupt fired when TX shift register becomes empty */ @@ -309,11 +286,11 @@ static int spi_st_probe(struct platform_device *pdev) master->dev.of_node = np; master->mode_bits = MODEBITS; master->setup = spi_st_setup; - master->cleanup = spi_st_cleanup; master->transfer_one = spi_st_transfer_one; master->bits_per_word_mask = SPI_BPW_MASK(8) | SPI_BPW_MASK(16); master->auto_runtime_pm = true; master->bus_num = pdev->id; + master->use_gpio_descriptors = true; spi_st = spi_master_get_devdata(master); spi_st->clk = devm_clk_get(&pdev->dev, "ssc"); -- cgit v1.2.3 From b651d1da86aa525c5a5b2bd61f528353c28d589d Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Tue, 1 Feb 2022 02:29:56 +0100 Subject: spi: bcm2835aux: Convert to use GPIO descriptors This one is pretty straight forward to switch over, the driver already relies on inspecting cs_gpio just check cs_gpiod instead and stop the special handling of requesting the GPIO and stuff the core will take care of. Cc: Lukas Wunner Cc: Martin Sperl Signed-off-by: Linus Walleij Link: https://lore.kernel.org/r/20220201012956.563272-1-linus.walleij@linaro.org Signed-off-by: Mark Brown --- drivers/spi/spi-bcm2835aux.c | 21 ++++----------------- 1 file changed, 4 insertions(+), 17 deletions(-) diff --git a/drivers/spi/spi-bcm2835aux.c b/drivers/spi/spi-bcm2835aux.c index 7d709a8c833b..e28521922330 100644 --- a/drivers/spi/spi-bcm2835aux.c +++ b/drivers/spi/spi-bcm2835aux.c @@ -22,7 +22,6 @@ #include #include #include -#include #include #include #include @@ -445,25 +444,12 @@ static void bcm2835aux_spi_handle_err(struct spi_master *master, static int bcm2835aux_spi_setup(struct spi_device *spi) { - int ret; - /* sanity check for native cs */ if (spi->mode & SPI_NO_CS) return 0; - if (gpio_is_valid(spi->cs_gpio)) { - /* with gpio-cs set the GPIO to the correct level - * and as output (in case the dt has the gpio not configured - * as output but native cs) - */ - ret = gpio_direction_output(spi->cs_gpio, - (spi->mode & SPI_CS_HIGH) ? 0 : 1); - if (ret) - dev_err(&spi->dev, - "could not set gpio %i as output: %i\n", - spi->cs_gpio, ret); - - return ret; - } + + if (spi->cs_gpiod) + return 0; /* for dt-backwards compatibility: only support native on CS0 * known things not supported with broken native CS: @@ -519,6 +505,7 @@ static int bcm2835aux_spi_probe(struct platform_device *pdev) master->prepare_message = bcm2835aux_spi_prepare_message; master->unprepare_message = bcm2835aux_spi_unprepare_message; master->dev.of_node = pdev->dev.of_node; + master->use_gpio_descriptors = true; bs = spi_master_get_devdata(master); -- cgit v1.2.3 From 941bffd7d7f5d6030a54184c5d81b0eb9116ca9a Mon Sep 17 00:00:00 2001 From: Stefan Binding Date: Fri, 21 Jan 2022 17:24:23 +0000 Subject: spi: Make spi_alloc_device and spi_add_device public again This functions were previously made private since they were not used. However, these functions will be needed again. Partial revert of commit da21fde0fdb3 ("spi: Make several public functions private to spi.c") Signed-off-by: Stefan Binding Reviewed-by: Hans de Goede Link: https://lore.kernel.org/r/20220121172431.6876-2-sbinding@opensource.cirrus.com Signed-off-by: Mark Brown --- drivers/spi/spi.c | 6 ++++-- include/linux/spi/spi.h | 12 ++++++++++++ 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index 4599b121d744..1eb84101c4ad 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -532,7 +532,7 @@ static DEFINE_MUTEX(board_lock); * * Return: a pointer to the new device, or NULL. */ -static struct spi_device *spi_alloc_device(struct spi_controller *ctlr) +struct spi_device *spi_alloc_device(struct spi_controller *ctlr) { struct spi_device *spi; @@ -557,6 +557,7 @@ static struct spi_device *spi_alloc_device(struct spi_controller *ctlr) device_initialize(&spi->dev); return spi; } +EXPORT_SYMBOL_GPL(spi_alloc_device); static void spi_dev_set_name(struct spi_device *spi) { @@ -652,7 +653,7 @@ static int __spi_add_device(struct spi_device *spi) * * Return: 0 on success; negative errno on failure */ -static int spi_add_device(struct spi_device *spi) +int spi_add_device(struct spi_device *spi) { struct spi_controller *ctlr = spi->controller; struct device *dev = ctlr->dev.parent; @@ -673,6 +674,7 @@ static int spi_add_device(struct spi_device *spi) mutex_unlock(&ctlr->add_lock); return status; } +EXPORT_SYMBOL_GPL(spi_add_device); static int spi_add_device_locked(struct spi_device *spi) { diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h index 7ab3fed7b804..0346a3ff27fd 100644 --- a/include/linux/spi/spi.h +++ b/include/linux/spi/spi.h @@ -1452,7 +1452,19 @@ spi_register_board_info(struct spi_board_info const *info, unsigned n) * use spi_new_device() to describe each device. You can also call * spi_unregister_device() to start making that device vanish, but * normally that would be handled by spi_unregister_controller(). + * + * You can also use spi_alloc_device() and spi_add_device() to use a two + * stage registration sequence for each spi_device. This gives the caller + * some more control over the spi_device structure before it is registered, + * but requires that caller to initialize fields that would otherwise + * be defined using the board info. */ +extern struct spi_device * +spi_alloc_device(struct spi_controller *ctlr); + +extern int +spi_add_device(struct spi_device *spi); + extern struct spi_device * spi_new_device(struct spi_controller *, struct spi_board_info *); -- cgit v1.2.3 From 70dd264bc07aee4f89e65138db11e908701388dd Mon Sep 17 00:00:00 2001 From: Stefan Binding Date: Fri, 21 Jan 2022 17:24:24 +0000 Subject: spi: Create helper API to lookup ACPI info for spi device This can then be used to find a spi resource inside an ACPI node, and allocate a spi device. Signed-off-by: Stefan Binding Reviewed-by: Hans de Goede Link: https://lore.kernel.org/r/20220121172431.6876-3-sbinding@opensource.cirrus.com Signed-off-by: Mark Brown --- drivers/spi/spi.c | 46 ++++++++++++++++++++++++++++++++++++---------- include/linux/spi/spi.h | 6 ++++++ 2 files changed, 42 insertions(+), 10 deletions(-) diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index 1eb84101c4ad..13f4701f0694 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -2410,8 +2410,18 @@ static int acpi_spi_add_resource(struct acpi_resource *ares, void *data) return 1; } -static acpi_status acpi_register_spi_device(struct spi_controller *ctlr, - struct acpi_device *adev) +/** + * acpi_spi_device_alloc - Allocate a spi device, and fill it in with ACPI information + * @ctlr: controller to which the spi device belongs + * @adev: ACPI Device for the spi device + * + * This should be used to allocate a new spi device from and ACPI Node. + * The caller is responsible for calling spi_add_device to register the spi device. + * + * Return: a pointer to the new device, or ERR_PTR on error. + */ +struct spi_device *acpi_spi_device_alloc(struct spi_controller *ctlr, + struct acpi_device *adev) { acpi_handle parent_handle = NULL; struct list_head resource_list; @@ -2419,10 +2429,6 @@ static acpi_status acpi_register_spi_device(struct spi_controller *ctlr, struct spi_device *spi; int ret; - if (acpi_bus_get_status(adev) || !adev->status.present || - acpi_device_enumerated(adev)) - return AE_OK; - lookup.ctlr = ctlr; lookup.irq = -1; @@ -2433,7 +2439,7 @@ static acpi_status acpi_register_spi_device(struct spi_controller *ctlr, if (ret < 0) /* found SPI in _CRS but it points to another controller */ - return AE_OK; + return ERR_PTR(-ENODEV); if (!lookup.max_speed_hz && ACPI_SUCCESS(acpi_get_parent(adev->handle, &parent_handle)) && @@ -2443,16 +2449,15 @@ static acpi_status acpi_register_spi_device(struct spi_controller *ctlr, } if (!lookup.max_speed_hz) - return AE_OK; + return ERR_PTR(-ENODEV); spi = spi_alloc_device(ctlr); if (!spi) { dev_err(&ctlr->dev, "failed to allocate SPI device for %s\n", dev_name(&adev->dev)); - return AE_NO_MEMORY; + return ERR_PTR(-ENOMEM); } - ACPI_COMPANION_SET(&spi->dev, adev); spi->max_speed_hz = lookup.max_speed_hz; spi->mode |= lookup.mode; @@ -2460,6 +2465,27 @@ static acpi_status acpi_register_spi_device(struct spi_controller *ctlr, spi->bits_per_word = lookup.bits_per_word; spi->chip_select = lookup.chip_select; + return spi; +} +EXPORT_SYMBOL_GPL(acpi_spi_device_alloc); + +static acpi_status acpi_register_spi_device(struct spi_controller *ctlr, + struct acpi_device *adev) +{ + struct spi_device *spi; + + if (acpi_bus_get_status(adev) || !adev->status.present || + acpi_device_enumerated(adev)) + return AE_OK; + + spi = acpi_spi_device_alloc(ctlr, adev); + if (IS_ERR(spi)) { + if (PTR_ERR(spi) == -ENOMEM) + return AE_NO_MEMORY; + else + return AE_OK; + } + acpi_set_modalias(adev, acpi_device_hid(adev), spi->modalias, sizeof(spi->modalias)); diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h index 0346a3ff27fd..d159cef12f1a 100644 --- a/include/linux/spi/spi.h +++ b/include/linux/spi/spi.h @@ -16,6 +16,7 @@ #include #include +#include struct dma_chan; struct software_node; @@ -759,6 +760,11 @@ extern int devm_spi_register_controller(struct device *dev, struct spi_controller *ctlr); extern void spi_unregister_controller(struct spi_controller *ctlr); +#if IS_ENABLED(CONFIG_ACPI) +extern struct spi_device *acpi_spi_device_alloc(struct spi_controller *ctlr, + struct acpi_device *adev); +#endif + /* * SPI resource management while processing a SPI message */ -- cgit v1.2.3 From 92640f98a78c6a3ea1ca32143144241eceb129bd Mon Sep 17 00:00:00 2001 From: Stefan Binding Date: Fri, 21 Jan 2022 17:24:25 +0000 Subject: spi: Support selection of the index of the ACPI Spi Resource before alloc If a node contains more than one SPI resource it may be necessary to use an index to select which one you want to allocate a spi device for. Signed-off-by: Stefan Binding Reviewed-by: Hans de Goede Link: https://lore.kernel.org/r/20220121172431.6876-4-sbinding@opensource.cirrus.com Signed-off-by: Mark Brown --- drivers/spi/spi.c | 51 ++++++++++++++++++++++++++++++++++++++++++------- include/linux/spi/spi.h | 3 ++- 2 files changed, 46 insertions(+), 8 deletions(-) diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index 13f4701f0694..06c0a308b38b 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -2320,6 +2320,8 @@ struct acpi_spi_lookup { int irq; u8 bits_per_word; u8 chip_select; + int n; + int index; }; static void acpi_spi_parse_apple_properties(struct acpi_device *dev, @@ -2351,6 +2353,8 @@ static void acpi_spi_parse_apple_properties(struct acpi_device *dev, lookup->mode |= SPI_CPHA; } +static struct spi_controller *acpi_spi_find_controller_by_adev(struct acpi_device *adev); + static int acpi_spi_add_resource(struct acpi_resource *ares, void *data) { struct acpi_spi_lookup *lookup = data; @@ -2364,14 +2368,35 @@ static int acpi_spi_add_resource(struct acpi_resource *ares, void *data) sb = &ares->data.spi_serial_bus; if (sb->type == ACPI_RESOURCE_SERIAL_TYPE_SPI) { + if (lookup->index != -1 && lookup->n++ != lookup->index) + return 1; + + if (lookup->index == -1 && !ctlr) + return -ENODEV; + status = acpi_get_handle(NULL, sb->resource_source.string_ptr, &parent_handle); - if (ACPI_FAILURE(status) || - ACPI_HANDLE(ctlr->dev.parent) != parent_handle) + if (ACPI_FAILURE(status)) return -ENODEV; + if (ctlr) { + if (ACPI_HANDLE(ctlr->dev.parent) != parent_handle) + return -ENODEV; + } else { + struct acpi_device *adev; + + if (acpi_bus_get_device(parent_handle, &adev)) + return -ENODEV; + + ctlr = acpi_spi_find_controller_by_adev(adev); + if (!ctlr) + return -ENODEV; + + lookup->ctlr = ctlr; + } + /* * ACPI DeviceSelection numbering is handled by the * host controller driver in Windows and can vary @@ -2414,14 +2439,21 @@ static int acpi_spi_add_resource(struct acpi_resource *ares, void *data) * acpi_spi_device_alloc - Allocate a spi device, and fill it in with ACPI information * @ctlr: controller to which the spi device belongs * @adev: ACPI Device for the spi device + * @index: Index of the spi resource inside the ACPI Node * * This should be used to allocate a new spi device from and ACPI Node. * The caller is responsible for calling spi_add_device to register the spi device. * + * If ctlr is set to NULL, the Controller for the spi device will be looked up + * using the resource. + * If index is set to -1, index is not used. + * Note: If index is -1, ctlr must be set. + * * Return: a pointer to the new device, or ERR_PTR on error. */ struct spi_device *acpi_spi_device_alloc(struct spi_controller *ctlr, - struct acpi_device *adev) + struct acpi_device *adev, + int index) { acpi_handle parent_handle = NULL; struct list_head resource_list; @@ -2429,8 +2461,13 @@ struct spi_device *acpi_spi_device_alloc(struct spi_controller *ctlr, struct spi_device *spi; int ret; + if (!ctlr && index == -1) + return ERR_PTR(-EINVAL); + lookup.ctlr = ctlr; lookup.irq = -1; + lookup.index = index; + lookup.n = 0; INIT_LIST_HEAD(&resource_list); ret = acpi_dev_get_resources(adev, &resource_list, @@ -2443,7 +2480,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(ctlr->dev.parent) == parent_handle) { + 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); } @@ -2451,9 +2488,9 @@ struct spi_device *acpi_spi_device_alloc(struct spi_controller *ctlr, if (!lookup.max_speed_hz) return ERR_PTR(-ENODEV); - spi = spi_alloc_device(ctlr); + spi = spi_alloc_device(lookup.ctlr); if (!spi) { - dev_err(&ctlr->dev, "failed to allocate SPI device for %s\n", + dev_err(&lookup.ctlr->dev, "failed to allocate SPI device for %s\n", dev_name(&adev->dev)); return ERR_PTR(-ENOMEM); } @@ -2478,7 +2515,7 @@ static acpi_status acpi_register_spi_device(struct spi_controller *ctlr, acpi_device_enumerated(adev)) return AE_OK; - spi = acpi_spi_device_alloc(ctlr, adev); + spi = acpi_spi_device_alloc(ctlr, adev, -1); if (IS_ERR(spi)) { if (PTR_ERR(spi) == -ENOMEM) return AE_NO_MEMORY; diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h index d159cef12f1a..e5bbb9cbd3d7 100644 --- a/include/linux/spi/spi.h +++ b/include/linux/spi/spi.h @@ -762,7 +762,8 @@ extern void spi_unregister_controller(struct spi_controller *ctlr); #if IS_ENABLED(CONFIG_ACPI) extern struct spi_device *acpi_spi_device_alloc(struct spi_controller *ctlr, - struct acpi_device *adev); + struct acpi_device *adev, + int index); #endif /* -- cgit v1.2.3 From 113962301d2d9a5c11381d9c25ddea7af71be2ff Mon Sep 17 00:00:00 2001 From: Stefan Binding Date: Fri, 21 Jan 2022 17:24:26 +0000 Subject: spi: Add API to count spi acpi resources Some ACPI nodes may have more than one Spi Resource. To be able to handle these case, its necessary to have a way of counting these resources. Signed-off-by: Stefan Binding Reviewed-by: Hans de Goede Link: https://lore.kernel.org/r/20220121172431.6876-5-sbinding@opensource.cirrus.com Signed-off-by: Mark Brown --- drivers/spi/spi.c | 40 ++++++++++++++++++++++++++++++++++++++++ include/linux/spi/spi.h | 1 + 2 files changed, 41 insertions(+) diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index 06c0a308b38b..ec9f2ed579e3 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -2324,6 +2324,46 @@ struct acpi_spi_lookup { int index; }; +static int acpi_spi_count(struct acpi_resource *ares, void *data) +{ + struct acpi_resource_spi_serialbus *sb; + int *count = data; + + if (ares->type != ACPI_RESOURCE_TYPE_SERIAL_BUS) + return 1; + + sb = &ares->data.spi_serial_bus; + if (sb->type != ACPI_RESOURCE_SERIAL_TYPE_SPI) + return 1; + + *count = *count + 1; + + return 1; +} + +/** + * acpi_spi_count_resources - Count the number of SpiSerialBus resources + * @adev: ACPI device + * + * Returns the number of SpiSerialBus resources in the ACPI-device's + * resource-list; or a negative error code. + */ +int acpi_spi_count_resources(struct acpi_device *adev) +{ + LIST_HEAD(r); + int count = 0; + int ret; + + ret = acpi_dev_get_resources(adev, &r, acpi_spi_count, &count); + if (ret < 0) + return ret; + + acpi_dev_free_resource_list(&r); + + return count; +} +EXPORT_SYMBOL_GPL(acpi_spi_count_resources); + static void acpi_spi_parse_apple_properties(struct acpi_device *dev, struct acpi_spi_lookup *lookup) { diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h index e5bbb9cbd3d7..394b4241d989 100644 --- a/include/linux/spi/spi.h +++ b/include/linux/spi/spi.h @@ -764,6 +764,7 @@ extern void spi_unregister_controller(struct spi_controller *ctlr); extern struct spi_device *acpi_spi_device_alloc(struct spi_controller *ctlr, struct acpi_device *adev, int index); +int acpi_spi_count_resources(struct acpi_device *adev); #endif /* -- cgit v1.2.3 From e3dc1399506f894110667ee5c66a6a70f06f3348 Mon Sep 17 00:00:00 2001 From: Stefan Binding Date: Fri, 21 Jan 2022 17:24:23 +0000 Subject: spi: Make spi_alloc_device and spi_add_device public again This functions were previously made private since they were not used. However, these functions will be needed again. Partial revert of commit da21fde0fdb3 ("spi: Make several public functions private to spi.c") Signed-off-by: Stefan Binding Reviewed-by: Hans de Goede Link: https://lore.kernel.org/r/20220121172431.6876-2-sbinding@opensource.cirrus.com Signed-off-by: Mark Brown --- drivers/spi/spi.c | 6 ++++-- include/linux/spi/spi.h | 12 ++++++++++++ 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index 4599b121d744..1eb84101c4ad 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -532,7 +532,7 @@ static DEFINE_MUTEX(board_lock); * * Return: a pointer to the new device, or NULL. */ -static struct spi_device *spi_alloc_device(struct spi_controller *ctlr) +struct spi_device *spi_alloc_device(struct spi_controller *ctlr) { struct spi_device *spi; @@ -557,6 +557,7 @@ static struct spi_device *spi_alloc_device(struct spi_controller *ctlr) device_initialize(&spi->dev); return spi; } +EXPORT_SYMBOL_GPL(spi_alloc_device); static void spi_dev_set_name(struct spi_device *spi) { @@ -652,7 +653,7 @@ static int __spi_add_device(struct spi_device *spi) * * Return: 0 on success; negative errno on failure */ -static int spi_add_device(struct spi_device *spi) +int spi_add_device(struct spi_device *spi) { struct spi_controller *ctlr = spi->controller; struct device *dev = ctlr->dev.parent; @@ -673,6 +674,7 @@ static int spi_add_device(struct spi_device *spi) mutex_unlock(&ctlr->add_lock); return status; } +EXPORT_SYMBOL_GPL(spi_add_device); static int spi_add_device_locked(struct spi_device *spi) { diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h index 7ab3fed7b804..0346a3ff27fd 100644 --- a/include/linux/spi/spi.h +++ b/include/linux/spi/spi.h @@ -1452,7 +1452,19 @@ spi_register_board_info(struct spi_board_info const *info, unsigned n) * use spi_new_device() to describe each device. You can also call * spi_unregister_device() to start making that device vanish, but * normally that would be handled by spi_unregister_controller(). + * + * You can also use spi_alloc_device() and spi_add_device() to use a two + * stage registration sequence for each spi_device. This gives the caller + * some more control over the spi_device structure before it is registered, + * but requires that caller to initialize fields that would otherwise + * be defined using the board info. */ +extern struct spi_device * +spi_alloc_device(struct spi_controller *ctlr); + +extern int +spi_add_device(struct spi_device *spi); + extern struct spi_device * spi_new_device(struct spi_controller *, struct spi_board_info *); -- cgit v1.2.3 From 000bee0ed70af79e610444096fb453430220960f Mon Sep 17 00:00:00 2001 From: Stefan Binding Date: Fri, 21 Jan 2022 17:24:24 +0000 Subject: spi: Create helper API to lookup ACPI info for spi device This can then be used to find a spi resource inside an ACPI node, and allocate a spi device. Signed-off-by: Stefan Binding Reviewed-by: Hans de Goede Link: https://lore.kernel.org/r/20220121172431.6876-3-sbinding@opensource.cirrus.com Signed-off-by: Mark Brown --- drivers/spi/spi.c | 46 ++++++++++++++++++++++++++++++++++++---------- include/linux/spi/spi.h | 6 ++++++ 2 files changed, 42 insertions(+), 10 deletions(-) diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index 1eb84101c4ad..13f4701f0694 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -2410,8 +2410,18 @@ static int acpi_spi_add_resource(struct acpi_resource *ares, void *data) return 1; } -static acpi_status acpi_register_spi_device(struct spi_controller *ctlr, - struct acpi_device *adev) +/** + * acpi_spi_device_alloc - Allocate a spi device, and fill it in with ACPI information + * @ctlr: controller to which the spi device belongs + * @adev: ACPI Device for the spi device + * + * This should be used to allocate a new spi device from and ACPI Node. + * The caller is responsible for calling spi_add_device to register the spi device. + * + * Return: a pointer to the new device, or ERR_PTR on error. + */ +struct spi_device *acpi_spi_device_alloc(struct spi_controller *ctlr, + struct acpi_device *adev) { acpi_handle parent_handle = NULL; struct list_head resource_list; @@ -2419,10 +2429,6 @@ static acpi_status acpi_register_spi_device(struct spi_controller *ctlr, struct spi_device *spi; int ret; - if (acpi_bus_get_status(adev) || !adev->status.present || - acpi_device_enumerated(adev)) - return AE_OK; - lookup.ctlr = ctlr; lookup.irq = -1; @@ -2433,7 +2439,7 @@ static acpi_status acpi_register_spi_device(struct spi_controller *ctlr, if (ret < 0) /* found SPI in _CRS but it points to another controller */ - return AE_OK; + return ERR_PTR(-ENODEV); if (!lookup.max_speed_hz && ACPI_SUCCESS(acpi_get_parent(adev->handle, &parent_handle)) && @@ -2443,16 +2449,15 @@ static acpi_status acpi_register_spi_device(struct spi_controller *ctlr, } if (!lookup.max_speed_hz) - return AE_OK; + return ERR_PTR(-ENODEV); spi = spi_alloc_device(ctlr); if (!spi) { dev_err(&ctlr->dev, "failed to allocate SPI device for %s\n", dev_name(&adev->dev)); - return AE_NO_MEMORY; + return ERR_PTR(-ENOMEM); } - ACPI_COMPANION_SET(&spi->dev, adev); spi->max_speed_hz = lookup.max_speed_hz; spi->mode |= lookup.mode; @@ -2460,6 +2465,27 @@ static acpi_status acpi_register_spi_device(struct spi_controller *ctlr, spi->bits_per_word = lookup.bits_per_word; spi->chip_select = lookup.chip_select; + return spi; +} +EXPORT_SYMBOL_GPL(acpi_spi_device_alloc); + +static acpi_status acpi_register_spi_device(struct spi_controller *ctlr, + struct acpi_device *adev) +{ + struct spi_device *spi; + + if (acpi_bus_get_status(adev) || !adev->status.present || + acpi_device_enumerated(adev)) + return AE_OK; + + spi = acpi_spi_device_alloc(ctlr, adev); + if (IS_ERR(spi)) { + if (PTR_ERR(spi) == -ENOMEM) + return AE_NO_MEMORY; + else + return AE_OK; + } + acpi_set_modalias(adev, acpi_device_hid(adev), spi->modalias, sizeof(spi->modalias)); diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h index 0346a3ff27fd..d159cef12f1a 100644 --- a/include/linux/spi/spi.h +++ b/include/linux/spi/spi.h @@ -16,6 +16,7 @@ #include #include +#include struct dma_chan; struct software_node; @@ -759,6 +760,11 @@ extern int devm_spi_register_controller(struct device *dev, struct spi_controller *ctlr); extern void spi_unregister_controller(struct spi_controller *ctlr); +#if IS_ENABLED(CONFIG_ACPI) +extern struct spi_device *acpi_spi_device_alloc(struct spi_controller *ctlr, + struct acpi_device *adev); +#endif + /* * SPI resource management while processing a SPI message */ -- cgit v1.2.3 From 87e59b36e5e26122efd55d77adb9fac827987db0 Mon Sep 17 00:00:00 2001 From: Stefan Binding Date: Fri, 21 Jan 2022 17:24:25 +0000 Subject: spi: Support selection of the index of the ACPI Spi Resource before alloc If a node contains more than one SPI resource it may be necessary to use an index to select which one you want to allocate a spi device for. Signed-off-by: Stefan Binding Reviewed-by: Hans de Goede Link: https://lore.kernel.org/r/20220121172431.6876-4-sbinding@opensource.cirrus.com Signed-off-by: Mark Brown --- drivers/spi/spi.c | 51 ++++++++++++++++++++++++++++++++++++++++++------- include/linux/spi/spi.h | 3 ++- 2 files changed, 46 insertions(+), 8 deletions(-) diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index 13f4701f0694..06c0a308b38b 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -2320,6 +2320,8 @@ struct acpi_spi_lookup { int irq; u8 bits_per_word; u8 chip_select; + int n; + int index; }; static void acpi_spi_parse_apple_properties(struct acpi_device *dev, @@ -2351,6 +2353,8 @@ static void acpi_spi_parse_apple_properties(struct acpi_device *dev, lookup->mode |= SPI_CPHA; } +static struct spi_controller *acpi_spi_find_controller_by_adev(struct acpi_device *adev); + static int acpi_spi_add_resource(struct acpi_resource *ares, void *data) { struct acpi_spi_lookup *lookup = data; @@ -2364,14 +2368,35 @@ static int acpi_spi_add_resource(struct acpi_resource *ares, void *data) sb = &ares->data.spi_serial_bus; if (sb->type == ACPI_RESOURCE_SERIAL_TYPE_SPI) { + if (lookup->index != -1 && lookup->n++ != lookup->index) + return 1; + + if (lookup->index == -1 && !ctlr) + return -ENODEV; + status = acpi_get_handle(NULL, sb->resource_source.string_ptr, &parent_handle); - if (ACPI_FAILURE(status) || - ACPI_HANDLE(ctlr->dev.parent) != parent_handle) + if (ACPI_FAILURE(status)) return -ENODEV; + if (ctlr) { + if (ACPI_HANDLE(ctlr->dev.parent) != parent_handle) + return -ENODEV; + } else { + struct acpi_device *adev; + + if (acpi_bus_get_device(parent_handle, &adev)) + return -ENODEV; + + ctlr = acpi_spi_find_controller_by_adev(adev); + if (!ctlr) + return -ENODEV; + + lookup->ctlr = ctlr; + } + /* * ACPI DeviceSelection numbering is handled by the * host controller driver in Windows and can vary @@ -2414,14 +2439,21 @@ static int acpi_spi_add_resource(struct acpi_resource *ares, void *data) * acpi_spi_device_alloc - Allocate a spi device, and fill it in with ACPI information * @ctlr: controller to which the spi device belongs * @adev: ACPI Device for the spi device + * @index: Index of the spi resource inside the ACPI Node * * This should be used to allocate a new spi device from and ACPI Node. * The caller is responsible for calling spi_add_device to register the spi device. * + * If ctlr is set to NULL, the Controller for the spi device will be looked up + * using the resource. + * If index is set to -1, index is not used. + * Note: If index is -1, ctlr must be set. + * * Return: a pointer to the new device, or ERR_PTR on error. */ struct spi_device *acpi_spi_device_alloc(struct spi_controller *ctlr, - struct acpi_device *adev) + struct acpi_device *adev, + int index) { acpi_handle parent_handle = NULL; struct list_head resource_list; @@ -2429,8 +2461,13 @@ struct spi_device *acpi_spi_device_alloc(struct spi_controller *ctlr, struct spi_device *spi; int ret; + if (!ctlr && index == -1) + return ERR_PTR(-EINVAL); + lookup.ctlr = ctlr; lookup.irq = -1; + lookup.index = index; + lookup.n = 0; INIT_LIST_HEAD(&resource_list); ret = acpi_dev_get_resources(adev, &resource_list, @@ -2443,7 +2480,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(ctlr->dev.parent) == parent_handle) { + 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); } @@ -2451,9 +2488,9 @@ struct spi_device *acpi_spi_device_alloc(struct spi_controller *ctlr, if (!lookup.max_speed_hz) return ERR_PTR(-ENODEV); - spi = spi_alloc_device(ctlr); + spi = spi_alloc_device(lookup.ctlr); if (!spi) { - dev_err(&ctlr->dev, "failed to allocate SPI device for %s\n", + dev_err(&lookup.ctlr->dev, "failed to allocate SPI device for %s\n", dev_name(&adev->dev)); return ERR_PTR(-ENOMEM); } @@ -2478,7 +2515,7 @@ static acpi_status acpi_register_spi_device(struct spi_controller *ctlr, acpi_device_enumerated(adev)) return AE_OK; - spi = acpi_spi_device_alloc(ctlr, adev); + spi = acpi_spi_device_alloc(ctlr, adev, -1); if (IS_ERR(spi)) { if (PTR_ERR(spi) == -ENOMEM) return AE_NO_MEMORY; diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h index d159cef12f1a..e5bbb9cbd3d7 100644 --- a/include/linux/spi/spi.h +++ b/include/linux/spi/spi.h @@ -762,7 +762,8 @@ extern void spi_unregister_controller(struct spi_controller *ctlr); #if IS_ENABLED(CONFIG_ACPI) extern struct spi_device *acpi_spi_device_alloc(struct spi_controller *ctlr, - struct acpi_device *adev); + struct acpi_device *adev, + int index); #endif /* -- cgit v1.2.3 From e612af7acef2459f1afd885f4107748995a05963 Mon Sep 17 00:00:00 2001 From: Stefan Binding Date: Fri, 21 Jan 2022 17:24:26 +0000 Subject: spi: Add API to count spi acpi resources Some ACPI nodes may have more than one Spi Resource. To be able to handle these case, its necessary to have a way of counting these resources. Signed-off-by: Stefan Binding Reviewed-by: Hans de Goede Link: https://lore.kernel.org/r/20220121172431.6876-5-sbinding@opensource.cirrus.com Signed-off-by: Mark Brown --- drivers/spi/spi.c | 40 ++++++++++++++++++++++++++++++++++++++++ include/linux/spi/spi.h | 1 + 2 files changed, 41 insertions(+) diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index 06c0a308b38b..ec9f2ed579e3 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -2324,6 +2324,46 @@ struct acpi_spi_lookup { int index; }; +static int acpi_spi_count(struct acpi_resource *ares, void *data) +{ + struct acpi_resource_spi_serialbus *sb; + int *count = data; + + if (ares->type != ACPI_RESOURCE_TYPE_SERIAL_BUS) + return 1; + + sb = &ares->data.spi_serial_bus; + if (sb->type != ACPI_RESOURCE_SERIAL_TYPE_SPI) + return 1; + + *count = *count + 1; + + return 1; +} + +/** + * acpi_spi_count_resources - Count the number of SpiSerialBus resources + * @adev: ACPI device + * + * Returns the number of SpiSerialBus resources in the ACPI-device's + * resource-list; or a negative error code. + */ +int acpi_spi_count_resources(struct acpi_device *adev) +{ + LIST_HEAD(r); + int count = 0; + int ret; + + ret = acpi_dev_get_resources(adev, &r, acpi_spi_count, &count); + if (ret < 0) + return ret; + + acpi_dev_free_resource_list(&r); + + return count; +} +EXPORT_SYMBOL_GPL(acpi_spi_count_resources); + static void acpi_spi_parse_apple_properties(struct acpi_device *dev, struct acpi_spi_lookup *lookup) { diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h index e5bbb9cbd3d7..394b4241d989 100644 --- a/include/linux/spi/spi.h +++ b/include/linux/spi/spi.h @@ -764,6 +764,7 @@ extern void spi_unregister_controller(struct spi_controller *ctlr); extern struct spi_device *acpi_spi_device_alloc(struct spi_controller *ctlr, struct acpi_device *adev, int index); +int acpi_spi_count_resources(struct acpi_device *adev); #endif /* -- cgit v1.2.3 From 7030c428fae100c339436f5cb6f9e7c0574097ad Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Tue, 1 Feb 2022 21:05:59 +0100 Subject: spi: Replace acpi_bus_get_device() Replace acpi_bus_get_device() that is going to be dropped with acpi_fetch_acpi_dev(). No intentional functional impact. Signed-off-by: Rafael J. Wysocki Link: https://lore.kernel.org/r/2231987.ElGaqSPkdT@kreacher 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 ec9f2ed579e3..c98c55f44ee6 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -2585,10 +2585,10 @@ static acpi_status acpi_register_spi_device(struct spi_controller *ctlr, static acpi_status acpi_spi_add_device(acpi_handle handle, u32 level, void *data, void **return_value) { + struct acpi_device *adev = acpi_fetch_acpi_dev(handle); struct spi_controller *ctlr = data; - struct acpi_device *adev; - if (acpi_bus_get_device(handle, &adev)) + if (!adev) return AE_OK; return acpi_register_spi_device(ctlr, adev); -- cgit v1.2.3 From 8d37f2710f022837635d9f97db3ac8c853e86979 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Wed, 2 Feb 2022 00:45:35 +0100 Subject: spi: mpc512x-psc: Fix compile errors MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit My patch created compilation bugs in the MPC512x-PSC driver. Fix them up. Cc: Uwe Kleine-König Cc: Anatolij Gustschin Cc: linuxppc-dev@lists.ozlabs.org Reported-by: kernel test robot Fixes: 2818824ced4b (" spi: mpc512x-psc: Convert to use GPIO descriptors") Signed-off-by: Linus Walleij Link: https://lore.kernel.org/r/20220201234535.569973-1-linus.walleij@linaro.org Signed-off-by: Mark Brown --- drivers/spi/spi-mpc512x-psc.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/spi/spi-mpc512x-psc.c b/drivers/spi/spi-mpc512x-psc.c index 8a488d8e4c1b..03630359ce70 100644 --- a/drivers/spi/spi-mpc512x-psc.c +++ b/drivers/spi/spi-mpc512x-psc.c @@ -127,7 +127,7 @@ static void mpc512x_psc_spi_activate_cs(struct spi_device *spi) out_be32(psc_addr(mps, ccr), ccr); mps->bits_per_word = cs->bits_per_word; - if (cs->gpiod) { + if (spi->cs_gpiod) { if (mps->cs_control) /* boardfile override */ mps->cs_control(spi, (spi->mode & SPI_CS_HIGH) ? 1 : 0); @@ -373,7 +373,6 @@ static int mpc512x_psc_spi_unprep_xfer_hw(struct spi_master *master) static int mpc512x_psc_spi_setup(struct spi_device *spi) { struct mpc512x_psc_spi_cs *cs = spi->controller_state; - int ret; if (spi->bits_per_word % 8) return -EINVAL; -- cgit v1.2.3 From 4e28b22225e3a8b7f1bd3e093301802a2238071a Mon Sep 17 00:00:00 2001 From: David Heidelberg Date: Wed, 2 Feb 2022 11:47:15 +0100 Subject: spi: dt-bindings: add mising description type to reg property Added missing description type. Fixes warning: Documentation/devicetree/bindings/spi/spi-sunplus-sp7021.yaml: properties:reg:items: 'anyOf' conditional failed Fixes: a708078eeb99 ("spi: Add Sunplus SP7021 schema") Signed-off-by: David Heidelberg Link: https://lore.kernel.org/r/20220202104715.27839-1-david@ixit.cz Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/spi/spi-sunplus-sp7021.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Documentation/devicetree/bindings/spi/spi-sunplus-sp7021.yaml b/Documentation/devicetree/bindings/spi/spi-sunplus-sp7021.yaml index 24382cdda645..38589fdbc80d 100644 --- a/Documentation/devicetree/bindings/spi/spi-sunplus-sp7021.yaml +++ b/Documentation/devicetree/bindings/spi/spi-sunplus-sp7021.yaml @@ -20,8 +20,8 @@ properties: reg: items: - - the SPI master registers - - the SPI slave registers + - description: the SPI master registers + - description: the SPI slave registers reg-names: items: -- cgit v1.2.3 From 60edd652005fe2931565f658f23f86d094f4c1f0 Mon Sep 17 00:00:00 2001 From: Leilk Liu Date: Tue, 25 Jan 2022 09:23:28 +0800 Subject: spi: Convert spi-slave-mt27xx to json-schema Convert Mediatek ARM SOC's SPI Slave controller binding to json-schema format. Signed-off-by: Leilk Liu Reviewed-by: Rob Herring Link: https://lore.kernel.org/r/20220125012330.13449-2-leilk.liu@mediatek.com Signed-off-by: Mark Brown --- .../bindings/spi/mediatek,spi-slave-mt27xx.yaml | 58 ++++++++++++++++++++++ .../devicetree/bindings/spi/spi-slave-mt27xx.txt | 33 ------------ 2 files changed, 58 insertions(+), 33 deletions(-) create mode 100644 Documentation/devicetree/bindings/spi/mediatek,spi-slave-mt27xx.yaml delete mode 100644 Documentation/devicetree/bindings/spi/spi-slave-mt27xx.txt diff --git a/Documentation/devicetree/bindings/spi/mediatek,spi-slave-mt27xx.yaml b/Documentation/devicetree/bindings/spi/mediatek,spi-slave-mt27xx.yaml new file mode 100644 index 000000000000..7977799a8ee1 --- /dev/null +++ b/Documentation/devicetree/bindings/spi/mediatek,spi-slave-mt27xx.yaml @@ -0,0 +1,58 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/spi/mediatek,spi-slave-mt27xx.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: SPI Slave controller for MediaTek ARM SoCs + +maintainers: + - Leilk Liu + +allOf: + - $ref: "/schemas/spi/spi-controller.yaml#" + +properties: + compatible: + enum: + - mediatek,mt2712-spi-slave + - mediatek,mt8195-spi-slave + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + clocks: + maxItems: 1 + + clock-names: + items: + - const: spi + +required: + - compatible + - reg + - interrupts + - clocks + - clock-names + +unevaluatedProperties: false + +examples: + - | + #include + #include + #include + #include + + spi@10013000 { + compatible = "mediatek,mt2712-spi-slave"; + reg = <0x10013000 0x100>; + interrupts = ; + clocks = <&infracfg CLK_INFRA_AO_SPI1>; + clock-names = "spi"; + assigned-clocks = <&topckgen CLK_TOP_SPISLV_SEL>; + assigned-clock-parents = <&topckgen CLK_TOP_UNIVPLL1_D2>; + }; diff --git a/Documentation/devicetree/bindings/spi/spi-slave-mt27xx.txt b/Documentation/devicetree/bindings/spi/spi-slave-mt27xx.txt deleted file mode 100644 index 9192724540fd..000000000000 --- a/Documentation/devicetree/bindings/spi/spi-slave-mt27xx.txt +++ /dev/null @@ -1,33 +0,0 @@ -Binding for MTK SPI Slave controller - -Required properties: -- compatible: should be one of the following. - - mediatek,mt2712-spi-slave: for mt2712 platforms - - mediatek,mt8195-spi-slave: for mt8195 platforms -- reg: Address and length of the register set for the device. -- interrupts: Should contain spi interrupt. -- clocks: phandles to input clocks. - It's clock gate, and should be <&infracfg CLK_INFRA_AO_SPI1>. -- clock-names: should be "spi" for the clock gate. - -Optional properties: -- assigned-clocks: it's mux clock, should be <&topckgen CLK_TOP_SPISLV_SEL>. -- assigned-clock-parents: parent of mux clock. - It's PLL, and should be one of the following. - - <&topckgen CLK_TOP_UNIVPLL1_D2>: specify parent clock 312MHZ. - It's the default one. - - <&topckgen CLK_TOP_UNIVPLL1_D4>: specify parent clock 156MHZ. - - <&topckgen CLK_TOP_UNIVPLL2_D4>: specify parent clock 104MHZ. - - <&topckgen CLK_TOP_UNIVPLL1_D8>: specify parent clock 78MHZ. - -Example: -- SoC Specific Portion: -spis1: spi@10013000 { - compatible = "mediatek,mt2712-spi-slave"; - reg = <0 0x10013000 0 0x100>; - interrupts = ; - clocks = <&infracfg CLK_INFRA_AO_SPI1>; - clock-names = "spi"; - assigned-clocks = <&topckgen CLK_TOP_SPISLV_SEL>; - assigned-clock-parents = <&topckgen CLK_TOP_UNIVPLL1_D2>; -}; -- cgit v1.2.3 From 08727dd751234bc878be64e60ea6f0d8ea0d54c0 Mon Sep 17 00:00:00 2001 From: Leilk Liu Date: Tue, 25 Jan 2022 09:23:29 +0800 Subject: spi: Convert spi-mt65xx to json-schema Convert Mediatek ARM SOC's SPI Master controller binding to json-schema format. Signed-off-by: Leilk Liu Reviewed-by: Rob Herring Link: https://lore.kernel.org/r/20220125012330.13449-3-leilk.liu@mediatek.com Signed-off-by: Mark Brown --- .../bindings/spi/mediatek,spi-mt65xx.yaml | 101 +++++++++++++++++++++ .../devicetree/bindings/spi/spi-mt65xx.txt | 68 -------------- 2 files changed, 101 insertions(+), 68 deletions(-) create mode 100644 Documentation/devicetree/bindings/spi/mediatek,spi-mt65xx.yaml delete mode 100644 Documentation/devicetree/bindings/spi/spi-mt65xx.txt diff --git a/Documentation/devicetree/bindings/spi/mediatek,spi-mt65xx.yaml b/Documentation/devicetree/bindings/spi/mediatek,spi-mt65xx.yaml new file mode 100644 index 000000000000..ea977fba49a7 --- /dev/null +++ b/Documentation/devicetree/bindings/spi/mediatek,spi-mt65xx.yaml @@ -0,0 +1,101 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/spi/mediatek,spi-mt65xx.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: SPI Bus controller for MediaTek ARM SoCs + +maintainers: + - Leilk Liu + +allOf: + - $ref: "/schemas/spi/spi-controller.yaml#" + +properties: + compatible: + oneOf: + - items: + - enum: + - mediatek,mt7629-spi + - const: mediatek,mt7622-spi + - items: + - enum: + - mediatek,mt8516-spi + - const: mediatek,mt2712-spi + - items: + - enum: + - mediatek,mt6779-spi + - mediatek,mt8192-spi + - mediatek,mt8195-spi + - const: mediatek,mt6765-spi + - items: + - enum: + - mediatek,mt2701-spi + - mediatek,mt2712-spi + - mediatek,mt6589-spi + - mediatek,mt6765-spi + - mediatek,mt6893-spi + - mediatek,mt7622-spi + - mediatek,mt8135-spi + - mediatek,mt8173-spi + - mediatek,mt8183-spi + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + clocks: + items: + - description: clock used for the parent clock + - description: clock used for the muxes clock + - description: clock used for the clock gate + + clock-names: + items: + - const: parent-clk + - const: sel-clk + - const: spi-clk + + mediatek,pad-select: + $ref: /schemas/types.yaml#/definitions/uint32-array + maxItems: 4 + items: + enum: [0, 1, 2, 3] + description: + specify which pins group(ck/mi/mo/cs) spi controller used. + This is an array. + +required: + - compatible + - reg + - interrupts + - clocks + - clock-names + - '#address-cells' + - '#size-cells' + +unevaluatedProperties: false + +examples: + - | + #include + #include + #include + #include + + spi@1100a000 { + compatible = "mediatek,mt8173-spi"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x1100a000 0x1000>; + interrupts = ; + clocks = <&topckgen CLK_TOP_SYSPLL3_D2>, + <&topckgen CLK_TOP_SPI_SEL>, + <&pericfg CLK_PERI_SPI0>; + clock-names = "parent-clk", "sel-clk", "spi-clk"; + cs-gpios = <&pio 105 GPIO_ACTIVE_LOW>, <&pio 72 GPIO_ACTIVE_LOW>; + mediatek,pad-select = <1>, <0>; + }; diff --git a/Documentation/devicetree/bindings/spi/spi-mt65xx.txt b/Documentation/devicetree/bindings/spi/spi-mt65xx.txt deleted file mode 100644 index 2a24969159cc..000000000000 --- a/Documentation/devicetree/bindings/spi/spi-mt65xx.txt +++ /dev/null @@ -1,68 +0,0 @@ -Binding for MTK SPI controller - -Required properties: -- compatible: should be one of the following. - - mediatek,mt2701-spi: for mt2701 platforms - - mediatek,mt2712-spi: for mt2712 platforms - - mediatek,mt6589-spi: for mt6589 platforms - - mediatek,mt6765-spi: for mt6765 platforms - - mediatek,mt7622-spi: for mt7622 platforms - - "mediatek,mt7629-spi", "mediatek,mt7622-spi": for mt7629 platforms - - mediatek,mt8135-spi: for mt8135 platforms - - mediatek,mt8173-spi: for mt8173 platforms - - mediatek,mt8183-spi: for mt8183 platforms - - mediatek,mt6893-spi: for mt6893 platforms - - "mediatek,mt8192-spi", "mediatek,mt6765-spi": for mt8192 platforms - - "mediatek,mt8195-spi", "mediatek,mt6765-spi": for mt8195 platforms - - "mediatek,mt8516-spi", "mediatek,mt2712-spi": for mt8516 platforms - - "mediatek,mt6779-spi", "mediatek,mt6765-spi": for mt6779 platforms - -- #address-cells: should be 1. - -- #size-cells: should be 0. - -- reg: Address and length of the register set for the device - -- interrupts: Should contain spi interrupt - -- clocks: phandles to input clocks. - The first should be one of the following. It's PLL. - - <&clk26m>: specify parent clock 26MHZ. - - <&topckgen CLK_TOP_SYSPLL3_D2>: specify parent clock 109MHZ. - It's the default one. - - <&topckgen CLK_TOP_SYSPLL4_D2>: specify parent clock 78MHZ. - - <&topckgen CLK_TOP_UNIVPLL2_D4>: specify parent clock 104MHZ. - - <&topckgen CLK_TOP_UNIVPLL1_D8>: specify parent clock 78MHZ. - The second should be <&topckgen CLK_TOP_SPI_SEL>. It's clock mux. - The third is <&pericfg CLK_PERI_SPI0>. It's clock gate. - -- clock-names: shall be "parent-clk" for the parent clock, "sel-clk" for the - muxes clock, and "spi-clk" for the clock gate. - -Optional properties: --cs-gpios: see spi-bus.txt. - -- mediatek,pad-select: specify which pins group(ck/mi/mo/cs) spi - controller used. This is an array, the element value should be 0~3, - only required for MT8173. - 0: specify GPIO69,70,71,72 for spi pins. - 1: specify GPIO102,103,104,105 for spi pins. - 2: specify GPIO128,129,130,131 for spi pins. - 3: specify GPIO5,6,7,8 for spi pins. - -Example: - -- SoC Specific Portion: -spi: spi@1100a000 { - compatible = "mediatek,mt8173-spi"; - #address-cells = <1>; - #size-cells = <0>; - reg = <0 0x1100a000 0 0x1000>; - interrupts = ; - clocks = <&topckgen CLK_TOP_SYSPLL3_D2>, - <&topckgen CLK_TOP_SPI_SEL>, - <&pericfg CLK_PERI_SPI0>; - clock-names = "parent-clk", "sel-clk", "spi-clk"; - cs-gpios = <&pio 105 GPIO_ACTIVE_LOW>, <&pio 72 GPIO_ACTIVE_LOW>; - mediatek,pad-select = <1>, <0>; -}; -- cgit v1.2.3 From ccbc5d0a92c5f1d42d1a1635b53f1987821e9cdd Mon Sep 17 00:00:00 2001 From: Leilk Liu Date: Tue, 25 Jan 2022 09:23:30 +0800 Subject: spi: Add compatible for Mediatek MT8186 This commit adds dt-binding documentation of spi bus for Mediatek MT8186 SoC Platform. Signed-off-by: Leilk Liu Acked-by: Rob Herring Link: https://lore.kernel.org/r/20220125012330.13449-4-leilk.liu@mediatek.com Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/spi/mediatek,spi-mt65xx.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/spi/mediatek,spi-mt65xx.yaml b/Documentation/devicetree/bindings/spi/mediatek,spi-mt65xx.yaml index ea977fba49a7..bfa44acb1bdd 100644 --- a/Documentation/devicetree/bindings/spi/mediatek,spi-mt65xx.yaml +++ b/Documentation/devicetree/bindings/spi/mediatek,spi-mt65xx.yaml @@ -26,6 +26,7 @@ properties: - items: - enum: - mediatek,mt6779-spi + - mediatek,mt8186-spi - mediatek,mt8192-spi - mediatek,mt8195-spi - const: mediatek,mt6765-spi -- cgit v1.2.3 From 833026ad56f76d1a1035d6511fd5aeed308465fd Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Tue, 25 Jan 2022 09:52:02 +0300 Subject: spi: spidev: prevent spidev->speed_hz from being zero A zero value for spi->max_speed_hz or spidev->speed_hz does not make sense and trying to set that can lead to divide by zero crashes in a some of the drivers. drivers/spi/spi-s3c64xx.c:874 s3c64xx_spi_setup() error: potential divide by zero bug '/ spi->max_speed_hz'. drivers/spi/spi-fsl-dspi.c:613 hz_to_spi_baud() error: potential divide by zero bug '/ speed_hz'. drivers/spi/spi-xlp.c:146 xlp_spi_setup() error: potential divide by zero bug '/ (spi->max_speed_hz)'. drivers/spi/spi-orion.c:162 orion_spi_baudrate_set() error: potential divide by zero bug '/ speed'. Signed-off-by: Dan Carpenter Link: https://lore.kernel.org/r/20220125065202.GA8807@kili Signed-off-by: Mark Brown --- drivers/spi/spidev.c | 31 +++++++++++++++++++------------ 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/drivers/spi/spidev.c b/drivers/spi/spidev.c index a5cceca8b82b..dd824db63fbe 100644 --- a/drivers/spi/spidev.c +++ b/drivers/spi/spidev.c @@ -453,22 +453,29 @@ spidev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) dev_dbg(&spi->dev, "%d bits per word\n", tmp); } break; - case SPI_IOC_WR_MAX_SPEED_HZ: + case SPI_IOC_WR_MAX_SPEED_HZ: { + u32 save; + retval = get_user(tmp, (__u32 __user *)arg); - if (retval == 0) { - u32 save = spi->max_speed_hz; + if (retval) + break; + if (tmp == 0) { + retval = -EINVAL; + break; + } - spi->max_speed_hz = tmp; - retval = spi_setup(spi); - if (retval == 0) { - spidev->speed_hz = tmp; - dev_dbg(&spi->dev, "%d Hz (max)\n", - spidev->speed_hz); - } - spi->max_speed_hz = save; + save = spi->max_speed_hz; + + spi->max_speed_hz = tmp; + retval = spi_setup(spi); + if (retval == 0) { + spidev->speed_hz = tmp; + dev_dbg(&spi->dev, "%d Hz (max)\n", spidev->speed_hz); } - break; + spi->max_speed_hz = save; + break; + } default: /* segmented and/or full-duplex I/O request */ /* Check message and copy into scratch area */ -- cgit v1.2.3 From 47e8fe57a66f72c5734b981b21557c732b9a5eb6 Mon Sep 17 00:00:00 2001 From: Li-hao Kuo Date: Mon, 7 Feb 2022 09:57:22 +0800 Subject: spi: Modify irq request position and modify parameters - Change irq request position to the back. - Add temporary varilable and setting (as suggested by Mr. Andy Shevchenko) Fixes: f62ca4e2a863 ("spi: Add spi driver for Sunplus SP7021") Signed-off-by: Li-hao Kuo Link: https://lore.kernel.org/r/a94e3b123773fe303221d2bd2e4ce36ffa905a1c.1644198957.git.lhjeff911@gmail.com Signed-off-by: Mark Brown --- drivers/spi/spi-sunplus-sp7021.c | 63 ++++++++++++++++++++-------------------- 1 file changed, 31 insertions(+), 32 deletions(-) diff --git a/drivers/spi/spi-sunplus-sp7021.c b/drivers/spi/spi-sunplus-sp7021.c index e5bdeb3eba45..ba5ed9f7277a 100644 --- a/drivers/spi/spi-sunplus-sp7021.c +++ b/drivers/spi/spi-sunplus-sp7021.c @@ -110,7 +110,8 @@ static irqreturn_t sp7021_spi_slave_irq(int irq, void *dev) unsigned int data_status; data_status = readl(pspim->s_base + SP7021_DATA_RDY_REG); - writel(data_status | SP7021_SLAVE_CLR_INT, pspim->s_base + SP7021_DATA_RDY_REG); + data_status |= SP7021_SLAVE_CLR_INT; + writel(data_status , pspim->s_base + SP7021_DATA_RDY_REG); complete(&pspim->slave_isr); return IRQ_HANDLED; } @@ -127,14 +128,16 @@ static int sp7021_spi_slave_abort(struct spi_controller *ctlr) static int sp7021_spi_slave_tx(struct spi_device *spi, struct spi_transfer *xfer) { struct sp7021_spi_ctlr *pspim = spi_controller_get_devdata(spi->controller); + u32 value; reinit_completion(&pspim->slave_isr); - writel(SP7021_SLAVE_DMA_EN | SP7021_SLAVE_DMA_RW | FIELD_PREP(SP7021_SLAVE_DMA_CMD, 3), - pspim->s_base + SP7021_SLAVE_DMA_CTRL_REG); + value = SP7021_SLAVE_DMA_EN | SP7021_SLAVE_DMA_RW | FIELD_PREP(SP7021_SLAVE_DMA_CMD, 3); + writel(value, pspim->s_base + SP7021_SLAVE_DMA_CTRL_REG); writel(xfer->len, pspim->s_base + SP7021_SLAVE_DMA_LENGTH_REG); writel(xfer->tx_dma, pspim->s_base + SP7021_SLAVE_DMA_ADDR_REG); - writel(readl(pspim->s_base + SP7021_DATA_RDY_REG) | SP7021_SLAVE_DATA_RDY, - pspim->s_base + SP7021_DATA_RDY_REG); + value = readl(pspim->s_base + SP7021_DATA_RDY_REG); + value |= SP7021_SLAVE_DATA_RDY; + writel(value, pspim->s_base + SP7021_DATA_RDY_REG); if (wait_for_completion_interruptible(&pspim->isr_done)) { dev_err(&spi->dev, "%s() wait_for_completion err\n", __func__); return -EINTR; @@ -145,11 +148,11 @@ static int sp7021_spi_slave_tx(struct spi_device *spi, struct spi_transfer *xfer static int sp7021_spi_slave_rx(struct spi_device *spi, struct spi_transfer *xfer) { struct sp7021_spi_ctlr *pspim = spi_controller_get_devdata(spi->controller); - int ret = 0; + u32 value; reinit_completion(&pspim->isr_done); - writel(SP7021_SLAVE_DMA_EN | FIELD_PREP(SP7021_SLAVE_DMA_CMD, 3), - pspim->s_base + SP7021_SLAVE_DMA_CTRL_REG); + value = SP7021_SLAVE_DMA_EN | FIELD_PREP(SP7021_SLAVE_DMA_CMD, 3); + writel(value, pspim->s_base + SP7021_SLAVE_DMA_CTRL_REG); writel(xfer->len, pspim->s_base + SP7021_SLAVE_DMA_LENGTH_REG); writel(xfer->rx_dma, pspim->s_base + SP7021_SLAVE_DMA_ADDR_REG); if (wait_for_completion_interruptible(&pspim->isr_done)) { @@ -157,7 +160,7 @@ static int sp7021_spi_slave_rx(struct spi_device *spi, struct spi_transfer *xfer return -EINTR; } writel(SP7021_SLAVE_SW_RST, pspim->s_base + SP7021_SLAVE_DMA_CTRL_REG); - return ret; + return 0; } static void sp7021_spi_master_rb(struct sp7021_spi_ctlr *pspim, unsigned int len) @@ -188,7 +191,6 @@ static irqreturn_t sp7021_spi_master_irq(int irq, void *dev) unsigned int tx_cnt, total_len; unsigned int tx_len, rx_cnt; unsigned int fd_status; - unsigned long flags; bool isrdone = false; u32 value; @@ -203,7 +205,7 @@ static irqreturn_t sp7021_spi_master_irq(int irq, void *dev) if (tx_len == 0 && total_len == 0) return IRQ_NONE; - spin_lock_irqsave(&pspim->lock, flags); + spin_lock_irq(&pspim->lock); rx_cnt = FIELD_GET(SP7021_RX_CNT_MASK, fd_status); if (fd_status & SP7021_RX_FULL_FLAG) @@ -243,7 +245,7 @@ static irqreturn_t sp7021_spi_master_irq(int irq, void *dev) if (isrdone) complete(&pspim->isr_done); - spin_unlock_irqrestore(&pspim->lock, flags); + spin_unlock_irq(&pspim->lock); return IRQ_HANDLED; } @@ -296,11 +298,10 @@ static void sp7021_spi_setup_clk(struct spi_controller *ctlr, struct spi_transfe u32 clk_rate, clk_sel, div; clk_rate = clk_get_rate(pspim->spi_clk); - div = clk_rate / xfer->speed_hz; - if (div < 2) - div = 2; + div = max(2U, clk_rate / xfer->speed_hz); + clk_sel = (div / 2) - 1; - pspim->xfer_conf &= SP7021_CLK_MASK; + pspim->xfer_conf &= ~SP7021_CLK_MASK; pspim->xfer_conf |= FIELD_PREP(SP7021_CLK_MASK, clk_sel); writel(pspim->xfer_conf, pspim->m_base + SP7021_SPI_CONFIG_REG); } @@ -313,7 +314,6 @@ static int sp7021_spi_master_transfer_one(struct spi_controller *ctlr, struct sp unsigned int xfer_cnt, xfer_len, last_len; unsigned int i, len_temp; u32 reg_temp; - int ret; xfer_cnt = xfer->len / SP7021_SPI_DATA_SIZE; last_len = xfer->len % SP7021_SPI_DATA_SIZE; @@ -366,9 +366,8 @@ static int sp7021_spi_master_transfer_one(struct spi_controller *ctlr, struct sp writel(pspim->xfer_conf, pspim->m_base + SP7021_SPI_CONFIG_REG); mutex_unlock(&pspim->buf_lock); - ret = 0; } - return ret; + return 0; } static int sp7021_spi_slave_transfer_one(struct spi_controller *ctlr, struct spi_device *spi, @@ -376,12 +375,12 @@ static int sp7021_spi_slave_transfer_one(struct spi_controller *ctlr, struct spi { struct sp7021_spi_ctlr *pspim = spi_master_get_devdata(ctlr); struct device *dev = pspim->dev; - int mode, ret = 0; + int mode, ret; mode = SP7021_SPI_IDLE; if (xfer->tx_buf && xfer->rx_buf) { dev_dbg(&ctlr->dev, "%s() wrong command\n", __func__); - ret = -EINVAL; + return -EINVAL; } else if (xfer->tx_buf) { xfer->tx_dma = dma_map_single(dev, (void *)xfer->tx_buf, xfer->len, DMA_TO_DEVICE); @@ -445,7 +444,7 @@ static int sp7021_spi_controller_probe(struct platform_device *pdev) ctlr = devm_spi_alloc_master(dev, sizeof(*pspim)); if (!ctlr) return -ENOMEM; - device_set_node(&ctlr->dev, pdev->dev.fwnode); + device_set_node(&ctlr->dev, dev_fwnode(dev)); ctlr->bus_num = pdev->id; ctlr->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LSB_FIRST; ctlr->auto_runtime_pm = true; @@ -488,16 +487,6 @@ static int sp7021_spi_controller_probe(struct platform_device *pdev) if (pspim->s_irq < 0) return pspim->s_irq; - ret = devm_request_irq(dev, pspim->m_irq, sp7021_spi_master_irq, - IRQF_TRIGGER_RISING, pdev->name, pspim); - if (ret) - return ret; - - ret = devm_request_irq(dev, pspim->s_irq, sp7021_spi_slave_irq, - IRQF_TRIGGER_RISING, pdev->name, pspim); - if (ret) - return ret; - pspim->spi_clk = devm_clk_get(dev, NULL); if (IS_ERR(pspim->spi_clk)) return dev_err_probe(dev, PTR_ERR(pspim->spi_clk), "clk get fail\n"); @@ -522,6 +511,16 @@ static int sp7021_spi_controller_probe(struct platform_device *pdev) if (ret) return ret; + ret = devm_request_irq(dev, pspim->m_irq, sp7021_spi_master_irq, + IRQF_TRIGGER_RISING, pdev->name, pspim); + if (ret) + return ret; + + ret = devm_request_irq(dev, pspim->s_irq, sp7021_spi_slave_irq, + IRQF_TRIGGER_RISING, pdev->name, pspim); + if (ret) + return ret; + pm_runtime_enable(dev); ret = spi_register_controller(ctlr); if (ret) { -- cgit v1.2.3 From d08de0259dfe172caf073b921c6b27ff089605a9 Mon Sep 17 00:00:00 2001 From: Luiz Angelo Daros de Luca Date: Sat, 29 Jan 2022 01:04:53 -0300 Subject: spi: ath79: add mem_ops for fast-read Reading from memory is 3x faster than bit-bang read operation. Also, for tl-wr2543nd, the bit-bang read was sporadically returning random data, possibly a HW defect, while fast-read works as expected. Signed-off-by: Luiz Angelo Daros de Luca Link: https://lore.kernel.org/r/20220129040453.8476-1-luizluca@gmail.com Signed-off-by: Mark Brown --- drivers/spi/spi-ath79.c | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/drivers/spi/spi-ath79.c b/drivers/spi/spi-ath79.c index d1e287d2d9cd..607e7a49fb89 100644 --- a/drivers/spi/spi-ath79.c +++ b/drivers/spi/spi-ath79.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -133,6 +134,38 @@ static u32 ath79_spi_txrx_mode0(struct spi_device *spi, unsigned int nsecs, return ath79_spi_rr(sp, AR71XX_SPI_REG_RDS); } +static int ath79_exec_mem_op(struct spi_mem *mem, + const struct spi_mem_op *op) +{ + struct ath79_spi *sp = ath79_spidev_to_sp(mem->spi); + + /* Ensures that reading is performed on device connected to hardware cs0 */ + if (mem->spi->chip_select || mem->spi->cs_gpiod) + return -ENOTSUPP; + + /* Only use for fast-read op. */ + if (op->cmd.opcode != 0x0b || op->data.dir != SPI_MEM_DATA_IN || + op->addr.nbytes != 3 || op->dummy.nbytes != 1) + return -ENOTSUPP; + + /* disable GPIO mode */ + ath79_spi_wr(sp, AR71XX_SPI_REG_FS, 0); + + memcpy_fromio(op->data.buf.in, sp->base + op->addr.val, op->data.nbytes); + + /* enable GPIO mode */ + ath79_spi_wr(sp, AR71XX_SPI_REG_FS, AR71XX_SPI_FS_GPIO); + + /* restore IOC register */ + ath79_spi_wr(sp, AR71XX_SPI_REG_IOC, sp->ioc_base); + + return 0; +} + +static const struct spi_controller_mem_ops ath79_mem_ops = { + .exec_op = ath79_exec_mem_op, +}; + static int ath79_spi_probe(struct platform_device *pdev) { struct spi_master *master; @@ -154,6 +187,7 @@ static int ath79_spi_probe(struct platform_device *pdev) master->bits_per_word_mask = SPI_BPW_RANGE_MASK(1, 32); master->flags = SPI_MASTER_GPIO_SS; master->num_chipselect = 3; + master->mem_ops = &ath79_mem_ops; sp->bitbang.master = master; sp->bitbang.chipselect = ath79_spi_chipselect; -- cgit v1.2.3 From 4f92724d4b92c024e721063f520d66e11ca4b54b Mon Sep 17 00:00:00 2001 From: Miaoqian Lin Date: Fri, 28 Jan 2022 16:52:38 +0000 Subject: spi: tegra114: Add missing IRQ check in tegra_spi_probe This func misses checking for platform_get_irq()'s call and may passes the negative error codes to request_threaded_irq(), which takes unsigned IRQ #, causing it to fail with -EINVAL, overriding an original error code. Stop calling request_threaded_irq() with invalid IRQ #s. Fixes: f333a331adfa ("spi/tegra114: add spi driver") Signed-off-by: Miaoqian Lin Link: https://lore.kernel.org/r/20220128165238.25615-1-linmq006@gmail.com Signed-off-by: Mark Brown --- drivers/spi/spi-tegra114.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/spi/spi-tegra114.c b/drivers/spi/spi-tegra114.c index e9de1d958bbd..8f345247a8c3 100644 --- a/drivers/spi/spi-tegra114.c +++ b/drivers/spi/spi-tegra114.c @@ -1352,6 +1352,10 @@ static int tegra_spi_probe(struct platform_device *pdev) tspi->phys = r->start; spi_irq = platform_get_irq(pdev, 0); + if (spi_irq < 0) { + ret = spi_irq; + goto exit_free_master; + } tspi->irq = spi_irq; tspi->clk = devm_clk_get(&pdev->dev, "spi"); -- cgit v1.2.3 From 3b8ab4da3405d07ddfe434f17f9014740b30a19c Mon Sep 17 00:00:00 2001 From: Li-hao Kuo Date: Mon, 7 Feb 2022 09:46:34 +0800 Subject: spi: Fix test error for sp7021. Remove the include path and modify parameters for fix error for bt binding test Fixes: a708078eeb99 ("spi: Add Sunplus SP7021 schema") Signed-off-by: Li-hao Kuo Link: https://lore.kernel.org/r/b8a94fbfcab68b1279b09b6297099310c209927b.1644198244.git.lhjeff911@gmail.com Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/spi/spi-sunplus-sp7021.yaml | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/Documentation/devicetree/bindings/spi/spi-sunplus-sp7021.yaml b/Documentation/devicetree/bindings/spi/spi-sunplus-sp7021.yaml index 38589fdbc80d..298eac28c40f 100644 --- a/Documentation/devicetree/bindings/spi/spi-sunplus-sp7021.yaml +++ b/Documentation/devicetree/bindings/spi/spi-sunplus-sp7021.yaml @@ -59,8 +59,6 @@ unevaluatedProperties: false examples: - | - #include - #include #include spi@9C002D80 { compatible = "sunplus,sp7021-spi"; @@ -73,8 +71,8 @@ examples: interrupts = <144 IRQ_TYPE_LEVEL_HIGH>, <146 IRQ_TYPE_LEVEL_HIGH>, <145 IRQ_TYPE_LEVEL_HIGH>; - clocks = <&clkc SPI_COMBO_0>; - resets = <&rstc RST_SPI_COMBO_0>; + clocks = <&clkc 0x32>; + resets = <&rstc 0x22>; pinctrl-names = "default"; pinctrl-0 = <&pins_spi0>; }; -- cgit v1.2.3 From 47c3e06ed95aa9b74932dbc6b23b544f644faf84 Mon Sep 17 00:00:00 2001 From: Miaoqian Lin Date: Fri, 28 Jan 2022 16:59:56 +0000 Subject: spi: tegra210-quad: Fix missin IRQ check in tegra_qspi_probe This func misses checking for platform_get_irq()'s call and may passes the negative error codes to request_threaded_irq(), which takes unsigned IRQ #, causing it to fail with -EINVAL, overriding an original error code. Stop calling request_threaded_irq() with invalid IRQ #s. Fixes: 921fc1838fb0 ("spi: tegra210-quad: Add support for Tegra210 QSPI controller") Signed-off-by: Miaoqian Lin Link: https://lore.kernel.org/r/20220128165956.27821-1-linmq006@gmail.com Signed-off-by: Mark Brown --- drivers/spi/spi-tegra210-quad.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/spi/spi-tegra210-quad.c b/drivers/spi/spi-tegra210-quad.c index ce1bdb4767ea..cb00ac2fc7d8 100644 --- a/drivers/spi/spi-tegra210-quad.c +++ b/drivers/spi/spi-tegra210-quad.c @@ -1240,6 +1240,8 @@ static int tegra_qspi_probe(struct platform_device *pdev) tqspi->phys = r->start; qspi_irq = platform_get_irq(pdev, 0); + if (qspi_irq < 0) + return qspi_irq; tqspi->irq = qspi_irq; tqspi->clk = devm_clk_get(&pdev->dev, "qspi"); -- cgit v1.2.3 From 7d8e4c98d13b6b54655140d6b6a6a17fbc9b32f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Sun, 23 Jan 2022 18:51:57 +0100 Subject: staging: fbtft: Fix error path in fbtft_driver_module_init() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If registering the platform driver fails, the function must not return without undoing the spi driver registration first. Fixes: c296d5f9957c ("staging: fbtft: core support") Link: https://lore.kernel.org/r/20220118181338.207943-1-u.kleine-koenig@pengutronix.de Signed-off-by: Uwe Kleine-König Acked-by: Lee Jones Link: https://lore.kernel.org/r/20220123175201.34839-2-u.kleine-koenig@pengutronix.de Signed-off-by: Mark Brown --- drivers/staging/fbtft/fbtft.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/staging/fbtft/fbtft.h b/drivers/staging/fbtft/fbtft.h index 4cdec34e23d2..55677efc0138 100644 --- a/drivers/staging/fbtft/fbtft.h +++ b/drivers/staging/fbtft/fbtft.h @@ -334,7 +334,10 @@ static int __init fbtft_driver_module_init(void) \ ret = spi_register_driver(&fbtft_driver_spi_driver); \ if (ret < 0) \ return ret; \ - return platform_driver_register(&fbtft_driver_platform_driver); \ + ret = platform_driver_register(&fbtft_driver_platform_driver); \ + if (ret < 0) \ + spi_unregister_driver(&fbtft_driver_spi_driver); \ + return ret; \ } \ \ static void __exit fbtft_driver_module_exit(void) \ -- cgit v1.2.3 From c222ea5d2f3361458672d1f52c78970aa021cb61 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Sun, 23 Jan 2022 18:51:58 +0100 Subject: staging: fbtft: Deduplicate driver registration macros MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The two macros FBTFT_REGISTER_DRIVER and FBTFT_REGISTER_SPI_DRIVER contain quite some duplication: Both define an spi driver and an of device table and the differences are quite subtle. So create two new macros and use both twice. Link: https://lore.kernel.org/r/20220118181338.207943-2-u.kleine-koenig@pengutronix.de Signed-off-by: Uwe Kleine-König Acked-by: Lee Jones Link: https://lore.kernel.org/r/20220123175201.34839-3-u.kleine-koenig@pengutronix.de Signed-off-by: Mark Brown --- drivers/staging/fbtft/fbtft.h | 93 +++++++++++++++++-------------------------- 1 file changed, 36 insertions(+), 57 deletions(-) diff --git a/drivers/staging/fbtft/fbtft.h b/drivers/staging/fbtft/fbtft.h index 55677efc0138..6a7545b5bcd2 100644 --- a/drivers/staging/fbtft/fbtft.h +++ b/drivers/staging/fbtft/fbtft.h @@ -272,21 +272,40 @@ void fbtft_write_reg8_bus9(struct fbtft_par *par, int len, ...); void fbtft_write_reg16_bus8(struct fbtft_par *par, int len, ...); void fbtft_write_reg16_bus16(struct fbtft_par *par, int len, ...); +#define FBTFT_DT_TABLE(_compatible) \ +static const struct of_device_id dt_ids[] = { \ + { .compatible = _compatible }, \ + {}, \ +}; \ +MODULE_DEVICE_TABLE(of, dt_ids); + +#define FBTFT_SPI_DRIVER(_name, _compatible, _display, _spi_ids) \ + \ +static int fbtft_driver_probe_spi(struct spi_device *spi) \ +{ \ + return fbtft_probe_common(_display, spi, NULL); \ +} \ + \ +static int fbtft_driver_remove_spi(struct spi_device *spi) \ +{ \ + struct fb_info *info = spi_get_drvdata(spi); \ + \ + fbtft_remove_common(&spi->dev, info); \ + return 0; \ +} \ + \ +static struct spi_driver fbtft_driver_spi_driver = { \ + .driver = { \ + .name = _name, \ + .of_match_table = dt_ids, \ + }, \ + .id_table = _spi_ids, \ + .probe = fbtft_driver_probe_spi, \ + .remove = fbtft_driver_remove_spi, \ +}; + #define FBTFT_REGISTER_DRIVER(_name, _compatible, _display) \ \ -static int fbtft_driver_probe_spi(struct spi_device *spi) \ -{ \ - return fbtft_probe_common(_display, spi, NULL); \ -} \ - \ -static int fbtft_driver_remove_spi(struct spi_device *spi) \ -{ \ - struct fb_info *info = spi_get_drvdata(spi); \ - \ - fbtft_remove_common(&spi->dev, info); \ - return 0; \ -} \ - \ static int fbtft_driver_probe_pdev(struct platform_device *pdev) \ { \ return fbtft_probe_common(_display, NULL, pdev); \ @@ -300,22 +319,9 @@ static int fbtft_driver_remove_pdev(struct platform_device *pdev) \ return 0; \ } \ \ -static const struct of_device_id dt_ids[] = { \ - { .compatible = _compatible }, \ - {}, \ -}; \ - \ -MODULE_DEVICE_TABLE(of, dt_ids); \ +FBTFT_DT_TABLE(_compatible) \ \ - \ -static struct spi_driver fbtft_driver_spi_driver = { \ - .driver = { \ - .name = _name, \ - .of_match_table = dt_ids, \ - }, \ - .probe = fbtft_driver_probe_spi, \ - .remove = fbtft_driver_remove_spi, \ -}; \ +FBTFT_SPI_DRIVER(_name, _compatible, _display, NULL) \ \ static struct platform_driver fbtft_driver_platform_driver = { \ .driver = { \ @@ -351,42 +357,15 @@ module_exit(fbtft_driver_module_exit); #define FBTFT_REGISTER_SPI_DRIVER(_name, _comp_vend, _comp_dev, _display) \ \ -static int fbtft_driver_probe_spi(struct spi_device *spi) \ -{ \ - return fbtft_probe_common(_display, spi, NULL); \ -} \ - \ -static int fbtft_driver_remove_spi(struct spi_device *spi) \ -{ \ - struct fb_info *info = spi_get_drvdata(spi); \ - \ - fbtft_remove_common(&spi->dev, info); \ - return 0; \ -} \ - \ -static const struct of_device_id dt_ids[] = { \ - { .compatible = _comp_vend "," _comp_dev }, \ - {}, \ -}; \ - \ -MODULE_DEVICE_TABLE(of, dt_ids); \ +FBTFT_DT_TABLE(_comp_vend "," _comp_dev) \ \ static const struct spi_device_id spi_ids[] = { \ { .name = _comp_dev }, \ {}, \ }; \ - \ MODULE_DEVICE_TABLE(spi, spi_ids); \ \ -static struct spi_driver fbtft_driver_spi_driver = { \ - .driver = { \ - .name = _name, \ - .of_match_table = dt_ids, \ - }, \ - .id_table = spi_ids, \ - .probe = fbtft_driver_probe_spi, \ - .remove = fbtft_driver_remove_spi, \ -}; \ +FBTFT_SPI_DRIVER(_name, _comp_vend "," _comp_dev, _display, spi_ids) \ \ module_spi_driver(fbtft_driver_spi_driver); -- cgit v1.2.3 From 316f569df766df9a49c36c052ec6afaf19cb6933 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Sun, 23 Jan 2022 18:51:59 +0100 Subject: tpm: st33zp24: Make st33zp24_remove() a void function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Up to now st33zp24_remove() returns zero unconditionally. Make it return no value instead which makes it easier to see in the callers that there is no error to handle. Also the return value of i2c and spi remove callbacks is ignored anyway. Link: https://lore.kernel.org/r/20220104231103.227924-1-u.kleine-koenig@pengutronix.de Signed-off-by: Uwe Kleine-König Acked-by: Lee Jones Link: https://lore.kernel.org/r/20220123175201.34839-4-u.kleine-koenig@pengutronix.de Signed-off-by: Mark Brown --- drivers/char/tpm/st33zp24/i2c.c | 5 +---- drivers/char/tpm/st33zp24/spi.c | 5 +---- drivers/char/tpm/st33zp24/st33zp24.c | 3 +-- drivers/char/tpm/st33zp24/st33zp24.h | 2 +- 4 files changed, 4 insertions(+), 11 deletions(-) diff --git a/drivers/char/tpm/st33zp24/i2c.c b/drivers/char/tpm/st33zp24/i2c.c index 7c617edff4ca..3170d59d660c 100644 --- a/drivers/char/tpm/st33zp24/i2c.c +++ b/drivers/char/tpm/st33zp24/i2c.c @@ -267,11 +267,8 @@ static int st33zp24_i2c_probe(struct i2c_client *client, static int st33zp24_i2c_remove(struct i2c_client *client) { struct tpm_chip *chip = i2c_get_clientdata(client); - int ret; - ret = st33zp24_remove(chip); - if (ret) - return ret; + st33zp24_remove(chip); return 0; } diff --git a/drivers/char/tpm/st33zp24/spi.c b/drivers/char/tpm/st33zp24/spi.c index a75dafd39445..ccd9e42b8eab 100644 --- a/drivers/char/tpm/st33zp24/spi.c +++ b/drivers/char/tpm/st33zp24/spi.c @@ -384,11 +384,8 @@ static int st33zp24_spi_probe(struct spi_device *dev) static int st33zp24_spi_remove(struct spi_device *dev) { struct tpm_chip *chip = spi_get_drvdata(dev); - int ret; - ret = st33zp24_remove(chip); - if (ret) - return ret; + st33zp24_remove(chip); return 0; } diff --git a/drivers/char/tpm/st33zp24/st33zp24.c b/drivers/char/tpm/st33zp24/st33zp24.c index ce9efb73c144..15b393e92c8e 100644 --- a/drivers/char/tpm/st33zp24/st33zp24.c +++ b/drivers/char/tpm/st33zp24/st33zp24.c @@ -511,10 +511,9 @@ _tpm_clean_answer: } EXPORT_SYMBOL(st33zp24_probe); -int st33zp24_remove(struct tpm_chip *chip) +void st33zp24_remove(struct tpm_chip *chip) { tpm_chip_unregister(chip); - return 0; } EXPORT_SYMBOL(st33zp24_remove); diff --git a/drivers/char/tpm/st33zp24/st33zp24.h b/drivers/char/tpm/st33zp24/st33zp24.h index 6747be1e2502..b387a476c555 100644 --- a/drivers/char/tpm/st33zp24/st33zp24.h +++ b/drivers/char/tpm/st33zp24/st33zp24.h @@ -34,5 +34,5 @@ int st33zp24_pm_resume(struct device *dev); int st33zp24_probe(void *phy_id, const struct st33zp24_phy_ops *ops, struct device *dev, int irq, int io_lpcpd); -int st33zp24_remove(struct tpm_chip *chip); +void st33zp24_remove(struct tpm_chip *chip); #endif /* __LOCAL_ST33ZP24_H__ */ -- cgit v1.2.3 From afb0a80e63d67e957b5d0eb4ade301aff6e13c8c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Sun, 23 Jan 2022 18:52:00 +0100 Subject: platform/chrome: cros_ec: Make cros_ec_unregister() return void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Up to now cros_ec_unregister() returns zero unconditionally. Make it return void instead which makes it easier to see in the callers that there is no error to handle. Also the return value of i2c, platform and spi remove callbacks is ignored anyway. Reviewed-by: Guenter Roeck Link: https://lore.kernel.org/r/20211020071753.wltjslmimb6wtlp5@pengutronix.de Signed-off-by: Uwe Kleine-König Acked-by: Lee Jones Link: https://lore.kernel.org/r/20220123175201.34839-5-u.kleine-koenig@pengutronix.de Signed-off-by: Mark Brown --- drivers/platform/chrome/cros_ec.c | 4 +--- drivers/platform/chrome/cros_ec.h | 2 +- drivers/platform/chrome/cros_ec_i2c.c | 4 +++- drivers/platform/chrome/cros_ec_lpc.c | 4 +++- drivers/platform/chrome/cros_ec_spi.c | 4 +++- 5 files changed, 11 insertions(+), 7 deletions(-) diff --git a/drivers/platform/chrome/cros_ec.c b/drivers/platform/chrome/cros_ec.c index fc5aa1525d13..d49a4efe46c8 100644 --- a/drivers/platform/chrome/cros_ec.c +++ b/drivers/platform/chrome/cros_ec.c @@ -302,13 +302,11 @@ EXPORT_SYMBOL(cros_ec_register); * * Return: 0 on success or negative error code. */ -int cros_ec_unregister(struct cros_ec_device *ec_dev) +void cros_ec_unregister(struct cros_ec_device *ec_dev) { if (ec_dev->pd) platform_device_unregister(ec_dev->pd); platform_device_unregister(ec_dev->ec); - - return 0; } EXPORT_SYMBOL(cros_ec_unregister); diff --git a/drivers/platform/chrome/cros_ec.h b/drivers/platform/chrome/cros_ec.h index 78363dcfdf23..bbca0096868a 100644 --- a/drivers/platform/chrome/cros_ec.h +++ b/drivers/platform/chrome/cros_ec.h @@ -11,7 +11,7 @@ #include int cros_ec_register(struct cros_ec_device *ec_dev); -int cros_ec_unregister(struct cros_ec_device *ec_dev); +void cros_ec_unregister(struct cros_ec_device *ec_dev); int cros_ec_suspend(struct cros_ec_device *ec_dev); int cros_ec_resume(struct cros_ec_device *ec_dev); diff --git a/drivers/platform/chrome/cros_ec_i2c.c b/drivers/platform/chrome/cros_ec_i2c.c index 30c8938c27d5..22feb0fd4ce7 100644 --- a/drivers/platform/chrome/cros_ec_i2c.c +++ b/drivers/platform/chrome/cros_ec_i2c.c @@ -313,7 +313,9 @@ static int cros_ec_i2c_remove(struct i2c_client *client) { struct cros_ec_device *ec_dev = i2c_get_clientdata(client); - return cros_ec_unregister(ec_dev); + cros_ec_unregister(ec_dev); + + return 0; } #ifdef CONFIG_PM_SLEEP diff --git a/drivers/platform/chrome/cros_ec_lpc.c b/drivers/platform/chrome/cros_ec_lpc.c index d6306d2a096f..7651417b4a25 100644 --- a/drivers/platform/chrome/cros_ec_lpc.c +++ b/drivers/platform/chrome/cros_ec_lpc.c @@ -439,7 +439,9 @@ static int cros_ec_lpc_remove(struct platform_device *pdev) acpi_remove_notify_handler(adev->handle, ACPI_ALL_NOTIFY, cros_ec_lpc_acpi_notify); - return cros_ec_unregister(ec_dev); + cros_ec_unregister(ec_dev); + + return 0; } static const struct acpi_device_id cros_ec_lpc_acpi_device_ids[] = { diff --git a/drivers/platform/chrome/cros_ec_spi.c b/drivers/platform/chrome/cros_ec_spi.c index 14c4046fa04d..713c58687721 100644 --- a/drivers/platform/chrome/cros_ec_spi.c +++ b/drivers/platform/chrome/cros_ec_spi.c @@ -790,7 +790,9 @@ static int cros_ec_spi_remove(struct spi_device *spi) { struct cros_ec_device *ec_dev = spi_get_drvdata(spi); - return cros_ec_unregister(ec_dev); + cros_ec_unregister(ec_dev); + + return 0; } #ifdef CONFIG_PM_SLEEP -- cgit v1.2.3 From a0386bba70934d42f586eaf68b21d5eeaffa7bd0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Sun, 23 Jan 2022 18:52:01 +0100 Subject: spi: make remove callback a void function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The value returned by an spi driver's remove function is mostly ignored. (Only an error message is printed if the value is non-zero that the error is ignored.) So change the prototype of the remove function to return no value. This way driver authors are not tempted to assume that passing an error to the upper layer is a good idea. All drivers are adapted accordingly. There is no intended change of behaviour, all callbacks were prepared to return 0 before. Signed-off-by: Uwe Kleine-König Acked-by: Marc Kleine-Budde Acked-by: Andy Shevchenko Reviewed-by: Geert Uytterhoeven Acked-by: Jérôme Pouiller Acked-by: Miquel Raynal Acked-by: Jonathan Cameron Acked-by: Claudius Heine Acked-by: Stefan Schmidt Acked-by: Alexandre Belloni Acked-by: Ulf Hansson # For MMC Acked-by: Marcus Folkesson Acked-by: Łukasz Stelmach Acked-by: Lee Jones Link: https://lore.kernel.org/r/20220123175201.34839-6-u.kleine-koenig@pengutronix.de Signed-off-by: Mark Brown --- drivers/bus/moxtet.c | 4 +--- drivers/char/tpm/st33zp24/spi.c | 4 +--- drivers/char/tpm/tpm_tis_spi_main.c | 3 +-- drivers/clk/clk-lmk04832.c | 4 +--- drivers/gpio/gpio-74x164.c | 4 +--- drivers/gpio/gpio-max3191x.c | 4 +--- drivers/gpio/gpio-max7301.c | 4 +--- drivers/gpio/gpio-mc33880.c | 4 +--- drivers/gpio/gpio-pisosr.c | 4 +--- drivers/gpu/drm/panel/panel-abt-y030xx067a.c | 4 +--- drivers/gpu/drm/panel/panel-ilitek-ili9322.c | 4 +--- drivers/gpu/drm/panel/panel-ilitek-ili9341.c | 3 +-- drivers/gpu/drm/panel/panel-innolux-ej030na.c | 4 +--- drivers/gpu/drm/panel/panel-lg-lb035q02.c | 4 +--- drivers/gpu/drm/panel/panel-lg-lg4573.c | 4 +--- drivers/gpu/drm/panel/panel-nec-nl8048hl11.c | 4 +--- drivers/gpu/drm/panel/panel-novatek-nt39016.c | 4 +--- drivers/gpu/drm/panel/panel-samsung-db7430.c | 3 +-- drivers/gpu/drm/panel/panel-samsung-ld9040.c | 4 +--- drivers/gpu/drm/panel/panel-samsung-s6d27a1.c | 3 +-- drivers/gpu/drm/panel/panel-samsung-s6e63m0-spi.c | 3 +-- drivers/gpu/drm/panel/panel-sitronix-st7789v.c | 4 +--- drivers/gpu/drm/panel/panel-sony-acx565akm.c | 4 +--- drivers/gpu/drm/panel/panel-tpo-td028ttec1.c | 4 +--- drivers/gpu/drm/panel/panel-tpo-td043mtea1.c | 4 +--- drivers/gpu/drm/panel/panel-tpo-tpg110.c | 3 +-- drivers/gpu/drm/panel/panel-widechips-ws2401.c | 3 +-- drivers/gpu/drm/tiny/hx8357d.c | 4 +--- drivers/gpu/drm/tiny/ili9163.c | 4 +--- drivers/gpu/drm/tiny/ili9225.c | 4 +--- drivers/gpu/drm/tiny/ili9341.c | 4 +--- drivers/gpu/drm/tiny/ili9486.c | 4 +--- drivers/gpu/drm/tiny/mi0283qt.c | 4 +--- drivers/gpu/drm/tiny/repaper.c | 4 +--- drivers/gpu/drm/tiny/st7586.c | 4 +--- drivers/gpu/drm/tiny/st7735r.c | 4 +--- drivers/hwmon/adcxx.c | 4 +--- drivers/hwmon/adt7310.c | 3 +-- drivers/hwmon/max1111.c | 3 +-- drivers/hwmon/max31722.c | 4 +--- drivers/iio/accel/bma400_spi.c | 4 +--- drivers/iio/accel/bmc150-accel-spi.c | 4 +--- drivers/iio/accel/bmi088-accel-spi.c | 4 +--- drivers/iio/accel/kxsd9-spi.c | 4 +--- drivers/iio/accel/mma7455_spi.c | 4 +--- drivers/iio/accel/sca3000.c | 4 +--- drivers/iio/adc/ad7266.c | 4 +--- drivers/iio/adc/ltc2496.c | 4 +--- drivers/iio/adc/mcp320x.c | 4 +--- drivers/iio/adc/mcp3911.c | 4 +--- drivers/iio/adc/ti-adc12138.c | 4 +--- drivers/iio/adc/ti-ads7950.c | 4 +--- drivers/iio/adc/ti-ads8688.c | 4 +--- drivers/iio/adc/ti-tlc4541.c | 4 +--- drivers/iio/amplifiers/ad8366.c | 4 +--- drivers/iio/common/ssp_sensors/ssp_dev.c | 4 +--- drivers/iio/dac/ad5360.c | 4 +--- drivers/iio/dac/ad5380.c | 4 +--- drivers/iio/dac/ad5446.c | 4 +--- drivers/iio/dac/ad5449.c | 4 +--- drivers/iio/dac/ad5504.c | 4 +--- drivers/iio/dac/ad5592r.c | 4 +--- drivers/iio/dac/ad5624r_spi.c | 4 +--- drivers/iio/dac/ad5686-spi.c | 4 +--- drivers/iio/dac/ad5761.c | 4 +--- drivers/iio/dac/ad5764.c | 4 +--- drivers/iio/dac/ad5791.c | 4 +--- drivers/iio/dac/ad8801.c | 4 +--- drivers/iio/dac/ltc1660.c | 4 +--- drivers/iio/dac/ltc2632.c | 4 +--- drivers/iio/dac/mcp4922.c | 4 +--- drivers/iio/dac/ti-dac082s085.c | 4 +--- drivers/iio/dac/ti-dac7311.c | 3 +-- drivers/iio/frequency/adf4350.c | 4 +--- drivers/iio/gyro/bmg160_spi.c | 4 +--- drivers/iio/gyro/fxas21002c_spi.c | 4 +--- drivers/iio/health/afe4403.c | 4 +--- drivers/iio/magnetometer/bmc150_magn_spi.c | 4 +--- drivers/iio/magnetometer/hmc5843_spi.c | 4 +--- drivers/iio/potentiometer/max5487.c | 4 +--- drivers/iio/pressure/ms5611_spi.c | 4 +--- drivers/iio/pressure/zpa2326_spi.c | 4 +--- drivers/input/keyboard/applespi.c | 4 +--- drivers/input/misc/adxl34x-spi.c | 4 +--- drivers/input/touchscreen/ads7846.c | 4 +--- drivers/input/touchscreen/cyttsp4_spi.c | 4 +--- drivers/input/touchscreen/tsc2005.c | 4 +--- drivers/leds/leds-cr0014114.c | 4 +--- drivers/leds/leds-dac124s085.c | 4 +--- drivers/leds/leds-el15203000.c | 4 +--- drivers/leds/leds-spi-byte.c | 4 +--- drivers/media/spi/cxd2880-spi.c | 4 +--- drivers/media/spi/gs1662.c | 4 +--- drivers/media/tuners/msi001.c | 3 +-- drivers/mfd/arizona-spi.c | 4 +--- drivers/mfd/da9052-spi.c | 3 +-- drivers/mfd/ezx-pcap.c | 4 +--- drivers/mfd/madera-spi.c | 4 +--- drivers/mfd/mc13xxx-spi.c | 3 +-- drivers/mfd/rsmu_spi.c | 4 +--- drivers/mfd/stmpe-spi.c | 4 +--- drivers/mfd/tps65912-spi.c | 4 +--- drivers/misc/ad525x_dpot-spi.c | 3 +-- drivers/misc/eeprom/eeprom_93xx46.c | 4 +--- drivers/misc/lattice-ecp3-config.c | 4 +--- drivers/misc/lis3lv02d/lis3lv02d_spi.c | 4 +--- drivers/mmc/host/mmc_spi.c | 3 +-- drivers/mtd/devices/mchp23k256.c | 4 +--- drivers/mtd/devices/mchp48l640.c | 4 +--- drivers/mtd/devices/mtd_dataflash.c | 4 +--- drivers/mtd/devices/sst25l.c | 4 +--- drivers/net/can/m_can/tcan4x5x-core.c | 4 +--- drivers/net/can/spi/hi311x.c | 4 +--- drivers/net/can/spi/mcp251x.c | 4 +--- drivers/net/can/spi/mcp251xfd/mcp251xfd-core.c | 4 +--- drivers/net/dsa/b53/b53_spi.c | 4 +--- drivers/net/dsa/microchip/ksz8795_spi.c | 4 +--- drivers/net/dsa/microchip/ksz9477_spi.c | 4 +--- drivers/net/dsa/sja1105/sja1105_main.c | 6 ++---- drivers/net/dsa/vitesse-vsc73xx-spi.c | 6 ++---- drivers/net/ethernet/asix/ax88796c_main.c | 4 +--- drivers/net/ethernet/micrel/ks8851_spi.c | 4 +--- drivers/net/ethernet/microchip/enc28j60.c | 4 +--- drivers/net/ethernet/microchip/encx24j600.c | 4 +--- drivers/net/ethernet/qualcomm/qca_spi.c | 4 +--- drivers/net/ethernet/vertexcom/mse102x.c | 4 +--- drivers/net/ethernet/wiznet/w5100-spi.c | 4 +--- drivers/net/ieee802154/adf7242.c | 4 +--- drivers/net/ieee802154/at86rf230.c | 4 +--- drivers/net/ieee802154/ca8210.c | 6 ++---- drivers/net/ieee802154/cc2520.c | 4 +--- drivers/net/ieee802154/mcr20a.c | 4 +--- drivers/net/ieee802154/mrf24j40.c | 4 +--- drivers/net/phy/spi_ks8995.c | 4 +--- drivers/net/wan/slic_ds26522.c | 3 +-- drivers/net/wireless/intersil/p54/p54spi.c | 4 +--- drivers/net/wireless/marvell/libertas/if_spi.c | 4 +--- drivers/net/wireless/microchip/wilc1000/spi.c | 4 +--- drivers/net/wireless/st/cw1200/cw1200_spi.c | 4 +--- drivers/net/wireless/ti/wl1251/spi.c | 4 +--- drivers/net/wireless/ti/wlcore/spi.c | 4 +--- drivers/nfc/nfcmrvl/spi.c | 3 +-- drivers/nfc/st-nci/spi.c | 4 +--- drivers/nfc/st95hf/core.c | 4 +--- drivers/nfc/trf7970a.c | 4 +--- drivers/platform/chrome/cros_ec_spi.c | 4 +--- drivers/platform/olpc/olpc-xo175-ec.c | 4 +--- drivers/rtc/rtc-ds1302.c | 3 +-- drivers/rtc/rtc-ds1305.c | 4 +--- drivers/rtc/rtc-ds1343.c | 4 +--- drivers/spi/spi-mem.c | 6 ++---- drivers/spi/spi-slave-system-control.c | 3 +-- drivers/spi/spi-slave-time.c | 3 +-- drivers/spi/spi-tle62x0.c | 3 +-- drivers/spi/spi.c | 11 ++--------- drivers/spi/spidev.c | 4 +--- drivers/staging/fbtft/fbtft.h | 3 +-- drivers/staging/pi433/pi433_if.c | 4 +--- drivers/staging/wfx/bus_spi.c | 3 +-- drivers/tty/serial/max3100.c | 5 ++--- drivers/tty/serial/max310x.c | 3 +-- drivers/tty/serial/sc16is7xx.c | 4 +--- drivers/usb/gadget/udc/max3420_udc.c | 4 +--- drivers/usb/host/max3421-hcd.c | 3 +-- drivers/video/backlight/ams369fg06.c | 3 +-- drivers/video/backlight/corgi_lcd.c | 3 +-- drivers/video/backlight/ili922x.c | 3 +-- drivers/video/backlight/l4f00242t03.c | 3 +-- drivers/video/backlight/lms501kf03.c | 3 +-- drivers/video/backlight/ltv350qv.c | 3 +-- drivers/video/backlight/tdo24m.c | 3 +-- drivers/video/backlight/tosa_lcd.c | 4 +--- drivers/video/backlight/vgg2432a4.c | 4 +--- drivers/video/fbdev/omap/lcd_mipid.c | 4 +--- .../fbdev/omap2/omapfb/displays/panel-lgphilips-lb035q02.c | 4 +--- .../video/fbdev/omap2/omapfb/displays/panel-nec-nl8048hl11.c | 4 +--- .../video/fbdev/omap2/omapfb/displays/panel-sony-acx565akm.c | 4 +--- .../video/fbdev/omap2/omapfb/displays/panel-tpo-td028ttec1.c | 4 +--- .../video/fbdev/omap2/omapfb/displays/panel-tpo-td043mtea1.c | 4 +--- include/linux/spi/spi.h | 2 +- sound/pci/hda/cs35l41_hda_spi.c | 4 +--- sound/soc/codecs/adau1761-spi.c | 3 +-- sound/soc/codecs/adau1781-spi.c | 3 +-- sound/soc/codecs/cs35l41-spi.c | 4 +--- sound/soc/codecs/pcm3168a-spi.c | 4 +--- sound/soc/codecs/pcm512x-spi.c | 3 +-- sound/soc/codecs/tlv320aic32x4-spi.c | 4 +--- sound/soc/codecs/tlv320aic3x-spi.c | 4 +--- sound/soc/codecs/wm0010.c | 4 +--- sound/soc/codecs/wm8804-spi.c | 3 +-- sound/spi/at73c213.c | 4 +--- 191 files changed, 197 insertions(+), 545 deletions(-) diff --git a/drivers/bus/moxtet.c b/drivers/bus/moxtet.c index fd87a59837fa..5eb0fe73ddc4 100644 --- a/drivers/bus/moxtet.c +++ b/drivers/bus/moxtet.c @@ -815,7 +815,7 @@ static int moxtet_probe(struct spi_device *spi) return 0; } -static int moxtet_remove(struct spi_device *spi) +static void moxtet_remove(struct spi_device *spi) { struct moxtet *moxtet = spi_get_drvdata(spi); @@ -828,8 +828,6 @@ static int moxtet_remove(struct spi_device *spi) device_for_each_child(moxtet->dev, NULL, __unregister); mutex_destroy(&moxtet->lock); - - return 0; } static const struct of_device_id moxtet_dt_ids[] = { diff --git a/drivers/char/tpm/st33zp24/spi.c b/drivers/char/tpm/st33zp24/spi.c index ccd9e42b8eab..22d184884694 100644 --- a/drivers/char/tpm/st33zp24/spi.c +++ b/drivers/char/tpm/st33zp24/spi.c @@ -381,13 +381,11 @@ static int st33zp24_spi_probe(struct spi_device *dev) * @param: client, the spi_device description (TPM SPI description). * @return: 0 in case of success. */ -static int st33zp24_spi_remove(struct spi_device *dev) +static void st33zp24_spi_remove(struct spi_device *dev) { struct tpm_chip *chip = spi_get_drvdata(dev); st33zp24_remove(chip); - - return 0; } static const struct spi_device_id st33zp24_spi_id[] = { diff --git a/drivers/char/tpm/tpm_tis_spi_main.c b/drivers/char/tpm/tpm_tis_spi_main.c index aaa59a00eeae..184396b3af50 100644 --- a/drivers/char/tpm/tpm_tis_spi_main.c +++ b/drivers/char/tpm/tpm_tis_spi_main.c @@ -254,13 +254,12 @@ static int tpm_tis_spi_driver_probe(struct spi_device *spi) static SIMPLE_DEV_PM_OPS(tpm_tis_pm, tpm_pm_suspend, tpm_tis_spi_resume); -static int tpm_tis_spi_remove(struct spi_device *dev) +static void tpm_tis_spi_remove(struct spi_device *dev) { struct tpm_chip *chip = spi_get_drvdata(dev); tpm_chip_unregister(chip); tpm_tis_remove(chip); - return 0; } static const struct spi_device_id tpm_tis_spi_id[] = { diff --git a/drivers/clk/clk-lmk04832.c b/drivers/clk/clk-lmk04832.c index 8f02c0b88000..f416f8bc2898 100644 --- a/drivers/clk/clk-lmk04832.c +++ b/drivers/clk/clk-lmk04832.c @@ -1544,14 +1544,12 @@ err_disable_oscin: return ret; } -static int lmk04832_remove(struct spi_device *spi) +static void lmk04832_remove(struct spi_device *spi) { struct lmk04832 *lmk = spi_get_drvdata(spi); clk_disable_unprepare(lmk->oscin); of_clk_del_provider(spi->dev.of_node); - - return 0; } static const struct spi_device_id lmk04832_id[] = { { "lmk04832", LMK04832 }, diff --git a/drivers/gpio/gpio-74x164.c b/drivers/gpio/gpio-74x164.c index 4a55cdf089d6..e00c33310517 100644 --- a/drivers/gpio/gpio-74x164.c +++ b/drivers/gpio/gpio-74x164.c @@ -163,15 +163,13 @@ exit_destroy: return ret; } -static int gen_74x164_remove(struct spi_device *spi) +static void gen_74x164_remove(struct spi_device *spi) { struct gen_74x164_chip *chip = spi_get_drvdata(spi); gpiod_set_value_cansleep(chip->gpiod_oe, 0); gpiochip_remove(&chip->gpio_chip); mutex_destroy(&chip->lock); - - return 0; } static const struct spi_device_id gen_74x164_spi_ids[] = { diff --git a/drivers/gpio/gpio-max3191x.c b/drivers/gpio/gpio-max3191x.c index 51cd6f98d1c7..161c4751c5f7 100644 --- a/drivers/gpio/gpio-max3191x.c +++ b/drivers/gpio/gpio-max3191x.c @@ -443,14 +443,12 @@ static int max3191x_probe(struct spi_device *spi) return 0; } -static int max3191x_remove(struct spi_device *spi) +static void max3191x_remove(struct spi_device *spi) { struct max3191x_chip *max3191x = spi_get_drvdata(spi); gpiochip_remove(&max3191x->gpio); mutex_destroy(&max3191x->lock); - - return 0; } static int __init max3191x_register_driver(struct spi_driver *sdrv) diff --git a/drivers/gpio/gpio-max7301.c b/drivers/gpio/gpio-max7301.c index 5862d73bf325..11813f41d460 100644 --- a/drivers/gpio/gpio-max7301.c +++ b/drivers/gpio/gpio-max7301.c @@ -64,11 +64,9 @@ static int max7301_probe(struct spi_device *spi) return ret; } -static int max7301_remove(struct spi_device *spi) +static void max7301_remove(struct spi_device *spi) { __max730x_remove(&spi->dev); - - return 0; } static const struct spi_device_id max7301_id[] = { diff --git a/drivers/gpio/gpio-mc33880.c b/drivers/gpio/gpio-mc33880.c index 31d2be1bebc8..cd9b16dbe1a9 100644 --- a/drivers/gpio/gpio-mc33880.c +++ b/drivers/gpio/gpio-mc33880.c @@ -134,7 +134,7 @@ exit_destroy: return ret; } -static int mc33880_remove(struct spi_device *spi) +static void mc33880_remove(struct spi_device *spi) { struct mc33880 *mc; @@ -142,8 +142,6 @@ static int mc33880_remove(struct spi_device *spi) gpiochip_remove(&mc->chip); mutex_destroy(&mc->lock); - - return 0; } static struct spi_driver mc33880_driver = { diff --git a/drivers/gpio/gpio-pisosr.c b/drivers/gpio/gpio-pisosr.c index 8e04054cf07e..81a47ae09ff8 100644 --- a/drivers/gpio/gpio-pisosr.c +++ b/drivers/gpio/gpio-pisosr.c @@ -163,15 +163,13 @@ static int pisosr_gpio_probe(struct spi_device *spi) return 0; } -static int pisosr_gpio_remove(struct spi_device *spi) +static void pisosr_gpio_remove(struct spi_device *spi) { struct pisosr_gpio *gpio = spi_get_drvdata(spi); gpiochip_remove(&gpio->chip); mutex_destroy(&gpio->lock); - - return 0; } static const struct spi_device_id pisosr_gpio_id_table[] = { diff --git a/drivers/gpu/drm/panel/panel-abt-y030xx067a.c b/drivers/gpu/drm/panel/panel-abt-y030xx067a.c index f043b484055b..ed626fdc08e8 100644 --- a/drivers/gpu/drm/panel/panel-abt-y030xx067a.c +++ b/drivers/gpu/drm/panel/panel-abt-y030xx067a.c @@ -293,15 +293,13 @@ static int y030xx067a_probe(struct spi_device *spi) return 0; } -static int y030xx067a_remove(struct spi_device *spi) +static void y030xx067a_remove(struct spi_device *spi) { struct y030xx067a *priv = spi_get_drvdata(spi); drm_panel_remove(&priv->panel); drm_panel_disable(&priv->panel); drm_panel_unprepare(&priv->panel); - - return 0; } static const struct drm_display_mode y030xx067a_modes[] = { diff --git a/drivers/gpu/drm/panel/panel-ilitek-ili9322.c b/drivers/gpu/drm/panel/panel-ilitek-ili9322.c index 8e84df9a0033..3dfafa585127 100644 --- a/drivers/gpu/drm/panel/panel-ilitek-ili9322.c +++ b/drivers/gpu/drm/panel/panel-ilitek-ili9322.c @@ -896,14 +896,12 @@ static int ili9322_probe(struct spi_device *spi) return 0; } -static int ili9322_remove(struct spi_device *spi) +static void ili9322_remove(struct spi_device *spi) { struct ili9322 *ili = spi_get_drvdata(spi); ili9322_power_off(ili); drm_panel_remove(&ili->panel); - - return 0; } /* diff --git a/drivers/gpu/drm/panel/panel-ilitek-ili9341.c b/drivers/gpu/drm/panel/panel-ilitek-ili9341.c index 2c3378a259b1..a07ef26234e5 100644 --- a/drivers/gpu/drm/panel/panel-ilitek-ili9341.c +++ b/drivers/gpu/drm/panel/panel-ilitek-ili9341.c @@ -728,7 +728,7 @@ static int ili9341_probe(struct spi_device *spi) return -1; } -static int ili9341_remove(struct spi_device *spi) +static void ili9341_remove(struct spi_device *spi) { const struct spi_device_id *id = spi_get_device_id(spi); struct ili9341 *ili = spi_get_drvdata(spi); @@ -741,7 +741,6 @@ static int ili9341_remove(struct spi_device *spi) drm_dev_unplug(drm); drm_atomic_helper_shutdown(drm); } - return 0; } static void ili9341_shutdown(struct spi_device *spi) diff --git a/drivers/gpu/drm/panel/panel-innolux-ej030na.c b/drivers/gpu/drm/panel/panel-innolux-ej030na.c index c558de3f99be..e3b1daa0cb72 100644 --- a/drivers/gpu/drm/panel/panel-innolux-ej030na.c +++ b/drivers/gpu/drm/panel/panel-innolux-ej030na.c @@ -219,15 +219,13 @@ static int ej030na_probe(struct spi_device *spi) return 0; } -static int ej030na_remove(struct spi_device *spi) +static void ej030na_remove(struct spi_device *spi) { struct ej030na *priv = spi_get_drvdata(spi); drm_panel_remove(&priv->panel); drm_panel_disable(&priv->panel); drm_panel_unprepare(&priv->panel); - - return 0; } static const struct drm_display_mode ej030na_modes[] = { diff --git a/drivers/gpu/drm/panel/panel-lg-lb035q02.c b/drivers/gpu/drm/panel/panel-lg-lb035q02.c index f3183b68704f..9d0d4faa3f58 100644 --- a/drivers/gpu/drm/panel/panel-lg-lb035q02.c +++ b/drivers/gpu/drm/panel/panel-lg-lb035q02.c @@ -203,14 +203,12 @@ static int lb035q02_probe(struct spi_device *spi) return 0; } -static int lb035q02_remove(struct spi_device *spi) +static void lb035q02_remove(struct spi_device *spi) { struct lb035q02_device *lcd = spi_get_drvdata(spi); drm_panel_remove(&lcd->panel); drm_panel_disable(&lcd->panel); - - return 0; } static const struct of_device_id lb035q02_of_match[] = { diff --git a/drivers/gpu/drm/panel/panel-lg-lg4573.c b/drivers/gpu/drm/panel/panel-lg-lg4573.c index 8e5160af1de5..cf246d15b7b6 100644 --- a/drivers/gpu/drm/panel/panel-lg-lg4573.c +++ b/drivers/gpu/drm/panel/panel-lg-lg4573.c @@ -266,14 +266,12 @@ static int lg4573_probe(struct spi_device *spi) return 0; } -static int lg4573_remove(struct spi_device *spi) +static void lg4573_remove(struct spi_device *spi) { struct lg4573 *ctx = spi_get_drvdata(spi); lg4573_display_off(ctx); drm_panel_remove(&ctx->panel); - - return 0; } static const struct of_device_id lg4573_of_match[] = { diff --git a/drivers/gpu/drm/panel/panel-nec-nl8048hl11.c b/drivers/gpu/drm/panel/panel-nec-nl8048hl11.c index 6e5ab1debc8b..81c5c541a351 100644 --- a/drivers/gpu/drm/panel/panel-nec-nl8048hl11.c +++ b/drivers/gpu/drm/panel/panel-nec-nl8048hl11.c @@ -212,15 +212,13 @@ static int nl8048_probe(struct spi_device *spi) return 0; } -static int nl8048_remove(struct spi_device *spi) +static void nl8048_remove(struct spi_device *spi) { struct nl8048_panel *lcd = spi_get_drvdata(spi); drm_panel_remove(&lcd->panel); drm_panel_disable(&lcd->panel); drm_panel_unprepare(&lcd->panel); - - return 0; } static const struct of_device_id nl8048_of_match[] = { diff --git a/drivers/gpu/drm/panel/panel-novatek-nt39016.c b/drivers/gpu/drm/panel/panel-novatek-nt39016.c index d036853db865..f58cfb10b58a 100644 --- a/drivers/gpu/drm/panel/panel-novatek-nt39016.c +++ b/drivers/gpu/drm/panel/panel-novatek-nt39016.c @@ -292,7 +292,7 @@ static int nt39016_probe(struct spi_device *spi) return 0; } -static int nt39016_remove(struct spi_device *spi) +static void nt39016_remove(struct spi_device *spi) { struct nt39016 *panel = spi_get_drvdata(spi); @@ -300,8 +300,6 @@ static int nt39016_remove(struct spi_device *spi) nt39016_disable(&panel->drm_panel); nt39016_unprepare(&panel->drm_panel); - - return 0; } static const struct drm_display_mode kd035g6_display_modes[] = { diff --git a/drivers/gpu/drm/panel/panel-samsung-db7430.c b/drivers/gpu/drm/panel/panel-samsung-db7430.c index ead479719f00..04640c5256a8 100644 --- a/drivers/gpu/drm/panel/panel-samsung-db7430.c +++ b/drivers/gpu/drm/panel/panel-samsung-db7430.c @@ -314,12 +314,11 @@ static int db7430_probe(struct spi_device *spi) return 0; } -static int db7430_remove(struct spi_device *spi) +static void db7430_remove(struct spi_device *spi) { struct db7430 *db = spi_get_drvdata(spi); drm_panel_remove(&db->panel); - return 0; } /* diff --git a/drivers/gpu/drm/panel/panel-samsung-ld9040.c b/drivers/gpu/drm/panel/panel-samsung-ld9040.c index c4b388850a13..01eb211f32f7 100644 --- a/drivers/gpu/drm/panel/panel-samsung-ld9040.c +++ b/drivers/gpu/drm/panel/panel-samsung-ld9040.c @@ -358,14 +358,12 @@ static int ld9040_probe(struct spi_device *spi) return 0; } -static int ld9040_remove(struct spi_device *spi) +static void ld9040_remove(struct spi_device *spi) { struct ld9040 *ctx = spi_get_drvdata(spi); ld9040_power_off(ctx); drm_panel_remove(&ctx->panel); - - return 0; } static const struct of_device_id ld9040_of_match[] = { diff --git a/drivers/gpu/drm/panel/panel-samsung-s6d27a1.c b/drivers/gpu/drm/panel/panel-samsung-s6d27a1.c index 1696ceb36aa0..2adb223a895c 100644 --- a/drivers/gpu/drm/panel/panel-samsung-s6d27a1.c +++ b/drivers/gpu/drm/panel/panel-samsung-s6d27a1.c @@ -291,12 +291,11 @@ static int s6d27a1_probe(struct spi_device *spi) return 0; } -static int s6d27a1_remove(struct spi_device *spi) +static void s6d27a1_remove(struct spi_device *spi) { struct s6d27a1 *ctx = spi_get_drvdata(spi); drm_panel_remove(&ctx->panel); - return 0; } static const struct of_device_id s6d27a1_match[] = { diff --git a/drivers/gpu/drm/panel/panel-samsung-s6e63m0-spi.c b/drivers/gpu/drm/panel/panel-samsung-s6e63m0-spi.c index c178d962b0d5..d99afcc672ca 100644 --- a/drivers/gpu/drm/panel/panel-samsung-s6e63m0-spi.c +++ b/drivers/gpu/drm/panel/panel-samsung-s6e63m0-spi.c @@ -62,10 +62,9 @@ static int s6e63m0_spi_probe(struct spi_device *spi) s6e63m0_spi_dcs_write, false); } -static int s6e63m0_spi_remove(struct spi_device *spi) +static void s6e63m0_spi_remove(struct spi_device *spi) { s6e63m0_remove(&spi->dev); - return 0; } static const struct of_device_id s6e63m0_spi_of_match[] = { diff --git a/drivers/gpu/drm/panel/panel-sitronix-st7789v.c b/drivers/gpu/drm/panel/panel-sitronix-st7789v.c index 61e565524542..bbc4569cbcdc 100644 --- a/drivers/gpu/drm/panel/panel-sitronix-st7789v.c +++ b/drivers/gpu/drm/panel/panel-sitronix-st7789v.c @@ -387,13 +387,11 @@ static int st7789v_probe(struct spi_device *spi) return 0; } -static int st7789v_remove(struct spi_device *spi) +static void st7789v_remove(struct spi_device *spi) { struct st7789v *ctx = spi_get_drvdata(spi); drm_panel_remove(&ctx->panel); - - return 0; } static const struct of_device_id st7789v_of_match[] = { diff --git a/drivers/gpu/drm/panel/panel-sony-acx565akm.c b/drivers/gpu/drm/panel/panel-sony-acx565akm.c index ba0b3ead150f..0d7541a33f87 100644 --- a/drivers/gpu/drm/panel/panel-sony-acx565akm.c +++ b/drivers/gpu/drm/panel/panel-sony-acx565akm.c @@ -655,7 +655,7 @@ static int acx565akm_probe(struct spi_device *spi) return 0; } -static int acx565akm_remove(struct spi_device *spi) +static void acx565akm_remove(struct spi_device *spi) { struct acx565akm_panel *lcd = spi_get_drvdata(spi); @@ -666,8 +666,6 @@ static int acx565akm_remove(struct spi_device *spi) drm_panel_disable(&lcd->panel); drm_panel_unprepare(&lcd->panel); - - return 0; } static const struct of_device_id acx565akm_of_match[] = { diff --git a/drivers/gpu/drm/panel/panel-tpo-td028ttec1.c b/drivers/gpu/drm/panel/panel-tpo-td028ttec1.c index ba0c00d1a001..4dbf8b88f264 100644 --- a/drivers/gpu/drm/panel/panel-tpo-td028ttec1.c +++ b/drivers/gpu/drm/panel/panel-tpo-td028ttec1.c @@ -350,15 +350,13 @@ static int td028ttec1_probe(struct spi_device *spi) return 0; } -static int td028ttec1_remove(struct spi_device *spi) +static void td028ttec1_remove(struct spi_device *spi) { struct td028ttec1_panel *lcd = spi_get_drvdata(spi); drm_panel_remove(&lcd->panel); drm_panel_disable(&lcd->panel); drm_panel_unprepare(&lcd->panel); - - return 0; } static const struct of_device_id td028ttec1_of_match[] = { diff --git a/drivers/gpu/drm/panel/panel-tpo-td043mtea1.c b/drivers/gpu/drm/panel/panel-tpo-td043mtea1.c index 1866cdb8f9c1..cf4609bb9b1d 100644 --- a/drivers/gpu/drm/panel/panel-tpo-td043mtea1.c +++ b/drivers/gpu/drm/panel/panel-tpo-td043mtea1.c @@ -463,7 +463,7 @@ static int td043mtea1_probe(struct spi_device *spi) return 0; } -static int td043mtea1_remove(struct spi_device *spi) +static void td043mtea1_remove(struct spi_device *spi) { struct td043mtea1_panel *lcd = spi_get_drvdata(spi); @@ -472,8 +472,6 @@ static int td043mtea1_remove(struct spi_device *spi) drm_panel_unprepare(&lcd->panel); sysfs_remove_group(&spi->dev.kobj, &td043mtea1_attr_group); - - return 0; } static const struct of_device_id td043mtea1_of_match[] = { diff --git a/drivers/gpu/drm/panel/panel-tpo-tpg110.c b/drivers/gpu/drm/panel/panel-tpo-tpg110.c index e3791dad6830..0b1f5a11a055 100644 --- a/drivers/gpu/drm/panel/panel-tpo-tpg110.c +++ b/drivers/gpu/drm/panel/panel-tpo-tpg110.c @@ -450,12 +450,11 @@ static int tpg110_probe(struct spi_device *spi) return 0; } -static int tpg110_remove(struct spi_device *spi) +static void tpg110_remove(struct spi_device *spi) { struct tpg110 *tpg = spi_get_drvdata(spi); drm_panel_remove(&tpg->panel); - return 0; } static const struct of_device_id tpg110_match[] = { diff --git a/drivers/gpu/drm/panel/panel-widechips-ws2401.c b/drivers/gpu/drm/panel/panel-widechips-ws2401.c index 8bc976f54b80..236f3cb2b594 100644 --- a/drivers/gpu/drm/panel/panel-widechips-ws2401.c +++ b/drivers/gpu/drm/panel/panel-widechips-ws2401.c @@ -407,12 +407,11 @@ static int ws2401_probe(struct spi_device *spi) return 0; } -static int ws2401_remove(struct spi_device *spi) +static void ws2401_remove(struct spi_device *spi) { struct ws2401 *ws = spi_get_drvdata(spi); drm_panel_remove(&ws->panel); - return 0; } /* diff --git a/drivers/gpu/drm/tiny/hx8357d.c b/drivers/gpu/drm/tiny/hx8357d.c index 9b33c05732aa..ebb025543f8d 100644 --- a/drivers/gpu/drm/tiny/hx8357d.c +++ b/drivers/gpu/drm/tiny/hx8357d.c @@ -263,14 +263,12 @@ static int hx8357d_probe(struct spi_device *spi) return 0; } -static int hx8357d_remove(struct spi_device *spi) +static void hx8357d_remove(struct spi_device *spi) { struct drm_device *drm = spi_get_drvdata(spi); drm_dev_unplug(drm); drm_atomic_helper_shutdown(drm); - - return 0; } static void hx8357d_shutdown(struct spi_device *spi) diff --git a/drivers/gpu/drm/tiny/ili9163.c b/drivers/gpu/drm/tiny/ili9163.c index bcc181351236..fc8ed245b0bc 100644 --- a/drivers/gpu/drm/tiny/ili9163.c +++ b/drivers/gpu/drm/tiny/ili9163.c @@ -193,14 +193,12 @@ static int ili9163_probe(struct spi_device *spi) return 0; } -static int ili9163_remove(struct spi_device *spi) +static void ili9163_remove(struct spi_device *spi) { struct drm_device *drm = spi_get_drvdata(spi); drm_dev_unplug(drm); drm_atomic_helper_shutdown(drm); - - return 0; } static void ili9163_shutdown(struct spi_device *spi) diff --git a/drivers/gpu/drm/tiny/ili9225.c b/drivers/gpu/drm/tiny/ili9225.c index 976d3209f164..cc92eb9f2a07 100644 --- a/drivers/gpu/drm/tiny/ili9225.c +++ b/drivers/gpu/drm/tiny/ili9225.c @@ -411,14 +411,12 @@ static int ili9225_probe(struct spi_device *spi) return 0; } -static int ili9225_remove(struct spi_device *spi) +static void ili9225_remove(struct spi_device *spi) { struct drm_device *drm = spi_get_drvdata(spi); drm_dev_unplug(drm); drm_atomic_helper_shutdown(drm); - - return 0; } static void ili9225_shutdown(struct spi_device *spi) diff --git a/drivers/gpu/drm/tiny/ili9341.c b/drivers/gpu/drm/tiny/ili9341.c index 37e0c33399c8..5b8cc770ee7b 100644 --- a/drivers/gpu/drm/tiny/ili9341.c +++ b/drivers/gpu/drm/tiny/ili9341.c @@ -225,14 +225,12 @@ static int ili9341_probe(struct spi_device *spi) return 0; } -static int ili9341_remove(struct spi_device *spi) +static void ili9341_remove(struct spi_device *spi) { struct drm_device *drm = spi_get_drvdata(spi); drm_dev_unplug(drm); drm_atomic_helper_shutdown(drm); - - return 0; } static void ili9341_shutdown(struct spi_device *spi) diff --git a/drivers/gpu/drm/tiny/ili9486.c b/drivers/gpu/drm/tiny/ili9486.c index e9a63f4b2993..6d655e18e0aa 100644 --- a/drivers/gpu/drm/tiny/ili9486.c +++ b/drivers/gpu/drm/tiny/ili9486.c @@ -243,14 +243,12 @@ static int ili9486_probe(struct spi_device *spi) return 0; } -static int ili9486_remove(struct spi_device *spi) +static void ili9486_remove(struct spi_device *spi) { struct drm_device *drm = spi_get_drvdata(spi); drm_dev_unplug(drm); drm_atomic_helper_shutdown(drm); - - return 0; } static void ili9486_shutdown(struct spi_device *spi) diff --git a/drivers/gpu/drm/tiny/mi0283qt.c b/drivers/gpu/drm/tiny/mi0283qt.c index 023de49e7a8e..5e060f6910bb 100644 --- a/drivers/gpu/drm/tiny/mi0283qt.c +++ b/drivers/gpu/drm/tiny/mi0283qt.c @@ -233,14 +233,12 @@ static int mi0283qt_probe(struct spi_device *spi) return 0; } -static int mi0283qt_remove(struct spi_device *spi) +static void mi0283qt_remove(struct spi_device *spi) { struct drm_device *drm = spi_get_drvdata(spi); drm_dev_unplug(drm); drm_atomic_helper_shutdown(drm); - - return 0; } static void mi0283qt_shutdown(struct spi_device *spi) diff --git a/drivers/gpu/drm/tiny/repaper.c b/drivers/gpu/drm/tiny/repaper.c index 97a775c48cea..beeeb170d0b1 100644 --- a/drivers/gpu/drm/tiny/repaper.c +++ b/drivers/gpu/drm/tiny/repaper.c @@ -1140,14 +1140,12 @@ static int repaper_probe(struct spi_device *spi) return 0; } -static int repaper_remove(struct spi_device *spi) +static void repaper_remove(struct spi_device *spi) { struct drm_device *drm = spi_get_drvdata(spi); drm_dev_unplug(drm); drm_atomic_helper_shutdown(drm); - - return 0; } static void repaper_shutdown(struct spi_device *spi) diff --git a/drivers/gpu/drm/tiny/st7586.c b/drivers/gpu/drm/tiny/st7586.c index 51b9b9fb3ead..3f38faa1cd8c 100644 --- a/drivers/gpu/drm/tiny/st7586.c +++ b/drivers/gpu/drm/tiny/st7586.c @@ -360,14 +360,12 @@ static int st7586_probe(struct spi_device *spi) return 0; } -static int st7586_remove(struct spi_device *spi) +static void st7586_remove(struct spi_device *spi) { struct drm_device *drm = spi_get_drvdata(spi); drm_dev_unplug(drm); drm_atomic_helper_shutdown(drm); - - return 0; } static void st7586_shutdown(struct spi_device *spi) diff --git a/drivers/gpu/drm/tiny/st7735r.c b/drivers/gpu/drm/tiny/st7735r.c index fc40dd10efa8..29d618093e94 100644 --- a/drivers/gpu/drm/tiny/st7735r.c +++ b/drivers/gpu/drm/tiny/st7735r.c @@ -247,14 +247,12 @@ static int st7735r_probe(struct spi_device *spi) return 0; } -static int st7735r_remove(struct spi_device *spi) +static void st7735r_remove(struct spi_device *spi) { struct drm_device *drm = spi_get_drvdata(spi); drm_dev_unplug(drm); drm_atomic_helper_shutdown(drm); - - return 0; } static void st7735r_shutdown(struct spi_device *spi) diff --git a/drivers/hwmon/adcxx.c b/drivers/hwmon/adcxx.c index e5bc5ce09f4e..de37bce24fa6 100644 --- a/drivers/hwmon/adcxx.c +++ b/drivers/hwmon/adcxx.c @@ -194,7 +194,7 @@ out_err: return status; } -static int adcxx_remove(struct spi_device *spi) +static void adcxx_remove(struct spi_device *spi) { struct adcxx *adc = spi_get_drvdata(spi); int i; @@ -205,8 +205,6 @@ static int adcxx_remove(struct spi_device *spi) device_remove_file(&spi->dev, &ad_input[i].dev_attr); mutex_unlock(&adc->lock); - - return 0; } static const struct spi_device_id adcxx_ids[] = { diff --git a/drivers/hwmon/adt7310.c b/drivers/hwmon/adt7310.c index c40cac16af68..832d9ec64934 100644 --- a/drivers/hwmon/adt7310.c +++ b/drivers/hwmon/adt7310.c @@ -88,10 +88,9 @@ static int adt7310_spi_probe(struct spi_device *spi) &adt7310_spi_ops); } -static int adt7310_spi_remove(struct spi_device *spi) +static void adt7310_spi_remove(struct spi_device *spi) { adt7x10_remove(&spi->dev, spi->irq); - return 0; } static const struct spi_device_id adt7310_id[] = { diff --git a/drivers/hwmon/max1111.c b/drivers/hwmon/max1111.c index 5fcfd57df61e..4c5487aeb3cf 100644 --- a/drivers/hwmon/max1111.c +++ b/drivers/hwmon/max1111.c @@ -254,7 +254,7 @@ err_remove: return err; } -static int max1111_remove(struct spi_device *spi) +static void max1111_remove(struct spi_device *spi) { struct max1111_data *data = spi_get_drvdata(spi); @@ -265,7 +265,6 @@ static int max1111_remove(struct spi_device *spi) sysfs_remove_group(&spi->dev.kobj, &max1110_attr_group); sysfs_remove_group(&spi->dev.kobj, &max1111_attr_group); mutex_destroy(&data->drvdata_lock); - return 0; } static const struct spi_device_id max1111_ids[] = { diff --git a/drivers/hwmon/max31722.c b/drivers/hwmon/max31722.c index 4cf4fe6809a3..93e048ee4955 100644 --- a/drivers/hwmon/max31722.c +++ b/drivers/hwmon/max31722.c @@ -100,7 +100,7 @@ static int max31722_probe(struct spi_device *spi) return 0; } -static int max31722_remove(struct spi_device *spi) +static void max31722_remove(struct spi_device *spi) { struct max31722_data *data = spi_get_drvdata(spi); int ret; @@ -111,8 +111,6 @@ static int max31722_remove(struct spi_device *spi) if (ret) /* There is nothing we can do about this ... */ dev_warn(&spi->dev, "Failed to put device in stand-by mode\n"); - - return 0; } static int __maybe_unused max31722_suspend(struct device *dev) diff --git a/drivers/iio/accel/bma400_spi.c b/drivers/iio/accel/bma400_spi.c index 9f622e37477b..9040a717b247 100644 --- a/drivers/iio/accel/bma400_spi.c +++ b/drivers/iio/accel/bma400_spi.c @@ -87,11 +87,9 @@ static int bma400_spi_probe(struct spi_device *spi) return bma400_probe(&spi->dev, regmap, id->name); } -static int bma400_spi_remove(struct spi_device *spi) +static void bma400_spi_remove(struct spi_device *spi) { bma400_remove(&spi->dev); - - return 0; } static const struct spi_device_id bma400_spi_ids[] = { diff --git a/drivers/iio/accel/bmc150-accel-spi.c b/drivers/iio/accel/bmc150-accel-spi.c index 11559567cb39..80007cc2d044 100644 --- a/drivers/iio/accel/bmc150-accel-spi.c +++ b/drivers/iio/accel/bmc150-accel-spi.c @@ -35,11 +35,9 @@ static int bmc150_accel_probe(struct spi_device *spi) true); } -static int bmc150_accel_remove(struct spi_device *spi) +static void bmc150_accel_remove(struct spi_device *spi) { bmc150_accel_core_remove(&spi->dev); - - return 0; } static const struct acpi_device_id bmc150_accel_acpi_match[] = { diff --git a/drivers/iio/accel/bmi088-accel-spi.c b/drivers/iio/accel/bmi088-accel-spi.c index 758ad2f12896..06d99d9949f3 100644 --- a/drivers/iio/accel/bmi088-accel-spi.c +++ b/drivers/iio/accel/bmi088-accel-spi.c @@ -56,11 +56,9 @@ static int bmi088_accel_probe(struct spi_device *spi) true); } -static int bmi088_accel_remove(struct spi_device *spi) +static void bmi088_accel_remove(struct spi_device *spi) { bmi088_accel_core_remove(&spi->dev); - - return 0; } static const struct spi_device_id bmi088_accel_id[] = { diff --git a/drivers/iio/accel/kxsd9-spi.c b/drivers/iio/accel/kxsd9-spi.c index 441e6b764281..57c451cfb9e5 100644 --- a/drivers/iio/accel/kxsd9-spi.c +++ b/drivers/iio/accel/kxsd9-spi.c @@ -32,11 +32,9 @@ static int kxsd9_spi_probe(struct spi_device *spi) spi_get_device_id(spi)->name); } -static int kxsd9_spi_remove(struct spi_device *spi) +static void kxsd9_spi_remove(struct spi_device *spi) { kxsd9_common_remove(&spi->dev); - - return 0; } static const struct spi_device_id kxsd9_spi_id[] = { diff --git a/drivers/iio/accel/mma7455_spi.c b/drivers/iio/accel/mma7455_spi.c index ecf690692dcc..b746031551a3 100644 --- a/drivers/iio/accel/mma7455_spi.c +++ b/drivers/iio/accel/mma7455_spi.c @@ -22,11 +22,9 @@ static int mma7455_spi_probe(struct spi_device *spi) return mma7455_core_probe(&spi->dev, regmap, id->name); } -static int mma7455_spi_remove(struct spi_device *spi) +static void mma7455_spi_remove(struct spi_device *spi) { mma7455_core_remove(&spi->dev); - - return 0; } static const struct spi_device_id mma7455_spi_ids[] = { diff --git a/drivers/iio/accel/sca3000.c b/drivers/iio/accel/sca3000.c index 43ecacbdc95a..83c81072511e 100644 --- a/drivers/iio/accel/sca3000.c +++ b/drivers/iio/accel/sca3000.c @@ -1524,7 +1524,7 @@ error_ret: return ret; } -static int sca3000_remove(struct spi_device *spi) +static void sca3000_remove(struct spi_device *spi) { struct iio_dev *indio_dev = spi_get_drvdata(spi); struct sca3000_state *st = iio_priv(indio_dev); @@ -1535,8 +1535,6 @@ static int sca3000_remove(struct spi_device *spi) sca3000_stop_all_interrupts(st); if (spi->irq) free_irq(spi->irq, indio_dev); - - return 0; } static const struct spi_device_id sca3000_id[] = { diff --git a/drivers/iio/adc/ad7266.c b/drivers/iio/adc/ad7266.c index 1d345d66742d..c17d9b5fbaf6 100644 --- a/drivers/iio/adc/ad7266.c +++ b/drivers/iio/adc/ad7266.c @@ -479,7 +479,7 @@ error_disable_reg: return ret; } -static int ad7266_remove(struct spi_device *spi) +static void ad7266_remove(struct spi_device *spi) { struct iio_dev *indio_dev = spi_get_drvdata(spi); struct ad7266_state *st = iio_priv(indio_dev); @@ -488,8 +488,6 @@ static int ad7266_remove(struct spi_device *spi) iio_triggered_buffer_cleanup(indio_dev); if (!IS_ERR(st->reg)) regulator_disable(st->reg); - - return 0; } static const struct spi_device_id ad7266_id[] = { diff --git a/drivers/iio/adc/ltc2496.c b/drivers/iio/adc/ltc2496.c index dd956a7c216e..5a55f79f2574 100644 --- a/drivers/iio/adc/ltc2496.c +++ b/drivers/iio/adc/ltc2496.c @@ -78,13 +78,11 @@ static int ltc2496_probe(struct spi_device *spi) return ltc2497core_probe(dev, indio_dev); } -static int ltc2496_remove(struct spi_device *spi) +static void ltc2496_remove(struct spi_device *spi) { struct iio_dev *indio_dev = spi_get_drvdata(spi); ltc2497core_remove(indio_dev); - - return 0; } static const struct of_device_id ltc2496_of_match[] = { diff --git a/drivers/iio/adc/mcp320x.c b/drivers/iio/adc/mcp320x.c index 8d1cff28cae0..b4c69acb33e3 100644 --- a/drivers/iio/adc/mcp320x.c +++ b/drivers/iio/adc/mcp320x.c @@ -459,15 +459,13 @@ reg_disable: return ret; } -static int mcp320x_remove(struct spi_device *spi) +static void mcp320x_remove(struct spi_device *spi) { struct iio_dev *indio_dev = spi_get_drvdata(spi); struct mcp320x *adc = iio_priv(indio_dev); iio_device_unregister(indio_dev); regulator_disable(adc->reg); - - return 0; } static const struct of_device_id mcp320x_dt_ids[] = { diff --git a/drivers/iio/adc/mcp3911.c b/drivers/iio/adc/mcp3911.c index 13535f148c4c..1cb4590fe412 100644 --- a/drivers/iio/adc/mcp3911.c +++ b/drivers/iio/adc/mcp3911.c @@ -321,7 +321,7 @@ reg_disable: return ret; } -static int mcp3911_remove(struct spi_device *spi) +static void mcp3911_remove(struct spi_device *spi) { struct iio_dev *indio_dev = spi_get_drvdata(spi); struct mcp3911 *adc = iio_priv(indio_dev); @@ -331,8 +331,6 @@ static int mcp3911_remove(struct spi_device *spi) clk_disable_unprepare(adc->clki); if (adc->vref) regulator_disable(adc->vref); - - return 0; } static const struct of_device_id mcp3911_dt_ids[] = { diff --git a/drivers/iio/adc/ti-adc12138.c b/drivers/iio/adc/ti-adc12138.c index 6eb62b564dae..59d75d09604f 100644 --- a/drivers/iio/adc/ti-adc12138.c +++ b/drivers/iio/adc/ti-adc12138.c @@ -503,7 +503,7 @@ err_clk_disable: return ret; } -static int adc12138_remove(struct spi_device *spi) +static void adc12138_remove(struct spi_device *spi) { struct iio_dev *indio_dev = spi_get_drvdata(spi); struct adc12138 *adc = iio_priv(indio_dev); @@ -514,8 +514,6 @@ static int adc12138_remove(struct spi_device *spi) regulator_disable(adc->vref_n); regulator_disable(adc->vref_p); clk_disable_unprepare(adc->cclk); - - return 0; } static const struct of_device_id adc12138_dt_ids[] = { diff --git a/drivers/iio/adc/ti-ads7950.c b/drivers/iio/adc/ti-ads7950.c index a7efa3eada2c..e3658b969c5b 100644 --- a/drivers/iio/adc/ti-ads7950.c +++ b/drivers/iio/adc/ti-ads7950.c @@ -662,7 +662,7 @@ error_destroy_mutex: return ret; } -static int ti_ads7950_remove(struct spi_device *spi) +static void ti_ads7950_remove(struct spi_device *spi) { struct iio_dev *indio_dev = spi_get_drvdata(spi); struct ti_ads7950_state *st = iio_priv(indio_dev); @@ -672,8 +672,6 @@ static int ti_ads7950_remove(struct spi_device *spi) iio_triggered_buffer_cleanup(indio_dev); regulator_disable(st->reg); mutex_destroy(&st->slock); - - return 0; } static const struct spi_device_id ti_ads7950_id[] = { diff --git a/drivers/iio/adc/ti-ads8688.c b/drivers/iio/adc/ti-ads8688.c index 2e24717d7f55..22c2583eedd0 100644 --- a/drivers/iio/adc/ti-ads8688.c +++ b/drivers/iio/adc/ti-ads8688.c @@ -479,7 +479,7 @@ err_regulator_disable: return ret; } -static int ads8688_remove(struct spi_device *spi) +static void ads8688_remove(struct spi_device *spi) { struct iio_dev *indio_dev = spi_get_drvdata(spi); struct ads8688_state *st = iio_priv(indio_dev); @@ -489,8 +489,6 @@ static int ads8688_remove(struct spi_device *spi) if (!IS_ERR(st->reg)) regulator_disable(st->reg); - - return 0; } static const struct spi_device_id ads8688_id[] = { diff --git a/drivers/iio/adc/ti-tlc4541.c b/drivers/iio/adc/ti-tlc4541.c index 403b787f9f7e..2406eda9dfc6 100644 --- a/drivers/iio/adc/ti-tlc4541.c +++ b/drivers/iio/adc/ti-tlc4541.c @@ -224,7 +224,7 @@ error_disable_reg: return ret; } -static int tlc4541_remove(struct spi_device *spi) +static void tlc4541_remove(struct spi_device *spi) { struct iio_dev *indio_dev = spi_get_drvdata(spi); struct tlc4541_state *st = iio_priv(indio_dev); @@ -232,8 +232,6 @@ static int tlc4541_remove(struct spi_device *spi) iio_device_unregister(indio_dev); iio_triggered_buffer_cleanup(indio_dev); regulator_disable(st->reg); - - return 0; } static const struct of_device_id tlc4541_dt_ids[] = { diff --git a/drivers/iio/amplifiers/ad8366.c b/drivers/iio/amplifiers/ad8366.c index cfcf18a0bce8..1134ae12e531 100644 --- a/drivers/iio/amplifiers/ad8366.c +++ b/drivers/iio/amplifiers/ad8366.c @@ -298,7 +298,7 @@ error_disable_reg: return ret; } -static int ad8366_remove(struct spi_device *spi) +static void ad8366_remove(struct spi_device *spi) { struct iio_dev *indio_dev = spi_get_drvdata(spi); struct ad8366_state *st = iio_priv(indio_dev); @@ -308,8 +308,6 @@ static int ad8366_remove(struct spi_device *spi) if (!IS_ERR(reg)) regulator_disable(reg); - - return 0; } static const struct spi_device_id ad8366_id[] = { diff --git a/drivers/iio/common/ssp_sensors/ssp_dev.c b/drivers/iio/common/ssp_sensors/ssp_dev.c index 1aee87100038..eafaf4529df5 100644 --- a/drivers/iio/common/ssp_sensors/ssp_dev.c +++ b/drivers/iio/common/ssp_sensors/ssp_dev.c @@ -586,7 +586,7 @@ err_setup_irq: return ret; } -static int ssp_remove(struct spi_device *spi) +static void ssp_remove(struct spi_device *spi) { struct ssp_data *data = spi_get_drvdata(spi); @@ -608,8 +608,6 @@ static int ssp_remove(struct spi_device *spi) mutex_destroy(&data->pending_lock); mfd_remove_devices(&spi->dev); - - return 0; } #ifdef CONFIG_PM_SLEEP diff --git a/drivers/iio/dac/ad5360.c b/drivers/iio/dac/ad5360.c index 2d3b14c407d8..ecbc6a51d60f 100644 --- a/drivers/iio/dac/ad5360.c +++ b/drivers/iio/dac/ad5360.c @@ -521,7 +521,7 @@ error_free_channels: return ret; } -static int ad5360_remove(struct spi_device *spi) +static void ad5360_remove(struct spi_device *spi) { struct iio_dev *indio_dev = spi_get_drvdata(spi); struct ad5360_state *st = iio_priv(indio_dev); @@ -531,8 +531,6 @@ static int ad5360_remove(struct spi_device *spi) kfree(indio_dev->channels); regulator_bulk_disable(st->chip_info->num_vrefs, st->vref_reg); - - return 0; } static const struct spi_device_id ad5360_ids[] = { diff --git a/drivers/iio/dac/ad5380.c b/drivers/iio/dac/ad5380.c index e38860a6a9f3..82e1d9bd773e 100644 --- a/drivers/iio/dac/ad5380.c +++ b/drivers/iio/dac/ad5380.c @@ -488,11 +488,9 @@ static int ad5380_spi_probe(struct spi_device *spi) return ad5380_probe(&spi->dev, regmap, id->driver_data, id->name); } -static int ad5380_spi_remove(struct spi_device *spi) +static void ad5380_spi_remove(struct spi_device *spi) { ad5380_remove(&spi->dev); - - return 0; } static const struct spi_device_id ad5380_spi_ids[] = { diff --git a/drivers/iio/dac/ad5446.c b/drivers/iio/dac/ad5446.c index 1c9b54c012a7..14cfabacbea5 100644 --- a/drivers/iio/dac/ad5446.c +++ b/drivers/iio/dac/ad5446.c @@ -491,11 +491,9 @@ static int ad5446_spi_probe(struct spi_device *spi) &ad5446_spi_chip_info[id->driver_data]); } -static int ad5446_spi_remove(struct spi_device *spi) +static void ad5446_spi_remove(struct spi_device *spi) { ad5446_remove(&spi->dev); - - return 0; } static struct spi_driver ad5446_spi_driver = { diff --git a/drivers/iio/dac/ad5449.c b/drivers/iio/dac/ad5449.c index f5e93c6acc9d..bad9bdaafa94 100644 --- a/drivers/iio/dac/ad5449.c +++ b/drivers/iio/dac/ad5449.c @@ -330,7 +330,7 @@ error_disable_reg: return ret; } -static int ad5449_spi_remove(struct spi_device *spi) +static void ad5449_spi_remove(struct spi_device *spi) { struct iio_dev *indio_dev = spi_get_drvdata(spi); struct ad5449 *st = iio_priv(indio_dev); @@ -338,8 +338,6 @@ static int ad5449_spi_remove(struct spi_device *spi) iio_device_unregister(indio_dev); regulator_bulk_disable(st->chip_info->num_channels, st->vref_reg); - - return 0; } static const struct spi_device_id ad5449_spi_ids[] = { diff --git a/drivers/iio/dac/ad5504.c b/drivers/iio/dac/ad5504.c index b631261efa97..8507573aa13e 100644 --- a/drivers/iio/dac/ad5504.c +++ b/drivers/iio/dac/ad5504.c @@ -336,7 +336,7 @@ error_disable_reg: return ret; } -static int ad5504_remove(struct spi_device *spi) +static void ad5504_remove(struct spi_device *spi) { struct iio_dev *indio_dev = spi_get_drvdata(spi); struct ad5504_state *st = iio_priv(indio_dev); @@ -345,8 +345,6 @@ static int ad5504_remove(struct spi_device *spi) if (!IS_ERR(st->reg)) regulator_disable(st->reg); - - return 0; } static const struct spi_device_id ad5504_id[] = { diff --git a/drivers/iio/dac/ad5592r.c b/drivers/iio/dac/ad5592r.c index 6bfd7951e18c..0f7abfa75bec 100644 --- a/drivers/iio/dac/ad5592r.c +++ b/drivers/iio/dac/ad5592r.c @@ -130,11 +130,9 @@ static int ad5592r_spi_probe(struct spi_device *spi) return ad5592r_probe(&spi->dev, id->name, &ad5592r_rw_ops); } -static int ad5592r_spi_remove(struct spi_device *spi) +static void ad5592r_spi_remove(struct spi_device *spi) { ad5592r_remove(&spi->dev); - - return 0; } static const struct spi_device_id ad5592r_spi_ids[] = { diff --git a/drivers/iio/dac/ad5624r_spi.c b/drivers/iio/dac/ad5624r_spi.c index 3c98941b9f99..371e812850eb 100644 --- a/drivers/iio/dac/ad5624r_spi.c +++ b/drivers/iio/dac/ad5624r_spi.c @@ -293,7 +293,7 @@ error_disable_reg: return ret; } -static int ad5624r_remove(struct spi_device *spi) +static void ad5624r_remove(struct spi_device *spi) { struct iio_dev *indio_dev = spi_get_drvdata(spi); struct ad5624r_state *st = iio_priv(indio_dev); @@ -301,8 +301,6 @@ static int ad5624r_remove(struct spi_device *spi) iio_device_unregister(indio_dev); if (!IS_ERR(st->reg)) regulator_disable(st->reg); - - return 0; } static const struct spi_device_id ad5624r_id[] = { diff --git a/drivers/iio/dac/ad5686-spi.c b/drivers/iio/dac/ad5686-spi.c index 2628810fdbb1..d26fb29b6b04 100644 --- a/drivers/iio/dac/ad5686-spi.c +++ b/drivers/iio/dac/ad5686-spi.c @@ -95,11 +95,9 @@ static int ad5686_spi_probe(struct spi_device *spi) ad5686_spi_write, ad5686_spi_read); } -static int ad5686_spi_remove(struct spi_device *spi) +static void ad5686_spi_remove(struct spi_device *spi) { ad5686_remove(&spi->dev); - - return 0; } static const struct spi_device_id ad5686_spi_id[] = { diff --git a/drivers/iio/dac/ad5761.c b/drivers/iio/dac/ad5761.c index e37e095e94fc..4cb8471db81e 100644 --- a/drivers/iio/dac/ad5761.c +++ b/drivers/iio/dac/ad5761.c @@ -394,7 +394,7 @@ disable_regulator_err: return ret; } -static int ad5761_remove(struct spi_device *spi) +static void ad5761_remove(struct spi_device *spi) { struct iio_dev *iio_dev = spi_get_drvdata(spi); struct ad5761_state *st = iio_priv(iio_dev); @@ -403,8 +403,6 @@ static int ad5761_remove(struct spi_device *spi) if (!IS_ERR_OR_NULL(st->vref_reg)) regulator_disable(st->vref_reg); - - return 0; } static const struct spi_device_id ad5761_id[] = { diff --git a/drivers/iio/dac/ad5764.c b/drivers/iio/dac/ad5764.c index ae089b9145cb..d235a8047ba0 100644 --- a/drivers/iio/dac/ad5764.c +++ b/drivers/iio/dac/ad5764.c @@ -332,7 +332,7 @@ error_disable_reg: return ret; } -static int ad5764_remove(struct spi_device *spi) +static void ad5764_remove(struct spi_device *spi) { struct iio_dev *indio_dev = spi_get_drvdata(spi); struct ad5764_state *st = iio_priv(indio_dev); @@ -341,8 +341,6 @@ static int ad5764_remove(struct spi_device *spi) if (st->chip_info->int_vref == 0) regulator_bulk_disable(ARRAY_SIZE(st->vref_reg), st->vref_reg); - - return 0; } static const struct spi_device_id ad5764_ids[] = { diff --git a/drivers/iio/dac/ad5791.c b/drivers/iio/dac/ad5791.c index 7b4579d73d18..2b14914b4050 100644 --- a/drivers/iio/dac/ad5791.c +++ b/drivers/iio/dac/ad5791.c @@ -428,7 +428,7 @@ error_disable_reg_pos: return ret; } -static int ad5791_remove(struct spi_device *spi) +static void ad5791_remove(struct spi_device *spi) { struct iio_dev *indio_dev = spi_get_drvdata(spi); struct ad5791_state *st = iio_priv(indio_dev); @@ -439,8 +439,6 @@ static int ad5791_remove(struct spi_device *spi) if (!IS_ERR(st->reg_vss)) regulator_disable(st->reg_vss); - - return 0; } static const struct spi_device_id ad5791_id[] = { diff --git a/drivers/iio/dac/ad8801.c b/drivers/iio/dac/ad8801.c index 5ecfdad54dec..6be35c92d435 100644 --- a/drivers/iio/dac/ad8801.c +++ b/drivers/iio/dac/ad8801.c @@ -193,7 +193,7 @@ error_disable_vrefh_reg: return ret; } -static int ad8801_remove(struct spi_device *spi) +static void ad8801_remove(struct spi_device *spi) { struct iio_dev *indio_dev = spi_get_drvdata(spi); struct ad8801_state *state = iio_priv(indio_dev); @@ -202,8 +202,6 @@ static int ad8801_remove(struct spi_device *spi) if (state->vrefl_reg) regulator_disable(state->vrefl_reg); regulator_disable(state->vrefh_reg); - - return 0; } static const struct spi_device_id ad8801_ids[] = { diff --git a/drivers/iio/dac/ltc1660.c b/drivers/iio/dac/ltc1660.c index f6ec9bf5815e..c76233c9bb72 100644 --- a/drivers/iio/dac/ltc1660.c +++ b/drivers/iio/dac/ltc1660.c @@ -206,15 +206,13 @@ error_disable_reg: return ret; } -static int ltc1660_remove(struct spi_device *spi) +static void ltc1660_remove(struct spi_device *spi) { struct iio_dev *indio_dev = spi_get_drvdata(spi); struct ltc1660_priv *priv = iio_priv(indio_dev); iio_device_unregister(indio_dev); regulator_disable(priv->vref_reg); - - return 0; } static const struct of_device_id ltc1660_dt_ids[] = { diff --git a/drivers/iio/dac/ltc2632.c b/drivers/iio/dac/ltc2632.c index 53e4b887d372..aed46c80757e 100644 --- a/drivers/iio/dac/ltc2632.c +++ b/drivers/iio/dac/ltc2632.c @@ -372,7 +372,7 @@ static int ltc2632_probe(struct spi_device *spi) return iio_device_register(indio_dev); } -static int ltc2632_remove(struct spi_device *spi) +static void ltc2632_remove(struct spi_device *spi) { struct iio_dev *indio_dev = spi_get_drvdata(spi); struct ltc2632_state *st = iio_priv(indio_dev); @@ -381,8 +381,6 @@ static int ltc2632_remove(struct spi_device *spi) if (st->vref_reg) regulator_disable(st->vref_reg); - - return 0; } static const struct spi_device_id ltc2632_id[] = { diff --git a/drivers/iio/dac/mcp4922.c b/drivers/iio/dac/mcp4922.c index 0ae414ee1716..cb9e60e71b91 100644 --- a/drivers/iio/dac/mcp4922.c +++ b/drivers/iio/dac/mcp4922.c @@ -172,7 +172,7 @@ error_disable_reg: return ret; } -static int mcp4922_remove(struct spi_device *spi) +static void mcp4922_remove(struct spi_device *spi) { struct iio_dev *indio_dev = spi_get_drvdata(spi); struct mcp4922_state *state; @@ -180,8 +180,6 @@ static int mcp4922_remove(struct spi_device *spi) iio_device_unregister(indio_dev); state = iio_priv(indio_dev); regulator_disable(state->vref_reg); - - return 0; } static const struct spi_device_id mcp4922_id[] = { diff --git a/drivers/iio/dac/ti-dac082s085.c b/drivers/iio/dac/ti-dac082s085.c index 6beda2193683..4e1156e6deb2 100644 --- a/drivers/iio/dac/ti-dac082s085.c +++ b/drivers/iio/dac/ti-dac082s085.c @@ -313,7 +313,7 @@ err: return ret; } -static int ti_dac_remove(struct spi_device *spi) +static void ti_dac_remove(struct spi_device *spi) { struct iio_dev *indio_dev = spi_get_drvdata(spi); struct ti_dac_chip *ti_dac = iio_priv(indio_dev); @@ -321,8 +321,6 @@ static int ti_dac_remove(struct spi_device *spi) iio_device_unregister(indio_dev); mutex_destroy(&ti_dac->lock); regulator_disable(ti_dac->vref); - - return 0; } static const struct of_device_id ti_dac_of_id[] = { diff --git a/drivers/iio/dac/ti-dac7311.c b/drivers/iio/dac/ti-dac7311.c index 99f275829ec2..e10d17e60ed3 100644 --- a/drivers/iio/dac/ti-dac7311.c +++ b/drivers/iio/dac/ti-dac7311.c @@ -292,7 +292,7 @@ err: return ret; } -static int ti_dac_remove(struct spi_device *spi) +static void ti_dac_remove(struct spi_device *spi) { struct iio_dev *indio_dev = spi_get_drvdata(spi); struct ti_dac_chip *ti_dac = iio_priv(indio_dev); @@ -300,7 +300,6 @@ static int ti_dac_remove(struct spi_device *spi) iio_device_unregister(indio_dev); mutex_destroy(&ti_dac->lock); regulator_disable(ti_dac->vref); - return 0; } static const struct of_device_id ti_dac_of_id[] = { diff --git a/drivers/iio/frequency/adf4350.c b/drivers/iio/frequency/adf4350.c index 3d9eba716b69..f3521330f6fb 100644 --- a/drivers/iio/frequency/adf4350.c +++ b/drivers/iio/frequency/adf4350.c @@ -589,7 +589,7 @@ error_disable_clk: return ret; } -static int adf4350_remove(struct spi_device *spi) +static void adf4350_remove(struct spi_device *spi) { struct iio_dev *indio_dev = spi_get_drvdata(spi); struct adf4350_state *st = iio_priv(indio_dev); @@ -604,8 +604,6 @@ static int adf4350_remove(struct spi_device *spi) if (!IS_ERR(reg)) regulator_disable(reg); - - return 0; } static const struct of_device_id adf4350_of_match[] = { diff --git a/drivers/iio/gyro/bmg160_spi.c b/drivers/iio/gyro/bmg160_spi.c index 745962e1e423..fc2e453527b9 100644 --- a/drivers/iio/gyro/bmg160_spi.c +++ b/drivers/iio/gyro/bmg160_spi.c @@ -27,11 +27,9 @@ static int bmg160_spi_probe(struct spi_device *spi) return bmg160_core_probe(&spi->dev, regmap, spi->irq, id->name); } -static int bmg160_spi_remove(struct spi_device *spi) +static void bmg160_spi_remove(struct spi_device *spi) { bmg160_core_remove(&spi->dev); - - return 0; } static const struct spi_device_id bmg160_spi_id[] = { diff --git a/drivers/iio/gyro/fxas21002c_spi.c b/drivers/iio/gyro/fxas21002c_spi.c index 77ceebef4e34..c3ac169facf9 100644 --- a/drivers/iio/gyro/fxas21002c_spi.c +++ b/drivers/iio/gyro/fxas21002c_spi.c @@ -34,11 +34,9 @@ static int fxas21002c_spi_probe(struct spi_device *spi) return fxas21002c_core_probe(&spi->dev, regmap, spi->irq, id->name); } -static int fxas21002c_spi_remove(struct spi_device *spi) +static void fxas21002c_spi_remove(struct spi_device *spi) { fxas21002c_core_remove(&spi->dev); - - return 0; } static const struct spi_device_id fxas21002c_spi_id[] = { diff --git a/drivers/iio/health/afe4403.c b/drivers/iio/health/afe4403.c index 273f16dcaff8..856ec901b091 100644 --- a/drivers/iio/health/afe4403.c +++ b/drivers/iio/health/afe4403.c @@ -570,7 +570,7 @@ err_disable_reg: return ret; } -static int afe4403_remove(struct spi_device *spi) +static void afe4403_remove(struct spi_device *spi) { struct iio_dev *indio_dev = spi_get_drvdata(spi); struct afe4403_data *afe = iio_priv(indio_dev); @@ -586,8 +586,6 @@ static int afe4403_remove(struct spi_device *spi) ret = regulator_disable(afe->regulator); if (ret) dev_warn(afe->dev, "Unable to disable regulator\n"); - - return 0; } static const struct spi_device_id afe4403_ids[] = { diff --git a/drivers/iio/magnetometer/bmc150_magn_spi.c b/drivers/iio/magnetometer/bmc150_magn_spi.c index c6ed3ea8460a..4c570412d65c 100644 --- a/drivers/iio/magnetometer/bmc150_magn_spi.c +++ b/drivers/iio/magnetometer/bmc150_magn_spi.c @@ -29,11 +29,9 @@ static int bmc150_magn_spi_probe(struct spi_device *spi) return bmc150_magn_probe(&spi->dev, regmap, spi->irq, id->name); } -static int bmc150_magn_spi_remove(struct spi_device *spi) +static void bmc150_magn_spi_remove(struct spi_device *spi) { bmc150_magn_remove(&spi->dev); - - return 0; } static const struct spi_device_id bmc150_magn_spi_id[] = { diff --git a/drivers/iio/magnetometer/hmc5843_spi.c b/drivers/iio/magnetometer/hmc5843_spi.c index 89cf59a62c28..a99dd9b33e95 100644 --- a/drivers/iio/magnetometer/hmc5843_spi.c +++ b/drivers/iio/magnetometer/hmc5843_spi.c @@ -74,11 +74,9 @@ static int hmc5843_spi_probe(struct spi_device *spi) id->driver_data, id->name); } -static int hmc5843_spi_remove(struct spi_device *spi) +static void hmc5843_spi_remove(struct spi_device *spi) { hmc5843_common_remove(&spi->dev); - - return 0; } static const struct spi_device_id hmc5843_id[] = { diff --git a/drivers/iio/potentiometer/max5487.c b/drivers/iio/potentiometer/max5487.c index 007c2bd324cb..42723c996c9f 100644 --- a/drivers/iio/potentiometer/max5487.c +++ b/drivers/iio/potentiometer/max5487.c @@ -112,7 +112,7 @@ static int max5487_spi_probe(struct spi_device *spi) return iio_device_register(indio_dev); } -static int max5487_spi_remove(struct spi_device *spi) +static void max5487_spi_remove(struct spi_device *spi) { struct iio_dev *indio_dev = spi_get_drvdata(spi); int ret; @@ -123,8 +123,6 @@ static int max5487_spi_remove(struct spi_device *spi) ret = max5487_write_cmd(spi, MAX5487_COPY_AB_TO_NV); if (ret) dev_warn(&spi->dev, "Failed to save wiper regs to NV regs\n"); - - return 0; } static const struct spi_device_id max5487_id[] = { diff --git a/drivers/iio/pressure/ms5611_spi.c b/drivers/iio/pressure/ms5611_spi.c index 9fa2dcd71760..7ccd960ced5d 100644 --- a/drivers/iio/pressure/ms5611_spi.c +++ b/drivers/iio/pressure/ms5611_spi.c @@ -107,11 +107,9 @@ static int ms5611_spi_probe(struct spi_device *spi) spi_get_device_id(spi)->driver_data); } -static int ms5611_spi_remove(struct spi_device *spi) +static void ms5611_spi_remove(struct spi_device *spi) { ms5611_remove(spi_get_drvdata(spi)); - - return 0; } static const struct of_device_id ms5611_spi_matches[] = { diff --git a/drivers/iio/pressure/zpa2326_spi.c b/drivers/iio/pressure/zpa2326_spi.c index 85201a4bae44..ee8ed77536ca 100644 --- a/drivers/iio/pressure/zpa2326_spi.c +++ b/drivers/iio/pressure/zpa2326_spi.c @@ -57,11 +57,9 @@ static int zpa2326_probe_spi(struct spi_device *spi) spi->irq, ZPA2326_DEVICE_ID, regmap); } -static int zpa2326_remove_spi(struct spi_device *spi) +static void zpa2326_remove_spi(struct spi_device *spi) { zpa2326_remove(&spi->dev); - - return 0; } static const struct spi_device_id zpa2326_spi_ids[] = { diff --git a/drivers/input/keyboard/applespi.c b/drivers/input/keyboard/applespi.c index eda1b23002b5..d1f5354d5ea2 100644 --- a/drivers/input/keyboard/applespi.c +++ b/drivers/input/keyboard/applespi.c @@ -1858,7 +1858,7 @@ static void applespi_drain_reads(struct applespi_data *applespi) spin_unlock_irqrestore(&applespi->cmd_msg_lock, flags); } -static int applespi_remove(struct spi_device *spi) +static void applespi_remove(struct spi_device *spi) { struct applespi_data *applespi = spi_get_drvdata(spi); @@ -1871,8 +1871,6 @@ static int applespi_remove(struct spi_device *spi) applespi_drain_reads(applespi); debugfs_remove_recursive(applespi->debugfs_root); - - return 0; } static void applespi_shutdown(struct spi_device *spi) diff --git a/drivers/input/misc/adxl34x-spi.c b/drivers/input/misc/adxl34x-spi.c index 6e51c9bc619f..91e44d4c66f7 100644 --- a/drivers/input/misc/adxl34x-spi.c +++ b/drivers/input/misc/adxl34x-spi.c @@ -87,13 +87,11 @@ static int adxl34x_spi_probe(struct spi_device *spi) return 0; } -static int adxl34x_spi_remove(struct spi_device *spi) +static void adxl34x_spi_remove(struct spi_device *spi) { struct adxl34x *ac = spi_get_drvdata(spi); adxl34x_remove(ac); - - return 0; } static int __maybe_unused adxl34x_spi_suspend(struct device *dev) diff --git a/drivers/input/touchscreen/ads7846.c b/drivers/input/touchscreen/ads7846.c index a25a77dd9a32..bed68a68f330 100644 --- a/drivers/input/touchscreen/ads7846.c +++ b/drivers/input/touchscreen/ads7846.c @@ -1411,13 +1411,11 @@ static int ads7846_probe(struct spi_device *spi) return 0; } -static int ads7846_remove(struct spi_device *spi) +static void ads7846_remove(struct spi_device *spi) { struct ads7846 *ts = spi_get_drvdata(spi); ads7846_stop(ts); - - return 0; } static struct spi_driver ads7846_driver = { diff --git a/drivers/input/touchscreen/cyttsp4_spi.c b/drivers/input/touchscreen/cyttsp4_spi.c index 2aec41eb76b7..5d7db84f2749 100644 --- a/drivers/input/touchscreen/cyttsp4_spi.c +++ b/drivers/input/touchscreen/cyttsp4_spi.c @@ -164,12 +164,10 @@ static int cyttsp4_spi_probe(struct spi_device *spi) return PTR_ERR_OR_ZERO(ts); } -static int cyttsp4_spi_remove(struct spi_device *spi) +static void cyttsp4_spi_remove(struct spi_device *spi) { struct cyttsp4 *ts = spi_get_drvdata(spi); cyttsp4_remove(ts); - - return 0; } static struct spi_driver cyttsp4_spi_driver = { diff --git a/drivers/input/touchscreen/tsc2005.c b/drivers/input/touchscreen/tsc2005.c index a2f55920b9b2..555dfe98b3c4 100644 --- a/drivers/input/touchscreen/tsc2005.c +++ b/drivers/input/touchscreen/tsc2005.c @@ -64,11 +64,9 @@ static int tsc2005_probe(struct spi_device *spi) tsc2005_cmd); } -static int tsc2005_remove(struct spi_device *spi) +static void tsc2005_remove(struct spi_device *spi) { tsc200x_remove(&spi->dev); - - return 0; } #ifdef CONFIG_OF diff --git a/drivers/leds/leds-cr0014114.c b/drivers/leds/leds-cr0014114.c index d03cfd3c0bfb..c87686bd7c18 100644 --- a/drivers/leds/leds-cr0014114.c +++ b/drivers/leds/leds-cr0014114.c @@ -266,14 +266,12 @@ static int cr0014114_probe(struct spi_device *spi) return 0; } -static int cr0014114_remove(struct spi_device *spi) +static void cr0014114_remove(struct spi_device *spi) { struct cr0014114 *priv = spi_get_drvdata(spi); cancel_delayed_work_sync(&priv->work); mutex_destroy(&priv->lock); - - return 0; } static const struct of_device_id cr0014114_dt_ids[] = { diff --git a/drivers/leds/leds-dac124s085.c b/drivers/leds/leds-dac124s085.c index 20dc9b9d7dea..cf5fb1195f87 100644 --- a/drivers/leds/leds-dac124s085.c +++ b/drivers/leds/leds-dac124s085.c @@ -85,15 +85,13 @@ eledcr: return ret; } -static int dac124s085_remove(struct spi_device *spi) +static void dac124s085_remove(struct spi_device *spi) { struct dac124s085 *dac = spi_get_drvdata(spi); int i; for (i = 0; i < ARRAY_SIZE(dac->leds); i++) led_classdev_unregister(&dac->leds[i].ldev); - - return 0; } static struct spi_driver dac124s085_driver = { diff --git a/drivers/leds/leds-el15203000.c b/drivers/leds/leds-el15203000.c index f9eb59a25570..7e7b617bcd56 100644 --- a/drivers/leds/leds-el15203000.c +++ b/drivers/leds/leds-el15203000.c @@ -315,13 +315,11 @@ static int el15203000_probe(struct spi_device *spi) return el15203000_probe_dt(priv); } -static int el15203000_remove(struct spi_device *spi) +static void el15203000_remove(struct spi_device *spi) { struct el15203000 *priv = spi_get_drvdata(spi); mutex_destroy(&priv->lock); - - return 0; } static const struct of_device_id el15203000_dt_ids[] = { diff --git a/drivers/leds/leds-spi-byte.c b/drivers/leds/leds-spi-byte.c index f1964c96fb15..2bc5c99daf51 100644 --- a/drivers/leds/leds-spi-byte.c +++ b/drivers/leds/leds-spi-byte.c @@ -130,13 +130,11 @@ static int spi_byte_probe(struct spi_device *spi) return 0; } -static int spi_byte_remove(struct spi_device *spi) +static void spi_byte_remove(struct spi_device *spi) { struct spi_byte_led *led = spi_get_drvdata(spi); mutex_destroy(&led->mutex); - - return 0; } static struct spi_driver spi_byte_driver = { diff --git a/drivers/media/spi/cxd2880-spi.c b/drivers/media/spi/cxd2880-spi.c index 6f2a66bc87fb..6be4e5528879 100644 --- a/drivers/media/spi/cxd2880-spi.c +++ b/drivers/media/spi/cxd2880-spi.c @@ -625,7 +625,7 @@ fail_regulator: return ret; } -static int +static void cxd2880_spi_remove(struct spi_device *spi) { struct cxd2880_dvb_spi *dvb_spi = spi_get_drvdata(spi); @@ -643,8 +643,6 @@ cxd2880_spi_remove(struct spi_device *spi) kfree(dvb_spi); pr_info("cxd2880_spi remove ok.\n"); - - return 0; } static const struct spi_device_id cxd2880_spi_id[] = { diff --git a/drivers/media/spi/gs1662.c b/drivers/media/spi/gs1662.c index f86ef1ca1288..75c21a93e6d0 100644 --- a/drivers/media/spi/gs1662.c +++ b/drivers/media/spi/gs1662.c @@ -458,13 +458,11 @@ static int gs_probe(struct spi_device *spi) return ret; } -static int gs_remove(struct spi_device *spi) +static void gs_remove(struct spi_device *spi) { struct v4l2_subdev *sd = spi_get_drvdata(spi); v4l2_device_unregister_subdev(sd); - - return 0; } static struct spi_driver gs_driver = { diff --git a/drivers/media/tuners/msi001.c b/drivers/media/tuners/msi001.c index 44247049a319..ad6c72c1ed04 100644 --- a/drivers/media/tuners/msi001.c +++ b/drivers/media/tuners/msi001.c @@ -472,7 +472,7 @@ err: return ret; } -static int msi001_remove(struct spi_device *spi) +static void msi001_remove(struct spi_device *spi) { struct v4l2_subdev *sd = spi_get_drvdata(spi); struct msi001_dev *dev = sd_to_msi001_dev(sd); @@ -486,7 +486,6 @@ static int msi001_remove(struct spi_device *spi) v4l2_device_unregister_subdev(&dev->sd); v4l2_ctrl_handler_free(&dev->hdl); kfree(dev); - return 0; } static const struct spi_device_id msi001_id_table[] = { diff --git a/drivers/mfd/arizona-spi.c b/drivers/mfd/arizona-spi.c index 9fe06dda3782..03620c8efe34 100644 --- a/drivers/mfd/arizona-spi.c +++ b/drivers/mfd/arizona-spi.c @@ -206,13 +206,11 @@ static int arizona_spi_probe(struct spi_device *spi) return arizona_dev_init(arizona); } -static int arizona_spi_remove(struct spi_device *spi) +static void arizona_spi_remove(struct spi_device *spi) { struct arizona *arizona = spi_get_drvdata(spi); arizona_dev_exit(arizona); - - return 0; } static const struct spi_device_id arizona_spi_ids[] = { diff --git a/drivers/mfd/da9052-spi.c b/drivers/mfd/da9052-spi.c index 5faf3766a5e2..b79a57b45c1e 100644 --- a/drivers/mfd/da9052-spi.c +++ b/drivers/mfd/da9052-spi.c @@ -55,12 +55,11 @@ static int da9052_spi_probe(struct spi_device *spi) return da9052_device_init(da9052, id->driver_data); } -static int da9052_spi_remove(struct spi_device *spi) +static void da9052_spi_remove(struct spi_device *spi) { struct da9052 *da9052 = spi_get_drvdata(spi); da9052_device_exit(da9052); - return 0; } static const struct spi_device_id da9052_spi_id[] = { diff --git a/drivers/mfd/ezx-pcap.c b/drivers/mfd/ezx-pcap.c index 70fa18b04ad2..2280f756f422 100644 --- a/drivers/mfd/ezx-pcap.c +++ b/drivers/mfd/ezx-pcap.c @@ -392,7 +392,7 @@ static int pcap_add_subdev(struct pcap_chip *pcap, return ret; } -static int ezx_pcap_remove(struct spi_device *spi) +static void ezx_pcap_remove(struct spi_device *spi) { struct pcap_chip *pcap = spi_get_drvdata(spi); unsigned long flags; @@ -412,8 +412,6 @@ static int ezx_pcap_remove(struct spi_device *spi) irq_set_chip_and_handler(i, NULL, NULL); destroy_workqueue(pcap->workqueue); - - return 0; } static int ezx_pcap_probe(struct spi_device *spi) diff --git a/drivers/mfd/madera-spi.c b/drivers/mfd/madera-spi.c index e860f5ff0933..da84eb50e53a 100644 --- a/drivers/mfd/madera-spi.c +++ b/drivers/mfd/madera-spi.c @@ -112,13 +112,11 @@ static int madera_spi_probe(struct spi_device *spi) return madera_dev_init(madera); } -static int madera_spi_remove(struct spi_device *spi) +static void madera_spi_remove(struct spi_device *spi) { struct madera *madera = spi_get_drvdata(spi); madera_dev_exit(madera); - - return 0; } static const struct spi_device_id madera_spi_ids[] = { diff --git a/drivers/mfd/mc13xxx-spi.c b/drivers/mfd/mc13xxx-spi.c index 4d8913d647e6..f803527e5819 100644 --- a/drivers/mfd/mc13xxx-spi.c +++ b/drivers/mfd/mc13xxx-spi.c @@ -166,10 +166,9 @@ static int mc13xxx_spi_probe(struct spi_device *spi) return mc13xxx_common_init(&spi->dev); } -static int mc13xxx_spi_remove(struct spi_device *spi) +static void mc13xxx_spi_remove(struct spi_device *spi) { mc13xxx_common_exit(&spi->dev); - return 0; } static struct spi_driver mc13xxx_spi_driver = { diff --git a/drivers/mfd/rsmu_spi.c b/drivers/mfd/rsmu_spi.c index fec2b4ec477c..d2f3d8f1e05a 100644 --- a/drivers/mfd/rsmu_spi.c +++ b/drivers/mfd/rsmu_spi.c @@ -220,13 +220,11 @@ static int rsmu_spi_probe(struct spi_device *client) return rsmu_core_init(rsmu); } -static int rsmu_spi_remove(struct spi_device *client) +static void rsmu_spi_remove(struct spi_device *client) { struct rsmu_ddata *rsmu = spi_get_drvdata(client); rsmu_core_exit(rsmu); - - return 0; } static const struct spi_device_id rsmu_spi_id[] = { diff --git a/drivers/mfd/stmpe-spi.c b/drivers/mfd/stmpe-spi.c index 6c5915016be5..ad8055a0e286 100644 --- a/drivers/mfd/stmpe-spi.c +++ b/drivers/mfd/stmpe-spi.c @@ -102,13 +102,11 @@ stmpe_spi_probe(struct spi_device *spi) return stmpe_probe(&spi_ci, id->driver_data); } -static int stmpe_spi_remove(struct spi_device *spi) +static void stmpe_spi_remove(struct spi_device *spi) { struct stmpe *stmpe = spi_get_drvdata(spi); stmpe_remove(stmpe); - - return 0; } static const struct of_device_id stmpe_spi_of_match[] = { diff --git a/drivers/mfd/tps65912-spi.c b/drivers/mfd/tps65912-spi.c index d701926aa46e..bba38fbc781d 100644 --- a/drivers/mfd/tps65912-spi.c +++ b/drivers/mfd/tps65912-spi.c @@ -50,13 +50,11 @@ static int tps65912_spi_probe(struct spi_device *spi) return tps65912_device_init(tps); } -static int tps65912_spi_remove(struct spi_device *spi) +static void tps65912_spi_remove(struct spi_device *spi) { struct tps65912 *tps = spi_get_drvdata(spi); tps65912_device_exit(tps); - - return 0; } static const struct spi_device_id tps65912_spi_id_table[] = { diff --git a/drivers/misc/ad525x_dpot-spi.c b/drivers/misc/ad525x_dpot-spi.c index a9e75d80ad36..263055bda48b 100644 --- a/drivers/misc/ad525x_dpot-spi.c +++ b/drivers/misc/ad525x_dpot-spi.c @@ -90,10 +90,9 @@ static int ad_dpot_spi_probe(struct spi_device *spi) spi_get_device_id(spi)->name); } -static int ad_dpot_spi_remove(struct spi_device *spi) +static void ad_dpot_spi_remove(struct spi_device *spi) { ad_dpot_remove(&spi->dev); - return 0; } static const struct spi_device_id ad_dpot_spi_id[] = { diff --git a/drivers/misc/eeprom/eeprom_93xx46.c b/drivers/misc/eeprom/eeprom_93xx46.c index 1f15399e5cb4..b630625b3024 100644 --- a/drivers/misc/eeprom/eeprom_93xx46.c +++ b/drivers/misc/eeprom/eeprom_93xx46.c @@ -555,14 +555,12 @@ static int eeprom_93xx46_probe(struct spi_device *spi) return 0; } -static int eeprom_93xx46_remove(struct spi_device *spi) +static void eeprom_93xx46_remove(struct spi_device *spi) { struct eeprom_93xx46_dev *edev = spi_get_drvdata(spi); if (!(edev->pdata->flags & EE_READONLY)) device_remove_file(&spi->dev, &dev_attr_erase); - - return 0; } static struct spi_driver eeprom_93xx46_driver = { diff --git a/drivers/misc/lattice-ecp3-config.c b/drivers/misc/lattice-ecp3-config.c index 98828030b5a4..bac4df2e5231 100644 --- a/drivers/misc/lattice-ecp3-config.c +++ b/drivers/misc/lattice-ecp3-config.c @@ -211,13 +211,11 @@ static int lattice_ecp3_probe(struct spi_device *spi) return 0; } -static int lattice_ecp3_remove(struct spi_device *spi) +static void lattice_ecp3_remove(struct spi_device *spi) { struct fpga_data *data = spi_get_drvdata(spi); wait_for_completion(&data->fw_loaded); - - return 0; } static const struct spi_device_id lattice_ecp3_id[] = { diff --git a/drivers/misc/lis3lv02d/lis3lv02d_spi.c b/drivers/misc/lis3lv02d/lis3lv02d_spi.c index 9e40dfb60742..203a108b8883 100644 --- a/drivers/misc/lis3lv02d/lis3lv02d_spi.c +++ b/drivers/misc/lis3lv02d/lis3lv02d_spi.c @@ -96,15 +96,13 @@ static int lis302dl_spi_probe(struct spi_device *spi) return lis3lv02d_init_device(&lis3_dev); } -static int lis302dl_spi_remove(struct spi_device *spi) +static void lis302dl_spi_remove(struct spi_device *spi) { struct lis3lv02d *lis3 = spi_get_drvdata(spi); lis3lv02d_joystick_disable(lis3); lis3lv02d_poweroff(lis3); lis3lv02d_remove_fs(&lis3_dev); - - return 0; } #ifdef CONFIG_PM_SLEEP diff --git a/drivers/mmc/host/mmc_spi.c b/drivers/mmc/host/mmc_spi.c index a576181e9db0..106dd204b1a7 100644 --- a/drivers/mmc/host/mmc_spi.c +++ b/drivers/mmc/host/mmc_spi.c @@ -1489,7 +1489,7 @@ nomem: } -static int mmc_spi_remove(struct spi_device *spi) +static void mmc_spi_remove(struct spi_device *spi) { struct mmc_host *mmc = dev_get_drvdata(&spi->dev); struct mmc_spi_host *host = mmc_priv(mmc); @@ -1507,7 +1507,6 @@ static int mmc_spi_remove(struct spi_device *spi) spi->max_speed_hz = mmc->f_max; mmc_spi_put_pdata(spi); mmc_free_host(mmc); - return 0; } static const struct spi_device_id mmc_spi_dev_ids[] = { diff --git a/drivers/mtd/devices/mchp23k256.c b/drivers/mtd/devices/mchp23k256.c index a8b31bddf14b..008df9d8898d 100644 --- a/drivers/mtd/devices/mchp23k256.c +++ b/drivers/mtd/devices/mchp23k256.c @@ -209,13 +209,11 @@ static int mchp23k256_probe(struct spi_device *spi) return 0; } -static int mchp23k256_remove(struct spi_device *spi) +static void mchp23k256_remove(struct spi_device *spi) { struct mchp23k256_flash *flash = spi_get_drvdata(spi); WARN_ON(mtd_device_unregister(&flash->mtd)); - - return 0; } static const struct of_device_id mchp23k256_of_table[] = { diff --git a/drivers/mtd/devices/mchp48l640.c b/drivers/mtd/devices/mchp48l640.c index 231a10790196..a3fd426df74b 100644 --- a/drivers/mtd/devices/mchp48l640.c +++ b/drivers/mtd/devices/mchp48l640.c @@ -341,13 +341,11 @@ static int mchp48l640_probe(struct spi_device *spi) return 0; } -static int mchp48l640_remove(struct spi_device *spi) +static void mchp48l640_remove(struct spi_device *spi) { struct mchp48l640_flash *flash = spi_get_drvdata(spi); WARN_ON(mtd_device_unregister(&flash->mtd)); - - return 0; } static const struct of_device_id mchp48l640_of_table[] = { diff --git a/drivers/mtd/devices/mtd_dataflash.c b/drivers/mtd/devices/mtd_dataflash.c index 734878abaa23..134e27328597 100644 --- a/drivers/mtd/devices/mtd_dataflash.c +++ b/drivers/mtd/devices/mtd_dataflash.c @@ -916,7 +916,7 @@ static int dataflash_probe(struct spi_device *spi) return status; } -static int dataflash_remove(struct spi_device *spi) +static void dataflash_remove(struct spi_device *spi) { struct dataflash *flash = spi_get_drvdata(spi); @@ -925,8 +925,6 @@ static int dataflash_remove(struct spi_device *spi) WARN_ON(mtd_device_unregister(&flash->mtd)); kfree(flash); - - return 0; } static struct spi_driver dataflash_driver = { diff --git a/drivers/mtd/devices/sst25l.c b/drivers/mtd/devices/sst25l.c index 7f124c1bfa40..8813994ce9f4 100644 --- a/drivers/mtd/devices/sst25l.c +++ b/drivers/mtd/devices/sst25l.c @@ -398,13 +398,11 @@ static int sst25l_probe(struct spi_device *spi) return 0; } -static int sst25l_remove(struct spi_device *spi) +static void sst25l_remove(struct spi_device *spi) { struct sst25l_flash *flash = spi_get_drvdata(spi); WARN_ON(mtd_device_unregister(&flash->mtd)); - - return 0; } static struct spi_driver sst25l_driver = { diff --git a/drivers/net/can/m_can/tcan4x5x-core.c b/drivers/net/can/m_can/tcan4x5x-core.c index 04687b15b250..41645a24384c 100644 --- a/drivers/net/can/m_can/tcan4x5x-core.c +++ b/drivers/net/can/m_can/tcan4x5x-core.c @@ -388,7 +388,7 @@ out_power: return ret; } -static int tcan4x5x_can_remove(struct spi_device *spi) +static void tcan4x5x_can_remove(struct spi_device *spi) { struct tcan4x5x_priv *priv = spi_get_drvdata(spi); @@ -397,8 +397,6 @@ static int tcan4x5x_can_remove(struct spi_device *spi) tcan4x5x_power_enable(priv->power, 0); m_can_class_free_dev(priv->cdev.net); - - return 0; } static const struct of_device_id tcan4x5x_of_match[] = { diff --git a/drivers/net/can/spi/hi311x.c b/drivers/net/can/spi/hi311x.c index cfcc14fe3e42..664b8f14d7b0 100644 --- a/drivers/net/can/spi/hi311x.c +++ b/drivers/net/can/spi/hi311x.c @@ -948,7 +948,7 @@ static int hi3110_can_probe(struct spi_device *spi) return dev_err_probe(dev, ret, "Probe failed\n"); } -static int hi3110_can_remove(struct spi_device *spi) +static void hi3110_can_remove(struct spi_device *spi) { struct hi3110_priv *priv = spi_get_drvdata(spi); struct net_device *net = priv->net; @@ -960,8 +960,6 @@ static int hi3110_can_remove(struct spi_device *spi) clk_disable_unprepare(priv->clk); free_candev(net); - - return 0; } static int __maybe_unused hi3110_can_suspend(struct device *dev) diff --git a/drivers/net/can/spi/mcp251x.c b/drivers/net/can/spi/mcp251x.c index 025e07cb7439..d23edaf22420 100644 --- a/drivers/net/can/spi/mcp251x.c +++ b/drivers/net/can/spi/mcp251x.c @@ -1427,7 +1427,7 @@ out_free: return ret; } -static int mcp251x_can_remove(struct spi_device *spi) +static void mcp251x_can_remove(struct spi_device *spi) { struct mcp251x_priv *priv = spi_get_drvdata(spi); struct net_device *net = priv->net; @@ -1442,8 +1442,6 @@ static int mcp251x_can_remove(struct spi_device *spi) clk_disable_unprepare(priv->clk); free_candev(net); - - return 0; } static int __maybe_unused mcp251x_can_suspend(struct device *dev) diff --git a/drivers/net/can/spi/mcp251xfd/mcp251xfd-core.c b/drivers/net/can/spi/mcp251xfd/mcp251xfd-core.c index b5986df6eca0..65c9b31666a6 100644 --- a/drivers/net/can/spi/mcp251xfd/mcp251xfd-core.c +++ b/drivers/net/can/spi/mcp251xfd/mcp251xfd-core.c @@ -1966,7 +1966,7 @@ static int mcp251xfd_probe(struct spi_device *spi) return err; } -static int mcp251xfd_remove(struct spi_device *spi) +static void mcp251xfd_remove(struct spi_device *spi) { struct mcp251xfd_priv *priv = spi_get_drvdata(spi); struct net_device *ndev = priv->ndev; @@ -1975,8 +1975,6 @@ static int mcp251xfd_remove(struct spi_device *spi) mcp251xfd_unregister(priv); spi->max_speed_hz = priv->spi_max_speed_hz_orig; free_candev(ndev); - - return 0; } static int __maybe_unused mcp251xfd_runtime_suspend(struct device *device) diff --git a/drivers/net/dsa/b53/b53_spi.c b/drivers/net/dsa/b53/b53_spi.c index 2b88f03e5252..0e54b2a0c211 100644 --- a/drivers/net/dsa/b53/b53_spi.c +++ b/drivers/net/dsa/b53/b53_spi.c @@ -314,7 +314,7 @@ static int b53_spi_probe(struct spi_device *spi) return 0; } -static int b53_spi_remove(struct spi_device *spi) +static void b53_spi_remove(struct spi_device *spi) { struct b53_device *dev = spi_get_drvdata(spi); @@ -322,8 +322,6 @@ static int b53_spi_remove(struct spi_device *spi) b53_switch_remove(dev); spi_set_drvdata(spi, NULL); - - return 0; } static void b53_spi_shutdown(struct spi_device *spi) diff --git a/drivers/net/dsa/microchip/ksz8795_spi.c b/drivers/net/dsa/microchip/ksz8795_spi.c index 866767b70d65..673589dc88ab 100644 --- a/drivers/net/dsa/microchip/ksz8795_spi.c +++ b/drivers/net/dsa/microchip/ksz8795_spi.c @@ -87,7 +87,7 @@ static int ksz8795_spi_probe(struct spi_device *spi) return 0; } -static int ksz8795_spi_remove(struct spi_device *spi) +static void ksz8795_spi_remove(struct spi_device *spi) { struct ksz_device *dev = spi_get_drvdata(spi); @@ -95,8 +95,6 @@ static int ksz8795_spi_remove(struct spi_device *spi) ksz_switch_remove(dev); spi_set_drvdata(spi, NULL); - - return 0; } static void ksz8795_spi_shutdown(struct spi_device *spi) diff --git a/drivers/net/dsa/microchip/ksz9477_spi.c b/drivers/net/dsa/microchip/ksz9477_spi.c index e3cb0e6c9f6f..940bb9665f15 100644 --- a/drivers/net/dsa/microchip/ksz9477_spi.c +++ b/drivers/net/dsa/microchip/ksz9477_spi.c @@ -65,7 +65,7 @@ static int ksz9477_spi_probe(struct spi_device *spi) return 0; } -static int ksz9477_spi_remove(struct spi_device *spi) +static void ksz9477_spi_remove(struct spi_device *spi) { struct ksz_device *dev = spi_get_drvdata(spi); @@ -73,8 +73,6 @@ static int ksz9477_spi_remove(struct spi_device *spi) ksz_switch_remove(dev); spi_set_drvdata(spi, NULL); - - return 0; } static void ksz9477_spi_shutdown(struct spi_device *spi) diff --git a/drivers/net/dsa/sja1105/sja1105_main.c b/drivers/net/dsa/sja1105/sja1105_main.c index b513713be610..c2a47c6693b8 100644 --- a/drivers/net/dsa/sja1105/sja1105_main.c +++ b/drivers/net/dsa/sja1105/sja1105_main.c @@ -3346,18 +3346,16 @@ static int sja1105_probe(struct spi_device *spi) return dsa_register_switch(priv->ds); } -static int sja1105_remove(struct spi_device *spi) +static void sja1105_remove(struct spi_device *spi) { struct sja1105_private *priv = spi_get_drvdata(spi); if (!priv) - return 0; + return; dsa_unregister_switch(priv->ds); spi_set_drvdata(spi, NULL); - - return 0; } static void sja1105_shutdown(struct spi_device *spi) diff --git a/drivers/net/dsa/vitesse-vsc73xx-spi.c b/drivers/net/dsa/vitesse-vsc73xx-spi.c index 645398901e05..3110895358d8 100644 --- a/drivers/net/dsa/vitesse-vsc73xx-spi.c +++ b/drivers/net/dsa/vitesse-vsc73xx-spi.c @@ -159,18 +159,16 @@ static int vsc73xx_spi_probe(struct spi_device *spi) return vsc73xx_probe(&vsc_spi->vsc); } -static int vsc73xx_spi_remove(struct spi_device *spi) +static void vsc73xx_spi_remove(struct spi_device *spi) { struct vsc73xx_spi *vsc_spi = spi_get_drvdata(spi); if (!vsc_spi) - return 0; + return; vsc73xx_remove(&vsc_spi->vsc); spi_set_drvdata(spi, NULL); - - return 0; } static void vsc73xx_spi_shutdown(struct spi_device *spi) diff --git a/drivers/net/ethernet/asix/ax88796c_main.c b/drivers/net/ethernet/asix/ax88796c_main.c index e7a9f9863258..bf70481bb1ca 100644 --- a/drivers/net/ethernet/asix/ax88796c_main.c +++ b/drivers/net/ethernet/asix/ax88796c_main.c @@ -1102,7 +1102,7 @@ err: return ret; } -static int ax88796c_remove(struct spi_device *spi) +static void ax88796c_remove(struct spi_device *spi) { struct ax88796c_device *ax_local = dev_get_drvdata(&spi->dev); struct net_device *ndev = ax_local->ndev; @@ -1112,8 +1112,6 @@ static int ax88796c_remove(struct spi_device *spi) netif_info(ax_local, probe, ndev, "removing network device %s %s\n", dev_driver_string(&spi->dev), dev_name(&spi->dev)); - - return 0; } #ifdef CONFIG_OF diff --git a/drivers/net/ethernet/micrel/ks8851_spi.c b/drivers/net/ethernet/micrel/ks8851_spi.c index 0303e727e99f..d167d93e4c12 100644 --- a/drivers/net/ethernet/micrel/ks8851_spi.c +++ b/drivers/net/ethernet/micrel/ks8851_spi.c @@ -452,11 +452,9 @@ static int ks8851_probe_spi(struct spi_device *spi) return ks8851_probe_common(netdev, dev, msg_enable); } -static int ks8851_remove_spi(struct spi_device *spi) +static void ks8851_remove_spi(struct spi_device *spi) { ks8851_remove_common(&spi->dev); - - return 0; } static const struct of_device_id ks8851_match_table[] = { diff --git a/drivers/net/ethernet/microchip/enc28j60.c b/drivers/net/ethernet/microchip/enc28j60.c index 634ac7649c43..db5a3edb4c3c 100644 --- a/drivers/net/ethernet/microchip/enc28j60.c +++ b/drivers/net/ethernet/microchip/enc28j60.c @@ -1612,15 +1612,13 @@ error_alloc: return ret; } -static int enc28j60_remove(struct spi_device *spi) +static void enc28j60_remove(struct spi_device *spi) { struct enc28j60_net *priv = spi_get_drvdata(spi); unregister_netdev(priv->netdev); free_irq(spi->irq, priv); free_netdev(priv->netdev); - - return 0; } static const struct of_device_id enc28j60_dt_ids[] = { diff --git a/drivers/net/ethernet/microchip/encx24j600.c b/drivers/net/ethernet/microchip/encx24j600.c index b90efc80fb59..dc1840cb5b10 100644 --- a/drivers/net/ethernet/microchip/encx24j600.c +++ b/drivers/net/ethernet/microchip/encx24j600.c @@ -1093,7 +1093,7 @@ error_out: return ret; } -static int encx24j600_spi_remove(struct spi_device *spi) +static void encx24j600_spi_remove(struct spi_device *spi) { struct encx24j600_priv *priv = dev_get_drvdata(&spi->dev); @@ -1101,8 +1101,6 @@ static int encx24j600_spi_remove(struct spi_device *spi) kthread_stop(priv->kworker_task); free_netdev(priv->ndev); - - return 0; } static const struct spi_device_id encx24j600_spi_id_table[] = { diff --git a/drivers/net/ethernet/qualcomm/qca_spi.c b/drivers/net/ethernet/qualcomm/qca_spi.c index 955cce644392..3c5494afd3c0 100644 --- a/drivers/net/ethernet/qualcomm/qca_spi.c +++ b/drivers/net/ethernet/qualcomm/qca_spi.c @@ -1001,7 +1001,7 @@ qca_spi_probe(struct spi_device *spi) return 0; } -static int +static void qca_spi_remove(struct spi_device *spi) { struct net_device *qcaspi_devs = spi_get_drvdata(spi); @@ -1011,8 +1011,6 @@ qca_spi_remove(struct spi_device *spi) unregister_netdev(qcaspi_devs); free_netdev(qcaspi_devs); - - return 0; } static const struct spi_device_id qca_spi_id[] = { diff --git a/drivers/net/ethernet/vertexcom/mse102x.c b/drivers/net/ethernet/vertexcom/mse102x.c index 89a31783fbb4..25739b182ac7 100644 --- a/drivers/net/ethernet/vertexcom/mse102x.c +++ b/drivers/net/ethernet/vertexcom/mse102x.c @@ -731,7 +731,7 @@ static int mse102x_probe_spi(struct spi_device *spi) return 0; } -static int mse102x_remove_spi(struct spi_device *spi) +static void mse102x_remove_spi(struct spi_device *spi) { struct mse102x_net *mse = dev_get_drvdata(&spi->dev); struct mse102x_net_spi *mses = to_mse102x_spi(mse); @@ -741,8 +741,6 @@ static int mse102x_remove_spi(struct spi_device *spi) mse102x_remove_device_debugfs(mses); unregister_netdev(mse->ndev); - - return 0; } static const struct of_device_id mse102x_match_table[] = { diff --git a/drivers/net/ethernet/wiznet/w5100-spi.c b/drivers/net/ethernet/wiznet/w5100-spi.c index 7779a36da3c8..7c52796273a4 100644 --- a/drivers/net/ethernet/wiznet/w5100-spi.c +++ b/drivers/net/ethernet/wiznet/w5100-spi.c @@ -461,11 +461,9 @@ static int w5100_spi_probe(struct spi_device *spi) return w5100_probe(&spi->dev, ops, priv_size, mac, spi->irq, -EINVAL); } -static int w5100_spi_remove(struct spi_device *spi) +static void w5100_spi_remove(struct spi_device *spi) { w5100_remove(&spi->dev); - - return 0; } static const struct spi_device_id w5100_spi_ids[] = { diff --git a/drivers/net/ieee802154/adf7242.c b/drivers/net/ieee802154/adf7242.c index 7db9cbd0f5de..6afdf1622944 100644 --- a/drivers/net/ieee802154/adf7242.c +++ b/drivers/net/ieee802154/adf7242.c @@ -1304,7 +1304,7 @@ err_alloc_wq: return ret; } -static int adf7242_remove(struct spi_device *spi) +static void adf7242_remove(struct spi_device *spi) { struct adf7242_local *lp = spi_get_drvdata(spi); @@ -1316,8 +1316,6 @@ static int adf7242_remove(struct spi_device *spi) ieee802154_unregister_hw(lp->hw); mutex_destroy(&lp->bmux); ieee802154_free_hw(lp->hw); - - return 0; } static const struct of_device_id adf7242_of_match[] = { diff --git a/drivers/net/ieee802154/at86rf230.c b/drivers/net/ieee802154/at86rf230.c index 7d67f41387f5..a4734323dc29 100644 --- a/drivers/net/ieee802154/at86rf230.c +++ b/drivers/net/ieee802154/at86rf230.c @@ -1759,7 +1759,7 @@ free_dev: return rc; } -static int at86rf230_remove(struct spi_device *spi) +static void at86rf230_remove(struct spi_device *spi) { struct at86rf230_local *lp = spi_get_drvdata(spi); @@ -1769,8 +1769,6 @@ static int at86rf230_remove(struct spi_device *spi) ieee802154_free_hw(lp->hw); at86rf230_debugfs_remove(); dev_dbg(&spi->dev, "unregistered at86rf230\n"); - - return 0; } static const struct of_device_id at86rf230_of_match[] = { diff --git a/drivers/net/ieee802154/ca8210.c b/drivers/net/ieee802154/ca8210.c index ece6ff6049f6..b499bbe4d48f 100644 --- a/drivers/net/ieee802154/ca8210.c +++ b/drivers/net/ieee802154/ca8210.c @@ -831,7 +831,7 @@ static void ca8210_rx_done(struct cas_control *cas_ctl) finish:; } -static int ca8210_remove(struct spi_device *spi_device); +static void ca8210_remove(struct spi_device *spi_device); /** * ca8210_spi_transfer_complete() - Called when a single spi transfer has @@ -3048,7 +3048,7 @@ static void ca8210_test_interface_clear(struct ca8210_priv *priv) * * Return: 0 or linux error code */ -static int ca8210_remove(struct spi_device *spi_device) +static void ca8210_remove(struct spi_device *spi_device) { struct ca8210_priv *priv; struct ca8210_platform_data *pdata; @@ -3088,8 +3088,6 @@ static int ca8210_remove(struct spi_device *spi_device) if (IS_ENABLED(CONFIG_IEEE802154_CA8210_DEBUGFS)) ca8210_test_interface_clear(priv); } - - return 0; } /** diff --git a/drivers/net/ieee802154/cc2520.c b/drivers/net/ieee802154/cc2520.c index 89c046b204e0..1e1f40f628a0 100644 --- a/drivers/net/ieee802154/cc2520.c +++ b/drivers/net/ieee802154/cc2520.c @@ -1213,7 +1213,7 @@ err_hw_init: return ret; } -static int cc2520_remove(struct spi_device *spi) +static void cc2520_remove(struct spi_device *spi) { struct cc2520_private *priv = spi_get_drvdata(spi); @@ -1222,8 +1222,6 @@ static int cc2520_remove(struct spi_device *spi) ieee802154_unregister_hw(priv->hw); ieee802154_free_hw(priv->hw); - - return 0; } static const struct spi_device_id cc2520_ids[] = { diff --git a/drivers/net/ieee802154/mcr20a.c b/drivers/net/ieee802154/mcr20a.c index 8dc04e2590b1..a3af52a8e6dd 100644 --- a/drivers/net/ieee802154/mcr20a.c +++ b/drivers/net/ieee802154/mcr20a.c @@ -1335,7 +1335,7 @@ free_dev: return ret; } -static int mcr20a_remove(struct spi_device *spi) +static void mcr20a_remove(struct spi_device *spi) { struct mcr20a_local *lp = spi_get_drvdata(spi); @@ -1343,8 +1343,6 @@ static int mcr20a_remove(struct spi_device *spi) ieee802154_unregister_hw(lp->hw); ieee802154_free_hw(lp->hw); - - return 0; } static const struct of_device_id mcr20a_of_match[] = { diff --git a/drivers/net/ieee802154/mrf24j40.c b/drivers/net/ieee802154/mrf24j40.c index ff83e00b77af..ee4cfbf2c5cc 100644 --- a/drivers/net/ieee802154/mrf24j40.c +++ b/drivers/net/ieee802154/mrf24j40.c @@ -1356,7 +1356,7 @@ err_ret: return ret; } -static int mrf24j40_remove(struct spi_device *spi) +static void mrf24j40_remove(struct spi_device *spi) { struct mrf24j40 *devrec = spi_get_drvdata(spi); @@ -1366,8 +1366,6 @@ static int mrf24j40_remove(struct spi_device *spi) ieee802154_free_hw(devrec->hw); /* TODO: Will ieee802154_free_device() wait until ->xmit() is * complete? */ - - return 0; } static const struct of_device_id mrf24j40_of_match[] = { diff --git a/drivers/net/phy/spi_ks8995.c b/drivers/net/phy/spi_ks8995.c index 8b5445a724ce..ff37f8ba6758 100644 --- a/drivers/net/phy/spi_ks8995.c +++ b/drivers/net/phy/spi_ks8995.c @@ -517,7 +517,7 @@ static int ks8995_probe(struct spi_device *spi) return 0; } -static int ks8995_remove(struct spi_device *spi) +static void ks8995_remove(struct spi_device *spi) { struct ks8995_switch *ks = spi_get_drvdata(spi); @@ -526,8 +526,6 @@ static int ks8995_remove(struct spi_device *spi) /* assert reset */ if (ks->pdata && gpio_is_valid(ks->pdata->reset_gpio)) gpiod_set_value(gpio_to_desc(ks->pdata->reset_gpio), 1); - - return 0; } /* ------------------------------------------------------------------------ */ diff --git a/drivers/net/wan/slic_ds26522.c b/drivers/net/wan/slic_ds26522.c index 8e3b1c717c10..6063552cea9b 100644 --- a/drivers/net/wan/slic_ds26522.c +++ b/drivers/net/wan/slic_ds26522.c @@ -194,10 +194,9 @@ static int slic_ds26522_init_configure(struct spi_device *spi) return 0; } -static int slic_ds26522_remove(struct spi_device *spi) +static void slic_ds26522_remove(struct spi_device *spi) { pr_info("DS26522 module uninstalled\n"); - return 0; } static int slic_ds26522_probe(struct spi_device *spi) diff --git a/drivers/net/wireless/intersil/p54/p54spi.c b/drivers/net/wireless/intersil/p54/p54spi.c index ab0fe8565851..f99b7ba69fc3 100644 --- a/drivers/net/wireless/intersil/p54/p54spi.c +++ b/drivers/net/wireless/intersil/p54/p54spi.c @@ -669,7 +669,7 @@ err_free: return ret; } -static int p54spi_remove(struct spi_device *spi) +static void p54spi_remove(struct spi_device *spi) { struct p54s_priv *priv = spi_get_drvdata(spi); @@ -684,8 +684,6 @@ static int p54spi_remove(struct spi_device *spi) mutex_destroy(&priv->mutex); p54_free_common(priv->hw); - - return 0; } diff --git a/drivers/net/wireless/marvell/libertas/if_spi.c b/drivers/net/wireless/marvell/libertas/if_spi.c index cd9f8ecf171f..ff1c7ec8c450 100644 --- a/drivers/net/wireless/marvell/libertas/if_spi.c +++ b/drivers/net/wireless/marvell/libertas/if_spi.c @@ -1195,7 +1195,7 @@ out: return err; } -static int libertas_spi_remove(struct spi_device *spi) +static void libertas_spi_remove(struct spi_device *spi) { struct if_spi_card *card = spi_get_drvdata(spi); struct lbs_private *priv = card->priv; @@ -1212,8 +1212,6 @@ static int libertas_spi_remove(struct spi_device *spi) if (card->pdata->teardown) card->pdata->teardown(spi); free_if_spi_card(card); - - return 0; } static int if_spi_suspend(struct device *dev) diff --git a/drivers/net/wireless/microchip/wilc1000/spi.c b/drivers/net/wireless/microchip/wilc1000/spi.c index 2c2ed4b09efd..d2db52289399 100644 --- a/drivers/net/wireless/microchip/wilc1000/spi.c +++ b/drivers/net/wireless/microchip/wilc1000/spi.c @@ -240,7 +240,7 @@ free: return ret; } -static int wilc_bus_remove(struct spi_device *spi) +static void wilc_bus_remove(struct spi_device *spi) { struct wilc *wilc = spi_get_drvdata(spi); struct wilc_spi *spi_priv = wilc->bus_data; @@ -248,8 +248,6 @@ static int wilc_bus_remove(struct spi_device *spi) clk_disable_unprepare(wilc->rtc_clk); wilc_netdev_cleanup(wilc); kfree(spi_priv); - - return 0; } static const struct of_device_id wilc_of_match[] = { diff --git a/drivers/net/wireless/st/cw1200/cw1200_spi.c b/drivers/net/wireless/st/cw1200/cw1200_spi.c index 271ed2ce2d7f..fe0d220da44d 100644 --- a/drivers/net/wireless/st/cw1200/cw1200_spi.c +++ b/drivers/net/wireless/st/cw1200/cw1200_spi.c @@ -423,7 +423,7 @@ static int cw1200_spi_probe(struct spi_device *func) } /* Disconnect Function to be called by SPI stack when device is disconnected */ -static int cw1200_spi_disconnect(struct spi_device *func) +static void cw1200_spi_disconnect(struct spi_device *func) { struct hwbus_priv *self = spi_get_drvdata(func); @@ -435,8 +435,6 @@ static int cw1200_spi_disconnect(struct spi_device *func) } } cw1200_spi_off(dev_get_platdata(&func->dev)); - - return 0; } static int __maybe_unused cw1200_spi_suspend(struct device *dev) diff --git a/drivers/net/wireless/ti/wl1251/spi.c b/drivers/net/wireless/ti/wl1251/spi.c index 5b894bd6237e..9df38726e8b0 100644 --- a/drivers/net/wireless/ti/wl1251/spi.c +++ b/drivers/net/wireless/ti/wl1251/spi.c @@ -327,14 +327,12 @@ out_free: return ret; } -static int wl1251_spi_remove(struct spi_device *spi) +static void wl1251_spi_remove(struct spi_device *spi) { struct wl1251 *wl = spi_get_drvdata(spi); wl1251_free_hw(wl); regulator_disable(wl->vio); - - return 0; } static struct spi_driver wl1251_spi_driver = { diff --git a/drivers/net/wireless/ti/wlcore/spi.c b/drivers/net/wireless/ti/wlcore/spi.c index 354a7e1c3315..7eae1ec2eb2b 100644 --- a/drivers/net/wireless/ti/wlcore/spi.c +++ b/drivers/net/wireless/ti/wlcore/spi.c @@ -546,13 +546,11 @@ out_dev_put: return ret; } -static int wl1271_remove(struct spi_device *spi) +static void wl1271_remove(struct spi_device *spi) { struct wl12xx_spi_glue *glue = spi_get_drvdata(spi); platform_device_unregister(glue->core); - - return 0; } static struct spi_driver wl1271_spi_driver = { diff --git a/drivers/nfc/nfcmrvl/spi.c b/drivers/nfc/nfcmrvl/spi.c index 5b833a9a83f8..a38e2fcdfd39 100644 --- a/drivers/nfc/nfcmrvl/spi.c +++ b/drivers/nfc/nfcmrvl/spi.c @@ -174,12 +174,11 @@ static int nfcmrvl_spi_probe(struct spi_device *spi) return 0; } -static int nfcmrvl_spi_remove(struct spi_device *spi) +static void nfcmrvl_spi_remove(struct spi_device *spi) { struct nfcmrvl_spi_drv_data *drv_data = spi_get_drvdata(spi); nfcmrvl_nci_unregister_dev(drv_data->priv); - return 0; } static const struct of_device_id of_nfcmrvl_spi_match[] __maybe_unused = { diff --git a/drivers/nfc/st-nci/spi.c b/drivers/nfc/st-nci/spi.c index 4e723992e74c..169eacc0a32a 100644 --- a/drivers/nfc/st-nci/spi.c +++ b/drivers/nfc/st-nci/spi.c @@ -263,13 +263,11 @@ static int st_nci_spi_probe(struct spi_device *dev) return r; } -static int st_nci_spi_remove(struct spi_device *dev) +static void st_nci_spi_remove(struct spi_device *dev) { struct st_nci_spi_phy *phy = spi_get_drvdata(dev); ndlc_remove(phy->ndlc); - - return 0; } static struct spi_device_id st_nci_spi_id_table[] = { diff --git a/drivers/nfc/st95hf/core.c b/drivers/nfc/st95hf/core.c index b23f47936473..ed704bb77226 100644 --- a/drivers/nfc/st95hf/core.c +++ b/drivers/nfc/st95hf/core.c @@ -1198,7 +1198,7 @@ err_disable_regulator: return ret; } -static int st95hf_remove(struct spi_device *nfc_spi_dev) +static void st95hf_remove(struct spi_device *nfc_spi_dev) { int result = 0; unsigned char reset_cmd = ST95HF_COMMAND_RESET; @@ -1236,8 +1236,6 @@ static int st95hf_remove(struct spi_device *nfc_spi_dev) /* disable regulator */ if (stcontext->st95hf_supply) regulator_disable(stcontext->st95hf_supply); - - return 0; } /* Register as SPI protocol driver */ diff --git a/drivers/nfc/trf7970a.c b/drivers/nfc/trf7970a.c index 29ca9c328df2..21d68664fe08 100644 --- a/drivers/nfc/trf7970a.c +++ b/drivers/nfc/trf7970a.c @@ -2144,7 +2144,7 @@ err_destroy_lock: return ret; } -static int trf7970a_remove(struct spi_device *spi) +static void trf7970a_remove(struct spi_device *spi) { struct trf7970a *trf = spi_get_drvdata(spi); @@ -2160,8 +2160,6 @@ static int trf7970a_remove(struct spi_device *spi) regulator_disable(trf->regulator); mutex_destroy(&trf->lock); - - return 0; } #ifdef CONFIG_PM_SLEEP diff --git a/drivers/platform/chrome/cros_ec_spi.c b/drivers/platform/chrome/cros_ec_spi.c index 713c58687721..8493af0f680e 100644 --- a/drivers/platform/chrome/cros_ec_spi.c +++ b/drivers/platform/chrome/cros_ec_spi.c @@ -786,13 +786,11 @@ static int cros_ec_spi_probe(struct spi_device *spi) return 0; } -static int cros_ec_spi_remove(struct spi_device *spi) +static void cros_ec_spi_remove(struct spi_device *spi) { struct cros_ec_device *ec_dev = spi_get_drvdata(spi); cros_ec_unregister(ec_dev); - - return 0; } #ifdef CONFIG_PM_SLEEP diff --git a/drivers/platform/olpc/olpc-xo175-ec.c b/drivers/platform/olpc/olpc-xo175-ec.c index 0d46706afd2d..4823bd2819f6 100644 --- a/drivers/platform/olpc/olpc-xo175-ec.c +++ b/drivers/platform/olpc/olpc-xo175-ec.c @@ -648,7 +648,7 @@ static struct olpc_ec_driver olpc_xo175_ec_driver = { .ec_cmd = olpc_xo175_ec_cmd, }; -static int olpc_xo175_ec_remove(struct spi_device *spi) +static void olpc_xo175_ec_remove(struct spi_device *spi) { if (pm_power_off == olpc_xo175_ec_power_off) pm_power_off = NULL; @@ -657,8 +657,6 @@ static int olpc_xo175_ec_remove(struct spi_device *spi) platform_device_unregister(olpc_ec); olpc_ec = NULL; - - return 0; } static int olpc_xo175_ec_probe(struct spi_device *spi) diff --git a/drivers/rtc/rtc-ds1302.c b/drivers/rtc/rtc-ds1302.c index 2f83adef966e..6d66ab5a8b17 100644 --- a/drivers/rtc/rtc-ds1302.c +++ b/drivers/rtc/rtc-ds1302.c @@ -185,10 +185,9 @@ static int ds1302_probe(struct spi_device *spi) return 0; } -static int ds1302_remove(struct spi_device *spi) +static void ds1302_remove(struct spi_device *spi) { spi_set_drvdata(spi, NULL); - return 0; } #ifdef CONFIG_OF diff --git a/drivers/rtc/rtc-ds1305.c b/drivers/rtc/rtc-ds1305.c index 9ef107b99b65..ed9360486953 100644 --- a/drivers/rtc/rtc-ds1305.c +++ b/drivers/rtc/rtc-ds1305.c @@ -720,7 +720,7 @@ static int ds1305_probe(struct spi_device *spi) return 0; } -static int ds1305_remove(struct spi_device *spi) +static void ds1305_remove(struct spi_device *spi) { struct ds1305 *ds1305 = spi_get_drvdata(spi); @@ -730,8 +730,6 @@ static int ds1305_remove(struct spi_device *spi) devm_free_irq(&spi->dev, spi->irq, ds1305); cancel_work_sync(&ds1305->work); } - - return 0; } static struct spi_driver ds1305_driver = { diff --git a/drivers/rtc/rtc-ds1343.c b/drivers/rtc/rtc-ds1343.c index f14ed6c96437..ed5a6ba89a3e 100644 --- a/drivers/rtc/rtc-ds1343.c +++ b/drivers/rtc/rtc-ds1343.c @@ -434,11 +434,9 @@ static int ds1343_probe(struct spi_device *spi) return 0; } -static int ds1343_remove(struct spi_device *spi) +static void ds1343_remove(struct spi_device *spi) { dev_pm_clear_wake_irq(&spi->dev); - - return 0; } #ifdef CONFIG_PM_SLEEP diff --git a/drivers/spi/spi-mem.c b/drivers/spi/spi-mem.c index 37f4443ce9a0..e9d83d65873b 100644 --- a/drivers/spi/spi-mem.c +++ b/drivers/spi/spi-mem.c @@ -854,15 +854,13 @@ static int spi_mem_probe(struct spi_device *spi) return memdrv->probe(mem); } -static int spi_mem_remove(struct spi_device *spi) +static void spi_mem_remove(struct spi_device *spi) { struct spi_mem_driver *memdrv = to_spi_mem_drv(spi->dev.driver); struct spi_mem *mem = spi_get_drvdata(spi); if (memdrv->remove) - return memdrv->remove(mem); - - return 0; + memdrv->remove(mem); } static void spi_mem_shutdown(struct spi_device *spi) diff --git a/drivers/spi/spi-slave-system-control.c b/drivers/spi/spi-slave-system-control.c index 169f3d595f60..d37cfe995a63 100644 --- a/drivers/spi/spi-slave-system-control.c +++ b/drivers/spi/spi-slave-system-control.c @@ -132,13 +132,12 @@ static int spi_slave_system_control_probe(struct spi_device *spi) return 0; } -static int spi_slave_system_control_remove(struct spi_device *spi) +static void spi_slave_system_control_remove(struct spi_device *spi) { struct spi_slave_system_control_priv *priv = spi_get_drvdata(spi); spi_slave_abort(spi); wait_for_completion(&priv->finished); - return 0; } static struct spi_driver spi_slave_system_control_driver = { diff --git a/drivers/spi/spi-slave-time.c b/drivers/spi/spi-slave-time.c index f2e07a392d68..f56c1afb8534 100644 --- a/drivers/spi/spi-slave-time.c +++ b/drivers/spi/spi-slave-time.c @@ -106,13 +106,12 @@ static int spi_slave_time_probe(struct spi_device *spi) return 0; } -static int spi_slave_time_remove(struct spi_device *spi) +static void spi_slave_time_remove(struct spi_device *spi) { struct spi_slave_time_priv *priv = spi_get_drvdata(spi); spi_slave_abort(spi); wait_for_completion(&priv->finished); - return 0; } static struct spi_driver spi_slave_time_driver = { diff --git a/drivers/spi/spi-tle62x0.c b/drivers/spi/spi-tle62x0.c index f8ad0709d015..a565352f6381 100644 --- a/drivers/spi/spi-tle62x0.c +++ b/drivers/spi/spi-tle62x0.c @@ -288,7 +288,7 @@ static int tle62x0_probe(struct spi_device *spi) return ret; } -static int tle62x0_remove(struct spi_device *spi) +static void tle62x0_remove(struct spi_device *spi) { struct tle62x0_state *st = spi_get_drvdata(spi); int ptr; @@ -298,7 +298,6 @@ static int tle62x0_remove(struct spi_device *spi) device_remove_file(&spi->dev, &dev_attr_status_show); kfree(st); - return 0; } static struct spi_driver tle62x0_driver = { diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index 4599b121d744..ead9a132dcb9 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -404,15 +404,8 @@ static void spi_remove(struct device *dev) { const struct spi_driver *sdrv = to_spi_driver(dev->driver); - if (sdrv->remove) { - int ret; - - ret = sdrv->remove(to_spi_device(dev)); - if (ret) - dev_warn(dev, - "Failed to unbind driver (%pe), ignoring\n", - ERR_PTR(ret)); - } + if (sdrv->remove) + sdrv->remove(to_spi_device(dev)); dev_pm_domain_detach(dev, true); } diff --git a/drivers/spi/spidev.c b/drivers/spi/spidev.c index a5cceca8b82b..9468f74308bd 100644 --- a/drivers/spi/spidev.c +++ b/drivers/spi/spidev.c @@ -803,7 +803,7 @@ static int spidev_probe(struct spi_device *spi) return status; } -static int spidev_remove(struct spi_device *spi) +static void spidev_remove(struct spi_device *spi) { struct spidev_data *spidev = spi_get_drvdata(spi); @@ -820,8 +820,6 @@ static int spidev_remove(struct spi_device *spi) if (spidev->users == 0) kfree(spidev); mutex_unlock(&device_list_lock); - - return 0; } static struct spi_driver spidev_spi_driver = { diff --git a/drivers/staging/fbtft/fbtft.h b/drivers/staging/fbtft/fbtft.h index 6a7545b5bcd2..b68f5f9b7c78 100644 --- a/drivers/staging/fbtft/fbtft.h +++ b/drivers/staging/fbtft/fbtft.h @@ -286,12 +286,11 @@ static int fbtft_driver_probe_spi(struct spi_device *spi) \ return fbtft_probe_common(_display, spi, NULL); \ } \ \ -static int fbtft_driver_remove_spi(struct spi_device *spi) \ +static void fbtft_driver_remove_spi(struct spi_device *spi) \ { \ struct fb_info *info = spi_get_drvdata(spi); \ \ fbtft_remove_common(&spi->dev, info); \ - return 0; \ } \ \ static struct spi_driver fbtft_driver_spi_driver = { \ diff --git a/drivers/staging/pi433/pi433_if.c b/drivers/staging/pi433/pi433_if.c index 68c09fa016ed..1d31c35875e3 100644 --- a/drivers/staging/pi433/pi433_if.c +++ b/drivers/staging/pi433/pi433_if.c @@ -1264,7 +1264,7 @@ RX_failed: return retval; } -static int pi433_remove(struct spi_device *spi) +static void pi433_remove(struct spi_device *spi) { struct pi433_device *device = spi_get_drvdata(spi); @@ -1284,8 +1284,6 @@ static int pi433_remove(struct spi_device *spi) kfree(device->rx_buffer); kfree(device); - - return 0; } static const struct of_device_id pi433_dt_ids[] = { diff --git a/drivers/staging/wfx/bus_spi.c b/drivers/staging/wfx/bus_spi.c index 55ffcd7c42e2..fa0ff66a457d 100644 --- a/drivers/staging/wfx/bus_spi.c +++ b/drivers/staging/wfx/bus_spi.c @@ -232,12 +232,11 @@ static int wfx_spi_probe(struct spi_device *func) return wfx_probe(bus->core); } -static int wfx_spi_remove(struct spi_device *func) +static void wfx_spi_remove(struct spi_device *func) { struct wfx_spi_priv *bus = spi_get_drvdata(func); wfx_release(bus->core); - return 0; } /* For dynamic driver binding, kernel does not use OF to match driver. It only diff --git a/drivers/tty/serial/max3100.c b/drivers/tty/serial/max3100.c index 3c92d4e01488..516cff362434 100644 --- a/drivers/tty/serial/max3100.c +++ b/drivers/tty/serial/max3100.c @@ -805,7 +805,7 @@ static int max3100_probe(struct spi_device *spi) return 0; } -static int max3100_remove(struct spi_device *spi) +static void max3100_remove(struct spi_device *spi) { struct max3100_port *s = spi_get_drvdata(spi); int i; @@ -828,13 +828,12 @@ static int max3100_remove(struct spi_device *spi) for (i = 0; i < MAX_MAX3100; i++) if (max3100s[i]) { mutex_unlock(&max3100s_lock); - return 0; + return; } pr_debug("removing max3100 driver\n"); uart_unregister_driver(&max3100_uart_driver); mutex_unlock(&max3100s_lock); - return 0; } #ifdef CONFIG_PM_SLEEP diff --git a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c index dde0824b2fa5..3112b4a05448 100644 --- a/drivers/tty/serial/max310x.c +++ b/drivers/tty/serial/max310x.c @@ -1487,10 +1487,9 @@ static int max310x_spi_probe(struct spi_device *spi) return max310x_probe(&spi->dev, devtype, regmap, spi->irq); } -static int max310x_spi_remove(struct spi_device *spi) +static void max310x_spi_remove(struct spi_device *spi) { max310x_remove(&spi->dev); - return 0; } static const struct spi_device_id max310x_id_table[] = { diff --git a/drivers/tty/serial/sc16is7xx.c b/drivers/tty/serial/sc16is7xx.c index 64e7e6c8145f..25d67b8c4db7 100644 --- a/drivers/tty/serial/sc16is7xx.c +++ b/drivers/tty/serial/sc16is7xx.c @@ -1440,11 +1440,9 @@ static int sc16is7xx_spi_probe(struct spi_device *spi) return sc16is7xx_probe(&spi->dev, devtype, regmap, spi->irq); } -static int sc16is7xx_spi_remove(struct spi_device *spi) +static void sc16is7xx_spi_remove(struct spi_device *spi) { sc16is7xx_remove(&spi->dev); - - return 0; } static const struct spi_device_id sc16is7xx_spi_id_table[] = { diff --git a/drivers/usb/gadget/udc/max3420_udc.c b/drivers/usb/gadget/udc/max3420_udc.c index d2a2b20cc1ad..7d9bd16190c0 100644 --- a/drivers/usb/gadget/udc/max3420_udc.c +++ b/drivers/usb/gadget/udc/max3420_udc.c @@ -1292,7 +1292,7 @@ del_gadget: return err; } -static int max3420_remove(struct spi_device *spi) +static void max3420_remove(struct spi_device *spi) { struct max3420_udc *udc = spi_get_drvdata(spi); unsigned long flags; @@ -1304,8 +1304,6 @@ static int max3420_remove(struct spi_device *spi) kthread_stop(udc->thread_task); spin_unlock_irqrestore(&udc->lock, flags); - - return 0; } static const struct of_device_id max3420_udc_of_match[] = { diff --git a/drivers/usb/host/max3421-hcd.c b/drivers/usb/host/max3421-hcd.c index 30de85a707fe..99a5523a79fb 100644 --- a/drivers/usb/host/max3421-hcd.c +++ b/drivers/usb/host/max3421-hcd.c @@ -1926,7 +1926,7 @@ error: return retval; } -static int +static void max3421_remove(struct spi_device *spi) { struct max3421_hcd *max3421_hcd; @@ -1947,7 +1947,6 @@ max3421_remove(struct spi_device *spi) free_irq(spi->irq, hcd); usb_put_hcd(hcd); - return 0; } static const struct of_device_id max3421_of_match_table[] = { diff --git a/drivers/video/backlight/ams369fg06.c b/drivers/video/backlight/ams369fg06.c index 8a4361e95a11..522dd81110b8 100644 --- a/drivers/video/backlight/ams369fg06.c +++ b/drivers/video/backlight/ams369fg06.c @@ -506,12 +506,11 @@ static int ams369fg06_probe(struct spi_device *spi) return 0; } -static int ams369fg06_remove(struct spi_device *spi) +static void ams369fg06_remove(struct spi_device *spi) { struct ams369fg06 *lcd = spi_get_drvdata(spi); ams369fg06_power(lcd, FB_BLANK_POWERDOWN); - return 0; } #ifdef CONFIG_PM_SLEEP diff --git a/drivers/video/backlight/corgi_lcd.c b/drivers/video/backlight/corgi_lcd.c index 33f5d80495e6..0a57033ae31d 100644 --- a/drivers/video/backlight/corgi_lcd.c +++ b/drivers/video/backlight/corgi_lcd.c @@ -542,7 +542,7 @@ static int corgi_lcd_probe(struct spi_device *spi) return 0; } -static int corgi_lcd_remove(struct spi_device *spi) +static void corgi_lcd_remove(struct spi_device *spi) { struct corgi_lcd *lcd = spi_get_drvdata(spi); @@ -550,7 +550,6 @@ static int corgi_lcd_remove(struct spi_device *spi) lcd->bl_dev->props.brightness = 0; backlight_update_status(lcd->bl_dev); corgi_lcd_set_power(lcd->lcd_dev, FB_BLANK_POWERDOWN); - return 0; } static struct spi_driver corgi_lcd_driver = { diff --git a/drivers/video/backlight/ili922x.c b/drivers/video/backlight/ili922x.c index 328aba9cddad..e7b6bd827986 100644 --- a/drivers/video/backlight/ili922x.c +++ b/drivers/video/backlight/ili922x.c @@ -526,10 +526,9 @@ static int ili922x_probe(struct spi_device *spi) return 0; } -static int ili922x_remove(struct spi_device *spi) +static void ili922x_remove(struct spi_device *spi) { ili922x_poweroff(spi); - return 0; } static struct spi_driver ili922x_driver = { diff --git a/drivers/video/backlight/l4f00242t03.c b/drivers/video/backlight/l4f00242t03.c index 46f97d1c3d21..cc763cf15f53 100644 --- a/drivers/video/backlight/l4f00242t03.c +++ b/drivers/video/backlight/l4f00242t03.c @@ -223,12 +223,11 @@ static int l4f00242t03_probe(struct spi_device *spi) return 0; } -static int l4f00242t03_remove(struct spi_device *spi) +static void l4f00242t03_remove(struct spi_device *spi) { struct l4f00242t03_priv *priv = spi_get_drvdata(spi); l4f00242t03_lcd_power_set(priv->ld, FB_BLANK_POWERDOWN); - return 0; } static void l4f00242t03_shutdown(struct spi_device *spi) diff --git a/drivers/video/backlight/lms501kf03.c b/drivers/video/backlight/lms501kf03.c index f949b66dce1b..5c46df8022bf 100644 --- a/drivers/video/backlight/lms501kf03.c +++ b/drivers/video/backlight/lms501kf03.c @@ -364,12 +364,11 @@ static int lms501kf03_probe(struct spi_device *spi) return 0; } -static int lms501kf03_remove(struct spi_device *spi) +static void lms501kf03_remove(struct spi_device *spi) { struct lms501kf03 *lcd = spi_get_drvdata(spi); lms501kf03_power(lcd, FB_BLANK_POWERDOWN); - return 0; } #ifdef CONFIG_PM_SLEEP diff --git a/drivers/video/backlight/ltv350qv.c b/drivers/video/backlight/ltv350qv.c index 5cbf621e48bd..b6d373af6e3f 100644 --- a/drivers/video/backlight/ltv350qv.c +++ b/drivers/video/backlight/ltv350qv.c @@ -255,12 +255,11 @@ static int ltv350qv_probe(struct spi_device *spi) return 0; } -static int ltv350qv_remove(struct spi_device *spi) +static void ltv350qv_remove(struct spi_device *spi) { struct ltv350qv *lcd = spi_get_drvdata(spi); ltv350qv_power(lcd, FB_BLANK_POWERDOWN); - return 0; } #ifdef CONFIG_PM_SLEEP diff --git a/drivers/video/backlight/tdo24m.c b/drivers/video/backlight/tdo24m.c index 0de044dcafd5..fc6fbaf85594 100644 --- a/drivers/video/backlight/tdo24m.c +++ b/drivers/video/backlight/tdo24m.c @@ -397,12 +397,11 @@ static int tdo24m_probe(struct spi_device *spi) return 0; } -static int tdo24m_remove(struct spi_device *spi) +static void tdo24m_remove(struct spi_device *spi) { struct tdo24m *lcd = spi_get_drvdata(spi); tdo24m_power(lcd, FB_BLANK_POWERDOWN); - return 0; } #ifdef CONFIG_PM_SLEEP diff --git a/drivers/video/backlight/tosa_lcd.c b/drivers/video/backlight/tosa_lcd.c index 38765544345b..23d6c6bf0f54 100644 --- a/drivers/video/backlight/tosa_lcd.c +++ b/drivers/video/backlight/tosa_lcd.c @@ -232,15 +232,13 @@ err_register: return ret; } -static int tosa_lcd_remove(struct spi_device *spi) +static void tosa_lcd_remove(struct spi_device *spi) { struct tosa_lcd_data *data = spi_get_drvdata(spi); i2c_unregister_device(data->i2c); tosa_lcd_tg_off(data); - - return 0; } #ifdef CONFIG_PM_SLEEP diff --git a/drivers/video/backlight/vgg2432a4.c b/drivers/video/backlight/vgg2432a4.c index 3567b45f9ba9..bfc1913e8b55 100644 --- a/drivers/video/backlight/vgg2432a4.c +++ b/drivers/video/backlight/vgg2432a4.c @@ -233,11 +233,9 @@ static int vgg2432a4_probe(struct spi_device *spi) return 0; } -static int vgg2432a4_remove(struct spi_device *spi) +static void vgg2432a4_remove(struct spi_device *spi) { ili9320_remove(spi_get_drvdata(spi)); - - return 0; } static void vgg2432a4_shutdown(struct spi_device *spi) diff --git a/drivers/video/fbdev/omap/lcd_mipid.c b/drivers/video/fbdev/omap/lcd_mipid.c index a75ae0c9b14c..03cff39d392d 100644 --- a/drivers/video/fbdev/omap/lcd_mipid.c +++ b/drivers/video/fbdev/omap/lcd_mipid.c @@ -570,14 +570,12 @@ static int mipid_spi_probe(struct spi_device *spi) return 0; } -static int mipid_spi_remove(struct spi_device *spi) +static void mipid_spi_remove(struct spi_device *spi) { struct mipid_device *md = dev_get_drvdata(&spi->dev); mipid_disable(&md->panel); kfree(md); - - return 0; } static struct spi_driver mipid_spi_driver = { diff --git a/drivers/video/fbdev/omap2/omapfb/displays/panel-lgphilips-lb035q02.c b/drivers/video/fbdev/omap2/omapfb/displays/panel-lgphilips-lb035q02.c index 1bec7a4422e8..aab67721263d 100644 --- a/drivers/video/fbdev/omap2/omapfb/displays/panel-lgphilips-lb035q02.c +++ b/drivers/video/fbdev/omap2/omapfb/displays/panel-lgphilips-lb035q02.c @@ -316,7 +316,7 @@ err_gpio: return r; } -static int lb035q02_panel_spi_remove(struct spi_device *spi) +static void lb035q02_panel_spi_remove(struct spi_device *spi) { struct panel_drv_data *ddata = spi_get_drvdata(spi); struct omap_dss_device *dssdev = &ddata->dssdev; @@ -328,8 +328,6 @@ static int lb035q02_panel_spi_remove(struct spi_device *spi) lb035q02_disconnect(dssdev); omap_dss_put_device(in); - - return 0; } static const struct of_device_id lb035q02_of_match[] = { diff --git a/drivers/video/fbdev/omap2/omapfb/displays/panel-nec-nl8048hl11.c b/drivers/video/fbdev/omap2/omapfb/displays/panel-nec-nl8048hl11.c index dff9ebbadfc0..be9910ff6e62 100644 --- a/drivers/video/fbdev/omap2/omapfb/displays/panel-nec-nl8048hl11.c +++ b/drivers/video/fbdev/omap2/omapfb/displays/panel-nec-nl8048hl11.c @@ -327,7 +327,7 @@ err_gpio: return r; } -static int nec_8048_remove(struct spi_device *spi) +static void nec_8048_remove(struct spi_device *spi) { struct panel_drv_data *ddata = dev_get_drvdata(&spi->dev); struct omap_dss_device *dssdev = &ddata->dssdev; @@ -341,8 +341,6 @@ static int nec_8048_remove(struct spi_device *spi) nec_8048_disconnect(dssdev); omap_dss_put_device(in); - - return 0; } #ifdef CONFIG_PM_SLEEP diff --git a/drivers/video/fbdev/omap2/omapfb/displays/panel-sony-acx565akm.c b/drivers/video/fbdev/omap2/omapfb/displays/panel-sony-acx565akm.c index 8d8b5ff7d43c..a909b5385ca5 100644 --- a/drivers/video/fbdev/omap2/omapfb/displays/panel-sony-acx565akm.c +++ b/drivers/video/fbdev/omap2/omapfb/displays/panel-sony-acx565akm.c @@ -857,7 +857,7 @@ err_gpio: return r; } -static int acx565akm_remove(struct spi_device *spi) +static void acx565akm_remove(struct spi_device *spi) { struct panel_drv_data *ddata = dev_get_drvdata(&spi->dev); struct omap_dss_device *dssdev = &ddata->dssdev; @@ -874,8 +874,6 @@ static int acx565akm_remove(struct spi_device *spi) acx565akm_disconnect(dssdev); omap_dss_put_device(in); - - return 0; } static const struct of_device_id acx565akm_of_match[] = { diff --git a/drivers/video/fbdev/omap2/omapfb/displays/panel-tpo-td028ttec1.c b/drivers/video/fbdev/omap2/omapfb/displays/panel-tpo-td028ttec1.c index 595ebd8bd5dc..3c0f887d3092 100644 --- a/drivers/video/fbdev/omap2/omapfb/displays/panel-tpo-td028ttec1.c +++ b/drivers/video/fbdev/omap2/omapfb/displays/panel-tpo-td028ttec1.c @@ -425,7 +425,7 @@ err_reg: return r; } -static int td028ttec1_panel_remove(struct spi_device *spi) +static void td028ttec1_panel_remove(struct spi_device *spi) { struct panel_drv_data *ddata = dev_get_drvdata(&spi->dev); struct omap_dss_device *dssdev = &ddata->dssdev; @@ -439,8 +439,6 @@ static int td028ttec1_panel_remove(struct spi_device *spi) td028ttec1_panel_disconnect(dssdev); omap_dss_put_device(in); - - return 0; } static const struct of_device_id td028ttec1_of_match[] = { diff --git a/drivers/video/fbdev/omap2/omapfb/displays/panel-tpo-td043mtea1.c b/drivers/video/fbdev/omap2/omapfb/displays/panel-tpo-td043mtea1.c index afac1d9445aa..58bbba7c037f 100644 --- a/drivers/video/fbdev/omap2/omapfb/displays/panel-tpo-td043mtea1.c +++ b/drivers/video/fbdev/omap2/omapfb/displays/panel-tpo-td043mtea1.c @@ -564,7 +564,7 @@ err_regulator: return r; } -static int tpo_td043_remove(struct spi_device *spi) +static void tpo_td043_remove(struct spi_device *spi) { struct panel_drv_data *ddata = dev_get_drvdata(&spi->dev); struct omap_dss_device *dssdev = &ddata->dssdev; @@ -580,8 +580,6 @@ static int tpo_td043_remove(struct spi_device *spi) omap_dss_put_device(in); sysfs_remove_group(&spi->dev.kobj, &tpo_td043_attr_group); - - return 0; } #ifdef CONFIG_PM_SLEEP diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h index 7ab3fed7b804..c84e61b99c7b 100644 --- a/include/linux/spi/spi.h +++ b/include/linux/spi/spi.h @@ -280,7 +280,7 @@ struct spi_message; struct spi_driver { const struct spi_device_id *id_table; int (*probe)(struct spi_device *spi); - int (*remove)(struct spi_device *spi); + void (*remove)(struct spi_device *spi); void (*shutdown)(struct spi_device *spi); struct device_driver driver; }; diff --git a/sound/pci/hda/cs35l41_hda_spi.c b/sound/pci/hda/cs35l41_hda_spi.c index 9f8123893cc8..50eb6c0e6658 100644 --- a/sound/pci/hda/cs35l41_hda_spi.c +++ b/sound/pci/hda/cs35l41_hda_spi.c @@ -28,11 +28,9 @@ static int cs35l41_hda_spi_probe(struct spi_device *spi) devm_regmap_init_spi(spi, &cs35l41_regmap_spi)); } -static int cs35l41_hda_spi_remove(struct spi_device *spi) +static void cs35l41_hda_spi_remove(struct spi_device *spi) { cs35l41_hda_remove(&spi->dev); - - return 0; } static const struct spi_device_id cs35l41_hda_spi_id[] = { diff --git a/sound/soc/codecs/adau1761-spi.c b/sound/soc/codecs/adau1761-spi.c index 655689c9778a..7c9242c2ff94 100644 --- a/sound/soc/codecs/adau1761-spi.c +++ b/sound/soc/codecs/adau1761-spi.c @@ -45,10 +45,9 @@ static int adau1761_spi_probe(struct spi_device *spi) id->driver_data, adau1761_spi_switch_mode); } -static int adau1761_spi_remove(struct spi_device *spi) +static void adau1761_spi_remove(struct spi_device *spi) { adau17x1_remove(&spi->dev); - return 0; } static const struct spi_device_id adau1761_spi_id[] = { diff --git a/sound/soc/codecs/adau1781-spi.c b/sound/soc/codecs/adau1781-spi.c index bb5613574786..1a09633d5a88 100644 --- a/sound/soc/codecs/adau1781-spi.c +++ b/sound/soc/codecs/adau1781-spi.c @@ -45,10 +45,9 @@ static int adau1781_spi_probe(struct spi_device *spi) id->driver_data, adau1781_spi_switch_mode); } -static int adau1781_spi_remove(struct spi_device *spi) +static void adau1781_spi_remove(struct spi_device *spi) { adau17x1_remove(&spi->dev); - return 0; } static const struct spi_device_id adau1781_spi_id[] = { diff --git a/sound/soc/codecs/cs35l41-spi.c b/sound/soc/codecs/cs35l41-spi.c index 6dfd5459aa20..169221a5b09f 100644 --- a/sound/soc/codecs/cs35l41-spi.c +++ b/sound/soc/codecs/cs35l41-spi.c @@ -55,13 +55,11 @@ static int cs35l41_spi_probe(struct spi_device *spi) return cs35l41_probe(cs35l41, pdata); } -static int cs35l41_spi_remove(struct spi_device *spi) +static void cs35l41_spi_remove(struct spi_device *spi) { struct cs35l41_private *cs35l41 = spi_get_drvdata(spi); cs35l41_remove(cs35l41); - - return 0; } #ifdef CONFIG_OF diff --git a/sound/soc/codecs/pcm3168a-spi.c b/sound/soc/codecs/pcm3168a-spi.c index ecd379f308e6..b5b08046f545 100644 --- a/sound/soc/codecs/pcm3168a-spi.c +++ b/sound/soc/codecs/pcm3168a-spi.c @@ -26,11 +26,9 @@ static int pcm3168a_spi_probe(struct spi_device *spi) return pcm3168a_probe(&spi->dev, regmap); } -static int pcm3168a_spi_remove(struct spi_device *spi) +static void pcm3168a_spi_remove(struct spi_device *spi) { pcm3168a_remove(&spi->dev); - - return 0; } static const struct spi_device_id pcm3168a_spi_id[] = { diff --git a/sound/soc/codecs/pcm512x-spi.c b/sound/soc/codecs/pcm512x-spi.c index 7cf559b47e1c..4d29e7196380 100644 --- a/sound/soc/codecs/pcm512x-spi.c +++ b/sound/soc/codecs/pcm512x-spi.c @@ -26,10 +26,9 @@ static int pcm512x_spi_probe(struct spi_device *spi) return pcm512x_probe(&spi->dev, regmap); } -static int pcm512x_spi_remove(struct spi_device *spi) +static void pcm512x_spi_remove(struct spi_device *spi) { pcm512x_remove(&spi->dev); - return 0; } static const struct spi_device_id pcm512x_spi_id[] = { diff --git a/sound/soc/codecs/tlv320aic32x4-spi.c b/sound/soc/codecs/tlv320aic32x4-spi.c index a8958cd1c692..03cce8d6404f 100644 --- a/sound/soc/codecs/tlv320aic32x4-spi.c +++ b/sound/soc/codecs/tlv320aic32x4-spi.c @@ -46,11 +46,9 @@ static int aic32x4_spi_probe(struct spi_device *spi) return aic32x4_probe(&spi->dev, regmap); } -static int aic32x4_spi_remove(struct spi_device *spi) +static void aic32x4_spi_remove(struct spi_device *spi) { aic32x4_remove(&spi->dev); - - return 0; } static const struct spi_device_id aic32x4_spi_id[] = { diff --git a/sound/soc/codecs/tlv320aic3x-spi.c b/sound/soc/codecs/tlv320aic3x-spi.c index 494e84402232..deed6ec7e081 100644 --- a/sound/soc/codecs/tlv320aic3x-spi.c +++ b/sound/soc/codecs/tlv320aic3x-spi.c @@ -35,11 +35,9 @@ static int aic3x_spi_probe(struct spi_device *spi) return aic3x_probe(&spi->dev, regmap, id->driver_data); } -static int aic3x_spi_remove(struct spi_device *spi) +static void aic3x_spi_remove(struct spi_device *spi) { aic3x_remove(&spi->dev); - - return 0; } static const struct spi_device_id aic3x_spi_id[] = { diff --git a/sound/soc/codecs/wm0010.c b/sound/soc/codecs/wm0010.c index 28b4656c4e14..1bef1c500c8e 100644 --- a/sound/soc/codecs/wm0010.c +++ b/sound/soc/codecs/wm0010.c @@ -969,7 +969,7 @@ static int wm0010_spi_probe(struct spi_device *spi) return 0; } -static int wm0010_spi_remove(struct spi_device *spi) +static void wm0010_spi_remove(struct spi_device *spi) { struct wm0010_priv *wm0010 = spi_get_drvdata(spi); @@ -980,8 +980,6 @@ static int wm0010_spi_remove(struct spi_device *spi) if (wm0010->irq) free_irq(wm0010->irq, wm0010); - - return 0; } static struct spi_driver wm0010_spi_driver = { diff --git a/sound/soc/codecs/wm8804-spi.c b/sound/soc/codecs/wm8804-spi.c index 9a8da1511c34..628568724c20 100644 --- a/sound/soc/codecs/wm8804-spi.c +++ b/sound/soc/codecs/wm8804-spi.c @@ -24,10 +24,9 @@ static int wm8804_spi_probe(struct spi_device *spi) return wm8804_probe(&spi->dev, regmap); } -static int wm8804_spi_remove(struct spi_device *spi) +static void wm8804_spi_remove(struct spi_device *spi) { wm8804_remove(&spi->dev); - return 0; } static const struct of_device_id wm8804_of_match[] = { diff --git a/sound/spi/at73c213.c b/sound/spi/at73c213.c index 76c0e37a838c..56d2c712e257 100644 --- a/sound/spi/at73c213.c +++ b/sound/spi/at73c213.c @@ -1001,7 +1001,7 @@ out: return retval; } -static int snd_at73c213_remove(struct spi_device *spi) +static void snd_at73c213_remove(struct spi_device *spi) { struct snd_card *card = dev_get_drvdata(&spi->dev); struct snd_at73c213 *chip = card->private_data; @@ -1066,8 +1066,6 @@ out: ssc_free(chip->ssc); snd_card_free(card); - - return 0; } #ifdef CONFIG_PM_SLEEP -- cgit v1.2.3 From 715bea3568e78b80b1d127d8452eac0e3cb6f299 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Almeida?= Date: Fri, 11 Feb 2022 11:31:53 -0300 Subject: spi: amd: Use iopoll for busy waiting MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of implementing a custom IO busy wait function, just use readl_poll_timeout(). Signed-off-by: André Almeida Link: https://lore.kernel.org/r/20220211143155.75513-2-andrealmeid@collabora.com Signed-off-by: Mark Brown --- drivers/spi/spi-amd.c | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/drivers/spi/spi-amd.c b/drivers/spi/spi-amd.c index 4b3ac7aceaf6..899b8d90ff61 100644 --- a/drivers/spi/spi-amd.c +++ b/drivers/spi/spi-amd.c @@ -12,6 +12,7 @@ #include #include #include +#include #define AMD_SPI_CTRL0_REG 0x00 #define AMD_SPI_EXEC_CMD BIT(16) @@ -103,16 +104,10 @@ static inline void amd_spi_set_tx_count(struct amd_spi *amd_spi, u8 tx_count) static int amd_spi_busy_wait(struct amd_spi *amd_spi) { - int timeout = 100000; + u32 val; - /* poll for SPI bus to become idle */ - while (amd_spi_readreg32(amd_spi, AMD_SPI_CTRL0_REG) & AMD_SPI_BUSY) { - usleep_range(10, 20); - if (timeout-- < 0) - return -ETIMEDOUT; - } - - return 0; + return readl_poll_timeout(amd_spi->io_remap_addr + AMD_SPI_CTRL0_REG, + val, !(val & AMD_SPI_BUSY), 20, 2000000); } static int amd_spi_execute_opcode(struct amd_spi *amd_spi) -- cgit v1.2.3 From fbc71367288cf1902822618e00c7c1cf6f35348d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Almeida?= Date: Fri, 11 Feb 2022 11:31:54 -0300 Subject: spi: amd: Remove needless rom_addr variable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit rom_addr is not used in the code, so we can just drop it from struct amd_spi. Signed-off-by: André Almeida Link: https://lore.kernel.org/r/20220211143155.75513-3-andrealmeid@collabora.com Signed-off-by: Mark Brown --- drivers/spi/spi-amd.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/spi/spi-amd.c b/drivers/spi/spi-amd.c index 899b8d90ff61..417ce14a21c6 100644 --- a/drivers/spi/spi-amd.c +++ b/drivers/spi/spi-amd.c @@ -38,7 +38,6 @@ struct amd_spi { void __iomem *io_remap_addr; unsigned long io_base_addr; - u32 rom_addr; }; static inline u8 amd_spi_readreg8(struct amd_spi *amd_spi, int idx) -- cgit v1.2.3 From 209043554915d7c51ac112a668ad1a255e1bea61 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Almeida?= Date: Fri, 11 Feb 2022 11:31:55 -0300 Subject: spi: amd: Add support for version AMDI0062 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add support for the AMD SPI controller version AMDI0062. Do this in a modular way where's easy to add new versions. Signed-off-by: André Almeida Link: https://lore.kernel.org/r/20220211143155.75513-4-andrealmeid@collabora.com Signed-off-by: Mark Brown --- drivers/spi/spi-amd.c | 81 ++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 71 insertions(+), 10 deletions(-) diff --git a/drivers/spi/spi-amd.c b/drivers/spi/spi-amd.c index 417ce14a21c6..d909afac6e21 100644 --- a/drivers/spi/spi-amd.c +++ b/drivers/spi/spi-amd.c @@ -19,6 +19,10 @@ #define AMD_SPI_FIFO_CLEAR BIT(20) #define AMD_SPI_BUSY BIT(31) +#define AMD_SPI_OPCODE_REG 0x45 +#define AMD_SPI_CMD_TRIGGER_REG 0x47 +#define AMD_SPI_TRIGGER_CMD BIT(7) + #define AMD_SPI_OPCODE_MASK 0xFF #define AMD_SPI_ALT_CS_REG 0x1D @@ -35,9 +39,15 @@ #define AMD_SPI_XFER_TX 1 #define AMD_SPI_XFER_RX 2 +enum amd_spi_versions { + AMD_SPI_V1 = 1, /* AMDI0061 */ + AMD_SPI_V2, /* AMDI0062 */ +}; + struct amd_spi { void __iomem *io_remap_addr; unsigned long io_base_addr; + enum amd_spi_versions version; }; static inline u8 amd_spi_readreg8(struct amd_spi *amd_spi, int idx) @@ -81,14 +91,29 @@ static void amd_spi_select_chip(struct amd_spi *amd_spi, u8 cs) amd_spi_setclear_reg8(amd_spi, AMD_SPI_ALT_CS_REG, cs, AMD_SPI_ALT_CS_MASK); } +static inline void amd_spi_clear_chip(struct amd_spi *amd_spi, u8 chip_select) +{ + amd_spi_writereg8(amd_spi, AMD_SPI_ALT_CS_REG, chip_select & ~AMD_SPI_ALT_CS_MASK); +} + static void amd_spi_clear_fifo_ptr(struct amd_spi *amd_spi) { amd_spi_setclear_reg32(amd_spi, AMD_SPI_CTRL0_REG, AMD_SPI_FIFO_CLEAR, AMD_SPI_FIFO_CLEAR); } -static void amd_spi_set_opcode(struct amd_spi *amd_spi, u8 cmd_opcode) +static int amd_spi_set_opcode(struct amd_spi *amd_spi, u8 cmd_opcode) { - amd_spi_setclear_reg32(amd_spi, AMD_SPI_CTRL0_REG, cmd_opcode, AMD_SPI_OPCODE_MASK); + switch (amd_spi->version) { + case AMD_SPI_V1: + amd_spi_setclear_reg32(amd_spi, AMD_SPI_CTRL0_REG, cmd_opcode, + AMD_SPI_OPCODE_MASK); + return 0; + case AMD_SPI_V2: + amd_spi_writereg8(amd_spi, AMD_SPI_OPCODE_REG, cmd_opcode); + return 0; + default: + return -ENODEV; + } } static inline void amd_spi_set_rx_count(struct amd_spi *amd_spi, u8 rx_count) @@ -104,9 +129,21 @@ static inline void amd_spi_set_tx_count(struct amd_spi *amd_spi, u8 tx_count) static int amd_spi_busy_wait(struct amd_spi *amd_spi) { u32 val; + int reg; + + switch (amd_spi->version) { + case AMD_SPI_V1: + reg = AMD_SPI_CTRL0_REG; + break; + case AMD_SPI_V2: + reg = AMD_SPI_STATUS_REG; + break; + default: + return -ENODEV; + } - return readl_poll_timeout(amd_spi->io_remap_addr + AMD_SPI_CTRL0_REG, - val, !(val & AMD_SPI_BUSY), 20, 2000000); + return readl_poll_timeout(amd_spi->io_remap_addr + reg, val, + !(val & AMD_SPI_BUSY), 20, 2000000); } static int amd_spi_execute_opcode(struct amd_spi *amd_spi) @@ -117,10 +154,20 @@ static int amd_spi_execute_opcode(struct amd_spi *amd_spi) if (ret) return ret; - /* Set ExecuteOpCode bit in the CTRL0 register */ - amd_spi_setclear_reg32(amd_spi, AMD_SPI_CTRL0_REG, AMD_SPI_EXEC_CMD, AMD_SPI_EXEC_CMD); - - return 0; + switch (amd_spi->version) { + case AMD_SPI_V1: + /* Set ExecuteOpCode bit in the CTRL0 register */ + amd_spi_setclear_reg32(amd_spi, AMD_SPI_CTRL0_REG, AMD_SPI_EXEC_CMD, + AMD_SPI_EXEC_CMD); + return 0; + case AMD_SPI_V2: + /* Trigger the command execution */ + amd_spi_setclear_reg8(amd_spi, AMD_SPI_CMD_TRIGGER_REG, + AMD_SPI_TRIGGER_CMD, AMD_SPI_TRIGGER_CMD); + return 0; + default: + return -ENODEV; + } } static int amd_spi_master_setup(struct spi_device *spi) @@ -190,6 +237,17 @@ static inline int amd_spi_fifo_xfer(struct amd_spi *amd_spi, message->actual_length = tx_len + rx_len + 1; /* complete the transaction */ message->status = 0; + + switch (amd_spi->version) { + case AMD_SPI_V1: + break; + case AMD_SPI_V2: + amd_spi_clear_chip(amd_spi, message->spi->chip_select); + break; + default: + return -ENODEV; + } + spi_finalize_current_message(master); return 0; @@ -235,6 +293,8 @@ static int amd_spi_probe(struct platform_device *pdev) } dev_dbg(dev, "io_remap_address: %p\n", amd_spi->io_remap_addr); + amd_spi->version = (enum amd_spi_versions) device_get_match_data(dev); + /* Initialize the spi_master fields */ master->bus_num = 0; master->num_chipselect = 4; @@ -260,7 +320,8 @@ err_free_master: #ifdef CONFIG_ACPI static const struct acpi_device_id spi_acpi_match[] = { - { "AMDI0061", 0 }, + { "AMDI0061", AMD_SPI_V1 }, + { "AMDI0062", AMD_SPI_V2 }, {}, }; MODULE_DEVICE_TABLE(acpi, spi_acpi_match); @@ -269,7 +330,7 @@ MODULE_DEVICE_TABLE(acpi, spi_acpi_match); static struct platform_driver amd_spi_driver = { .driver = { .name = "amd_spi", - .acpi_match_table = ACPI_PTR(spi_acpi_match), + .acpi_match_table = spi_acpi_match, }, .probe = amd_spi_probe, }; -- cgit v1.2.3 From cd149eff8d2201a63c074a6d9d03e52926aa535d Mon Sep 17 00:00:00 2001 From: Mika Westerberg Date: Wed, 9 Feb 2022 15:27:04 +0300 Subject: mtd: spi-nor: intel-spi: Disable write protection only if asked Currently the driver tries to disable the BIOS write protection automatically even if this is not what the user wants. For this reason modify the driver so that by default it does not touch the write protection. Only if specifically asked by the user (setting writeable=1 command line parameter) the driver tries to disable the BIOS write protection. Signed-off-by: Mika Westerberg Reviewed-by: Andy Shevchenko Reviewed-by: Mauro Lima Reviewed-by: Tudor Ambarus Acked-by: Lee Jones Link: https://lore.kernel.org/r/20220209122706.42439-2-mika.westerberg@linux.intel.com Signed-off-by: Mark Brown --- drivers/mfd/lpc_ich.c | 59 ++++++++++++++++++++++--- drivers/mtd/spi-nor/controllers/intel-spi-pci.c | 29 +++++++----- drivers/mtd/spi-nor/controllers/intel-spi.c | 41 ++++++++--------- include/linux/platform_data/x86/intel-spi.h | 6 ++- 4 files changed, 96 insertions(+), 39 deletions(-) diff --git a/drivers/mfd/lpc_ich.c b/drivers/mfd/lpc_ich.c index f10e53187f67..9ffab9aafd81 100644 --- a/drivers/mfd/lpc_ich.c +++ b/drivers/mfd/lpc_ich.c @@ -63,6 +63,8 @@ #define SPIBASE_BYT 0x54 #define SPIBASE_BYT_SZ 512 #define SPIBASE_BYT_EN BIT(1) +#define BYT_BCR 0xfc +#define BYT_BCR_WPD BIT(0) #define SPIBASE_LPT 0x3800 #define SPIBASE_LPT_SZ 512 @@ -1084,12 +1086,57 @@ wdt_done: return ret; } +static bool lpc_ich_byt_set_writeable(void __iomem *base, void *data) +{ + u32 val; + + val = readl(base + BYT_BCR); + if (!(val & BYT_BCR_WPD)) { + val |= BYT_BCR_WPD; + writel(val, base + BYT_BCR); + val = readl(base + BYT_BCR); + } + + return val & BYT_BCR_WPD; +} + +static bool lpc_ich_lpt_set_writeable(void __iomem *base, void *data) +{ + struct pci_dev *pdev = data; + u32 bcr; + + pci_read_config_dword(pdev, BCR, &bcr); + if (!(bcr & BCR_WPD)) { + bcr |= BCR_WPD; + pci_write_config_dword(pdev, BCR, bcr); + pci_read_config_dword(pdev, BCR, &bcr); + } + + return bcr & BCR_WPD; +} + +static bool lpc_ich_bxt_set_writeable(void __iomem *base, void *data) +{ + unsigned int spi = PCI_DEVFN(13, 2); + struct pci_bus *bus = data; + u32 bcr; + + pci_bus_read_config_dword(bus, spi, BCR, &bcr); + if (!(bcr & BCR_WPD)) { + bcr |= BCR_WPD; + pci_bus_write_config_dword(bus, spi, BCR, bcr); + pci_bus_read_config_dword(bus, spi, BCR, &bcr); + } + + return bcr & BCR_WPD; +} + static int lpc_ich_init_spi(struct pci_dev *dev) { struct lpc_ich_priv *priv = pci_get_drvdata(dev); struct resource *res = &intel_spi_res[0]; struct intel_spi_boardinfo *info; - u32 spi_base, rcba, bcr; + u32 spi_base, rcba; info = devm_kzalloc(&dev->dev, sizeof(*info), GFP_KERNEL); if (!info) @@ -1103,6 +1150,8 @@ static int lpc_ich_init_spi(struct pci_dev *dev) if (spi_base & SPIBASE_BYT_EN) { res->start = spi_base & ~(SPIBASE_BYT_SZ - 1); res->end = res->start + SPIBASE_BYT_SZ - 1; + + info->set_writeable = lpc_ich_byt_set_writeable; } break; @@ -1113,8 +1162,8 @@ static int lpc_ich_init_spi(struct pci_dev *dev) res->start = spi_base + SPIBASE_LPT; res->end = res->start + SPIBASE_LPT_SZ - 1; - pci_read_config_dword(dev, BCR, &bcr); - info->writeable = !!(bcr & BCR_WPD); + info->set_writeable = lpc_ich_lpt_set_writeable; + info->data = dev; } break; @@ -1135,8 +1184,8 @@ static int lpc_ich_init_spi(struct pci_dev *dev) res->start = spi_base & 0xfffffff0; res->end = res->start + SPIBASE_APL_SZ - 1; - pci_bus_read_config_dword(bus, spi, BCR, &bcr); - info->writeable = !!(bcr & BCR_WPD); + info->set_writeable = lpc_ich_bxt_set_writeable; + info->data = bus; } pci_bus_write_config_byte(bus, p2sb, 0xe1, 0x1); diff --git a/drivers/mtd/spi-nor/controllers/intel-spi-pci.c b/drivers/mtd/spi-nor/controllers/intel-spi-pci.c index 1bc53b8bb88a..508f7ca098ef 100644 --- a/drivers/mtd/spi-nor/controllers/intel-spi-pci.c +++ b/drivers/mtd/spi-nor/controllers/intel-spi-pci.c @@ -16,12 +16,30 @@ #define BCR 0xdc #define BCR_WPD BIT(0) +static bool intel_spi_pci_set_writeable(void __iomem *base, void *data) +{ + struct pci_dev *pdev = data; + u32 bcr; + + /* Try to make the chip read/write */ + pci_read_config_dword(pdev, BCR, &bcr); + if (!(bcr & BCR_WPD)) { + bcr |= BCR_WPD; + pci_write_config_dword(pdev, BCR, bcr); + pci_read_config_dword(pdev, BCR, &bcr); + } + + return bcr & BCR_WPD; +} + static const struct intel_spi_boardinfo bxt_info = { .type = INTEL_SPI_BXT, + .set_writeable = intel_spi_pci_set_writeable, }; static const struct intel_spi_boardinfo cnl_info = { .type = INTEL_SPI_CNL, + .set_writeable = intel_spi_pci_set_writeable, }; static int intel_spi_pci_probe(struct pci_dev *pdev, @@ -29,7 +47,6 @@ static int intel_spi_pci_probe(struct pci_dev *pdev, { struct intel_spi_boardinfo *info; struct intel_spi *ispi; - u32 bcr; int ret; ret = pcim_enable_device(pdev); @@ -41,15 +58,7 @@ static int intel_spi_pci_probe(struct pci_dev *pdev, if (!info) return -ENOMEM; - /* Try to make the chip read/write */ - pci_read_config_dword(pdev, BCR, &bcr); - if (!(bcr & BCR_WPD)) { - bcr |= BCR_WPD; - pci_write_config_dword(pdev, BCR, bcr); - pci_read_config_dword(pdev, BCR, &bcr); - } - info->writeable = !!(bcr & BCR_WPD); - + info->data = pdev; ispi = intel_spi_probe(&pdev->dev, &pdev->resource[0], info); if (IS_ERR(ispi)) return PTR_ERR(ispi); diff --git a/drivers/mtd/spi-nor/controllers/intel-spi.c b/drivers/mtd/spi-nor/controllers/intel-spi.c index a413892ff449..f35597cbea0c 100644 --- a/drivers/mtd/spi-nor/controllers/intel-spi.c +++ b/drivers/mtd/spi-nor/controllers/intel-spi.c @@ -131,7 +131,6 @@ * @sregs: Start of software sequencer registers * @nregions: Maximum number of regions * @pr_num: Maximum number of protected range registers - * @writeable: Is the chip writeable * @locked: Is SPI setting locked * @swseq_reg: Use SW sequencer in register reads/writes * @swseq_erase: Use SW sequencer in erase operation @@ -149,7 +148,6 @@ struct intel_spi { void __iomem *sregs; size_t nregions; size_t pr_num; - bool writeable; bool locked; bool swseq_reg; bool swseq_erase; @@ -304,6 +302,14 @@ static int intel_spi_wait_sw_busy(struct intel_spi *ispi) INTEL_SPI_TIMEOUT * 1000); } +static bool intel_spi_set_writeable(struct intel_spi *ispi) +{ + if (!ispi->info->set_writeable) + return false; + + return ispi->info->set_writeable(ispi->base, ispi->info->data); +} + static int intel_spi_init(struct intel_spi *ispi) { u32 opmenu0, opmenu1, lvscc, uvscc, val; @@ -316,19 +322,6 @@ static int intel_spi_init(struct intel_spi *ispi) ispi->nregions = BYT_FREG_NUM; ispi->pr_num = BYT_PR_NUM; ispi->swseq_reg = true; - - if (writeable) { - /* Disable write protection */ - val = readl(ispi->base + BYT_BCR); - if (!(val & BYT_BCR_WPD)) { - val |= BYT_BCR_WPD; - writel(val, ispi->base + BYT_BCR); - val = readl(ispi->base + BYT_BCR); - } - - ispi->writeable = !!(val & BYT_BCR_WPD); - } - break; case INTEL_SPI_LPT: @@ -358,6 +351,12 @@ static int intel_spi_init(struct intel_spi *ispi) return -EINVAL; } + /* Try to disable write protection if user asked to do so */ + if (writeable && !intel_spi_set_writeable(ispi)) { + dev_warn(ispi->dev, "can't disable chip write protection\n"); + writeable = false; + } + /* Disable #SMI generation from HW sequencer */ val = readl(ispi->base + HSFSTS_CTL); val &= ~HSFSTS_CTL_FSMIE; @@ -884,9 +883,12 @@ static void intel_spi_fill_partition(struct intel_spi *ispi, /* * If any of the regions have protection bits set, make the * whole partition read-only to be on the safe side. + * + * Also if the user did not ask the chip to be writeable + * mask the bit too. */ - if (intel_spi_is_protected(ispi, base, limit)) - ispi->writeable = false; + if (!writeable || intel_spi_is_protected(ispi, base, limit)) + part->mask_flags |= MTD_WRITEABLE; end = (limit << 12) + 4096; if (end > part->size) @@ -927,7 +929,6 @@ struct intel_spi *intel_spi_probe(struct device *dev, ispi->dev = dev; ispi->info = info; - ispi->writeable = info->writeable; ret = intel_spi_init(ispi); if (ret) @@ -945,10 +946,6 @@ struct intel_spi *intel_spi_probe(struct device *dev, intel_spi_fill_partition(ispi, &part); - /* Prevent writes if not explicitly enabled */ - if (!ispi->writeable || !writeable) - ispi->nor.mtd.flags &= ~MTD_WRITEABLE; - ret = mtd_device_register(&ispi->nor.mtd, &part, 1); if (ret) return ERR_PTR(ret); diff --git a/include/linux/platform_data/x86/intel-spi.h b/include/linux/platform_data/x86/intel-spi.h index 7f53a5c6f35e..7dda3f690465 100644 --- a/include/linux/platform_data/x86/intel-spi.h +++ b/include/linux/platform_data/x86/intel-spi.h @@ -19,11 +19,13 @@ enum intel_spi_type { /** * struct intel_spi_boardinfo - Board specific data for Intel SPI driver * @type: Type which this controller is compatible with - * @writeable: The chip is writeable + * @set_writeable: Try to make the chip writeable (optional) + * @data: Data to be passed to @set_writeable can be %NULL */ struct intel_spi_boardinfo { enum intel_spi_type type; - bool writeable; + bool (*set_writeable)(void __iomem *base, void *data); + void *data; }; #endif /* INTEL_SPI_PDATA_H */ -- cgit v1.2.3 From e23e5a05d1fd9479586c40ffbcc056b3e34ef816 Mon Sep 17 00:00:00 2001 From: Mika Westerberg Date: Wed, 9 Feb 2022 15:27:05 +0300 Subject: mtd: spi-nor: intel-spi: Convert to SPI MEM The preferred way to implement SPI-NOR controller drivers is through SPI subsubsystem utilizing the SPI MEM core functions. This converts the Intel SPI flash controller driver over the SPI MEM by moving the driver from SPI-NOR subsystem to SPI subsystem and in one go make it use the SPI MEM functions. The driver name will be changed from intel-spi to spi-intel to match the convention used in the SPI subsystem. Signed-off-by: Mika Westerberg Reviewed-by: Andy Shevchenko Reviewed-by: Mauro Lima Reviewed-by: Boris Brezillon Acked-by: Lee Jones Acked-by: Pratyush Yadav Reviewed-by: Tudor Ambarus Link: https://lore.kernel.org/r/20220209122706.42439-3-mika.westerberg@linux.intel.com Signed-off-by: Mark Brown --- drivers/mtd/spi-nor/controllers/Kconfig | 36 - drivers/mtd/spi-nor/controllers/Makefile | 3 - drivers/mtd/spi-nor/controllers/intel-spi-pci.c | 108 -- .../mtd/spi-nor/controllers/intel-spi-platform.c | 54 - drivers/mtd/spi-nor/controllers/intel-spi.c | 965 --------------- drivers/mtd/spi-nor/controllers/intel-spi.h | 21 - drivers/spi/Kconfig | 39 + drivers/spi/Makefile | 3 + drivers/spi/spi-intel-pci.c | 94 ++ drivers/spi/spi-intel-platform.c | 39 + drivers/spi/spi-intel.c | 1250 ++++++++++++++++++++ drivers/spi/spi-intel.h | 19 + include/linux/mfd/lpc_ich.h | 2 +- include/linux/platform_data/x86/intel-spi.h | 31 - include/linux/platform_data/x86/spi-intel.h | 31 + 15 files changed, 1476 insertions(+), 1219 deletions(-) delete mode 100644 drivers/mtd/spi-nor/controllers/intel-spi-pci.c delete mode 100644 drivers/mtd/spi-nor/controllers/intel-spi-platform.c delete mode 100644 drivers/mtd/spi-nor/controllers/intel-spi.c delete mode 100644 drivers/mtd/spi-nor/controllers/intel-spi.h create mode 100644 drivers/spi/spi-intel-pci.c create mode 100644 drivers/spi/spi-intel-platform.c create mode 100644 drivers/spi/spi-intel.c create mode 100644 drivers/spi/spi-intel.h delete mode 100644 include/linux/platform_data/x86/intel-spi.h create mode 100644 include/linux/platform_data/x86/spi-intel.h diff --git a/drivers/mtd/spi-nor/controllers/Kconfig b/drivers/mtd/spi-nor/controllers/Kconfig index 5c0e0ec2e6d1..50f4f3484d42 100644 --- a/drivers/mtd/spi-nor/controllers/Kconfig +++ b/drivers/mtd/spi-nor/controllers/Kconfig @@ -26,39 +26,3 @@ config SPI_NXP_SPIFI SPIFI is a specialized controller for connecting serial SPI Flash. Enable this option if you have a device with a SPIFI controller and want to access the Flash as a mtd device. - -config SPI_INTEL_SPI - tristate - -config SPI_INTEL_SPI_PCI - tristate "Intel PCH/PCU SPI flash PCI driver (DANGEROUS)" - depends on X86 && PCI - select SPI_INTEL_SPI - help - This enables PCI support for the Intel PCH/PCU SPI controller in - master mode. This controller is present in modern Intel hardware - and is used to hold BIOS and other persistent settings. Using - this driver it is possible to upgrade BIOS directly from Linux. - - Say N here unless you know what you are doing. Overwriting the - SPI flash may render the system unbootable. - - To compile this driver as a module, choose M here: the module - will be called intel-spi-pci. - -config SPI_INTEL_SPI_PLATFORM - tristate "Intel PCH/PCU SPI flash platform driver (DANGEROUS)" - depends on X86 - select SPI_INTEL_SPI - help - This enables platform support for the Intel PCH/PCU SPI - controller in master mode. This controller is present in modern - Intel hardware and is used to hold BIOS and other persistent - settings. Using this driver it is possible to upgrade BIOS - directly from Linux. - - Say N here unless you know what you are doing. Overwriting the - SPI flash may render the system unbootable. - - To compile this driver as a module, choose M here: the module - will be called intel-spi-platform. diff --git a/drivers/mtd/spi-nor/controllers/Makefile b/drivers/mtd/spi-nor/controllers/Makefile index e7abba491d98..6e2a1dc68466 100644 --- a/drivers/mtd/spi-nor/controllers/Makefile +++ b/drivers/mtd/spi-nor/controllers/Makefile @@ -2,6 +2,3 @@ obj-$(CONFIG_SPI_ASPEED_SMC) += aspeed-smc.o obj-$(CONFIG_SPI_HISI_SFC) += hisi-sfc.o obj-$(CONFIG_SPI_NXP_SPIFI) += nxp-spifi.o -obj-$(CONFIG_SPI_INTEL_SPI) += intel-spi.o -obj-$(CONFIG_SPI_INTEL_SPI_PCI) += intel-spi-pci.o -obj-$(CONFIG_SPI_INTEL_SPI_PLATFORM) += intel-spi-platform.o diff --git a/drivers/mtd/spi-nor/controllers/intel-spi-pci.c b/drivers/mtd/spi-nor/controllers/intel-spi-pci.c deleted file mode 100644 index 508f7ca098ef..000000000000 --- a/drivers/mtd/spi-nor/controllers/intel-spi-pci.c +++ /dev/null @@ -1,108 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Intel PCH/PCU SPI flash PCI driver. - * - * Copyright (C) 2016, Intel Corporation - * Author: Mika Westerberg - */ - -#include -#include -#include -#include - -#include "intel-spi.h" - -#define BCR 0xdc -#define BCR_WPD BIT(0) - -static bool intel_spi_pci_set_writeable(void __iomem *base, void *data) -{ - struct pci_dev *pdev = data; - u32 bcr; - - /* Try to make the chip read/write */ - pci_read_config_dword(pdev, BCR, &bcr); - if (!(bcr & BCR_WPD)) { - bcr |= BCR_WPD; - pci_write_config_dword(pdev, BCR, bcr); - pci_read_config_dword(pdev, BCR, &bcr); - } - - return bcr & BCR_WPD; -} - -static const struct intel_spi_boardinfo bxt_info = { - .type = INTEL_SPI_BXT, - .set_writeable = intel_spi_pci_set_writeable, -}; - -static const struct intel_spi_boardinfo cnl_info = { - .type = INTEL_SPI_CNL, - .set_writeable = intel_spi_pci_set_writeable, -}; - -static int intel_spi_pci_probe(struct pci_dev *pdev, - const struct pci_device_id *id) -{ - struct intel_spi_boardinfo *info; - struct intel_spi *ispi; - int ret; - - ret = pcim_enable_device(pdev); - if (ret) - return ret; - - info = devm_kmemdup(&pdev->dev, (void *)id->driver_data, sizeof(*info), - GFP_KERNEL); - if (!info) - return -ENOMEM; - - info->data = pdev; - ispi = intel_spi_probe(&pdev->dev, &pdev->resource[0], info); - if (IS_ERR(ispi)) - return PTR_ERR(ispi); - - pci_set_drvdata(pdev, ispi); - return 0; -} - -static void intel_spi_pci_remove(struct pci_dev *pdev) -{ - intel_spi_remove(pci_get_drvdata(pdev)); -} - -static const struct pci_device_id intel_spi_pci_ids[] = { - { PCI_VDEVICE(INTEL, 0x02a4), (unsigned long)&bxt_info }, - { PCI_VDEVICE(INTEL, 0x06a4), (unsigned long)&bxt_info }, - { PCI_VDEVICE(INTEL, 0x18e0), (unsigned long)&bxt_info }, - { PCI_VDEVICE(INTEL, 0x19e0), (unsigned long)&bxt_info }, - { PCI_VDEVICE(INTEL, 0x1bca), (unsigned long)&bxt_info }, - { PCI_VDEVICE(INTEL, 0x34a4), (unsigned long)&bxt_info }, - { PCI_VDEVICE(INTEL, 0x43a4), (unsigned long)&cnl_info }, - { PCI_VDEVICE(INTEL, 0x4b24), (unsigned long)&bxt_info }, - { PCI_VDEVICE(INTEL, 0x4da4), (unsigned long)&bxt_info }, - { PCI_VDEVICE(INTEL, 0x51a4), (unsigned long)&cnl_info }, - { PCI_VDEVICE(INTEL, 0x54a4), (unsigned long)&cnl_info }, - { PCI_VDEVICE(INTEL, 0x7aa4), (unsigned long)&cnl_info }, - { PCI_VDEVICE(INTEL, 0xa0a4), (unsigned long)&bxt_info }, - { PCI_VDEVICE(INTEL, 0xa1a4), (unsigned long)&bxt_info }, - { PCI_VDEVICE(INTEL, 0xa224), (unsigned long)&bxt_info }, - { PCI_VDEVICE(INTEL, 0xa324), (unsigned long)&cnl_info }, - { PCI_VDEVICE(INTEL, 0xa3a4), (unsigned long)&bxt_info }, - { }, -}; -MODULE_DEVICE_TABLE(pci, intel_spi_pci_ids); - -static struct pci_driver intel_spi_pci_driver = { - .name = "intel-spi", - .id_table = intel_spi_pci_ids, - .probe = intel_spi_pci_probe, - .remove = intel_spi_pci_remove, -}; - -module_pci_driver(intel_spi_pci_driver); - -MODULE_DESCRIPTION("Intel PCH/PCU SPI flash PCI driver"); -MODULE_AUTHOR("Mika Westerberg "); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/mtd/spi-nor/controllers/intel-spi-platform.c b/drivers/mtd/spi-nor/controllers/intel-spi-platform.c deleted file mode 100644 index f80f1086f928..000000000000 --- a/drivers/mtd/spi-nor/controllers/intel-spi-platform.c +++ /dev/null @@ -1,54 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Intel PCH/PCU SPI flash platform driver. - * - * Copyright (C) 2016, Intel Corporation - * Author: Mika Westerberg - */ - -#include -#include -#include - -#include "intel-spi.h" - -static int intel_spi_platform_probe(struct platform_device *pdev) -{ - struct intel_spi_boardinfo *info; - struct intel_spi *ispi; - struct resource *mem; - - info = dev_get_platdata(&pdev->dev); - if (!info) - return -EINVAL; - - mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - ispi = intel_spi_probe(&pdev->dev, mem, info); - if (IS_ERR(ispi)) - return PTR_ERR(ispi); - - platform_set_drvdata(pdev, ispi); - return 0; -} - -static int intel_spi_platform_remove(struct platform_device *pdev) -{ - struct intel_spi *ispi = platform_get_drvdata(pdev); - - return intel_spi_remove(ispi); -} - -static struct platform_driver intel_spi_platform_driver = { - .probe = intel_spi_platform_probe, - .remove = intel_spi_platform_remove, - .driver = { - .name = "intel-spi", - }, -}; - -module_platform_driver(intel_spi_platform_driver); - -MODULE_DESCRIPTION("Intel PCH/PCU SPI flash platform driver"); -MODULE_AUTHOR("Mika Westerberg "); -MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("platform:intel-spi"); diff --git a/drivers/mtd/spi-nor/controllers/intel-spi.c b/drivers/mtd/spi-nor/controllers/intel-spi.c deleted file mode 100644 index f35597cbea0c..000000000000 --- a/drivers/mtd/spi-nor/controllers/intel-spi.c +++ /dev/null @@ -1,965 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Intel PCH/PCU SPI flash driver. - * - * Copyright (C) 2016, Intel Corporation - * Author: Mika Westerberg - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "intel-spi.h" - -/* Offsets are from @ispi->base */ -#define BFPREG 0x00 - -#define HSFSTS_CTL 0x04 -#define HSFSTS_CTL_FSMIE BIT(31) -#define HSFSTS_CTL_FDBC_SHIFT 24 -#define HSFSTS_CTL_FDBC_MASK (0x3f << HSFSTS_CTL_FDBC_SHIFT) - -#define HSFSTS_CTL_FCYCLE_SHIFT 17 -#define HSFSTS_CTL_FCYCLE_MASK (0x0f << HSFSTS_CTL_FCYCLE_SHIFT) -/* HW sequencer opcodes */ -#define HSFSTS_CTL_FCYCLE_READ (0x00 << HSFSTS_CTL_FCYCLE_SHIFT) -#define HSFSTS_CTL_FCYCLE_WRITE (0x02 << HSFSTS_CTL_FCYCLE_SHIFT) -#define HSFSTS_CTL_FCYCLE_ERASE (0x03 << HSFSTS_CTL_FCYCLE_SHIFT) -#define HSFSTS_CTL_FCYCLE_ERASE_64K (0x04 << HSFSTS_CTL_FCYCLE_SHIFT) -#define HSFSTS_CTL_FCYCLE_RDID (0x06 << HSFSTS_CTL_FCYCLE_SHIFT) -#define HSFSTS_CTL_FCYCLE_WRSR (0x07 << HSFSTS_CTL_FCYCLE_SHIFT) -#define HSFSTS_CTL_FCYCLE_RDSR (0x08 << HSFSTS_CTL_FCYCLE_SHIFT) - -#define HSFSTS_CTL_FGO BIT(16) -#define HSFSTS_CTL_FLOCKDN BIT(15) -#define HSFSTS_CTL_FDV BIT(14) -#define HSFSTS_CTL_SCIP BIT(5) -#define HSFSTS_CTL_AEL BIT(2) -#define HSFSTS_CTL_FCERR BIT(1) -#define HSFSTS_CTL_FDONE BIT(0) - -#define FADDR 0x08 -#define DLOCK 0x0c -#define FDATA(n) (0x10 + ((n) * 4)) - -#define FRACC 0x50 - -#define FREG(n) (0x54 + ((n) * 4)) -#define FREG_BASE_MASK 0x3fff -#define FREG_LIMIT_SHIFT 16 -#define FREG_LIMIT_MASK (0x03fff << FREG_LIMIT_SHIFT) - -/* Offset is from @ispi->pregs */ -#define PR(n) ((n) * 4) -#define PR_WPE BIT(31) -#define PR_LIMIT_SHIFT 16 -#define PR_LIMIT_MASK (0x3fff << PR_LIMIT_SHIFT) -#define PR_RPE BIT(15) -#define PR_BASE_MASK 0x3fff - -/* Offsets are from @ispi->sregs */ -#define SSFSTS_CTL 0x00 -#define SSFSTS_CTL_FSMIE BIT(23) -#define SSFSTS_CTL_DS BIT(22) -#define SSFSTS_CTL_DBC_SHIFT 16 -#define SSFSTS_CTL_SPOP BIT(11) -#define SSFSTS_CTL_ACS BIT(10) -#define SSFSTS_CTL_SCGO BIT(9) -#define SSFSTS_CTL_COP_SHIFT 12 -#define SSFSTS_CTL_FRS BIT(7) -#define SSFSTS_CTL_DOFRS BIT(6) -#define SSFSTS_CTL_AEL BIT(4) -#define SSFSTS_CTL_FCERR BIT(3) -#define SSFSTS_CTL_FDONE BIT(2) -#define SSFSTS_CTL_SCIP BIT(0) - -#define PREOP_OPTYPE 0x04 -#define OPMENU0 0x08 -#define OPMENU1 0x0c - -#define OPTYPE_READ_NO_ADDR 0 -#define OPTYPE_WRITE_NO_ADDR 1 -#define OPTYPE_READ_WITH_ADDR 2 -#define OPTYPE_WRITE_WITH_ADDR 3 - -/* CPU specifics */ -#define BYT_PR 0x74 -#define BYT_SSFSTS_CTL 0x90 -#define BYT_BCR 0xfc -#define BYT_BCR_WPD BIT(0) -#define BYT_FREG_NUM 5 -#define BYT_PR_NUM 5 - -#define LPT_PR 0x74 -#define LPT_SSFSTS_CTL 0x90 -#define LPT_FREG_NUM 5 -#define LPT_PR_NUM 5 - -#define BXT_PR 0x84 -#define BXT_SSFSTS_CTL 0xa0 -#define BXT_FREG_NUM 12 -#define BXT_PR_NUM 6 - -#define CNL_PR 0x84 -#define CNL_FREG_NUM 6 -#define CNL_PR_NUM 5 - -#define LVSCC 0xc4 -#define UVSCC 0xc8 -#define ERASE_OPCODE_SHIFT 8 -#define ERASE_OPCODE_MASK (0xff << ERASE_OPCODE_SHIFT) -#define ERASE_64K_OPCODE_SHIFT 16 -#define ERASE_64K_OPCODE_MASK (0xff << ERASE_OPCODE_SHIFT) - -#define INTEL_SPI_TIMEOUT 5000 /* ms */ -#define INTEL_SPI_FIFO_SZ 64 - -/** - * struct intel_spi - Driver private data - * @dev: Device pointer - * @info: Pointer to board specific info - * @nor: SPI NOR layer structure - * @base: Beginning of MMIO space - * @pregs: Start of protection registers - * @sregs: Start of software sequencer registers - * @nregions: Maximum number of regions - * @pr_num: Maximum number of protected range registers - * @locked: Is SPI setting locked - * @swseq_reg: Use SW sequencer in register reads/writes - * @swseq_erase: Use SW sequencer in erase operation - * @erase_64k: 64k erase supported - * @atomic_preopcode: Holds preopcode when atomic sequence is requested - * @opcodes: Opcodes which are supported. This are programmed by BIOS - * before it locks down the controller. - */ -struct intel_spi { - struct device *dev; - const struct intel_spi_boardinfo *info; - struct spi_nor nor; - void __iomem *base; - void __iomem *pregs; - void __iomem *sregs; - size_t nregions; - size_t pr_num; - bool locked; - bool swseq_reg; - bool swseq_erase; - bool erase_64k; - u8 atomic_preopcode; - u8 opcodes[8]; -}; - -static bool writeable; -module_param(writeable, bool, 0); -MODULE_PARM_DESC(writeable, "Enable write access to SPI flash chip (default=0)"); - -static void intel_spi_dump_regs(struct intel_spi *ispi) -{ - u32 value; - int i; - - dev_dbg(ispi->dev, "BFPREG=0x%08x\n", readl(ispi->base + BFPREG)); - - value = readl(ispi->base + HSFSTS_CTL); - dev_dbg(ispi->dev, "HSFSTS_CTL=0x%08x\n", value); - if (value & HSFSTS_CTL_FLOCKDN) - dev_dbg(ispi->dev, "-> Locked\n"); - - dev_dbg(ispi->dev, "FADDR=0x%08x\n", readl(ispi->base + FADDR)); - dev_dbg(ispi->dev, "DLOCK=0x%08x\n", readl(ispi->base + DLOCK)); - - for (i = 0; i < 16; i++) - dev_dbg(ispi->dev, "FDATA(%d)=0x%08x\n", - i, readl(ispi->base + FDATA(i))); - - dev_dbg(ispi->dev, "FRACC=0x%08x\n", readl(ispi->base + FRACC)); - - for (i = 0; i < ispi->nregions; i++) - dev_dbg(ispi->dev, "FREG(%d)=0x%08x\n", i, - readl(ispi->base + FREG(i))); - for (i = 0; i < ispi->pr_num; i++) - dev_dbg(ispi->dev, "PR(%d)=0x%08x\n", i, - readl(ispi->pregs + PR(i))); - - if (ispi->sregs) { - value = readl(ispi->sregs + SSFSTS_CTL); - dev_dbg(ispi->dev, "SSFSTS_CTL=0x%08x\n", value); - dev_dbg(ispi->dev, "PREOP_OPTYPE=0x%08x\n", - readl(ispi->sregs + PREOP_OPTYPE)); - dev_dbg(ispi->dev, "OPMENU0=0x%08x\n", - readl(ispi->sregs + OPMENU0)); - dev_dbg(ispi->dev, "OPMENU1=0x%08x\n", - readl(ispi->sregs + OPMENU1)); - } - - if (ispi->info->type == INTEL_SPI_BYT) - dev_dbg(ispi->dev, "BCR=0x%08x\n", readl(ispi->base + BYT_BCR)); - - dev_dbg(ispi->dev, "LVSCC=0x%08x\n", readl(ispi->base + LVSCC)); - dev_dbg(ispi->dev, "UVSCC=0x%08x\n", readl(ispi->base + UVSCC)); - - dev_dbg(ispi->dev, "Protected regions:\n"); - for (i = 0; i < ispi->pr_num; i++) { - u32 base, limit; - - value = readl(ispi->pregs + PR(i)); - if (!(value & (PR_WPE | PR_RPE))) - continue; - - limit = (value & PR_LIMIT_MASK) >> PR_LIMIT_SHIFT; - base = value & PR_BASE_MASK; - - dev_dbg(ispi->dev, " %02d base: 0x%08x limit: 0x%08x [%c%c]\n", - i, base << 12, (limit << 12) | 0xfff, - value & PR_WPE ? 'W' : '.', - value & PR_RPE ? 'R' : '.'); - } - - dev_dbg(ispi->dev, "Flash regions:\n"); - for (i = 0; i < ispi->nregions; i++) { - u32 region, base, limit; - - region = readl(ispi->base + FREG(i)); - base = region & FREG_BASE_MASK; - limit = (region & FREG_LIMIT_MASK) >> FREG_LIMIT_SHIFT; - - if (base >= limit || (i > 0 && limit == 0)) - dev_dbg(ispi->dev, " %02d disabled\n", i); - else - dev_dbg(ispi->dev, " %02d base: 0x%08x limit: 0x%08x\n", - i, base << 12, (limit << 12) | 0xfff); - } - - dev_dbg(ispi->dev, "Using %cW sequencer for register access\n", - ispi->swseq_reg ? 'S' : 'H'); - dev_dbg(ispi->dev, "Using %cW sequencer for erase operation\n", - ispi->swseq_erase ? 'S' : 'H'); -} - -/* Reads max INTEL_SPI_FIFO_SZ bytes from the device fifo */ -static int intel_spi_read_block(struct intel_spi *ispi, void *buf, size_t size) -{ - size_t bytes; - int i = 0; - - if (size > INTEL_SPI_FIFO_SZ) - return -EINVAL; - - while (size > 0) { - bytes = min_t(size_t, size, 4); - memcpy_fromio(buf, ispi->base + FDATA(i), bytes); - size -= bytes; - buf += bytes; - i++; - } - - return 0; -} - -/* Writes max INTEL_SPI_FIFO_SZ bytes to the device fifo */ -static int intel_spi_write_block(struct intel_spi *ispi, const void *buf, - size_t size) -{ - size_t bytes; - int i = 0; - - if (size > INTEL_SPI_FIFO_SZ) - return -EINVAL; - - while (size > 0) { - bytes = min_t(size_t, size, 4); - memcpy_toio(ispi->base + FDATA(i), buf, bytes); - size -= bytes; - buf += bytes; - i++; - } - - return 0; -} - -static int intel_spi_wait_hw_busy(struct intel_spi *ispi) -{ - u32 val; - - return readl_poll_timeout(ispi->base + HSFSTS_CTL, val, - !(val & HSFSTS_CTL_SCIP), 0, - INTEL_SPI_TIMEOUT * 1000); -} - -static int intel_spi_wait_sw_busy(struct intel_spi *ispi) -{ - u32 val; - - return readl_poll_timeout(ispi->sregs + SSFSTS_CTL, val, - !(val & SSFSTS_CTL_SCIP), 0, - INTEL_SPI_TIMEOUT * 1000); -} - -static bool intel_spi_set_writeable(struct intel_spi *ispi) -{ - if (!ispi->info->set_writeable) - return false; - - return ispi->info->set_writeable(ispi->base, ispi->info->data); -} - -static int intel_spi_init(struct intel_spi *ispi) -{ - u32 opmenu0, opmenu1, lvscc, uvscc, val; - int i; - - switch (ispi->info->type) { - case INTEL_SPI_BYT: - ispi->sregs = ispi->base + BYT_SSFSTS_CTL; - ispi->pregs = ispi->base + BYT_PR; - ispi->nregions = BYT_FREG_NUM; - ispi->pr_num = BYT_PR_NUM; - ispi->swseq_reg = true; - break; - - case INTEL_SPI_LPT: - ispi->sregs = ispi->base + LPT_SSFSTS_CTL; - ispi->pregs = ispi->base + LPT_PR; - ispi->nregions = LPT_FREG_NUM; - ispi->pr_num = LPT_PR_NUM; - ispi->swseq_reg = true; - break; - - case INTEL_SPI_BXT: - ispi->sregs = ispi->base + BXT_SSFSTS_CTL; - ispi->pregs = ispi->base + BXT_PR; - ispi->nregions = BXT_FREG_NUM; - ispi->pr_num = BXT_PR_NUM; - ispi->erase_64k = true; - break; - - case INTEL_SPI_CNL: - ispi->sregs = NULL; - ispi->pregs = ispi->base + CNL_PR; - ispi->nregions = CNL_FREG_NUM; - ispi->pr_num = CNL_PR_NUM; - break; - - default: - return -EINVAL; - } - - /* Try to disable write protection if user asked to do so */ - if (writeable && !intel_spi_set_writeable(ispi)) { - dev_warn(ispi->dev, "can't disable chip write protection\n"); - writeable = false; - } - - /* Disable #SMI generation from HW sequencer */ - val = readl(ispi->base + HSFSTS_CTL); - val &= ~HSFSTS_CTL_FSMIE; - writel(val, ispi->base + HSFSTS_CTL); - - /* - * Determine whether erase operation should use HW or SW sequencer. - * - * The HW sequencer has a predefined list of opcodes, with only the - * erase opcode being programmable in LVSCC and UVSCC registers. - * If these registers don't contain a valid erase opcode, erase - * cannot be done using HW sequencer. - */ - lvscc = readl(ispi->base + LVSCC); - uvscc = readl(ispi->base + UVSCC); - if (!(lvscc & ERASE_OPCODE_MASK) || !(uvscc & ERASE_OPCODE_MASK)) - ispi->swseq_erase = true; - /* SPI controller on Intel BXT supports 64K erase opcode */ - if (ispi->info->type == INTEL_SPI_BXT && !ispi->swseq_erase) - if (!(lvscc & ERASE_64K_OPCODE_MASK) || - !(uvscc & ERASE_64K_OPCODE_MASK)) - ispi->erase_64k = false; - - if (ispi->sregs == NULL && (ispi->swseq_reg || ispi->swseq_erase)) { - dev_err(ispi->dev, "software sequencer not supported, but required\n"); - return -EINVAL; - } - - /* - * Some controllers can only do basic operations using hardware - * sequencer. All other operations are supposed to be carried out - * using software sequencer. - */ - if (ispi->swseq_reg) { - /* Disable #SMI generation from SW sequencer */ - val = readl(ispi->sregs + SSFSTS_CTL); - val &= ~SSFSTS_CTL_FSMIE; - writel(val, ispi->sregs + SSFSTS_CTL); - } - - /* Check controller's lock status */ - val = readl(ispi->base + HSFSTS_CTL); - ispi->locked = !!(val & HSFSTS_CTL_FLOCKDN); - - if (ispi->locked && ispi->sregs) { - /* - * BIOS programs allowed opcodes and then locks down the - * register. So read back what opcodes it decided to support. - * That's the set we are going to support as well. - */ - opmenu0 = readl(ispi->sregs + OPMENU0); - opmenu1 = readl(ispi->sregs + OPMENU1); - - if (opmenu0 && opmenu1) { - for (i = 0; i < ARRAY_SIZE(ispi->opcodes) / 2; i++) { - ispi->opcodes[i] = opmenu0 >> i * 8; - ispi->opcodes[i + 4] = opmenu1 >> i * 8; - } - } - } - - intel_spi_dump_regs(ispi); - - return 0; -} - -static int intel_spi_opcode_index(struct intel_spi *ispi, u8 opcode, int optype) -{ - int i; - int preop; - - if (ispi->locked) { - for (i = 0; i < ARRAY_SIZE(ispi->opcodes); i++) - if (ispi->opcodes[i] == opcode) - return i; - - return -EINVAL; - } - - /* The lock is off, so just use index 0 */ - writel(opcode, ispi->sregs + OPMENU0); - preop = readw(ispi->sregs + PREOP_OPTYPE); - writel(optype << 16 | preop, ispi->sregs + PREOP_OPTYPE); - - return 0; -} - -static int intel_spi_hw_cycle(struct intel_spi *ispi, u8 opcode, size_t len) -{ - u32 val, status; - int ret; - - val = readl(ispi->base + HSFSTS_CTL); - val &= ~(HSFSTS_CTL_FCYCLE_MASK | HSFSTS_CTL_FDBC_MASK); - - switch (opcode) { - case SPINOR_OP_RDID: - val |= HSFSTS_CTL_FCYCLE_RDID; - break; - case SPINOR_OP_WRSR: - val |= HSFSTS_CTL_FCYCLE_WRSR; - break; - case SPINOR_OP_RDSR: - val |= HSFSTS_CTL_FCYCLE_RDSR; - break; - default: - return -EINVAL; - } - - if (len > INTEL_SPI_FIFO_SZ) - return -EINVAL; - - val |= (len - 1) << HSFSTS_CTL_FDBC_SHIFT; - val |= HSFSTS_CTL_FCERR | HSFSTS_CTL_FDONE; - val |= HSFSTS_CTL_FGO; - writel(val, ispi->base + HSFSTS_CTL); - - ret = intel_spi_wait_hw_busy(ispi); - if (ret) - return ret; - - status = readl(ispi->base + HSFSTS_CTL); - if (status & HSFSTS_CTL_FCERR) - return -EIO; - else if (status & HSFSTS_CTL_AEL) - return -EACCES; - - return 0; -} - -static int intel_spi_sw_cycle(struct intel_spi *ispi, u8 opcode, size_t len, - int optype) -{ - u32 val = 0, status; - u8 atomic_preopcode; - int ret; - - ret = intel_spi_opcode_index(ispi, opcode, optype); - if (ret < 0) - return ret; - - if (len > INTEL_SPI_FIFO_SZ) - return -EINVAL; - - /* - * Always clear it after each SW sequencer operation regardless - * of whether it is successful or not. - */ - atomic_preopcode = ispi->atomic_preopcode; - ispi->atomic_preopcode = 0; - - /* Only mark 'Data Cycle' bit when there is data to be transferred */ - if (len > 0) - val = ((len - 1) << SSFSTS_CTL_DBC_SHIFT) | SSFSTS_CTL_DS; - val |= ret << SSFSTS_CTL_COP_SHIFT; - val |= SSFSTS_CTL_FCERR | SSFSTS_CTL_FDONE; - val |= SSFSTS_CTL_SCGO; - if (atomic_preopcode) { - u16 preop; - - switch (optype) { - case OPTYPE_WRITE_NO_ADDR: - case OPTYPE_WRITE_WITH_ADDR: - /* Pick matching preopcode for the atomic sequence */ - preop = readw(ispi->sregs + PREOP_OPTYPE); - if ((preop & 0xff) == atomic_preopcode) - ; /* Do nothing */ - else if ((preop >> 8) == atomic_preopcode) - val |= SSFSTS_CTL_SPOP; - else - return -EINVAL; - - /* Enable atomic sequence */ - val |= SSFSTS_CTL_ACS; - break; - - default: - return -EINVAL; - } - - } - writel(val, ispi->sregs + SSFSTS_CTL); - - ret = intel_spi_wait_sw_busy(ispi); - if (ret) - return ret; - - status = readl(ispi->sregs + SSFSTS_CTL); - if (status & SSFSTS_CTL_FCERR) - return -EIO; - else if (status & SSFSTS_CTL_AEL) - return -EACCES; - - return 0; -} - -static int intel_spi_read_reg(struct spi_nor *nor, u8 opcode, u8 *buf, - size_t len) -{ - struct intel_spi *ispi = nor->priv; - int ret; - - /* Address of the first chip */ - writel(0, ispi->base + FADDR); - - if (ispi->swseq_reg) - ret = intel_spi_sw_cycle(ispi, opcode, len, - OPTYPE_READ_NO_ADDR); - else - ret = intel_spi_hw_cycle(ispi, opcode, len); - - if (ret) - return ret; - - return intel_spi_read_block(ispi, buf, len); -} - -static int intel_spi_write_reg(struct spi_nor *nor, u8 opcode, const u8 *buf, - size_t len) -{ - struct intel_spi *ispi = nor->priv; - int ret; - - /* - * This is handled with atomic operation and preop code in Intel - * controller so we only verify that it is available. If the - * controller is not locked, program the opcode to the PREOP - * register for later use. - * - * When hardware sequencer is used there is no need to program - * any opcodes (it handles them automatically as part of a command). - */ - if (opcode == SPINOR_OP_WREN) { - u16 preop; - - if (!ispi->swseq_reg) - return 0; - - preop = readw(ispi->sregs + PREOP_OPTYPE); - if ((preop & 0xff) != opcode && (preop >> 8) != opcode) { - if (ispi->locked) - return -EINVAL; - writel(opcode, ispi->sregs + PREOP_OPTYPE); - } - - /* - * This enables atomic sequence on next SW sycle. Will - * be cleared after next operation. - */ - ispi->atomic_preopcode = opcode; - return 0; - } - - /* - * We hope that HW sequencer will do the right thing automatically and - * with the SW sequencer we cannot use preopcode anyway, so just ignore - * the Write Disable operation and pretend it was completed - * successfully. - */ - if (opcode == SPINOR_OP_WRDI) - return 0; - - writel(0, ispi->base + FADDR); - - /* Write the value beforehand */ - ret = intel_spi_write_block(ispi, buf, len); - if (ret) - return ret; - - if (ispi->swseq_reg) - return intel_spi_sw_cycle(ispi, opcode, len, - OPTYPE_WRITE_NO_ADDR); - return intel_spi_hw_cycle(ispi, opcode, len); -} - -static ssize_t intel_spi_read(struct spi_nor *nor, loff_t from, size_t len, - u_char *read_buf) -{ - struct intel_spi *ispi = nor->priv; - size_t block_size, retlen = 0; - u32 val, status; - ssize_t ret; - - /* - * Atomic sequence is not expected with HW sequencer reads. Make - * sure it is cleared regardless. - */ - if (WARN_ON_ONCE(ispi->atomic_preopcode)) - ispi->atomic_preopcode = 0; - - switch (nor->read_opcode) { - case SPINOR_OP_READ: - case SPINOR_OP_READ_FAST: - case SPINOR_OP_READ_4B: - case SPINOR_OP_READ_FAST_4B: - break; - default: - return -EINVAL; - } - - while (len > 0) { - block_size = min_t(size_t, len, INTEL_SPI_FIFO_SZ); - - /* Read cannot cross 4K boundary */ - block_size = min_t(loff_t, from + block_size, - round_up(from + 1, SZ_4K)) - from; - - writel(from, ispi->base + FADDR); - - val = readl(ispi->base + HSFSTS_CTL); - val &= ~(HSFSTS_CTL_FDBC_MASK | HSFSTS_CTL_FCYCLE_MASK); - val |= HSFSTS_CTL_AEL | HSFSTS_CTL_FCERR | HSFSTS_CTL_FDONE; - val |= (block_size - 1) << HSFSTS_CTL_FDBC_SHIFT; - val |= HSFSTS_CTL_FCYCLE_READ; - val |= HSFSTS_CTL_FGO; - writel(val, ispi->base + HSFSTS_CTL); - - ret = intel_spi_wait_hw_busy(ispi); - if (ret) - return ret; - - status = readl(ispi->base + HSFSTS_CTL); - if (status & HSFSTS_CTL_FCERR) - ret = -EIO; - else if (status & HSFSTS_CTL_AEL) - ret = -EACCES; - - if (ret < 0) { - dev_err(ispi->dev, "read error: %llx: %#x\n", from, - status); - return ret; - } - - ret = intel_spi_read_block(ispi, read_buf, block_size); - if (ret) - return ret; - - len -= block_size; - from += block_size; - retlen += block_size; - read_buf += block_size; - } - - return retlen; -} - -static ssize_t intel_spi_write(struct spi_nor *nor, loff_t to, size_t len, - const u_char *write_buf) -{ - struct intel_spi *ispi = nor->priv; - size_t block_size, retlen = 0; - u32 val, status; - ssize_t ret; - - /* Not needed with HW sequencer write, make sure it is cleared */ - ispi->atomic_preopcode = 0; - - while (len > 0) { - block_size = min_t(size_t, len, INTEL_SPI_FIFO_SZ); - - /* Write cannot cross 4K boundary */ - block_size = min_t(loff_t, to + block_size, - round_up(to + 1, SZ_4K)) - to; - - writel(to, ispi->base + FADDR); - - val = readl(ispi->base + HSFSTS_CTL); - val &= ~(HSFSTS_CTL_FDBC_MASK | HSFSTS_CTL_FCYCLE_MASK); - val |= HSFSTS_CTL_AEL | HSFSTS_CTL_FCERR | HSFSTS_CTL_FDONE; - val |= (block_size - 1) << HSFSTS_CTL_FDBC_SHIFT; - val |= HSFSTS_CTL_FCYCLE_WRITE; - - ret = intel_spi_write_block(ispi, write_buf, block_size); - if (ret) { - dev_err(ispi->dev, "failed to write block\n"); - return ret; - } - - /* Start the write now */ - val |= HSFSTS_CTL_FGO; - writel(val, ispi->base + HSFSTS_CTL); - - ret = intel_spi_wait_hw_busy(ispi); - if (ret) { - dev_err(ispi->dev, "timeout\n"); - return ret; - } - - status = readl(ispi->base + HSFSTS_CTL); - if (status & HSFSTS_CTL_FCERR) - ret = -EIO; - else if (status & HSFSTS_CTL_AEL) - ret = -EACCES; - - if (ret < 0) { - dev_err(ispi->dev, "write error: %llx: %#x\n", to, - status); - return ret; - } - - len -= block_size; - to += block_size; - retlen += block_size; - write_buf += block_size; - } - - return retlen; -} - -static int intel_spi_erase(struct spi_nor *nor, loff_t offs) -{ - size_t erase_size, len = nor->mtd.erasesize; - struct intel_spi *ispi = nor->priv; - u32 val, status, cmd; - int ret; - - /* If the hardware can do 64k erase use that when possible */ - if (len >= SZ_64K && ispi->erase_64k) { - cmd = HSFSTS_CTL_FCYCLE_ERASE_64K; - erase_size = SZ_64K; - } else { - cmd = HSFSTS_CTL_FCYCLE_ERASE; - erase_size = SZ_4K; - } - - if (ispi->swseq_erase) { - while (len > 0) { - writel(offs, ispi->base + FADDR); - - ret = intel_spi_sw_cycle(ispi, nor->erase_opcode, - 0, OPTYPE_WRITE_WITH_ADDR); - if (ret) - return ret; - - offs += erase_size; - len -= erase_size; - } - - return 0; - } - - /* Not needed with HW sequencer erase, make sure it is cleared */ - ispi->atomic_preopcode = 0; - - while (len > 0) { - writel(offs, ispi->base + FADDR); - - val = readl(ispi->base + HSFSTS_CTL); - val &= ~(HSFSTS_CTL_FDBC_MASK | HSFSTS_CTL_FCYCLE_MASK); - val |= HSFSTS_CTL_AEL | HSFSTS_CTL_FCERR | HSFSTS_CTL_FDONE; - val |= cmd; - val |= HSFSTS_CTL_FGO; - writel(val, ispi->base + HSFSTS_CTL); - - ret = intel_spi_wait_hw_busy(ispi); - if (ret) - return ret; - - status = readl(ispi->base + HSFSTS_CTL); - if (status & HSFSTS_CTL_FCERR) - return -EIO; - else if (status & HSFSTS_CTL_AEL) - return -EACCES; - - offs += erase_size; - len -= erase_size; - } - - return 0; -} - -static bool intel_spi_is_protected(const struct intel_spi *ispi, - unsigned int base, unsigned int limit) -{ - int i; - - for (i = 0; i < ispi->pr_num; i++) { - u32 pr_base, pr_limit, pr_value; - - pr_value = readl(ispi->pregs + PR(i)); - if (!(pr_value & (PR_WPE | PR_RPE))) - continue; - - pr_limit = (pr_value & PR_LIMIT_MASK) >> PR_LIMIT_SHIFT; - pr_base = pr_value & PR_BASE_MASK; - - if (pr_base >= base && pr_limit <= limit) - return true; - } - - return false; -} - -/* - * There will be a single partition holding all enabled flash regions. We - * call this "BIOS". - */ -static void intel_spi_fill_partition(struct intel_spi *ispi, - struct mtd_partition *part) -{ - u64 end; - int i; - - memset(part, 0, sizeof(*part)); - - /* Start from the mandatory descriptor region */ - part->size = 4096; - part->name = "BIOS"; - - /* - * Now try to find where this partition ends based on the flash - * region registers. - */ - for (i = 1; i < ispi->nregions; i++) { - u32 region, base, limit; - - region = readl(ispi->base + FREG(i)); - base = region & FREG_BASE_MASK; - limit = (region & FREG_LIMIT_MASK) >> FREG_LIMIT_SHIFT; - - if (base >= limit || limit == 0) - continue; - - /* - * If any of the regions have protection bits set, make the - * whole partition read-only to be on the safe side. - * - * Also if the user did not ask the chip to be writeable - * mask the bit too. - */ - if (!writeable || intel_spi_is_protected(ispi, base, limit)) - part->mask_flags |= MTD_WRITEABLE; - - end = (limit << 12) + 4096; - if (end > part->size) - part->size = end; - } -} - -static const struct spi_nor_controller_ops intel_spi_controller_ops = { - .read_reg = intel_spi_read_reg, - .write_reg = intel_spi_write_reg, - .read = intel_spi_read, - .write = intel_spi_write, - .erase = intel_spi_erase, -}; - -struct intel_spi *intel_spi_probe(struct device *dev, - struct resource *mem, const struct intel_spi_boardinfo *info) -{ - const struct spi_nor_hwcaps hwcaps = { - .mask = SNOR_HWCAPS_READ | - SNOR_HWCAPS_READ_FAST | - SNOR_HWCAPS_PP, - }; - struct mtd_partition part; - struct intel_spi *ispi; - int ret; - - if (!info || !mem) - return ERR_PTR(-EINVAL); - - ispi = devm_kzalloc(dev, sizeof(*ispi), GFP_KERNEL); - if (!ispi) - return ERR_PTR(-ENOMEM); - - ispi->base = devm_ioremap_resource(dev, mem); - if (IS_ERR(ispi->base)) - return ERR_CAST(ispi->base); - - ispi->dev = dev; - ispi->info = info; - - ret = intel_spi_init(ispi); - if (ret) - return ERR_PTR(ret); - - ispi->nor.dev = ispi->dev; - ispi->nor.priv = ispi; - ispi->nor.controller_ops = &intel_spi_controller_ops; - - ret = spi_nor_scan(&ispi->nor, NULL, &hwcaps); - if (ret) { - dev_info(dev, "failed to locate the chip\n"); - return ERR_PTR(ret); - } - - intel_spi_fill_partition(ispi, &part); - - ret = mtd_device_register(&ispi->nor.mtd, &part, 1); - if (ret) - return ERR_PTR(ret); - - return ispi; -} -EXPORT_SYMBOL_GPL(intel_spi_probe); - -int intel_spi_remove(struct intel_spi *ispi) -{ - return mtd_device_unregister(&ispi->nor.mtd); -} -EXPORT_SYMBOL_GPL(intel_spi_remove); - -MODULE_DESCRIPTION("Intel PCH/PCU SPI flash core driver"); -MODULE_AUTHOR("Mika Westerberg "); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/mtd/spi-nor/controllers/intel-spi.h b/drivers/mtd/spi-nor/controllers/intel-spi.h deleted file mode 100644 index f2871179fd34..000000000000 --- a/drivers/mtd/spi-nor/controllers/intel-spi.h +++ /dev/null @@ -1,21 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * Intel PCH/PCU SPI flash driver. - * - * Copyright (C) 2016, Intel Corporation - * Author: Mika Westerberg - */ - -#ifndef INTEL_SPI_H -#define INTEL_SPI_H - -#include - -struct intel_spi; -struct resource; - -struct intel_spi *intel_spi_probe(struct device *dev, - struct resource *mem, const struct intel_spi_boardinfo *info); -int intel_spi_remove(struct intel_spi *ispi); - -#endif /* INTEL_SPI_H */ diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index b2a8821971e1..0201257511fb 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -427,6 +427,45 @@ config SPI_INGENIC To compile this driver as a module, choose M here: the module will be called spi-ingenic. +config SPI_INTEL + tristate + +config SPI_INTEL_PCI + tristate "Intel PCH/PCU SPI flash PCI driver (DANGEROUS)" + depends on PCI + depends on X86 || COMPILE_TEST + depends on SPI_MEM + select SPI_INTEL + help + This enables PCI support for the Intel PCH/PCU SPI controller in + master mode. This controller is present in modern Intel hardware + and is used to hold BIOS and other persistent settings. Using + this driver it is possible to upgrade BIOS directly from Linux. + + Say N here unless you know what you are doing. Overwriting the + SPI flash may render the system unbootable. + + To compile this driver as a module, choose M here: the module + will be called spi-intel-pci. + +config SPI_INTEL_PLATFORM + tristate "Intel PCH/PCU SPI flash platform driver (DANGEROUS)" + depends on X86 || COMPILE_TEST + depends on SPI_MEM + select SPI_INTEL + help + This enables platform support for the Intel PCH/PCU SPI + controller in master mode. This controller is present in modern + Intel hardware and is used to hold BIOS and other persistent + settings. Using this driver it is possible to upgrade BIOS + directly from Linux. + + Say N here unless you know what you are doing. Overwriting the + SPI flash may render the system unbootable. + + To compile this driver as a module, choose M here: the module + will be called spi-intel-platform. + config SPI_JCORE tristate "J-Core SPI Master" depends on OF && (SUPERH || COMPILE_TEST) diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile index dd7393a6046f..36b2045f08d2 100644 --- a/drivers/spi/Makefile +++ b/drivers/spi/Makefile @@ -61,6 +61,9 @@ obj-$(CONFIG_SPI_HISI_SFC_V3XX) += spi-hisi-sfc-v3xx.o obj-$(CONFIG_SPI_IMG_SPFI) += spi-img-spfi.o obj-$(CONFIG_SPI_IMX) += spi-imx.o obj-$(CONFIG_SPI_INGENIC) += spi-ingenic.o +obj-$(CONFIG_SPI_INTEL) += spi-intel.o +obj-$(CONFIG_SPI_INTEL_PCI) += spi-intel-pci.o +obj-$(CONFIG_SPI_INTEL_PLATFORM) += spi-intel-platform.o obj-$(CONFIG_SPI_LANTIQ_SSC) += spi-lantiq-ssc.o obj-$(CONFIG_SPI_JCORE) += spi-jcore.o obj-$(CONFIG_SPI_LM70_LLP) += spi-lm70llp.o diff --git a/drivers/spi/spi-intel-pci.c b/drivers/spi/spi-intel-pci.c new file mode 100644 index 000000000000..a9cb4d77ffe3 --- /dev/null +++ b/drivers/spi/spi-intel-pci.c @@ -0,0 +1,94 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Intel PCH/PCU SPI flash PCI driver. + * + * Copyright (C) 2016 - 2022, Intel Corporation + * Author: Mika Westerberg + */ + +#include +#include + +#include "spi-intel.h" + +#define BCR 0xdc +#define BCR_WPD BIT(0) + +static bool intel_spi_pci_set_writeable(void __iomem *base, void *data) +{ + struct pci_dev *pdev = data; + u32 bcr; + + /* Try to make the chip read/write */ + pci_read_config_dword(pdev, BCR, &bcr); + if (!(bcr & BCR_WPD)) { + bcr |= BCR_WPD; + pci_write_config_dword(pdev, BCR, bcr); + pci_read_config_dword(pdev, BCR, &bcr); + } + + return bcr & BCR_WPD; +} + +static const struct intel_spi_boardinfo bxt_info = { + .type = INTEL_SPI_BXT, + .set_writeable = intel_spi_pci_set_writeable, +}; + +static const struct intel_spi_boardinfo cnl_info = { + .type = INTEL_SPI_CNL, + .set_writeable = intel_spi_pci_set_writeable, +}; + +static int intel_spi_pci_probe(struct pci_dev *pdev, + const struct pci_device_id *id) +{ + struct intel_spi_boardinfo *info; + int ret; + + ret = pcim_enable_device(pdev); + if (ret) + return ret; + + info = devm_kmemdup(&pdev->dev, (void *)id->driver_data, sizeof(*info), + GFP_KERNEL); + if (!info) + return -ENOMEM; + + info->data = pdev; + return intel_spi_probe(&pdev->dev, &pdev->resource[0], info); +} + +static const struct pci_device_id intel_spi_pci_ids[] = { + { PCI_VDEVICE(INTEL, 0x02a4), (unsigned long)&bxt_info }, + { PCI_VDEVICE(INTEL, 0x06a4), (unsigned long)&bxt_info }, + { PCI_VDEVICE(INTEL, 0x18e0), (unsigned long)&bxt_info }, + { PCI_VDEVICE(INTEL, 0x19e0), (unsigned long)&bxt_info }, + { PCI_VDEVICE(INTEL, 0x1bca), (unsigned long)&bxt_info }, + { PCI_VDEVICE(INTEL, 0x34a4), (unsigned long)&bxt_info }, + { PCI_VDEVICE(INTEL, 0x43a4), (unsigned long)&cnl_info }, + { PCI_VDEVICE(INTEL, 0x4b24), (unsigned long)&bxt_info }, + { PCI_VDEVICE(INTEL, 0x4da4), (unsigned long)&bxt_info }, + { PCI_VDEVICE(INTEL, 0x51a4), (unsigned long)&cnl_info }, + { PCI_VDEVICE(INTEL, 0x54a4), (unsigned long)&cnl_info }, + { PCI_VDEVICE(INTEL, 0x7aa4), (unsigned long)&cnl_info }, + { PCI_VDEVICE(INTEL, 0xa0a4), (unsigned long)&bxt_info }, + { PCI_VDEVICE(INTEL, 0xa1a4), (unsigned long)&bxt_info }, + { PCI_VDEVICE(INTEL, 0xa224), (unsigned long)&bxt_info }, + { PCI_VDEVICE(INTEL, 0xa324), (unsigned long)&cnl_info }, + { PCI_VDEVICE(INTEL, 0xa3a4), (unsigned long)&bxt_info }, + { }, +}; +MODULE_DEVICE_TABLE(pci, intel_spi_pci_ids); + +static struct pci_driver intel_spi_pci_driver = { + .name = "intel-spi", + .id_table = intel_spi_pci_ids, + .probe = intel_spi_pci_probe, +}; + +module_pci_driver(intel_spi_pci_driver); + +MODULE_DESCRIPTION("Intel PCH/PCU SPI flash PCI driver"); +MODULE_AUTHOR("Mika Westerberg "); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/spi/spi-intel-platform.c b/drivers/spi/spi-intel-platform.c new file mode 100644 index 000000000000..2ef09fa35661 --- /dev/null +++ b/drivers/spi/spi-intel-platform.c @@ -0,0 +1,39 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Intel PCH/PCU SPI flash platform driver. + * + * Copyright (C) 2016 - 2022, Intel Corporation + * Author: Mika Westerberg + */ + +#include +#include + +#include "spi-intel.h" + +static int intel_spi_platform_probe(struct platform_device *pdev) +{ + struct intel_spi_boardinfo *info; + struct resource *mem; + + info = dev_get_platdata(&pdev->dev); + if (!info) + return -EINVAL; + + mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + return intel_spi_probe(&pdev->dev, mem, info); +} + +static struct platform_driver intel_spi_platform_driver = { + .probe = intel_spi_platform_probe, + .driver = { + .name = "intel-spi", + }, +}; + +module_platform_driver(intel_spi_platform_driver); + +MODULE_DESCRIPTION("Intel PCH/PCU SPI flash platform driver"); +MODULE_AUTHOR("Mika Westerberg "); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:intel-spi"); diff --git a/drivers/spi/spi-intel.c b/drivers/spi/spi-intel.c new file mode 100644 index 000000000000..e937cfe85559 --- /dev/null +++ b/drivers/spi/spi-intel.c @@ -0,0 +1,1250 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Intel PCH/PCU SPI flash driver. + * + * Copyright (C) 2016 - 2022, Intel Corporation + * Author: Mika Westerberg + */ + +#include +#include + +#include +#include + +#include +#include +#include + +#include "spi-intel.h" + +/* Offsets are from @ispi->base */ +#define BFPREG 0x00 + +#define HSFSTS_CTL 0x04 +#define HSFSTS_CTL_FSMIE BIT(31) +#define HSFSTS_CTL_FDBC_SHIFT 24 +#define HSFSTS_CTL_FDBC_MASK (0x3f << HSFSTS_CTL_FDBC_SHIFT) + +#define HSFSTS_CTL_FCYCLE_SHIFT 17 +#define HSFSTS_CTL_FCYCLE_MASK (0x0f << HSFSTS_CTL_FCYCLE_SHIFT) +/* HW sequencer opcodes */ +#define HSFSTS_CTL_FCYCLE_READ (0x00 << HSFSTS_CTL_FCYCLE_SHIFT) +#define HSFSTS_CTL_FCYCLE_WRITE (0x02 << HSFSTS_CTL_FCYCLE_SHIFT) +#define HSFSTS_CTL_FCYCLE_ERASE (0x03 << HSFSTS_CTL_FCYCLE_SHIFT) +#define HSFSTS_CTL_FCYCLE_ERASE_64K (0x04 << HSFSTS_CTL_FCYCLE_SHIFT) +#define HSFSTS_CTL_FCYCLE_RDID (0x06 << HSFSTS_CTL_FCYCLE_SHIFT) +#define HSFSTS_CTL_FCYCLE_WRSR (0x07 << HSFSTS_CTL_FCYCLE_SHIFT) +#define HSFSTS_CTL_FCYCLE_RDSR (0x08 << HSFSTS_CTL_FCYCLE_SHIFT) + +#define HSFSTS_CTL_FGO BIT(16) +#define HSFSTS_CTL_FLOCKDN BIT(15) +#define HSFSTS_CTL_FDV BIT(14) +#define HSFSTS_CTL_SCIP BIT(5) +#define HSFSTS_CTL_AEL BIT(2) +#define HSFSTS_CTL_FCERR BIT(1) +#define HSFSTS_CTL_FDONE BIT(0) + +#define FADDR 0x08 +#define DLOCK 0x0c +#define FDATA(n) (0x10 + ((n) * 4)) + +#define FRACC 0x50 + +#define FREG(n) (0x54 + ((n) * 4)) +#define FREG_BASE_MASK 0x3fff +#define FREG_LIMIT_SHIFT 16 +#define FREG_LIMIT_MASK (0x03fff << FREG_LIMIT_SHIFT) + +/* Offset is from @ispi->pregs */ +#define PR(n) ((n) * 4) +#define PR_WPE BIT(31) +#define PR_LIMIT_SHIFT 16 +#define PR_LIMIT_MASK (0x3fff << PR_LIMIT_SHIFT) +#define PR_RPE BIT(15) +#define PR_BASE_MASK 0x3fff + +/* Offsets are from @ispi->sregs */ +#define SSFSTS_CTL 0x00 +#define SSFSTS_CTL_FSMIE BIT(23) +#define SSFSTS_CTL_DS BIT(22) +#define SSFSTS_CTL_DBC_SHIFT 16 +#define SSFSTS_CTL_SPOP BIT(11) +#define SSFSTS_CTL_ACS BIT(10) +#define SSFSTS_CTL_SCGO BIT(9) +#define SSFSTS_CTL_COP_SHIFT 12 +#define SSFSTS_CTL_FRS BIT(7) +#define SSFSTS_CTL_DOFRS BIT(6) +#define SSFSTS_CTL_AEL BIT(4) +#define SSFSTS_CTL_FCERR BIT(3) +#define SSFSTS_CTL_FDONE BIT(2) +#define SSFSTS_CTL_SCIP BIT(0) + +#define PREOP_OPTYPE 0x04 +#define OPMENU0 0x08 +#define OPMENU1 0x0c + +#define OPTYPE_READ_NO_ADDR 0 +#define OPTYPE_WRITE_NO_ADDR 1 +#define OPTYPE_READ_WITH_ADDR 2 +#define OPTYPE_WRITE_WITH_ADDR 3 + +/* CPU specifics */ +#define BYT_PR 0x74 +#define BYT_SSFSTS_CTL 0x90 +#define BYT_FREG_NUM 5 +#define BYT_PR_NUM 5 + +#define LPT_PR 0x74 +#define LPT_SSFSTS_CTL 0x90 +#define LPT_FREG_NUM 5 +#define LPT_PR_NUM 5 + +#define BXT_PR 0x84 +#define BXT_SSFSTS_CTL 0xa0 +#define BXT_FREG_NUM 12 +#define BXT_PR_NUM 6 + +#define CNL_PR 0x84 +#define CNL_FREG_NUM 6 +#define CNL_PR_NUM 5 + +#define LVSCC 0xc4 +#define UVSCC 0xc8 +#define ERASE_OPCODE_SHIFT 8 +#define ERASE_OPCODE_MASK (0xff << ERASE_OPCODE_SHIFT) +#define ERASE_64K_OPCODE_SHIFT 16 +#define ERASE_64K_OPCODE_MASK (0xff << ERASE_OPCODE_SHIFT) + +#define INTEL_SPI_TIMEOUT 5000 /* ms */ +#define INTEL_SPI_FIFO_SZ 64 + +/** + * struct intel_spi - Driver private data + * @dev: Device pointer + * @info: Pointer to board specific info + * @base: Beginning of MMIO space + * @pregs: Start of protection registers + * @sregs: Start of software sequencer registers + * @master: Pointer to the SPI controller structure + * @nregions: Maximum number of regions + * @pr_num: Maximum number of protected range registers + * @locked: Is SPI setting locked + * @swseq_reg: Use SW sequencer in register reads/writes + * @swseq_erase: Use SW sequencer in erase operation + * @atomic_preopcode: Holds preopcode when atomic sequence is requested + * @opcodes: Opcodes which are supported. This are programmed by BIOS + * before it locks down the controller. + * @mem_ops: Pointer to SPI MEM ops supported by the controller + */ +struct intel_spi { + struct device *dev; + const struct intel_spi_boardinfo *info; + void __iomem *base; + void __iomem *pregs; + void __iomem *sregs; + struct spi_controller *master; + size_t nregions; + size_t pr_num; + bool locked; + bool swseq_reg; + bool swseq_erase; + u8 atomic_preopcode; + u8 opcodes[8]; + const struct intel_spi_mem_op *mem_ops; +}; + +struct intel_spi_mem_op { + struct spi_mem_op mem_op; + u32 replacement_op; + int (*exec_op)(struct intel_spi *ispi, + const struct intel_spi_mem_op *iop, + const struct spi_mem_op *op); +}; + +static bool writeable; +module_param(writeable, bool, 0); +MODULE_PARM_DESC(writeable, "Enable write access to SPI flash chip (default=0)"); + +static void intel_spi_dump_regs(struct intel_spi *ispi) +{ + u32 value; + int i; + + dev_dbg(ispi->dev, "BFPREG=0x%08x\n", readl(ispi->base + BFPREG)); + + value = readl(ispi->base + HSFSTS_CTL); + dev_dbg(ispi->dev, "HSFSTS_CTL=0x%08x\n", value); + if (value & HSFSTS_CTL_FLOCKDN) + dev_dbg(ispi->dev, "-> Locked\n"); + + dev_dbg(ispi->dev, "FADDR=0x%08x\n", readl(ispi->base + FADDR)); + dev_dbg(ispi->dev, "DLOCK=0x%08x\n", readl(ispi->base + DLOCK)); + + for (i = 0; i < 16; i++) + dev_dbg(ispi->dev, "FDATA(%d)=0x%08x\n", + i, readl(ispi->base + FDATA(i))); + + dev_dbg(ispi->dev, "FRACC=0x%08x\n", readl(ispi->base + FRACC)); + + for (i = 0; i < ispi->nregions; i++) + dev_dbg(ispi->dev, "FREG(%d)=0x%08x\n", i, + readl(ispi->base + FREG(i))); + for (i = 0; i < ispi->pr_num; i++) + dev_dbg(ispi->dev, "PR(%d)=0x%08x\n", i, + readl(ispi->pregs + PR(i))); + + if (ispi->sregs) { + value = readl(ispi->sregs + SSFSTS_CTL); + dev_dbg(ispi->dev, "SSFSTS_CTL=0x%08x\n", value); + dev_dbg(ispi->dev, "PREOP_OPTYPE=0x%08x\n", + readl(ispi->sregs + PREOP_OPTYPE)); + dev_dbg(ispi->dev, "OPMENU0=0x%08x\n", + readl(ispi->sregs + OPMENU0)); + dev_dbg(ispi->dev, "OPMENU1=0x%08x\n", + readl(ispi->sregs + OPMENU1)); + } + + dev_dbg(ispi->dev, "LVSCC=0x%08x\n", readl(ispi->base + LVSCC)); + dev_dbg(ispi->dev, "UVSCC=0x%08x\n", readl(ispi->base + UVSCC)); + + dev_dbg(ispi->dev, "Protected regions:\n"); + for (i = 0; i < ispi->pr_num; i++) { + u32 base, limit; + + value = readl(ispi->pregs + PR(i)); + if (!(value & (PR_WPE | PR_RPE))) + continue; + + limit = (value & PR_LIMIT_MASK) >> PR_LIMIT_SHIFT; + base = value & PR_BASE_MASK; + + dev_dbg(ispi->dev, " %02d base: 0x%08x limit: 0x%08x [%c%c]\n", + i, base << 12, (limit << 12) | 0xfff, + value & PR_WPE ? 'W' : '.', value & PR_RPE ? 'R' : '.'); + } + + dev_dbg(ispi->dev, "Flash regions:\n"); + for (i = 0; i < ispi->nregions; i++) { + u32 region, base, limit; + + region = readl(ispi->base + FREG(i)); + base = region & FREG_BASE_MASK; + limit = (region & FREG_LIMIT_MASK) >> FREG_LIMIT_SHIFT; + + if (base >= limit || (i > 0 && limit == 0)) + dev_dbg(ispi->dev, " %02d disabled\n", i); + else + dev_dbg(ispi->dev, " %02d base: 0x%08x limit: 0x%08x\n", + i, base << 12, (limit << 12) | 0xfff); + } + + dev_dbg(ispi->dev, "Using %cW sequencer for register access\n", + ispi->swseq_reg ? 'S' : 'H'); + dev_dbg(ispi->dev, "Using %cW sequencer for erase operation\n", + ispi->swseq_erase ? 'S' : 'H'); +} + +/* Reads max INTEL_SPI_FIFO_SZ bytes from the device fifo */ +static int intel_spi_read_block(struct intel_spi *ispi, void *buf, size_t size) +{ + size_t bytes; + int i = 0; + + if (size > INTEL_SPI_FIFO_SZ) + return -EINVAL; + + while (size > 0) { + bytes = min_t(size_t, size, 4); + memcpy_fromio(buf, ispi->base + FDATA(i), bytes); + size -= bytes; + buf += bytes; + i++; + } + + return 0; +} + +/* Writes max INTEL_SPI_FIFO_SZ bytes to the device fifo */ +static int intel_spi_write_block(struct intel_spi *ispi, const void *buf, + size_t size) +{ + size_t bytes; + int i = 0; + + if (size > INTEL_SPI_FIFO_SZ) + return -EINVAL; + + while (size > 0) { + bytes = min_t(size_t, size, 4); + memcpy_toio(ispi->base + FDATA(i), buf, bytes); + size -= bytes; + buf += bytes; + i++; + } + + return 0; +} + +static int intel_spi_wait_hw_busy(struct intel_spi *ispi) +{ + u32 val; + + return readl_poll_timeout(ispi->base + HSFSTS_CTL, val, + !(val & HSFSTS_CTL_SCIP), 0, + INTEL_SPI_TIMEOUT * 1000); +} + +static int intel_spi_wait_sw_busy(struct intel_spi *ispi) +{ + u32 val; + + return readl_poll_timeout(ispi->sregs + SSFSTS_CTL, val, + !(val & SSFSTS_CTL_SCIP), 0, + INTEL_SPI_TIMEOUT * 1000); +} + +static bool intel_spi_set_writeable(struct intel_spi *ispi) +{ + if (!ispi->info->set_writeable) + return false; + + return ispi->info->set_writeable(ispi->base, ispi->info->data); +} + +static int intel_spi_opcode_index(struct intel_spi *ispi, u8 opcode, int optype) +{ + int i; + int preop; + + if (ispi->locked) { + for (i = 0; i < ARRAY_SIZE(ispi->opcodes); i++) + if (ispi->opcodes[i] == opcode) + return i; + + return -EINVAL; + } + + /* The lock is off, so just use index 0 */ + writel(opcode, ispi->sregs + OPMENU0); + preop = readw(ispi->sregs + PREOP_OPTYPE); + writel(optype << 16 | preop, ispi->sregs + PREOP_OPTYPE); + + return 0; +} + +static int intel_spi_hw_cycle(struct intel_spi *ispi, u8 opcode, size_t len) +{ + u32 val, status; + int ret; + + val = readl(ispi->base + HSFSTS_CTL); + val &= ~(HSFSTS_CTL_FCYCLE_MASK | HSFSTS_CTL_FDBC_MASK); + + switch (opcode) { + case SPINOR_OP_RDID: + val |= HSFSTS_CTL_FCYCLE_RDID; + break; + case SPINOR_OP_WRSR: + val |= HSFSTS_CTL_FCYCLE_WRSR; + break; + case SPINOR_OP_RDSR: + val |= HSFSTS_CTL_FCYCLE_RDSR; + break; + default: + return -EINVAL; + } + + if (len > INTEL_SPI_FIFO_SZ) + return -EINVAL; + + val |= (len - 1) << HSFSTS_CTL_FDBC_SHIFT; + val |= HSFSTS_CTL_FCERR | HSFSTS_CTL_FDONE; + val |= HSFSTS_CTL_FGO; + writel(val, ispi->base + HSFSTS_CTL); + + ret = intel_spi_wait_hw_busy(ispi); + if (ret) + return ret; + + status = readl(ispi->base + HSFSTS_CTL); + if (status & HSFSTS_CTL_FCERR) + return -EIO; + else if (status & HSFSTS_CTL_AEL) + return -EACCES; + + return 0; +} + +static int intel_spi_sw_cycle(struct intel_spi *ispi, u8 opcode, size_t len, + int optype) +{ + u32 val = 0, status; + u8 atomic_preopcode; + int ret; + + ret = intel_spi_opcode_index(ispi, opcode, optype); + if (ret < 0) + return ret; + + if (len > INTEL_SPI_FIFO_SZ) + return -EINVAL; + + /* + * Always clear it after each SW sequencer operation regardless + * of whether it is successful or not. + */ + atomic_preopcode = ispi->atomic_preopcode; + ispi->atomic_preopcode = 0; + + /* Only mark 'Data Cycle' bit when there is data to be transferred */ + if (len > 0) + val = ((len - 1) << SSFSTS_CTL_DBC_SHIFT) | SSFSTS_CTL_DS; + val |= ret << SSFSTS_CTL_COP_SHIFT; + val |= SSFSTS_CTL_FCERR | SSFSTS_CTL_FDONE; + val |= SSFSTS_CTL_SCGO; + if (atomic_preopcode) { + u16 preop; + + switch (optype) { + case OPTYPE_WRITE_NO_ADDR: + case OPTYPE_WRITE_WITH_ADDR: + /* Pick matching preopcode for the atomic sequence */ + preop = readw(ispi->sregs + PREOP_OPTYPE); + if ((preop & 0xff) == atomic_preopcode) + ; /* Do nothing */ + else if ((preop >> 8) == atomic_preopcode) + val |= SSFSTS_CTL_SPOP; + else + return -EINVAL; + + /* Enable atomic sequence */ + val |= SSFSTS_CTL_ACS; + break; + + default: + return -EINVAL; + } + } + writel(val, ispi->sregs + SSFSTS_CTL); + + ret = intel_spi_wait_sw_busy(ispi); + if (ret) + return ret; + + status = readl(ispi->sregs + SSFSTS_CTL); + if (status & SSFSTS_CTL_FCERR) + return -EIO; + else if (status & SSFSTS_CTL_AEL) + return -EACCES; + + return 0; +} + +static int intel_spi_read_reg(struct intel_spi *ispi, + const struct intel_spi_mem_op *iop, + const struct spi_mem_op *op) +{ + size_t nbytes = op->data.nbytes; + u8 opcode = op->cmd.opcode; + int ret; + + /* Address of the first chip */ + writel(0, ispi->base + FADDR); + + if (ispi->swseq_reg) + ret = intel_spi_sw_cycle(ispi, opcode, nbytes, + OPTYPE_READ_NO_ADDR); + else + ret = intel_spi_hw_cycle(ispi, opcode, nbytes); + + if (ret) + return ret; + + return intel_spi_read_block(ispi, op->data.buf.in, nbytes); +} + +static int intel_spi_write_reg(struct intel_spi *ispi, + const struct intel_spi_mem_op *iop, + const struct spi_mem_op *op) +{ + size_t nbytes = op->data.nbytes; + u8 opcode = op->cmd.opcode; + int ret; + + /* + * This is handled with atomic operation and preop code in Intel + * controller so we only verify that it is available. If the + * controller is not locked, program the opcode to the PREOP + * register for later use. + * + * When hardware sequencer is used there is no need to program + * any opcodes (it handles them automatically as part of a command). + */ + if (opcode == SPINOR_OP_WREN) { + u16 preop; + + if (!ispi->swseq_reg) + return 0; + + preop = readw(ispi->sregs + PREOP_OPTYPE); + if ((preop & 0xff) != opcode && (preop >> 8) != opcode) { + if (ispi->locked) + return -EINVAL; + writel(opcode, ispi->sregs + PREOP_OPTYPE); + } + + /* + * This enables atomic sequence on next SW sycle. Will + * be cleared after next operation. + */ + ispi->atomic_preopcode = opcode; + return 0; + } + + /* + * We hope that HW sequencer will do the right thing automatically and + * with the SW sequencer we cannot use preopcode anyway, so just ignore + * the Write Disable operation and pretend it was completed + * successfully. + */ + if (opcode == SPINOR_OP_WRDI) + return 0; + + writel(0, ispi->base + FADDR); + + /* Write the value beforehand */ + ret = intel_spi_write_block(ispi, op->data.buf.out, nbytes); + if (ret) + return ret; + + if (ispi->swseq_reg) + return intel_spi_sw_cycle(ispi, opcode, nbytes, + OPTYPE_WRITE_NO_ADDR); + return intel_spi_hw_cycle(ispi, opcode, nbytes); +} + +static int intel_spi_read(struct intel_spi *ispi, + const struct intel_spi_mem_op *iop, + const struct spi_mem_op *op) +{ + void *read_buf = op->data.buf.in; + size_t block_size, nbytes = op->data.nbytes; + u32 addr = op->addr.val; + u32 val, status; + int ret; + + /* + * Atomic sequence is not expected with HW sequencer reads. Make + * sure it is cleared regardless. + */ + if (WARN_ON_ONCE(ispi->atomic_preopcode)) + ispi->atomic_preopcode = 0; + + while (nbytes > 0) { + block_size = min_t(size_t, nbytes, INTEL_SPI_FIFO_SZ); + + /* Read cannot cross 4K boundary */ + block_size = min_t(loff_t, addr + block_size, + round_up(addr + 1, SZ_4K)) - addr; + + writel(addr, ispi->base + FADDR); + + val = readl(ispi->base + HSFSTS_CTL); + val &= ~(HSFSTS_CTL_FDBC_MASK | HSFSTS_CTL_FCYCLE_MASK); + val |= HSFSTS_CTL_AEL | HSFSTS_CTL_FCERR | HSFSTS_CTL_FDONE; + val |= (block_size - 1) << HSFSTS_CTL_FDBC_SHIFT; + val |= HSFSTS_CTL_FCYCLE_READ; + val |= HSFSTS_CTL_FGO; + writel(val, ispi->base + HSFSTS_CTL); + + ret = intel_spi_wait_hw_busy(ispi); + if (ret) + return ret; + + status = readl(ispi->base + HSFSTS_CTL); + if (status & HSFSTS_CTL_FCERR) + ret = -EIO; + else if (status & HSFSTS_CTL_AEL) + ret = -EACCES; + + if (ret < 0) { + dev_err(ispi->dev, "read error: %x: %#x\n", addr, status); + return ret; + } + + ret = intel_spi_read_block(ispi, read_buf, block_size); + if (ret) + return ret; + + nbytes -= block_size; + addr += block_size; + read_buf += block_size; + } + + return 0; +} + +static int intel_spi_write(struct intel_spi *ispi, + const struct intel_spi_mem_op *iop, + const struct spi_mem_op *op) +{ + size_t block_size, nbytes = op->data.nbytes; + const void *write_buf = op->data.buf.out; + u32 addr = op->addr.val; + u32 val, status; + int ret; + + /* Not needed with HW sequencer write, make sure it is cleared */ + ispi->atomic_preopcode = 0; + + while (nbytes > 0) { + block_size = min_t(size_t, nbytes, INTEL_SPI_FIFO_SZ); + + /* Write cannot cross 4K boundary */ + block_size = min_t(loff_t, addr + block_size, + round_up(addr + 1, SZ_4K)) - addr; + + writel(addr, ispi->base + FADDR); + + val = readl(ispi->base + HSFSTS_CTL); + val &= ~(HSFSTS_CTL_FDBC_MASK | HSFSTS_CTL_FCYCLE_MASK); + val |= HSFSTS_CTL_AEL | HSFSTS_CTL_FCERR | HSFSTS_CTL_FDONE; + val |= (block_size - 1) << HSFSTS_CTL_FDBC_SHIFT; + val |= HSFSTS_CTL_FCYCLE_WRITE; + + ret = intel_spi_write_block(ispi, write_buf, block_size); + if (ret) { + dev_err(ispi->dev, "failed to write block\n"); + return ret; + } + + /* Start the write now */ + val |= HSFSTS_CTL_FGO; + writel(val, ispi->base + HSFSTS_CTL); + + ret = intel_spi_wait_hw_busy(ispi); + if (ret) { + dev_err(ispi->dev, "timeout\n"); + return ret; + } + + status = readl(ispi->base + HSFSTS_CTL); + if (status & HSFSTS_CTL_FCERR) + ret = -EIO; + else if (status & HSFSTS_CTL_AEL) + ret = -EACCES; + + if (ret < 0) { + dev_err(ispi->dev, "write error: %x: %#x\n", addr, status); + return ret; + } + + nbytes -= block_size; + addr += block_size; + write_buf += block_size; + } + + return 0; +} + +static int intel_spi_erase(struct intel_spi *ispi, + const struct intel_spi_mem_op *iop, + const struct spi_mem_op *op) +{ + u8 opcode = op->cmd.opcode; + u32 addr = op->addr.val; + u32 val, status; + int ret; + + writel(addr, ispi->base + FADDR); + + if (ispi->swseq_erase) + return intel_spi_sw_cycle(ispi, opcode, 0, + OPTYPE_WRITE_WITH_ADDR); + + /* Not needed with HW sequencer erase, make sure it is cleared */ + ispi->atomic_preopcode = 0; + + val = readl(ispi->base + HSFSTS_CTL); + val &= ~(HSFSTS_CTL_FDBC_MASK | HSFSTS_CTL_FCYCLE_MASK); + val |= HSFSTS_CTL_AEL | HSFSTS_CTL_FCERR | HSFSTS_CTL_FDONE; + val |= HSFSTS_CTL_FGO; + val |= iop->replacement_op; + writel(val, ispi->base + HSFSTS_CTL); + + ret = intel_spi_wait_hw_busy(ispi); + if (ret) + return ret; + + status = readl(ispi->base + HSFSTS_CTL); + if (status & HSFSTS_CTL_FCERR) + return -EIO; + if (status & HSFSTS_CTL_AEL) + return -EACCES; + + return 0; +} + +static bool intel_spi_cmp_mem_op(const struct intel_spi_mem_op *iop, + const struct spi_mem_op *op) +{ + if (iop->mem_op.cmd.nbytes != op->cmd.nbytes || + iop->mem_op.cmd.buswidth != op->cmd.buswidth || + iop->mem_op.cmd.dtr != op->cmd.dtr || + iop->mem_op.cmd.opcode != op->cmd.opcode) + return false; + + if (iop->mem_op.addr.nbytes != op->addr.nbytes || + iop->mem_op.addr.dtr != op->addr.dtr) + return false; + + if (iop->mem_op.data.dir != op->data.dir || + iop->mem_op.data.dtr != op->data.dtr) + return false; + + if (iop->mem_op.data.dir != SPI_MEM_NO_DATA) { + if (iop->mem_op.data.buswidth != op->data.buswidth) + return false; + } + + return true; +} + +static const struct intel_spi_mem_op * +intel_spi_match_mem_op(struct intel_spi *ispi, const struct spi_mem_op *op) +{ + const struct intel_spi_mem_op *iop; + + for (iop = ispi->mem_ops; iop->mem_op.cmd.opcode; iop++) { + if (intel_spi_cmp_mem_op(iop, op)) + break; + } + + return iop->mem_op.cmd.opcode ? iop : NULL; +} + +static bool intel_spi_supports_mem_op(struct spi_mem *mem, + const struct spi_mem_op *op) +{ + struct intel_spi *ispi = spi_master_get_devdata(mem->spi->master); + const struct intel_spi_mem_op *iop; + + iop = intel_spi_match_mem_op(ispi, op); + if (!iop) { + dev_dbg(ispi->dev, "%#x not supported\n", op->cmd.opcode); + return false; + } + + /* + * For software sequencer check that the opcode is actually + * present in the opmenu if it is locked. + */ + if (ispi->swseq_reg && ispi->locked) { + int i; + + /* Check if it is in the locked opcodes list */ + for (i = 0; i < ARRAY_SIZE(ispi->opcodes); i++) { + if (ispi->opcodes[i] == op->cmd.opcode) + return true; + } + + dev_dbg(ispi->dev, "%#x not supported\n", op->cmd.opcode); + return false; + } + + return true; +} + +static int intel_spi_exec_mem_op(struct spi_mem *mem, const struct spi_mem_op *op) +{ + struct intel_spi *ispi = spi_master_get_devdata(mem->spi->master); + const struct intel_spi_mem_op *iop; + + iop = intel_spi_match_mem_op(ispi, op); + if (!iop) + return -EOPNOTSUPP; + + return iop->exec_op(ispi, iop, op); +} + +static const char *intel_spi_get_name(struct spi_mem *mem) +{ + const struct intel_spi *ispi = spi_master_get_devdata(mem->spi->master); + + /* + * Return name of the flash controller device to be compatible + * with the MTD version. + */ + return dev_name(ispi->dev); +} + +static const struct spi_controller_mem_ops intel_spi_mem_ops = { + .supports_op = intel_spi_supports_mem_op, + .exec_op = intel_spi_exec_mem_op, + .get_name = intel_spi_get_name, +}; + +#define INTEL_SPI_OP_ADDR(__nbytes) \ + { \ + .nbytes = __nbytes, \ + } + +#define INTEL_SPI_OP_NO_DATA \ + { \ + .dir = SPI_MEM_NO_DATA, \ + } + +#define INTEL_SPI_OP_DATA_IN(__buswidth) \ + { \ + .dir = SPI_MEM_DATA_IN, \ + .buswidth = __buswidth, \ + } + +#define INTEL_SPI_OP_DATA_OUT(__buswidth) \ + { \ + .dir = SPI_MEM_DATA_OUT, \ + .buswidth = __buswidth, \ + } + +#define INTEL_SPI_MEM_OP(__cmd, __addr, __data, __exec_op) \ + { \ + .mem_op = { \ + .cmd = __cmd, \ + .addr = __addr, \ + .data = __data, \ + }, \ + .exec_op = __exec_op, \ + } + +#define INTEL_SPI_MEM_OP_REPL(__cmd, __addr, __data, __exec_op, __repl) \ + { \ + .mem_op = { \ + .cmd = __cmd, \ + .addr = __addr, \ + .data = __data, \ + }, \ + .exec_op = __exec_op, \ + .replacement_op = __repl, \ + } + +/* + * The controller handles pretty much everything internally based on the + * SFDP data but we want to make sure we only support the operations + * actually possible. Only check buswidth and transfer direction, the + * core validates data. + */ +#define INTEL_SPI_GENERIC_OPS \ + /* Status register operations */ \ + INTEL_SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_RDID, 1), \ + SPI_MEM_OP_NO_ADDR, \ + INTEL_SPI_OP_DATA_IN(1), \ + intel_spi_read_reg), \ + INTEL_SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_RDSR, 1), \ + SPI_MEM_OP_NO_ADDR, \ + INTEL_SPI_OP_DATA_IN(1), \ + intel_spi_read_reg), \ + INTEL_SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_WRSR, 1), \ + SPI_MEM_OP_NO_ADDR, \ + INTEL_SPI_OP_DATA_OUT(1), \ + intel_spi_write_reg), \ + /* Normal read */ \ + INTEL_SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_READ, 1), \ + INTEL_SPI_OP_ADDR(3), \ + INTEL_SPI_OP_DATA_IN(1), \ + intel_spi_read), \ + INTEL_SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_READ, 1), \ + INTEL_SPI_OP_ADDR(3), \ + INTEL_SPI_OP_DATA_IN(2), \ + intel_spi_read), \ + INTEL_SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_READ, 1), \ + INTEL_SPI_OP_ADDR(3), \ + INTEL_SPI_OP_DATA_IN(4), \ + intel_spi_read), \ + INTEL_SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_READ, 1), \ + INTEL_SPI_OP_ADDR(4), \ + INTEL_SPI_OP_DATA_IN(1), \ + intel_spi_read), \ + INTEL_SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_READ, 1), \ + INTEL_SPI_OP_ADDR(4), \ + INTEL_SPI_OP_DATA_IN(2), \ + intel_spi_read), \ + INTEL_SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_READ, 1), \ + INTEL_SPI_OP_ADDR(4), \ + INTEL_SPI_OP_DATA_IN(4), \ + intel_spi_read), \ + /* Fast read */ \ + INTEL_SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_READ_FAST, 1), \ + INTEL_SPI_OP_ADDR(3), \ + INTEL_SPI_OP_DATA_IN(1), \ + intel_spi_read), \ + INTEL_SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_READ_FAST, 1), \ + INTEL_SPI_OP_ADDR(3), \ + INTEL_SPI_OP_DATA_IN(2), \ + intel_spi_read), \ + INTEL_SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_READ_FAST, 1), \ + INTEL_SPI_OP_ADDR(3), \ + INTEL_SPI_OP_DATA_IN(4), \ + intel_spi_read), \ + INTEL_SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_READ_FAST, 1), \ + INTEL_SPI_OP_ADDR(4), \ + INTEL_SPI_OP_DATA_IN(1), \ + intel_spi_read), \ + INTEL_SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_READ_FAST, 1), \ + INTEL_SPI_OP_ADDR(4), \ + INTEL_SPI_OP_DATA_IN(2), \ + intel_spi_read), \ + INTEL_SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_READ_FAST, 1), \ + INTEL_SPI_OP_ADDR(4), \ + INTEL_SPI_OP_DATA_IN(4), \ + intel_spi_read), \ + /* Read with 4-byte address opcode */ \ + INTEL_SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_READ_4B, 1), \ + INTEL_SPI_OP_ADDR(4), \ + INTEL_SPI_OP_DATA_IN(1), \ + intel_spi_read), \ + INTEL_SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_READ_4B, 1), \ + INTEL_SPI_OP_ADDR(4), \ + INTEL_SPI_OP_DATA_IN(2), \ + intel_spi_read), \ + INTEL_SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_READ_4B, 1), \ + INTEL_SPI_OP_ADDR(4), \ + INTEL_SPI_OP_DATA_IN(4), \ + intel_spi_read), \ + /* Fast read with 4-byte address opcode */ \ + INTEL_SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_READ_FAST_4B, 1), \ + INTEL_SPI_OP_ADDR(4), \ + INTEL_SPI_OP_DATA_IN(1), \ + intel_spi_read), \ + INTEL_SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_READ_FAST_4B, 1), \ + INTEL_SPI_OP_ADDR(4), \ + INTEL_SPI_OP_DATA_IN(2), \ + intel_spi_read), \ + INTEL_SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_READ_FAST_4B, 1), \ + INTEL_SPI_OP_ADDR(4), \ + INTEL_SPI_OP_DATA_IN(4), \ + intel_spi_read), \ + /* Write operations */ \ + INTEL_SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_PP, 1), \ + INTEL_SPI_OP_ADDR(3), \ + INTEL_SPI_OP_DATA_OUT(1), \ + intel_spi_write), \ + INTEL_SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_PP, 1), \ + INTEL_SPI_OP_ADDR(4), \ + INTEL_SPI_OP_DATA_OUT(1), \ + intel_spi_write), \ + INTEL_SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_PP_4B, 1), \ + INTEL_SPI_OP_ADDR(4), \ + INTEL_SPI_OP_DATA_OUT(1), \ + intel_spi_write), \ + INTEL_SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_WREN, 1), \ + SPI_MEM_OP_NO_ADDR, \ + SPI_MEM_OP_NO_DATA, \ + intel_spi_write_reg), \ + INTEL_SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_WRDI, 1), \ + SPI_MEM_OP_NO_ADDR, \ + SPI_MEM_OP_NO_DATA, \ + intel_spi_write_reg), \ + /* Erase operations */ \ + INTEL_SPI_MEM_OP_REPL(SPI_MEM_OP_CMD(SPINOR_OP_BE_4K, 1), \ + INTEL_SPI_OP_ADDR(3), \ + SPI_MEM_OP_NO_DATA, \ + intel_spi_erase, \ + HSFSTS_CTL_FCYCLE_ERASE), \ + INTEL_SPI_MEM_OP_REPL(SPI_MEM_OP_CMD(SPINOR_OP_BE_4K, 1), \ + INTEL_SPI_OP_ADDR(4), \ + SPI_MEM_OP_NO_DATA, \ + intel_spi_erase, \ + HSFSTS_CTL_FCYCLE_ERASE), \ + INTEL_SPI_MEM_OP_REPL(SPI_MEM_OP_CMD(SPINOR_OP_BE_4K_4B, 1), \ + INTEL_SPI_OP_ADDR(4), \ + SPI_MEM_OP_NO_DATA, \ + intel_spi_erase, \ + HSFSTS_CTL_FCYCLE_ERASE) \ + +static const struct intel_spi_mem_op generic_mem_ops[] = { + INTEL_SPI_GENERIC_OPS, + { }, +}; + +static const struct intel_spi_mem_op erase_64k_mem_ops[] = { + INTEL_SPI_GENERIC_OPS, + /* 64k sector erase operations */ + INTEL_SPI_MEM_OP_REPL(SPI_MEM_OP_CMD(SPINOR_OP_SE, 1), + INTEL_SPI_OP_ADDR(3), + SPI_MEM_OP_NO_DATA, + intel_spi_erase, + HSFSTS_CTL_FCYCLE_ERASE_64K), + INTEL_SPI_MEM_OP_REPL(SPI_MEM_OP_CMD(SPINOR_OP_SE, 1), + INTEL_SPI_OP_ADDR(4), + SPI_MEM_OP_NO_DATA, + intel_spi_erase, + HSFSTS_CTL_FCYCLE_ERASE_64K), + INTEL_SPI_MEM_OP_REPL(SPI_MEM_OP_CMD(SPINOR_OP_SE_4B, 1), + INTEL_SPI_OP_ADDR(4), + SPI_MEM_OP_NO_DATA, + intel_spi_erase, + HSFSTS_CTL_FCYCLE_ERASE_64K), + { }, +}; + +static int intel_spi_init(struct intel_spi *ispi) +{ + u32 opmenu0, opmenu1, lvscc, uvscc, val; + bool erase_64k = false; + int i; + + switch (ispi->info->type) { + case INTEL_SPI_BYT: + ispi->sregs = ispi->base + BYT_SSFSTS_CTL; + ispi->pregs = ispi->base + BYT_PR; + ispi->nregions = BYT_FREG_NUM; + ispi->pr_num = BYT_PR_NUM; + ispi->swseq_reg = true; + break; + + case INTEL_SPI_LPT: + ispi->sregs = ispi->base + LPT_SSFSTS_CTL; + ispi->pregs = ispi->base + LPT_PR; + ispi->nregions = LPT_FREG_NUM; + ispi->pr_num = LPT_PR_NUM; + ispi->swseq_reg = true; + break; + + case INTEL_SPI_BXT: + ispi->sregs = ispi->base + BXT_SSFSTS_CTL; + ispi->pregs = ispi->base + BXT_PR; + ispi->nregions = BXT_FREG_NUM; + ispi->pr_num = BXT_PR_NUM; + erase_64k = true; + break; + + case INTEL_SPI_CNL: + ispi->sregs = NULL; + ispi->pregs = ispi->base + CNL_PR; + ispi->nregions = CNL_FREG_NUM; + ispi->pr_num = CNL_PR_NUM; + break; + + default: + return -EINVAL; + } + + /* Try to disable write protection if user asked to do so */ + if (writeable && !intel_spi_set_writeable(ispi)) { + dev_warn(ispi->dev, "can't disable chip write protection\n"); + writeable = false; + } + + /* Disable #SMI generation from HW sequencer */ + val = readl(ispi->base + HSFSTS_CTL); + val &= ~HSFSTS_CTL_FSMIE; + writel(val, ispi->base + HSFSTS_CTL); + + /* + * Determine whether erase operation should use HW or SW sequencer. + * + * The HW sequencer has a predefined list of opcodes, with only the + * erase opcode being programmable in LVSCC and UVSCC registers. + * If these registers don't contain a valid erase opcode, erase + * cannot be done using HW sequencer. + */ + lvscc = readl(ispi->base + LVSCC); + uvscc = readl(ispi->base + UVSCC); + if (!(lvscc & ERASE_OPCODE_MASK) || !(uvscc & ERASE_OPCODE_MASK)) + ispi->swseq_erase = true; + /* SPI controller on Intel BXT supports 64K erase opcode */ + if (ispi->info->type == INTEL_SPI_BXT && !ispi->swseq_erase) + if (!(lvscc & ERASE_64K_OPCODE_MASK) || + !(uvscc & ERASE_64K_OPCODE_MASK)) + erase_64k = false; + + if (!ispi->sregs && (ispi->swseq_reg || ispi->swseq_erase)) { + dev_err(ispi->dev, "software sequencer not supported, but required\n"); + return -EINVAL; + } + + /* + * Some controllers can only do basic operations using hardware + * sequencer. All other operations are supposed to be carried out + * using software sequencer. + */ + if (ispi->swseq_reg) { + /* Disable #SMI generation from SW sequencer */ + val = readl(ispi->sregs + SSFSTS_CTL); + val &= ~SSFSTS_CTL_FSMIE; + writel(val, ispi->sregs + SSFSTS_CTL); + } + + /* Check controller's lock status */ + val = readl(ispi->base + HSFSTS_CTL); + ispi->locked = !!(val & HSFSTS_CTL_FLOCKDN); + + if (ispi->locked && ispi->sregs) { + /* + * BIOS programs allowed opcodes and then locks down the + * register. So read back what opcodes it decided to support. + * That's the set we are going to support as well. + */ + opmenu0 = readl(ispi->sregs + OPMENU0); + opmenu1 = readl(ispi->sregs + OPMENU1); + + if (opmenu0 && opmenu1) { + for (i = 0; i < ARRAY_SIZE(ispi->opcodes) / 2; i++) { + ispi->opcodes[i] = opmenu0 >> i * 8; + ispi->opcodes[i + 4] = opmenu1 >> i * 8; + } + } + } + + if (erase_64k) { + dev_dbg(ispi->dev, "Using erase_64k memory operations"); + ispi->mem_ops = erase_64k_mem_ops; + } else { + dev_dbg(ispi->dev, "Using generic memory operations"); + ispi->mem_ops = generic_mem_ops; + } + + intel_spi_dump_regs(ispi); + return 0; +} + +static bool intel_spi_is_protected(const struct intel_spi *ispi, + unsigned int base, unsigned int limit) +{ + int i; + + for (i = 0; i < ispi->pr_num; i++) { + u32 pr_base, pr_limit, pr_value; + + pr_value = readl(ispi->pregs + PR(i)); + if (!(pr_value & (PR_WPE | PR_RPE))) + continue; + + pr_limit = (pr_value & PR_LIMIT_MASK) >> PR_LIMIT_SHIFT; + pr_base = pr_value & PR_BASE_MASK; + + if (pr_base >= base && pr_limit <= limit) + return true; + } + + return false; +} + +/* + * There will be a single partition holding all enabled flash regions. We + * call this "BIOS". + */ +static void intel_spi_fill_partition(struct intel_spi *ispi, + struct mtd_partition *part) +{ + u64 end; + int i; + + memset(part, 0, sizeof(*part)); + + /* Start from the mandatory descriptor region */ + part->size = 4096; + part->name = "BIOS"; + + /* + * Now try to find where this partition ends based on the flash + * region registers. + */ + for (i = 1; i < ispi->nregions; i++) { + u32 region, base, limit; + + region = readl(ispi->base + FREG(i)); + base = region & FREG_BASE_MASK; + limit = (region & FREG_LIMIT_MASK) >> FREG_LIMIT_SHIFT; + + if (base >= limit || limit == 0) + continue; + + /* + * If any of the regions have protection bits set, make the + * whole partition read-only to be on the safe side. + * + * Also if the user did not ask the chip to be writeable + * mask the bit too. + */ + if (!writeable || intel_spi_is_protected(ispi, base, limit)) + part->mask_flags |= MTD_WRITEABLE; + + end = (limit << 12) + 4096; + if (end > part->size) + part->size = end; + } +} + +static int intel_spi_populate_chip(struct intel_spi *ispi) +{ + struct flash_platform_data *pdata; + struct spi_board_info chip; + + pdata = devm_kzalloc(ispi->dev, sizeof(*pdata), GFP_KERNEL); + if (!pdata) + return -ENOMEM; + + pdata->nr_parts = 1; + pdata->parts = devm_kcalloc(ispi->dev, sizeof(*pdata->parts), + pdata->nr_parts, GFP_KERNEL); + if (!pdata->parts) + return -ENOMEM; + + intel_spi_fill_partition(ispi, pdata->parts); + + memset(&chip, 0, sizeof(chip)); + snprintf(chip.modalias, 8, "spi-nor"); + chip.platform_data = pdata; + + return spi_new_device(ispi->master, &chip) ? 0 : -ENODEV; +} + +/** + * intel_spi_probe() - Probe the Intel SPI flash controller + * @dev: Pointer to the parent device + * @mem: MMIO resource + * @info: Platform spefific information + * + * Probes Intel SPI flash controller and creates the flash chip device. + * Returns %0 on success and negative errno in case of failure. + */ +int intel_spi_probe(struct device *dev, struct resource *mem, + const struct intel_spi_boardinfo *info) +{ + struct spi_controller *master; + struct intel_spi *ispi; + int ret; + + master = devm_spi_alloc_master(dev, sizeof(*ispi)); + if (!master) + return -ENOMEM; + + master->mem_ops = &intel_spi_mem_ops; + + ispi = spi_master_get_devdata(master); + + ispi->base = devm_ioremap_resource(dev, mem); + if (IS_ERR(ispi->base)) + return PTR_ERR(ispi->base); + + ispi->dev = dev; + ispi->master = master; + ispi->info = info; + + ret = intel_spi_init(ispi); + if (ret) + return ret; + + ret = devm_spi_register_master(dev, master); + if (ret) + return ret; + + return intel_spi_populate_chip(ispi); +} +EXPORT_SYMBOL_GPL(intel_spi_probe); + +MODULE_DESCRIPTION("Intel PCH/PCU SPI flash core driver"); +MODULE_AUTHOR("Mika Westerberg "); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/spi/spi-intel.h b/drivers/spi/spi-intel.h new file mode 100644 index 000000000000..a4f0327a46ff --- /dev/null +++ b/drivers/spi/spi-intel.h @@ -0,0 +1,19 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Intel PCH/PCU SPI flash driver. + * + * Copyright (C) 2016 - 2022, Intel Corporation + * Author: Mika Westerberg + */ + +#ifndef SPI_INTEL_H +#define SPI_INTEL_H + +#include + +struct resource; + +int intel_spi_probe(struct device *dev, struct resource *mem, + const struct intel_spi_boardinfo *info); + +#endif /* SPI_INTEL_H */ diff --git a/include/linux/mfd/lpc_ich.h b/include/linux/mfd/lpc_ich.h index 39967a5eca6d..ea4a4b1b246a 100644 --- a/include/linux/mfd/lpc_ich.h +++ b/include/linux/mfd/lpc_ich.h @@ -8,7 +8,7 @@ #ifndef LPC_ICH_H #define LPC_ICH_H -#include +#include /* GPIO resources */ #define ICH_RES_GPIO 0 diff --git a/include/linux/platform_data/x86/intel-spi.h b/include/linux/platform_data/x86/intel-spi.h deleted file mode 100644 index 7dda3f690465..000000000000 --- a/include/linux/platform_data/x86/intel-spi.h +++ /dev/null @@ -1,31 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * Intel PCH/PCU SPI flash driver. - * - * Copyright (C) 2016, Intel Corporation - * Author: Mika Westerberg - */ - -#ifndef INTEL_SPI_PDATA_H -#define INTEL_SPI_PDATA_H - -enum intel_spi_type { - INTEL_SPI_BYT = 1, - INTEL_SPI_LPT, - INTEL_SPI_BXT, - INTEL_SPI_CNL, -}; - -/** - * struct intel_spi_boardinfo - Board specific data for Intel SPI driver - * @type: Type which this controller is compatible with - * @set_writeable: Try to make the chip writeable (optional) - * @data: Data to be passed to @set_writeable can be %NULL - */ -struct intel_spi_boardinfo { - enum intel_spi_type type; - bool (*set_writeable)(void __iomem *base, void *data); - void *data; -}; - -#endif /* INTEL_SPI_PDATA_H */ diff --git a/include/linux/platform_data/x86/spi-intel.h b/include/linux/platform_data/x86/spi-intel.h new file mode 100644 index 000000000000..a512ec37abbb --- /dev/null +++ b/include/linux/platform_data/x86/spi-intel.h @@ -0,0 +1,31 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Intel PCH/PCU SPI flash driver. + * + * Copyright (C) 2016, Intel Corporation + * Author: Mika Westerberg + */ + +#ifndef SPI_INTEL_PDATA_H +#define SPI_INTEL_PDATA_H + +enum intel_spi_type { + INTEL_SPI_BYT = 1, + INTEL_SPI_LPT, + INTEL_SPI_BXT, + INTEL_SPI_CNL, +}; + +/** + * struct intel_spi_boardinfo - Board specific data for Intel SPI driver + * @type: Type which this controller is compatible with + * @set_writeable: Try to make the chip writeable (optional) + * @data: Data to be passed to @set_writeable can be %NULL + */ +struct intel_spi_boardinfo { + enum intel_spi_type type; + bool (*set_writeable)(void __iomem *base, void *data); + void *data; +}; + +#endif /* SPI_INTEL_PDATA_H */ -- cgit v1.2.3 From 4ab13489735d9b5b6e91634eab83922914a3310c Mon Sep 17 00:00:00 2001 From: Mika Westerberg Date: Wed, 9 Feb 2022 15:27:06 +0300 Subject: Documentation / MTD: Rename the intel-spi driver Since the driver is renamed (and moved) update the BIOS upgrade guide accordingly from intel-spi to spi-intel. Keep the guide under MTD documentation because this is pretty much still about MTD and SPI-NOR. Signed-off-by: Mika Westerberg Reviewed-by: Andy Shevchenko Reviewed-by: Mauro Lima Reviewed-by: Tudor Ambarus Link: https://lore.kernel.org/r/20220209122706.42439-4-mika.westerberg@linux.intel.com Signed-off-by: Mark Brown --- Documentation/driver-api/mtd/index.rst | 2 +- Documentation/driver-api/mtd/intel-spi.rst | 90 ------------------------------ Documentation/driver-api/mtd/spi-intel.rst | 90 ++++++++++++++++++++++++++++++ 3 files changed, 91 insertions(+), 91 deletions(-) delete mode 100644 Documentation/driver-api/mtd/intel-spi.rst create mode 100644 Documentation/driver-api/mtd/spi-intel.rst diff --git a/Documentation/driver-api/mtd/index.rst b/Documentation/driver-api/mtd/index.rst index 436ba5a851d7..6a4278f409d7 100644 --- a/Documentation/driver-api/mtd/index.rst +++ b/Documentation/driver-api/mtd/index.rst @@ -7,6 +7,6 @@ Memory Technology Device (MTD) .. toctree:: :maxdepth: 1 - intel-spi + spi-intel nand_ecc spi-nor diff --git a/Documentation/driver-api/mtd/intel-spi.rst b/Documentation/driver-api/mtd/intel-spi.rst deleted file mode 100644 index 0465f6879262..000000000000 --- a/Documentation/driver-api/mtd/intel-spi.rst +++ /dev/null @@ -1,90 +0,0 @@ -============================== -Upgrading BIOS using intel-spi -============================== - -Many Intel CPUs like Baytrail and Braswell include SPI serial flash host -controller which is used to hold BIOS and other platform specific data. -Since contents of the SPI serial flash is crucial for machine to function, -it is typically protected by different hardware protection mechanisms to -avoid accidental (or on purpose) overwrite of the content. - -Not all manufacturers protect the SPI serial flash, mainly because it -allows upgrading the BIOS image directly from an OS. - -The intel-spi driver makes it possible to read and write the SPI serial -flash, if certain protection bits are not set and locked. If it finds -any of them set, the whole MTD device is made read-only to prevent -partial overwrites. By default the driver exposes SPI serial flash -contents as read-only but it can be changed from kernel command line, -passing "intel-spi.writeable=1". - -Please keep in mind that overwriting the BIOS image on SPI serial flash -might render the machine unbootable and requires special equipment like -Dediprog to revive. You have been warned! - -Below are the steps how to upgrade MinnowBoard MAX BIOS directly from -Linux. - - 1) Download and extract the latest Minnowboard MAX BIOS SPI image - [1]. At the time writing this the latest image is v92. - - 2) Install mtd-utils package [2]. We need this in order to erase the SPI - serial flash. Distros like Debian and Fedora have this prepackaged with - name "mtd-utils". - - 3) Add "intel-spi.writeable=1" to the kernel command line and reboot - the board (you can also reload the driver passing "writeable=1" as - module parameter to modprobe). - - 4) Once the board is up and running again, find the right MTD partition - (it is named as "BIOS"):: - - # cat /proc/mtd - dev: size erasesize name - mtd0: 00800000 00001000 "BIOS" - - So here it will be /dev/mtd0 but it may vary. - - 5) Make backup of the existing image first:: - - # dd if=/dev/mtd0ro of=bios.bak - 16384+0 records in - 16384+0 records out - 8388608 bytes (8.4 MB) copied, 10.0269 s, 837 kB/s - - 6) Verify the backup:: - - # sha1sum /dev/mtd0ro bios.bak - fdbb011920572ca6c991377c4b418a0502668b73 /dev/mtd0ro - fdbb011920572ca6c991377c4b418a0502668b73 bios.bak - - The SHA1 sums must match. Otherwise do not continue any further! - - 7) Erase the SPI serial flash. After this step, do not reboot the - board! Otherwise it will not start anymore:: - - # flash_erase /dev/mtd0 0 0 - Erasing 4 Kibyte @ 7ff000 -- 100 % complete - - 8) Once completed without errors you can write the new BIOS image:: - - # dd if=MNW2MAX1.X64.0092.R01.1605221712.bin of=/dev/mtd0 - - 9) Verify that the new content of the SPI serial flash matches the new - BIOS image:: - - # sha1sum /dev/mtd0ro MNW2MAX1.X64.0092.R01.1605221712.bin - 9b4df9e4be2057fceec3a5529ec3d950836c87a2 /dev/mtd0ro - 9b4df9e4be2057fceec3a5529ec3d950836c87a2 MNW2MAX1.X64.0092.R01.1605221712.bin - - The SHA1 sums should match. - - 10) Now you can reboot your board and observe the new BIOS starting up - properly. - -References ----------- - -[1] https://firmware.intel.com/sites/default/files/MinnowBoard%2EMAX_%2EX64%2E92%2ER01%2Ezip - -[2] http://www.linux-mtd.infradead.org/ diff --git a/Documentation/driver-api/mtd/spi-intel.rst b/Documentation/driver-api/mtd/spi-intel.rst new file mode 100644 index 000000000000..df854f20ead1 --- /dev/null +++ b/Documentation/driver-api/mtd/spi-intel.rst @@ -0,0 +1,90 @@ +============================== +Upgrading BIOS using spi-intel +============================== + +Many Intel CPUs like Baytrail and Braswell include SPI serial flash host +controller which is used to hold BIOS and other platform specific data. +Since contents of the SPI serial flash is crucial for machine to function, +it is typically protected by different hardware protection mechanisms to +avoid accidental (or on purpose) overwrite of the content. + +Not all manufacturers protect the SPI serial flash, mainly because it +allows upgrading the BIOS image directly from an OS. + +The spi-intel driver makes it possible to read and write the SPI serial +flash, if certain protection bits are not set and locked. If it finds +any of them set, the whole MTD device is made read-only to prevent +partial overwrites. By default the driver exposes SPI serial flash +contents as read-only but it can be changed from kernel command line, +passing "spi_intel.writeable=1". + +Please keep in mind that overwriting the BIOS image on SPI serial flash +might render the machine unbootable and requires special equipment like +Dediprog to revive. You have been warned! + +Below are the steps how to upgrade MinnowBoard MAX BIOS directly from +Linux. + + 1) Download and extract the latest Minnowboard MAX BIOS SPI image + [1]. At the time writing this the latest image is v92. + + 2) Install mtd-utils package [2]. We need this in order to erase the SPI + serial flash. Distros like Debian and Fedora have this prepackaged with + name "mtd-utils". + + 3) Add "spi_intel.writeable=1" to the kernel command line and reboot + the board (you can also reload the driver passing "writeable=1" as + module parameter to modprobe). + + 4) Once the board is up and running again, find the right MTD partition + (it is named as "BIOS"):: + + # cat /proc/mtd + dev: size erasesize name + mtd0: 00800000 00001000 "BIOS" + + So here it will be /dev/mtd0 but it may vary. + + 5) Make backup of the existing image first:: + + # dd if=/dev/mtd0ro of=bios.bak + 16384+0 records in + 16384+0 records out + 8388608 bytes (8.4 MB) copied, 10.0269 s, 837 kB/s + + 6) Verify the backup:: + + # sha1sum /dev/mtd0ro bios.bak + fdbb011920572ca6c991377c4b418a0502668b73 /dev/mtd0ro + fdbb011920572ca6c991377c4b418a0502668b73 bios.bak + + The SHA1 sums must match. Otherwise do not continue any further! + + 7) Erase the SPI serial flash. After this step, do not reboot the + board! Otherwise it will not start anymore:: + + # flash_erase /dev/mtd0 0 0 + Erasing 4 Kibyte @ 7ff000 -- 100 % complete + + 8) Once completed without errors you can write the new BIOS image:: + + # dd if=MNW2MAX1.X64.0092.R01.1605221712.bin of=/dev/mtd0 + + 9) Verify that the new content of the SPI serial flash matches the new + BIOS image:: + + # sha1sum /dev/mtd0ro MNW2MAX1.X64.0092.R01.1605221712.bin + 9b4df9e4be2057fceec3a5529ec3d950836c87a2 /dev/mtd0ro + 9b4df9e4be2057fceec3a5529ec3d950836c87a2 MNW2MAX1.X64.0092.R01.1605221712.bin + + The SHA1 sums should match. + + 10) Now you can reboot your board and observe the new BIOS starting up + properly. + +References +---------- + +[1] https://firmware.intel.com/sites/default/files/MinnowBoard%2EMAX_%2EX64%2E92%2ER01%2Ezip + +[2] http://www.linux-mtd.infradead.org/ -- cgit v1.2.3 From 5790597d7113faabb1714d3d1efa268e36eb4811 Mon Sep 17 00:00:00 2001 From: Li-hao Kuo Date: Mon, 14 Feb 2022 10:20:11 +0800 Subject: spi: Fix warning for Clang build and simplify code Clang build fails with spi-sunplus-sp7021.c:405:2: error: variable 'ret' is used uninitialized whenever switch default is taken default: simplify code Restore initializing ret. and add return error at default Fixes: 47e8fe57a66f ("spi: Modify irq request position and modify parameters") Reported-by: Tom Rix Reported-by: kernel test robot Reported-by: Nathan Chancellor Reported-by: Mark Brown Signed-off-by: Li-hao Kuo Link: https://lore.kernel.org/r/7d91e6ce29f9a8df2c53a47b4b977664020e237a.1644805060.git.lhjeff911@gmail.com Signed-off-by: Mark Brown --- drivers/spi/spi-sunplus-sp7021.c | 38 +++++++++----------------------------- 1 file changed, 9 insertions(+), 29 deletions(-) diff --git a/drivers/spi/spi-sunplus-sp7021.c b/drivers/spi/spi-sunplus-sp7021.c index ba5ed9f7277a..ade7a0fca8cb 100644 --- a/drivers/spi/spi-sunplus-sp7021.c +++ b/drivers/spi/spi-sunplus-sp7021.c @@ -69,12 +69,6 @@ #define SP7021_SPI_DATA_SIZE (255) #define SP7021_FIFO_DATA_LEN (16) -enum SP_SPI_MODE { - SP7021_SLAVE_READ = 0, - SP7021_SLAVE_WRITE = 1, - SP7021_SPI_IDLE = 2, -}; - enum { SP7021_MASTER_MODE = 0, SP7021_SLAVE_MODE = 1, @@ -375,40 +369,26 @@ static int sp7021_spi_slave_transfer_one(struct spi_controller *ctlr, struct spi { struct sp7021_spi_ctlr *pspim = spi_master_get_devdata(ctlr); struct device *dev = pspim->dev; - int mode, ret; + int ret; - mode = SP7021_SPI_IDLE; - if (xfer->tx_buf && xfer->rx_buf) { - dev_dbg(&ctlr->dev, "%s() wrong command\n", __func__); - return -EINVAL; - } else if (xfer->tx_buf) { + if (xfer->tx_buf && !xfer->rx_buf) { xfer->tx_dma = dma_map_single(dev, (void *)xfer->tx_buf, xfer->len, DMA_TO_DEVICE); if (dma_mapping_error(dev, xfer->tx_dma)) return -ENOMEM; - mode = SP7021_SLAVE_WRITE; - } else if (xfer->rx_buf) { + ret = sp7021_spi_slave_tx(spi, xfer); + dma_unmap_single(dev, xfer->tx_dma, xfer->len, DMA_TO_DEVICE); + } else if (xfer->rx_buf && !xfer->tx_buf) { xfer->rx_dma = dma_map_single(dev, xfer->rx_buf, xfer->len, DMA_FROM_DEVICE); if (dma_mapping_error(dev, xfer->rx_dma)) return -ENOMEM; - mode = SP7021_SLAVE_READ; - } - - switch (mode) { - case SP7021_SLAVE_WRITE: - ret = sp7021_spi_slave_tx(spi, xfer); - break; - case SP7021_SLAVE_READ: ret = sp7021_spi_slave_rx(spi, xfer); - break; - default: - break; - } - if (xfer->tx_buf) - dma_unmap_single(dev, xfer->tx_dma, xfer->len, DMA_TO_DEVICE); - if (xfer->rx_buf) dma_unmap_single(dev, xfer->rx_dma, xfer->len, DMA_FROM_DEVICE); + } else { + dev_dbg(&ctlr->dev, "%s() wrong command\n", __func__); + return -EINVAL; + } spi_finalize_current_transfer(ctlr); return ret; -- cgit v1.2.3 From f48dc6b9664963107e500aecfc2f4df27dc5afb6 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Fri, 11 Feb 2022 00:19:54 +0100 Subject: spi: Retire legacy GPIO handling All drivers using GPIOs as chip select have been rewritten to use GPIO descriptors passing the ->use_gpio_descriptors flag. Retire the code and fields used by the legacy GPIO API. Do not drop the ->use_gpio_descriptors flag: it now only indicates that we want to use GPIOs in addition to native chip selects. Signed-off-by: Linus Walleij Link: https://lore.kernel.org/r/20220210231954.807904-1-linus.walleij@linaro.org Signed-off-by: Mark Brown --- drivers/spi/spi.c | 125 +++++++++++------------------------------------- include/linux/spi/spi.h | 14 +----- 2 files changed, 30 insertions(+), 109 deletions(-) diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index d9832d8e9f44..85f8ae4cc0c0 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -18,7 +18,6 @@ #include #include #include -#include #include #include #include @@ -542,7 +541,6 @@ struct spi_device *spi_alloc_device(struct spi_controller *ctlr) spi->dev.parent = &ctlr->dev; spi->dev.bus = &spi_bus_type; spi->dev.release = spidev_release; - spi->cs_gpio = -ENOENT; spi->mode = ctlr->buswidth_override_bits; spin_lock_init(&spi->statistics.lock); @@ -606,11 +604,8 @@ static int __spi_add_device(struct spi_device *spi) return -ENODEV; } - /* Descriptors take precedence */ if (ctlr->cs_gpiods) spi->cs_gpiod = ctlr->cs_gpiods[spi->chip_select]; - else if (ctlr->cs_gpios) - spi->cs_gpio = ctlr->cs_gpios[spi->chip_select]; /* * Drivers may modify this initial i/o setup, but will @@ -940,39 +935,30 @@ static void spi_set_cs(struct spi_device *spi, bool enable, bool force) spi->controller->last_cs_enable = enable; spi->controller->last_cs_mode_high = spi->mode & SPI_CS_HIGH; - if ((spi->cs_gpiod || gpio_is_valid(spi->cs_gpio) || - !spi->controller->set_cs_timing) && !activate) { + if ((spi->cs_gpiod || !spi->controller->set_cs_timing) && !activate) { spi_delay_exec(&spi->cs_hold, NULL); } if (spi->mode & SPI_CS_HIGH) enable = !enable; - if (spi->cs_gpiod || gpio_is_valid(spi->cs_gpio)) { + if (spi->cs_gpiod) { if (!(spi->mode & SPI_NO_CS)) { - if (spi->cs_gpiod) { - /* - * Historically ACPI has no means of the GPIO polarity and - * thus the SPISerialBus() resource defines it on the per-chip - * basis. In order to avoid a chain of negations, the GPIO - * polarity is considered being Active High. Even for the cases - * when _DSD() is involved (in the updated versions of ACPI) - * the GPIO CS polarity must be defined Active High to avoid - * ambiguity. That's why we use enable, that takes SPI_CS_HIGH - * into account. - */ - if (has_acpi_companion(&spi->dev)) - gpiod_set_value_cansleep(spi->cs_gpiod, !enable); - else - /* Polarity handled by GPIO library */ - gpiod_set_value_cansleep(spi->cs_gpiod, activate); - } else { - /* - * Invert the enable line, as active low is - * default for SPI. - */ - gpio_set_value_cansleep(spi->cs_gpio, !enable); - } + /* + * Historically ACPI has no means of the GPIO polarity and + * thus the SPISerialBus() resource defines it on the per-chip + * basis. In order to avoid a chain of negations, the GPIO + * polarity is considered being Active High. Even for the cases + * when _DSD() is involved (in the updated versions of ACPI) + * the GPIO CS polarity must be defined Active High to avoid + * ambiguity. That's why we use enable, that takes SPI_CS_HIGH + * into account. + */ + if (has_acpi_companion(&spi->dev)) + gpiod_set_value_cansleep(spi->cs_gpiod, !enable); + else + /* Polarity handled by GPIO library */ + gpiod_set_value_cansleep(spi->cs_gpiod, activate); } /* Some SPI masters need both GPIO CS & slave_select */ if ((spi->controller->flags & SPI_MASTER_GPIO_SS) && @@ -982,8 +968,7 @@ static void spi_set_cs(struct spi_device *spi, bool enable, bool force) spi->controller->set_cs(spi, !enable); } - if (spi->cs_gpiod || gpio_is_valid(spi->cs_gpio) || - !spi->controller->set_cs_timing) { + if (spi->cs_gpiod || !spi->controller->set_cs_timing) { if (activate) spi_delay_exec(&spi->cs_setup, NULL); else @@ -2827,46 +2812,6 @@ struct spi_controller *__devm_spi_alloc_controller(struct device *dev, } EXPORT_SYMBOL_GPL(__devm_spi_alloc_controller); -#ifdef CONFIG_OF -static int of_spi_get_gpio_numbers(struct spi_controller *ctlr) -{ - int nb, i, *cs; - struct device_node *np = ctlr->dev.of_node; - - if (!np) - return 0; - - nb = of_gpio_named_count(np, "cs-gpios"); - ctlr->num_chipselect = max_t(int, nb, ctlr->num_chipselect); - - /* Return error only for an incorrectly formed cs-gpios property */ - if (nb == 0 || nb == -ENOENT) - return 0; - else if (nb < 0) - return nb; - - cs = devm_kcalloc(&ctlr->dev, ctlr->num_chipselect, sizeof(int), - GFP_KERNEL); - ctlr->cs_gpios = cs; - - if (!ctlr->cs_gpios) - return -ENOMEM; - - for (i = 0; i < ctlr->num_chipselect; i++) - cs[i] = -ENOENT; - - for (i = 0; i < nb; i++) - cs[i] = of_get_named_gpio(np, "cs-gpios", i); - - return 0; -} -#else -static int of_spi_get_gpio_numbers(struct spi_controller *ctlr) -{ - return 0; -} -#endif - /** * spi_get_gpio_descs() - grab chip select GPIOs for the master * @ctlr: The SPI master to grab GPIO descriptors for @@ -3051,22 +2996,15 @@ int spi_register_controller(struct spi_controller *ctlr) */ dev_set_name(&ctlr->dev, "spi%u", ctlr->bus_num); - if (!spi_controller_is_slave(ctlr)) { - if (ctlr->use_gpio_descriptors) { - status = spi_get_gpio_descs(ctlr); - if (status) - goto free_bus_id; - /* - * A controller using GPIO descriptors always - * supports SPI_CS_HIGH if need be. - */ - ctlr->mode_bits |= SPI_CS_HIGH; - } else { - /* Legacy code path for GPIOs from DT */ - status = of_spi_get_gpio_numbers(ctlr); - if (status) - goto free_bus_id; - } + if (!spi_controller_is_slave(ctlr) && ctlr->use_gpio_descriptors) { + status = spi_get_gpio_descs(ctlr); + if (status) + goto free_bus_id; + /* + * A controller using GPIO descriptors always + * supports SPI_CS_HIGH if need be. + */ + ctlr->mode_bits |= SPI_CS_HIGH; } /* @@ -3555,12 +3493,6 @@ int spi_setup(struct spi_device *spi) */ bad_bits = spi->mode & ~(spi->controller->mode_bits | SPI_CS_WORD | SPI_NO_TX | SPI_NO_RX); - /* - * Nothing prevents from working with active-high CS in case if it - * is driven by GPIO. - */ - if (gpio_is_valid(spi->cs_gpio)) - bad_bits &= ~SPI_CS_HIGH; ugly_bits = bad_bits & (SPI_TX_DUAL | SPI_TX_QUAD | SPI_TX_OCTAL | SPI_RX_DUAL | SPI_RX_QUAD | SPI_RX_OCTAL); @@ -3686,8 +3618,7 @@ static int __spi_validate(struct spi_device *spi, struct spi_message *message) * cs_change is set for each transfer. */ if ((spi->mode & SPI_CS_WORD) && (!(ctlr->mode_bits & SPI_CS_WORD) || - spi->cs_gpiod || - gpio_is_valid(spi->cs_gpio))) { + spi->cs_gpiod)) { size_t maxsize; int ret; diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h index c3746ff35691..579d71cdf6fa 100644 --- a/include/linux/spi/spi.h +++ b/include/linux/spi/spi.h @@ -137,9 +137,6 @@ extern int spi_delay_exec(struct spi_delay *_delay, struct spi_transfer *xfer); * for driver coldplugging, and in uevents used for hotplugging * @driver_override: If the name of a driver is written to this attribute, then * the device will bind to the named driver and only the named driver. - * @cs_gpio: LEGACY: gpio number of the chipselect line (optional, -ENOENT when - * not using a GPIO line) use cs_gpiod in new drivers by opting in on - * the spi_master. * @cs_gpiod: gpio descriptor of the chipselect line (optional, NULL when * not using a GPIO line) * @word_delay: delay to be inserted between consecutive @@ -186,7 +183,6 @@ struct spi_device { void *controller_data; char modalias[SPI_NAME_SIZE]; const char *driver_override; - int cs_gpio; /* LEGACY: chip select gpio */ struct gpio_desc *cs_gpiod; /* chip select gpio desc */ struct spi_delay word_delay; /* inter-word delay */ /* CS delays */ @@ -418,17 +414,12 @@ extern struct spi_device *spi_new_ancillary_device(struct spi_device *spi, u8 ch * controller has native support for memory like operations. * @unprepare_message: undo any work done by prepare_message(). * @slave_abort: abort the ongoing transfer request on an SPI slave controller - * @cs_gpios: LEGACY: array of GPIO descs to use as chip select lines; one per - * CS number. Any individual value may be -ENOENT for CS lines that - * are not GPIOs (driven by the SPI controller itself). Use the cs_gpiods - * in new drivers. * @cs_gpiods: Array of GPIO descs to use as chip select lines; one per CS * number. Any individual value may be NULL for CS lines that * are not GPIOs (driven by the SPI controller itself). * @use_gpio_descriptors: Turns on the code in the SPI core to parse and grab - * GPIO descriptors rather than using global GPIO numbers grabbed by the - * driver. This will fill in @cs_gpiods and @cs_gpios should not be used, - * and SPI devices will have the cs_gpiod assigned rather than cs_gpio. + * GPIO descriptors. This will fill in @cs_gpiods and SPI devices will have + * the cs_gpiod assigned if a GPIO line is found for the chipselect. * @unused_native_cs: When cs_gpiods is used, spi_register_controller() will * fill in this field with the first unused native CS, to be used by SPI * controller drivers that need to drive a native CS when using GPIO CS. @@ -642,7 +633,6 @@ struct spi_controller { const struct spi_controller_mem_ops *mem_ops; /* gpio chip select */ - int *cs_gpios; struct gpio_desc **cs_gpiods; bool use_gpio_descriptors; s8 unused_native_cs; -- cgit v1.2.3 From 47b34f495b8b75475952f12c521c4c1fc2fa09b4 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 15 Feb 2022 15:51:39 +0200 Subject: spi: intel-pci: Add support for Intel Ice Lake-N SPI serial flash Intel Ice Lake-N has the same SPI serial flash controller as Ice Lake-LP. Add Ice Lake-N PCI ID to the driver list of supported devices. The device can be found on MacBookPro16,2 [1]. [1]: https://linux-hardware.org/?probe=f1c5cf0c43 Signed-off-by: Andy Shevchenko Acked-by: Mika Westerberg Link: https://lore.kernel.org/r/20220215135139.4328-1-andriy.shevchenko@linux.intel.com Signed-off-by: Mark Brown --- drivers/spi/spi-intel-pci.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/spi/spi-intel-pci.c b/drivers/spi/spi-intel-pci.c index a9cb4d77ffe3..a5ef7a526a7f 100644 --- a/drivers/spi/spi-intel-pci.c +++ b/drivers/spi/spi-intel-pci.c @@ -66,6 +66,7 @@ static const struct pci_device_id intel_spi_pci_ids[] = { { PCI_VDEVICE(INTEL, 0x19e0), (unsigned long)&bxt_info }, { PCI_VDEVICE(INTEL, 0x1bca), (unsigned long)&bxt_info }, { PCI_VDEVICE(INTEL, 0x34a4), (unsigned long)&bxt_info }, + { PCI_VDEVICE(INTEL, 0x38a4), (unsigned long)&bxt_info }, { PCI_VDEVICE(INTEL, 0x43a4), (unsigned long)&cnl_info }, { PCI_VDEVICE(INTEL, 0x4b24), (unsigned long)&bxt_info }, { PCI_VDEVICE(INTEL, 0x4da4), (unsigned long)&bxt_info }, -- cgit v1.2.3 From 2b993ab79b5dc83eb699e747bfac6c04f4f5fc70 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Almeida?= Date: Wed, 16 Feb 2022 13:27:19 -0300 Subject: spi: amd: Fix building without ACPI enabled MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit 209043554915 ("spi: amd: Add support for version AMDI0062") removed the cast ACPI_PTR() for no good reason. This wrapper is important to make sure that the driver can be compiled with or without CONFIG_ACPI enabled, useful for compiling test. Give back the cast so compilation works again. Fixes: 209043554915 ("spi: amd: Add support for version AMDI0062") Signed-off-by: André Almeida Link: https://lore.kernel.org/r/20220216162719.116062-1-andrealmeid@collabora.com Signed-off-by: Mark Brown --- drivers/spi/spi-amd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/spi/spi-amd.c b/drivers/spi/spi-amd.c index d909afac6e21..cba6a4486c24 100644 --- a/drivers/spi/spi-amd.c +++ b/drivers/spi/spi-amd.c @@ -330,7 +330,7 @@ MODULE_DEVICE_TABLE(acpi, spi_acpi_match); static struct platform_driver amd_spi_driver = { .driver = { .name = "amd_spi", - .acpi_match_table = spi_acpi_match, + .acpi_match_table = ACPI_PTR(spi_acpi_match), }, .probe = amd_spi_probe, }; -- cgit v1.2.3 From 54d0fd06e2bd52d3b17648de787157a7c0625adb Mon Sep 17 00:00:00 2001 From: Jarkko Nikula Date: Wed, 16 Feb 2022 11:13:17 +0200 Subject: spi: pxa2xx: Add support for Intel Raptor Lake PCH-S Add support for LPSS SPI on Intel Raptor Lake PCH-S. It has four controllers each having two chip selects. Signed-off-by: Jarkko Nikula Link: https://lore.kernel.org/r/20220216091317.1302254-1-jarkko.nikula@linux.intel.com Signed-off-by: Mark Brown --- drivers/spi/spi-pxa2xx.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/spi/spi-pxa2xx.c b/drivers/spi/spi-pxa2xx.c index abb9f0ffd377..edb42d08857d 100644 --- a/drivers/spi/spi-pxa2xx.c +++ b/drivers/spi/spi-pxa2xx.c @@ -1394,6 +1394,11 @@ static const struct pci_device_id pxa2xx_spi_pci_compound_match[] = { { PCI_VDEVICE(INTEL, 0x5ac2), LPSS_BXT_SSP }, { PCI_VDEVICE(INTEL, 0x5ac4), LPSS_BXT_SSP }, { PCI_VDEVICE(INTEL, 0x5ac6), LPSS_BXT_SSP }, + /* RPL-S */ + { PCI_VDEVICE(INTEL, 0x7a2a), LPSS_CNL_SSP }, + { PCI_VDEVICE(INTEL, 0x7a2b), LPSS_CNL_SSP }, + { PCI_VDEVICE(INTEL, 0x7a79), LPSS_CNL_SSP }, + { PCI_VDEVICE(INTEL, 0x7a7b), LPSS_CNL_SSP }, /* ADL-S */ { PCI_VDEVICE(INTEL, 0x7aaa), LPSS_CNL_SSP }, { PCI_VDEVICE(INTEL, 0x7aab), LPSS_CNL_SSP }, -- cgit v1.2.3 From 869f2c94db92f0f1d6acd0dff1c1ebb8160f5e29 Mon Sep 17 00:00:00 2001 From: Jon Lin Date: Wed, 16 Feb 2022 09:40:25 +0800 Subject: spi: rockchip: Stop spi slave dma receiver when cs inactive The spi which's version is higher than ver 2 will automatically enable this feature. If the length of master transmission is uncertain, the RK spi slave is better to automatically stop after cs inactive instead of waiting for xfer_completion forever. Signed-off-by: Jon Lin Link: https://lore.kernel.org/r/20220216014028.8123-4-jon.lin@rock-chips.com Signed-off-by: Mark Brown --- drivers/spi/spi-rockchip.c | 81 +++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 73 insertions(+), 8 deletions(-) diff --git a/drivers/spi/spi-rockchip.c b/drivers/spi/spi-rockchip.c index c6a1bb09be05..5ecd0692cca1 100644 --- a/drivers/spi/spi-rockchip.c +++ b/drivers/spi/spi-rockchip.c @@ -133,7 +133,8 @@ #define INT_TF_OVERFLOW (1 << 1) #define INT_RF_UNDERFLOW (1 << 2) #define INT_RF_OVERFLOW (1 << 3) -#define INT_RF_FULL (1 << 4) +#define INT_RF_FULL (1 << 4) +#define INT_CS_INACTIVE (1 << 6) /* Bit fields in ICR, 4bit */ #define ICR_MASK 0x0f @@ -194,6 +195,8 @@ struct rockchip_spi { bool cs_asserted[ROCKCHIP_SPI_MAX_CS_NUM]; bool slave_abort; + bool cs_inactive; /* spi slave tansmition stop when cs inactive */ + struct spi_transfer *xfer; /* Store xfer temporarily */ }; static inline void spi_enable_chip(struct rockchip_spi *rs, bool enable) @@ -343,6 +346,15 @@ static irqreturn_t rockchip_spi_isr(int irq, void *dev_id) struct spi_controller *ctlr = dev_id; struct rockchip_spi *rs = spi_controller_get_devdata(ctlr); + /* When int_cs_inactive comes, spi slave abort */ + if (rs->cs_inactive && readl_relaxed(rs->regs + ROCKCHIP_SPI_IMR) & INT_CS_INACTIVE) { + ctlr->slave_abort(ctlr); + writel_relaxed(0, rs->regs + ROCKCHIP_SPI_IMR); + writel_relaxed(0xffffffff, rs->regs + ROCKCHIP_SPI_ICR); + + return IRQ_HANDLED; + } + if (rs->tx_left) rockchip_spi_pio_writer(rs); @@ -350,6 +362,7 @@ static irqreturn_t rockchip_spi_isr(int irq, void *dev_id) if (!rs->rx_left) { spi_enable_chip(rs, false); writel_relaxed(0, rs->regs + ROCKCHIP_SPI_IMR); + writel_relaxed(0xffffffff, rs->regs + ROCKCHIP_SPI_ICR); spi_finalize_current_transfer(ctlr); } @@ -357,14 +370,18 @@ static irqreturn_t rockchip_spi_isr(int irq, void *dev_id) } static int rockchip_spi_prepare_irq(struct rockchip_spi *rs, - struct spi_transfer *xfer) + struct spi_controller *ctlr, + struct spi_transfer *xfer) { rs->tx = xfer->tx_buf; rs->rx = xfer->rx_buf; rs->tx_left = rs->tx ? xfer->len / rs->n_bytes : 0; rs->rx_left = xfer->len / rs->n_bytes; - writel_relaxed(INT_RF_FULL, rs->regs + ROCKCHIP_SPI_IMR); + if (rs->cs_inactive) + writel_relaxed(INT_RF_FULL | INT_CS_INACTIVE, rs->regs + ROCKCHIP_SPI_IMR); + else + writel_relaxed(INT_RF_FULL, rs->regs + ROCKCHIP_SPI_IMR); spi_enable_chip(rs, true); if (rs->tx_left) @@ -383,6 +400,9 @@ static void rockchip_spi_dma_rxcb(void *data) if (state & TXDMA && !rs->slave_abort) return; + if (rs->cs_inactive) + writel_relaxed(0, rs->regs + ROCKCHIP_SPI_IMR); + spi_enable_chip(rs, false); spi_finalize_current_transfer(ctlr); } @@ -423,14 +443,16 @@ static int rockchip_spi_prepare_dma(struct rockchip_spi *rs, atomic_set(&rs->state, 0); + rs->tx = xfer->tx_buf; + rs->rx = xfer->rx_buf; + rxdesc = NULL; if (xfer->rx_buf) { struct dma_slave_config rxconf = { .direction = DMA_DEV_TO_MEM, .src_addr = rs->dma_addr_rx, .src_addr_width = rs->n_bytes, - .src_maxburst = rockchip_spi_calc_burst_size(xfer->len / - rs->n_bytes), + .src_maxburst = rockchip_spi_calc_burst_size(xfer->len / rs->n_bytes), }; dmaengine_slave_config(ctlr->dma_rx, &rxconf); @@ -474,10 +496,13 @@ static int rockchip_spi_prepare_dma(struct rockchip_spi *rs, /* rx must be started before tx due to spi instinct */ if (rxdesc) { atomic_or(RXDMA, &rs->state); - dmaengine_submit(rxdesc); + ctlr->dma_rx->cookie = dmaengine_submit(rxdesc); dma_async_issue_pending(ctlr->dma_rx); } + if (rs->cs_inactive) + writel_relaxed(INT_CS_INACTIVE, rs->regs + ROCKCHIP_SPI_IMR); + spi_enable_chip(rs, true); if (txdesc) { @@ -584,7 +609,42 @@ static size_t rockchip_spi_max_transfer_size(struct spi_device *spi) static int rockchip_spi_slave_abort(struct spi_controller *ctlr) { struct rockchip_spi *rs = spi_controller_get_devdata(ctlr); + u32 rx_fifo_left; + struct dma_tx_state state; + enum dma_status status; + + /* Get current dma rx point */ + if (atomic_read(&rs->state) & RXDMA) { + dmaengine_pause(ctlr->dma_rx); + status = dmaengine_tx_status(ctlr->dma_rx, ctlr->dma_rx->cookie, &state); + if (status == DMA_ERROR) { + rs->rx = rs->xfer->rx_buf; + rs->xfer->len = 0; + rx_fifo_left = readl_relaxed(rs->regs + ROCKCHIP_SPI_RXFLR); + for (; rx_fifo_left; rx_fifo_left--) + readl_relaxed(rs->regs + ROCKCHIP_SPI_RXDR); + goto out; + } else { + rs->rx += rs->xfer->len - rs->n_bytes * state.residue; + } + } + /* Get the valid data left in rx fifo and set rs->xfer->len real rx size */ + if (rs->rx) { + rx_fifo_left = readl_relaxed(rs->regs + ROCKCHIP_SPI_RXFLR); + for (; rx_fifo_left; rx_fifo_left--) { + u32 rxw = readl_relaxed(rs->regs + ROCKCHIP_SPI_RXDR); + + if (rs->n_bytes == 1) + *(u8 *)rs->rx = (u8)rxw; + else + *(u16 *)rs->rx = (u16)rxw; + rs->rx += rs->n_bytes; + } + rs->xfer->len = (unsigned int)(rs->rx - rs->xfer->rx_buf); + } + +out: if (atomic_read(&rs->state) & RXDMA) dmaengine_terminate_sync(ctlr->dma_rx); if (atomic_read(&rs->state) & TXDMA) @@ -626,7 +686,7 @@ static int rockchip_spi_transfer_one( } rs->n_bytes = xfer->bits_per_word <= 8 ? 1 : 2; - + rs->xfer = xfer; use_dma = ctlr->can_dma ? ctlr->can_dma(ctlr, spi, xfer) : false; ret = rockchip_spi_config(rs, spi, xfer, use_dma, ctlr->slave); @@ -636,7 +696,7 @@ static int rockchip_spi_transfer_one( if (use_dma) return rockchip_spi_prepare_dma(rs, ctlr, xfer); - return rockchip_spi_prepare_irq(rs, xfer); + return rockchip_spi_prepare_irq(rs, ctlr, xfer); } static bool rockchip_spi_can_dma(struct spi_controller *ctlr, @@ -815,8 +875,13 @@ static int rockchip_spi_probe(struct platform_device *pdev) switch (readl_relaxed(rs->regs + ROCKCHIP_SPI_VERSION)) { case ROCKCHIP_SPI_VER2_TYPE2: ctlr->mode_bits |= SPI_CS_HIGH; + if (ctlr->can_dma && slave_mode) + rs->cs_inactive = true; + else + rs->cs_inactive = false; break; default: + rs->cs_inactive = false; break; } -- cgit v1.2.3 From 3a4bf922d42efa4e9a3dc803d1fd786d43e8a501 Mon Sep 17 00:00:00 2001 From: Jon Lin Date: Wed, 16 Feb 2022 09:40:26 +0800 Subject: spi: rockchip: Preset cs-high and clk polarity in setup progress After power up, the cs and clock is in default status, and the cs-high and clock polarity dts property configuration will take no effect until the calling of rockchip_spi_config in the first transmission. So preset them to make sure a correct voltage before the first transmission coming. Signed-off-by: Jon Lin Link: https://lore.kernel.org/r/20220216014028.8123-5-jon.lin@rock-chips.com Signed-off-by: Mark Brown --- drivers/spi/spi-rockchip.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/drivers/spi/spi-rockchip.c b/drivers/spi/spi-rockchip.c index 5ecd0692cca1..83da8fdb3c02 100644 --- a/drivers/spi/spi-rockchip.c +++ b/drivers/spi/spi-rockchip.c @@ -713,6 +713,29 @@ static bool rockchip_spi_can_dma(struct spi_controller *ctlr, return xfer->len / bytes_per_word >= rs->fifo_len; } +static int rockchip_spi_setup(struct spi_device *spi) +{ + struct rockchip_spi *rs = spi_controller_get_devdata(spi->controller); + u32 cr0; + + pm_runtime_get_sync(rs->dev); + + cr0 = readl_relaxed(rs->regs + ROCKCHIP_SPI_CTRLR0); + + cr0 &= ~(0x3 << CR0_SCPH_OFFSET); + cr0 |= ((spi->mode & 0x3) << CR0_SCPH_OFFSET); + if (spi->mode & SPI_CS_HIGH && spi->chip_select <= 1) + cr0 |= BIT(spi->chip_select) << CR0_SOI_OFFSET; + else if (spi->chip_select <= 1) + cr0 &= ~(BIT(spi->chip_select) << CR0_SOI_OFFSET); + + writel_relaxed(cr0, rs->regs + ROCKCHIP_SPI_CTRLR0); + + pm_runtime_put(rs->dev); + + return 0; +} + static int rockchip_spi_probe(struct platform_device *pdev) { int ret; @@ -840,6 +863,7 @@ static int rockchip_spi_probe(struct platform_device *pdev) ctlr->min_speed_hz = rs->freq / BAUDR_SCKDV_MAX; ctlr->max_speed_hz = min(rs->freq / BAUDR_SCKDV_MIN, MAX_SCLK_OUT); + ctlr->setup = rockchip_spi_setup; ctlr->set_cs = rockchip_spi_set_cs; ctlr->transfer_one = rockchip_spi_transfer_one; ctlr->max_transfer_size = rockchip_spi_max_transfer_size; -- cgit v1.2.3 From e882575efc771f130a24322377dc1033551da11d Mon Sep 17 00:00:00 2001 From: shengfei Xu Date: Wed, 16 Feb 2022 09:40:27 +0800 Subject: spi: rockchip: Suspend and resume the bus during NOIRQ_SYSTEM_SLEEP_PM ops the wakeup interrupt handler which is guaranteed not to run while @resume noirq() is being executed. the patch can help to avoid the wakeup source try to access spi when the spi is in suspend mode. Signed-off-by: shengfei Xu Signed-off-by: Jon Lin Link: https://lore.kernel.org/r/20220216014028.8123-6-jon.lin@rock-chips.com Signed-off-by: Mark Brown --- drivers/spi/spi-rockchip.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/drivers/spi/spi-rockchip.c b/drivers/spi/spi-rockchip.c index 83da8fdb3c02..8b4d56ee2193 100644 --- a/drivers/spi/spi-rockchip.c +++ b/drivers/spi/spi-rockchip.c @@ -964,14 +964,14 @@ static int rockchip_spi_suspend(struct device *dev) { int ret; struct spi_controller *ctlr = dev_get_drvdata(dev); + struct rockchip_spi *rs = spi_controller_get_devdata(ctlr); ret = spi_controller_suspend(ctlr); if (ret < 0) return ret; - ret = pm_runtime_force_suspend(dev); - if (ret < 0) - return ret; + clk_disable_unprepare(rs->spiclk); + clk_disable_unprepare(rs->apb_pclk); pinctrl_pm_select_sleep_state(dev); @@ -986,10 +986,14 @@ static int rockchip_spi_resume(struct device *dev) pinctrl_pm_select_default_state(dev); - ret = pm_runtime_force_resume(dev); + ret = clk_prepare_enable(rs->apb_pclk); if (ret < 0) return ret; + ret = clk_prepare_enable(rs->spiclk); + if (ret < 0) + clk_disable_unprepare(rs->apb_pclk); + ret = spi_controller_resume(ctlr); if (ret < 0) { clk_disable_unprepare(rs->spiclk); @@ -1031,7 +1035,7 @@ static int rockchip_spi_runtime_resume(struct device *dev) #endif /* CONFIG_PM */ static const struct dev_pm_ops rockchip_spi_pm = { - SET_SYSTEM_SLEEP_PM_OPS(rockchip_spi_suspend, rockchip_spi_resume) + SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(rockchip_spi_suspend, rockchip_spi_resume) SET_RUNTIME_PM_OPS(rockchip_spi_runtime_suspend, rockchip_spi_runtime_resume, NULL) }; -- cgit v1.2.3 From 2fcdde56c44fe1cd13ce328128f509bbda2cdb41 Mon Sep 17 00:00:00 2001 From: Jon Lin Date: Wed, 16 Feb 2022 09:40:28 +0800 Subject: spi: rockchip: clear interrupt status in error handler The interrupt status bit of the previous error data transmition will affect the next operation and cause continuous SPI transmission failure. Signed-off-by: Jon Lin Link: https://lore.kernel.org/r/20220216014028.8123-7-jon.lin@rock-chips.com Signed-off-by: Mark Brown --- drivers/spi/spi-rockchip.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/spi/spi-rockchip.c b/drivers/spi/spi-rockchip.c index 8b4d56ee2193..cdc16eecaf6b 100644 --- a/drivers/spi/spi-rockchip.c +++ b/drivers/spi/spi-rockchip.c @@ -278,8 +278,9 @@ static void rockchip_spi_handle_err(struct spi_controller *ctlr, */ spi_enable_chip(rs, false); - /* make sure all interrupts are masked */ + /* make sure all interrupts are masked and status cleared */ writel_relaxed(0, rs->regs + ROCKCHIP_SPI_IMR); + writel_relaxed(0xffffffff, rs->regs + ROCKCHIP_SPI_ICR); if (atomic_read(&rs->state) & TXDMA) dmaengine_terminate_async(ctlr->dma_tx); -- cgit v1.2.3 From 07025ceaac9f4f7a9e1a3285c3216469bf066320 Mon Sep 17 00:00:00 2001 From: Yang Li Date: Thu, 17 Feb 2022 09:00:24 +0800 Subject: spi: clean up some inconsistent indenting Eliminate the follow smatch warning: drivers/spi/spi-sunplus-sp7021.c:379 sp7021_spi_slave_transfer_one() warn: inconsistent indenting Reported-by: Abaci Robot Signed-off-by: Yang Li Link: https://lore.kernel.org/r/20220217010024.111904-1-yang.lee@linux.alibaba.com Signed-off-by: Mark Brown --- drivers/spi/spi-sunplus-sp7021.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/spi/spi-sunplus-sp7021.c b/drivers/spi/spi-sunplus-sp7021.c index ade7a0fca8cb..f989f7b99296 100644 --- a/drivers/spi/spi-sunplus-sp7021.c +++ b/drivers/spi/spi-sunplus-sp7021.c @@ -376,8 +376,8 @@ static int sp7021_spi_slave_transfer_one(struct spi_controller *ctlr, struct spi xfer->len, DMA_TO_DEVICE); if (dma_mapping_error(dev, xfer->tx_dma)) return -ENOMEM; - ret = sp7021_spi_slave_tx(spi, xfer); - dma_unmap_single(dev, xfer->tx_dma, xfer->len, DMA_TO_DEVICE); + ret = sp7021_spi_slave_tx(spi, xfer); + dma_unmap_single(dev, xfer->tx_dma, xfer->len, DMA_TO_DEVICE); } else if (xfer->rx_buf && !xfer->tx_buf) { xfer->rx_dma = dma_map_single(dev, xfer->rx_buf, xfer->len, DMA_FROM_DEVICE); -- cgit v1.2.3 From 043786303b175977e515d4e99cf6b5f886b136dc Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Fri, 18 Feb 2022 14:58:35 +0100 Subject: spi: use sysfs_emit() for printing statistics and add trailing newline Use dedicated function sysfs_emit() that does some extra checking, e.g. to ensure that no more than PAGESIZE bytes are written. In addition add a trailing newline to the output, that makes it better readable from the console. Signed-off-by: Heiner Kallweit Link: https://lore.kernel.org/r/56e1588d-d53b-73e9-fdc8-7fe30bf91f11@gmail.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 85f8ae4cc0c0..cd4dc3131e17 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -143,7 +143,7 @@ static ssize_t spi_statistics_##name##_show(struct spi_statistics *stat, \ unsigned long flags; \ ssize_t len; \ spin_lock_irqsave(&stat->lock, flags); \ - len = sprintf(buf, format_string, stat->field); \ + len = sysfs_emit(buf, format_string "\n", stat->field); \ spin_unlock_irqrestore(&stat->lock, flags); \ return len; \ } \ -- cgit v1.2.3 From b252ada293d5d30566121c61fa7552e74396d533 Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Wed, 26 Jan 2022 12:26:05 +0100 Subject: dt-bindings: mtd: spi-nor: Allow two CS per device The Xilinx QSPI controller has two advanced modes which allow the controller to behave differently and consider two flashes as one single storage. One of these two modes is quite complex to support from a binding point of view and is the dual parallel memories. In this mode, each byte of data is stored in both devices: the even bits in one, the odd bits in the other. The split is automatically handled by the QSPI controller and is transparent for the user. The other mode is simpler to support, it is called dual stacked memories. The controller shares the same SPI bus but each of the devices contain half of the data. Once in this mode, the controller does not follow CS requests but instead internally wires the two CS levels with the value of the most significant address bit. Supporting these two modes will involve core changes which include the possibility of providing two CS for a single SPI device Signed-off-by: Miquel Raynal Acked-by: Rob Herring Reviewed-by: Pratyush Yadav Link: https://lore.kernel.org/r/20220126112608.955728-2-miquel.raynal@bootlin.com Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/mtd/jedec,spi-nor.yaml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/mtd/jedec,spi-nor.yaml b/Documentation/devicetree/bindings/mtd/jedec,spi-nor.yaml index 39421f7233e4..4abfb4cfc157 100644 --- a/Documentation/devicetree/bindings/mtd/jedec,spi-nor.yaml +++ b/Documentation/devicetree/bindings/mtd/jedec,spi-nor.yaml @@ -47,7 +47,8 @@ properties: identified by the JEDEC READ ID opcode (0x9F). reg: - maxItems: 1 + minItems: 1 + maxItems: 2 spi-max-frequency: true spi-rx-bus-width: true -- cgit v1.2.3 From e2edd1b64f1c79e8abda365149ed62a2a9a494b4 Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Wed, 26 Jan 2022 12:26:06 +0100 Subject: spi: dt-bindings: Describe stacked/parallel memories modes Describe two new memories modes: - A stacked mode when the bus is common but the address space extended with an additinals wires. - A parallel mode with parallel busses accessing parallel flashes where the data is spread. Signed-off-by: Miquel Raynal Acked-by: Pratyush Yadav Reviewed-by: Rob Herring Link: https://lore.kernel.org/r/20220126112608.955728-3-miquel.raynal@bootlin.com Signed-off-by: Mark Brown --- .../bindings/spi/spi-peripheral-props.yaml | 25 ++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/Documentation/devicetree/bindings/spi/spi-peripheral-props.yaml b/Documentation/devicetree/bindings/spi/spi-peripheral-props.yaml index 5dd209206e88..fedb7ae98ff6 100644 --- a/Documentation/devicetree/bindings/spi/spi-peripheral-props.yaml +++ b/Documentation/devicetree/bindings/spi/spi-peripheral-props.yaml @@ -82,6 +82,31 @@ properties: description: Delay, in microseconds, after a write transfer. + stacked-memories: + description: Several SPI memories can be wired in stacked mode. + This basically means that either a device features several chip + selects, or that different devices must be seen as a single + bigger chip. This basically doubles (or more) the total address + space with only a single additional wire, while still needing + to repeat the commands when crossing a chip boundary. The size of + each chip should be provided as members of the array. + $ref: /schemas/types.yaml#/definitions/uint64-array + minItems: 2 + maxItems: 4 + + parallel-memories: + description: Several SPI memories can be wired in parallel mode. + The devices are physically on a different buses but will always + act synchronously as each data word is spread across the + different memories (eg. even bits are stored in one memory, odd + bits in the other). This basically doubles the address space and + the throughput while greatly complexifying the wiring because as + many busses as devices must be wired. The size of each chip should + be provided as members of the array. + $ref: /schemas/types.yaml#/definitions/uint64-array + minItems: 2 + maxItems: 4 + # The controller specific properties go here. allOf: - $ref: cdns,qspi-nor-peripheral-props.yaml# -- cgit v1.2.3 From eba5368503b4291db7819512600fa014ea17c5a8 Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Wed, 26 Jan 2022 12:26:07 +0100 Subject: spi: dt-bindings: Add an example with two stacked flashes Provide an example of how to describe two flashes in eg. stacked mode. Signed-off-by: Miquel Raynal Reviewed-by: Rob Herring Link: https://lore.kernel.org/r/20220126112608.955728-4-miquel.raynal@bootlin.com Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/spi/spi-controller.yaml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Documentation/devicetree/bindings/spi/spi-controller.yaml b/Documentation/devicetree/bindings/spi/spi-controller.yaml index 36b72518f565..0f4d40218400 100644 --- a/Documentation/devicetree/bindings/spi/spi-controller.yaml +++ b/Documentation/devicetree/bindings/spi/spi-controller.yaml @@ -139,4 +139,11 @@ examples: spi-max-frequency = <100000>; reg = <1>; }; + + flash@2 { + compatible = "jedec,spi-nor"; + spi-max-frequency = <50000000>; + reg = <2>, <3>; + stacked-memories = /bits/ 64 <0x10000000 0x10000000>; + }; }; -- cgit v1.2.3 From c5a3106aa4923bec979c2a76667a493cb5d134fd Mon Sep 17 00:00:00 2001 From: "Minghao Chi (CGEL ZTE)" Date: Mon, 21 Feb 2022 02:02:33 +0000 Subject: spi: Use of_device_get_match_data() Use of_device_get_match_data() to simplify the code. Reported-by: Zeal Robot Signed-off-by: Minghao Chi (CGEL ZTE) Link: https://lore.kernel.org/r/20220221020233.1925154-1-chi.minghao@zte.com.cn Signed-off-by: Mark Brown --- drivers/spi/spi-lantiq-ssc.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/drivers/spi/spi-lantiq-ssc.c b/drivers/spi/spi-lantiq-ssc.c index bcb52601804a..aae26f62ea87 100644 --- a/drivers/spi/spi-lantiq-ssc.c +++ b/drivers/spi/spi-lantiq-ssc.c @@ -906,17 +906,11 @@ static int lantiq_ssc_probe(struct platform_device *pdev) struct spi_master *master; struct lantiq_ssc_spi *spi; const struct lantiq_ssc_hwcfg *hwcfg; - const struct of_device_id *match; u32 id, supports_dma, revision; unsigned int num_cs; int err; - match = of_match_device(lantiq_ssc_match, dev); - if (!match) { - dev_err(dev, "no device match\n"); - return -EINVAL; - } - hwcfg = match->data; + hwcfg = of_device_get_match_data(dev); master = spi_alloc_master(dev, sizeof(struct lantiq_ssc_spi)); if (!master) -- cgit v1.2.3 From 5741150c808b2bbeb1017609f3029daf6651b7d5 Mon Sep 17 00:00:00 2001 From: Ahmad Fatoum Date: Tue, 1 Feb 2022 12:51:41 +0100 Subject: spi: stm32: ignore Rx queue not empty in stm32f4 Tx only mode STM32F4_SPI_SR_RXNE and STM32F4_SPI_SR_OVR are distinct bits in the same status register. ~STM32F4_SPI_SR_OVR | STM32F4_SPI_SR_RXNE is thus equal to ~STM32F4_SPI_SR_OVR. The original intention was likely for transmission-only transfers to ignore interrupts both for when the Rx queue has bytes (RXNE) as well as when these bytes haven't been read in time (OVR). Fix the typo by adding the missing parenthesis. Signed-off-by: Ahmad Fatoum Link: https://lore.kernel.org/r/20220201115142.3999860-1-a.fatoum@pengutronix.de Signed-off-by: Mark Brown --- drivers/spi/spi-stm32.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/spi/spi-stm32.c b/drivers/spi/spi-stm32.c index 7fc24505a72c..a6adc20f6862 100644 --- a/drivers/spi/spi-stm32.c +++ b/drivers/spi/spi-stm32.c @@ -763,7 +763,7 @@ static irqreturn_t stm32f4_spi_irq_event(int irq, void *dev_id) if (!spi->cur_usedma && (spi->cur_comm == SPI_SIMPLEX_TX || spi->cur_comm == SPI_3WIRE_TX)) { /* OVR flag shouldn't be handled for TX only mode */ - sr &= ~STM32F4_SPI_SR_OVR | STM32F4_SPI_SR_RXNE; + sr &= ~(STM32F4_SPI_SR_OVR | STM32F4_SPI_SR_RXNE); mask |= STM32F4_SPI_SR_TXE; } -- cgit v1.2.3 From 1847e3046c528bd85bd51e2860f4139bd9052d6c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Sat, 19 Feb 2022 14:15:48 +0100 Subject: spi: gpio: Implement LSB First bitbang support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add support for slave DT property spi-lsb-first, i.e., SPI_LSB_FIRST mode. Duplicate the inline helpers bitbang_txrx_be_cpha{0,1} as LE versions. Conditionally call them from all the spi-gpio txrx_word callbacks. Some alternatives to this implementation approach were discussed back then [0], but eventually it was considered reasonable. [0] https://lore.kernel.org/linux-arm-kernel/20191212033952.5967-8-afaerber@suse.de/ Signed-off-by: Andreas Färber Signed-off-by: Heiner Kallweit Tested-by: Christian Hewitt Link: https://lore.kernel.org/r/feac3377-4ad1-77d8-9a18-3588d80fb909@gmail.com Signed-off-by: Mark Brown --- drivers/spi/spi-bitbang-txrx.h | 66 ++++++++++++++++++++++++++++++++++++++++++ drivers/spi/spi-gpio.c | 42 +++++++++++++++++++++------ 2 files changed, 99 insertions(+), 9 deletions(-) diff --git a/drivers/spi/spi-bitbang-txrx.h b/drivers/spi/spi-bitbang-txrx.h index ae61d72c7d28..267342dfa738 100644 --- a/drivers/spi/spi-bitbang-txrx.h +++ b/drivers/spi/spi-bitbang-txrx.h @@ -41,6 +41,8 @@ * chips need ... there may be several reasons you'd need to tweak timings * in these routines, not just to make it faster or slower to match a * particular CPU clock rate. + * + * ToDo: Maybe the bitrev macros can be used to improve the code? */ static inline u32 @@ -106,3 +108,67 @@ bitbang_txrx_be_cpha1(struct spi_device *spi, } return word; } + +static inline u32 +bitbang_txrx_le_cpha0(struct spi_device *spi, + unsigned int nsecs, unsigned int cpol, unsigned int flags, + u32 word, u8 bits) +{ + /* if (cpol == 0) this is SPI_MODE_0; else this is SPI_MODE_2 */ + + u32 oldbit = !(word & 1); + /* clock starts at inactive polarity */ + for (; likely(bits); bits--) { + + /* setup LSB (to slave) on trailing edge */ + if ((flags & SPI_MASTER_NO_TX) == 0) { + if ((word & 1) != oldbit) { + setmosi(spi, word & 1); + oldbit = word & 1; + } + } + spidelay(nsecs); /* T(setup) */ + + setsck(spi, !cpol); + spidelay(nsecs); + + /* sample LSB (from slave) on leading edge */ + word >>= 1; + if ((flags & SPI_MASTER_NO_RX) == 0) + word |= getmiso(spi) << (bits - 1); + setsck(spi, cpol); + } + return word; +} + +static inline u32 +bitbang_txrx_le_cpha1(struct spi_device *spi, + unsigned int nsecs, unsigned int cpol, unsigned int flags, + u32 word, u8 bits) +{ + /* if (cpol == 0) this is SPI_MODE_1; else this is SPI_MODE_3 */ + + u32 oldbit = !(word & 1); + /* clock starts at inactive polarity */ + for (; likely(bits); bits--) { + + /* setup LSB (to slave) on leading edge */ + setsck(spi, !cpol); + if ((flags & SPI_MASTER_NO_TX) == 0) { + if ((word & 1) != oldbit) { + setmosi(spi, word & 1); + oldbit = word & 1; + } + } + spidelay(nsecs); /* T(setup) */ + + setsck(spi, cpol); + spidelay(nsecs); + + /* sample LSB (from slave) on trailing edge */ + word >>= 1; + if ((flags & SPI_MASTER_NO_RX) == 0) + word |= getmiso(spi) << (bits - 1); + } + return word; +} diff --git a/drivers/spi/spi-gpio.c b/drivers/spi/spi-gpio.c index 0584f4d2fde2..4b12c4964a66 100644 --- a/drivers/spi/spi-gpio.c +++ b/drivers/spi/spi-gpio.c @@ -135,25 +135,37 @@ static inline int getmiso(const struct spi_device *spi) static u32 spi_gpio_txrx_word_mode0(struct spi_device *spi, unsigned nsecs, u32 word, u8 bits, unsigned flags) { - return bitbang_txrx_be_cpha0(spi, nsecs, 0, flags, word, bits); + if (unlikely(spi->mode & SPI_LSB_FIRST)) + return bitbang_txrx_le_cpha0(spi, nsecs, 0, flags, word, bits); + else + return bitbang_txrx_be_cpha0(spi, nsecs, 0, flags, word, bits); } static u32 spi_gpio_txrx_word_mode1(struct spi_device *spi, unsigned nsecs, u32 word, u8 bits, unsigned flags) { - return bitbang_txrx_be_cpha1(spi, nsecs, 0, flags, word, bits); + if (unlikely(spi->mode & SPI_LSB_FIRST)) + return bitbang_txrx_le_cpha1(spi, nsecs, 0, flags, word, bits); + else + return bitbang_txrx_be_cpha1(spi, nsecs, 0, flags, word, bits); } static u32 spi_gpio_txrx_word_mode2(struct spi_device *spi, unsigned nsecs, u32 word, u8 bits, unsigned flags) { - return bitbang_txrx_be_cpha0(spi, nsecs, 1, flags, word, bits); + if (unlikely(spi->mode & SPI_LSB_FIRST)) + return bitbang_txrx_le_cpha0(spi, nsecs, 1, flags, word, bits); + else + return bitbang_txrx_be_cpha0(spi, nsecs, 1, flags, word, bits); } static u32 spi_gpio_txrx_word_mode3(struct spi_device *spi, unsigned nsecs, u32 word, u8 bits, unsigned flags) { - return bitbang_txrx_be_cpha1(spi, nsecs, 1, flags, word, bits); + if (unlikely(spi->mode & SPI_LSB_FIRST)) + return bitbang_txrx_le_cpha1(spi, nsecs, 1, flags, word, bits); + else + return bitbang_txrx_be_cpha1(spi, nsecs, 1, flags, word, bits); } /* @@ -170,28 +182,40 @@ static u32 spi_gpio_spec_txrx_word_mode0(struct spi_device *spi, unsigned nsecs, u32 word, u8 bits, unsigned flags) { flags = spi->master->flags; - return bitbang_txrx_be_cpha0(spi, nsecs, 0, flags, word, bits); + if (unlikely(spi->mode & SPI_LSB_FIRST)) + return bitbang_txrx_le_cpha0(spi, nsecs, 0, flags, word, bits); + else + return bitbang_txrx_be_cpha0(spi, nsecs, 0, flags, word, bits); } static u32 spi_gpio_spec_txrx_word_mode1(struct spi_device *spi, unsigned nsecs, u32 word, u8 bits, unsigned flags) { flags = spi->master->flags; - return bitbang_txrx_be_cpha1(spi, nsecs, 0, flags, word, bits); + if (unlikely(spi->mode & SPI_LSB_FIRST)) + return bitbang_txrx_le_cpha1(spi, nsecs, 0, flags, word, bits); + else + return bitbang_txrx_be_cpha1(spi, nsecs, 0, flags, word, bits); } static u32 spi_gpio_spec_txrx_word_mode2(struct spi_device *spi, unsigned nsecs, u32 word, u8 bits, unsigned flags) { flags = spi->master->flags; - return bitbang_txrx_be_cpha0(spi, nsecs, 1, flags, word, bits); + if (unlikely(spi->mode & SPI_LSB_FIRST)) + return bitbang_txrx_le_cpha0(spi, nsecs, 1, flags, word, bits); + else + return bitbang_txrx_be_cpha0(spi, nsecs, 1, flags, word, bits); } static u32 spi_gpio_spec_txrx_word_mode3(struct spi_device *spi, unsigned nsecs, u32 word, u8 bits, unsigned flags) { flags = spi->master->flags; - return bitbang_txrx_be_cpha1(spi, nsecs, 1, flags, word, bits); + if (unlikely(spi->mode & SPI_LSB_FIRST)) + return bitbang_txrx_le_cpha1(spi, nsecs, 1, flags, word, bits); + else + return bitbang_txrx_be_cpha1(spi, nsecs, 1, flags, word, bits); } /*----------------------------------------------------------------------*/ @@ -378,7 +402,7 @@ static int spi_gpio_probe(struct platform_device *pdev) master->bits_per_word_mask = SPI_BPW_RANGE_MASK(1, 32); master->mode_bits = SPI_3WIRE | SPI_3WIRE_HIZ | SPI_CPHA | SPI_CPOL | - SPI_CS_HIGH; + SPI_CS_HIGH | SPI_LSB_FIRST; if (!spi_gpio->mosi) { /* HW configuration without MOSI pin * -- cgit v1.2.3 From 4d986ffa036a773456476f70bd0fde2fb1330b7d Mon Sep 17 00:00:00 2001 From: Wang Qing Date: Mon, 14 Feb 2022 18:00:07 -0800 Subject: spi: add missing pci_dev_put() before return pci_get_slot() increases its reference count, the caller must decrement the reference count by calling pci_dev_put() Signed-off-by: Wang Qing Link: https://lore.kernel.org/r/1644890407-65167-1-git-send-email-wangqing@vivo.com Signed-off-by: Mark Brown --- drivers/spi/spi-topcliff-pch.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/spi/spi-topcliff-pch.c b/drivers/spi/spi-topcliff-pch.c index 8c4615b76339..8e1cc345810a 100644 --- a/drivers/spi/spi-topcliff-pch.c +++ b/drivers/spi/spi-topcliff-pch.c @@ -877,7 +877,7 @@ static void pch_spi_request_dma(struct pch_spi_data *data, int bpw) dev_err(&data->master->dev, "ERROR: dma_request_channel FAILS(Tx)\n"); data->use_dma = 0; - return; + goto out; } dma->chan_tx = chan; @@ -894,9 +894,12 @@ static void pch_spi_request_dma(struct pch_spi_data *data, int bpw) dma_release_channel(dma->chan_tx); dma->chan_tx = NULL; data->use_dma = 0; - return; + goto out; } dma->chan_rx = chan; + +out: + pci_dev_put(dma_dev); } static void pch_spi_release_dma(struct pch_spi_data *data) -- cgit v1.2.3 From a586f944f3a30cfffdbda081aa094bc6845f5ba9 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 23 Feb 2022 21:19:48 +0200 Subject: spi: pxa2xx-pci: Do not dereference fwnode in struct device In order to make the underneath API easier to change in the future, prevent users from dereferencing fwnode from struct device. Instead, use the specific dev_fwnode() API for that. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20220223191948.31325-1-andriy.shevchenko@linux.intel.com Signed-off-by: Mark Brown --- drivers/spi/spi-pxa2xx-pci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/spi/spi-pxa2xx-pci.c b/drivers/spi/spi-pxa2xx-pci.c index 2e134eb4bd2c..47c8cb56a4d0 100644 --- a/drivers/spi/spi-pxa2xx-pci.c +++ b/drivers/spi/spi-pxa2xx-pci.c @@ -261,7 +261,7 @@ static int pxa2xx_spi_pci_probe(struct pci_dev *dev, return PTR_ERR(ssp->clk); memset(&pi, 0, sizeof(pi)); - pi.fwnode = dev->dev.fwnode; + pi.fwnode = dev_fwnode(&dev->dev); pi.parent = &dev->dev; pi.name = "pxa2xx-spi"; pi.id = ssp->port_id; -- cgit v1.2.3 From 609d7ffdc42199a0ec949db057e3b4be6745d6c5 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 23 Feb 2022 21:16:37 +0200 Subject: spi: pxa2xx-pci: Balance reference count for PCI DMA device The pci_get_slot() increases its reference count, the caller must decrement the reference count by calling pci_dev_put(). Fixes: 743485ea3bee ("spi: pxa2xx-pci: Do a specific setup in a separate function") Fixes: 25014521603f ("spi: pxa2xx-pci: Enable DMA for Intel Merrifield") Reported-by: Wang Qing Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20220223191637.31147-1-andriy.shevchenko@linux.intel.com Signed-off-by: Mark Brown --- drivers/spi/spi-pxa2xx-pci.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/drivers/spi/spi-pxa2xx-pci.c b/drivers/spi/spi-pxa2xx-pci.c index 47c8cb56a4d0..6d60972e4e20 100644 --- a/drivers/spi/spi-pxa2xx-pci.c +++ b/drivers/spi/spi-pxa2xx-pci.c @@ -76,14 +76,23 @@ static bool lpss_dma_filter(struct dma_chan *chan, void *param) return true; } +static void lpss_dma_put_device(void *dma_dev) +{ + pci_dev_put(dma_dev); +} + static int lpss_spi_setup(struct pci_dev *dev, struct pxa_spi_info *c) { struct pci_dev *dma_dev; + int ret; c->num_chipselect = 1; c->max_clk_rate = 50000000; dma_dev = pci_get_slot(dev->bus, PCI_DEVFN(PCI_SLOT(dev->devfn), 0)); + ret = devm_add_action_or_reset(&dev->dev, lpss_dma_put_device, dma_dev); + if (ret) + return ret; if (c->tx_param) { struct dw_dma_slave *slave = c->tx_param; @@ -107,8 +116,9 @@ static int lpss_spi_setup(struct pci_dev *dev, struct pxa_spi_info *c) static int mrfld_spi_setup(struct pci_dev *dev, struct pxa_spi_info *c) { - struct pci_dev *dma_dev = pci_get_slot(dev->bus, PCI_DEVFN(21, 0)); struct dw_dma_slave *tx, *rx; + struct pci_dev *dma_dev; + int ret; switch (PCI_FUNC(dev->devfn)) { case 0: @@ -133,6 +143,11 @@ static int mrfld_spi_setup(struct pci_dev *dev, struct pxa_spi_info *c) return -ENODEV; } + dma_dev = pci_get_slot(dev->bus, PCI_DEVFN(21, 0)); + ret = devm_add_action_or_reset(&dev->dev, lpss_dma_put_device, dma_dev); + if (ret) + return ret; + tx = c->tx_param; tx->dma_dev = &dma_dev->dev; -- cgit v1.2.3 From ac982578e7d340dc4f4fd243f4a4b24787d28c3f Mon Sep 17 00:00:00 2001 From: Krishna Yarlagadda Date: Tue, 22 Feb 2022 23:26:07 +0530 Subject: spi: tegra210-quad: use device_reset method Use device_reset api to replace duplicate code in driver to call reset_control_get api with reset handle. Signed-off-by: Krishna Yarlagadda Link: https://lore.kernel.org/r/20220222175611.58051-2-kyarlagadda@nvidia.com Signed-off-by: Mark Brown --- drivers/spi/spi-tegra210-quad.c | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) diff --git a/drivers/spi/spi-tegra210-quad.c b/drivers/spi/spi-tegra210-quad.c index cb00ac2fc7d8..a353f2a9abd4 100644 --- a/drivers/spi/spi-tegra210-quad.c +++ b/drivers/spi/spi-tegra210-quad.c @@ -137,7 +137,6 @@ struct tegra_qspi { spinlock_t lock; struct clk *clk; - struct reset_control *rst; void __iomem *base; phys_addr_t phys; unsigned int irq; @@ -948,9 +947,8 @@ static void tegra_qspi_handle_error(struct tegra_qspi *tqspi) dev_err(tqspi->dev, "error in transfer, fifo status 0x%08x\n", tqspi->status_reg); tegra_qspi_dump_regs(tqspi); tegra_qspi_flush_fifos(tqspi, true); - reset_control_assert(tqspi->rst); - udelay(2); - reset_control_deassert(tqspi->rst); + if (device_reset(tqspi->dev) < 0) + dev_warn_once(tqspi->dev, "device reset failed\n"); } static void tegra_qspi_transfer_end(struct spi_device *spi) @@ -1251,13 +1249,6 @@ static int tegra_qspi_probe(struct platform_device *pdev) return ret; } - tqspi->rst = devm_reset_control_get_exclusive(&pdev->dev, NULL); - if (IS_ERR(tqspi->rst)) { - ret = PTR_ERR(tqspi->rst); - dev_err(&pdev->dev, "failed to get reset control: %d\n", ret); - return ret; - } - tqspi->max_buf_size = QSPI_FIFO_DEPTH << 2; tqspi->dma_buf_size = DEFAULT_QSPI_DMA_BUF_LEN; @@ -1279,9 +1270,8 @@ static int tegra_qspi_probe(struct platform_device *pdev) goto exit_pm_disable; } - reset_control_assert(tqspi->rst); - udelay(2); - reset_control_deassert(tqspi->rst); + if (device_reset(tqspi->dev) < 0) + dev_warn_once(tqspi->dev, "device reset failed\n"); tqspi->def_command1_reg = QSPI_M_S | QSPI_CS_SW_HW | QSPI_CS_SW_VAL; tegra_qspi_writel(tqspi, tqspi->def_command1_reg, QSPI_COMMAND1); -- cgit v1.2.3 From de2f678b11bdcbabb6d804c543f9a3325c0e83bf Mon Sep 17 00:00:00 2001 From: Krishna Yarlagadda Date: Tue, 22 Feb 2022 23:26:08 +0530 Subject: spi: Add Tegra234 QUAD SPI compatible Add compatible string for Tegra234 for Tegra QUAD SPI Signed-off-by: Krishna Yarlagadda Link: https://lore.kernel.org/r/20220222175611.58051-3-kyarlagadda@nvidia.com Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/spi/nvidia,tegra210-quad.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/spi/nvidia,tegra210-quad.yaml b/Documentation/devicetree/bindings/spi/nvidia,tegra210-quad.yaml index 35a8045b2c70..6efea8970e62 100644 --- a/Documentation/devicetree/bindings/spi/nvidia,tegra210-quad.yaml +++ b/Documentation/devicetree/bindings/spi/nvidia,tegra210-quad.yaml @@ -19,6 +19,7 @@ properties: - nvidia,tegra210-qspi - nvidia,tegra186-qspi - nvidia,tegra194-qspi + - nvidia,tegra234-qspi reg: maxItems: 1 -- cgit v1.2.3 From ea23f0e148b82e5bcbc6c814926f53133552f0f3 Mon Sep 17 00:00:00 2001 From: Krishna Yarlagadda Date: Tue, 22 Feb 2022 23:26:09 +0530 Subject: spi: tegra210-quad: add new chips to compatible Add support for Tegra234 and soc data to select capabilities. Signed-off-by: Krishna Yarlagadda Link: https://lore.kernel.org/r/20220222175611.58051-4-kyarlagadda@nvidia.com Signed-off-by: Mark Brown --- drivers/spi/spi-tegra210-quad.c | 33 ++++++++++++++++++++++++++++++--- 1 file changed, 30 insertions(+), 3 deletions(-) diff --git a/drivers/spi/spi-tegra210-quad.c b/drivers/spi/spi-tegra210-quad.c index a353f2a9abd4..3725ee5331ae 100644 --- a/drivers/spi/spi-tegra210-quad.c +++ b/drivers/spi/spi-tegra210-quad.c @@ -125,6 +125,10 @@ #define QSPI_DMA_TIMEOUT (msecs_to_jiffies(1000)) #define DEFAULT_QSPI_DMA_BUF_LEN (64 * 1024) +struct tegra_qspi_soc_data { + bool has_dma; +}; + struct tegra_qspi_client_data { int tx_clk_tap_delay; int rx_clk_tap_delay; @@ -184,6 +188,7 @@ struct tegra_qspi { u32 *tx_dma_buf; dma_addr_t tx_dma_phys; struct dma_async_tx_descriptor *tx_dma_desc; + const struct tegra_qspi_soc_data *soc_data; }; static inline u32 tegra_qspi_readl(struct tegra_qspi *tqspi, unsigned long offset) @@ -1191,10 +1196,32 @@ static irqreturn_t tegra_qspi_isr_thread(int irq, void *context_data) return handle_dma_based_xfer(tqspi); } +static struct tegra_qspi_soc_data tegra210_qspi_soc_data = { + .has_dma = true, +}; + +static struct tegra_qspi_soc_data tegra186_qspi_soc_data = { + .has_dma = true, +}; + +static struct tegra_qspi_soc_data tegra234_qspi_soc_data = { + .has_dma = false, +}; + static const struct of_device_id tegra_qspi_of_match[] = { - { .compatible = "nvidia,tegra210-qspi", }, - { .compatible = "nvidia,tegra186-qspi", }, - { .compatible = "nvidia,tegra194-qspi", }, + { + .compatible = "nvidia,tegra210-qspi", + .data = &tegra210_qspi_soc_data, + }, { + .compatible = "nvidia,tegra186-qspi", + .data = &tegra186_qspi_soc_data, + }, { + .compatible = "nvidia,tegra194-qspi", + .data = &tegra186_qspi_soc_data, + }, { + .compatible = "nvidia,tegra234-qspi", + .data = &tegra234_qspi_soc_data, + }, {} }; -- cgit v1.2.3 From 83854c231262d2ad43c4fb32414ba25304f925d8 Mon Sep 17 00:00:00 2001 From: Li-hao Kuo Date: Fri, 25 Feb 2022 14:31:53 +0800 Subject: spi: dt-bindings: remove unused required property fix issue /builds/robherring/linux-dt/Documentation/devicetree/bindings/spi/spi-sunplus-sp7021.example.dt.yaml: spi@9C002D80: 'clocks-names' is a required property From schema: /builds/robherring/linux-dt/Documentation/devicetree/bindings/spi/spi-sunplus-sp7021.yaml delete unused required(clock-name) Fixes: 3b8ab4da34 ("spi: Fix test error for sp7021") Reported-by: Rob Herring Signed-off-by: Li-hao Kuo Link: https://lore.kernel.org/r/097bbc8b703b17e8fb3e3f6f6d2f97fe668bd5c5.1645770648.git.lhjeff911@gmail.com Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/spi/spi-sunplus-sp7021.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/Documentation/devicetree/bindings/spi/spi-sunplus-sp7021.yaml b/Documentation/devicetree/bindings/spi/spi-sunplus-sp7021.yaml index 298eac28c40f..3a58cf0f1ec8 100644 --- a/Documentation/devicetree/bindings/spi/spi-sunplus-sp7021.yaml +++ b/Documentation/devicetree/bindings/spi/spi-sunplus-sp7021.yaml @@ -50,7 +50,6 @@ required: - interrupts - interrupt-names - clocks - - clocks-names - resets - pinctrl-names - pinctrl-0 -- cgit v1.2.3 From 78e27f970f73a4ee57dc050a6233e09a56963391 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 25 Feb 2022 19:23:40 +0200 Subject: spi: pxa2xx-pci: Refactor CE4100 to use ->setup() Refactor CE4100 handling code to use ->setup() instead of spreading potentially confusing conditional. Besides that, it will allow to refactor further to avoid intermediate storage for the used configuration parameters. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20220225172350.69797-1-andriy.shevchenko@linux.intel.com Signed-off-by: Mark Brown --- drivers/spi/spi-pxa2xx-pci.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/drivers/spi/spi-pxa2xx-pci.c b/drivers/spi/spi-pxa2xx-pci.c index 6d60972e4e20..bd20379d9342 100644 --- a/drivers/spi/spi-pxa2xx-pci.c +++ b/drivers/spi/spi-pxa2xx-pci.c @@ -30,7 +30,7 @@ enum { struct pxa_spi_info { enum pxa_ssp_type type; int port_id; - int num_chipselect; + unsigned int num_chipselect; unsigned long max_clk_rate; /* DMA channel request parameters */ @@ -114,6 +114,14 @@ static int lpss_spi_setup(struct pci_dev *dev, struct pxa_spi_info *c) return 0; } +static int ce4100_spi_setup(struct pci_dev *dev, struct pxa_spi_info *c) +{ + c->num_chipselect = dev->devfn; + c->max_clk_rate = 3686400; + + return 0; +} + static int mrfld_spi_setup(struct pci_dev *dev, struct pxa_spi_info *c) { struct dw_dma_slave *tx, *rx; @@ -163,8 +171,7 @@ static struct pxa_spi_info spi_info_configs[] = { [PORT_CE4100] = { .type = PXA25x_SSP, .port_id = -1, - .num_chipselect = -1, - .max_clk_rate = 3686400, + .setup = ce4100_spi_setup, }, [PORT_BYT] = { .type = LPSS_BYT_SSP, @@ -248,7 +255,7 @@ static int pxa2xx_spi_pci_probe(struct pci_dev *dev, } memset(&spi_pdata, 0, sizeof(spi_pdata)); - spi_pdata.num_chipselect = (c->num_chipselect > 0) ? c->num_chipselect : dev->devfn; + spi_pdata.num_chipselect = c->num_chipselect; spi_pdata.dma_filter = c->dma_filter; spi_pdata.tx_param = c->tx_param; spi_pdata.rx_param = c->rx_param; -- cgit v1.2.3 From 71ea0e3ac70a50b0c56105e116ed903f8e504e8f Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 25 Feb 2022 19:23:41 +0200 Subject: spi: pxa2xx-pci: Refactor Quark X1000 to use ->setup() Refactor Quark X1000 handling code to use ->setup() instead of using the configuration data structure directly. It will allow to refactor further to avoid intermediate storage for the used configuration parameters. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20220225172350.69797-2-andriy.shevchenko@linux.intel.com Signed-off-by: Mark Brown --- drivers/spi/spi-pxa2xx-pci.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/drivers/spi/spi-pxa2xx-pci.c b/drivers/spi/spi-pxa2xx-pci.c index bd20379d9342..4d617ad72bca 100644 --- a/drivers/spi/spi-pxa2xx-pci.c +++ b/drivers/spi/spi-pxa2xx-pci.c @@ -167,6 +167,14 @@ static int mrfld_spi_setup(struct pci_dev *dev, struct pxa_spi_info *c) return 0; } +static int qrk_spi_setup(struct pci_dev *dev, struct pxa_spi_info *c) +{ + c->num_chipselect = 1; + c->max_clk_rate = 50000000; + + return 0; +} + static struct pxa_spi_info spi_info_configs[] = { [PORT_CE4100] = { .type = PXA25x_SSP, @@ -209,8 +217,7 @@ static struct pxa_spi_info spi_info_configs[] = { [PORT_QUARK_X1000] = { .type = QUARK_X1000_SSP, .port_id = -1, - .num_chipselect = 1, - .max_clk_rate = 50000000, + .setup = qrk_spi_setup, }, [PORT_LPT0] = { .type = LPSS_LPT_SSP, -- cgit v1.2.3 From 1d9d62959f1b52eb939df38b9fda8beea455c751 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 25 Feb 2022 19:23:42 +0200 Subject: spi: pxa2xx-pci: Drop redundant NULL check in ->probe() Since all platforms are using ->setup() function, drop unneeded check. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20220225172350.69797-3-andriy.shevchenko@linux.intel.com Signed-off-by: Mark Brown --- drivers/spi/spi-pxa2xx-pci.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/drivers/spi/spi-pxa2xx-pci.c b/drivers/spi/spi-pxa2xx-pci.c index 4d617ad72bca..90b95e49a164 100644 --- a/drivers/spi/spi-pxa2xx-pci.c +++ b/drivers/spi/spi-pxa2xx-pci.c @@ -255,11 +255,9 @@ static int pxa2xx_spi_pci_probe(struct pci_dev *dev, return ret; c = &spi_info_configs[ent->driver_data]; - if (c->setup) { - ret = c->setup(dev, c); - if (ret) - return ret; - } + ret = c->setup(dev, c); + if (ret) + return ret; memset(&spi_pdata, 0, sizeof(spi_pdata)); spi_pdata.num_chipselect = c->num_chipselect; -- cgit v1.2.3 From 108607ce4e39a51caca51aa97c44c31041a597d1 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 25 Feb 2022 19:23:43 +0200 Subject: spi: pxa2xx-pci: Move port_id assignment to ->setup() Instead of using conditional, move port_id to the corresponding ->setup() functions. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20220225172350.69797-4-andriy.shevchenko@linux.intel.com Signed-off-by: Mark Brown --- drivers/spi/spi-pxa2xx-pci.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/spi/spi-pxa2xx-pci.c b/drivers/spi/spi-pxa2xx-pci.c index 90b95e49a164..87629da3e544 100644 --- a/drivers/spi/spi-pxa2xx-pci.c +++ b/drivers/spi/spi-pxa2xx-pci.c @@ -29,7 +29,7 @@ enum { struct pxa_spi_info { enum pxa_ssp_type type; - int port_id; + unsigned int port_id; unsigned int num_chipselect; unsigned long max_clk_rate; @@ -116,6 +116,7 @@ static int lpss_spi_setup(struct pci_dev *dev, struct pxa_spi_info *c) static int ce4100_spi_setup(struct pci_dev *dev, struct pxa_spi_info *c) { + c->port_id = dev->devfn; c->num_chipselect = dev->devfn; c->max_clk_rate = 3686400; @@ -169,6 +170,7 @@ static int mrfld_spi_setup(struct pci_dev *dev, struct pxa_spi_info *c) static int qrk_spi_setup(struct pci_dev *dev, struct pxa_spi_info *c) { + c->port_id = dev->devfn; c->num_chipselect = 1; c->max_clk_rate = 50000000; @@ -178,7 +180,6 @@ static int qrk_spi_setup(struct pci_dev *dev, struct pxa_spi_info *c) static struct pxa_spi_info spi_info_configs[] = { [PORT_CE4100] = { .type = PXA25x_SSP, - .port_id = -1, .setup = ce4100_spi_setup, }, [PORT_BYT] = { @@ -216,7 +217,6 @@ static struct pxa_spi_info spi_info_configs[] = { }, [PORT_QUARK_X1000] = { .type = QUARK_X1000_SSP, - .port_id = -1, .setup = qrk_spi_setup, }, [PORT_LPT0] = { @@ -271,8 +271,8 @@ static int pxa2xx_spi_pci_probe(struct pci_dev *dev, ssp->dev = &dev->dev; ssp->phys_base = pci_resource_start(dev, 0); ssp->mmio_base = pcim_iomap_table(dev)[0]; - ssp->port_id = (c->port_id >= 0) ? c->port_id : dev->devfn; ssp->type = c->type; + ssp->port_id = c->port_id; pci_set_master(dev); -- cgit v1.2.3 From bd2e24de10da015147b02f8c2c4b8ebea8fa9574 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 25 Feb 2022 19:23:44 +0200 Subject: spi: pxa2xx-pci: Move dma_burst_size assignment to ->setup() Instead of using conditional, move dma_burst_size to the corresponding ->setup() function. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20220225172350.69797-5-andriy.shevchenko@linux.intel.com Signed-off-by: Mark Brown --- drivers/spi/spi-pxa2xx-pci.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/spi/spi-pxa2xx-pci.c b/drivers/spi/spi-pxa2xx-pci.c index 87629da3e544..c2cbb002784a 100644 --- a/drivers/spi/spi-pxa2xx-pci.c +++ b/drivers/spi/spi-pxa2xx-pci.c @@ -38,7 +38,7 @@ struct pxa_spi_info { void *tx_param; void *rx_param; - int dma_burst_size; + unsigned int dma_burst_size; int (*setup)(struct pci_dev *pdev, struct pxa_spi_info *c); }; @@ -111,6 +111,7 @@ static int lpss_spi_setup(struct pci_dev *dev, struct pxa_spi_info *c) } c->dma_filter = lpss_dma_filter; + c->dma_burst_size = 1; return 0; } @@ -265,7 +266,7 @@ static int pxa2xx_spi_pci_probe(struct pci_dev *dev, spi_pdata.tx_param = c->tx_param; spi_pdata.rx_param = c->rx_param; spi_pdata.enable_dma = c->rx_param && c->tx_param; - spi_pdata.dma_burst_size = c->dma_burst_size ? c->dma_burst_size : 1; + spi_pdata.dma_burst_size = c->dma_burst_size; ssp = &spi_pdata.ssp; ssp->dev = &dev->dev; -- cgit v1.2.3 From 03f8e04e9f9be8d28c52ae801f37d49988f02ce4 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 25 Feb 2022 19:23:45 +0200 Subject: spi: pxa2xx-pci: Move max_clk_rate assignment to ->setup() Move max_clk_rate to the corresponding ->setup() function to unify with the rest. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20220225172350.69797-6-andriy.shevchenko@linux.intel.com Signed-off-by: Mark Brown --- drivers/spi/spi-pxa2xx-pci.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/spi/spi-pxa2xx-pci.c b/drivers/spi/spi-pxa2xx-pci.c index c2cbb002784a..5ac1487c9b3f 100644 --- a/drivers/spi/spi-pxa2xx-pci.c +++ b/drivers/spi/spi-pxa2xx-pci.c @@ -153,6 +153,8 @@ static int mrfld_spi_setup(struct pci_dev *dev, struct pxa_spi_info *c) return -ENODEV; } + c->max_clk_rate = 25000000; + dma_dev = pci_get_slot(dev->bus, PCI_DEVFN(21, 0)); ret = devm_add_action_or_reset(&dev->dev, lpss_dma_put_device, dma_dev); if (ret) @@ -213,7 +215,6 @@ static struct pxa_spi_info spi_info_configs[] = { }, [PORT_MRFLD] = { .type = MRFLD_SSP, - .max_clk_rate = 25000000, .setup = mrfld_spi_setup, }, [PORT_QUARK_X1000] = { -- cgit v1.2.3 From 7e425c3c3d15241aa5b6c442a83f11b8bc4fee91 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 25 Feb 2022 19:23:46 +0200 Subject: spi: pxa2xx-pci: Replace enum with direct use of PCI IDs Instead of creating an abstraction on top of PCI IDs, just use them directly. The corresponding enum can be dropped. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20220225172350.69797-7-andriy.shevchenko@linux.intel.com Signed-off-by: Mark Brown --- drivers/spi/spi-pxa2xx-pci.c | 161 ++++++++++++++++++++++--------------------- 1 file changed, 83 insertions(+), 78 deletions(-) diff --git a/drivers/spi/spi-pxa2xx-pci.c b/drivers/spi/spi-pxa2xx-pci.c index 5ac1487c9b3f..a0f24e811e9f 100644 --- a/drivers/spi/spi-pxa2xx-pci.c +++ b/drivers/spi/spi-pxa2xx-pci.c @@ -15,17 +15,17 @@ #include #include -enum { - PORT_QUARK_X1000, - PORT_BYT, - PORT_MRFLD, - PORT_BSW0, - PORT_BSW1, - PORT_BSW2, - PORT_CE4100, - PORT_LPT0, - PORT_LPT1, -}; +#define PCI_DEVICE_ID_INTEL_QUARK_X1000 0x0935 +#define PCI_DEVICE_ID_INTEL_BYT 0x0f0e +#define PCI_DEVICE_ID_INTEL_MRFLD 0x1194 +#define PCI_DEVICE_ID_INTEL_BSW0 0x228e +#define PCI_DEVICE_ID_INTEL_BSW1 0x2290 +#define PCI_DEVICE_ID_INTEL_BSW2 0x22ac +#define PCI_DEVICE_ID_INTEL_CE4100 0x2e6a +#define PCI_DEVICE_ID_INTEL_LPT0_0 0x9c65 +#define PCI_DEVICE_ID_INTEL_LPT0_1 0x9c66 +#define PCI_DEVICE_ID_INTEL_LPT1_0 0x9ce5 +#define PCI_DEVICE_ID_INTEL_LPT1_1 0x9ce6 struct pxa_spi_info { enum pxa_ssp_type type; @@ -86,6 +86,49 @@ static int lpss_spi_setup(struct pci_dev *dev, struct pxa_spi_info *c) struct pci_dev *dma_dev; int ret; + switch (dev->device) { + case PCI_DEVICE_ID_INTEL_BYT: + c->type = LPSS_BYT_SSP; + c->port_id = 0; + c->tx_param = &byt_tx_param; + c->rx_param = &byt_rx_param; + break; + case PCI_DEVICE_ID_INTEL_BSW0: + c->type = LPSS_BSW_SSP; + c->port_id = 0; + c->tx_param = &bsw0_tx_param; + c->rx_param = &bsw0_rx_param; + break; + case PCI_DEVICE_ID_INTEL_BSW1: + c->type = LPSS_BSW_SSP; + c->port_id = 1; + c->tx_param = &bsw1_tx_param; + c->rx_param = &bsw1_rx_param; + break; + case PCI_DEVICE_ID_INTEL_BSW2: + c->type = LPSS_BSW_SSP; + c->port_id = 2; + c->tx_param = &bsw2_tx_param; + c->rx_param = &bsw2_rx_param; + break; + case PCI_DEVICE_ID_INTEL_LPT0_0: + case PCI_DEVICE_ID_INTEL_LPT1_0: + c->type = LPSS_LPT_SSP; + c->port_id = 0; + c->tx_param = &lpt0_tx_param; + c->rx_param = &lpt0_rx_param; + break; + case PCI_DEVICE_ID_INTEL_LPT0_1: + case PCI_DEVICE_ID_INTEL_LPT1_1: + c->type = LPSS_LPT_SSP; + c->port_id = 1; + c->tx_param = &lpt1_tx_param; + c->rx_param = &lpt1_rx_param; + break; + default: + return -ENODEV; + } + c->num_chipselect = 1; c->max_clk_rate = 50000000; @@ -115,8 +158,13 @@ static int lpss_spi_setup(struct pci_dev *dev, struct pxa_spi_info *c) return 0; } +static struct pxa_spi_info lpss_info_config = { + .setup = lpss_spi_setup, +}; + static int ce4100_spi_setup(struct pci_dev *dev, struct pxa_spi_info *c) { + c->type = PXA25x_SSP; c->port_id = dev->devfn; c->num_chipselect = dev->devfn; c->max_clk_rate = 3686400; @@ -124,6 +172,10 @@ static int ce4100_spi_setup(struct pci_dev *dev, struct pxa_spi_info *c) return 0; } +static struct pxa_spi_info ce4100_info_config = { + .setup = ce4100_spi_setup, +}; + static int mrfld_spi_setup(struct pci_dev *dev, struct pxa_spi_info *c) { struct dw_dma_slave *tx, *rx; @@ -153,6 +205,7 @@ static int mrfld_spi_setup(struct pci_dev *dev, struct pxa_spi_info *c) return -ENODEV; } + c->type = MRFLD_SSP; c->max_clk_rate = 25000000; dma_dev = pci_get_slot(dev->bus, PCI_DEVFN(21, 0)); @@ -171,8 +224,13 @@ static int mrfld_spi_setup(struct pci_dev *dev, struct pxa_spi_info *c) return 0; } +static struct pxa_spi_info mrfld_info_config = { + .setup = mrfld_spi_setup, +}; + static int qrk_spi_setup(struct pci_dev *dev, struct pxa_spi_info *c) { + c->type = QUARK_X1000_SSP; c->port_id = dev->devfn; c->num_chipselect = 1; c->max_clk_rate = 50000000; @@ -180,61 +238,8 @@ static int qrk_spi_setup(struct pci_dev *dev, struct pxa_spi_info *c) return 0; } -static struct pxa_spi_info spi_info_configs[] = { - [PORT_CE4100] = { - .type = PXA25x_SSP, - .setup = ce4100_spi_setup, - }, - [PORT_BYT] = { - .type = LPSS_BYT_SSP, - .port_id = 0, - .setup = lpss_spi_setup, - .tx_param = &byt_tx_param, - .rx_param = &byt_rx_param, - }, - [PORT_BSW0] = { - .type = LPSS_BSW_SSP, - .port_id = 0, - .setup = lpss_spi_setup, - .tx_param = &bsw0_tx_param, - .rx_param = &bsw0_rx_param, - }, - [PORT_BSW1] = { - .type = LPSS_BSW_SSP, - .port_id = 1, - .setup = lpss_spi_setup, - .tx_param = &bsw1_tx_param, - .rx_param = &bsw1_rx_param, - }, - [PORT_BSW2] = { - .type = LPSS_BSW_SSP, - .port_id = 2, - .setup = lpss_spi_setup, - .tx_param = &bsw2_tx_param, - .rx_param = &bsw2_rx_param, - }, - [PORT_MRFLD] = { - .type = MRFLD_SSP, - .setup = mrfld_spi_setup, - }, - [PORT_QUARK_X1000] = { - .type = QUARK_X1000_SSP, - .setup = qrk_spi_setup, - }, - [PORT_LPT0] = { - .type = LPSS_LPT_SSP, - .port_id = 0, - .setup = lpss_spi_setup, - .tx_param = &lpt0_tx_param, - .rx_param = &lpt0_rx_param, - }, - [PORT_LPT1] = { - .type = LPSS_LPT_SSP, - .port_id = 1, - .setup = lpss_spi_setup, - .tx_param = &lpt1_tx_param, - .rx_param = &lpt1_rx_param, - }, +static struct pxa_spi_info qrk_info_config = { + .setup = qrk_spi_setup, }; static int pxa2xx_spi_pci_probe(struct pci_dev *dev, @@ -256,7 +261,7 @@ static int pxa2xx_spi_pci_probe(struct pci_dev *dev, if (ret) return ret; - c = &spi_info_configs[ent->driver_data]; + c = (struct pxa_spi_info *)ent->driver_data; ret = c->setup(dev, c); if (ret) return ret; @@ -320,17 +325,17 @@ static void pxa2xx_spi_pci_remove(struct pci_dev *dev) } static const struct pci_device_id pxa2xx_spi_pci_devices[] = { - { PCI_VDEVICE(INTEL, 0x0935), PORT_QUARK_X1000 }, - { PCI_VDEVICE(INTEL, 0x0f0e), PORT_BYT }, - { PCI_VDEVICE(INTEL, 0x1194), PORT_MRFLD }, - { PCI_VDEVICE(INTEL, 0x228e), PORT_BSW0 }, - { PCI_VDEVICE(INTEL, 0x2290), PORT_BSW1 }, - { PCI_VDEVICE(INTEL, 0x22ac), PORT_BSW2 }, - { PCI_VDEVICE(INTEL, 0x2e6a), PORT_CE4100 }, - { PCI_VDEVICE(INTEL, 0x9c65), PORT_LPT0 }, - { PCI_VDEVICE(INTEL, 0x9c66), PORT_LPT1 }, - { PCI_VDEVICE(INTEL, 0x9ce5), PORT_LPT0 }, - { PCI_VDEVICE(INTEL, 0x9ce6), PORT_LPT1 }, + { PCI_DEVICE_DATA(INTEL, QUARK_X1000, &qrk_info_config) }, + { PCI_DEVICE_DATA(INTEL, BYT, &lpss_info_config) }, + { PCI_DEVICE_DATA(INTEL, MRFLD, &mrfld_info_config) }, + { PCI_DEVICE_DATA(INTEL, BSW0, &lpss_info_config) }, + { PCI_DEVICE_DATA(INTEL, BSW1, &lpss_info_config) }, + { PCI_DEVICE_DATA(INTEL, BSW2, &lpss_info_config) }, + { PCI_DEVICE_DATA(INTEL, CE4100, &ce4100_info_config) }, + { PCI_DEVICE_DATA(INTEL, LPT0_0, &lpss_info_config) }, + { PCI_DEVICE_DATA(INTEL, LPT0_1, &lpss_info_config) }, + { PCI_DEVICE_DATA(INTEL, LPT1_0, &lpss_info_config) }, + { PCI_DEVICE_DATA(INTEL, LPT1_1, &lpss_info_config) }, { } }; MODULE_DEVICE_TABLE(pci, pxa2xx_spi_pci_devices); -- cgit v1.2.3 From cb50f3f32a044ea45192a43e756b26048d35ba95 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 25 Feb 2022 19:23:47 +0200 Subject: spi: pxa2xx-pci: Drop unneeded checks in lpss_spi_setup() All of the LPSS devices are using DMA and set the parameters up, hence no need to test for that. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20220225172350.69797-8-andriy.shevchenko@linux.intel.com Signed-off-by: Mark Brown --- drivers/spi/spi-pxa2xx-pci.c | 23 +++++++++-------------- 1 file changed, 9 insertions(+), 14 deletions(-) diff --git a/drivers/spi/spi-pxa2xx-pci.c b/drivers/spi/spi-pxa2xx-pci.c index a0f24e811e9f..c041a9288d0c 100644 --- a/drivers/spi/spi-pxa2xx-pci.c +++ b/drivers/spi/spi-pxa2xx-pci.c @@ -83,6 +83,7 @@ static void lpss_dma_put_device(void *dma_dev) static int lpss_spi_setup(struct pci_dev *dev, struct pxa_spi_info *c) { + struct dw_dma_slave *tx, *rx; struct pci_dev *dma_dev; int ret; @@ -137,21 +138,15 @@ static int lpss_spi_setup(struct pci_dev *dev, struct pxa_spi_info *c) if (ret) return ret; - if (c->tx_param) { - struct dw_dma_slave *slave = c->tx_param; - - slave->dma_dev = &dma_dev->dev; - slave->m_master = 0; - slave->p_master = 1; - } - - if (c->rx_param) { - struct dw_dma_slave *slave = c->rx_param; + tx = c->tx_param; + tx->dma_dev = &dma_dev->dev; + tx->m_master = 0; + tx->p_master = 1; - slave->dma_dev = &dma_dev->dev; - slave->m_master = 0; - slave->p_master = 1; - } + rx = c->rx_param; + rx->dma_dev = &dma_dev->dev; + rx->m_master = 0; + rx->p_master = 1; c->dma_filter = lpss_dma_filter; c->dma_burst_size = 1; -- cgit v1.2.3 From c3f4fc096b37bc2e4535f16ac3d65d517bbc14eb Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 25 Feb 2022 19:23:48 +0200 Subject: spi: pxa2xx-pci: Extract pxa2xx_spi_pci_clk_register() Extract pxa2xx_spi_pci_clk_register() from ->probe() in order to reuse it later on for getting rid of max_clk_rate temporary storage. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20220225172350.69797-9-andriy.shevchenko@linux.intel.com Signed-off-by: Mark Brown --- drivers/spi/spi-pxa2xx-pci.c | 35 ++++++++++++++++++++++------------- 1 file changed, 22 insertions(+), 13 deletions(-) diff --git a/drivers/spi/spi-pxa2xx-pci.c b/drivers/spi/spi-pxa2xx-pci.c index c041a9288d0c..2dbe08034ad0 100644 --- a/drivers/spi/spi-pxa2xx-pci.c +++ b/drivers/spi/spi-pxa2xx-pci.c @@ -65,6 +65,24 @@ static struct dw_dma_slave lpt1_rx_param = { .src_id = 1 }; static struct dw_dma_slave lpt0_tx_param = { .dst_id = 2 }; static struct dw_dma_slave lpt0_rx_param = { .src_id = 3 }; +static void pxa2xx_spi_pci_clk_unregister(void *clk) +{ + clk_unregister(clk); +} + +static int pxa2xx_spi_pci_clk_register(struct pci_dev *dev, struct ssp_device *ssp, + unsigned long rate) +{ + char buf[40]; + + snprintf(buf, sizeof(buf), "pxa2xx-spi.%d", ssp->port_id); + ssp->clk = clk_register_fixed_rate(&dev->dev, buf, NULL, 0, rate); + if (IS_ERR(ssp->clk)) + return PTR_ERR(ssp->clk); + + return devm_add_action_or_reset(&dev->dev, pxa2xx_spi_pci_clk_unregister, ssp->clk); +} + static bool lpss_dma_filter(struct dma_chan *chan, void *param) { struct dw_dma_slave *dws = param; @@ -246,7 +264,6 @@ static int pxa2xx_spi_pci_probe(struct pci_dev *dev, struct pxa2xx_spi_controller spi_pdata; struct ssp_device *ssp; struct pxa_spi_info *c; - char buf[40]; ret = pcim_enable_device(dev); if (ret) @@ -283,11 +300,9 @@ static int pxa2xx_spi_pci_probe(struct pci_dev *dev, return ret; ssp->irq = pci_irq_vector(dev, 0); - snprintf(buf, sizeof(buf), "pxa2xx-spi.%d", ssp->port_id); - ssp->clk = clk_register_fixed_rate(&dev->dev, buf, NULL, 0, - c->max_clk_rate); - if (IS_ERR(ssp->clk)) - return PTR_ERR(ssp->clk); + ret = pxa2xx_spi_pci_clk_register(dev, ssp, c->max_clk_rate); + if (ret) + return ret; memset(&pi, 0, sizeof(pi)); pi.fwnode = dev_fwnode(&dev->dev); @@ -298,10 +313,8 @@ static int pxa2xx_spi_pci_probe(struct pci_dev *dev, pi.size_data = sizeof(spi_pdata); pdev = platform_device_register_full(&pi); - if (IS_ERR(pdev)) { - clk_unregister(ssp->clk); + if (IS_ERR(pdev)) return PTR_ERR(pdev); - } pci_set_drvdata(dev, pdev); @@ -311,12 +324,8 @@ static int pxa2xx_spi_pci_probe(struct pci_dev *dev, static void pxa2xx_spi_pci_remove(struct pci_dev *dev) { struct platform_device *pdev = pci_get_drvdata(dev); - struct pxa2xx_spi_controller *spi_pdata; - - spi_pdata = dev_get_platdata(&pdev->dev); platform_device_unregister(pdev); - clk_unregister(spi_pdata->ssp.clk); } static const struct pci_device_id pxa2xx_spi_pci_devices[] = { -- cgit v1.2.3 From ba8d1353d9c2d9190a523860e37bd7cb7b9de31b Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 25 Feb 2022 19:23:49 +0200 Subject: spi: pxa2xx-pci: Drop temporary storage use for a handful of members Instead of using temporary storage, assign the values directly to the corresponding struct pxa2xx_spi_controller members. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20220225172350.69797-10-andriy.shevchenko@linux.intel.com Signed-off-by: Mark Brown --- drivers/spi/spi-pxa2xx-pci.c | 110 +++++++++++++++++++------------------------ 1 file changed, 49 insertions(+), 61 deletions(-) diff --git a/drivers/spi/spi-pxa2xx-pci.c b/drivers/spi/spi-pxa2xx-pci.c index 2dbe08034ad0..3c5d14affa95 100644 --- a/drivers/spi/spi-pxa2xx-pci.c +++ b/drivers/spi/spi-pxa2xx-pci.c @@ -28,19 +28,7 @@ #define PCI_DEVICE_ID_INTEL_LPT1_1 0x9ce6 struct pxa_spi_info { - enum pxa_ssp_type type; - unsigned int port_id; - unsigned int num_chipselect; - unsigned long max_clk_rate; - - /* DMA channel request parameters */ - bool (*dma_filter)(struct dma_chan *chan, void *param); - void *tx_param; - void *rx_param; - - unsigned int dma_burst_size; - - int (*setup)(struct pci_dev *pdev, struct pxa_spi_info *c); + int (*setup)(struct pci_dev *pdev, struct pxa2xx_spi_controller *c); }; static struct dw_dma_slave byt_tx_param = { .dst_id = 0 }; @@ -99,48 +87,49 @@ static void lpss_dma_put_device(void *dma_dev) pci_dev_put(dma_dev); } -static int lpss_spi_setup(struct pci_dev *dev, struct pxa_spi_info *c) +static int lpss_spi_setup(struct pci_dev *dev, struct pxa2xx_spi_controller *c) { + struct ssp_device *ssp = &c->ssp; struct dw_dma_slave *tx, *rx; struct pci_dev *dma_dev; int ret; switch (dev->device) { case PCI_DEVICE_ID_INTEL_BYT: - c->type = LPSS_BYT_SSP; - c->port_id = 0; + ssp->type = LPSS_BYT_SSP; + ssp->port_id = 0; c->tx_param = &byt_tx_param; c->rx_param = &byt_rx_param; break; case PCI_DEVICE_ID_INTEL_BSW0: - c->type = LPSS_BSW_SSP; - c->port_id = 0; + ssp->type = LPSS_BSW_SSP; + ssp->port_id = 0; c->tx_param = &bsw0_tx_param; c->rx_param = &bsw0_rx_param; break; case PCI_DEVICE_ID_INTEL_BSW1: - c->type = LPSS_BSW_SSP; - c->port_id = 1; + ssp->type = LPSS_BSW_SSP; + ssp->port_id = 1; c->tx_param = &bsw1_tx_param; c->rx_param = &bsw1_rx_param; break; case PCI_DEVICE_ID_INTEL_BSW2: - c->type = LPSS_BSW_SSP; - c->port_id = 2; + ssp->type = LPSS_BSW_SSP; + ssp->port_id = 2; c->tx_param = &bsw2_tx_param; c->rx_param = &bsw2_rx_param; break; case PCI_DEVICE_ID_INTEL_LPT0_0: case PCI_DEVICE_ID_INTEL_LPT1_0: - c->type = LPSS_LPT_SSP; - c->port_id = 0; + ssp->type = LPSS_LPT_SSP; + ssp->port_id = 0; c->tx_param = &lpt0_tx_param; c->rx_param = &lpt0_rx_param; break; case PCI_DEVICE_ID_INTEL_LPT0_1: case PCI_DEVICE_ID_INTEL_LPT1_1: - c->type = LPSS_LPT_SSP; - c->port_id = 1; + ssp->type = LPSS_LPT_SSP; + ssp->port_id = 1; c->tx_param = &lpt1_tx_param; c->rx_param = &lpt1_rx_param; break; @@ -149,7 +138,10 @@ static int lpss_spi_setup(struct pci_dev *dev, struct pxa_spi_info *c) } c->num_chipselect = 1; - c->max_clk_rate = 50000000; + + ret = pxa2xx_spi_pci_clk_register(dev, ssp, 50000000); + if (ret) + return ret; dma_dev = pci_get_slot(dev->bus, PCI_DEVFN(PCI_SLOT(dev->devfn), 0)); ret = devm_add_action_or_reset(&dev->dev, lpss_dma_put_device, dma_dev); @@ -168,6 +160,7 @@ static int lpss_spi_setup(struct pci_dev *dev, struct pxa_spi_info *c) c->dma_filter = lpss_dma_filter; c->dma_burst_size = 1; + c->enable_dma = 1; return 0; } @@ -175,41 +168,45 @@ static struct pxa_spi_info lpss_info_config = { .setup = lpss_spi_setup, }; -static int ce4100_spi_setup(struct pci_dev *dev, struct pxa_spi_info *c) +static int ce4100_spi_setup(struct pci_dev *dev, struct pxa2xx_spi_controller *c) { - c->type = PXA25x_SSP; - c->port_id = dev->devfn; + struct ssp_device *ssp = &c->ssp; + + ssp->type = PXA25x_SSP; + ssp->port_id = dev->devfn; c->num_chipselect = dev->devfn; - c->max_clk_rate = 3686400; - return 0; + return pxa2xx_spi_pci_clk_register(dev, ssp, 3686400); } static struct pxa_spi_info ce4100_info_config = { .setup = ce4100_spi_setup, }; -static int mrfld_spi_setup(struct pci_dev *dev, struct pxa_spi_info *c) +static int mrfld_spi_setup(struct pci_dev *dev, struct pxa2xx_spi_controller *c) { + struct ssp_device *ssp = &c->ssp; struct dw_dma_slave *tx, *rx; struct pci_dev *dma_dev; int ret; + ssp->type = MRFLD_SSP; + switch (PCI_FUNC(dev->devfn)) { case 0: - c->port_id = 3; + ssp->port_id = 3; c->num_chipselect = 1; c->tx_param = &mrfld3_tx_param; c->rx_param = &mrfld3_rx_param; break; case 1: - c->port_id = 5; + ssp->port_id = 5; c->num_chipselect = 4; c->tx_param = &mrfld5_tx_param; c->rx_param = &mrfld5_rx_param; break; case 2: - c->port_id = 6; + ssp->port_id = 6; c->num_chipselect = 1; c->tx_param = &mrfld6_tx_param; c->rx_param = &mrfld6_rx_param; @@ -218,8 +215,9 @@ static int mrfld_spi_setup(struct pci_dev *dev, struct pxa_spi_info *c) return -ENODEV; } - c->type = MRFLD_SSP; - c->max_clk_rate = 25000000; + ret = pxa2xx_spi_pci_clk_register(dev, ssp, 25000000); + if (ret) + return ret; dma_dev = pci_get_slot(dev->bus, PCI_DEVFN(21, 0)); ret = devm_add_action_or_reset(&dev->dev, lpss_dma_put_device, dma_dev); @@ -234,6 +232,7 @@ static int mrfld_spi_setup(struct pci_dev *dev, struct pxa_spi_info *c) c->dma_filter = lpss_dma_filter; c->dma_burst_size = 8; + c->enable_dma = 1; return 0; } @@ -241,14 +240,15 @@ static struct pxa_spi_info mrfld_info_config = { .setup = mrfld_spi_setup, }; -static int qrk_spi_setup(struct pci_dev *dev, struct pxa_spi_info *c) +static int qrk_spi_setup(struct pci_dev *dev, struct pxa2xx_spi_controller *c) { - c->type = QUARK_X1000_SSP; - c->port_id = dev->devfn; + struct ssp_device *ssp = &c->ssp; + + ssp->type = QUARK_X1000_SSP; + ssp->port_id = dev->devfn; c->num_chipselect = 1; - c->max_clk_rate = 50000000; - return 0; + return pxa2xx_spi_pci_clk_register(dev, ssp, 50000000); } static struct pxa_spi_info qrk_info_config = { @@ -262,8 +262,8 @@ static int pxa2xx_spi_pci_probe(struct pci_dev *dev, int ret; struct platform_device *pdev; struct pxa2xx_spi_controller spi_pdata; + struct pxa_spi_info *info; struct ssp_device *ssp; - struct pxa_spi_info *c; ret = pcim_enable_device(dev); if (ret) @@ -273,25 +273,17 @@ static int pxa2xx_spi_pci_probe(struct pci_dev *dev, if (ret) return ret; - c = (struct pxa_spi_info *)ent->driver_data; - ret = c->setup(dev, c); - if (ret) - return ret; - memset(&spi_pdata, 0, sizeof(spi_pdata)); - spi_pdata.num_chipselect = c->num_chipselect; - spi_pdata.dma_filter = c->dma_filter; - spi_pdata.tx_param = c->tx_param; - spi_pdata.rx_param = c->rx_param; - spi_pdata.enable_dma = c->rx_param && c->tx_param; - spi_pdata.dma_burst_size = c->dma_burst_size; ssp = &spi_pdata.ssp; ssp->dev = &dev->dev; ssp->phys_base = pci_resource_start(dev, 0); ssp->mmio_base = pcim_iomap_table(dev)[0]; - ssp->type = c->type; - ssp->port_id = c->port_id; + + info = (struct pxa_spi_info *)ent->driver_data; + ret = info->setup(dev, &spi_pdata); + if (ret) + return ret; pci_set_master(dev); @@ -300,10 +292,6 @@ static int pxa2xx_spi_pci_probe(struct pci_dev *dev, return ret; ssp->irq = pci_irq_vector(dev, 0); - ret = pxa2xx_spi_pci_clk_register(dev, ssp, c->max_clk_rate); - if (ret) - return ret; - memset(&pi, 0, sizeof(pi)); pi.fwnode = dev_fwnode(&dev->dev); pi.parent = &dev->dev; -- cgit v1.2.3 From fcaaf76ed5f3bbf346db9e49d9d9c0978d8f8dce Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 25 Feb 2022 19:23:50 +0200 Subject: spi: pxa2xx-pci: Constify struct pxa_spi_info variables Now when there are no dynamical changes required, we may constify struct pxa_spi_info variables. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20220225172350.69797-11-andriy.shevchenko@linux.intel.com Signed-off-by: Mark Brown --- drivers/spi/spi-pxa2xx-pci.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/spi/spi-pxa2xx-pci.c b/drivers/spi/spi-pxa2xx-pci.c index 3c5d14affa95..861b21c63504 100644 --- a/drivers/spi/spi-pxa2xx-pci.c +++ b/drivers/spi/spi-pxa2xx-pci.c @@ -164,7 +164,7 @@ static int lpss_spi_setup(struct pci_dev *dev, struct pxa2xx_spi_controller *c) return 0; } -static struct pxa_spi_info lpss_info_config = { +static const struct pxa_spi_info lpss_info_config = { .setup = lpss_spi_setup, }; @@ -179,7 +179,7 @@ static int ce4100_spi_setup(struct pci_dev *dev, struct pxa2xx_spi_controller *c return pxa2xx_spi_pci_clk_register(dev, ssp, 3686400); } -static struct pxa_spi_info ce4100_info_config = { +static const struct pxa_spi_info ce4100_info_config = { .setup = ce4100_spi_setup, }; @@ -236,7 +236,7 @@ static int mrfld_spi_setup(struct pci_dev *dev, struct pxa2xx_spi_controller *c) return 0; } -static struct pxa_spi_info mrfld_info_config = { +static const struct pxa_spi_info mrfld_info_config = { .setup = mrfld_spi_setup, }; @@ -251,18 +251,18 @@ static int qrk_spi_setup(struct pci_dev *dev, struct pxa2xx_spi_controller *c) return pxa2xx_spi_pci_clk_register(dev, ssp, 50000000); } -static struct pxa_spi_info qrk_info_config = { +static const struct pxa_spi_info qrk_info_config = { .setup = qrk_spi_setup, }; 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 pxa_spi_info *info; struct ssp_device *ssp; ret = pcim_enable_device(dev); -- cgit v1.2.3 From 6bb477df04366e0f69dd2f49e1ae1099069326bc Mon Sep 17 00:00:00 2001 From: Yun Zhou Date: Thu, 17 Feb 2022 22:12:34 +0800 Subject: spi: use specific last_cs instead of last_cs_enable Commit d40f0b6f2e21 instroduced last_cs_enable to avoid setting chipselect if it's not necessary, but it also introduces a bug. The chipselect may not be set correctly on multi-device SPI busses. The reason is that we can't judge the chipselect by bool last_cs_enable, since chipselect may be modified after other devices were accessed. So we should record the specific state of chipselect in case of confusion. Signed-off-by: Yun Zhou Link: https://lore.kernel.org/r/20220217141234.72737-1-yun.zhou@windriver.com Signed-off-by: Mark Brown --- drivers/spi/spi.c | 8 ++++++-- include/linux/spi/spi.h | 5 +++-- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index cd4dc3131e17..6326e592fcfd 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -926,13 +926,14 @@ static void spi_set_cs(struct spi_device *spi, bool enable, bool force) * Avoid calling into the driver (or doing delays) if the chip select * isn't actually changing from the last time this was called. */ - if (!force && (spi->controller->last_cs_enable == enable) && + if (!force && ((enable && spi->controller->last_cs == spi->chip_select) || + (!enable && spi->controller->last_cs != spi->chip_select)) && (spi->controller->last_cs_mode_high == (spi->mode & SPI_CS_HIGH))) return; trace_spi_set_cs(spi, activate); - spi->controller->last_cs_enable = enable; + spi->controller->last_cs = enable ? spi->chip_select : -1; spi->controller->last_cs_mode_high = spi->mode & SPI_CS_HIGH; if ((spi->cs_gpiod || !spi->controller->set_cs_timing) && !activate) { @@ -3016,6 +3017,9 @@ int spi_register_controller(struct spi_controller *ctlr) goto free_bus_id; } + /* setting last_cs to -1 means no chip selected */ + ctlr->last_cs = -1; + status = device_add(&ctlr->dev); if (status < 0) goto free_bus_id; diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h index 579d71cdf6fa..7d005fa4631c 100644 --- a/include/linux/spi/spi.h +++ b/include/linux/spi/spi.h @@ -370,7 +370,8 @@ extern struct spi_device *spi_new_ancillary_device(struct spi_device *spi, u8 ch * @cur_msg_prepared: spi_prepare_message was called for the currently * in-flight message * @cur_msg_mapped: message has been mapped for DMA - * @last_cs_enable: was enable true on the last call to set_cs. + * @last_cs: the last chip_select that is recorded by set_cs, -1 on non chip + * selected * @last_cs_mode_high: was (mode & SPI_CS_HIGH) true on the last call to set_cs. * @xfer_completion: used by core transfer_one_message() * @busy: message pump is busy @@ -603,7 +604,7 @@ struct spi_controller { bool auto_runtime_pm; bool cur_msg_prepared; bool cur_msg_mapped; - bool last_cs_enable; + char last_cs; bool last_cs_mode_high; bool fallback; struct completion xfer_completion; -- cgit v1.2.3 From f16ed63e53c79070283d3c264de5309794272ae9 Mon Sep 17 00:00:00 2001 From: Lad Prabhakar Date: Sun, 27 Feb 2022 22:59:56 +0000 Subject: spi: dt-bindings: renesas,rspi: Document RZ/V2L SoC Add RSPI binding documentation for Renesas RZ/V2L SoC. RSPI block is identical to one found on RZ/A, so no driver changes are required. The fallback compatible string "renesas,rspi-rz" will be used on RZ/V2L. Signed-off-by: Lad Prabhakar Reviewed-by: Biju Das Acked-by: Krzysztof Kozlowski Reviewed-by: Geert Uytterhoeven Link: https://lore.kernel.org/r/20220227225956.29570-1-prabhakar.mahadev-lad.rj@bp.renesas.com Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/spi/renesas,rspi.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Documentation/devicetree/bindings/spi/renesas,rspi.yaml b/Documentation/devicetree/bindings/spi/renesas,rspi.yaml index 76e6d9e52fc7..a902f0ca2198 100644 --- a/Documentation/devicetree/bindings/spi/renesas,rspi.yaml +++ b/Documentation/devicetree/bindings/spi/renesas,rspi.yaml @@ -22,6 +22,7 @@ properties: - renesas,rspi-r7s72100 # RZ/A1H - renesas,rspi-r7s9210 # RZ/A2 - renesas,r9a07g044-rspi # RZ/G2{L,LC} + - renesas,r9a07g054-rspi # RZ/V2L - const: renesas,rspi-rz # RZ/A and RZ/G2{L,LC} - items: @@ -124,6 +125,7 @@ allOf: enum: - renesas,qspi - renesas,r9a07g044-rspi + - renesas,r9a07g054-rspi then: required: - resets -- cgit v1.2.3 From ee8ad9440f18478796dbd7e0891efcc44376ab70 Mon Sep 17 00:00:00 2001 From: Lad Prabhakar Date: Tue, 1 Mar 2022 13:42:43 +0000 Subject: spi: dt-bindings: renesas,rspi: Drop comment for generic compatible string Drop comment "# RZ/A and RZ/G2{L,LC}" for generic compatible string "renesas,rspi-rz" as this will avoid changing the line for every new SoC addition. Suggested-by: Geert Uytterhoeven Signed-off-by: Lad Prabhakar Link: https://lore.kernel.org/r/20220301134244.20174-1-prabhakar.mahadev-lad.rj@bp.renesas.com Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/spi/renesas,rspi.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/spi/renesas,rspi.yaml b/Documentation/devicetree/bindings/spi/renesas,rspi.yaml index a902f0ca2198..2c3c6bd6ec45 100644 --- a/Documentation/devicetree/bindings/spi/renesas,rspi.yaml +++ b/Documentation/devicetree/bindings/spi/renesas,rspi.yaml @@ -23,7 +23,7 @@ properties: - renesas,rspi-r7s9210 # RZ/A2 - renesas,r9a07g044-rspi # RZ/G2{L,LC} - renesas,r9a07g054-rspi # RZ/V2L - - const: renesas,rspi-rz # RZ/A and RZ/G2{L,LC} + - const: renesas,rspi-rz - items: - enum: -- cgit v1.2.3 From d149dd2a806b9d11e570c3731eca8bda3c5f6238 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Tue, 1 Mar 2022 15:23:57 -0600 Subject: spi: dt-bindings: mediatek: Set min size for 'mediatek,pad-select' The minimum array length defaults to the same size as the maximum. For 'mediatek,pad-select', the example has a length of 2 and in-tree .dts files have a length of 1, but the schema says the length must be 4. There's currently no warning in the example because the schema fixups are not handling this case correctly. Signed-off-by: Rob Herring Link: https://lore.kernel.org/r/20220301212358.1887668-1-robh@kernel.org Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/spi/mediatek,spi-mt65xx.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/spi/mediatek,spi-mt65xx.yaml b/Documentation/devicetree/bindings/spi/mediatek,spi-mt65xx.yaml index bfa44acb1bdd..ac9ff12ae27a 100644 --- a/Documentation/devicetree/bindings/spi/mediatek,spi-mt65xx.yaml +++ b/Documentation/devicetree/bindings/spi/mediatek,spi-mt65xx.yaml @@ -62,6 +62,7 @@ properties: mediatek,pad-select: $ref: /schemas/types.yaml#/definitions/uint32-array + minItems: 1 maxItems: 4 items: enum: [0, 1, 2, 3] -- cgit v1.2.3 From 13262fc26c1837c51a5131dbbdd67a2387f8bfc7 Mon Sep 17 00:00:00 2001 From: Jiasheng Jiang Date: Wed, 2 Mar 2022 17:20:51 +0800 Subject: spi: spi-zynqmp-gqspi: Handle error for dma_set_mask As the potential failure of the dma_set_mask(), it should be better to check it and return error if fails. Fixes: 126bdb606fd2 ("spi: spi-zynqmp-gqspi: return -ENOMEM if dma_map_single fails") Signed-off-by: Jiasheng Jiang Link: https://lore.kernel.org/r/20220302092051.121343-1-jiasheng@iscas.ac.cn Signed-off-by: Mark Brown --- drivers/spi/spi-zynqmp-gqspi.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/spi/spi-zynqmp-gqspi.c b/drivers/spi/spi-zynqmp-gqspi.c index 328b6559bb19..2b5afae8ff7f 100644 --- a/drivers/spi/spi-zynqmp-gqspi.c +++ b/drivers/spi/spi-zynqmp-gqspi.c @@ -1172,7 +1172,10 @@ static int zynqmp_qspi_probe(struct platform_device *pdev) goto clk_dis_all; } - dma_set_mask(&pdev->dev, DMA_BIT_MASK(44)); + ret = dma_set_mask(&pdev->dev, DMA_BIT_MASK(44)); + if (ret) + goto clk_dis_all; + ctlr->bits_per_word_mask = SPI_BPW_MASK(8); ctlr->num_chipselect = GQSPI_DEFAULT_NUM_CS; ctlr->mem_ops = &zynqmp_qspi_mem_ops; -- cgit v1.2.3 From dc8fea13f98ace0ae8815dd44d1e60c184f3f930 Mon Sep 17 00:00:00 2001 From: "Minghao Chi (CGEL ZTE)" Date: Thu, 3 Mar 2022 09:21:31 +0000 Subject: spi: Use of_device_get_match_data() Use of_device_get_match_data() to simplify the code. Reported-by: Zeal Robot Signed-off-by: Minghao Chi (CGEL ZTE) Link: https://lore.kernel.org/r/20220303092131.2060044-1-chi.minghao@zte.com.cn Signed-off-by: Mark Brown --- drivers/spi/spi-npcm-fiu.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/spi/spi-npcm-fiu.c b/drivers/spi/spi-npcm-fiu.c index b62471ab6d7f..71ed75bf0a20 100644 --- a/drivers/spi/spi-npcm-fiu.c +++ b/drivers/spi/spi-npcm-fiu.c @@ -671,7 +671,6 @@ static const struct of_device_id npcm_fiu_dt_ids[] = { static int npcm_fiu_probe(struct platform_device *pdev) { const struct fiu_data *fiu_data_match; - const struct of_device_id *match; struct device *dev = &pdev->dev; struct spi_controller *ctrl; struct npcm_fiu_spi *fiu; @@ -685,13 +684,12 @@ static int npcm_fiu_probe(struct platform_device *pdev) fiu = spi_controller_get_devdata(ctrl); - match = of_match_device(npcm_fiu_dt_ids, dev); - if (!match || !match->data) { + fiu_data_match = of_device_get_match_data(dev); + if (!fiu_data_match) { dev_err(dev, "No compatible OF match\n"); return -ENODEV; } - fiu_data_match = match->data; id = of_alias_get_id(dev->of_node, "fiu"); if (id < 0 || id >= fiu_data_match->fiu_max) { dev_err(dev, "Invalid platform device id: %d\n", id); -- cgit v1.2.3 From 9729cad0278b4fdde172bb7b5da65bd1a0e0fb8b Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Tue, 11 Jan 2022 18:48:02 +0100 Subject: dt-bindings: extcon: maxim,max77843: Add MAX77843 bindings Document the bindings for MAX77843 MUIC/extcon driver, based on Exynos5433 TM2 devicetree. These are neither accurate nor finished bindings but at least allow parsing existing DTS files. Signed-off-by: Krzysztof Kozlowski Reviewed-by: Rob Herring Signed-off-by: Lee Jones Link: https://lore.kernel.org/r/20220111174805.223732-3-krzysztof.kozlowski@canonical.com --- .../devicetree/bindings/extcon/maxim,max77843.yaml | 40 ++++++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 Documentation/devicetree/bindings/extcon/maxim,max77843.yaml diff --git a/Documentation/devicetree/bindings/extcon/maxim,max77843.yaml b/Documentation/devicetree/bindings/extcon/maxim,max77843.yaml new file mode 100644 index 000000000000..f9ffe3d6f957 --- /dev/null +++ b/Documentation/devicetree/bindings/extcon/maxim,max77843.yaml @@ -0,0 +1,40 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/extcon/maxim,max77843.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Maxim MAX77843 MicroUSB and Companion Power Management IC Extcon + +maintainers: + - Chanwoo Choi + - Krzysztof Kozlowski + +description: | + This is a part of device tree bindings for Maxim MAX77843 MicroUSB + Integrated Circuit (MUIC). + + See also Documentation/devicetree/bindings/mfd/maxim,max77843.yaml for + additional information and example. + +properties: + compatible: + const: maxim,max77843-muic + + connector: + $ref: /schemas/connector/usb-connector.yaml# + + ports: + $ref: /schemas/graph.yaml#/properties/port + description: + Any connector to the data bus of this controller should be modelled using + the OF graph bindings specified + properties: + port: + $ref: /schemas/graph.yaml#/properties/port + +required: + - compatible + - connector + +additionalProperties: false -- cgit v1.2.3 From 77357c50e4003f38e3e058fa64ae5e84dec414a3 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Tue, 11 Jan 2022 18:48:03 +0100 Subject: regulator: dt-bindings: maxim,max77843: Add MAX77843 bindings Document the bindings for MAX77843 regulator driver. The bindings are almost identical to MAX77693 bindings, except the actual names of regulators. Signed-off-by: Krzysztof Kozlowski Reviewed-by: Mark Brown Reviewed-by: Rob Herring Signed-off-by: Lee Jones Link: https://lore.kernel.org/r/20220111174805.223732-4-krzysztof.kozlowski@canonical.com --- .../bindings/regulator/maxim,max77843.yaml | 65 ++++++++++++++++++++++ 1 file changed, 65 insertions(+) create mode 100644 Documentation/devicetree/bindings/regulator/maxim,max77843.yaml diff --git a/Documentation/devicetree/bindings/regulator/maxim,max77843.yaml b/Documentation/devicetree/bindings/regulator/maxim,max77843.yaml new file mode 100644 index 000000000000..a963025e96c1 --- /dev/null +++ b/Documentation/devicetree/bindings/regulator/maxim,max77843.yaml @@ -0,0 +1,65 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/regulator/maxim,max77843.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Maxim MAX77843 MicroUSB and Companion Power Management IC regulators + +maintainers: + - Krzysztof Kozlowski + +description: | + This is a part of device tree bindings for Maxim MAX77843 MicroUSB Integrated + Circuit (MUIC). + + See also Documentation/devicetree/bindings/mfd/maxim,max77843.yaml for + additional information and example. + +properties: + compatible: + const: maxim,max77843-regulator + + CHARGER: + type: object + $ref: regulator.yaml# + additionalProperties: false + description: | + Current regulator. + + properties: + regulator-name: true + regulator-always-on: true + regulator-boot-on: true + regulator-min-microamp: + minimum: 100000 + regulator-max-microamp: + maximum: 3150000 + + required: + - regulator-name + +patternProperties: + "^SAFEOUT[12]$": + type: object + $ref: regulator.yaml# + additionalProperties: false + description: | + Safeout LDO regulator. + + properties: + regulator-name: true + regulator-always-on: true + regulator-boot-on: true + regulator-min-microvolt: + minimum: 3300000 + regulator-max-microvolt: + maximum: 4950000 + + required: + - regulator-name + +required: + - compatible + +additionalProperties: false -- cgit v1.2.3 From 4fddb6211da1749a5fb683a33d7d4890d1290b1b Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Tue, 11 Jan 2022 18:48:04 +0100 Subject: dt-bindings: mfd: maxim,max77843: Add MAX77843 bindings Document the bindings for MAX77843 MFD driver, based on Exynos5433 TM2 devicetree. These are neither accurate nor finished bindings but at least allow parsing existing DTS files. The example DTS was copied from existing DTS (exynos5433-tm2-common.dtsi), so keep the license as GPL-2.0-only. Signed-off-by: Krzysztof Kozlowski Reviewed-by: Rob Herring Signed-off-by: Lee Jones Link: https://lore.kernel.org/r/20220111174805.223732-5-krzysztof.kozlowski@canonical.com --- .../devicetree/bindings/mfd/maxim,max77843.yaml | 144 +++++++++++++++++++++ 1 file changed, 144 insertions(+) create mode 100644 Documentation/devicetree/bindings/mfd/maxim,max77843.yaml diff --git a/Documentation/devicetree/bindings/mfd/maxim,max77843.yaml b/Documentation/devicetree/bindings/mfd/maxim,max77843.yaml new file mode 100644 index 000000000000..61a0f9dcb983 --- /dev/null +++ b/Documentation/devicetree/bindings/mfd/maxim,max77843.yaml @@ -0,0 +1,144 @@ +# SPDX-License-Identifier: GPL-2.0-only +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/mfd/maxim,max77843.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Maxim MAX77843 MicroUSB and Companion Power Management IC + +maintainers: + - Krzysztof Kozlowski + +description: | + This is a part of device tree bindings for Maxim MAX77843 MicroUSB + Integrated Circuit (MUIC). + + The Maxim MAX77843 is a MicroUSB and Companion Power Management IC which + includes voltage current regulators, charger, fuel-gauge, haptic motor driver + and MicroUSB management IC. + +properties: + compatible: + const: maxim,max77843 + + interrupts: + maxItems: 1 + + reg: + maxItems: 1 + + extcon: + $ref: /schemas/extcon/maxim,max77843.yaml + + motor-driver: + type: object + properties: + compatible: + const: maxim,max77843-haptic + + haptic-supply: + description: Power supply to the haptic motor + + pwms: + maxItems: 1 + + required: + - compatible + - haptic-supply + - pwms + + regulators: + $ref: /schemas/regulator/maxim,max77843.yaml + +required: + - compatible + - interrupts + - reg + +additionalProperties: false + +examples: + - | + #include + + i2c { + #address-cells = <1>; + #size-cells = <0>; + + pmic@66 { + compatible = "maxim,max77843"; + interrupt-parent = <&gpa1>; + interrupts = <5 IRQ_TYPE_EDGE_FALLING>; + reg = <0x66>; + + extcon { + compatible = "maxim,max77843-muic"; + + connector { + compatible = "samsung,usb-connector-11pin", + "usb-b-connector"; + label = "micro-USB"; + type = "micro"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + /* + * TODO: The DTS this is based on does not have + * port@0 which is a required property. The ports + * look incomplete and need fixing. + * Add a disabled port just to satisfy dtschema. + */ + reg = <0>; + status = "disabled"; + }; + + port@3 { + reg = <3>; + endpoint { + remote-endpoint = <&mhl_to_musb_con>; + }; + }; + }; + }; + + ports { + port { + endpoint { + remote-endpoint = <&usb_to_muic>; + }; + }; + }; + }; + + regulators { + compatible = "maxim,max77843-regulator"; + + SAFEOUT1 { + regulator-name = "SAFEOUT1"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <4950000>; + }; + + SAFEOUT2 { + regulator-name = "SAFEOUT2"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <4950000>; + }; + + CHARGER { + regulator-name = "CHARGER"; + regulator-min-microamp = <100000>; + regulator-max-microamp = <3150000>; + }; + }; + + motor-driver { + compatible = "maxim,max77843-haptic"; + haptic-supply = <&ldo38_reg>; + pwms = <&pwm 0 33670 0>; + }; + }; + }; -- cgit v1.2.3 From 04732ff2a1f0f4c37164a788af2a69a01d6c6191 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Tue, 11 Jan 2022 18:48:05 +0100 Subject: MAINTAINERS: mfd: Cover MAX77843 by Maxim PMIC/MUIC for Exynos boards entry The MAX77843 is used in Exynos5433-based TM2 boards and shares some parts of code with MAX77693 (regulator and haptic motor drivers). Include all MAX77843 drivers in the entry for Maxim PMIC/MUIC drivers for Exynos boards, so they will receive some dedicated review coverage. Signed-off-by: Krzysztof Kozlowski Signed-off-by: Lee Jones Link: https://lore.kernel.org/r/20220111174805.223732-6-krzysztof.kozlowski@canonical.com --- MAINTAINERS | 2 ++ 1 file changed, 2 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index ea3e6c914384..ecb875856ca1 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -11720,9 +11720,11 @@ M: Bartlomiej Zolnierkiewicz L: linux-kernel@vger.kernel.org S: Supported F: Documentation/devicetree/bindings/*/maxim,max77686.yaml +F: Documentation/devicetree/bindings/*/maxim,max77843.yaml F: Documentation/devicetree/bindings/clock/maxim,max77686.txt F: Documentation/devicetree/bindings/mfd/max14577.txt F: Documentation/devicetree/bindings/mfd/max77693.txt +F: drivers/*/*max77843.c F: drivers/*/max14577*.c F: drivers/*/max77686*.c F: drivers/*/max77693*.c -- cgit v1.2.3 From 0ff4827ed66f3cdb9d4f5cfad4a3c211215ff4f0 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Mon, 24 Jan 2022 09:23:44 +0100 Subject: spi: dt-bindings: samsung: Convert to dtschema Convert the Samsung SoC (S3C24xx, S3C64xx, S5Pv210, Exynos) SPI controller bindings to DT schema format. The conversion also drops requirement from providing controller-data and its data for each of SPI peripheral device nodes. The dtschema cannot express this and the requirement is being relaxed in the driver now. Signed-off-by: Krzysztof Kozlowski Reviewed-by: Sam Protsenko Acked-by: Pratyush Yadav Reviewed-by: Mark Brown Reviewed-by: Rob Herring Signed-off-by: Lee Jones Link: https://lore.kernel.org/r/20220124082347.32747-2-krzysztof.kozlowski@canonical.com --- .../bindings/soc/samsung/exynos-usi.yaml | 2 +- .../bindings/spi/samsung,spi-peripheral-props.yaml | 33 ++++ .../devicetree/bindings/spi/samsung,spi.yaml | 187 +++++++++++++++++++++ .../bindings/spi/spi-peripheral-props.yaml | 1 + .../devicetree/bindings/spi/spi-samsung.txt | 122 -------------- MAINTAINERS | 2 +- 6 files changed, 223 insertions(+), 124 deletions(-) create mode 100644 Documentation/devicetree/bindings/spi/samsung,spi-peripheral-props.yaml create mode 100644 Documentation/devicetree/bindings/spi/samsung,spi.yaml delete mode 100644 Documentation/devicetree/bindings/spi/spi-samsung.txt diff --git a/Documentation/devicetree/bindings/soc/samsung/exynos-usi.yaml b/Documentation/devicetree/bindings/soc/samsung/exynos-usi.yaml index 273f2d95a043..e72b6a3fae99 100644 --- a/Documentation/devicetree/bindings/soc/samsung/exynos-usi.yaml +++ b/Documentation/devicetree/bindings/soc/samsung/exynos-usi.yaml @@ -22,7 +22,7 @@ description: | [1] Documentation/devicetree/bindings/serial/samsung_uart.yaml [2] Documentation/devicetree/bindings/i2c/i2c-exynos5.txt - [3] Documentation/devicetree/bindings/spi/spi-samsung.txt + [3] Documentation/devicetree/bindings/spi/samsung,spi.yaml properties: $nodename: diff --git a/Documentation/devicetree/bindings/spi/samsung,spi-peripheral-props.yaml b/Documentation/devicetree/bindings/spi/samsung,spi-peripheral-props.yaml new file mode 100644 index 000000000000..f0db3fb3d688 --- /dev/null +++ b/Documentation/devicetree/bindings/spi/samsung,spi-peripheral-props.yaml @@ -0,0 +1,33 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/spi/samsung,spi-peripheral-props.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Peripheral-specific properties for Samsung S3C/S5P/Exynos SoC SPI controller + +maintainers: + - Krzysztof Kozlowski + +description: + See spi-peripheral-props.yaml for more info. + +properties: + controller-data: + type: object + additionalProperties: false + + properties: + samsung,spi-feedback-delay: + description: | + The sampling phase shift to be applied on the miso line (to account + for any lag in the miso line). Valid values: + - 0: No phase shift. + - 1: 90 degree phase shift sampling. + - 2: 180 degree phase shift sampling. + - 3: 270 degree phase shift sampling. + $ref: /schemas/types.yaml#/definitions/uint32 + enum: [0, 1, 2, 3] + default: 0 + +additionalProperties: true diff --git a/Documentation/devicetree/bindings/spi/samsung,spi.yaml b/Documentation/devicetree/bindings/spi/samsung,spi.yaml new file mode 100644 index 000000000000..61c77088e8ee --- /dev/null +++ b/Documentation/devicetree/bindings/spi/samsung,spi.yaml @@ -0,0 +1,187 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/spi/samsung,spi.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Samsung S3C/S5P/Exynos SoC SPI controller + +maintainers: + - Krzysztof Kozlowski + +description: + All the SPI controller nodes should be represented in the aliases node using + the following format 'spi{n}' where n is a unique number for the alias. + +properties: + compatible: + oneOf: + - enum: + - samsung,s3c2443-spi # for S3C2443, S3C2416 and S3C2450 + - samsung,s3c6410-spi + - samsung,s5pv210-spi # for S5PV210 and S5PC110 + - samsung,exynos5433-spi + - const: samsung,exynos7-spi + deprecated: true + + clocks: + minItems: 2 + maxItems: 3 + + clock-names: + minItems: 2 + maxItems: 3 + + cs-gpios: true + + dmas: + minItems: 2 + maxItems: 2 + + dma-names: + items: + - const: tx + - const: rx + + interrupts: + maxItems: 1 + + no-cs-readback: + description: + The CS line is disconnected, therefore the device should not operate + based on CS signalling. + type: boolean + + num-cs: + minimum: 1 + maximum: 4 + default: 1 + + samsung,spi-src-clk: + description: + If the spi controller includes a internal clock mux to select the clock + source for the spi bus clock, this property can be used to indicate the + clock to be used for driving the spi bus clock. If not specified, the + clock number 0 is used as default. + $ref: /schemas/types.yaml#/definitions/uint32 + default: 0 + + reg: + maxItems: 1 + +required: + - compatible + - clocks + - clock-names + - dmas + - dma-names + - interrupts + - reg + +allOf: + - $ref: spi-controller.yaml# + - if: + properties: + compatible: + contains: + const: samsung,exynos5433-spi + then: + properties: + clocks: + minItems: 3 + maxItems: 3 + clock-names: + items: + - const: spi + - enum: + - spi_busclk0 + - spi_busclk1 + - spi_busclk2 + - spi_busclk3 + - const: spi_ioclk + else: + properties: + clocks: + minItems: 2 + maxItems: 2 + clock-names: + items: + - const: spi + - enum: + - spi_busclk0 + - spi_busclk1 + - spi_busclk2 + - spi_busclk3 + +unevaluatedProperties: false + +examples: + - | + #include + #include + #include + #include + + spi@14d30000 { + compatible = "samsung,exynos5433-spi"; + reg = <0x14d30000 0x100>; + interrupts = ; + dmas = <&pdma0 11>, <&pdma0 10>; + dma-names = "tx", "rx"; + #address-cells = <1>; + #size-cells = <0>; + clocks = <&cmu_peric CLK_PCLK_SPI1>, + <&cmu_peric CLK_SCLK_SPI1>, + <&cmu_peric CLK_SCLK_IOCLK_SPI1>; + clock-names = "spi", + "spi_busclk0", + "spi_ioclk"; + samsung,spi-src-clk = <0>; + pinctrl-names = "default"; + pinctrl-0 = <&spi1_bus>; + num-cs = <1>; + + cs-gpios = <&gpd6 3 GPIO_ACTIVE_HIGH>; + + audio-codec@0 { + compatible = "wlf,wm5110"; + reg = <0x0>; + spi-max-frequency = <20000000>; + interrupt-parent = <&gpa0>; + interrupts = <4 IRQ_TYPE_NONE>; + clocks = <&pmu_system_controller 0>, + <&s2mps13_osc S2MPS11_CLK_BT>; + clock-names = "mclk1", "mclk2"; + + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + + wlf,micd-detect-debounce = <300>; + wlf,micd-bias-start-time = <0x1>; + wlf,micd-rate = <0x7>; + wlf,micd-dbtime = <0x2>; + wlf,micd-force-micbias; + wlf,micd-configs = <0x0 1 0>; + wlf,hpdet-channel = <1>; + wlf,gpsw = <0x1>; + wlf,inmode = <2 0 2 0>; + + wlf,reset = <&gpc0 7 GPIO_ACTIVE_HIGH>; + wlf,ldoena = <&gpf0 0 GPIO_ACTIVE_HIGH>; + + /* core supplies */ + AVDD-supply = <&ldo18_reg>; + DBVDD1-supply = <&ldo18_reg>; + CPVDD-supply = <&ldo18_reg>; + DBVDD2-supply = <&ldo18_reg>; + DBVDD3-supply = <&ldo18_reg>; + SPKVDDL-supply = <&ldo18_reg>; + SPKVDDR-supply = <&ldo18_reg>; + + controller-data { + samsung,spi-feedback-delay = <0>; + }; + }; + }; diff --git a/Documentation/devicetree/bindings/spi/spi-peripheral-props.yaml b/Documentation/devicetree/bindings/spi/spi-peripheral-props.yaml index 5dd209206e88..df885eeb144f 100644 --- a/Documentation/devicetree/bindings/spi/spi-peripheral-props.yaml +++ b/Documentation/devicetree/bindings/spi/spi-peripheral-props.yaml @@ -85,5 +85,6 @@ properties: # The controller specific properties go here. allOf: - $ref: cdns,qspi-nor-peripheral-props.yaml# + - $ref: samsung,spi-peripheral-props.yaml# additionalProperties: true diff --git a/Documentation/devicetree/bindings/spi/spi-samsung.txt b/Documentation/devicetree/bindings/spi/spi-samsung.txt deleted file mode 100644 index 49028a4f5df1..000000000000 --- a/Documentation/devicetree/bindings/spi/spi-samsung.txt +++ /dev/null @@ -1,122 +0,0 @@ -* Samsung SPI Controller - -The Samsung SPI controller is used to interface with various devices such as flash -and display controllers using the SPI communication interface. - -Required SoC Specific Properties: - -- compatible: should be one of the following. - - samsung,s3c2443-spi: for s3c2443, s3c2416 and s3c2450 platforms - - samsung,s3c6410-spi: for s3c6410 platforms - - samsung,s5pv210-spi: for s5pv210 and s5pc110 platforms - - samsung,exynos5433-spi: for exynos5433 compatible controllers - - samsung,exynos7-spi: for exynos7 platforms - -- reg: physical base address of the controller and length of memory mapped - region. - -- interrupts: The interrupt number to the cpu. The interrupt specifier format - depends on the interrupt controller. - -- dmas : Two or more DMA channel specifiers following the convention outlined - in bindings/dma/dma.txt - -- dma-names: Names for the dma channels. There must be at least one channel - named "tx" for transmit and named "rx" for receive. - -- clocks: specifies the clock IDs provided to the SPI controller; they are - required for interacting with the controller itself, for synchronizing the bus - and as I/O clock (the latter is required by exynos5433 and exynos7). - -- clock-names: string names of the clocks in the 'clocks' property; for all the - the devices the names must be "spi", "spi_busclkN" (where N is determined by - "samsung,spi-src-clk"), while Exynos5433 should specify a third clock - "spi_ioclk" for the I/O clock. - -Required Board Specific Properties: - -- #address-cells: should be 1. -- #size-cells: should be 0. - -Optional Board Specific Properties: - -- samsung,spi-src-clk: If the spi controller includes a internal clock mux to - select the clock source for the spi bus clock, this property can be used to - indicate the clock to be used for driving the spi bus clock. If not specified, - the clock number 0 is used as default. - -- num-cs: Specifies the number of chip select lines supported. If - not specified, the default number of chip select lines is set to 1. - -- cs-gpios: should specify GPIOs used for chipselects (see spi-bus.txt) - -- no-cs-readback: the CS line is disconnected, therefore the device should not - operate based on CS signalling. - -SPI Controller specific data in SPI slave nodes: - -- The spi slave nodes should provide the following information which is required - by the spi controller. - - - samsung,spi-feedback-delay: The sampling phase shift to be applied on the - miso line (to account for any lag in the miso line). The following are the - valid values. - - - 0: No phase shift. - - 1: 90 degree phase shift sampling. - - 2: 180 degree phase shift sampling. - - 3: 270 degree phase shift sampling. - -Aliases: - -- All the SPI controller nodes should be represented in the aliases node using - the following format 'spi{n}' where n is a unique number for the alias. - - -Example: - -- SoC Specific Portion: - - spi_0: spi@12d20000 { - compatible = "samsung,exynos4210-spi"; - reg = <0x12d20000 0x100>; - interrupts = <0 66 0>; - dmas = <&pdma0 5 - &pdma0 4>; - dma-names = "tx", "rx"; - #address-cells = <1>; - #size-cells = <0>; - }; - -- Board Specific Portion: - - spi_0: spi@12d20000 { - #address-cells = <1>; - #size-cells = <0>; - pinctrl-names = "default"; - pinctrl-0 = <&spi0_bus>; - cs-gpios = <&gpa2 5 0>; - - w25q80bw@0 { - #address-cells = <1>; - #size-cells = <1>; - compatible = "w25x80"; - reg = <0>; - spi-max-frequency = <10000>; - - controller-data { - samsung,spi-feedback-delay = <0>; - }; - - partition@0 { - label = "U-Boot"; - reg = <0x0 0x40000>; - read-only; - }; - - partition@40000 { - label = "Kernel"; - reg = <0x40000 0xc0000>; - }; - }; - }; diff --git a/MAINTAINERS b/MAINTAINERS index ecb875856ca1..23202ad1f5f7 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -17091,7 +17091,7 @@ M: Andi Shyti L: linux-spi@vger.kernel.org L: linux-samsung-soc@vger.kernel.org S: Maintained -F: Documentation/devicetree/bindings/spi/spi-samsung.txt +F: Documentation/devicetree/bindings/spi/samsung,spi*.yaml F: drivers/spi/spi-s3c* F: include/linux/platform_data/spi-s3c64xx.h F: include/linux/spi/s3c24xx-fiq.h -- cgit v1.2.3 From f412fe11c1a9d815565f3918c56f3fd02167c734 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Mon, 24 Jan 2022 09:23:45 +0100 Subject: mfd: dt-bindings: google,cros-ec: Reference Samsung SPI bindings The ChromeOS Embedded Controller appears on boards with Samsung Exynos SoC, where Exynos SPI bindings expect controller-data node. Reference SPI peripheral bindings which include now Samsung SPI peripheral parts. Signed-off-by: Krzysztof Kozlowski Reviewed-by: Rob Herring Signed-off-by: Lee Jones Link: https://lore.kernel.org/r/20220124082347.32747-3-krzysztof.kozlowski@canonical.com --- .../devicetree/bindings/mfd/google,cros-ec.yaml | 29 ++++++++++++---------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/Documentation/devicetree/bindings/mfd/google,cros-ec.yaml b/Documentation/devicetree/bindings/mfd/google,cros-ec.yaml index d1f53bd449f7..525ab18005b3 100644 --- a/Documentation/devicetree/bindings/mfd/google,cros-ec.yaml +++ b/Documentation/devicetree/bindings/mfd/google,cros-ec.yaml @@ -31,7 +31,7 @@ properties: controller-data: description: - SPI controller data, see bindings/spi/spi-samsung.txt + SPI controller data, see bindings/spi/samsung,spi-peripheral-props.yaml type: object google,cros-ec-spi-pre-delay: @@ -148,18 +148,21 @@ patternProperties: required: - compatible -if: - properties: - compatible: - contains: - enum: - - google,cros-ec-i2c - - google,cros-ec-rpmsg -then: - properties: - google,cros-ec-spi-pre-delay: false - google,cros-ec-spi-msg-delay: false - spi-max-frequency: false +allOf: + - if: + properties: + compatible: + contains: + enum: + - google,cros-ec-i2c + - google,cros-ec-rpmsg + then: + properties: + google,cros-ec-spi-pre-delay: false + google,cros-ec-spi-msg-delay: false + spi-max-frequency: false + else: + $ref: /schemas/spi/spi-peripheral-props.yaml additionalProperties: false -- cgit v1.2.3 From 96f06006a3505287b37ba19d4e50e504ac5b6a50 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Mon, 24 Jan 2022 09:23:46 +0100 Subject: mfd: dt-bindings: google,cros-ec: Fix indentation in example Correct level of indentation in the example. Signed-off-by: Krzysztof Kozlowski Reviewed-by: Rob Herring Signed-off-by: Lee Jones Link: https://lore.kernel.org/r/20220124082347.32747-4-krzysztof.kozlowski@canonical.com --- Documentation/devicetree/bindings/mfd/google,cros-ec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/mfd/google,cros-ec.yaml b/Documentation/devicetree/bindings/mfd/google,cros-ec.yaml index 525ab18005b3..4caadf73fc4a 100644 --- a/Documentation/devicetree/bindings/mfd/google,cros-ec.yaml +++ b/Documentation/devicetree/bindings/mfd/google,cros-ec.yaml @@ -203,7 +203,7 @@ examples: spi-max-frequency = <5000000>; proximity { - compatible = "google,cros-ec-mkbp-proximity"; + compatible = "google,cros-ec-mkbp-proximity"; }; cbas { -- cgit v1.2.3 From 7db7a24657c969291921d6580d62748b1320dd2f Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Mon, 24 Jan 2022 09:23:47 +0100 Subject: spi: s3c64xx: Allow controller-data to be optional The Samsung SoC SPI driver requires to provide controller-data node for each of SPI peripheral device nodes. Make this controller-data node optional, so DTS could be simpler. Suggested-by: Rob Herring Signed-off-by: Krzysztof Kozlowski Reviewed-by: Sam Protsenko Reviewed-by: Andi Shyti Reviwed-by: Mark Brown Signed-off-by: Lee Jones Link: https://lore.kernel.org/r/20220124082347.32747-5-krzysztof.kozlowski@canonical.com --- drivers/spi/spi-s3c64xx.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/drivers/spi/spi-s3c64xx.c b/drivers/spi/spi-s3c64xx.c index 8755cd85e83c..386550fca81c 100644 --- a/drivers/spi/spi-s3c64xx.c +++ b/drivers/spi/spi-s3c64xx.c @@ -796,16 +796,14 @@ static struct s3c64xx_spi_csinfo *s3c64xx_get_slave_ctrldata( return ERR_PTR(-EINVAL); } - data_np = of_get_child_by_name(slave_np, "controller-data"); - if (!data_np) { - dev_err(&spi->dev, "child node 'controller-data' not found\n"); - return ERR_PTR(-EINVAL); - } - cs = kzalloc(sizeof(*cs), GFP_KERNEL); - if (!cs) { - of_node_put(data_np); + if (!cs) return ERR_PTR(-ENOMEM); + + data_np = of_get_child_by_name(slave_np, "controller-data"); + if (!data_np) { + dev_info(&spi->dev, "feedback delay set to default (0)\n"); + return cs; } of_property_read_u32(data_np, "samsung,spi-feedback-delay", &fb_delay); -- cgit v1.2.3 From ce44e3aeec43a887a7999f4e0e50df1e4557af78 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Tue, 15 Feb 2022 08:47:57 +0100 Subject: dt-bindings: power: supply: maxim,max14577: Convert to dtschema Convert the Charger bindings of Maxim MAX14577/MAX77836 MUIC to DT schema format. The existing bindings were defined in ../bindings/mfd/max14577.txt. Signed-off-by: Krzysztof Kozlowski Reviewed-by: Rob Herring Acked-by: Sebastian Reichel Signed-off-by: Lee Jones Link: https://lore.kernel.org/r/20220215074759.29402-2-krzysztof.kozlowski@canonical.com --- .../bindings/power/supply/maxim,max14577.yaml | 84 ++++++++++++++++++++++ MAINTAINERS | 1 + 2 files changed, 85 insertions(+) create mode 100644 Documentation/devicetree/bindings/power/supply/maxim,max14577.yaml diff --git a/Documentation/devicetree/bindings/power/supply/maxim,max14577.yaml b/Documentation/devicetree/bindings/power/supply/maxim,max14577.yaml new file mode 100644 index 000000000000..3978b48299de --- /dev/null +++ b/Documentation/devicetree/bindings/power/supply/maxim,max14577.yaml @@ -0,0 +1,84 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/power/supply/maxim,max14577.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Maxim MAX14577/MAX77836 MicroUSB and Companion Power Management IC Charger + +maintainers: + - Krzysztof Kozlowski + +description: | + This is a part of device tree bindings for Maxim MAX14577/MAX77836 MicroUSB + Integrated Circuit (MUIC). + + See also Documentation/devicetree/bindings/mfd/maxim,max14577.yaml for + additional information and example. + +properties: + compatible: + enum: + - maxim,max14577-charger + - maxim,max77836-charger + + maxim,constant-uvolt: + description: + Battery Constant Voltage in uV + $ref: /schemas/types.yaml#/definitions/uint32 + minimum: 4000000 + maximum: 4350000 + + maxim,eoc-uamp: + description: | + Current in uA for End-Of-Charge mode. + MAX14577: 50000-20000 + MAX77836: 5000-100000 + $ref: /schemas/types.yaml#/definitions/uint32 + + maxim,fast-charge-uamp: + description: | + Current in uA for Fast Charge + MAX14577: 90000-950000 + MAX77836: 45000-475000 + $ref: /schemas/types.yaml#/definitions/uint32 + + maxim,ovp-uvolt: + description: + OverVoltage Protection Threshold in uV; In an overvoltage condition, INT + asserts and charging stops. + $ref: /schemas/types.yaml#/definitions/uint32 + enum: [6000000, 6500000, 7000000, 7500000] + +required: + - compatible + - maxim,constant-uvolt + - maxim,eoc-uamp + - maxim,fast-charge-uamp + - maxim,ovp-uvolt + +allOf: + - if: + properties: + compatible: + contains: + const: maxim,max14577-charger + then: + properties: + maxim,eoc-uamp: + minimum: 50000 + maximum: 200000 + maxim,fast-charge-uamp: + minimum: 90000 + maximum: 950000 + else: + # max77836 + properties: + maxim,eoc-uamp: + minimum: 5000 + maximum: 100000 + maxim,fast-charge-uamp: + minimum: 45000 + maximum: 475000 + +additionalProperties: false diff --git a/MAINTAINERS b/MAINTAINERS index 23202ad1f5f7..636bd6da988c 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -11710,6 +11710,7 @@ M: Krzysztof Kozlowski M: Bartlomiej Zolnierkiewicz L: linux-pm@vger.kernel.org S: Supported +F: Documentation/devicetree/bindings/power/supply/maxim,max14577.yaml F: drivers/power/supply/max14577_charger.c F: drivers/power/supply/max77693_charger.c -- cgit v1.2.3 From e1cd4265e547e02efc2a2547e8f390a7a9041787 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Tue, 15 Feb 2022 08:47:58 +0100 Subject: regulator: dt-bindings: maxim,max14577: Convert to dtschema Convert the regulator bindings of Maxim MAX14577/MAX77835 MUIC to DT schema format. The existing bindings were defined in ../bindings/mfd/max14577.txt. Signed-off-by: Krzysztof Kozlowski Reviewed-by: Rob Herring Reviewed-by: Mark Brown Signed-off-by: Lee Jones Link: https://lore.kernel.org/r/20220215074759.29402-3-krzysztof.kozlowski@canonical.com --- .../bindings/regulator/maxim,max14577.yaml | 78 ++++++++++++++++++++++ 1 file changed, 78 insertions(+) create mode 100644 Documentation/devicetree/bindings/regulator/maxim,max14577.yaml diff --git a/Documentation/devicetree/bindings/regulator/maxim,max14577.yaml b/Documentation/devicetree/bindings/regulator/maxim,max14577.yaml new file mode 100644 index 000000000000..16f01886a601 --- /dev/null +++ b/Documentation/devicetree/bindings/regulator/maxim,max14577.yaml @@ -0,0 +1,78 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/regulator/maxim,max14577.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Maxim MAX14577/MAX77836 MicroUSB and Companion Power Management IC regulators + +maintainers: + - Krzysztof Kozlowski + +description: | + This is a part of device tree bindings for Maxim MAX14577/MAX77836 MicroUSB + Integrated Circuit (MUIC). + + See also Documentation/devicetree/bindings/mfd/maxim,max14577.yaml for + additional information and example. + +properties: + compatible: + enum: + - maxim,max14577-regulator + - maxim,max77836-regulator + + CHARGER: + type: object + $ref: regulator.yaml# + unevaluatedProperties: false + description: | + Current regulator. + + properties: + regulator-min-microvolt: false + regulator-max-microvolt: false + + SAFEOUT: + type: object + $ref: regulator.yaml# + unevaluatedProperties: false + description: | + Safeout LDO regulator (fixed voltage). + + properties: + regulator-min-microamp: false + regulator-max-microamp: false + regulator-min-microvolt: + const: 4900000 + regulator-max-microvolt: + const: 4900000 + +patternProperties: + "^LDO[12]$": + type: object + $ref: regulator.yaml# + unevaluatedProperties: false + description: | + Current regulator. + + properties: + regulator-min-microamp: false + regulator-max-microamp: false + regulator-min-microvolt: + minimum: 800000 + regulator-max-microvolt: + maximum: 3950000 + +allOf: + - if: + properties: + compatible: + contains: + const: maxim,max14577-regulator + then: + properties: + LDO1: false + LDO2: false + +additionalProperties: false -- cgit v1.2.3 From ed6e9aa8f52f88975b4692eb00bdeaf35cd3d529 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Tue, 15 Feb 2022 08:47:59 +0100 Subject: dt-bindings: mfd: maxim,max14577: Convert to dtschema Convert the MFD part of Maxim MAX14577/MAX77836 MUIC to DT schema format. The example DTS was copied from existing DTS (exynos3250-rinato.dts), so keep the license as GPL-2.0-only. Signed-off-by: Krzysztof Kozlowski Reviewed-by: Rob Herring Signed-off-by: Lee Jones Link: https://lore.kernel.org/r/20220215074759.29402-4-krzysztof.kozlowski@canonical.com --- Documentation/devicetree/bindings/mfd/max14577.txt | 147 ---------------- .../devicetree/bindings/mfd/maxim,max14577.yaml | 195 +++++++++++++++++++++ MAINTAINERS | 2 +- 3 files changed, 196 insertions(+), 148 deletions(-) delete mode 100644 Documentation/devicetree/bindings/mfd/max14577.txt create mode 100644 Documentation/devicetree/bindings/mfd/maxim,max14577.yaml diff --git a/Documentation/devicetree/bindings/mfd/max14577.txt b/Documentation/devicetree/bindings/mfd/max14577.txt deleted file mode 100644 index be11943a0560..000000000000 --- a/Documentation/devicetree/bindings/mfd/max14577.txt +++ /dev/null @@ -1,147 +0,0 @@ -Maxim MAX14577/77836 Multi-Function Device - -MAX14577 is a Multi-Function Device with Micro-USB Interface Circuit, Li+ -Battery Charger and SFOUT LDO output for powering USB devices. It is -interfaced to host controller using I2C. - -MAX77836 additionally contains PMIC (with two LDO regulators) and Fuel Gauge. -For the description of Fuel Gauge low SOC alert interrupt see: -../power/supply/max17040_battery.txt - - -Required properties: -- compatible : Must be "maxim,max14577" or "maxim,max77836". -- reg : I2C slave address for the max14577 chip (0x25 for max14577/max77836) -- interrupts : IRQ line for the chip. - - -Required nodes: - - charger : - Node for configuring the charger driver. - Required properties: - - compatible : "maxim,max14577-charger" - or "maxim,max77836-charger" - - maxim,fast-charge-uamp : Current in uA for Fast Charge; - Valid values: - - for max14577: 90000 - 950000; - - for max77836: 45000 - 475000; - - maxim,eoc-uamp : Current in uA for End-Of-Charge mode; - Valid values: - - for max14577: 50000 - 200000; - - for max77836: 5000 - 100000; - - maxim,ovp-uvolt : OverVoltage Protection Threshold in uV; - In an overvoltage condition, INT asserts and charging - stops. Valid values: - - 6000000, 6500000, 7000000, 7500000; - - maxim,constant-uvolt : Battery Constant Voltage in uV; - Valid values: - - 4000000 - 4280000 (step by 20000); - - 4350000; - - -Optional nodes: -- max14577-muic/max77836-muic : - Node used only by extcon consumers. - Required properties: - - compatible : "maxim,max14577-muic" or "maxim,max77836-muic" - -- regulators : - Required properties: - - compatible : "maxim,max14577-regulator" - or "maxim,max77836-regulator" - - May contain a sub-node per regulator from the list below. Each - sub-node should contain the constraints and initialization information - for that regulator. See regulator.txt for a description of standard - properties for these sub-nodes. - - List of valid regulator names: - - for max14577: CHARGER, SAFEOUT. - - for max77836: CHARGER, SAFEOUT, LDO1, LDO2. - - The SAFEOUT is a fixed voltage regulator so there is no need to specify - voltages for it. - - -Example: - -#include - -max14577@25 { - compatible = "maxim,max14577"; - reg = <0x25>; - interrupt-parent = <&gpx1>; - interrupts = <5 IRQ_TYPE_LEVEL_LOW>; - - muic: max14577-muic { - compatible = "maxim,max14577-muic"; - }; - - regulators { - compatible = "maxim,max14577-regulator"; - - SAFEOUT { - regulator-name = "SAFEOUT"; - }; - CHARGER { - regulator-name = "CHARGER"; - regulator-min-microamp = <90000>; - regulator-max-microamp = <950000>; - regulator-boot-on; - }; - }; - - charger { - compatible = "maxim,max14577-charger"; - - maxim,constant-uvolt = <4350000>; - maxim,fast-charge-uamp = <450000>; - maxim,eoc-uamp = <50000>; - maxim,ovp-uvolt = <6500000>; - }; -}; - - -max77836@25 { - compatible = "maxim,max77836"; - reg = <0x25>; - interrupt-parent = <&gpx1>; - interrupts = <5 IRQ_TYPE_LEVEL_LOW>; - - muic: max77836-muic { - compatible = "maxim,max77836-muic"; - }; - - regulators { - compatible = "maxim,max77836-regulator"; - - SAFEOUT { - regulator-name = "SAFEOUT"; - }; - CHARGER { - regulator-name = "CHARGER"; - regulator-min-microamp = <90000>; - regulator-max-microamp = <950000>; - regulator-boot-on; - }; - LDO1 { - regulator-name = "LDO1"; - regulator-min-microvolt = <2700000>; - regulator-max-microvolt = <2700000>; - }; - LDO2 { - regulator-name = "LDO2"; - regulator-min-microvolt = <800000>; - regulator-max-microvolt = <3950000>; - }; - }; - - charger { - compatible = "maxim,max77836-charger"; - - maxim,constant-uvolt = <4350000>; - maxim,fast-charge-uamp = <225000>; - maxim,eoc-uamp = <7500>; - maxim,ovp-uvolt = <6500000>; - }; -}; diff --git a/Documentation/devicetree/bindings/mfd/maxim,max14577.yaml b/Documentation/devicetree/bindings/mfd/maxim,max14577.yaml new file mode 100644 index 000000000000..27870b8760a6 --- /dev/null +++ b/Documentation/devicetree/bindings/mfd/maxim,max14577.yaml @@ -0,0 +1,195 @@ +# SPDX-License-Identifier: GPL-2.0-only +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/mfd/maxim,max14577.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Maxim MAX14577/MAX77836 MicroUSB and Companion Power Management IC + +maintainers: + - Krzysztof Kozlowski + +description: | + This is a part of device tree bindings for Maxim MAX14577/MAX77836 MicroUSB + Integrated Circuit (MUIC). + + The Maxim MAX14577 is a MicroUSB and Companion Power Management IC which + includes voltage safeout regulators, charger and MicroUSB management IC. + + The Maxim MAX77836 is a MicroUSB and Companion Power Management IC which + includes voltage safeout and LDO regulators, charger, fuel-gauge and MicroUSB + management IC. + +properties: + compatible: + enum: + - maxim,max14577 + - maxim,max77836 + + interrupts: + maxItems: 1 + + reg: + maxItems: 1 + + wakeup-source: true + + charger: + $ref: /schemas/power/supply/maxim,max14577.yaml + + extcon: + type: object + properties: + compatible: + enum: + - maxim,max14577-muic + - maxim,max77836-muic + + required: + - compatible + + regulators: + $ref: /schemas/regulator/maxim,max14577.yaml + +required: + - compatible + - interrupts + - reg + - charger + +allOf: + - if: + properties: + compatible: + contains: + const: maxim,max14577 + then: + properties: + charger: + properties: + compatible: + const: maxim,max14577-charger + extcon: + properties: + compatible: + const: maxim,max14577-muic + regulator: + properties: + compatible: + const: maxim,max14577-regulator + else: + properties: + charger: + properties: + compatible: + const: maxim,max77836-charger + extcon: + properties: + compatible: + const: maxim,max77836-muic + regulator: + properties: + compatible: + const: maxim,max77836-regulator + +additionalProperties: false + +examples: + - | + #include + + i2c { + #address-cells = <1>; + #size-cells = <0>; + + pmic@25 { + compatible = "maxim,max14577"; + reg = <0x25>; + interrupt-parent = <&gpx1>; + interrupts = <5 IRQ_TYPE_LEVEL_LOW>; + + extcon { + compatible = "maxim,max14577-muic"; + }; + + regulators { + compatible = "maxim,max14577-regulator"; + + SAFEOUT { + regulator-name = "SAFEOUT"; + }; + + CHARGER { + regulator-name = "CHARGER"; + regulator-min-microamp = <90000>; + regulator-max-microamp = <950000>; + regulator-boot-on; + }; + }; + + charger { + compatible = "maxim,max14577-charger"; + + maxim,constant-uvolt = <4350000>; + maxim,fast-charge-uamp = <450000>; + maxim,eoc-uamp = <50000>; + maxim,ovp-uvolt = <6500000>; + }; + }; + }; + + - | + #include + + i2c { + #address-cells = <1>; + #size-cells = <0>; + + pmic@25 { + compatible = "maxim,max77836"; + interrupt-parent = <&gpx1>; + interrupts = <5 IRQ_TYPE_NONE>; + reg = <0x25>; + wakeup-source; + + extcon { + compatible = "maxim,max77836-muic"; + }; + + regulators { + compatible = "maxim,max77836-regulator"; + + SAFEOUT { + regulator-name = "SAFEOUT"; + }; + + CHARGER { + regulator-name = "CHARGER"; + regulator-min-microamp = <45000>; + regulator-max-microamp = <475000>; + regulator-boot-on; + }; + + LDO1 { + regulator-name = "MOT_2.7V"; + regulator-min-microvolt = <1100000>; + regulator-max-microvolt = <2700000>; + }; + + LDO2 { + regulator-name = "UNUSED_LDO2"; + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <3950000>; + }; + }; + + charger { + compatible = "maxim,max77836-charger"; + + maxim,constant-uvolt = <4350000>; + maxim,fast-charge-uamp = <225000>; + maxim,eoc-uamp = <7500>; + maxim,ovp-uvolt = <6500000>; + }; + }; + }; diff --git a/MAINTAINERS b/MAINTAINERS index 636bd6da988c..31d1c0926697 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -11720,10 +11720,10 @@ M: Krzysztof Kozlowski M: Bartlomiej Zolnierkiewicz L: linux-kernel@vger.kernel.org S: Supported +F: Documentation/devicetree/bindings/*/maxim,max14577.yaml F: Documentation/devicetree/bindings/*/maxim,max77686.yaml F: Documentation/devicetree/bindings/*/maxim,max77843.yaml F: Documentation/devicetree/bindings/clock/maxim,max77686.txt -F: Documentation/devicetree/bindings/mfd/max14577.txt F: Documentation/devicetree/bindings/mfd/max77693.txt F: drivers/*/*max77843.c F: drivers/*/max14577*.c -- cgit v1.2.3 From 6b9d48b418fbc91ae8dbcba2cfe078c4736a77f2 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Tue, 15 Feb 2022 08:53:43 +0100 Subject: regulator: dt-bindings: maxim,max77802: Convert to dtschema Convert the regulators of Maxim MAX77802 PMIC to DT schema format. Signed-off-by: Krzysztof Kozlowski Reviewed-by: Rob Herring Reviewed-by: Javier Martinez Canillas Acked-by: Mark Brown Signed-off-by: Lee Jones Link: https://lore.kernel.org/r/20220215075344.31421-2-krzysztof.kozlowski@canonical.com --- .../devicetree/bindings/regulator/max77802.txt | 111 --------------------- .../bindings/regulator/maxim,max77802.yaml | 85 ++++++++++++++++ 2 files changed, 85 insertions(+), 111 deletions(-) delete mode 100644 Documentation/devicetree/bindings/regulator/max77802.txt create mode 100644 Documentation/devicetree/bindings/regulator/maxim,max77802.yaml diff --git a/Documentation/devicetree/bindings/regulator/max77802.txt b/Documentation/devicetree/bindings/regulator/max77802.txt deleted file mode 100644 index b82943d83677..000000000000 --- a/Documentation/devicetree/bindings/regulator/max77802.txt +++ /dev/null @@ -1,111 +0,0 @@ -Binding for Maxim MAX77802 regulators - -This is a part of device tree bindings of MAX77802 multi-function device. -More information can be found in bindings/mfd/max77802.txt file. - -The MAX77802 PMIC has 10 high-efficiency Buck and 32 Low-dropout (LDO) -regulators that can be controlled over I2C. - -Following properties should be present in main device node of the MFD chip. - -Optional properties: -- inb1-supply: The input supply for BUCK1 -- inb2-supply: The input supply for BUCK2 -- inb3-supply: The input supply for BUCK3 -- inb4-supply: The input supply for BUCK4 -- inb5-supply: The input supply for BUCK5 -- inb6-supply: The input supply for BUCK6 -- inb7-supply: The input supply for BUCK7 -- inb8-supply: The input supply for BUCK8 -- inb9-supply: The input supply for BUCK9 -- inb10-supply: The input supply for BUCK10 -- inl1-supply: The input supply for LDO8 and LDO15 -- inl2-supply: The input supply for LDO17, LDO27, LDO30 and LDO35 -- inl3-supply: The input supply for LDO3, LDO5, LDO6 and LDO7 -- inl4-supply: The input supply for LDO10, LDO11, LDO13 and LDO14 -- inl5-supply: The input supply for LDO9 and LDO19 -- inl6-supply: The input supply for LDO4, LDO21, LDO24 and LDO33 -- inl7-supply: The input supply for LDO18, LDO20, LDO28 and LDO29 -- inl9-supply: The input supply for LDO12, LDO23, LDO25, LDO26, LDO32 and LDO34 -- inl10-supply: The input supply for LDO1 and LDO2 - -Optional nodes: -- regulators : The regulators of max77802 have to be instantiated - under subnode named "regulators" using the following format. - - regulator-name { - standard regulator constraints.... - }; - refer Documentation/devicetree/bindings/regulator/regulator.txt - -The regulator node name should be initialized with a string to get matched -with their hardware counterparts as follow. The valid names are: - - -LDOn : for LDOs, where n can lie in ranges 1-15, 17-21, 23-30 - and 32-35. - example: LDO1, LDO2, LDO35. - -BUCKn : for BUCKs, where n can lie in range 1 to 10. - example: BUCK1, BUCK5, BUCK10. - -The max77802 regulator supports two different operating modes: Normal and Low -Power Mode. Some regulators support the modes to be changed at startup or by -the consumers during normal operation while others only support to change the -mode during system suspend. The standard regulator suspend states binding can -be used to configure the regulator operating mode. - -The regulators that support the standard "regulator-initial-mode" property, -changing their mode during normal operation are: LDOs 1, 3, 20 and 21. - -The possible values for "regulator-initial-mode" and "regulator-mode" are: - 1: Normal regulator voltage output mode. - 3: Low Power which reduces the quiescent current down to only 1uA - -The valid modes list is defined in the dt-bindings/regulator/maxim,max77802.h -header and can be included by device tree source files. - -The standard "regulator-mode" property can only be used for regulators that -support changing their mode to Low Power Mode during suspend. These regulators -are: BUCKs 2-4 and LDOs 1-35. Also, it only takes effect if the regulator has -been enabled for the given suspend state using "regulator-on-in-suspend" and -has not been disabled for that state using "regulator-off-in-suspend". - -Example: - - max77802@9 { - compatible = "maxim,max77802"; - interrupt-parent = <&wakeup_eint>; - interrupts = <26 0>; - reg = <0x09>; - #address-cells = <1>; - #size-cells = <0>; - - inb1-supply = <&parent_reg>; - - regulators { - ldo1_reg: LDO1 { - regulator-name = "vdd_1v0"; - regulator-min-microvolt = <1000000>; - regulator-max-microvolt = <1000000>; - regulator-always-on; - regulator-initial-mode = ; - }; - - ldo11_reg: LDO11 { - regulator-name = "vdd_ldo11"; - regulator-min-microvolt = <1900000>; - regulator-max-microvolt = <1900000>; - regulator-always-on; - regulator-state-mem { - regulator-on-in-suspend; - regulator-mode = ; - }; - }; - - buck1_reg: BUCK1 { - regulator-name = "vdd_mif"; - regulator-min-microvolt = <950000>; - regulator-max-microvolt = <1300000>; - regulator-always-on; - regulator-boot-on; - }; - }; diff --git a/Documentation/devicetree/bindings/regulator/maxim,max77802.yaml b/Documentation/devicetree/bindings/regulator/maxim,max77802.yaml new file mode 100644 index 000000000000..f2b4dd15a0f3 --- /dev/null +++ b/Documentation/devicetree/bindings/regulator/maxim,max77802.yaml @@ -0,0 +1,85 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/regulator/maxim,max77802.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Maxim MAX77802 Power Management IC regulators + +maintainers: + - Javier Martinez Canillas + - Krzysztof Kozlowski + +description: | + This is a part of device tree bindings for Maxim MAX77802 Power Management + Integrated Circuit (PMIC). + + The Maxim MAX77686 provides 10 high-efficiency Buck and 32 Low-DropOut (LDO) + regulators. + + See also Documentation/devicetree/bindings/mfd/maxim,max77802.yaml for + additional information and example. + + Certain regulators support "regulator-initial-mode" and "regulator-mode". + The valid modes list is defined in the dt-bindings/regulator/maxim,max77802.h + and their meaning is:: + 1 - Normal regulator voltage output mode. + 3 - Low Power which reduces the quiescent current down to only 1uA + + The standard "regulator-mode" property can only be used for regulators that + support changing their mode to Low Power Mode during suspend. These + regulators are:: bucks 2-4 and LDOs 1-35. Also, it only takes effect if the + regulator has been enabled for the given suspend state using + "regulator-on-in-suspend" and has not been disabled for that state using + "regulator-off-in-suspend". + +patternProperties: + # LDO1, LDO3, LDO20, LDO21 + "^LDO([13]|2[01])$": + type: object + $ref: regulator.yaml# + unevaluatedProperties: false + description: + LDOs supporting the regulator-initial-mode property and changing their + mode during normal operation. + + # LDO2, LDO4-15, LDO17-19, LDO23-30, LDO32-35 + "^LDO([24-9]|1[0-5789]|2[3-9]|3[02345])$": + type: object + $ref: regulator.yaml# + unevaluatedProperties: false + description: + LDOs supporting the regulator-mode property (changing mode to Low Power + Mode during suspend). + + properties: + regulator-initial-mode: false + + # buck2-4 + "^BUCK[2-4]$": + type: object + $ref: regulator.yaml# + unevaluatedProperties: false + description: + bucks supporting the regulator-mode property (changing mode to Low Power + Mode during suspend). + + properties: + regulator-initial-mode: false + + # buck1, buck5-10 + "^BUCK([15-9]|10)$": + type: object + $ref: regulator.yaml# + unevaluatedProperties: false + + properties: + regulator-initial-mode: false + + patternProperties: + regulator-state-(standby|mem|disk): + type: object + properties: + regulator-mode: false + +additionalProperties: false -- cgit v1.2.3 From 172e611b54e813c49a35b6b74bccaa99f27bf566 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Tue, 15 Feb 2022 08:53:44 +0100 Subject: dt-bindings: mfd: maxim,max77802: Convert to dtschema Convert the MFD part of Maxim MAX77802 PMIC to DT schema format. The example DTS was copied from existing DTS (exynos5800-peach-pi.dts), so keep the license as GPL-2.0-only. Signed-off-by: Krzysztof Kozlowski Reviewed-by: Rob Herring Reviewed-by: Javier Martinez Canillas Signed-off-by: Lee Jones Link: https://lore.kernel.org/r/20220215075344.31421-3-krzysztof.kozlowski@canonical.com --- Documentation/devicetree/bindings/mfd/max77802.txt | 25 --- .../devicetree/bindings/mfd/maxim,max77802.yaml | 194 +++++++++++++++++++++ MAINTAINERS | 2 +- 3 files changed, 195 insertions(+), 26 deletions(-) delete mode 100644 Documentation/devicetree/bindings/mfd/max77802.txt create mode 100644 Documentation/devicetree/bindings/mfd/maxim,max77802.yaml diff --git a/Documentation/devicetree/bindings/mfd/max77802.txt b/Documentation/devicetree/bindings/mfd/max77802.txt deleted file mode 100644 index 09decac20d91..000000000000 --- a/Documentation/devicetree/bindings/mfd/max77802.txt +++ /dev/null @@ -1,25 +0,0 @@ -Maxim MAX77802 multi-function device - -The Maxim MAX77802 is a Power Management IC (PMIC) that contains 10 high -efficiency Buck regulators, 32 Low-DropOut (LDO) regulators used to power -up application processors and peripherals, a 2-channel 32kHz clock outputs, -a Real-Time-Clock (RTC) and a I2C interface to program the individual -regulators, clocks outputs and the RTC. - -Bindings for the built-in 32k clock generator block and -regulators are defined in ../clk/maxim,max77802.txt and -../regulator/max77802.txt respectively. - -Required properties: -- compatible : Must be "maxim,max77802" -- reg : Specifies the I2C slave address of PMIC block. -- interrupts : I2C device IRQ line connected to the main SoC. - -Example: - - max77802: pmic@9 { - compatible = "maxim,max77802"; - interrupt-parent = <&intc>; - interrupts = <26 IRQ_TYPE_NONE>; - reg = <0x09>; - }; diff --git a/Documentation/devicetree/bindings/mfd/maxim,max77802.yaml b/Documentation/devicetree/bindings/mfd/maxim,max77802.yaml new file mode 100644 index 000000000000..baa1346ac5d5 --- /dev/null +++ b/Documentation/devicetree/bindings/mfd/maxim,max77802.yaml @@ -0,0 +1,194 @@ +# SPDX-License-Identifier: GPL-2.0-only +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/mfd/maxim,max77802.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Maxim MAX77802 Power Management IC + +maintainers: + - Javier Martinez Canillas + - Krzysztof Kozlowski + +description: | + This is a part of device tree bindings for Maxim MAX77802 Power Management + Integrated Circuit (PMIC). + + The Maxim MAX77802 is a Power Management IC which includes voltage and + current regulators (10 high efficiency Buck regulators and 32 Low-DropOut + (LDO)), RTC and clock outputs. + + The MAX77802 provides two 32.768khz clock outputs that can be controlled + (gated/ungated) over I2C. The clock IDs are defined as preprocessor macros + in dt-bindings/clock/maxim,max77802.h. + +properties: + compatible: + const: maxim,max77802 + + '#clock-cells': + const: 1 + + interrupts: + maxItems: 1 + + reg: + maxItems: 1 + + regulators: + $ref: /schemas/regulator/maxim,max77802.yaml + description: + List of child nodes that specify the regulators. + + inb1-supply: + description: Power supply for buck1 + inb2-supply: + description: Power supply for buck2 + inb3-supply: + description: Power supply for buck3 + inb4-supply: + description: Power supply for buck4 + inb5-supply: + description: Power supply for buck5 + inb6-supply: + description: Power supply for buck6 + inb7-supply: + description: Power supply for buck7 + inb8-supply: + description: Power supply for buck8 + inb9-supply: + description: Power supply for buck9 + inb10-supply: + description: Power supply for buck10 + + inl1-supply: + description: Power supply for LDO8, LDO15 + inl2-supply: + description: Power supply for LDO17, LDO27, LDO30, LDO35 + inl3-supply: + description: Power supply for LDO3, LDO5, LDO7, LDO7 + inl4-supply: + description: Power supply for LDO10, LDO11, LDO13, LDO14 + inl5-supply: + description: Power supply for LDO9, LDO19 + inl6-supply: + description: Power supply for LDO4, LDO21, LDO24, LDO33 + inl7-supply: + description: Power supply for LDO18, LDO20, LDO28, LDO29 + inl9-supply: + description: Power supply for LDO12, LDO23, LDO25, LDO26, LDO32, LDO34 + inl10-supply: + description: Power supply for LDO1, LDO2 + + wakeup-source: true + +required: + - compatible + - '#clock-cells' + - reg + +additionalProperties: false + +examples: + - | + #include + #include + + i2c { + #address-cells = <1>; + #size-cells = <0>; + + pmic@9 { + compatible = "maxim,max77802"; + interrupt-parent = <&gpx3>; + interrupts = <1 IRQ_TYPE_NONE>; + pinctrl-names = "default"; + pinctrl-0 = <&max77802_irq>, <&pmic_selb>, + <&pmic_dvs_1>, <&pmic_dvs_2>, <&pmic_dvs_3>; + wakeup-source; + reg = <0x9>; + #clock-cells = <1>; + + inb1-supply = <&tps65090_dcdc2>; + inb2-supply = <&tps65090_dcdc1>; + inb3-supply = <&tps65090_dcdc2>; + inb4-supply = <&tps65090_dcdc2>; + inb5-supply = <&tps65090_dcdc1>; + inb6-supply = <&tps65090_dcdc2>; + inb7-supply = <&tps65090_dcdc1>; + inb8-supply = <&tps65090_dcdc1>; + inb9-supply = <&tps65090_dcdc1>; + inb10-supply = <&tps65090_dcdc1>; + + inl1-supply = <&buck5_reg>; + inl2-supply = <&buck7_reg>; + inl3-supply = <&buck9_reg>; + inl4-supply = <&buck9_reg>; + inl5-supply = <&buck9_reg>; + inl6-supply = <&tps65090_dcdc2>; + inl7-supply = <&buck9_reg>; + inl9-supply = <&tps65090_dcdc2>; + inl10-supply = <&buck7_reg>; + + regulators { + BUCK1 { + regulator-name = "vdd_mif"; + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <1300000>; + regulator-always-on; + regulator-boot-on; + regulator-ramp-delay = <12500>; + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + BUCK2 { + regulator-name = "vdd_arm"; + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <1500000>; + regulator-always-on; + regulator-boot-on; + regulator-ramp-delay = <12500>; + regulator-coupled-with = <&buck3_reg>; + regulator-coupled-max-spread = <300000>; + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + // ... + + BUCK10 { + regulator-name = "vdd_1v8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-always-on; + regulator-boot-on; + regulator-state-mem { + regulator-on-in-suspend; + }; + }; + + LDO1 { + regulator-name = "vdd_1v0"; + regulator-min-microvolt = <1000000>; + regulator-max-microvolt = <1000000>; + regulator-always-on; + regulator-initial-mode = ; + regulator-state-mem { + regulator-on-in-suspend; + regulator-mode = ; + }; + }; + + // ... + + LDO35 { + regulator-name = "ldo_35"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + }; + }; + }; + }; diff --git a/MAINTAINERS b/MAINTAINERS index 31d1c0926697..823cdb3fe41b 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -11695,7 +11695,7 @@ MAXIM MAX77802 PMIC REGULATOR DEVICE DRIVER M: Javier Martinez Canillas L: linux-kernel@vger.kernel.org S: Supported -F: Documentation/devicetree/bindings/*/*max77802.txt +F: Documentation/devicetree/bindings/*/*max77802.yaml F: drivers/regulator/max77802-regulator.c F: include/dt-bindings/*/*max77802.h -- cgit v1.2.3 From af524ae5ad13a9c28acf0b2ec4489d5903c4fbed Mon Sep 17 00:00:00 2001 From: Kuldeep Singh Date: Thu, 3 Mar 2022 00:59:15 +0530 Subject: spi: Update NXP Flexspi maintainer details Add Han Xu as flexspi maintainer. Also, update my email address as previous one is not working anymore. Signed-off-by: Kuldeep Singh Acked-by: Rob Herring Link: https://lore.kernel.org/r/20220302192915.6193-1-singh.kuldeep87k@gmail.com Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/spi/spi-nxp-fspi.yaml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/spi/spi-nxp-fspi.yaml b/Documentation/devicetree/bindings/spi/spi-nxp-fspi.yaml index 283815d59e85..1b552c298277 100644 --- a/Documentation/devicetree/bindings/spi/spi-nxp-fspi.yaml +++ b/Documentation/devicetree/bindings/spi/spi-nxp-fspi.yaml @@ -7,7 +7,8 @@ $schema: http://devicetree.org/meta-schemas/core.yaml# title: NXP Flex Serial Peripheral Interface (FSPI) maintainers: - - Kuldeep Singh + - Han Xu + - Kuldeep Singh allOf: - $ref: "spi-controller.yaml#" -- cgit v1.2.3 From c59dbc642d4e76187516960780b6cd26e7f2c943 Mon Sep 17 00:00:00 2001 From: Yihao Han Date: Thu, 3 Mar 2022 04:50:54 -0800 Subject: spi: cadence: fix platform_get_irq.cocci warning Remove dev_err() messages after platform_get_irq*() failures. platform_get_irq() already prints an error. Generated by: scripts/coccinelle/api/platform_get_irq.cocci Signed-off-by: Yihao Han Link: https://lore.kernel.org/r/20220303125054.3574-1-hanyihao@vivo.com Signed-off-by: Mark Brown --- drivers/spi/spi-cadence-xspi.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/spi/spi-cadence-xspi.c b/drivers/spi/spi-cadence-xspi.c index 4bc1b93fc276..3ab19be83095 100644 --- a/drivers/spi/spi-cadence-xspi.c +++ b/drivers/spi/spi-cadence-xspi.c @@ -578,10 +578,8 @@ static int cdns_xspi_probe(struct platform_device *pdev) } cdns_xspi->irq = platform_get_irq(pdev, 0); - if (cdns_xspi->irq < 0) { - dev_err(dev, "Failed to get IRQ\n"); + if (cdns_xspi->irq < 0) return -ENXIO; - } ret = devm_request_irq(dev, cdns_xspi->irq, cdns_xspi_irq_handler, IRQF_SHARED, pdev->name, cdns_xspi); -- cgit v1.2.3 From fa0f3db49e10ac61774e1c90167ec79429d6fd56 Mon Sep 17 00:00:00 2001 From: Xingbang Liu Date: Wed, 2 Mar 2022 15:15:21 +0800 Subject: spi: qup: replace spin_lock_irqsave by spin_lock in hard IRQ The code has been in a irq-disabled context since it is hard IRQ. There is no necessity to do it again. Signed-off-by: Xingbang Liu Link: https://lore.kernel.org/r/20220302071521.6638-1-liu.airalert@gmail.com Signed-off-by: Mark Brown --- drivers/spi/spi-qup.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/spi/spi-qup.c b/drivers/spi/spi-qup.c index d39dec6d1c91..00d6084306b4 100644 --- a/drivers/spi/spi-qup.c +++ b/drivers/spi/spi-qup.c @@ -593,7 +593,6 @@ static irqreturn_t spi_qup_qup_irq(int irq, void *dev_id) { struct spi_qup *controller = dev_id; u32 opflags, qup_err, spi_err; - unsigned long flags; int error = 0; qup_err = readl_relaxed(controller->base + QUP_ERROR_FLAGS); @@ -625,10 +624,10 @@ static irqreturn_t spi_qup_qup_irq(int irq, void *dev_id) error = -EIO; } - spin_lock_irqsave(&controller->lock, flags); + spin_lock(&controller->lock); if (!controller->error) controller->error = error; - spin_unlock_irqrestore(&controller->lock, flags); + spin_unlock(&controller->lock); if (spi_qup_is_dma_xfer(controller->mode)) { writel_relaxed(opflags, controller->base + QUP_OPERATIONAL); -- cgit v1.2.3 From 320689a1b543ca1396b3ed43bb18045e4a7ffd79 Mon Sep 17 00:00:00 2001 From: Jon Hunter Date: Mon, 7 Mar 2022 11:35:29 +0000 Subject: spi: Fix Tegra QSPI example When running dt_binding_check on the nvidia,tegra210-quad.yaml binding document the following error is reported ... nvidia,tegra210-quad.example.dt.yaml:0:0: /example-0/spi@70410000/flash@0: failed to match any schema with compatible: ['spi-nor'] Update the example in the binding document to fix the above error. Signed-off-by: Jon Hunter Fixes: 9684752e5fe3 ("dt-bindings: spi: Add Tegra Quad SPI device tree binding") Link: https://lore.kernel.org/r/20220307113529.315685-1-jonathanh@nvidia.com Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/spi/nvidia,tegra210-quad.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/spi/nvidia,tegra210-quad.yaml b/Documentation/devicetree/bindings/spi/nvidia,tegra210-quad.yaml index 6efea8970e62..0296edd1de22 100644 --- a/Documentation/devicetree/bindings/spi/nvidia,tegra210-quad.yaml +++ b/Documentation/devicetree/bindings/spi/nvidia,tegra210-quad.yaml @@ -107,7 +107,7 @@ examples: dma-names = "rx", "tx"; flash@0 { - compatible = "spi-nor"; + compatible = "jedec,spi-nor"; reg = <0>; spi-max-frequency = <104000000>; spi-tx-bus-width = <2>; -- cgit v1.2.3 From b15e3bc76925eb1366348483fca89f115c8cde31 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonathan=20Neusch=C3=A4fer?= Date: Sun, 6 Mar 2022 15:23:12 +0100 Subject: spi: npcm-fiu: Fix typo ("npxm") MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The platform is called NPCM, not NPXM. Signed-off-by: Jonathan Neuschäfer Link: https://lore.kernel.org/r/20220306142312.109017-1-j.neuschaefer@gmx.net Signed-off-by: Mark Brown --- drivers/spi/spi-npcm-fiu.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/spi/spi-npcm-fiu.c b/drivers/spi/spi-npcm-fiu.c index 71ed75bf0a20..ba67dbed9fb8 100644 --- a/drivers/spi/spi-npcm-fiu.c +++ b/drivers/spi/spi-npcm-fiu.c @@ -201,7 +201,7 @@ struct fiu_data { int fiu_max; }; -static const struct npcm_fiu_info npxm7xx_fiu_info[] = { +static const struct npcm_fiu_info npcm7xx_fiu_info[] = { {.name = "FIU0", .fiu_id = FIU0, .max_map_size = MAP_SIZE_128MB, .max_cs = 2}, {.name = "FIU3", .fiu_id = FIU3, @@ -209,8 +209,8 @@ static const struct npcm_fiu_info npxm7xx_fiu_info[] = { {.name = "FIUX", .fiu_id = FIUX, .max_map_size = MAP_SIZE_16MB, .max_cs = 2} }; -static const struct fiu_data npxm7xx_fiu_data = { - .npcm_fiu_data_info = npxm7xx_fiu_info, +static const struct fiu_data npcm7xx_fiu_data = { + .npcm_fiu_data_info = npcm7xx_fiu_info, .fiu_max = 3, }; @@ -664,7 +664,7 @@ static const struct spi_controller_mem_ops npcm_fiu_mem_ops = { }; static const struct of_device_id npcm_fiu_dt_ids[] = { - { .compatible = "nuvoton,npcm750-fiu", .data = &npxm7xx_fiu_data }, + { .compatible = "nuvoton,npcm750-fiu", .data = &npcm7xx_fiu_data }, { /* sentinel */ } }; -- cgit v1.2.3 From 75a1b44a54bd97500e524cf42e8c81cc632672b3 Mon Sep 17 00:00:00 2001 From: Krishna Yarlagadda Date: Mon, 7 Mar 2022 22:25:17 +0530 Subject: spi: tegra210-quad: add acpi support Add ACPI ID for Tegra QUAD SPI. Switch to common device property calls. Skip clock calls that are not updated in ACPI boot. Runtime PM support is not yet enabled with ACPI boot. Signed-off-by: Krishna Yarlagadda Link: https://lore.kernel.org/r/20220307165519.38380-2-kyarlagadda@nvidia.com Signed-off-by: Mark Brown --- drivers/spi/spi-tegra210-quad.c | 52 ++++++++++++++++++++++++++++++++--------- 1 file changed, 41 insertions(+), 11 deletions(-) diff --git a/drivers/spi/spi-tegra210-quad.c b/drivers/spi/spi-tegra210-quad.c index 3725ee5331ae..517a348d1c19 100644 --- a/drivers/spi/spi-tegra210-quad.c +++ b/drivers/spi/spi-tegra210-quad.c @@ -21,6 +21,8 @@ #include #include #include +#include +#include #define QSPI_COMMAND1 0x000 #define QSPI_BIT_LENGTH(x) (((x) & 0x1f) << 0) @@ -771,7 +773,7 @@ static u32 tegra_qspi_setup_transfer_one(struct spi_device *spi, struct spi_tran u32 tx_tap = 0, rx_tap = 0; int req_mode; - if (speed != tqspi->cur_speed) { + if (!has_acpi_companion(tqspi->dev) && speed != tqspi->cur_speed) { clk_set_rate(tqspi->clk, speed); tqspi->cur_speed = speed; } @@ -879,16 +881,16 @@ static int tegra_qspi_start_transfer_one(struct spi_device *spi, static struct tegra_qspi_client_data *tegra_qspi_parse_cdata_dt(struct spi_device *spi) { struct tegra_qspi_client_data *cdata; - struct device_node *slave_np = spi->dev.of_node; cdata = devm_kzalloc(&spi->dev, sizeof(*cdata), GFP_KERNEL); if (!cdata) return NULL; - of_property_read_u32(slave_np, "nvidia,tx-clk-tap-delay", - &cdata->tx_clk_tap_delay); - of_property_read_u32(slave_np, "nvidia,rx-clk-tap-delay", - &cdata->rx_clk_tap_delay); + device_property_read_u32(&spi->dev, "nvidia,tx-clk-tap-delay", + &cdata->tx_clk_tap_delay); + device_property_read_u32(&spi->dev, "nvidia,rx-clk-tap-delay", + &cdata->rx_clk_tap_delay); + return cdata; } @@ -1227,6 +1229,24 @@ static const struct of_device_id tegra_qspi_of_match[] = { MODULE_DEVICE_TABLE(of, tegra_qspi_of_match); +#ifdef CONFIG_ACPI +static const struct acpi_device_id tegra_qspi_acpi_match[] = { + { + .id = "NVDA1213", + .driver_data = (kernel_ulong_t)&tegra210_qspi_soc_data, + }, { + .id = "NVDA1313", + .driver_data = (kernel_ulong_t)&tegra186_qspi_soc_data, + }, { + .id = "NVDA1413", + .driver_data = (kernel_ulong_t)&tegra234_qspi_soc_data, + }, + {} +}; + +MODULE_DEVICE_TABLE(acpi, tegra_qspi_acpi_match); +#endif + static int tegra_qspi_probe(struct platform_device *pdev) { struct spi_master *master; @@ -1269,11 +1289,14 @@ static int tegra_qspi_probe(struct platform_device *pdev) return qspi_irq; tqspi->irq = qspi_irq; - tqspi->clk = devm_clk_get(&pdev->dev, "qspi"); - if (IS_ERR(tqspi->clk)) { - ret = PTR_ERR(tqspi->clk); - dev_err(&pdev->dev, "failed to get clock: %d\n", ret); - return ret; + if (!has_acpi_companion(tqspi->dev)) { + tqspi->clk = devm_clk_get(&pdev->dev, "qspi"); + if (IS_ERR(tqspi->clk)) { + ret = PTR_ERR(tqspi->clk); + dev_err(&pdev->dev, "failed to get clock: %d\n", ret); + return ret; + } + } tqspi->max_buf_size = QSPI_FIFO_DEPTH << 2; @@ -1377,6 +1400,9 @@ static int __maybe_unused tegra_qspi_runtime_suspend(struct device *dev) struct spi_master *master = dev_get_drvdata(dev); struct tegra_qspi *tqspi = spi_master_get_devdata(master); + /* Runtime pm disabled with ACPI */ + if (has_acpi_companion(tqspi->dev)) + return 0; /* flush all write which are in PPSB queue by reading back */ tegra_qspi_readl(tqspi, QSPI_COMMAND1); @@ -1391,6 +1417,9 @@ static int __maybe_unused tegra_qspi_runtime_resume(struct device *dev) struct tegra_qspi *tqspi = spi_master_get_devdata(master); int ret; + /* Runtime pm disabled with ACPI */ + if (has_acpi_companion(tqspi->dev)) + return 0; ret = clk_prepare_enable(tqspi->clk); if (ret < 0) dev_err(tqspi->dev, "failed to enable clock: %d\n", ret); @@ -1408,6 +1437,7 @@ static struct platform_driver tegra_qspi_driver = { .name = "tegra-qspi", .pm = &tegra_qspi_pm_ops, .of_match_table = tegra_qspi_of_match, + .acpi_match_table = ACPI_PTR(tegra_qspi_acpi_match), }, .probe = tegra_qspi_probe, .remove = tegra_qspi_remove, -- cgit v1.2.3 From 1b8342cc4a387933780c50f0cf51c94455be7d11 Mon Sep 17 00:00:00 2001 From: Krishna Yarlagadda Date: Mon, 7 Mar 2022 22:25:18 +0530 Subject: spi: tegra210-quad: combined sequence mode Add combined sequence mode supported by Tegra QSPI controller. For commands which contain cmd, addr, data parts to it, controller can accept all 3 transfers at once and avoid interrupt for each transfer. This would improve read & write performance. Signed-off-by: Krishna Yarlagadda Reported-by: kernel test robot Reported-by: Dan Carpenter Link: https://lore.kernel.org/r/20220307165519.38380-3-kyarlagadda@nvidia.com Signed-off-by: Mark Brown --- drivers/spi/spi-tegra210-quad.c | 238 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 233 insertions(+), 5 deletions(-) diff --git a/drivers/spi/spi-tegra210-quad.c b/drivers/spi/spi-tegra210-quad.c index 517a348d1c19..66f647f32876 100644 --- a/drivers/spi/spi-tegra210-quad.c +++ b/drivers/spi/spi-tegra210-quad.c @@ -121,14 +121,39 @@ #define QSPI_NUM_DUMMY_CYCLE(x) (((x) & 0xff) << 0) #define QSPI_DUMMY_CYCLES_MAX 0xff +#define QSPI_CMB_SEQ_CMD 0x19c +#define QSPI_COMMAND_VALUE_SET(X) (((x) & 0xFF) << 0) + +#define QSPI_CMB_SEQ_CMD_CFG 0x1a0 +#define QSPI_COMMAND_X1_X2_X4(x) (((x) & 0x3) << 13) +#define QSPI_COMMAND_X1_X2_X4_MASK (0x03 << 13) +#define QSPI_COMMAND_SDR_DDR BIT(12) +#define QSPI_COMMAND_SIZE_SET(x) (((x) & 0xFF) << 0) + +#define QSPI_GLOBAL_CONFIG 0X1a4 +#define QSPI_CMB_SEQ_EN BIT(0) + +#define QSPI_CMB_SEQ_ADDR 0x1a8 +#define QSPI_ADDRESS_VALUE_SET(X) (((x) & 0xFFFF) << 0) + +#define QSPI_CMB_SEQ_ADDR_CFG 0x1ac +#define QSPI_ADDRESS_X1_X2_X4(x) (((x) & 0x3) << 13) +#define QSPI_ADDRESS_X1_X2_X4_MASK (0x03 << 13) +#define QSPI_ADDRESS_SDR_DDR BIT(12) +#define QSPI_ADDRESS_SIZE_SET(x) (((x) & 0xFF) << 0) + #define DATA_DIR_TX BIT(0) #define DATA_DIR_RX BIT(1) #define QSPI_DMA_TIMEOUT (msecs_to_jiffies(1000)) #define DEFAULT_QSPI_DMA_BUF_LEN (64 * 1024) +#define CMD_TRANSFER 0 +#define ADDR_TRANSFER 1 +#define DATA_TRANSFER 2 struct tegra_qspi_soc_data { bool has_dma; + bool cmb_xfer_capable; }; struct tegra_qspi_client_data { @@ -912,7 +937,6 @@ static int tegra_qspi_setup(struct spi_device *spi) cdata = tegra_qspi_parse_cdata_dt(spi); spi->controller_data = cdata; } - spin_lock_irqsave(&tqspi->lock, flags); /* keep default cs state to inactive */ @@ -971,19 +995,179 @@ static void tegra_qspi_transfer_end(struct spi_device *spi) tegra_qspi_writel(tqspi, tqspi->def_command1_reg, QSPI_COMMAND1); } -static int tegra_qspi_transfer_one_message(struct spi_master *master, struct spi_message *msg) +static u32 tegra_qspi_cmd_config(bool is_ddr, u8 bus_width, u8 len) +{ + u32 cmd_config = 0; + + /* Extract Command configuration and value */ + if (is_ddr) + cmd_config |= QSPI_COMMAND_SDR_DDR; + else + cmd_config &= ~QSPI_COMMAND_SDR_DDR; + + cmd_config |= QSPI_COMMAND_X1_X2_X4(bus_width); + cmd_config |= QSPI_COMMAND_SIZE_SET((len * 8) - 1); + + return cmd_config; +} + +static u32 tegra_qspi_addr_config(bool is_ddr, u8 bus_width, u8 len) +{ + u32 addr_config = 0; + + /* Extract Address configuration and value */ + is_ddr = 0; //Only SDR mode supported + bus_width = 0; //X1 mode + + if (is_ddr) + addr_config |= QSPI_ADDRESS_SDR_DDR; + else + addr_config &= ~QSPI_ADDRESS_SDR_DDR; + + addr_config |= QSPI_ADDRESS_X1_X2_X4(bus_width); + addr_config |= QSPI_ADDRESS_SIZE_SET((len * 8) - 1); + + return addr_config; +} + +static int tegra_qspi_combined_seq_xfer(struct tegra_qspi *tqspi, + struct spi_message *msg) +{ + bool is_first_msg = true; + struct spi_transfer *xfer; + struct spi_device *spi = msg->spi; + u8 transfer_phase = 0; + u32 cmd1 = 0, dma_ctl = 0; + int ret = 0; + u32 address_value = 0; + u32 cmd_config = 0, addr_config = 0; + u8 cmd_value = 0, val = 0; + + /* Enable Combined sequence mode */ + val = tegra_qspi_readl(tqspi, QSPI_GLOBAL_CONFIG); + val |= QSPI_CMB_SEQ_EN; + tegra_qspi_writel(tqspi, val, QSPI_GLOBAL_CONFIG); + /* Process individual transfer list */ + list_for_each_entry(xfer, &msg->transfers, transfer_list) { + switch (transfer_phase) { + case CMD_TRANSFER: + /* X1 SDR mode */ + cmd_config = tegra_qspi_cmd_config(false, 0, + xfer->len); + cmd_value = *((const u8 *)(xfer->tx_buf)); + break; + case ADDR_TRANSFER: + /* X1 SDR mode */ + addr_config = tegra_qspi_addr_config(false, 0, + xfer->len); + address_value = *((const u32 *)(xfer->tx_buf)); + break; + case DATA_TRANSFER: + /* Program Command, Address value in register */ + tegra_qspi_writel(tqspi, cmd_value, QSPI_CMB_SEQ_CMD); + tegra_qspi_writel(tqspi, address_value, + QSPI_CMB_SEQ_ADDR); + /* Program Command and Address config in register */ + tegra_qspi_writel(tqspi, cmd_config, + QSPI_CMB_SEQ_CMD_CFG); + tegra_qspi_writel(tqspi, addr_config, + QSPI_CMB_SEQ_ADDR_CFG); + + reinit_completion(&tqspi->xfer_completion); + cmd1 = tegra_qspi_setup_transfer_one(spi, xfer, + is_first_msg); + ret = tegra_qspi_start_transfer_one(spi, xfer, + cmd1); + + if (ret < 0) { + dev_err(tqspi->dev, "Failed to start transfer-one: %d\n", + ret); + return ret; + } + + is_first_msg = false; + ret = wait_for_completion_timeout + (&tqspi->xfer_completion, + QSPI_DMA_TIMEOUT); + + if (WARN_ON(ret == 0)) { + dev_err(tqspi->dev, "QSPI Transfer failed with timeout: %d\n", + ret); + if (tqspi->is_curr_dma_xfer && + (tqspi->cur_direction & DATA_DIR_TX)) + dmaengine_terminate_all + (tqspi->tx_dma_chan); + + if (tqspi->is_curr_dma_xfer && + (tqspi->cur_direction & DATA_DIR_RX)) + dmaengine_terminate_all + (tqspi->rx_dma_chan); + + /* Abort transfer by resetting pio/dma bit */ + if (!tqspi->is_curr_dma_xfer) { + cmd1 = tegra_qspi_readl + (tqspi, + QSPI_COMMAND1); + cmd1 &= ~QSPI_PIO; + tegra_qspi_writel + (tqspi, cmd1, + QSPI_COMMAND1); + } else { + dma_ctl = tegra_qspi_readl + (tqspi, + QSPI_DMA_CTL); + dma_ctl &= ~QSPI_DMA_EN; + tegra_qspi_writel(tqspi, dma_ctl, + QSPI_DMA_CTL); + } + + /* Reset controller if timeout happens */ + if (device_reset(tqspi->dev) < 0) + dev_warn_once(tqspi->dev, + "device reset failed\n"); + ret = -EIO; + goto exit; + } + + if (tqspi->tx_status || tqspi->rx_status) { + dev_err(tqspi->dev, "QSPI Transfer failed\n"); + tqspi->tx_status = 0; + tqspi->rx_status = 0; + ret = -EIO; + goto exit; + } + break; + default: + ret = -EINVAL; + goto exit; + } + msg->actual_length += xfer->len; + transfer_phase++; + } + +exit: + msg->status = ret; + + return ret; +} + +static int tegra_qspi_non_combined_seq_xfer(struct tegra_qspi *tqspi, + struct spi_message *msg) { - struct tegra_qspi *tqspi = spi_master_get_devdata(master); struct spi_device *spi = msg->spi; struct spi_transfer *transfer; bool is_first_msg = true; - int ret; + int ret = 0, val = 0; msg->status = 0; msg->actual_length = 0; tqspi->tx_status = 0; tqspi->rx_status = 0; + /* Disable Combined sequence mode */ + val = tegra_qspi_readl(tqspi, QSPI_GLOBAL_CONFIG); + val &= ~QSPI_CMB_SEQ_EN; + tegra_qspi_writel(tqspi, val, QSPI_GLOBAL_CONFIG); list_for_each_entry(transfer, &msg->transfers, transfer_list) { struct spi_transfer *xfer = transfer; u8 dummy_bytes = 0; @@ -1021,7 +1205,6 @@ static int tegra_qspi_transfer_one_message(struct spi_master *master, struct spi goto complete_xfer; } - is_first_msg = false; ret = wait_for_completion_timeout(&tqspi->xfer_completion, QSPI_DMA_TIMEOUT); if (WARN_ON(ret == 0)) { @@ -1066,7 +1249,48 @@ complete_xfer: ret = 0; exit: msg->status = ret; + + return ret; +} + +static bool tegra_qspi_validate_cmb_seq(struct tegra_qspi *tqspi, + struct spi_message *msg) +{ + int transfer_count = 0; + struct spi_transfer *xfer; + + list_for_each_entry(xfer, &msg->transfers, transfer_list) { + transfer_count++; + } + if (!tqspi->soc_data->cmb_xfer_capable || transfer_count != 3) + return false; + xfer = list_first_entry(&msg->transfers, typeof(*xfer), + transfer_list); + if (xfer->len > 2) + return false; + xfer = list_next_entry(xfer, transfer_list); + if (xfer->len > 4 || xfer->len < 3) + return false; + xfer = list_next_entry(xfer, transfer_list); + if (!tqspi->soc_data->has_dma || xfer->len > (QSPI_FIFO_DEPTH << 2)) + return false; + + return true; +} + +static int tegra_qspi_transfer_one_message(struct spi_master *master, + struct spi_message *msg) +{ + struct tegra_qspi *tqspi = spi_master_get_devdata(master); + int ret; + + if (tegra_qspi_validate_cmb_seq(tqspi, msg)) + ret = tegra_qspi_combined_seq_xfer(tqspi, msg); + else + ret = tegra_qspi_non_combined_seq_xfer(tqspi, msg); + spi_finalize_current_message(master); + return ret; } @@ -1200,14 +1424,17 @@ static irqreturn_t tegra_qspi_isr_thread(int irq, void *context_data) static struct tegra_qspi_soc_data tegra210_qspi_soc_data = { .has_dma = true, + .cmb_xfer_capable = false, }; static struct tegra_qspi_soc_data tegra186_qspi_soc_data = { .has_dma = true, + .cmb_xfer_capable = true, }; static struct tegra_qspi_soc_data tegra234_qspi_soc_data = { .has_dma = false, + .cmb_xfer_capable = true, }; static const struct of_device_id tegra_qspi_of_match[] = { @@ -1278,6 +1505,7 @@ static int tegra_qspi_probe(struct platform_device *pdev) tqspi->dev = &pdev->dev; spin_lock_init(&tqspi->lock); + tqspi->soc_data = device_get_match_data(&pdev->dev); r = platform_get_resource(pdev, IORESOURCE_MEM, 0); tqspi->base = devm_ioremap_resource(&pdev->dev, r); if (IS_ERR(tqspi->base)) -- cgit v1.2.3 From 80ab9012bbf1011f57c06b3c6e4ac3816c4a86f5 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 7 Mar 2022 19:37:40 +0200 Subject: spi: topcliff-pch: Prevent usage of potentially stale DMA device DMA device is expected to be available while SPI transfer is ongoing. Prevent usage of potentially stale DMA device by keeping reference count till the end of the transfer. Fixes: 4d986ffa036a ("spi: add missing pci_dev_put() before return") Reported-by: Christophe JAILLET Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20220307173740.80996-1-andriy.shevchenko@linux.intel.com Signed-off-by: Mark Brown --- drivers/spi/spi-topcliff-pch.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/spi/spi-topcliff-pch.c b/drivers/spi/spi-topcliff-pch.c index 8e1cc345810a..dfaa1d79a78b 100644 --- a/drivers/spi/spi-topcliff-pch.c +++ b/drivers/spi/spi-topcliff-pch.c @@ -103,6 +103,7 @@ static int use_dma = 1; struct pch_spi_dma_ctrl { + struct pci_dev *dma_dev; struct dma_async_tx_descriptor *desc_tx; struct dma_async_tx_descriptor *desc_rx; struct pch_dma_slave param_tx; @@ -876,7 +877,6 @@ static void pch_spi_request_dma(struct pch_spi_data *data, int bpw) if (!chan) { dev_err(&data->master->dev, "ERROR: dma_request_channel FAILS(Tx)\n"); - data->use_dma = 0; goto out; } dma->chan_tx = chan; @@ -893,13 +893,15 @@ static void pch_spi_request_dma(struct pch_spi_data *data, int bpw) "ERROR: dma_request_channel FAILS(Rx)\n"); dma_release_channel(dma->chan_tx); dma->chan_tx = NULL; - data->use_dma = 0; goto out; } dma->chan_rx = chan; + dma->dma_dev = dma_dev; + return; out: pci_dev_put(dma_dev); + data->use_dma = 0; } static void pch_spi_release_dma(struct pch_spi_data *data) @@ -915,6 +917,8 @@ static void pch_spi_release_dma(struct pch_spi_data *data) dma_release_channel(dma->chan_rx); dma->chan_rx = NULL; } + + pci_dev_put(dma->dma_dev); } static void pch_spi_handle_dma(struct pch_spi_data *data, int *bpw) -- cgit v1.2.3 From 363d3c51bc5b3243b5b035a1f50d6d994a1b203f Mon Sep 17 00:00:00 2001 From: Alim Akhtar Date: Tue, 8 Mar 2022 17:46:39 +0530 Subject: spi: dt-bindings: samsung: Add fsd spi compatible Adds spi controller dt-binding compatible information for Tesla Full Self-Driving (FSD) SoC. Cc: linux-fsd@tesla.com Signed-off-by: Adithya K V Signed-off-by: Alim Akhtar Reviewed-by: Krzysztof Kozlowski Reviewed-by: Andi Shyti Link: https://lore.kernel.org/r/20220308121640.27344-1-alim.akhtar@samsung.com Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/spi/samsung,spi.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/spi/samsung,spi.yaml b/Documentation/devicetree/bindings/spi/samsung,spi.yaml index 61c77088e8ee..bf9a76d931d2 100644 --- a/Documentation/devicetree/bindings/spi/samsung,spi.yaml +++ b/Documentation/devicetree/bindings/spi/samsung,spi.yaml @@ -21,6 +21,7 @@ properties: - samsung,s3c6410-spi - samsung,s5pv210-spi # for S5PV210 and S5PC110 - samsung,exynos5433-spi + - tesla,fsd-spi - const: samsung,exynos7-spi deprecated: true -- cgit v1.2.3 From 4ebb15a15799da4954f1d4926fcd3263ea46e417 Mon Sep 17 00:00:00 2001 From: Alim Akhtar Date: Tue, 8 Mar 2022 17:46:40 +0530 Subject: spi: s3c64xx: Add spi port configuration for Tesla FSD SoC Add compatible and port configuration for spi controller for Tesla Full Self-Driving SoC. Cc: linux-fsd@tesla.com Signed-off-by: Aswani Reddy Signed-off-by: Alim Akhtar Reviewed-by: Krzysztof Kozlowski Reviewed-by: Andi Shyti Link: https://lore.kernel.org/r/20220308121640.27344-2-alim.akhtar@samsung.com Signed-off-by: Mark Brown --- drivers/spi/spi-s3c64xx.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/drivers/spi/spi-s3c64xx.c b/drivers/spi/spi-s3c64xx.c index 386550fca81c..423518bf0270 100644 --- a/drivers/spi/spi-s3c64xx.c +++ b/drivers/spi/spi-s3c64xx.c @@ -1440,6 +1440,16 @@ static const struct s3c64xx_spi_port_config exynos5433_spi_port_config = { .quirks = S3C64XX_SPI_QUIRK_CS_AUTO, }; +static struct s3c64xx_spi_port_config fsd_spi_port_config = { + .fifo_lvl_mask = { 0x7f, 0x7f, 0x7f, 0x7f, 0x7f}, + .rx_lvl_offset = 15, + .tx_st_done = 25, + .high_speed = true, + .clk_from_cmu = true, + .clk_ioclk = false, + .quirks = S3C64XX_SPI_QUIRK_CS_AUTO, +}; + static const struct platform_device_id s3c64xx_spi_driver_ids[] = { { .name = "s3c2443-spi", @@ -1470,6 +1480,9 @@ static const struct of_device_id s3c64xx_spi_dt_match[] = { { .compatible = "samsung,exynos5433-spi", .data = (void *)&exynos5433_spi_port_config, }, + { .compatible = "tesla,fsd-spi", + .data = (void *)&fsd_spi_port_config, + }, { }, }; MODULE_DEVICE_TABLE(of, s3c64xx_spi_dt_match); -- cgit v1.2.3 From 2cfdf0b4441aa918c3b18142740c92407b3c35a2 Mon Sep 17 00:00:00 2001 From: Yihao Han Date: Thu, 10 Mar 2022 01:48:06 -0800 Subject: spi: rockchip-sfc: fix platform_get_irq.cocci warning Remove dev_err() messages after platform_get_irq*() failures. platform_get_irq() already prints an error. Generated by: scripts/coccinelle/api/platform_get_irq.cocci Signed-off-by: Yihao Han Link: https://lore.kernel.org/r/20220310094806.13734-1-hanyihao@vivo.com Signed-off-by: Mark Brown --- drivers/spi/spi-rockchip-sfc.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/spi/spi-rockchip-sfc.c b/drivers/spi/spi-rockchip-sfc.c index a46b38544027..bd87d3c92dd3 100644 --- a/drivers/spi/spi-rockchip-sfc.c +++ b/drivers/spi/spi-rockchip-sfc.c @@ -624,10 +624,8 @@ static int rockchip_sfc_probe(struct platform_device *pdev) /* Find the irq */ ret = platform_get_irq(pdev, 0); - if (ret < 0) { - dev_err(dev, "Failed to get the irq\n"); + if (ret < 0) goto err_irq; - } ret = devm_request_irq(dev, ret, rockchip_sfc_irq_handler, 0, pdev->name, sfc); -- cgit v1.2.3 From 1889421a891ff439b25495011b8b75f81660abca Mon Sep 17 00:00:00 2001 From: Kuldeep Singh Date: Wed, 9 Mar 2022 22:48:47 +0530 Subject: spi: Update clock-names property for arm pl022 PL022 has two input clocks named sspclk and apb_pclk. Current schema refers to two notations of sspclk which are indeed same and thus one can be dropped. Update clock-names property to reflect the same. Signed-off-by: Kuldeep Singh Link: https://lore.kernel.org/r/20220309171847.5345-1-singh.kuldeep87k@gmail.com Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/spi/spi-pl022.yaml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/Documentation/devicetree/bindings/spi/spi-pl022.yaml b/Documentation/devicetree/bindings/spi/spi-pl022.yaml index 6d633728fc2b..bda45ff3d294 100644 --- a/Documentation/devicetree/bindings/spi/spi-pl022.yaml +++ b/Documentation/devicetree/bindings/spi/spi-pl022.yaml @@ -38,9 +38,7 @@ properties: clock-names: items: - - enum: - - SSPCLK - - sspclk + - const: sspclk - const: apb_pclk pl022,autosuspend-delay: -- cgit v1.2.3 From 03b1be379dcee2e9c866c2a455a1a4a9581b3efd Mon Sep 17 00:00:00 2001 From: Leilk Liu Date: Tue, 15 Mar 2022 11:24:06 +0800 Subject: spi: mediatek: support tick_delay without enhance_timing this patch support tick_delay bit[31:30] without enhance_timing feature. Fixes: f84d866ab43f("spi: mediatek: add tick_delay support") Signed-off-by: Leilk Liu Reviewed-by: AngeloGioacchino Del Regno Link: https://lore.kernel.org/r/20220315032411.2826-2-leilk.liu@mediatek.com Signed-off-by: Mark Brown --- drivers/spi/spi-mt65xx.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/drivers/spi/spi-mt65xx.c b/drivers/spi/spi-mt65xx.c index bbfeb8046c17..3fd89548ec3c 100644 --- a/drivers/spi/spi-mt65xx.c +++ b/drivers/spi/spi-mt65xx.c @@ -43,8 +43,11 @@ #define SPI_CFG1_PACKET_LOOP_OFFSET 8 #define SPI_CFG1_PACKET_LENGTH_OFFSET 16 #define SPI_CFG1_GET_TICK_DLY_OFFSET 29 +#define SPI_CFG1_GET_TICK_DLY_OFFSET_V1 30 #define SPI_CFG1_GET_TICK_DLY_MASK 0xe0000000 +#define SPI_CFG1_GET_TICK_DLY_MASK_V1 0xc0000000 + #define SPI_CFG1_CS_IDLE_MASK 0xff #define SPI_CFG1_PACKET_LOOP_MASK 0xff00 #define SPI_CFG1_PACKET_LENGTH_MASK 0x3ff0000 @@ -346,9 +349,15 @@ static int mtk_spi_prepare_message(struct spi_master *master, /* tick delay */ reg_val = readl(mdata->base + SPI_CFG1_REG); - reg_val &= ~SPI_CFG1_GET_TICK_DLY_MASK; - reg_val |= ((chip_config->tick_delay & 0x7) - << SPI_CFG1_GET_TICK_DLY_OFFSET); + if (mdata->dev_comp->enhance_timing) { + reg_val &= ~SPI_CFG1_GET_TICK_DLY_MASK; + reg_val |= ((chip_config->tick_delay & 0x7) + << SPI_CFG1_GET_TICK_DLY_OFFSET); + } else { + reg_val &= ~SPI_CFG1_GET_TICK_DLY_MASK_V1; + reg_val |= ((chip_config->tick_delay & 0x3) + << SPI_CFG1_GET_TICK_DLY_OFFSET_V1); + } writel(reg_val, mdata->base + SPI_CFG1_REG); /* set hw cs timing */ -- cgit v1.2.3 From 2002c13243d595e211c0dad6b8e2e87f906f474b Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Mon, 14 Mar 2022 12:53:45 +0100 Subject: spi: sun4i: fix typos in comments Various spelling mistakes in comments. Detected with the help of Coccinelle. Signed-off-by: Julia Lawall Acked-by: Chen-Yu Tsai Link: https://lore.kernel.org/r/20220314115354.144023-22-Julia.Lawall@inria.fr Signed-off-by: Mark Brown --- drivers/spi/spi-sun4i.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/spi/spi-sun4i.c b/drivers/spi/spi-sun4i.c index 1fdfc6e6691d..6000d0761206 100644 --- a/drivers/spi/spi-sun4i.c +++ b/drivers/spi/spi-sun4i.c @@ -280,7 +280,7 @@ static int sun4i_spi_transfer_one(struct spi_master *master, * SPI_CLK = MOD_CLK / (2 ^ (cdr + 1)) * Or we can use CDR2, which is calculated with the formula: * SPI_CLK = MOD_CLK / (2 * (cdr + 1)) - * Wether we use the former or the latter is set through the + * Whether we use the former or the latter is set through the * DRS bit. * * First try CDR2, and if we can't reach the expected -- cgit v1.2.3 From da40a352db2bae470a3eea038cc53454c24e67f3 Mon Sep 17 00:00:00 2001 From: Leilk Liu Date: Tue, 15 Mar 2022 11:24:07 +0800 Subject: spi: Add compatible for MT7986 This patch adds dt-binding documentation for MT7986. Signed-off-by: Leilk Liu Reviewed-by: AngeloGioacchino Del Regno Link: https://lore.kernel.org/r/20220315032411.2826-3-leilk.liu@mediatek.com Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/spi/mediatek,spi-mt65xx.yaml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Documentation/devicetree/bindings/spi/mediatek,spi-mt65xx.yaml b/Documentation/devicetree/bindings/spi/mediatek,spi-mt65xx.yaml index ac9ff12ae27a..818130b11bb9 100644 --- a/Documentation/devicetree/bindings/spi/mediatek,spi-mt65xx.yaml +++ b/Documentation/devicetree/bindings/spi/mediatek,spi-mt65xx.yaml @@ -30,6 +30,10 @@ properties: - mediatek,mt8192-spi - mediatek,mt8195-spi - const: mediatek,mt6765-spi + - items: + - enum: + - mediatek,mt7986-spi-ipm + - const: mediatek,spi-ipm - items: - enum: - mediatek,mt2701-spi -- cgit v1.2.3 From 7e963fb2a33ce488e65258ab5be38a4855923033 Mon Sep 17 00:00:00 2001 From: Leilk Liu Date: Tue, 15 Mar 2022 11:24:08 +0800 Subject: spi: mediatek: add ipm design support for MT7986 this patch add the support of ipm design. Signed-off-by: Leilk Liu Reviewed-by: AngeloGioacchino Del Regno Link: https://lore.kernel.org/r/20220315032411.2826-4-leilk.liu@mediatek.com Signed-off-by: Mark Brown --- drivers/spi/spi-mt65xx.c | 102 ++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 87 insertions(+), 15 deletions(-) diff --git a/drivers/spi/spi-mt65xx.c b/drivers/spi/spi-mt65xx.c index 3fd89548ec3c..1a0b3208dfca 100644 --- a/drivers/spi/spi-mt65xx.c +++ b/drivers/spi/spi-mt65xx.c @@ -31,6 +31,7 @@ #define SPI_CFG2_REG 0x0028 #define SPI_TX_SRC_REG_64 0x002c #define SPI_RX_DST_REG_64 0x0030 +#define SPI_CFG3_IPM_REG 0x0040 #define SPI_CFG0_SCK_HIGH_OFFSET 0 #define SPI_CFG0_SCK_LOW_OFFSET 8 @@ -51,6 +52,7 @@ #define SPI_CFG1_CS_IDLE_MASK 0xff #define SPI_CFG1_PACKET_LOOP_MASK 0xff00 #define SPI_CFG1_PACKET_LENGTH_MASK 0x3ff0000 +#define SPI_CFG1_IPM_PACKET_LENGTH_MASK GENMASK(31, 16) #define SPI_CFG2_SCK_HIGH_OFFSET 0 #define SPI_CFG2_SCK_LOW_OFFSET 16 @@ -71,7 +73,13 @@ #define SPI_CMD_TX_ENDIAN BIT(15) #define SPI_CMD_FINISH_IE BIT(16) #define SPI_CMD_PAUSE_IE BIT(17) +#define SPI_CMD_IPM_NONIDLE_MODE BIT(19) +#define SPI_CMD_IPM_SPIM_LOOP BIT(21) +#define SPI_CMD_IPM_GET_TICKDLY_OFFSET 22 +#define SPI_CMD_IPM_GET_TICKDLY_MASK GENMASK(24, 22) +#define SPI_CFG3_IPM_HALF_DUPLEX_DIR BIT(2) +#define SPI_CFG3_IPM_HALF_DUPLEX_EN BIT(3) #define MT8173_SPI_MAX_PAD_SEL 3 #define MTK_SPI_PAUSE_INT_STATUS 0x2 @@ -81,6 +89,7 @@ #define MTK_SPI_MAX_FIFO_SIZE 32U #define MTK_SPI_PACKET_SIZE 1024 +#define MTK_SPI_IPM_PACKET_SIZE SZ_64K #define MTK_SPI_32BITS_MASK (0xffffffff) #define DMA_ADDR_EXT_BITS (36) @@ -96,6 +105,9 @@ struct mtk_spi_compatible { bool dma_ext; /* some IC no need unprepare SPI clk */ bool no_need_unprepare; + /* IPM design adjust and extend register to support more features */ + bool ipm_design; + }; struct mtk_spi { @@ -119,6 +131,12 @@ static const struct mtk_spi_compatible mt2712_compat = { .must_tx = true, }; +static const struct mtk_spi_compatible mtk_ipm_compat = { + .enhance_timing = true, + .dma_ext = true, + .ipm_design = true, +}; + static const struct mtk_spi_compatible mt6765_compat = { .need_pad_sel = true, .must_tx = true, @@ -160,6 +178,9 @@ static const struct mtk_chip_config mtk_default_chip_info = { }; static const struct of_device_id mtk_spi_of_match[] = { + { .compatible = "mediatek,spi-ipm", + .data = (void *)&mtk_ipm_compat, + }, { .compatible = "mediatek,mt2701-spi", .data = (void *)&mtk_common_compat, }, @@ -278,12 +299,11 @@ static int mtk_spi_set_hw_cs_timing(struct spi_device *spi) return 0; } -static int mtk_spi_prepare_message(struct spi_master *master, - struct spi_message *msg) +static int mtk_spi_hw_init(struct spi_master *master, + struct spi_device *spi) { u16 cpha, cpol; u32 reg_val; - struct spi_device *spi = msg->spi; struct mtk_chip_config *chip_config = spi->controller_data; struct mtk_spi *mdata = spi_master_get_devdata(master); @@ -291,6 +311,15 @@ static int mtk_spi_prepare_message(struct spi_master *master, cpol = spi->mode & SPI_CPOL ? 1 : 0; reg_val = readl(mdata->base + SPI_CMD_REG); + if (mdata->dev_comp->ipm_design) { + /* SPI transfer without idle time until packet length done */ + reg_val |= SPI_CMD_IPM_NONIDLE_MODE; + if (spi->mode & SPI_LOOP) + reg_val |= SPI_CMD_IPM_SPIM_LOOP; + else + reg_val &= ~SPI_CMD_IPM_SPIM_LOOP; + } + if (cpha) reg_val |= SPI_CMD_CPHA; else @@ -348,23 +377,39 @@ static int mtk_spi_prepare_message(struct spi_master *master, mdata->base + SPI_PAD_SEL_REG); /* tick delay */ - reg_val = readl(mdata->base + SPI_CFG1_REG); if (mdata->dev_comp->enhance_timing) { - reg_val &= ~SPI_CFG1_GET_TICK_DLY_MASK; - reg_val |= ((chip_config->tick_delay & 0x7) - << SPI_CFG1_GET_TICK_DLY_OFFSET); + if (mdata->dev_comp->ipm_design) { + reg_val = readl(mdata->base + SPI_CMD_REG); + reg_val &= ~SPI_CMD_IPM_GET_TICKDLY_MASK; + reg_val |= ((chip_config->tick_delay & 0x7) + << SPI_CMD_IPM_GET_TICKDLY_OFFSET); + writel(reg_val, mdata->base + SPI_CMD_REG); + } else { + reg_val = readl(mdata->base + SPI_CFG1_REG); + reg_val &= ~SPI_CFG1_GET_TICK_DLY_MASK; + reg_val |= ((chip_config->tick_delay & 0x7) + << SPI_CFG1_GET_TICK_DLY_OFFSET); + writel(reg_val, mdata->base + SPI_CFG1_REG); + } } else { + reg_val = readl(mdata->base + SPI_CFG1_REG); reg_val &= ~SPI_CFG1_GET_TICK_DLY_MASK_V1; reg_val |= ((chip_config->tick_delay & 0x3) << SPI_CFG1_GET_TICK_DLY_OFFSET_V1); + writel(reg_val, mdata->base + SPI_CFG1_REG); } - writel(reg_val, mdata->base + SPI_CFG1_REG); /* set hw cs timing */ mtk_spi_set_hw_cs_timing(spi); return 0; } +static int mtk_spi_prepare_message(struct spi_master *master, + struct spi_message *msg) +{ + return mtk_spi_hw_init(master, msg->spi); +} + static void mtk_spi_set_cs(struct spi_device *spi, bool enable) { u32 reg_val; @@ -386,13 +431,13 @@ static void mtk_spi_set_cs(struct spi_device *spi, bool enable) } static void mtk_spi_prepare_transfer(struct spi_master *master, - struct spi_transfer *xfer) + u32 speed_hz) { u32 div, sck_time, reg_val; struct mtk_spi *mdata = spi_master_get_devdata(master); - if (xfer->speed_hz < mdata->spi_clk_hz / 2) - div = DIV_ROUND_UP(mdata->spi_clk_hz, xfer->speed_hz); + if (speed_hz < mdata->spi_clk_hz / 2) + div = DIV_ROUND_UP(mdata->spi_clk_hz, speed_hz); else div = 1; @@ -423,12 +468,24 @@ static void mtk_spi_setup_packet(struct spi_master *master) u32 packet_size, packet_loop, reg_val; struct mtk_spi *mdata = spi_master_get_devdata(master); - packet_size = min_t(u32, mdata->xfer_len, MTK_SPI_PACKET_SIZE); + if (mdata->dev_comp->ipm_design) + packet_size = min_t(u32, + mdata->xfer_len, + MTK_SPI_IPM_PACKET_SIZE); + else + packet_size = min_t(u32, + mdata->xfer_len, + MTK_SPI_PACKET_SIZE); + packet_loop = mdata->xfer_len / packet_size; reg_val = readl(mdata->base + SPI_CFG1_REG); - reg_val &= ~(SPI_CFG1_PACKET_LENGTH_MASK | SPI_CFG1_PACKET_LOOP_MASK); + if (mdata->dev_comp->ipm_design) + reg_val &= ~SPI_CFG1_IPM_PACKET_LENGTH_MASK; + else + reg_val &= ~SPI_CFG1_PACKET_LENGTH_MASK; reg_val |= (packet_size - 1) << SPI_CFG1_PACKET_LENGTH_OFFSET; + reg_val &= ~SPI_CFG1_PACKET_LOOP_MASK; reg_val |= (packet_loop - 1) << SPI_CFG1_PACKET_LOOP_OFFSET; writel(reg_val, mdata->base + SPI_CFG1_REG); } @@ -523,7 +580,7 @@ static int mtk_spi_fifo_transfer(struct spi_master *master, mdata->cur_transfer = xfer; mdata->xfer_len = min(MTK_SPI_MAX_FIFO_SIZE, xfer->len); mdata->num_xfered = 0; - mtk_spi_prepare_transfer(master, xfer); + mtk_spi_prepare_transfer(master, xfer->speed_hz); mtk_spi_setup_packet(master); if (xfer->tx_buf) { @@ -556,7 +613,7 @@ static int mtk_spi_dma_transfer(struct spi_master *master, mdata->cur_transfer = xfer; mdata->num_xfered = 0; - mtk_spi_prepare_transfer(master, xfer); + mtk_spi_prepare_transfer(master, xfer->speed_hz); cmd = readl(mdata->base + SPI_CMD_REG); if (xfer->tx_buf) @@ -591,6 +648,19 @@ static int mtk_spi_transfer_one(struct spi_master *master, struct spi_device *spi, struct spi_transfer *xfer) { + struct mtk_spi *mdata = spi_master_get_devdata(spi->master); + u32 reg_val = 0; + + /* prepare xfer direction and duplex mode */ + if (mdata->dev_comp->ipm_design) { + if (!xfer->tx_buf || !xfer->rx_buf) { + reg_val |= SPI_CFG3_IPM_HALF_DUPLEX_EN; + if (xfer->rx_buf) + reg_val |= SPI_CFG3_IPM_HALF_DUPLEX_DIR; + } + writel(reg_val, mdata->base + SPI_CFG3_IPM_REG); + } + if (master->can_dma(master, spi, xfer)) return mtk_spi_dma_transfer(master, spi, xfer); else @@ -757,6 +827,8 @@ static int mtk_spi_probe(struct platform_device *pdev) if (mdata->dev_comp->must_tx) master->flags = SPI_MASTER_MUST_TX; + if (mdata->dev_comp->ipm_design) + master->mode_bits |= SPI_LOOP; if (mdata->dev_comp->need_pad_sel) { mdata->pad_num = of_property_count_u32_elems( -- cgit v1.2.3 From c9839acfcbe20ce43d363c2a9d0772472d9921c0 Mon Sep 17 00:00:00 2001 From: Minghao Chi Date: Tue, 15 Mar 2022 02:31:38 +0000 Subject: spi: tegra20: Use of_device_get_match_data() Use of_device_get_match_data() to simplify the code. Reported-by: Zeal Robot Signed-off-by: Minghao Chi Link: https://lore.kernel.org/r/20220315023138.2118293-1-chi.minghao@zte.com.cn Signed-off-by: Mark Brown --- drivers/spi/spi-tegra20-slink.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/drivers/spi/spi-tegra20-slink.c b/drivers/spi/spi-tegra20-slink.c index 2a03739a0c60..80c3787deea9 100644 --- a/drivers/spi/spi-tegra20-slink.c +++ b/drivers/spi/spi-tegra20-slink.c @@ -1006,14 +1006,8 @@ static int tegra_slink_probe(struct platform_device *pdev) struct resource *r; int ret, spi_irq; const struct tegra_slink_chip_data *cdata = NULL; - const struct of_device_id *match; - match = of_match_device(tegra_slink_of_match, &pdev->dev); - if (!match) { - dev_err(&pdev->dev, "Error: No device match found\n"); - return -ENODEV; - } - cdata = match->data; + cdata = of_device_get_match_data(&pdev->dev); master = spi_alloc_master(&pdev->dev, sizeof(*tspi)); if (!master) { -- cgit v1.2.3 From ebc4cb43ea5ada3db46c80156fca58a54b9bbca8 Mon Sep 17 00:00:00 2001 From: Biju Das Date: Wed, 16 Mar 2022 17:53:17 +0000 Subject: spi: Fix erroneous sgs value with min_t() While computing sgs in spi_map_buf(), the data type used in min_t() for max_seg_size is 'unsigned int' where as that of ctlr->max_dma_len is 'size_t'. min_t(unsigned int,x,y) gives wrong results if one of x/y is 'size_t' Consider the below examples on a 64-bit machine (ie size_t is 64-bits, and unsigned int is 32-bit). case 1) min_t(unsigned int, 5, 0x100000001); case 2) min_t(size_t, 5, 0x100000001); Case 1 returns '1', where as case 2 returns '5'. As you can see the result from case 1 is wrong. This patch fixes the above issue by using the data type of the parameters that are used in min_t with maximum data length. Fixes: commit 1a4e53d2fc4f68aa ("spi: Fix invalid sgs value") Reported-by: Linus Torvalds Suggested-by: Geert Uytterhoeven Signed-off-by: Biju Das Reviewed-by: Lad Prabhakar Link: https://lore.kernel.org/r/20220316175317.465-1-biju.das.jz@bp.renesas.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 6937cf2d59e0..c4dd1200fe99 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -1000,10 +1000,10 @@ int spi_map_buf(struct spi_controller *ctlr, struct device *dev, int i, ret; if (vmalloced_buf || kmap_buf) { - desc_len = min_t(unsigned int, max_seg_size, PAGE_SIZE); + desc_len = min_t(unsigned long, max_seg_size, PAGE_SIZE); sgs = DIV_ROUND_UP(len + offset_in_page(buf), desc_len); } else if (virt_addr_valid(buf)) { - desc_len = min_t(unsigned int, max_seg_size, ctlr->max_dma_len); + desc_len = min_t(size_t, max_seg_size, ctlr->max_dma_len); sgs = DIV_ROUND_UP(len, desc_len); } else { return -EINVAL; -- cgit v1.2.3 From 89b35e3f28514087d3f1e28e8f5634fbfd07c554 Mon Sep 17 00:00:00 2001 From: Eddie James Date: Thu, 17 Mar 2022 16:14:26 -0500 Subject: spi: fsi: Implement a timeout for polling status The data transfer routines must poll the status register to determine when more data can be shifted in or out. If the hardware gets into a bad state, these polling loops may never exit. Prevent this by returning an error if a timeout is exceeded. Signed-off-by: Eddie James Link: https://lore.kernel.org/r/20220317211426.38940-1-eajames@linux.ibm.com Signed-off-by: Mark Brown --- drivers/spi/spi-fsi.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/spi/spi-fsi.c b/drivers/spi/spi-fsi.c index b6c7467f0b59..d403a7a3021d 100644 --- a/drivers/spi/spi-fsi.c +++ b/drivers/spi/spi-fsi.c @@ -25,6 +25,7 @@ #define SPI_FSI_BASE 0x70000 #define SPI_FSI_INIT_TIMEOUT_MS 1000 +#define SPI_FSI_STATUS_TIMEOUT_MS 100 #define SPI_FSI_MAX_RX_SIZE 8 #define SPI_FSI_MAX_TX_SIZE 40 @@ -299,6 +300,7 @@ static int fsi_spi_transfer_data(struct fsi_spi *ctx, struct spi_transfer *transfer) { int rc = 0; + unsigned long end; u64 status = 0ULL; if (transfer->tx_buf) { @@ -315,10 +317,14 @@ static int fsi_spi_transfer_data(struct fsi_spi *ctx, if (rc) return rc; + end = jiffies + msecs_to_jiffies(SPI_FSI_STATUS_TIMEOUT_MS); do { rc = fsi_spi_status(ctx, &status, "TX"); if (rc) return rc; + + if (time_after(jiffies, end)) + return -ETIMEDOUT; } while (status & SPI_FSI_STATUS_TDR_FULL); sent += nb; @@ -329,10 +335,14 @@ static int fsi_spi_transfer_data(struct fsi_spi *ctx, u8 *rx = transfer->rx_buf; while (transfer->len > recv) { + end = jiffies + msecs_to_jiffies(SPI_FSI_STATUS_TIMEOUT_MS); do { rc = fsi_spi_status(ctx, &status, "RX"); if (rc) return rc; + + if (time_after(jiffies, end)) + return -ETIMEDOUT; } while (!(status & SPI_FSI_STATUS_RDR_FULL)); rc = fsi_spi_read_reg(ctx, SPI_FSI_DATA_RX, &in); -- cgit v1.2.3