Re: [PATCH v4 3/3] pwm: mtk-disp: Switch to atomic API
From: Jitao Shi <hidden>
Date: 2021-06-11 02:37:59
Also in:
linux-mediatek, linux-pwm, lkml
On Sun, 2021-06-06 at 23:22 +0200, Uwe Kleine-König wrote:
Hello, On Thu, Jun 03, 2021 at 06:05:31PM +0800, Jitao Shi wrote:quoted
Convert the legacy api to atomic API. Signed-off-by: Jitao Shi <redacted> --- drivers/pwm/pwm-mtk-disp.c | 78 ++++++++++++++++++++++++++++---------- 1 file changed, 59 insertions(+), 19 deletions(-)diff --git a/drivers/pwm/pwm-mtk-disp.c b/drivers/pwm/pwm-mtk-disp.c index b87b3c00a685..d77348d0527c 100644 --- a/drivers/pwm/pwm-mtk-disp.c +++ b/drivers/pwm/pwm-mtk-disp.c@@ -67,8 +67,8 @@ static void mtk_disp_pwm_update_bits(struct mtk_disp_pwm *mdp, u32 offset, writel(value, address); } -static int mtk_disp_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, - int duty_ns, int period_ns) +static int mtk_disp_pwm_config(struct pwm_chip *chip, + const struct pwm_state *state) { struct mtk_disp_pwm *mdp = to_mtk_disp_pwm(chip); u32 clk_div, period, high_width, value;@@ -102,7 +102,7 @@ static int mtk_disp_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, * high_width = (PWM_CLK_RATE * duty_ns) / (10^9 * (clk_div + 1)) */ rate = clk_get_rate(mdp->clk_main); - clk_div = div_u64(rate * period_ns, NSEC_PER_SEC) >> + clk_div = div_u64(rate * state->period, NSEC_PER_SEC) >> PWM_PERIOD_BIT_WIDTH; if (clk_div > PWM_CLKDIV_MAX) { dev_err(chip->dev, "clock rate is too high: rate = %d Hz\n",@@ -114,11 +114,11 @@ static int mtk_disp_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, return -EINVAL; } div = NSEC_PER_SEC * (clk_div + 1); - period = div64_u64(rate * period_ns, div); + period = div64_u64(rate * state->period, div); if (period > 0) period--; - high_width = div64_u64(rate * duty_ns, div); + high_width = div64_u64(rate * state->duty_cycle, div); value = period | (high_width << PWM_HIGH_WIDTH_SHIFT); mtk_disp_pwm_update_bits(mdp, mdp->data->con0,@@ -144,39 +144,79 @@ static int mtk_disp_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, mdp->data->con0_sel); } + mtk_disp_pwm_update_bits(mdp, DISP_PWM_EN, mdp->data->enable_mask, + mdp->data->enable_mask); + mdp->enabled = true; + return 0; } -static int mtk_disp_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm) +static int mtk_disp_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, + const struct pwm_state *state) { struct mtk_disp_pwm *mdp = to_mtk_disp_pwm(chip); - int err; - mtk_disp_pwm_update_bits(mdp, DISP_PWM_EN, mdp->data->enable_mask, - mdp->data->enable_mask); - mdp->enabled = true; + if (!state->enabled) { + mtk_disp_pwm_update_bits(mdp, DISP_PWM_EN, mdp->data->enable_mask, + 0x0); - return 0; + if (mdp->enabled) { + clk_disable_unprepare(mdp->clk_mm); + clk_disable_unprepare(mdp->clk_main); + } + mdp->enabled = false; + return 0; + } + + return mtk_disp_pwm_config(chip, state);Please unroll this function call. Having the old name is irritating.
I'll fix it next version. Thanks for your review.
quoted
} -static void mtk_disp_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm) +static void mtk_disp_pwm_get_state(struct pwm_chip *chip, + struct pwm_device *pwm, + struct pwm_state *state)Adding .get_state() is great and warrants a separate patch.
I'll separate .get_state() next version. Thanks for your review.
quoted
{ struct mtk_disp_pwm *mdp = to_mtk_disp_pwm(chip); + u32 clk_div, period, high_width, con0, con1; + u64 rate; + int err; - mtk_disp_pwm_update_bits(mdp, DISP_PWM_EN, mdp->data->enable_mask, - 0x0); + if (!mdp->enabled) { + err = clk_prepare_enable(mdp->clk_main); + if (err < 0) { + dev_err(chip->dev, "Can't enable mdp->clk_main: %d\n", err); + return; + } + err = clk_prepare_enable(mdp->clk_mm); + if (err < 0) { + dev_err(chip->dev, "Can't enable mdp->clk_mm: %d\n", err); + clk_disable_unprepare(mdp->clk_main); + return; + } + } + + rate = clk_get_rate(mdp->clk_main); - if (mdp->enabled) { + con0 = readl(mdp->base + mdp->data->con0); + con1 = readl(mdp->base + mdp->data->con1); + + state->enabled = !!(con0 & BIT(0)); + + clk_div = (con0 & PWM_CLKDIV_MASK) >> PWM_CLKDIV_SHIFT;clk_div = FIELD_GET(PWM_CLKDIV_MASK, con0);
I'll fix it next version.
quoted
+ period = con1 & PWM_PERIOD_MASK; + state->period = div_u64(period * (clk_div + 1) * NSEC_PER_SEC, rate);Can this multiplication overflow? Note this is a 32bit multiplication only. As .apply() uses round-down in the divisions (which is good) please round up there to get idempotency between .get_state() and .apply().
I'll fix it next version.
quoted
+ high_width = (con1 & PWM_HIGH_WIDTH_MASK) >> PWM_HIGH_WIDTH_SHIFT; + state->duty_cycle = div_u64(high_width * (clk_div + 1) * NSEC_PER_SEC, + rate); + + if (!mdp->enabled) { clk_disable_unprepare(mdp->clk_mm); clk_disable_unprepare(mdp->clk_main); } - mdp->enabled = false; }If my review comments contain too little details for you to understand, please feel free to ask. I'm willing to explain in more detail. Best regards Uwe
Thanks for your review. Best Regards Jitao _______________________________________________ linux-arm-kernel mailing list linux-arm-kernel@lists.infradead.org http://lists.infradead.org/mailman/listinfo/linux-arm-kernel