aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStefan Agner <stefan@agner.ch>2015-11-23 17:45:07 -0500
committerThierry Reding <thierry.reding@gmail.com>2015-12-16 10:54:32 -0500
commit816aec2325e620b6454474372a21f90a8740cb28 (patch)
tree6db9059a4e4673662a15aaebc67b4791b6ccb42d
parent37670676a122a38e72ecd9dac0feff2a3dac967f (diff)
pwm: fsl-ftm: Fix clock enable/disable when using PM
A FTM PWM instance enables/disables three clocks: The bus clock, the counter clock and the PWM clock. The bus clock gets enabled on pwm_request, whereas the counter and PWM clocks will be enabled upon pwm_enable. The driver has three closesly related issues when enabling/disabling clocks during suspend/resume: - The three clocks are not treated differently in regards to the individual PWM state enabled/requested. This can lead to clocks getting disabled which have not been enabled in the first place (a PWM channel which only has been requested going through suspend/resume). - When entering suspend, the current behavior relies on the FTM_OUTMASK register: If a PWM output is unmasked, the driver assumes the clocks are enabled. However, some PWM instances have only 2 channels connected (e.g. Vybrid's FTM1). In that case, the FTM_OUTMASK reads 0x3 if all channels are disabled, even if the code wrote 0xff to it before. For those PWM instances, the current approach to detect enabled PWM signals does not work. - A third issue applies to the bus clock only, which can get enabled multiple times (once for each PWM channel of a PWM chip). This is fine, however when entering suspend mode, the clock only gets disabled once. This change introduces a different approach by relying on the enable and prepared counters of the clock framework and using the frameworks PWM signal states to address all three issues. Clocks get disabled during suspend and back enabled on resume regarding to the PWM channels individual state (requested/enabled). Since we do not count the clock enables in the driver, this change no longer clears the Status and Control registers Clock Source Selection (FTM_SC[CLKS]). However, since we disable the selected clock anyway, and we explicitly select the clock source on reenabling a PWM channel this approach should not make a difference in practice. Signed-off-by: Stefan Agner <stefan@agner.ch> Signed-off-by: Thierry Reding <thierry.reding@gmail.com>
-rw-r--r--drivers/pwm/pwm-fsl-ftm.c58
1 files changed, 25 insertions, 33 deletions
diff --git a/drivers/pwm/pwm-fsl-ftm.c b/drivers/pwm/pwm-fsl-ftm.c
index f9dfc8b6407a..7225ac6b3df5 100644
--- a/drivers/pwm/pwm-fsl-ftm.c
+++ b/drivers/pwm/pwm-fsl-ftm.c
@@ -80,7 +80,6 @@ struct fsl_pwm_chip {
80 80
81 struct mutex lock; 81 struct mutex lock;
82 82
83 unsigned int use_count;
84 unsigned int cnt_select; 83 unsigned int cnt_select;
85 unsigned int clk_ps; 84 unsigned int clk_ps;
86 85
@@ -300,9 +299,6 @@ static int fsl_counter_clock_enable(struct fsl_pwm_chip *fpc)
300{ 299{
301 int ret; 300 int ret;
302 301
303 if (fpc->use_count++ != 0)
304 return 0;
305
306 /* select counter clock source */ 302 /* select counter clock source */
307 regmap_update_bits(fpc->regmap, FTM_SC, FTM_SC_CLK_MASK, 303 regmap_update_bits(fpc->regmap, FTM_SC, FTM_SC_CLK_MASK,
308 FTM_SC_CLK(fpc->cnt_select)); 304 FTM_SC_CLK(fpc->cnt_select));
@@ -334,25 +330,6 @@ static int fsl_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
334 return ret; 330 return ret;
335} 331}
336 332
337static void fsl_counter_clock_disable(struct fsl_pwm_chip *fpc)
338{
339 /*
340 * already disabled, do nothing
341 */
342 if (fpc->use_count == 0)
343 return;
344
345 /* there are still users, so can't disable yet */
346 if (--fpc->use_count > 0)
347 return;
348
349 /* no users left, disable PWM counter clock */
350 regmap_update_bits(fpc->regmap, FTM_SC, FTM_SC_CLK_MASK, 0);
351
352 clk_disable_unprepare(fpc->clk[FSL_PWM_CLK_CNTEN]);
353 clk_disable_unprepare(fpc->clk[fpc->cnt_select]);
354}
355
356static void fsl_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm) 333static void fsl_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
357{ 334{
358 struct fsl_pwm_chip *fpc = to_fsl_chip(chip); 335 struct fsl_pwm_chip *fpc = to_fsl_chip(chip);
@@ -362,7 +339,8 @@ static void fsl_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
362 regmap_update_bits(fpc->regmap, FTM_OUTMASK, BIT(pwm->hwpwm), 339 regmap_update_bits(fpc->regmap, FTM_OUTMASK, BIT(pwm->hwpwm),
363 BIT(pwm->hwpwm)); 340 BIT(pwm->hwpwm));
364 341
365 fsl_counter_clock_disable(fpc); 342 clk_disable_unprepare(fpc->clk[FSL_PWM_CLK_CNTEN]);
343 clk_disable_unprepare(fpc->clk[fpc->cnt_select]);
366 344
367 regmap_read(fpc->regmap, FTM_OUTMASK, &val); 345 regmap_read(fpc->regmap, FTM_OUTMASK, &val);
368 if ((val & 0xFF) == 0xFF) 346 if ((val & 0xFF) == 0xFF)
@@ -492,17 +470,24 @@ static int fsl_pwm_remove(struct platform_device *pdev)
492static int fsl_pwm_suspend(struct device *dev) 470static int fsl_pwm_suspend(struct device *dev)
493{ 471{
494 struct fsl_pwm_chip *fpc = dev_get_drvdata(dev); 472 struct fsl_pwm_chip *fpc = dev_get_drvdata(dev);
495 u32 val; 473 int i;
496 474
497 regcache_cache_only(fpc->regmap, true); 475 regcache_cache_only(fpc->regmap, true);
498 regcache_mark_dirty(fpc->regmap); 476 regcache_mark_dirty(fpc->regmap);
499 477
500 /* read from cache */ 478 for (i = 0; i < fpc->chip.npwm; i++) {
501 regmap_read(fpc->regmap, FTM_OUTMASK, &val); 479 struct pwm_device *pwm = &fpc->chip.pwms[i];
502 if ((val & 0xFF) != 0xFF) { 480
481 if (!test_bit(PWMF_REQUESTED, &pwm->flags))
482 continue;
483
484 clk_disable_unprepare(fpc->clk[FSL_PWM_CLK_SYS]);
485
486 if (!pwm_is_enabled(pwm))
487 continue;
488
503 clk_disable_unprepare(fpc->clk[FSL_PWM_CLK_CNTEN]); 489 clk_disable_unprepare(fpc->clk[FSL_PWM_CLK_CNTEN]);
504 clk_disable_unprepare(fpc->clk[fpc->cnt_select]); 490 clk_disable_unprepare(fpc->clk[fpc->cnt_select]);
505 clk_disable_unprepare(fpc->clk[FSL_PWM_CLK_SYS]);
506 } 491 }
507 492
508 return 0; 493 return 0;
@@ -511,12 +496,19 @@ static int fsl_pwm_suspend(struct device *dev)
511static int fsl_pwm_resume(struct device *dev) 496static int fsl_pwm_resume(struct device *dev)
512{ 497{
513 struct fsl_pwm_chip *fpc = dev_get_drvdata(dev); 498 struct fsl_pwm_chip *fpc = dev_get_drvdata(dev);
514 u32 val; 499 int i;
500
501 for (i = 0; i < fpc->chip.npwm; i++) {
502 struct pwm_device *pwm = &fpc->chip.pwms[i];
503
504 if (!test_bit(PWMF_REQUESTED, &pwm->flags))
505 continue;
515 506
516 /* read from cache */
517 regmap_read(fpc->regmap, FTM_OUTMASK, &val);
518 if ((val & 0xFF) != 0xFF) {
519 clk_prepare_enable(fpc->clk[FSL_PWM_CLK_SYS]); 507 clk_prepare_enable(fpc->clk[FSL_PWM_CLK_SYS]);
508
509 if (!pwm_is_enabled(pwm))
510 continue;
511
520 clk_prepare_enable(fpc->clk[fpc->cnt_select]); 512 clk_prepare_enable(fpc->clk[fpc->cnt_select]);
521 clk_prepare_enable(fpc->clk[FSL_PWM_CLK_CNTEN]); 513 clk_prepare_enable(fpc->clk[FSL_PWM_CLK_CNTEN]);
522 } 514 }