[PATCH v4 0/3] fix the clock on/off mismatch and switch pwm api to atomic API
STALE1883d
9 messages,
2 authors,
2021-06-11 · open the first message on its own page
Change since v3:
- Seperate the clock sequence as single patch.
- fixup the reg commit when clocks sequence changed
- Merege the apply and get_state as single patch
Change since v2:
- Change commit messages to remove the clock operations for atomic APIs.
- Rebase to v5.13 rc1
Changes since v1:
- Seperate clock operation as single patch.
- Seperate apply() as single patch.
- Seperate get_state() operation as single patch.
Jitao Shi (3):
pwm: mtk-disp: adjust the clocks to avoid them mismatch
pwm: mtk-disp: move the commit to clock enabled
pwm: mtk-disp: Switch to atomic API
drivers/pwm/pwm-mtk-disp.c | 167 +++++++++++++++++++++----------------
1 file changed, 93 insertions(+), 74 deletions(-)
--
2.25.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
Due to the clock sequence changing, so move the reg commit to
config().
Signed-off-by: Jitao Shi <redacted>
---
drivers/pwm/pwm-mtk-disp.c | 20 +++++++-------------
1 file changed, 7 insertions(+), 13 deletions(-)
diff --git a/drivers/pwm/pwm-mtk-disp.c b/drivers/pwm/pwm-mtk-disp.c
index b5771e2c54b8..b87b3c00a685 100644
--- a/drivers/pwm/pwm-mtk-disp.c
+++ b/drivers/pwm/pwm-mtk-disp.c @@ -135,6 +135,13 @@ static int mtk_disp_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
mtk_disp_pwm_update_bits ( mdp , mdp -> data -> commit ,
mdp -> data -> commit_mask ,
0x0 );
+ } else {
+ mtk_disp_pwm_update_bits ( mdp , mdp -> data -> bls_debug ,
+ mdp -> data -> bls_debug_mask ,
+ mdp -> data -> bls_debug_mask );
+ mtk_disp_pwm_update_bits ( mdp , mdp -> data -> con0 ,
+ mdp -> data -> con0_sel ,
+ mdp -> data -> con0_sel );
}
return 0 ; @@ -208,19 +215,6 @@ static int mtk_disp_pwm_probe(struct platform_device *pdev)
platform_set_drvdata ( pdev , mdp );
- /*
- * For MT2701 , disable double buffer before writing register
- * and select manual mode and use PWM_PERIOD / PWM_HIGH_WIDTH .
- */
- if ( ! mdp -> data -> has_commit ) {
- mtk_disp_pwm_update_bits ( mdp , mdp -> data -> bls_debug ,
- mdp -> data -> bls_debug_mask ,
- mdp -> data -> bls_debug_mask );
- mtk_disp_pwm_update_bits ( mdp , mdp -> data -> con0 ,
- mdp -> data -> con0_sel ,
- mdp -> data -> con0_sel );
- }
-
return 0 ;
}
--
2.25.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
The clk_main and clk_mm clocks are still on when system enter
suspend. That will casue the power consumption.
The clocks call the clk_prepare() in probe(), but the clk_unprepare()
is called in remove(), it isn't called when system suspend.
Remove the clcok opterations from probe() and remove.
Add the clk_prepare_enable() in config().
Add the clk_disable_unprepare() in disable().
Signed-off-by: Jitao Shi <redacted>
---
drivers/pwm/pwm-mtk-disp.c | 81 ++++++++++++++++----------------------
1 file changed, 33 insertions(+), 48 deletions(-)
diff --git a/drivers/pwm/pwm-mtk-disp.c b/drivers/pwm/pwm-mtk-disp.c
index 9b3ba401a3db..b5771e2c54b8 100644
--- a/drivers/pwm/pwm-mtk-disp.c
+++ b/drivers/pwm/pwm-mtk-disp.c @@ -47,6 +47,7 @@ struct mtk_disp_pwm {
struct clk * clk_main ;
struct clk * clk_mm ;
void __iomem * base ;
+ bool enabled ;
};
static inline struct mtk_disp_pwm * to_mtk_disp_pwm ( struct pwm_chip * chip ) @@ -74,6 +75,22 @@ static int mtk_disp_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
u64 div , rate ;
int err ;
+ 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 ;
+ }
+ 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 err ;
+ }
+ }
+
/*
* Find period , high_width and clk_div to suit duty_ns and period_ns .
* Calculate proper div value to keep period value in the bound . @@ -87,9 +104,15 @@ static int mtk_disp_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
rate = clk_get_rate ( mdp -> clk_main );
clk_div = div_u64 ( rate * period_ns , NSEC_PER_SEC ) >>
PWM_PERIOD_BIT_WIDTH ;
- if ( clk_div > PWM_CLKDIV_MAX )
+ if ( clk_div > PWM_CLKDIV_MAX ) {
+ dev_err ( chip -> dev , "clock rate is too high: rate = %d Hz \n " ,
+ rate );
+ if ( ! mdp -> enabled ) {
+ clk_disable_unprepare ( mdp -> clk_mm );
+ clk_disable_unprepare ( mdp -> clk_main );
+ }
return - EINVAL ;
-
+ }
div = NSEC_PER_SEC * ( clk_div + 1 );
period = div64_u64 ( rate * period_ns , div );
if ( period > 0 ) @@ -98,16 +121,6 @@ static int mtk_disp_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
high_width = div64_u64 ( rate * duty_ns , div );
value = period | ( high_width << PWM_HIGH_WIDTH_SHIFT );
- err = clk_enable ( mdp -> clk_main );
- if ( err < 0 )
- return err ;
-
- err = clk_enable ( mdp -> clk_mm );
- if ( err < 0 ) {
- clk_disable ( mdp -> clk_main );
- return err ;
- }
-
mtk_disp_pwm_update_bits ( mdp , mdp -> data -> con0 ,
PWM_CLKDIV_MASK ,
clk_div << PWM_CLKDIV_SHIFT ); @@ -124,9 +137,6 @@ static int mtk_disp_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
0x0 );
}
- clk_disable ( mdp -> clk_mm );
- clk_disable ( mdp -> clk_main );
-
return 0 ;
}
@@ -135,18 +145,9 @@ static int mtk_disp_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
struct mtk_disp_pwm * mdp = to_mtk_disp_pwm ( chip );
int err ;
- err = clk_enable ( mdp -> clk_main );
- if ( err < 0 )
- return err ;
-
- err = clk_enable ( mdp -> clk_mm );
- if ( err < 0 ) {
- clk_disable ( mdp -> clk_main );
- return err ;
- }
-
mtk_disp_pwm_update_bits ( mdp , DISP_PWM_EN , mdp -> data -> enable_mask ,
mdp -> data -> enable_mask );
+ mdp -> enabled = true ;
return 0 ;
} @@ -158,8 +159,11 @@ static void mtk_disp_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
mtk_disp_pwm_update_bits ( mdp , DISP_PWM_EN , mdp -> data -> enable_mask ,
0x0 );
- clk_disable ( mdp -> clk_mm );
- clk_disable ( mdp -> clk_main );
+ if ( mdp -> enabled ) {
+ clk_disable_unprepare ( mdp -> clk_mm );
+ clk_disable_unprepare ( mdp -> clk_main );
+ }
+ mdp -> enabled = false ;
}
static const struct pwm_ops mtk_disp_pwm_ops = { @@ -192,14 +196,6 @@ static int mtk_disp_pwm_probe(struct platform_device *pdev)
if ( IS_ERR ( mdp -> clk_mm ))
return PTR_ERR ( mdp -> clk_mm );
- ret = clk_prepare ( mdp -> clk_main );
- if ( ret < 0 )
- return ret ;
-
- ret = clk_prepare ( mdp -> clk_mm );
- if ( ret < 0 )
- goto disable_clk_main ;
-
mdp -> chip . dev = & pdev -> dev ;
mdp -> chip . ops = & mtk_disp_pwm_ops ;
mdp -> chip . npwm = 1 ; @@ -207,7 +203,7 @@ static int mtk_disp_pwm_probe(struct platform_device *pdev)
ret = pwmchip_add ( & mdp -> chip );
if ( ret < 0 ) {
dev_err ( & pdev -> dev , "pwmchip_add() failed: %d \n " , ret );
- goto disable_clk_mm ;
+ return ret ;
}
platform_set_drvdata ( pdev , mdp ); @@ -226,24 +222,13 @@ static int mtk_disp_pwm_probe(struct platform_device *pdev)
}
return 0 ;
-
- disable_clk_mm :
- clk_unprepare ( mdp -> clk_mm );
- disable_clk_main :
- clk_unprepare ( mdp -> clk_main );
- return ret ;
}
static int mtk_disp_pwm_remove ( struct platform_device * pdev )
{
struct mtk_disp_pwm * mdp = platform_get_drvdata ( pdev );
- int ret ;
-
- ret = pwmchip_remove ( & mdp -> chip );
- clk_unprepare ( mdp -> clk_mm );
- clk_unprepare ( mdp -> clk_main );
- return ret ;
+ return pwmchip_remove ( & mdp -> chip );
}
static const struct mtk_pwm_data mt2701_pwm_data = { --
2.25.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
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 );
}
- 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 )
{
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 ;
+ period = con1 & PWM_PERIOD_MASK ;
+ state -> period = div_u64 ( period * ( clk_div + 1 ) * NSEC_PER_SEC , rate );
+ 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 ;
}
static const struct pwm_ops mtk_disp_pwm_ops = {
- . config = mtk_disp_pwm_config ,
- . enable = mtk_disp_pwm_enable ,
- . disable = mtk_disp_pwm_disable ,
+ . apply = mtk_disp_pwm_apply ,
+ . get_state = mtk_disp_pwm_get_state ,
. owner = THIS_MODULE ,
};
--
2.25.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
Hello,
you missed to address Lee and me for your patch series. I just happend
to stumble over this series by a fluke.
On Thu, Jun 03, 2021 at 06:05:29PM +0800, Jitao Shi wrote: The clk_main and clk_mm clocks are still on when system enter
suspend. That will casue the power consumption.
The clocks call the clk_prepare() in probe(), but the clk_unprepare()
is called in remove(), it isn't called when system suspend.
The English could be improved here. Something like:
The clks "main" and "mm" are prepared in .probe() (and
unprepared in .remove()). This results in the clocks being on
during suspend which results in unnecessarily increased power
consumption.
Remove the clcok opterations from probe() and remove.
s/clcok/clock/, s/e\./e()/
quoted hunk Add the clk_prepare_enable() in config().
Add the clk_disable_unprepare() in disable().
Signed-off-by: Jitao Shi <redacted>
---
drivers/pwm/pwm-mtk-disp.c | 81 ++++++++++++++++----------------------
1 file changed, 33 insertions(+), 48 deletions(-)
diff --git a/drivers/pwm/pwm-mtk-disp.c b/drivers/pwm/pwm-mtk-disp.c
index 9b3ba401a3db..b5771e2c54b8 100644
--- a/drivers/pwm/pwm-mtk-disp.c
+++ b/drivers/pwm/pwm-mtk-disp.c @@ -47,6 +47,7 @@ struct mtk_disp_pwm {
struct clk * clk_main ;
struct clk * clk_mm ;
void __iomem * base ;
+ bool enabled ;
};
static inline struct mtk_disp_pwm * to_mtk_disp_pwm ( struct pwm_chip * chip ) @@ -74,6 +75,22 @@ static int mtk_disp_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
u64 div , rate ;
int err ;
+ 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 ;
Please use %pe to get symbolic error names which are better
understandable.
quoted hunk + }
+ 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 err;
+ }
+ }
+
/*
* Find period, high_width and clk_div to suit duty_ns and period_ns.
* Calculate proper div value to keep period value in the bound. @@ -87,9 +104,15 @@ static int mtk_disp_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
rate = clk_get_rate(mdp->clk_main);
clk_div = div_u64(rate * period_ns, NSEC_PER_SEC) >>
PWM_PERIOD_BIT_WIDTH;
- if (clk_div > PWM_CLKDIV_MAX)
+ if (clk_div > PWM_CLKDIV_MAX) {
+ dev_err(chip->dev, "clock rate is too high: rate = %d Hz\n",
+ rate);
Adding an error message here is orthogonal to this patch. Either drop it
or mention it in the commit log please.
quoted hunk + if (!mdp->enabled) {
+ clk_disable_unprepare(mdp->clk_mm);
+ clk_disable_unprepare(mdp->clk_main);
+ }
return -EINVAL;
-
+ }
div = NSEC_PER_SEC * (clk_div + 1);
period = div64_u64(rate * period_ns, div);
if (period > 0)
[...] @@ -135,18 +145,9 @@ static int mtk_disp_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
struct mtk_disp_pwm *mdp = to_mtk_disp_pwm(chip);
int err;
- err = clk_enable(mdp->clk_main);
- if (err < 0)
- return err;
-
- err = clk_enable(mdp->clk_mm);
- if (err < 0) {
- clk_disable(mdp->clk_main);
- return err;
- }
-
mtk_disp_pwm_update_bits(mdp, DISP_PWM_EN, mdp->data->enable_mask,
mdp->data->enable_mask);
+ mdp->enabled = true;
The modification to .enable() looks wrong. After the PWM was disabled
the clocks are off, so .enable() must reenable them, doesn't it?
return 0;
}
Best regards
Uwe
--
Pengutronix e.K. | Uwe Kleine-König |
Industrial Linux Solutions | https://www.pengutronix.de/ |
On Thu, Jun 03, 2021 at 06:05:30PM +0800, Jitao Shi wrote: Due to the clock sequence changing, so move the reg commit to
Which change do you refer to, here? The previous patch? If so, I assume
this means the series is not bisectable because the driver is broken
when only the first patch is applied?
quoted hunk config().
Signed-off-by: Jitao Shi <redacted>
---
drivers/pwm/pwm-mtk-disp.c | 20 +++++++-------------
1 file changed, 7 insertions(+), 13 deletions(-)
diff --git a/drivers/pwm/pwm-mtk-disp.c b/drivers/pwm/pwm-mtk-disp.c
index b5771e2c54b8..b87b3c00a685 100644
--- a/drivers/pwm/pwm-mtk-disp.c
+++ b/drivers/pwm/pwm-mtk-disp.c @@ -135,6 +135,13 @@ static int mtk_disp_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
mtk_disp_pwm_update_bits ( mdp , mdp -> data -> commit ,
mdp -> data -> commit_mask ,
0x0 );
+ } else {
You dropped the code comment? Is it wrong? Or is it too obvious to be
mentioned?
quoted hunk + mtk_disp_pwm_update_bits(mdp, mdp->data->bls_debug,
+ mdp->data->bls_debug_mask,
+ mdp->data->bls_debug_mask);
+ mtk_disp_pwm_update_bits(mdp, mdp->data->con0,
+ mdp->data->con0_sel,
+ mdp->data->con0_sel);
}
return 0; @@ -208,19 +215,6 @@ static int mtk_disp_pwm_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, mdp);
- /*
- * For MT2701, disable double buffer before writing register
- * and select manual mode and use PWM_PERIOD/PWM_HIGH_WIDTH.
- */
- if (!mdp->data->has_commit) {
- mtk_disp_pwm_update_bits(mdp, mdp->data->bls_debug,
- mdp->data->bls_debug_mask,
- mdp->data->bls_debug_mask);
- mtk_disp_pwm_update_bits(mdp, mdp->data->con0,
- mdp->data->con0_sel,
- mdp->data->con0_sel);
- }
-
return 0;
}
Best regards
Uwe
--
Pengutronix e.K. | Uwe Kleine-König |
Industrial Linux Solutions | https://www.pengutronix.de/ |
Hello,
On Thu, Jun 03, 2021 at 06:05:31PM +0800, Jitao Shi wrote: quoted hunk 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.
}
-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.
{
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);
+ 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().
+ 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
--
Pengutronix e.K. | Uwe Kleine-König |
Industrial Linux Solutions | https://www.pengutronix.de/ |
On Sun, 2021-06-06 at 23:14 +0200, Uwe Kleine-König wrote: On Thu, Jun 03, 2021 at 06:05:30PM +0800, Jitao Shi wrote: quoted Due to the clock sequence changing, so move the reg commit to
Which change do you refer to, here? The previous patch? If so, I assume
this means the series is not bisectable because the driver is broken
when only the first patch is applied? Yes, this patch is depend the previous patch.
I'll squash it to the previous patch in next version.
quoted config().
Signed-off-by: Jitao Shi <redacted>
---
drivers/pwm/pwm-mtk-disp.c | 20 +++++++-------------
1 file changed, 7 insertions(+), 13 deletions(-)
diff --git a/drivers/pwm/pwm-mtk-disp.c b/drivers/pwm/pwm-mtk-disp.c
index b5771e2c54b8..b87b3c00a685 100644
--- a/drivers/pwm/pwm-mtk-disp.c
+++ b/drivers/pwm/pwm-mtk-disp.c @@ -135,6 +135,13 @@ static int mtk_disp_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
mtk_disp_pwm_update_bits ( mdp , mdp -> data -> commit ,
mdp -> data -> commit_mask ,
0x0 );
+ } else {
You dropped the code comment? Is it wrong? Or is it too obvious to be
mentioned?
I'll fix them next verison.
quoted + mtk_disp_pwm_update_bits(mdp, mdp->data->bls_debug,
+ mdp->data->bls_debug_mask,
+ mdp->data->bls_debug_mask);
+ mtk_disp_pwm_update_bits(mdp, mdp->data->con0,
+ mdp->data->con0_sel,
+ mdp->data->con0_sel);
}
return 0; @@ -208,19 +215,6 @@ static int mtk_disp_pwm_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, mdp);
- /*
- * For MT2701, disable double buffer before writing register
- * and select manual mode and use PWM_PERIOD/PWM_HIGH_WIDTH.
- */
- if (!mdp->data->has_commit) {
- mtk_disp_pwm_update_bits(mdp, mdp->data->bls_debug,
- mdp->data->bls_debug_mask,
- mdp->data->bls_debug_mask);
- mtk_disp_pwm_update_bits(mdp, mdp->data->con0,
- mdp->data->con0_sel,
- mdp->data->con0_sel);
- }
-
return 0;
}
Best regards
Uwe
Best Regards
Jitao
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
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