From f271946117dde2ca8741b8138b347b2d68e6ad56 Mon Sep 17 00:00:00 2001 From: Jon Hunter Date: Fri, 28 Oct 2022 13:33:55 +0100 Subject: [PATCH 01/42] pwm: tegra: Improve required rate calculation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For the case where dev_pm_opp_set_rate() is called to set the PWM clock rate, the requested rate is calculated as ... required_clk_rate = (NSEC_PER_SEC / period_ns) << PWM_DUTY_WIDTH; The above calculation may lead to rounding errors because the NSEC_PER_SEC is divided by 'period_ns' before applying the PWM_DUTY_WIDTH multiplication factor. For example, if the period is 45334ns, the above calculation yields a rate of 5646848Hz instead of 5646976Hz. Fix this by applying the multiplication factor before dividing and using the DIV_ROUND_UP macro which yields the expected result of 5646976Hz. Fixes: 1d7796bdb63a ("pwm: tegra: Support dynamic clock frequency configuration") Signed-off-by: Jon Hunter Reviewed-by: Uwe Kleine-König Signed-off-by: Thierry Reding --- drivers/pwm/pwm-tegra.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/pwm/pwm-tegra.c b/drivers/pwm/pwm-tegra.c index dad9978c9186..b05ea2e8accc 100644 --- a/drivers/pwm/pwm-tegra.c +++ b/drivers/pwm/pwm-tegra.c @@ -145,8 +145,8 @@ static int tegra_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, * source clock rate as required_clk_rate, PWM controller will * be able to configure the requested period. */ - required_clk_rate = - (NSEC_PER_SEC / period_ns) << PWM_DUTY_WIDTH; + required_clk_rate = DIV_ROUND_UP_ULL(NSEC_PER_SEC << PWM_DUTY_WIDTH, + period_ns); err = dev_pm_opp_set_rate(pc->dev, required_clk_rate); if (err < 0) From 5eccd0d9fabc4d2ab8d2a0c056fb1d7e2ff892fc Mon Sep 17 00:00:00 2001 From: Jon Hunter Date: Fri, 28 Oct 2022 13:33:56 +0100 Subject: [PATCH 02/42] pwm: tegra: Ensure the clock rate is not less than needed MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When dynamically scaling the PWM clock, the function dev_pm_opp_set_rate() may set the PWM clock to a rate that is lower than what is required. The clock rate requested when calling dev_pm_opp_set_rate() is the minimum clock rate that is needed to drive the PWM to achieve the required period. Hence, if the actual clock rate is less than the requested clock rate, then the required period cannot be achieved and configuring the PWM fails. Fix this by calling clk_round_rate() to check if the clock rate that will be provided is sufficient and if not, double the required clock rate to ensure the required period can be attained. Fixes: 8c193f4714df ("pwm: tegra: Optimize period calculation") Signed-off-by: Jon Hunter Acked-by: Uwe Kleine-König Signed-off-by: Thierry Reding --- drivers/pwm/pwm-tegra.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/drivers/pwm/pwm-tegra.c b/drivers/pwm/pwm-tegra.c index b05ea2e8accc..6fc4b69a3ba7 100644 --- a/drivers/pwm/pwm-tegra.c +++ b/drivers/pwm/pwm-tegra.c @@ -148,6 +148,17 @@ static int tegra_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, required_clk_rate = DIV_ROUND_UP_ULL(NSEC_PER_SEC << PWM_DUTY_WIDTH, period_ns); + if (required_clk_rate > clk_round_rate(pc->clk, required_clk_rate)) + /* + * required_clk_rate is a lower bound for the input + * rate; for lower rates there is no value for PWM_SCALE + * that yields a period less than or equal to the + * requested period. Hence, for lower rates, double the + * required_clk_rate to get a clock rate that can meet + * the requested period. + */ + required_clk_rate *= 2; + err = dev_pm_opp_set_rate(pc->dev, required_clk_rate); if (err < 0) return -EINVAL; From dd1f1da4ada5d8ac774c2ebe97230637820b3323 Mon Sep 17 00:00:00 2001 From: Steven Price Date: Thu, 10 Nov 2022 11:45:48 +0000 Subject: [PATCH 03/42] pwm: tegra: Fix 32 bit build MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The value of NSEC_PER_SEC << PWM_DUTY_WIDTH doesn't fix within a 32 bit integer causing a build warning/error (and the value truncated): drivers/pwm/pwm-tegra.c: In function ‘tegra_pwm_config’: drivers/pwm/pwm-tegra.c:148:53: error: result of ‘1000000000 << 8’ requires 39 bits to represent, but ‘long int’ only has 32 bits [-Werror=shift-overflow=] 148 | required_clk_rate = DIV_ROUND_UP_ULL(NSEC_PER_SEC << PWM_DUTY_WIDTH, | ^~ Explicitly cast to a u64 to ensure the correct result. Fixes: cfcb68817fb3 ("pwm: tegra: Improve required rate calculation") Signed-off-by: Steven Price Reviewed-by: Uwe Kleine-König Reviewed-by: Jon Hunter --- drivers/pwm/pwm-tegra.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/pwm/pwm-tegra.c b/drivers/pwm/pwm-tegra.c index 6fc4b69a3ba7..249dc0193297 100644 --- a/drivers/pwm/pwm-tegra.c +++ b/drivers/pwm/pwm-tegra.c @@ -145,7 +145,7 @@ static int tegra_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, * source clock rate as required_clk_rate, PWM controller will * be able to configure the requested period. */ - required_clk_rate = DIV_ROUND_UP_ULL(NSEC_PER_SEC << PWM_DUTY_WIDTH, + required_clk_rate = DIV_ROUND_UP_ULL((u64)NSEC_PER_SEC << PWM_DUTY_WIDTH, period_ns); if (required_clk_rate > clk_round_rate(pc->clk, required_clk_rate)) From 5719efcc5abb34ceb47b03e58709d99713f80db1 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Mon, 21 Nov 2022 17:13:02 +0100 Subject: [PATCH 04/42] dt-bindings: pwm: renesas,pwm-rcar: Add r8a779g0 support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Document support for the PWM timers in the Renesas R-Car V4H (R8A779G0) SoC. Based on a patch in the BSP by CongDang. Signed-off-by: Geert Uytterhoeven Acked-by: Krzysztof Kozlowski Reviewed-by: Wolfram Sang Acked-by: Uwe Kleine-König Signed-off-by: Thierry Reding --- Documentation/devicetree/bindings/pwm/renesas,pwm-rcar.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/pwm/renesas,pwm-rcar.yaml b/Documentation/devicetree/bindings/pwm/renesas,pwm-rcar.yaml index 1c94acbc2b4a..4c8097010687 100644 --- a/Documentation/devicetree/bindings/pwm/renesas,pwm-rcar.yaml +++ b/Documentation/devicetree/bindings/pwm/renesas,pwm-rcar.yaml @@ -35,6 +35,7 @@ properties: - renesas,pwm-r8a77980 # R-Car V3H - renesas,pwm-r8a77990 # R-Car E3 - renesas,pwm-r8a77995 # R-Car D3 + - renesas,pwm-r8a779g0 # R-Car V4H - const: renesas,pwm-rcar reg: From 50315945d178eebec4e8e2c50c265767ddb926eb Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Mon, 21 Nov 2022 17:13:42 +0100 Subject: [PATCH 05/42] dt-bindings: pwm: renesas,tpu: Add r8a779g0 support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Document support for the 16-Bit Timer Pulse Unit (TPU) in the Renesas R-Car V4H (R8A779G0) SoC. Based on a patch in the BSP by CongDang. Signed-off-by: Geert Uytterhoeven Acked-by: Krzysztof Kozlowski Reviewed-by: Laurent Pinchart Reviewed-by: Wolfram Sang Acked-by: Uwe Kleine-König Signed-off-by: Thierry Reding --- Documentation/devicetree/bindings/pwm/renesas,tpu-pwm.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/pwm/renesas,tpu-pwm.yaml b/Documentation/devicetree/bindings/pwm/renesas,tpu-pwm.yaml index c6b2ab56b7fe..a3e52b22dd18 100644 --- a/Documentation/devicetree/bindings/pwm/renesas,tpu-pwm.yaml +++ b/Documentation/devicetree/bindings/pwm/renesas,tpu-pwm.yaml @@ -40,6 +40,7 @@ properties: - renesas,tpu-r8a77970 # R-Car V3M - renesas,tpu-r8a77980 # R-Car V3H - renesas,tpu-r8a779a0 # R-Car V3U + - renesas,tpu-r8a779g0 # R-Car V4H - const: renesas,tpu reg: From 731c47930f63883bae5de0293241f851042cbd77 Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Mon, 24 Oct 2022 21:52:11 +0100 Subject: [PATCH 06/42] pwm: jz4740: Force dependency on Device Tree MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Ingenic SoCs all require CONFIG_OF, so there is no case where we want to use this driver without CONFIG_OF. Signed-off-by: Paul Cercueil Acked-by: Uwe Kleine-König Signed-off-by: Thierry Reding --- drivers/pwm/Kconfig | 2 +- drivers/pwm/pwm-jz4740.c | 10 ++++------ 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig index 60d13a949bc5..1fe420a45f91 100644 --- a/drivers/pwm/Kconfig +++ b/drivers/pwm/Kconfig @@ -283,7 +283,7 @@ config PWM_IQS620A config PWM_JZ4740 tristate "Ingenic JZ47xx PWM support" depends on MIPS || COMPILE_TEST - depends on COMMON_CLK + depends on COMMON_CLK && OF select MFD_SYSCON help Generic PWM framework driver for Ingenic JZ47xx based diff --git a/drivers/pwm/pwm-jz4740.c b/drivers/pwm/pwm-jz4740.c index a5fdf97c0d2e..1a1a651c2cce 100644 --- a/drivers/pwm/pwm-jz4740.c +++ b/drivers/pwm/pwm-jz4740.c @@ -248,19 +248,18 @@ static int jz4740_pwm_probe(struct platform_device *pdev) return devm_pwmchip_add(dev, &jz4740->chip); } -static const struct soc_info __maybe_unused jz4740_soc_info = { +static const struct soc_info jz4740_soc_info = { .num_pwms = 8, }; -static const struct soc_info __maybe_unused jz4725b_soc_info = { +static const struct soc_info jz4725b_soc_info = { .num_pwms = 6, }; -static const struct soc_info __maybe_unused x1000_soc_info = { +static const struct soc_info x1000_soc_info = { .num_pwms = 5, }; -#ifdef CONFIG_OF static const struct of_device_id jz4740_pwm_dt_ids[] = { { .compatible = "ingenic,jz4740-pwm", .data = &jz4740_soc_info }, { .compatible = "ingenic,jz4725b-pwm", .data = &jz4725b_soc_info }, @@ -268,12 +267,11 @@ static const struct of_device_id jz4740_pwm_dt_ids[] = { {}, }; MODULE_DEVICE_TABLE(of, jz4740_pwm_dt_ids); -#endif static struct platform_driver jz4740_pwm_driver = { .driver = { .name = "jz4740-pwm", - .of_match_table = of_match_ptr(jz4740_pwm_dt_ids), + .of_match_table = jz4740_pwm_dt_ids, }, .probe = jz4740_pwm_probe, }; From 69ba53dac3b16a3b0aa65e7817901e67bc554b32 Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Mon, 24 Oct 2022 21:52:12 +0100 Subject: [PATCH 07/42] pwm: jz4740: Depend on MACH_INGENIC instead of MIPS MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The MACH_INGENIC Kconfig option will be selected when building a kernel targeting Ingenic SoCs, but also when compiling a generic MIPS kernel that happens to support Ingenic SoCs. Therefore, if MACH_INGENIC is not set, we know that we're not even trying to build a generic kernel that supports these SoCs, and we can hide the options to compile the SoC-specific drivers. Signed-off-by: Paul Cercueil Acked-by: Uwe Kleine-König Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Thierry Reding --- drivers/pwm/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig index 1fe420a45f91..cb623d0702f6 100644 --- a/drivers/pwm/Kconfig +++ b/drivers/pwm/Kconfig @@ -282,7 +282,7 @@ config PWM_IQS620A config PWM_JZ4740 tristate "Ingenic JZ47xx PWM support" - depends on MIPS || COMPILE_TEST + depends on MACH_INGENIC || COMPILE_TEST depends on COMMON_CLK && OF select MFD_SYSCON help From 7d9199995412fd30ea79e24d6c29f04a9b5d49ee Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Mon, 24 Oct 2022 21:52:13 +0100 Subject: [PATCH 08/42] pwm: jz4740: Use regmap_{set,clear}_bits MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Simplify a bit the code by using regmap_set_bits() and regmap_clear_bits() instead of regmap_update_bits() when possible. Signed-off-by: Paul Cercueil Reviewed-by: Philippe Mathieu-Daudé Acked-by: Uwe Kleine-König Signed-off-by: Thierry Reding --- drivers/pwm/pwm-jz4740.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/drivers/pwm/pwm-jz4740.c b/drivers/pwm/pwm-jz4740.c index 1a1a651c2cce..3b7067f6cd0d 100644 --- a/drivers/pwm/pwm-jz4740.c +++ b/drivers/pwm/pwm-jz4740.c @@ -88,8 +88,7 @@ static int jz4740_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm) struct jz4740_pwm_chip *jz = to_jz4740(chip); /* Enable PWM output */ - regmap_update_bits(jz->map, TCU_REG_TCSRc(pwm->hwpwm), - TCU_TCSR_PWM_EN, TCU_TCSR_PWM_EN); + regmap_set_bits(jz->map, TCU_REG_TCSRc(pwm->hwpwm), TCU_TCSR_PWM_EN); /* Start counter */ regmap_write(jz->map, TCU_REG_TESR, BIT(pwm->hwpwm)); @@ -113,8 +112,7 @@ static void jz4740_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm) * In TCU2 mode (channel 1/2 on JZ4750+), this must be done before the * counter is stopped, while in TCU1 mode the order does not matter. */ - regmap_update_bits(jz->map, TCU_REG_TCSRc(pwm->hwpwm), - TCU_TCSR_PWM_EN, 0); + regmap_clear_bits(jz->map, TCU_REG_TCSRc(pwm->hwpwm), TCU_TCSR_PWM_EN); /* Stop counter */ regmap_write(jz->map, TCU_REG_TECR, BIT(pwm->hwpwm)); @@ -184,8 +182,8 @@ static int jz4740_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, regmap_write(jz4740->map, TCU_REG_TDFRc(pwm->hwpwm), period); /* Set abrupt shutdown */ - regmap_update_bits(jz4740->map, TCU_REG_TCSRc(pwm->hwpwm), - TCU_TCSR_PWM_SD, TCU_TCSR_PWM_SD); + regmap_set_bits(jz4740->map, TCU_REG_TCSRc(pwm->hwpwm), + TCU_TCSR_PWM_SD); /* * Set polarity. From 45558b3abb87eeb2cedb8a59cb2699c120b5102a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Fri, 2 Dec 2022 19:35:05 +0100 Subject: [PATCH 09/42] pwm: sifive: Call pwm_sifive_update_clock() while mutex is held MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As was documented in commit 0f02f491b786 ("pwm: sifive: Reduce time the controller lock is held") a caller of pwm_sifive_update_clock() must hold the mutex. So fix pwm_sifive_clock_notifier() to grab the lock. While this necessity was only documented later, the race exists since the driver was introduced. Fixes: 9e37a53eb051 ("pwm: sifive: Add a driver for SiFive SoC PWM") Reported-by: Emil Renner Berthing Reviewed-by: Emil Renner Berthing Link: https://lore.kernel.org/r/20221018061656.1428111-1-u.kleine-koenig@pengutronix.de Signed-off-by: Uwe Kleine-König Signed-off-by: Thierry Reding --- drivers/pwm/pwm-sifive.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/pwm/pwm-sifive.c b/drivers/pwm/pwm-sifive.c index 2d4fa5e5fdd4..bb7239313401 100644 --- a/drivers/pwm/pwm-sifive.c +++ b/drivers/pwm/pwm-sifive.c @@ -204,8 +204,11 @@ static int pwm_sifive_clock_notifier(struct notifier_block *nb, struct pwm_sifive_ddata *ddata = container_of(nb, struct pwm_sifive_ddata, notifier); - if (event == POST_RATE_CHANGE) + if (event == POST_RATE_CHANGE) { + mutex_lock(&ddata->lock); pwm_sifive_update_clock(ddata, ndata->new_rate); + mutex_unlock(&ddata->lock); + } return NOTIFY_OK; } From 0b5ef3429d8f78427558ab0dcbfd862098ba2a63 Mon Sep 17 00:00:00 2001 From: xinlei lee Date: Fri, 2 Dec 2022 19:35:06 +0100 Subject: [PATCH 10/42] pwm: mtk-disp: Fix the parameters calculated by the enabled flag of disp_pwm MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In the original mtk_disp_pwm_get_state() function wrongly uses bit 0 of CON0 to judge if the PWM is enabled. However that is indicated by a bit (at a machine dependent position) in the DISP_PWM_EN register. Fix this accordingly. Fixes: 3f2b16734914 ("pwm: mtk-disp: Implement atomic API .get_state()") Signed-off-by: xinlei lee Reviewed-by: Uwe Kleine-König Reviewed-by: AngeloGioacchino Del Regno Link: https://lore.kernel.org/r/1666172538-11652-1-git-send-email-xinlei.lee@mediatek.com Signed-off-by: Uwe Kleine-König Signed-off-by: Thierry Reding --- drivers/pwm/pwm-mtk-disp.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/pwm/pwm-mtk-disp.c b/drivers/pwm/pwm-mtk-disp.c index c605013e4114..3fbb4bae93a4 100644 --- a/drivers/pwm/pwm-mtk-disp.c +++ b/drivers/pwm/pwm-mtk-disp.c @@ -178,7 +178,7 @@ static void mtk_disp_pwm_get_state(struct pwm_chip *chip, { struct mtk_disp_pwm *mdp = to_mtk_disp_pwm(chip); u64 rate, period, high_width; - u32 clk_div, con0, con1; + u32 clk_div, pwm_en, con0, con1; int err; err = clk_prepare_enable(mdp->clk_main); @@ -197,7 +197,8 @@ static void mtk_disp_pwm_get_state(struct pwm_chip *chip, rate = clk_get_rate(mdp->clk_main); con0 = readl(mdp->base + mdp->data->con0); con1 = readl(mdp->base + mdp->data->con1); - state->enabled = !!(con0 & BIT(0)); + pwm_en = readl(mdp->base + DISP_PWM_EN); + state->enabled = !!(pwm_en & mdp->data->enable_mask); clk_div = FIELD_GET(PWM_CLKDIV_MASK, con0); period = FIELD_GET(PWM_PERIOD_MASK, con1); /* From 07d8d8d29aa76f3c28020a9c914cc890eb86a48c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Fri, 2 Dec 2022 19:35:07 +0100 Subject: [PATCH 11/42] pwm: lpc18xx-sct: Fix a comment to match code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit lpc18xx_pwm_probe() only ensures clk_rate <= NSEC_PER_SEC, the following reasoning is right even under this slightly lesser condition. Fixes: 8933d30c5f46 ("pwm: lpc18xx: Fix period handling") Acked-by: Vladimir Zapolskiy Link: https://lore.kernel.org/r/20221108153013.132514-1-u.kleine-koenig@pengutronix.de Signed-off-by: Uwe Kleine-König Signed-off-by: Thierry Reding --- drivers/pwm/pwm-lpc18xx-sct.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/pwm/pwm-lpc18xx-sct.c b/drivers/pwm/pwm-lpc18xx-sct.c index 763f2e3a146d..378e1df944dc 100644 --- a/drivers/pwm/pwm-lpc18xx-sct.c +++ b/drivers/pwm/pwm-lpc18xx-sct.c @@ -175,7 +175,7 @@ static void lpc18xx_pwm_config_duty(struct pwm_chip *chip, u32 val; /* - * With clk_rate < NSEC_PER_SEC this cannot overflow. + * With clk_rate <= NSEC_PER_SEC this cannot overflow. * With duty_ns <= period_ns < max_period_ns this also fits into an u32. */ val = mul_u64_u64_div_u64(duty_ns, lpc18xx_pwm->clk_rate, NSEC_PER_SEC); From aa3c668f2f98856af96e13f44da6ca4f26f0b98c Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Fri, 2 Dec 2022 19:35:08 +0100 Subject: [PATCH 12/42] pwm: mediatek: always use bus clock for PWM on MT7622 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit According to MT7622 Reference Manual for Development Board v1.0 the PWM unit found in the MT7622 SoC also comes with the PWM_CK_26M_SEL register at offset 0x210 just like other modern MediaTek ARM64 SoCs. And also MT7622 sets that register to 0x00000001 on reset which is described as 'Select 26M fix CLK as BCLK' in the datasheet. Hence set has_ck_26m_sel to true also for MT7622 which results in the driver writing 0 to the PWM_CK_26M_SEL register which is described as 'Select bus CLK as BCLK'. Fixes: 0c0ead76235db0 ("pwm: mediatek: Always use bus clock") Signed-off-by: Daniel Golle Reviewed-by: AngeloGioacchino Del Regno Acked-by: Uwe Kleine-König Link: https://lore.kernel.org/r/Y1iF2slvSblf6bYK@makrotopia.org Signed-off-by: Uwe Kleine-König Signed-off-by: Thierry Reding --- drivers/pwm/pwm-mediatek.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/pwm/pwm-mediatek.c b/drivers/pwm/pwm-mediatek.c index 6901a44dc428..a337b47dc2f7 100644 --- a/drivers/pwm/pwm-mediatek.c +++ b/drivers/pwm/pwm-mediatek.c @@ -296,7 +296,7 @@ static const struct pwm_mediatek_of_data mt6795_pwm_data = { static const struct pwm_mediatek_of_data mt7622_pwm_data = { .num_pwms = 6, .pwm45_fixup = false, - .has_ck_26m_sel = false, + .has_ck_26m_sel = true, }; static const struct pwm_mediatek_of_data mt7623_pwm_data = { From e51b156b18fb6d34a1e409d153040a02adb5c7e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Fri, 2 Dec 2022 19:35:09 +0100 Subject: [PATCH 13/42] pwm: Document variables protected by pwm_lock MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit To simplify validation of the used locking, document for the global pwm mutex what it actually protects against concurrent access. Also note for two functions modifying these that pwm_lock is held by the caller. Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20221117211143.3817381-2-u.kleine-koenig@pengutronix.de Signed-off-by: Uwe Kleine-König Signed-off-by: Thierry Reding --- drivers/pwm/core.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/pwm/core.c b/drivers/pwm/core.c index d333e7422f4a..ebe06efe9de5 100644 --- a/drivers/pwm/core.c +++ b/drivers/pwm/core.c @@ -27,7 +27,10 @@ static DEFINE_MUTEX(pwm_lookup_lock); static LIST_HEAD(pwm_lookup_list); + +/* protects access to pwm_chips, allocated_pwms, and pwm_tree */ static DEFINE_MUTEX(pwm_lock); + static LIST_HEAD(pwm_chips); static DECLARE_BITMAP(allocated_pwms, MAX_PWMS); static RADIX_TREE(pwm_tree, GFP_KERNEL); @@ -37,6 +40,7 @@ static struct pwm_device *pwm_to_device(unsigned int pwm) return radix_tree_lookup(&pwm_tree, pwm); } +/* Called with pwm_lock held */ static int alloc_pwms(unsigned int count) { unsigned int start; @@ -50,6 +54,7 @@ static int alloc_pwms(unsigned int count) return start; } +/* Called with pwm_lock held */ static void free_pwms(struct pwm_chip *chip) { unsigned int i; From c8135b5174145a65c72c4303f2752cc8cecf8d08 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Fri, 2 Dec 2022 19:35:10 +0100 Subject: [PATCH 14/42] pwm: Reduce time the pwm_lock mutex is held in pwmchip_add() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This simplifies error handling as the need for goto error handling goes away and at the end of the function the code can be simplified as this code isn't used in the error case any more. Now memory allocation and the call to of_pwmchip_add() are done without holding the lock. Both don't access the data structures protected by &pwm_lock. Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20221117211143.3817381-3-u.kleine-koenig@pengutronix.de Signed-off-by: Uwe Kleine-König Signed-off-by: Thierry Reding --- drivers/pwm/core.c | 27 ++++++++++++--------------- 1 file changed, 12 insertions(+), 15 deletions(-) diff --git a/drivers/pwm/core.c b/drivers/pwm/core.c index ebe06efe9de5..2338119a09d8 100644 --- a/drivers/pwm/core.c +++ b/drivers/pwm/core.c @@ -272,20 +272,21 @@ int pwmchip_add(struct pwm_chip *chip) if (!pwm_ops_check(chip)) return -EINVAL; + chip->pwms = kcalloc(chip->npwm, sizeof(*pwm), GFP_KERNEL); + if (!chip->pwms) + return -ENOMEM; + mutex_lock(&pwm_lock); ret = alloc_pwms(chip->npwm); - if (ret < 0) - goto out; + if (ret < 0) { + mutex_unlock(&pwm_lock); + kfree(chip->pwms); + return ret; + } chip->base = ret; - chip->pwms = kcalloc(chip->npwm, sizeof(*pwm), GFP_KERNEL); - if (!chip->pwms) { - ret = -ENOMEM; - goto out; - } - for (i = 0; i < chip->npwm; i++) { pwm = &chip->pwms[i]; @@ -301,18 +302,14 @@ int pwmchip_add(struct pwm_chip *chip) INIT_LIST_HEAD(&chip->list); list_add(&chip->list, &pwm_chips); - ret = 0; + mutex_unlock(&pwm_lock); if (IS_ENABLED(CONFIG_OF)) of_pwmchip_add(chip); -out: - mutex_unlock(&pwm_lock); + pwmchip_sysfs_export(chip); - if (!ret) - pwmchip_sysfs_export(chip); - - return ret; + return 0; } EXPORT_SYMBOL_GPL(pwmchip_add); From 4034e5944884dca1673e52cc392b07d0d35b6ff0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Fri, 2 Dec 2022 19:35:11 +0100 Subject: [PATCH 15/42] pwm: Mark free pwm IDs as used in alloc_pwms() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit alloc_pwms() only identified a free range of IDs and this range was marked as used only later by pwmchip_add(). Instead let alloc_pwms() already do the marking (which makes the function actually allocating the range and so justifies the function name). This way access to the allocated_pwms bitfield is limited to two functions only. Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20221117211143.3817381-4-u.kleine-koenig@pengutronix.de Signed-off-by: Uwe Kleine-König Signed-off-by: Thierry Reding --- drivers/pwm/core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/pwm/core.c b/drivers/pwm/core.c index 2338119a09d8..b43b24bd3c9f 100644 --- a/drivers/pwm/core.c +++ b/drivers/pwm/core.c @@ -51,6 +51,8 @@ static int alloc_pwms(unsigned int count) if (start + count > MAX_PWMS) return -ENOSPC; + bitmap_set(allocated_pwms, start, count); + return start; } @@ -297,8 +299,6 @@ int pwmchip_add(struct pwm_chip *chip) radix_tree_insert(&pwm_tree, pwm->pwm, pwm); } - bitmap_set(allocated_pwms, chip->base, chip->npwm); - INIT_LIST_HEAD(&chip->list); list_add(&chip->list, &pwm_chips); From fa1b9aa4492cc4f29178ef38ca0467c48714250e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Fri, 2 Dec 2022 19:35:12 +0100 Subject: [PATCH 16/42] pwm: Don't initialize list head before calling list_add() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit list_add() just overwrites the members of the element to add (here: chip->list) without any checks, even in the DEBUG_LIST case. So save the effort to initialize the list. Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20221117211143.3817381-5-u.kleine-koenig@pengutronix.de Signed-off-by: Uwe Kleine-König Signed-off-by: Thierry Reding --- drivers/pwm/core.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/pwm/core.c b/drivers/pwm/core.c index b43b24bd3c9f..61bacd8d9b44 100644 --- a/drivers/pwm/core.c +++ b/drivers/pwm/core.c @@ -299,7 +299,6 @@ int pwmchip_add(struct pwm_chip *chip) radix_tree_insert(&pwm_tree, pwm->pwm, pwm); } - INIT_LIST_HEAD(&chip->list); list_add(&chip->list, &pwm_chips); mutex_unlock(&pwm_lock); From 55f363e19cb8ca65400eeb11d716519609fbeae6 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 2 Dec 2022 19:35:13 +0100 Subject: [PATCH 17/42] pwm: core: Remove S_IFREG from debugfs_create_file() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The debugfs_create_file() already has a check and adds S_IFREG automatically. Remove unneeded flag. Signed-off-by: Andy Shevchenko Acked-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20221117165812.27757-1-andriy.shevchenko@linux.intel.com Signed-off-by: Uwe Kleine-König Signed-off-by: Thierry Reding --- drivers/pwm/core.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/pwm/core.c b/drivers/pwm/core.c index 61bacd8d9b44..3a0967209853 100644 --- a/drivers/pwm/core.c +++ b/drivers/pwm/core.c @@ -1180,8 +1180,7 @@ DEFINE_SEQ_ATTRIBUTE(pwm_debugfs); static int __init pwm_debugfs_init(void) { - debugfs_create_file("pwm", S_IFREG | 0444, NULL, NULL, - &pwm_debugfs_fops); + debugfs_create_file("pwm", 0444, NULL, NULL, &pwm_debugfs_fops); return 0; } From c637d87a7d96bd04674515b879b500f66361b74c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Fri, 2 Dec 2022 19:35:14 +0100 Subject: [PATCH 18/42] pwm: fsl-ftm: Use regmap_clear_bits and regmap_set_bits where applicable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Found using coccinelle and the following semantic patch: @@ expression map, reg, bits; @@ - regmap_update_bits(map, reg, bits, bits) + regmap_set_bits(map, reg, bits) @@ expression map, reg, bits; @@ - regmap_update_bits(map, reg, bits, 0) + regmap_clear_bits(map, reg, bits) Link: https://lore.kernel.org/r/20221115111347.3705732-2-u.kleine-koenig@pengutronix.de Signed-off-by: Uwe Kleine-König Signed-off-by: Thierry Reding --- drivers/pwm/pwm-fsl-ftm.c | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/drivers/pwm/pwm-fsl-ftm.c b/drivers/pwm/pwm-fsl-ftm.c index 0247757f9a72..5caadbd6194e 100644 --- a/drivers/pwm/pwm-fsl-ftm.c +++ b/drivers/pwm/pwm-fsl-ftm.c @@ -65,13 +65,12 @@ static void ftm_clear_write_protection(struct fsl_pwm_chip *fpc) regmap_read(fpc->regmap, FTM_FMS, &val); if (val & FTM_FMS_WPEN) - regmap_update_bits(fpc->regmap, FTM_MODE, FTM_MODE_WPDIS, - FTM_MODE_WPDIS); + regmap_set_bits(fpc->regmap, FTM_MODE, FTM_MODE_WPDIS); } static void ftm_set_write_protection(struct fsl_pwm_chip *fpc) { - regmap_update_bits(fpc->regmap, FTM_FMS, FTM_FMS_WPEN, FTM_FMS_WPEN); + regmap_set_bits(fpc->regmap, FTM_FMS, FTM_FMS_WPEN); } static bool fsl_pwm_periodcfg_are_equal(const struct fsl_pwm_periodcfg *a, @@ -94,8 +93,7 @@ static int fsl_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm) ret = clk_prepare_enable(fpc->ipg_clk); if (!ret && fpc->soc->has_enable_bits) { mutex_lock(&fpc->lock); - regmap_update_bits(fpc->regmap, FTM_SC, BIT(pwm->hwpwm + 16), - BIT(pwm->hwpwm + 16)); + regmap_set_bits(fpc->regmap, FTM_SC, BIT(pwm->hwpwm + 16)); mutex_unlock(&fpc->lock); } @@ -108,8 +106,7 @@ static void fsl_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm) if (fpc->soc->has_enable_bits) { mutex_lock(&fpc->lock); - regmap_update_bits(fpc->regmap, FTM_SC, BIT(pwm->hwpwm + 16), - 0); + regmap_clear_bits(fpc->regmap, FTM_SC, BIT(pwm->hwpwm + 16)); mutex_unlock(&fpc->lock); } @@ -317,8 +314,8 @@ static int fsl_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, if (!newstate->enabled) { if (oldstate->enabled) { - regmap_update_bits(fpc->regmap, FTM_OUTMASK, - BIT(pwm->hwpwm), BIT(pwm->hwpwm)); + regmap_set_bits(fpc->regmap, FTM_OUTMASK, + BIT(pwm->hwpwm)); clk_disable_unprepare(fpc->clk[FSL_PWM_CLK_CNTEN]); clk_disable_unprepare(fpc->clk[fpc->period.clk_select]); } @@ -342,8 +339,7 @@ static int fsl_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, goto end_mutex; } - regmap_update_bits(fpc->regmap, FTM_OUTMASK, BIT(pwm->hwpwm), - 0); + regmap_clear_bits(fpc->regmap, FTM_OUTMASK, BIT(pwm->hwpwm)); } end_mutex: From 50f2151034b65125b6cce6b385ce8b74556e45f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Fri, 2 Dec 2022 19:35:15 +0100 Subject: [PATCH 19/42] pwm: img: Use regmap_clear_bits and regmap_set_bits where applicable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Found using coccinelle and the following semantic patch: @@ expression map, reg, bits; @@ - regmap_update_bits(map, reg, bits, bits) + regmap_set_bits(map, reg, bits) @@ expression map, reg, bits; @@ - regmap_update_bits(map, reg, bits, 0) + regmap_clear_bits(map, reg, bits) Link: https://lore.kernel.org/r/20221115111347.3705732-3-u.kleine-koenig@pengutronix.de Signed-off-by: Uwe Kleine-König Signed-off-by: Thierry Reding --- drivers/pwm/pwm-img.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/drivers/pwm/pwm-img.c b/drivers/pwm/pwm-img.c index 0fccf061ab95..89362afe3c91 100644 --- a/drivers/pwm/pwm-img.c +++ b/drivers/pwm/pwm-img.c @@ -161,9 +161,9 @@ static int img_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm) val |= BIT(pwm->hwpwm); img_pwm_writel(imgchip, PWM_CTRL_CFG, val); - regmap_update_bits(imgchip->periph_regs, PERIP_PWM_PDM_CONTROL, - PERIP_PWM_PDM_CONTROL_CH_MASK << - PERIP_PWM_PDM_CONTROL_CH_SHIFT(pwm->hwpwm), 0); + regmap_clear_bits(imgchip->periph_regs, PERIP_PWM_PDM_CONTROL, + PERIP_PWM_PDM_CONTROL_CH_MASK << + PERIP_PWM_PDM_CONTROL_CH_SHIFT(pwm->hwpwm)); return 0; } @@ -397,11 +397,10 @@ static int img_pwm_resume(struct device *dev) for (i = 0; i < imgchip->chip.npwm; i++) if (imgchip->suspend_ctrl_cfg & BIT(i)) - regmap_update_bits(imgchip->periph_regs, - PERIP_PWM_PDM_CONTROL, - PERIP_PWM_PDM_CONTROL_CH_MASK << - PERIP_PWM_PDM_CONTROL_CH_SHIFT(i), - 0); + regmap_clear_bits(imgchip->periph_regs, + PERIP_PWM_PDM_CONTROL, + PERIP_PWM_PDM_CONTROL_CH_MASK << + PERIP_PWM_PDM_CONTROL_CH_SHIFT(i)); if (pm_runtime_status_suspended(dev)) img_pwm_runtime_suspend(dev); From 2c85895bf3d202f6932598b124d0db2be4278999 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Fri, 2 Dec 2022 19:35:16 +0100 Subject: [PATCH 20/42] pwm: iqs620a: Use regmap_clear_bits and regmap_set_bits where applicable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Found using coccinelle and the following semantic patch: @@ expression map, reg, bits; @@ - regmap_update_bits(map, reg, bits, bits) + regmap_set_bits(map, reg, bits) @@ expression map, reg, bits; @@ - regmap_update_bits(map, reg, bits, 0) + regmap_clear_bits(map, reg, bits) Link: https://lore.kernel.org/r/20221115111347.3705732-4-u.kleine-koenig@pengutronix.de Signed-off-by: Uwe Kleine-König Signed-off-by: Thierry Reding --- drivers/pwm/pwm-iqs620a.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/pwm/pwm-iqs620a.c b/drivers/pwm/pwm-iqs620a.c index 54bd95a5cab0..7246176fce06 100644 --- a/drivers/pwm/pwm-iqs620a.c +++ b/drivers/pwm/pwm-iqs620a.c @@ -47,8 +47,8 @@ static int iqs620_pwm_init(struct iqs620_pwm_private *iqs620_pwm, int ret; if (!duty_scale) - return regmap_update_bits(iqs62x->regmap, IQS620_PWR_SETTINGS, - IQS620_PWR_SETTINGS_PWM_OUT, 0); + return regmap_clear_bits(iqs62x->regmap, IQS620_PWR_SETTINGS, + IQS620_PWR_SETTINGS_PWM_OUT); ret = regmap_write(iqs62x->regmap, IQS620_PWM_DUTY_CYCLE, duty_scale - 1); From 85cad49f5ed269ffa0c80081d6506e39fa78456b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Fri, 2 Dec 2022 19:35:17 +0100 Subject: [PATCH 21/42] pwm: stm32-lp: Use regmap_clear_bits and regmap_set_bits where applicable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Found using coccinelle and the following semantic patch: @@ expression map, reg, bits; @@ - regmap_update_bits(map, reg, bits, bits) + regmap_set_bits(map, reg, bits) @@ expression map, reg, bits; @@ - regmap_update_bits(map, reg, bits, 0) + regmap_clear_bits(map, reg, bits) Tested-by: Fabrice Gasnier Link: https://lore.kernel.org/r/20221115111347.3705732-5-u.kleine-koenig@pengutronix.de Signed-off-by: Uwe Kleine-König Signed-off-by: Thierry Reding --- drivers/pwm/pwm-stm32-lp.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/pwm/pwm-stm32-lp.c b/drivers/pwm/pwm-stm32-lp.c index 3115abb3f52a..212bdc7d51ee 100644 --- a/drivers/pwm/pwm-stm32-lp.c +++ b/drivers/pwm/pwm-stm32-lp.c @@ -140,9 +140,8 @@ static int stm32_pwm_lp_apply(struct pwm_chip *chip, struct pwm_device *pwm, if (reenable) { /* Start LP timer in continuous mode */ - ret = regmap_update_bits(priv->regmap, STM32_LPTIM_CR, - STM32_LPTIM_CNTSTRT, - STM32_LPTIM_CNTSTRT); + ret = regmap_set_bits(priv->regmap, STM32_LPTIM_CR, + STM32_LPTIM_CNTSTRT); if (ret) { regmap_write(priv->regmap, STM32_LPTIM_CR, 0); goto err; From 632ae5d7eb348b3ef88552ec0999260b6f9d6ab1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Fri, 2 Dec 2022 19:35:18 +0100 Subject: [PATCH 22/42] pwm: stm32: Use regmap_clear_bits and regmap_set_bits where applicable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Found using coccinelle and the following semantic patch: @@ expression map, reg, bits; @@ - regmap_update_bits(map, reg, bits, bits) + regmap_set_bits(map, reg, bits) @@ expression map, reg, bits; @@ - regmap_update_bits(map, reg, bits, 0) + regmap_clear_bits(map, reg, bits) Tested-by: Fabrice Gasnier Link: https://lore.kernel.org/r/20221115111347.3705732-6-u.kleine-koenig@pengutronix.de Signed-off-by: Uwe Kleine-König Signed-off-by: Thierry Reding --- drivers/pwm/pwm-stm32.c | 34 ++++++++++++++++------------------ 1 file changed, 16 insertions(+), 18 deletions(-) diff --git a/drivers/pwm/pwm-stm32.c b/drivers/pwm/pwm-stm32.c index 794ca5b02968..21e4a34dfff3 100644 --- a/drivers/pwm/pwm-stm32.c +++ b/drivers/pwm/pwm-stm32.c @@ -115,14 +115,14 @@ static int stm32_pwm_raw_capture(struct stm32_pwm *priv, struct pwm_device *pwm, int ret; /* Ensure registers have been updated, enable counter and capture */ - regmap_update_bits(priv->regmap, TIM_EGR, TIM_EGR_UG, TIM_EGR_UG); - regmap_update_bits(priv->regmap, TIM_CR1, TIM_CR1_CEN, TIM_CR1_CEN); + regmap_set_bits(priv->regmap, TIM_EGR, TIM_EGR_UG); + regmap_set_bits(priv->regmap, TIM_CR1, TIM_CR1_CEN); /* Use cc1 or cc3 DMA resp for PWM input channels 1 & 2 or 3 & 4 */ dma_id = pwm->hwpwm < 2 ? STM32_TIMERS_DMA_CH1 : STM32_TIMERS_DMA_CH3; ccen = pwm->hwpwm < 2 ? TIM_CCER_CC12E : TIM_CCER_CC34E; ccr = pwm->hwpwm < 2 ? TIM_CCR1 : TIM_CCR3; - regmap_update_bits(priv->regmap, TIM_CCER, ccen, ccen); + regmap_set_bits(priv->regmap, TIM_CCER, ccen); /* * Timer DMA burst mode. Request 2 registers, 2 bursts, to get both @@ -160,8 +160,8 @@ static int stm32_pwm_raw_capture(struct stm32_pwm *priv, struct pwm_device *pwm, } stop: - regmap_update_bits(priv->regmap, TIM_CCER, ccen, 0); - regmap_update_bits(priv->regmap, TIM_CR1, TIM_CR1_CEN, 0); + regmap_clear_bits(priv->regmap, TIM_CCER, ccen); + regmap_clear_bits(priv->regmap, TIM_CR1, TIM_CR1_CEN); return ret; } @@ -359,7 +359,7 @@ static int stm32_pwm_config(struct stm32_pwm *priv, int ch, regmap_write(priv->regmap, TIM_PSC, prescaler); regmap_write(priv->regmap, TIM_ARR, prd - 1); - regmap_update_bits(priv->regmap, TIM_CR1, TIM_CR1_ARPE, TIM_CR1_ARPE); + regmap_set_bits(priv->regmap, TIM_CR1, TIM_CR1_ARPE); /* Calculate the duty cycles */ dty = prd * duty_ns; @@ -377,7 +377,7 @@ static int stm32_pwm_config(struct stm32_pwm *priv, int ch, else regmap_update_bits(priv->regmap, TIM_CCMR2, mask, ccmr); - regmap_update_bits(priv->regmap, TIM_BDTR, TIM_BDTR_MOE, TIM_BDTR_MOE); + regmap_set_bits(priv->regmap, TIM_BDTR, TIM_BDTR_MOE); return 0; } @@ -411,13 +411,13 @@ static int stm32_pwm_enable(struct stm32_pwm *priv, int ch) if (priv->have_complementary_output) mask |= TIM_CCER_CC1NE << (ch * 4); - regmap_update_bits(priv->regmap, TIM_CCER, mask, mask); + regmap_set_bits(priv->regmap, TIM_CCER, mask); /* Make sure that registers are updated */ - regmap_update_bits(priv->regmap, TIM_EGR, TIM_EGR_UG, TIM_EGR_UG); + regmap_set_bits(priv->regmap, TIM_EGR, TIM_EGR_UG); /* Enable controller */ - regmap_update_bits(priv->regmap, TIM_CR1, TIM_CR1_CEN, TIM_CR1_CEN); + regmap_set_bits(priv->regmap, TIM_CR1, TIM_CR1_CEN); return 0; } @@ -431,11 +431,11 @@ static void stm32_pwm_disable(struct stm32_pwm *priv, int ch) if (priv->have_complementary_output) mask |= TIM_CCER_CC1NE << (ch * 4); - regmap_update_bits(priv->regmap, TIM_CCER, mask, 0); + regmap_clear_bits(priv->regmap, TIM_CCER, mask); /* When all channels are disabled, we can disable the controller */ if (!active_channels(priv)) - regmap_update_bits(priv->regmap, TIM_CR1, TIM_CR1_CEN, 0); + regmap_clear_bits(priv->regmap, TIM_CR1, TIM_CR1_CEN); clk_disable(priv->clk); } @@ -568,10 +568,9 @@ static void stm32_pwm_detect_complementary(struct stm32_pwm *priv) * If complementary bit doesn't exist writing 1 will have no * effect so we can detect it. */ - regmap_update_bits(priv->regmap, - TIM_CCER, TIM_CCER_CC1NE, TIM_CCER_CC1NE); + regmap_set_bits(priv->regmap, TIM_CCER, TIM_CCER_CC1NE); regmap_read(priv->regmap, TIM_CCER, &ccer); - regmap_update_bits(priv->regmap, TIM_CCER, TIM_CCER_CC1NE, 0); + regmap_clear_bits(priv->regmap, TIM_CCER, TIM_CCER_CC1NE); priv->have_complementary_output = (ccer != 0); } @@ -585,10 +584,9 @@ static int stm32_pwm_detect_channels(struct stm32_pwm *priv) * If channels enable bits don't exist writing 1 will have no * effect so we can detect and count them. */ - regmap_update_bits(priv->regmap, - TIM_CCER, TIM_CCER_CCXE, TIM_CCER_CCXE); + regmap_set_bits(priv->regmap, TIM_CCER, TIM_CCER_CCXE); regmap_read(priv->regmap, TIM_CCER, &ccer); - regmap_update_bits(priv->regmap, TIM_CCER, TIM_CCER_CCXE, 0); + regmap_clear_bits(priv->regmap, TIM_CCER, TIM_CCER_CCXE); if (ccer & TIM_CCER_CC1E) npwm++; From 241eab76657f72d82a5a77ef7d7958c6e07dd2b0 Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Fri, 2 Dec 2022 19:35:19 +0100 Subject: [PATCH 23/42] pwm: mediatek: Add support for MT7986 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add support for PWM on MT7986 which has 2 PWM channels, one of them is typically used for a temperature controlled fan. Signed-off-by: Daniel Golle Reviewed-by: Sam Shih Link: https://lore.kernel.org/r/Y1K5ym1EL8kwzQEt@makrotopia.org Signed-off-by: Uwe Kleine-König Signed-off-by: Thierry Reding --- drivers/pwm/pwm-mediatek.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/pwm/pwm-mediatek.c b/drivers/pwm/pwm-mediatek.c index a337b47dc2f7..5b5eeaff35da 100644 --- a/drivers/pwm/pwm-mediatek.c +++ b/drivers/pwm/pwm-mediatek.c @@ -329,6 +329,12 @@ static const struct pwm_mediatek_of_data mt8365_pwm_data = { .has_ck_26m_sel = true, }; +static const struct pwm_mediatek_of_data mt7986_pwm_data = { + .num_pwms = 2, + .pwm45_fixup = false, + .has_ck_26m_sel = true, +}; + static const struct pwm_mediatek_of_data mt8516_pwm_data = { .num_pwms = 5, .pwm45_fixup = false, @@ -342,6 +348,7 @@ static const struct of_device_id pwm_mediatek_of_match[] = { { .compatible = "mediatek,mt7623-pwm", .data = &mt7623_pwm_data }, { .compatible = "mediatek,mt7628-pwm", .data = &mt7628_pwm_data }, { .compatible = "mediatek,mt7629-pwm", .data = &mt7629_pwm_data }, + { .compatible = "mediatek,mt7986-pwm", .data = &mt7986_pwm_data }, { .compatible = "mediatek,mt8183-pwm", .data = &mt8183_pwm_data }, { .compatible = "mediatek,mt8365-pwm", .data = &mt8365_pwm_data }, { .compatible = "mediatek,mt8516-pwm", .data = &mt8516_pwm_data }, From f956b838934ab06deeee2ce9d5c8dfe64e4beb24 Mon Sep 17 00:00:00 2001 From: Doug Brown Date: Fri, 2 Dec 2022 19:35:20 +0100 Subject: [PATCH 24/42] pwm: pxa: Remove pxa_pwm_enable/disable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit These functions are only acting as wrappers for clk_prepare_enable and clk_disable_unprepare now, so remove them to simplify the driver. Suggested-by: Uwe Kleine-König Signed-off-by: Doug Brown Reviewed-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20221113233639.24244-2-doug@schmorgal.com Signed-off-by: Uwe Kleine-König Signed-off-by: Thierry Reding --- drivers/pwm/pwm-pxa.c | 19 +++---------------- 1 file changed, 3 insertions(+), 16 deletions(-) diff --git a/drivers/pwm/pwm-pxa.c b/drivers/pwm/pwm-pxa.c index 0bcaa58c6a91..0ac052652c62 100644 --- a/drivers/pwm/pwm-pxa.c +++ b/drivers/pwm/pwm-pxa.c @@ -101,23 +101,10 @@ static int pxa_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, return 0; } -static int pxa_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm) -{ - struct pxa_pwm_chip *pc = to_pxa_pwm_chip(chip); - - return clk_prepare_enable(pc->clk); -} - -static void pxa_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm) -{ - struct pxa_pwm_chip *pc = to_pxa_pwm_chip(chip); - - clk_disable_unprepare(pc->clk); -} - static int pxa_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, const struct pwm_state *state) { + struct pxa_pwm_chip *pc = to_pxa_pwm_chip(chip); int err; if (state->polarity != PWM_POLARITY_NORMAL) @@ -125,7 +112,7 @@ static int pxa_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, if (!state->enabled) { if (pwm->state.enabled) - pxa_pwm_disable(chip, pwm); + clk_disable_unprepare(pc->clk); return 0; } @@ -135,7 +122,7 @@ static int pxa_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, return err; if (!pwm->state.enabled) - return pxa_pwm_enable(chip, pwm); + return clk_prepare_enable(pc->clk); return 0; } From 152f2d1def5e4b974947877126ff292a68a8c521 Mon Sep 17 00:00:00 2001 From: Doug Brown Date: Fri, 2 Dec 2022 19:35:21 +0100 Subject: [PATCH 25/42] pwm: pxa: Set duty cycle to 0 when disabling PWM MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When disabling PWM, the duty cycle needs to be set to 0. This prevents the previous duty cycle from showing up momentarily when the clock is re-enabled next time. Because the clock has to be running in order to configure the duty cycle, unconditionally enable it early in pxa_pwm_apply and account for the correct enable count at the end. Suggested-by: Uwe Kleine-König Signed-off-by: Doug Brown Reviewed-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20221113233639.24244-3-doug@schmorgal.com Signed-off-by: Uwe Kleine-König Signed-off-by: Thierry Reding --- drivers/pwm/pwm-pxa.c | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/drivers/pwm/pwm-pxa.c b/drivers/pwm/pwm-pxa.c index 0ac052652c62..9ee9b41d62b8 100644 --- a/drivers/pwm/pwm-pxa.c +++ b/drivers/pwm/pwm-pxa.c @@ -105,24 +105,31 @@ static int pxa_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, const struct pwm_state *state) { struct pxa_pwm_chip *pc = to_pxa_pwm_chip(chip); + u64 duty_cycle; int err; if (state->polarity != PWM_POLARITY_NORMAL) return -EINVAL; - if (!state->enabled) { - if (pwm->state.enabled) - clk_disable_unprepare(pc->clk); - - return 0; - } - - err = pxa_pwm_config(chip, pwm, state->duty_cycle, state->period); + err = clk_prepare_enable(pc->clk); if (err) return err; - if (!pwm->state.enabled) - return clk_prepare_enable(pc->clk); + duty_cycle = state->enabled ? state->duty_cycle : 0; + + err = pxa_pwm_config(chip, pwm, duty_cycle, state->period); + if (err) { + clk_disable_unprepare(pc->clk); + return err; + } + + if (state->enabled && !pwm->state.enabled) + return 0; + + clk_disable_unprepare(pc->clk); + + if (!state->enabled && pwm->state.enabled) + clk_disable_unprepare(pc->clk); return 0; } From 939d002b7501128640aaeffe175d6331dcce2ca6 Mon Sep 17 00:00:00 2001 From: Doug Brown Date: Fri, 2 Dec 2022 19:35:22 +0100 Subject: [PATCH 26/42] pwm: pxa: Remove clk enable/disable from pxa_pwm_config MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Now that pxa_pwm_apply always enables the clock first, there is no need for pxa_pwm_config to do any clock enabling/disabling. Signed-off-by: Doug Brown Reviewed-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20221113233639.24244-4-doug@schmorgal.com Signed-off-by: Uwe Kleine-König Signed-off-by: Thierry Reding --- drivers/pwm/pwm-pxa.c | 9 --------- 1 file changed, 9 deletions(-) diff --git a/drivers/pwm/pwm-pxa.c b/drivers/pwm/pwm-pxa.c index 9ee9b41d62b8..cf4d22c91929 100644 --- a/drivers/pwm/pwm-pxa.c +++ b/drivers/pwm/pwm-pxa.c @@ -64,7 +64,6 @@ static int pxa_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, unsigned long long c; unsigned long period_cycles, prescale, pv, dc; unsigned long offset; - int rc; offset = pwm->hwpwm ? 0x10 : 0; @@ -86,18 +85,10 @@ static int pxa_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, else dc = mul_u64_u64_div_u64(pv + 1, duty_ns, period_ns); - /* NOTE: the clock to PWM has to be enabled first - * before writing to the registers - */ - rc = clk_prepare_enable(pc->clk); - if (rc < 0) - return rc; - writel(prescale, pc->mmio_base + offset + PWMCR); writel(dc, pc->mmio_base + offset + PWMDCR); writel(pv, pc->mmio_base + offset + PWMPCR); - clk_disable_unprepare(pc->clk); return 0; } From 092c2ef4571cbc7e5f466bc241ff054723c41973 Mon Sep 17 00:00:00 2001 From: Doug Brown Date: Fri, 2 Dec 2022 19:35:23 +0100 Subject: [PATCH 27/42] pwm: pxa: Use abrupt shutdown mode MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Switch to abrupt shutdown mode in order to stop the clock as soon as possible when PWM is disabled. This minimizes the possibility of the clock being re-enabled while it is still in the process of turning off, which will result in the clock ending up erroneously disabled. Signed-off-by: Doug Brown Reviewed-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20221113233639.24244-5-doug@schmorgal.com Signed-off-by: Uwe Kleine-König Signed-off-by: Thierry Reding --- drivers/pwm/pwm-pxa.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/pwm/pwm-pxa.c b/drivers/pwm/pwm-pxa.c index cf4d22c91929..00063ead7c0a 100644 --- a/drivers/pwm/pwm-pxa.c +++ b/drivers/pwm/pwm-pxa.c @@ -85,7 +85,7 @@ static int pxa_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, else dc = mul_u64_u64_div_u64(pv + 1, duty_ns, period_ns); - writel(prescale, pc->mmio_base + offset + PWMCR); + writel(prescale | PWMCR_SD, pc->mmio_base + offset + PWMCR); writel(dc, pc->mmio_base + offset + PWMDCR); writel(pv, pc->mmio_base + offset + PWMPCR); From 8ba2725ffac351a1b80063ac7eb362832fae16a2 Mon Sep 17 00:00:00 2001 From: Doug Brown Date: Fri, 2 Dec 2022 19:35:24 +0100 Subject: [PATCH 28/42] pwm: pxa: Add reference manual link and limitations MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a pointer to the location of reference manuals for some of the supported chips, and add a limitations section explaining the hardware's PWM disable behavior. Suggested-by: Uwe Kleine-König Signed-off-by: Doug Brown Reviewed-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20221113233639.24244-6-doug@schmorgal.com Signed-off-by: Uwe Kleine-König Signed-off-by: Thierry Reding --- drivers/pwm/pwm-pxa.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/pwm/pwm-pxa.c b/drivers/pwm/pwm-pxa.c index 00063ead7c0a..46ed668bd141 100644 --- a/drivers/pwm/pwm-pxa.c +++ b/drivers/pwm/pwm-pxa.c @@ -6,6 +6,13 @@ * * 2008-02-13 initial version * eric miao + * + * Links to reference manuals for some of the supported PWM chips can be found + * in Documentation/arm/marvell.rst. + * + * Limitations: + * - When PWM is stopped, the current PWM period stops abruptly at the next + * input clock (PWMCR_SD is set) and the output is driven to inactive. */ #include From 958f03074980e8ae1b0c257a732fe467069ec267 Mon Sep 17 00:00:00 2001 From: Doug Brown Date: Fri, 2 Dec 2022 19:35:25 +0100 Subject: [PATCH 29/42] pwm: pxa: Enable for MMP platform MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The PXA168, which is part of the MMP platform, also uses this driver. Signed-off-by: Doug Brown Acked-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20221113233639.24244-7-doug@schmorgal.com Signed-off-by: Uwe Kleine-König Signed-off-by: Thierry Reding --- drivers/pwm/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig index cb623d0702f6..dae023d783a2 100644 --- a/drivers/pwm/Kconfig +++ b/drivers/pwm/Kconfig @@ -434,7 +434,7 @@ config PWM_PCA9685 config PWM_PXA tristate "PXA PWM support" - depends on ARCH_PXA || COMPILE_TEST + depends on ARCH_PXA || ARCH_MMP || COMPILE_TEST depends on HAS_IOMEM help Generic PWM framework driver for PXA. From 6c452cff79f8bf1c0146fda598d32061cfd25443 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Fri, 2 Dec 2022 19:35:26 +0100 Subject: [PATCH 30/42] pwm: Make .get_state() callback return an error code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit .get_state() might fail in some cases. To make it possible that a driver signals such a failure change the prototype of .get_state() to return an error code. This patch was created using coccinelle and the following semantic patch: @p1@ identifier getstatefunc; identifier driver; @@ struct pwm_ops driver = { ..., .get_state = getstatefunc ,... }; @p2@ identifier p1.getstatefunc; identifier chip, pwm, state; @@ -void +int getstatefunc(struct pwm_chip *chip, struct pwm_device *pwm, struct pwm_state *state) { ... - return; + return 0; ... } plus the actual change of the prototype in include/linux/pwm.h (plus some manual fixing of indentions and empty lines). So for now all drivers return success unconditionally. They are adapted in the following patches to make the changes easier reviewable. Reviewed-by: Heiko Stuebner Reviewed-by: Baolin Wang Reviewed-by: Tzung-Bi Shih Reviewed-by: Neil Armstrong Reviewed-by: Nobuhiro Iwamatsu Reviewed-by: Andre Przywara Reviewed-by: Dave Stevenson Acked-by: Douglas Anderson Acked-by: Jernej Skrabec Acked-by: Pavel Machek Acked-by: Conor Dooley Link: https://lore.kernel.org/r/20221130152148.2769768-2-u.kleine-koenig@pengutronix.de Signed-off-by: Uwe Kleine-König Signed-off-by: Thierry Reding --- drivers/gpio/gpio-mvebu.c | 9 ++++++--- drivers/gpu/drm/bridge/ti-sn65dsi86.c | 14 ++++++++------ drivers/leds/rgb/leds-qcom-lpg.c | 14 ++++++++------ drivers/pwm/pwm-atmel.c | 6 ++++-- drivers/pwm/pwm-bcm-iproc.c | 8 +++++--- drivers/pwm/pwm-crc.c | 10 ++++++---- drivers/pwm/pwm-cros-ec.c | 8 +++++--- drivers/pwm/pwm-dwc.c | 6 ++++-- drivers/pwm/pwm-hibvt.c | 6 ++++-- drivers/pwm/pwm-imx-tpm.c | 8 +++++--- drivers/pwm/pwm-imx27.c | 8 +++++--- drivers/pwm/pwm-intel-lgm.c | 6 ++++-- drivers/pwm/pwm-iqs620a.c | 6 ++++-- drivers/pwm/pwm-keembay.c | 6 ++++-- drivers/pwm/pwm-lpss.c | 6 ++++-- drivers/pwm/pwm-meson.c | 8 +++++--- drivers/pwm/pwm-mtk-disp.c | 12 +++++++----- drivers/pwm/pwm-pca9685.c | 8 +++++--- drivers/pwm/pwm-raspberrypi-poe.c | 8 +++++--- drivers/pwm/pwm-rockchip.c | 12 +++++++----- drivers/pwm/pwm-sifive.c | 6 ++++-- drivers/pwm/pwm-sl28cpld.c | 8 +++++--- drivers/pwm/pwm-sprd.c | 8 +++++--- drivers/pwm/pwm-stm32-lp.c | 8 +++++--- drivers/pwm/pwm-sun4i.c | 12 +++++++----- drivers/pwm/pwm-sunplus.c | 6 ++++-- drivers/pwm/pwm-visconti.c | 6 ++++-- drivers/pwm/pwm-xilinx.c | 8 +++++--- include/linux/pwm.h | 4 ++-- 29 files changed, 146 insertions(+), 89 deletions(-) diff --git a/drivers/gpio/gpio-mvebu.c b/drivers/gpio/gpio-mvebu.c index 1bb317b8dcce..91a4232ee58c 100644 --- a/drivers/gpio/gpio-mvebu.c +++ b/drivers/gpio/gpio-mvebu.c @@ -657,9 +657,10 @@ static void mvebu_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm) spin_unlock_irqrestore(&mvpwm->lock, flags); } -static void mvebu_pwm_get_state(struct pwm_chip *chip, - struct pwm_device *pwm, - struct pwm_state *state) { +static int mvebu_pwm_get_state(struct pwm_chip *chip, + struct pwm_device *pwm, + struct pwm_state *state) +{ struct mvebu_pwm *mvpwm = to_mvebu_pwm(chip); struct mvebu_gpio_chip *mvchip = mvpwm->mvchip; @@ -693,6 +694,8 @@ static void mvebu_pwm_get_state(struct pwm_chip *chip, state->enabled = false; spin_unlock_irqrestore(&mvpwm->lock, flags); + + return 0; } static int mvebu_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, diff --git a/drivers/gpu/drm/bridge/ti-sn65dsi86.c b/drivers/gpu/drm/bridge/ti-sn65dsi86.c index 3c3561942eb6..6826d2423ae9 100644 --- a/drivers/gpu/drm/bridge/ti-sn65dsi86.c +++ b/drivers/gpu/drm/bridge/ti-sn65dsi86.c @@ -1500,8 +1500,8 @@ out: return ret; } -static void ti_sn_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm, - struct pwm_state *state) +static int ti_sn_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm, + struct pwm_state *state) { struct ti_sn65dsi86 *pdata = pwm_chip_to_ti_sn_bridge(chip); unsigned int pwm_en_inv; @@ -1512,19 +1512,19 @@ static void ti_sn_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm, ret = regmap_read(pdata->regmap, SN_PWM_EN_INV_REG, &pwm_en_inv); if (ret) - return; + return 0; ret = ti_sn65dsi86_read_u16(pdata, SN_BACKLIGHT_SCALE_REG, &scale); if (ret) - return; + return 0; ret = ti_sn65dsi86_read_u16(pdata, SN_BACKLIGHT_REG, &backlight); if (ret) - return; + return 0; ret = regmap_read(pdata->regmap, SN_PWM_PRE_DIV_REG, &pre_div); if (ret) - return; + return 0; state->enabled = FIELD_GET(SN_PWM_EN_MASK, pwm_en_inv); if (FIELD_GET(SN_PWM_INV_MASK, pwm_en_inv)) @@ -1539,6 +1539,8 @@ static void ti_sn_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm, if (state->duty_cycle > state->period) state->duty_cycle = state->period; + + return 0; } static const struct pwm_ops ti_sn_pwm_ops = { diff --git a/drivers/leds/rgb/leds-qcom-lpg.c b/drivers/leds/rgb/leds-qcom-lpg.c index 02f51cc61837..741cc2fd817d 100644 --- a/drivers/leds/rgb/leds-qcom-lpg.c +++ b/drivers/leds/rgb/leds-qcom-lpg.c @@ -968,8 +968,8 @@ out_unlock: return ret; } -static void lpg_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm, - struct pwm_state *state) +static int lpg_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm, + struct pwm_state *state) { struct lpg *lpg = container_of(chip, struct lpg, pwm); struct lpg_channel *chan = &lpg->channels[pwm->hwpwm]; @@ -982,20 +982,20 @@ static void lpg_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm, ret = regmap_read(lpg->map, chan->base + LPG_SIZE_CLK_REG, &val); if (ret) - return; + return 0; refclk = lpg_clk_rates[val & PWM_CLK_SELECT_MASK]; if (refclk) { ret = regmap_read(lpg->map, chan->base + LPG_PREDIV_CLK_REG, &val); if (ret) - return; + return 0; pre_div = lpg_pre_divs[FIELD_GET(PWM_FREQ_PRE_DIV_MASK, val)]; m = FIELD_GET(PWM_FREQ_EXP_MASK, val); ret = regmap_bulk_read(lpg->map, chan->base + PWM_VALUE_REG, &pwm_value, sizeof(pwm_value)); if (ret) - return; + return 0; state->period = DIV_ROUND_UP_ULL((u64)NSEC_PER_SEC * LPG_RESOLUTION * pre_div * (1 << m), refclk); state->duty_cycle = DIV_ROUND_UP_ULL((u64)NSEC_PER_SEC * pwm_value * pre_div * (1 << m), refclk); @@ -1006,13 +1006,15 @@ static void lpg_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm, ret = regmap_read(lpg->map, chan->base + PWM_ENABLE_CONTROL_REG, &val); if (ret) - return; + return 0; state->enabled = FIELD_GET(LPG_ENABLE_CONTROL_OUTPUT, val); state->polarity = PWM_POLARITY_NORMAL; if (state->duty_cycle > state->period) state->duty_cycle = state->period; + + return 0; } static const struct pwm_ops lpg_pwm_ops = { diff --git a/drivers/pwm/pwm-atmel.c b/drivers/pwm/pwm-atmel.c index 8e00a4286145..cdbc23649032 100644 --- a/drivers/pwm/pwm-atmel.c +++ b/drivers/pwm/pwm-atmel.c @@ -356,8 +356,8 @@ static int atmel_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, return 0; } -static void atmel_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm, - struct pwm_state *state) +static int atmel_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm, + struct pwm_state *state) { struct atmel_pwm_chip *atmel_pwm = to_atmel_pwm_chip(chip); u32 sr, cmr; @@ -396,6 +396,8 @@ static void atmel_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm, state->polarity = PWM_POLARITY_INVERSED; else state->polarity = PWM_POLARITY_NORMAL; + + return 0; } static const struct pwm_ops atmel_pwm_ops = { diff --git a/drivers/pwm/pwm-bcm-iproc.c b/drivers/pwm/pwm-bcm-iproc.c index 7251037d4dd5..97ec131eb7c1 100644 --- a/drivers/pwm/pwm-bcm-iproc.c +++ b/drivers/pwm/pwm-bcm-iproc.c @@ -68,8 +68,8 @@ static void iproc_pwmc_disable(struct iproc_pwmc *ip, unsigned int channel) ndelay(400); } -static void iproc_pwmc_get_state(struct pwm_chip *chip, struct pwm_device *pwm, - struct pwm_state *state) +static int iproc_pwmc_get_state(struct pwm_chip *chip, struct pwm_device *pwm, + struct pwm_state *state) { struct iproc_pwmc *ip = to_iproc_pwmc(chip); u64 tmp, multi, rate; @@ -91,7 +91,7 @@ static void iproc_pwmc_get_state(struct pwm_chip *chip, struct pwm_device *pwm, if (rate == 0) { state->period = 0; state->duty_cycle = 0; - return; + return 0; } value = readl(ip->base + IPROC_PWM_PRESCALE_OFFSET); @@ -107,6 +107,8 @@ static void iproc_pwmc_get_state(struct pwm_chip *chip, struct pwm_device *pwm, value = readl(ip->base + IPROC_PWM_DUTY_CYCLE_OFFSET(pwm->hwpwm)); tmp = (value & IPROC_PWM_PERIOD_MAX) * multi; state->duty_cycle = div64_u64(tmp, rate); + + return 0; } static int iproc_pwmc_apply(struct pwm_chip *chip, struct pwm_device *pwm, diff --git a/drivers/pwm/pwm-crc.c b/drivers/pwm/pwm-crc.c index 7b357d1cf642..4099850117ba 100644 --- a/drivers/pwm/pwm-crc.c +++ b/drivers/pwm/pwm-crc.c @@ -121,8 +121,8 @@ static int crc_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, return 0; } -static void crc_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm, - struct pwm_state *state) +static int crc_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm, + struct pwm_state *state) { struct crystalcove_pwm *crc_pwm = to_crc_pwm(chip); struct device *dev = crc_pwm->chip.dev; @@ -132,13 +132,13 @@ static void crc_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm, error = regmap_read(crc_pwm->regmap, PWM0_CLK_DIV, &clk_div_reg); if (error) { dev_err(dev, "Error reading PWM0_CLK_DIV %d\n", error); - return; + return 0; } error = regmap_read(crc_pwm->regmap, PWM0_DUTY_CYCLE, &duty_cycle_reg); if (error) { dev_err(dev, "Error reading PWM0_DUTY_CYCLE %d\n", error); - return; + return 0; } clk_div = (clk_div_reg & ~PWM_OUTPUT_ENABLE) + 1; @@ -149,6 +149,8 @@ static void crc_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm, DIV_ROUND_UP_ULL(duty_cycle_reg * state->period, PWM_MAX_LEVEL); state->polarity = PWM_POLARITY_NORMAL; state->enabled = !!(clk_div_reg & PWM_OUTPUT_ENABLE); + + return 0; } static const struct pwm_ops crc_pwm_ops = { diff --git a/drivers/pwm/pwm-cros-ec.c b/drivers/pwm/pwm-cros-ec.c index 7f10f56c3eb6..11684edc0620 100644 --- a/drivers/pwm/pwm-cros-ec.c +++ b/drivers/pwm/pwm-cros-ec.c @@ -183,8 +183,8 @@ static int cros_ec_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, return 0; } -static void cros_ec_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm, - struct pwm_state *state) +static int cros_ec_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm, + struct pwm_state *state) { struct cros_ec_pwm_device *ec_pwm = pwm_to_cros_ec_pwm(chip); struct cros_ec_pwm *channel = pwm_get_chip_data(pwm); @@ -193,7 +193,7 @@ static void cros_ec_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm, ret = cros_ec_pwm_get_duty(ec_pwm, pwm->hwpwm); if (ret < 0) { dev_err(chip->dev, "error getting initial duty: %d\n", ret); - return; + return 0; } state->enabled = (ret > 0); @@ -212,6 +212,8 @@ static void cros_ec_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm, state->duty_cycle = channel->duty_cycle; else state->duty_cycle = ret; + + return 0; } static struct pwm_device * diff --git a/drivers/pwm/pwm-dwc.c b/drivers/pwm/pwm-dwc.c index 7568300bb11e..bd2308812096 100644 --- a/drivers/pwm/pwm-dwc.c +++ b/drivers/pwm/pwm-dwc.c @@ -163,8 +163,8 @@ static int dwc_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, return 0; } -static void dwc_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm, - struct pwm_state *state) +static int dwc_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm, + struct pwm_state *state) { struct dwc_pwm *dwc = to_dwc_pwm(chip); u64 duty, period; @@ -188,6 +188,8 @@ static void dwc_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm, state->polarity = PWM_POLARITY_INVERSED; pm_runtime_put_sync(chip->dev); + + return 0; } static const struct pwm_ops dwc_pwm_ops = { diff --git a/drivers/pwm/pwm-hibvt.c b/drivers/pwm/pwm-hibvt.c index 333f1b18ff4e..12c05c155cab 100644 --- a/drivers/pwm/pwm-hibvt.c +++ b/drivers/pwm/pwm-hibvt.c @@ -128,8 +128,8 @@ static void hibvt_pwm_set_polarity(struct pwm_chip *chip, PWM_POLARITY_MASK, (0x0 << PWM_POLARITY_SHIFT)); } -static void hibvt_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm, - struct pwm_state *state) +static int hibvt_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm, + struct pwm_state *state) { struct hibvt_pwm_chip *hi_pwm_chip = to_hibvt_pwm_chip(chip); void __iomem *base; @@ -146,6 +146,8 @@ static void hibvt_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm, value = readl(base + PWM_CTRL_ADDR(pwm->hwpwm)); state->enabled = (PWM_ENABLE_MASK & value); + + return 0; } static int hibvt_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, diff --git a/drivers/pwm/pwm-imx-tpm.c b/drivers/pwm/pwm-imx-tpm.c index e5e7b7c339a8..ed1aad96fff0 100644 --- a/drivers/pwm/pwm-imx-tpm.c +++ b/drivers/pwm/pwm-imx-tpm.c @@ -132,9 +132,9 @@ static int pwm_imx_tpm_round_state(struct pwm_chip *chip, return 0; } -static void pwm_imx_tpm_get_state(struct pwm_chip *chip, - struct pwm_device *pwm, - struct pwm_state *state) +static int pwm_imx_tpm_get_state(struct pwm_chip *chip, + struct pwm_device *pwm, + struct pwm_state *state) { struct imx_tpm_pwm_chip *tpm = to_imx_tpm_pwm_chip(chip); u32 rate, val, prescale; @@ -164,6 +164,8 @@ static void pwm_imx_tpm_get_state(struct pwm_chip *chip, /* get channel status */ state->enabled = FIELD_GET(PWM_IMX_TPM_CnSC_ELS, val) ? true : false; + + return 0; } /* this function is supposed to be called with mutex hold */ diff --git a/drivers/pwm/pwm-imx27.c b/drivers/pwm/pwm-imx27.c index ea91a2f81a9f..3a22c2fddc45 100644 --- a/drivers/pwm/pwm-imx27.c +++ b/drivers/pwm/pwm-imx27.c @@ -118,8 +118,8 @@ static void pwm_imx27_clk_disable_unprepare(struct pwm_imx27_chip *imx) clk_disable_unprepare(imx->clk_ipg); } -static void pwm_imx27_get_state(struct pwm_chip *chip, - struct pwm_device *pwm, struct pwm_state *state) +static int pwm_imx27_get_state(struct pwm_chip *chip, + struct pwm_device *pwm, struct pwm_state *state) { struct pwm_imx27_chip *imx = to_pwm_imx27_chip(chip); u32 period, prescaler, pwm_clk, val; @@ -128,7 +128,7 @@ static void pwm_imx27_get_state(struct pwm_chip *chip, ret = pwm_imx27_clk_prepare_enable(imx); if (ret < 0) - return; + return 0; val = readl(imx->mmio_base + MX3_PWMCR); @@ -170,6 +170,8 @@ static void pwm_imx27_get_state(struct pwm_chip *chip, state->duty_cycle = DIV_ROUND_UP_ULL(tmp, pwm_clk); pwm_imx27_clk_disable_unprepare(imx); + + return 0; } static void pwm_imx27_sw_reset(struct pwm_chip *chip) diff --git a/drivers/pwm/pwm-intel-lgm.c b/drivers/pwm/pwm-intel-lgm.c index b66c35074087..0cd7dd548e82 100644 --- a/drivers/pwm/pwm-intel-lgm.c +++ b/drivers/pwm/pwm-intel-lgm.c @@ -86,8 +86,8 @@ static int lgm_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, return lgm_pwm_enable(chip, 1); } -static void lgm_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm, - struct pwm_state *state) +static int lgm_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm, + struct pwm_state *state) { struct lgm_pwm_chip *pc = to_lgm_pwm_chip(chip); u32 duty, val; @@ -100,6 +100,8 @@ static void lgm_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm, regmap_read(pc->regmap, LGM_PWM_FAN_CON0, &val); duty = FIELD_GET(LGM_PWM_FAN_DC_MSK, val); state->duty_cycle = DIV_ROUND_UP(duty * pc->period, LGM_PWM_MAX_DUTY_CYCLE); + + return 0; } static const struct pwm_ops lgm_pwm_ops = { diff --git a/drivers/pwm/pwm-iqs620a.c b/drivers/pwm/pwm-iqs620a.c index 7246176fce06..4987ca940b64 100644 --- a/drivers/pwm/pwm-iqs620a.c +++ b/drivers/pwm/pwm-iqs620a.c @@ -104,8 +104,8 @@ static int iqs620_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, return ret; } -static void iqs620_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm, - struct pwm_state *state) +static int iqs620_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm, + struct pwm_state *state) { struct iqs620_pwm_private *iqs620_pwm; @@ -126,6 +126,8 @@ static void iqs620_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm, mutex_unlock(&iqs620_pwm->lock); state->period = IQS620_PWM_PERIOD_NS; + + return 0; } static int iqs620_pwm_notifier(struct notifier_block *notifier, diff --git a/drivers/pwm/pwm-keembay.c b/drivers/pwm/pwm-keembay.c index 733811b05721..ac02d8bb4a0b 100644 --- a/drivers/pwm/pwm-keembay.c +++ b/drivers/pwm/pwm-keembay.c @@ -89,8 +89,8 @@ static void keembay_pwm_disable(struct keembay_pwm *priv, int ch) KMB_PWM_LEADIN_OFFSET(ch)); } -static void keembay_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm, - struct pwm_state *state) +static int keembay_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm, + struct pwm_state *state) { struct keembay_pwm *priv = to_keembay_pwm_dev(chip); unsigned long long high, low; @@ -113,6 +113,8 @@ static void keembay_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm, state->duty_cycle = DIV_ROUND_UP_ULL(high, clk_rate); state->period = DIV_ROUND_UP_ULL(high + low, clk_rate); state->polarity = PWM_POLARITY_NORMAL; + + return 0; } static int keembay_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, diff --git a/drivers/pwm/pwm-lpss.c b/drivers/pwm/pwm-lpss.c index accdef5dd58e..81ac297b8ba5 100644 --- a/drivers/pwm/pwm-lpss.c +++ b/drivers/pwm/pwm-lpss.c @@ -205,8 +205,8 @@ static int pwm_lpss_apply(struct pwm_chip *chip, struct pwm_device *pwm, return ret; } -static void pwm_lpss_get_state(struct pwm_chip *chip, struct pwm_device *pwm, - struct pwm_state *state) +static int pwm_lpss_get_state(struct pwm_chip *chip, struct pwm_device *pwm, + struct pwm_state *state) { struct pwm_lpss_chip *lpwm = to_lpwm(chip); unsigned long base_unit_range; @@ -236,6 +236,8 @@ static void pwm_lpss_get_state(struct pwm_chip *chip, struct pwm_device *pwm, state->enabled = !!(ctrl & PWM_ENABLE); pm_runtime_put(chip->dev); + + return 0; } static const struct pwm_ops pwm_lpss_ops = { diff --git a/drivers/pwm/pwm-meson.c b/drivers/pwm/pwm-meson.c index 57112f438c6d..16d79ca5d8f5 100644 --- a/drivers/pwm/pwm-meson.c +++ b/drivers/pwm/pwm-meson.c @@ -318,8 +318,8 @@ static unsigned int meson_pwm_cnt_to_ns(struct pwm_chip *chip, return cnt * fin_ns * (channel->pre_div + 1); } -static void meson_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm, - struct pwm_state *state) +static int meson_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm, + struct pwm_state *state) { struct meson_pwm *meson = to_meson_pwm(chip); struct meson_pwm_channel_data *channel_data; @@ -327,7 +327,7 @@ static void meson_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm, u32 value, tmp; if (!state) - return; + return 0; channel = &meson->channels[pwm->hwpwm]; channel_data = &meson_pwm_per_channel_data[pwm->hwpwm]; @@ -357,6 +357,8 @@ static void meson_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm, state->period = 0; state->duty_cycle = 0; } + + return 0; } static const struct pwm_ops meson_pwm_ops = { diff --git a/drivers/pwm/pwm-mtk-disp.c b/drivers/pwm/pwm-mtk-disp.c index 3fbb4bae93a4..ccf0ccdef29d 100644 --- a/drivers/pwm/pwm-mtk-disp.c +++ b/drivers/pwm/pwm-mtk-disp.c @@ -172,9 +172,9 @@ static int mtk_disp_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, return 0; } -static void mtk_disp_pwm_get_state(struct pwm_chip *chip, - struct pwm_device *pwm, - struct pwm_state *state) +static int mtk_disp_pwm_get_state(struct pwm_chip *chip, + struct pwm_device *pwm, + struct pwm_state *state) { struct mtk_disp_pwm *mdp = to_mtk_disp_pwm(chip); u64 rate, period, high_width; @@ -184,14 +184,14 @@ static void mtk_disp_pwm_get_state(struct pwm_chip *chip, err = clk_prepare_enable(mdp->clk_main); if (err < 0) { dev_err(chip->dev, "Can't enable mdp->clk_main: %pe\n", ERR_PTR(err)); - return; + return 0; } err = clk_prepare_enable(mdp->clk_mm); if (err < 0) { dev_err(chip->dev, "Can't enable mdp->clk_mm: %pe\n", ERR_PTR(err)); clk_disable_unprepare(mdp->clk_main); - return; + return 0; } rate = clk_get_rate(mdp->clk_main); @@ -212,6 +212,8 @@ static void mtk_disp_pwm_get_state(struct pwm_chip *chip, state->polarity = PWM_POLARITY_NORMAL; clk_disable_unprepare(mdp->clk_mm); clk_disable_unprepare(mdp->clk_main); + + return 0; } static const struct pwm_ops mtk_disp_pwm_ops = { diff --git a/drivers/pwm/pwm-pca9685.c b/drivers/pwm/pwm-pca9685.c index f230c10d28bb..41be244e7dd3 100644 --- a/drivers/pwm/pwm-pca9685.c +++ b/drivers/pwm/pwm-pca9685.c @@ -431,8 +431,8 @@ static int pca9685_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, return ret; } -static void pca9685_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm, - struct pwm_state *state) +static int pca9685_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm, + struct pwm_state *state) { struct pca9685 *pca = to_pca(chip); unsigned long long duty; @@ -458,12 +458,14 @@ static void pca9685_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm, */ state->duty_cycle = 0; state->enabled = false; - return; + return 0; } state->enabled = true; duty = pca9685_pwm_get_duty(pca, pwm->hwpwm); state->duty_cycle = DIV_ROUND_DOWN_ULL(duty * state->period, PCA9685_COUNTER_RANGE); + + return 0; } static int pca9685_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm) diff --git a/drivers/pwm/pwm-raspberrypi-poe.c b/drivers/pwm/pwm-raspberrypi-poe.c index 6ff73029f367..2939b71a7ba7 100644 --- a/drivers/pwm/pwm-raspberrypi-poe.c +++ b/drivers/pwm/pwm-raspberrypi-poe.c @@ -82,9 +82,9 @@ static int raspberrypi_pwm_get_property(struct rpi_firmware *firmware, return 0; } -static void raspberrypi_pwm_get_state(struct pwm_chip *chip, - struct pwm_device *pwm, - struct pwm_state *state) +static int raspberrypi_pwm_get_state(struct pwm_chip *chip, + struct pwm_device *pwm, + struct pwm_state *state) { struct raspberrypi_pwm *rpipwm = raspberrypi_pwm_from_chip(chip); @@ -93,6 +93,8 @@ static void raspberrypi_pwm_get_state(struct pwm_chip *chip, RPI_PWM_MAX_DUTY); state->enabled = !!(rpipwm->duty_cycle); state->polarity = PWM_POLARITY_NORMAL; + + return 0; } static int raspberrypi_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, diff --git a/drivers/pwm/pwm-rockchip.c b/drivers/pwm/pwm-rockchip.c index a5af859217c1..3ec7d1756903 100644 --- a/drivers/pwm/pwm-rockchip.c +++ b/drivers/pwm/pwm-rockchip.c @@ -57,9 +57,9 @@ static inline struct rockchip_pwm_chip *to_rockchip_pwm_chip(struct pwm_chip *c) return container_of(c, struct rockchip_pwm_chip, chip); } -static void rockchip_pwm_get_state(struct pwm_chip *chip, - struct pwm_device *pwm, - struct pwm_state *state) +static int rockchip_pwm_get_state(struct pwm_chip *chip, + struct pwm_device *pwm, + struct pwm_state *state) { struct rockchip_pwm_chip *pc = to_rockchip_pwm_chip(chip); u32 enable_conf = pc->data->enable_conf; @@ -70,11 +70,11 @@ static void rockchip_pwm_get_state(struct pwm_chip *chip, ret = clk_enable(pc->pclk); if (ret) - return; + return 0; ret = clk_enable(pc->clk); if (ret) - return; + return 0; clk_rate = clk_get_rate(pc->clk); @@ -96,6 +96,8 @@ static void rockchip_pwm_get_state(struct pwm_chip *chip, clk_disable(pc->clk); clk_disable(pc->pclk); + + return 0; } static void rockchip_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, diff --git a/drivers/pwm/pwm-sifive.c b/drivers/pwm/pwm-sifive.c index bb7239313401..62b6acc6373d 100644 --- a/drivers/pwm/pwm-sifive.c +++ b/drivers/pwm/pwm-sifive.c @@ -105,8 +105,8 @@ static void pwm_sifive_update_clock(struct pwm_sifive_ddata *ddata, "New real_period = %u ns\n", ddata->real_period); } -static void pwm_sifive_get_state(struct pwm_chip *chip, struct pwm_device *pwm, - struct pwm_state *state) +static int pwm_sifive_get_state(struct pwm_chip *chip, struct pwm_device *pwm, + struct pwm_state *state) { struct pwm_sifive_ddata *ddata = pwm_sifive_chip_to_ddata(chip); u32 duty, val; @@ -123,6 +123,8 @@ static void pwm_sifive_get_state(struct pwm_chip *chip, struct pwm_device *pwm, state->duty_cycle = (u64)duty * ddata->real_period >> PWM_SIFIVE_CMPWIDTH; state->polarity = PWM_POLARITY_INVERSED; + + return 0; } static int pwm_sifive_apply(struct pwm_chip *chip, struct pwm_device *pwm, diff --git a/drivers/pwm/pwm-sl28cpld.c b/drivers/pwm/pwm-sl28cpld.c index 589aeaaa6ac8..e64900ad4ba1 100644 --- a/drivers/pwm/pwm-sl28cpld.c +++ b/drivers/pwm/pwm-sl28cpld.c @@ -87,9 +87,9 @@ struct sl28cpld_pwm { #define sl28cpld_pwm_from_chip(_chip) \ container_of(_chip, struct sl28cpld_pwm, pwm_chip) -static void sl28cpld_pwm_get_state(struct pwm_chip *chip, - struct pwm_device *pwm, - struct pwm_state *state) +static int sl28cpld_pwm_get_state(struct pwm_chip *chip, + struct pwm_device *pwm, + struct pwm_state *state) { struct sl28cpld_pwm *priv = sl28cpld_pwm_from_chip(chip); unsigned int reg; @@ -115,6 +115,8 @@ static void sl28cpld_pwm_get_state(struct pwm_chip *chip, * the PWM core. */ state->duty_cycle = min(state->duty_cycle, state->period); + + return 0; } static int sl28cpld_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, diff --git a/drivers/pwm/pwm-sprd.c b/drivers/pwm/pwm-sprd.c index 7004f55bbf11..bda8bc5af976 100644 --- a/drivers/pwm/pwm-sprd.c +++ b/drivers/pwm/pwm-sprd.c @@ -65,8 +65,8 @@ static void sprd_pwm_write(struct sprd_pwm_chip *spc, u32 hwid, writel_relaxed(val, spc->base + offset); } -static void sprd_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm, - struct pwm_state *state) +static int sprd_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm, + struct pwm_state *state) { struct sprd_pwm_chip *spc = container_of(chip, struct sprd_pwm_chip, chip); @@ -83,7 +83,7 @@ static void sprd_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm, if (ret) { dev_err(spc->dev, "failed to enable pwm%u clocks\n", pwm->hwpwm); - return; + return 0; } val = sprd_pwm_read(spc, pwm->hwpwm, SPRD_PWM_ENABLE); @@ -113,6 +113,8 @@ static void sprd_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm, /* Disable PWM clocks if the PWM channel is not in enable state. */ if (!state->enabled) clk_bulk_disable_unprepare(SPRD_PWM_CHN_CLKS_NUM, chn->clks); + + return 0; } static int sprd_pwm_config(struct sprd_pwm_chip *spc, struct pwm_device *pwm, diff --git a/drivers/pwm/pwm-stm32-lp.c b/drivers/pwm/pwm-stm32-lp.c index 212bdc7d51ee..514ff58a4471 100644 --- a/drivers/pwm/pwm-stm32-lp.c +++ b/drivers/pwm/pwm-stm32-lp.c @@ -156,9 +156,9 @@ err: return ret; } -static void stm32_pwm_lp_get_state(struct pwm_chip *chip, - struct pwm_device *pwm, - struct pwm_state *state) +static int stm32_pwm_lp_get_state(struct pwm_chip *chip, + struct pwm_device *pwm, + struct pwm_state *state) { struct stm32_pwm_lp *priv = to_stm32_pwm_lp(chip); unsigned long rate = clk_get_rate(priv->clk); @@ -184,6 +184,8 @@ static void stm32_pwm_lp_get_state(struct pwm_chip *chip, tmp = prd - val; tmp = (tmp << presc) * NSEC_PER_SEC; state->duty_cycle = DIV_ROUND_CLOSEST_ULL(tmp, rate); + + return 0; } static const struct pwm_ops stm32_pwm_lp_ops = { diff --git a/drivers/pwm/pwm-sun4i.c b/drivers/pwm/pwm-sun4i.c index c8445b0a3339..37d75e252d4e 100644 --- a/drivers/pwm/pwm-sun4i.c +++ b/drivers/pwm/pwm-sun4i.c @@ -108,9 +108,9 @@ static inline void sun4i_pwm_writel(struct sun4i_pwm_chip *chip, writel(val, chip->base + offset); } -static void sun4i_pwm_get_state(struct pwm_chip *chip, - struct pwm_device *pwm, - struct pwm_state *state) +static int sun4i_pwm_get_state(struct pwm_chip *chip, + struct pwm_device *pwm, + struct pwm_state *state) { struct sun4i_pwm_chip *sun4i_pwm = to_sun4i_pwm_chip(chip); u64 clk_rate, tmp; @@ -132,7 +132,7 @@ static void sun4i_pwm_get_state(struct pwm_chip *chip, state->duty_cycle = DIV_ROUND_UP_ULL(state->period, 2); state->polarity = PWM_POLARITY_NORMAL; state->enabled = true; - return; + return 0; } if ((PWM_REG_PRESCAL(val, pwm->hwpwm) == PWM_PRESCAL_MASK) && @@ -142,7 +142,7 @@ static void sun4i_pwm_get_state(struct pwm_chip *chip, prescaler = prescaler_table[PWM_REG_PRESCAL(val, pwm->hwpwm)]; if (prescaler == 0) - return; + return 0; if (val & BIT_CH(PWM_ACT_STATE, pwm->hwpwm)) state->polarity = PWM_POLARITY_NORMAL; @@ -162,6 +162,8 @@ static void sun4i_pwm_get_state(struct pwm_chip *chip, tmp = (u64)prescaler * NSEC_PER_SEC * PWM_REG_PRD(val); state->period = DIV_ROUND_CLOSEST_ULL(tmp, clk_rate); + + return 0; } static int sun4i_pwm_calculate(struct sun4i_pwm_chip *sun4i_pwm, diff --git a/drivers/pwm/pwm-sunplus.c b/drivers/pwm/pwm-sunplus.c index e776fd16512d..d6ebe9f03b35 100644 --- a/drivers/pwm/pwm-sunplus.c +++ b/drivers/pwm/pwm-sunplus.c @@ -124,8 +124,8 @@ static int sunplus_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, return 0; } -static void sunplus_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm, - struct pwm_state *state) +static int sunplus_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm, + struct pwm_state *state) { struct sunplus_pwm *priv = to_sunplus_pwm(chip); u32 mode0, dd_freq, duty; @@ -155,6 +155,8 @@ static void sunplus_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm, } state->polarity = PWM_POLARITY_NORMAL; + + return 0; } static const struct pwm_ops sunplus_pwm_ops = { diff --git a/drivers/pwm/pwm-visconti.c b/drivers/pwm/pwm-visconti.c index 927c4cbb1daf..e3fb79b3e2a7 100644 --- a/drivers/pwm/pwm-visconti.c +++ b/drivers/pwm/pwm-visconti.c @@ -103,8 +103,8 @@ static int visconti_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, return 0; } -static void visconti_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm, - struct pwm_state *state) +static int visconti_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm, + struct pwm_state *state) { struct visconti_pwm_chip *priv = visconti_pwm_from_chip(chip); u32 period, duty, pwmc0, pwmc0_clk; @@ -122,6 +122,8 @@ static void visconti_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm state->polarity = PWM_POLARITY_NORMAL; state->enabled = true; + + return 0; } static const struct pwm_ops visconti_pwm_ops = { diff --git a/drivers/pwm/pwm-xilinx.c b/drivers/pwm/pwm-xilinx.c index 4dab2b86c427..f7a50fdcd9a5 100644 --- a/drivers/pwm/pwm-xilinx.c +++ b/drivers/pwm/pwm-xilinx.c @@ -169,9 +169,9 @@ static int xilinx_pwm_apply(struct pwm_chip *chip, struct pwm_device *unused, return 0; } -static void xilinx_pwm_get_state(struct pwm_chip *chip, - struct pwm_device *unused, - struct pwm_state *state) +static int xilinx_pwm_get_state(struct pwm_chip *chip, + struct pwm_device *unused, + struct pwm_state *state) { struct xilinx_timer_priv *priv = xilinx_pwm_chip_to_priv(chip); u32 tlr0, tlr1, tcsr0, tcsr1; @@ -191,6 +191,8 @@ static void xilinx_pwm_get_state(struct pwm_chip *chip, */ if (state->period == state->duty_cycle) state->duty_cycle = 0; + + return 0; } static const struct pwm_ops xilinx_pwm_ops = { diff --git a/include/linux/pwm.h b/include/linux/pwm.h index d70c6e5a839d..4de09163c968 100644 --- a/include/linux/pwm.h +++ b/include/linux/pwm.h @@ -276,8 +276,8 @@ struct pwm_ops { struct pwm_capture *result, unsigned long timeout); int (*apply)(struct pwm_chip *chip, struct pwm_device *pwm, const struct pwm_state *state); - void (*get_state)(struct pwm_chip *chip, struct pwm_device *pwm, - struct pwm_state *state); + int (*get_state)(struct pwm_chip *chip, struct pwm_device *pwm, + struct pwm_state *state); struct module *owner; }; From 3dae106f4ca358bb1d8d8708d3289fa130b1ad5b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Fri, 2 Dec 2022 19:35:27 +0100 Subject: [PATCH 31/42] pwm/tracing: Also record trace events for failed API calls MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Record and report an error code for the events. This allows to report about failed calls without ambiguity and so gives a more complete picture. Acked-by: Conor Dooley Link: https://lore.kernel.org/r/20221130152148.2769768-3-u.kleine-koenig@pengutronix.de Signed-off-by: Uwe Kleine-König Signed-off-by: Thierry Reding --- drivers/pwm/core.c | 18 ++++++++---------- include/trace/events/pwm.h | 20 ++++++++++---------- 2 files changed, 18 insertions(+), 20 deletions(-) diff --git a/drivers/pwm/core.c b/drivers/pwm/core.c index 3a0967209853..61d15510fdd7 100644 --- a/drivers/pwm/core.c +++ b/drivers/pwm/core.c @@ -115,8 +115,8 @@ static int pwm_device_request(struct pwm_device *pwm, const char *label) } if (pwm->chip->ops->get_state) { - pwm->chip->ops->get_state(pwm->chip, pwm, &pwm->state); - trace_pwm_get(pwm, &pwm->state); + err = pwm->chip->ops->get_state(pwm->chip, pwm, &pwm->state); + trace_pwm_get(pwm, &pwm->state, err); if (IS_ENABLED(CONFIG_PWM_DEBUG)) pwm->last = pwm->state; @@ -458,8 +458,8 @@ static void pwm_apply_state_debug(struct pwm_device *pwm, * checks. */ - chip->ops->get_state(chip, pwm, &s1); - trace_pwm_get(pwm, &s1); + err = chip->ops->get_state(chip, pwm, &s1); + trace_pwm_get(pwm, &s1, err); /* * The lowlevel driver either ignored .polarity (which is a bug) or as @@ -515,16 +515,15 @@ static void pwm_apply_state_debug(struct pwm_device *pwm, /* reapply the state that the driver reported being configured. */ err = chip->ops->apply(chip, pwm, &s1); + trace_pwm_apply(pwm, &s1, err); if (err) { *last = s1; dev_err(chip->dev, "failed to reapply current setting\n"); return; } - trace_pwm_apply(pwm, &s1); - - chip->ops->get_state(chip, pwm, last); - trace_pwm_get(pwm, last); + err = chip->ops->get_state(chip, pwm, last); + trace_pwm_get(pwm, last, err); /* reapplication of the current state should give an exact match */ if (s1.enabled != last->enabled || @@ -572,11 +571,10 @@ int pwm_apply_state(struct pwm_device *pwm, const struct pwm_state *state) return 0; err = chip->ops->apply(chip, pwm, state); + trace_pwm_apply(pwm, state, err); if (err) return err; - trace_pwm_apply(pwm, state); - pwm->state = *state; /* diff --git a/include/trace/events/pwm.h b/include/trace/events/pwm.h index cf243de41cc8..12b35e4ff917 100644 --- a/include/trace/events/pwm.h +++ b/include/trace/events/pwm.h @@ -10,9 +10,9 @@ DECLARE_EVENT_CLASS(pwm, - TP_PROTO(struct pwm_device *pwm, const struct pwm_state *state), + TP_PROTO(struct pwm_device *pwm, const struct pwm_state *state, int err), - TP_ARGS(pwm, state), + TP_ARGS(pwm, state, err), TP_STRUCT__entry( __field(struct pwm_device *, pwm) @@ -20,6 +20,7 @@ DECLARE_EVENT_CLASS(pwm, __field(u64, duty_cycle) __field(enum pwm_polarity, polarity) __field(bool, enabled) + __field(int, err) ), TP_fast_assign( @@ -28,28 +29,27 @@ DECLARE_EVENT_CLASS(pwm, __entry->duty_cycle = state->duty_cycle; __entry->polarity = state->polarity; __entry->enabled = state->enabled; + __entry->err = err; ), - TP_printk("%p: period=%llu duty_cycle=%llu polarity=%d enabled=%d", + TP_printk("%p: period=%llu duty_cycle=%llu polarity=%d enabled=%d err=%d", __entry->pwm, __entry->period, __entry->duty_cycle, - __entry->polarity, __entry->enabled) + __entry->polarity, __entry->enabled, __entry->err) ); DEFINE_EVENT(pwm, pwm_apply, - TP_PROTO(struct pwm_device *pwm, const struct pwm_state *state), - - TP_ARGS(pwm, state) + TP_PROTO(struct pwm_device *pwm, const struct pwm_state *state, int err), + TP_ARGS(pwm, state, err) ); DEFINE_EVENT(pwm, pwm_get, - TP_PROTO(struct pwm_device *pwm, const struct pwm_state *state), - - TP_ARGS(pwm, state) + TP_PROTO(struct pwm_device *pwm, const struct pwm_state *state, int err), + TP_ARGS(pwm, state, err) ); #endif /* _TRACE_PWM_H */ From f00de180661d8191aa979c2a8a8f4ec2b35a4cfd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Fri, 2 Dec 2022 19:35:28 +0100 Subject: [PATCH 32/42] drm/bridge: ti-sn65dsi86: Propagate errors in .get_state() to the caller MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit .get_state() can return an error indication. Make use of it to propagate failing hardware accesses. Acked-by: Douglas Anderson Reviewed-by: Laurent Pinchart Acked-by: Conor Dooley Link: https://lore.kernel.org/r/20221130152148.2769768-4-u.kleine-koenig@pengutronix.de Signed-off-by: Uwe Kleine-König Signed-off-by: Thierry Reding --- drivers/gpu/drm/bridge/ti-sn65dsi86.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/bridge/ti-sn65dsi86.c b/drivers/gpu/drm/bridge/ti-sn65dsi86.c index 6826d2423ae9..9671071490d8 100644 --- a/drivers/gpu/drm/bridge/ti-sn65dsi86.c +++ b/drivers/gpu/drm/bridge/ti-sn65dsi86.c @@ -1512,19 +1512,19 @@ static int ti_sn_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm, ret = regmap_read(pdata->regmap, SN_PWM_EN_INV_REG, &pwm_en_inv); if (ret) - return 0; + return ret; ret = ti_sn65dsi86_read_u16(pdata, SN_BACKLIGHT_SCALE_REG, &scale); if (ret) - return 0; + return ret; ret = ti_sn65dsi86_read_u16(pdata, SN_BACKLIGHT_REG, &backlight); if (ret) - return 0; + return ret; ret = regmap_read(pdata->regmap, SN_PWM_PRE_DIV_REG, &pre_div); if (ret) - return 0; + return ret; state->enabled = FIELD_GET(SN_PWM_EN_MASK, pwm_en_inv); if (FIELD_GET(SN_PWM_INV_MASK, pwm_en_inv)) From fea768cf68c04d68ea2a8091c559667378f3b77c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Fri, 2 Dec 2022 19:35:29 +0100 Subject: [PATCH 33/42] leds: qcom-lpg: Propagate errors in .get_state() to the caller MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit .get_state() can return an error indication. Make use of it to propagate failing hardware accesses. Acked-by: Pavel Machek Acked-by: Conor Dooley Link: https://lore.kernel.org/r/20221130152148.2769768-5-u.kleine-koenig@pengutronix.de Signed-off-by: Uwe Kleine-König Signed-off-by: Thierry Reding --- drivers/leds/rgb/leds-qcom-lpg.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/leds/rgb/leds-qcom-lpg.c b/drivers/leds/rgb/leds-qcom-lpg.c index 741cc2fd817d..0dcc046a9a19 100644 --- a/drivers/leds/rgb/leds-qcom-lpg.c +++ b/drivers/leds/rgb/leds-qcom-lpg.c @@ -982,20 +982,20 @@ static int lpg_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm, ret = regmap_read(lpg->map, chan->base + LPG_SIZE_CLK_REG, &val); if (ret) - return 0; + return ret; refclk = lpg_clk_rates[val & PWM_CLK_SELECT_MASK]; if (refclk) { ret = regmap_read(lpg->map, chan->base + LPG_PREDIV_CLK_REG, &val); if (ret) - return 0; + return ret; pre_div = lpg_pre_divs[FIELD_GET(PWM_FREQ_PRE_DIV_MASK, val)]; m = FIELD_GET(PWM_FREQ_EXP_MASK, val); ret = regmap_bulk_read(lpg->map, chan->base + PWM_VALUE_REG, &pwm_value, sizeof(pwm_value)); if (ret) - return 0; + return ret; state->period = DIV_ROUND_UP_ULL((u64)NSEC_PER_SEC * LPG_RESOLUTION * pre_div * (1 << m), refclk); state->duty_cycle = DIV_ROUND_UP_ULL((u64)NSEC_PER_SEC * pwm_value * pre_div * (1 << m), refclk); @@ -1006,7 +1006,7 @@ static int lpg_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm, ret = regmap_read(lpg->map, chan->base + PWM_ENABLE_CONTROL_REG, &val); if (ret) - return 0; + return ret; state->enabled = FIELD_GET(LPG_ENABLE_CONTROL_OUTPUT, val); state->polarity = PWM_POLARITY_NORMAL; From 9c9d5e9957ac443cc544d63688e2442c230430ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Fri, 2 Dec 2022 19:35:30 +0100 Subject: [PATCH 34/42] pwm: crc: Propagate errors in .get_state() to the caller MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit .get_state() can return an error indication. Make use of it to propagate failing hardware accesses. Acked-by: Conor Dooley Link: https://lore.kernel.org/r/20221130152148.2769768-6-u.kleine-koenig@pengutronix.de Signed-off-by: Uwe Kleine-König Signed-off-by: Thierry Reding --- drivers/pwm/pwm-crc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/pwm/pwm-crc.c b/drivers/pwm/pwm-crc.c index 4099850117ba..4703b4a0b6e4 100644 --- a/drivers/pwm/pwm-crc.c +++ b/drivers/pwm/pwm-crc.c @@ -132,13 +132,13 @@ static int crc_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm, error = regmap_read(crc_pwm->regmap, PWM0_CLK_DIV, &clk_div_reg); if (error) { dev_err(dev, "Error reading PWM0_CLK_DIV %d\n", error); - return 0; + return error; } error = regmap_read(crc_pwm->regmap, PWM0_DUTY_CYCLE, &duty_cycle_reg); if (error) { dev_err(dev, "Error reading PWM0_DUTY_CYCLE %d\n", error); - return 0; + return error; } clk_div = (clk_div_reg & ~PWM_OUTPUT_ENABLE) + 1; From ee02c1cb87f957ff0c66337d776486e72967987d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Fri, 2 Dec 2022 19:35:31 +0100 Subject: [PATCH 35/42] pwm: cros-ec: Propagate errors in .get_state() to the caller MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit .get_state() can return an error indication. Make use of it to propagate failing hardware accesses. Reviewed-by: Tzung-Bi Shih Acked-by: Conor Dooley Link: https://lore.kernel.org/r/20221130152148.2769768-7-u.kleine-koenig@pengutronix.de Signed-off-by: Uwe Kleine-König Signed-off-by: Thierry Reding --- drivers/pwm/pwm-cros-ec.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/pwm/pwm-cros-ec.c b/drivers/pwm/pwm-cros-ec.c index 11684edc0620..86df6702cb83 100644 --- a/drivers/pwm/pwm-cros-ec.c +++ b/drivers/pwm/pwm-cros-ec.c @@ -193,7 +193,7 @@ static int cros_ec_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm, ret = cros_ec_pwm_get_duty(ec_pwm, pwm->hwpwm); if (ret < 0) { dev_err(chip->dev, "error getting initial duty: %d\n", ret); - return 0; + return ret; } state->enabled = (ret > 0); From 51b9f2fb38bd209bbfa49e1eca2e262667f29e48 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Fri, 2 Dec 2022 19:35:32 +0100 Subject: [PATCH 36/42] pwm: imx27: Propagate errors in .get_state() to the caller MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit .get_state() can return an error indication. Make use of it to propagate failing hardware accesses. Acked-by: Conor Dooley Link: https://lore.kernel.org/r/20221130152148.2769768-8-u.kleine-koenig@pengutronix.de Signed-off-by: Uwe Kleine-König Signed-off-by: Thierry Reding --- drivers/pwm/pwm-imx27.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/pwm/pwm-imx27.c b/drivers/pwm/pwm-imx27.c index 3a22c2fddc45..29a3089c534c 100644 --- a/drivers/pwm/pwm-imx27.c +++ b/drivers/pwm/pwm-imx27.c @@ -128,7 +128,7 @@ static int pwm_imx27_get_state(struct pwm_chip *chip, ret = pwm_imx27_clk_prepare_enable(imx); if (ret < 0) - return 0; + return ret; val = readl(imx->mmio_base + MX3_PWMCR); From 2f47786ce460206f2ff8ecb7d19352e2307b5511 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Fri, 2 Dec 2022 19:35:33 +0100 Subject: [PATCH 37/42] pwm: mtk-disp: Propagate errors in .get_state() to the caller MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit .get_state() can return an error indication. Make use of it to propagate failing hardware accesses. Reviewed-by: AngeloGioacchino Del Regno Acked-by: Conor Dooley Link: https://lore.kernel.org/r/20221130152148.2769768-9-u.kleine-koenig@pengutronix.de Signed-off-by: Uwe Kleine-König Signed-off-by: Thierry Reding --- drivers/pwm/pwm-mtk-disp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/pwm/pwm-mtk-disp.c b/drivers/pwm/pwm-mtk-disp.c index ccf0ccdef29d..692a06121b28 100644 --- a/drivers/pwm/pwm-mtk-disp.c +++ b/drivers/pwm/pwm-mtk-disp.c @@ -184,14 +184,14 @@ static int mtk_disp_pwm_get_state(struct pwm_chip *chip, err = clk_prepare_enable(mdp->clk_main); if (err < 0) { dev_err(chip->dev, "Can't enable mdp->clk_main: %pe\n", ERR_PTR(err)); - return 0; + return err; } err = clk_prepare_enable(mdp->clk_mm); if (err < 0) { dev_err(chip->dev, "Can't enable mdp->clk_mm: %pe\n", ERR_PTR(err)); clk_disable_unprepare(mdp->clk_main); - return 0; + return err; } rate = clk_get_rate(mdp->clk_main); From 790a8bae62f701821305dac37a9f6013cde8488f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Fri, 2 Dec 2022 19:35:34 +0100 Subject: [PATCH 38/42] pwm: rockchip: Propagate errors in .get_state() to the caller MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit .get_state() can return an error indication. Make use of it to propagate failing hardware accesses. Reviewed-by: Heiko Stuebner Acked-by: Conor Dooley Link: https://lore.kernel.org/r/20221130152148.2769768-10-u.kleine-koenig@pengutronix.de Signed-off-by: Uwe Kleine-König Signed-off-by: Thierry Reding --- drivers/pwm/pwm-rockchip.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/pwm/pwm-rockchip.c b/drivers/pwm/pwm-rockchip.c index 3ec7d1756903..7f084eb34092 100644 --- a/drivers/pwm/pwm-rockchip.c +++ b/drivers/pwm/pwm-rockchip.c @@ -70,11 +70,11 @@ static int rockchip_pwm_get_state(struct pwm_chip *chip, ret = clk_enable(pc->pclk); if (ret) - return 0; + return ret; ret = clk_enable(pc->clk); if (ret) - return 0; + return ret; clk_rate = clk_get_rate(pc->clk); From 500f879843adf329281e418d302e1ad40baa26c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Fri, 2 Dec 2022 19:35:35 +0100 Subject: [PATCH 39/42] pwm: sprd: Propagate errors in .get_state() to the caller MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit .get_state() can return an error indication. Make use of it to propagate failing hardware accesses. Reviewed-by: Baolin Wang Acked-by: Conor Dooley Link: https://lore.kernel.org/r/20221130152148.2769768-11-u.kleine-koenig@pengutronix.de Signed-off-by: Uwe Kleine-König Signed-off-by: Thierry Reding --- drivers/pwm/pwm-sprd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/pwm/pwm-sprd.c b/drivers/pwm/pwm-sprd.c index bda8bc5af976..d866ce345f97 100644 --- a/drivers/pwm/pwm-sprd.c +++ b/drivers/pwm/pwm-sprd.c @@ -83,7 +83,7 @@ static int sprd_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm, if (ret) { dev_err(spc->dev, "failed to enable pwm%u clocks\n", pwm->hwpwm); - return 0; + return ret; } val = sprd_pwm_read(spc, pwm->hwpwm, SPRD_PWM_ENABLE); From c73a3107624ddc305483ced13deca9ce8a073783 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Fri, 2 Dec 2022 19:35:36 +0100 Subject: [PATCH 40/42] pwm: Handle .get_state() failures MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This suppresses diagnosis for PWM_DEBUG routines and makes sure that pwm->state isn't modified in pwm_device_request() if .get_state() fails. Acked-by: Conor Dooley Link: https://lore.kernel.org/r/20221130152148.2769768-12-u.kleine-koenig@pengutronix.de Signed-off-by: Uwe Kleine-König Signed-off-by: Thierry Reding --- drivers/pwm/core.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/drivers/pwm/core.c b/drivers/pwm/core.c index 61d15510fdd7..e01147f66e15 100644 --- a/drivers/pwm/core.c +++ b/drivers/pwm/core.c @@ -115,8 +115,13 @@ static int pwm_device_request(struct pwm_device *pwm, const char *label) } if (pwm->chip->ops->get_state) { - err = pwm->chip->ops->get_state(pwm->chip, pwm, &pwm->state); - trace_pwm_get(pwm, &pwm->state, err); + struct pwm_state state; + + err = pwm->chip->ops->get_state(pwm->chip, pwm, &state); + trace_pwm_get(pwm, &state, err); + + if (!err) + pwm->state = state; if (IS_ENABLED(CONFIG_PWM_DEBUG)) pwm->last = pwm->state; @@ -460,6 +465,9 @@ static void pwm_apply_state_debug(struct pwm_device *pwm, err = chip->ops->get_state(chip, pwm, &s1); trace_pwm_get(pwm, &s1, err); + if (err) + /* If that failed there isn't much to debug */ + return; /* * The lowlevel driver either ignored .polarity (which is a bug) or as @@ -524,6 +532,8 @@ static void pwm_apply_state_debug(struct pwm_device *pwm, err = chip->ops->get_state(chip, pwm, last); trace_pwm_get(pwm, last, err); + if (err) + return; /* reapplication of the current state should give an exact match */ if (s1.enabled != last->enabled || From a08b318a155e77d4c61bbdc28248b347d66f7248 Mon Sep 17 00:00:00 2001 From: Andre Przywara Date: Fri, 2 Dec 2022 19:35:37 +0100 Subject: [PATCH 41/42] pwm: sun4i: Propagate errors in .get_state() to the caller MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit .get_state() can return an error indication now. Make use of it to propagate an impossible prescaler encoding, should that have sneaked in somehow. Also check the return value of clk_get_rate(). That's unlikely to fail, but we use that in two divide operations down in the code, so let's avoid a divide-by-zero condition on the way. Signed-off-by: Andre Przywara Reviewed-by: Uwe Kleine-König Reviewed-by: Samuel Holland Reviewed-by: Jernej Skrabec Link: https://lore.kernel.org/r/20221201152223.3133-1-andre.przywara@arm.com Signed-off-by: Uwe Kleine-König Signed-off-by: Thierry Reding --- drivers/pwm/pwm-sun4i.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/pwm/pwm-sun4i.c b/drivers/pwm/pwm-sun4i.c index 37d75e252d4e..b973da73e9ab 100644 --- a/drivers/pwm/pwm-sun4i.c +++ b/drivers/pwm/pwm-sun4i.c @@ -118,6 +118,8 @@ static int sun4i_pwm_get_state(struct pwm_chip *chip, unsigned int prescaler; clk_rate = clk_get_rate(sun4i_pwm->clk); + if (!clk_rate) + return -EINVAL; val = sun4i_pwm_readl(sun4i_pwm, PWM_CTRL_REG); @@ -142,7 +144,7 @@ static int sun4i_pwm_get_state(struct pwm_chip *chip, prescaler = prescaler_table[PWM_REG_PRESCAL(val, pwm->hwpwm)]; if (prescaler == 0) - return 0; + return -EINVAL; if (val & BIT_CH(PWM_ACT_STATE, pwm->hwpwm)) state->polarity = PWM_POLARITY_NORMAL; From 8fa22f4b88e877c0811d2a0e506cf56755add554 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Fri, 2 Dec 2022 19:35:38 +0100 Subject: [PATCH 42/42] pwm: pca9685: Convert to i2c's .probe_new() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The probe function doesn't make use of the i2c_device_id * parameter so it can be trivially converted. Link: https://lore.kernel.org/r/20221118224540.619276-538-uwe@kleine-koenig.org Signed-off-by: Uwe Kleine-König Signed-off-by: Thierry Reding --- drivers/pwm/pwm-pca9685.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/pwm/pwm-pca9685.c b/drivers/pwm/pwm-pca9685.c index 41be244e7dd3..3ed5a48ca581 100644 --- a/drivers/pwm/pwm-pca9685.c +++ b/drivers/pwm/pwm-pca9685.c @@ -515,8 +515,7 @@ static const struct regmap_config pca9685_regmap_i2c_config = { .cache_type = REGCACHE_NONE, }; -static int pca9685_pwm_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int pca9685_pwm_probe(struct i2c_client *client) { struct pca9685 *pca; unsigned int reg; @@ -666,7 +665,7 @@ static struct i2c_driver pca9685_i2c_driver = { .of_match_table = of_match_ptr(pca9685_dt_ids), .pm = &pca9685_pwm_pm, }, - .probe = pca9685_pwm_probe, + .probe_new = pca9685_pwm_probe, .remove = pca9685_pwm_remove, .id_table = pca9685_id, };