diff options
author | Philip Avinash <avinashphilip@ti.com> | 2013-01-17 04:20:02 -0500 |
---|---|---|
committer | Thierry Reding <thierry.reding@avionic-design.de> | 2013-01-17 10:52:58 -0500 |
commit | 0e2feb17dec9d97f6b44d5af872633f7ffba9ffb (patch) | |
tree | 65288a11f9cedc298d87adf7b36d64da5062b77f /drivers/pwm | |
parent | 0074b49b3fa0886047413dbca0508594b1d80c61 (diff) |
pwm: pwm-tiehrpwm: Low power sleep support
In low power modes of AM33XX platforms, peripherals power is cut off.
This patch supports low power sleep transition support for EHRPWM
driver.
Signed-off-by: Philip Avinash <avinashphilip@ti.com>
Signed-off-by: Thierry Reding <thierry.reding@avionic-design.de>
Diffstat (limited to 'drivers/pwm')
-rw-r--r-- | drivers/pwm/pwm-tiehrpwm.c | 83 |
1 files changed, 83 insertions, 0 deletions
diff --git a/drivers/pwm/pwm-tiehrpwm.c b/drivers/pwm/pwm-tiehrpwm.c index 4fcafbfba60e..33e15c4fba02 100644 --- a/drivers/pwm/pwm-tiehrpwm.c +++ b/drivers/pwm/pwm-tiehrpwm.c | |||
@@ -113,6 +113,17 @@ | |||
113 | 113 | ||
114 | #define NUM_PWM_CHANNEL 2 /* EHRPWM channels */ | 114 | #define NUM_PWM_CHANNEL 2 /* EHRPWM channels */ |
115 | 115 | ||
116 | struct ehrpwm_context { | ||
117 | u16 tbctl; | ||
118 | u16 tbprd; | ||
119 | u16 cmpa; | ||
120 | u16 cmpb; | ||
121 | u16 aqctla; | ||
122 | u16 aqctlb; | ||
123 | u16 aqsfrc; | ||
124 | u16 aqcsfrc; | ||
125 | }; | ||
126 | |||
116 | struct ehrpwm_pwm_chip { | 127 | struct ehrpwm_pwm_chip { |
117 | struct pwm_chip chip; | 128 | struct pwm_chip chip; |
118 | unsigned int clk_rate; | 129 | unsigned int clk_rate; |
@@ -120,6 +131,7 @@ struct ehrpwm_pwm_chip { | |||
120 | unsigned long period_cycles[NUM_PWM_CHANNEL]; | 131 | unsigned long period_cycles[NUM_PWM_CHANNEL]; |
121 | enum pwm_polarity polarity[NUM_PWM_CHANNEL]; | 132 | enum pwm_polarity polarity[NUM_PWM_CHANNEL]; |
122 | struct clk *tbclk; | 133 | struct clk *tbclk; |
134 | struct ehrpwm_context ctx; | ||
123 | }; | 135 | }; |
124 | 136 | ||
125 | static inline struct ehrpwm_pwm_chip *to_ehrpwm_pwm_chip(struct pwm_chip *chip) | 137 | static inline struct ehrpwm_pwm_chip *to_ehrpwm_pwm_chip(struct pwm_chip *chip) |
@@ -127,6 +139,11 @@ static inline struct ehrpwm_pwm_chip *to_ehrpwm_pwm_chip(struct pwm_chip *chip) | |||
127 | return container_of(chip, struct ehrpwm_pwm_chip, chip); | 139 | return container_of(chip, struct ehrpwm_pwm_chip, chip); |
128 | } | 140 | } |
129 | 141 | ||
142 | static u16 ehrpwm_read(void *base, int offset) | ||
143 | { | ||
144 | return readw(base + offset); | ||
145 | } | ||
146 | |||
130 | static void ehrpwm_write(void *base, int offset, unsigned int val) | 147 | static void ehrpwm_write(void *base, int offset, unsigned int val) |
131 | { | 148 | { |
132 | writew(val & 0xFFFF, base + offset); | 149 | writew(val & 0xFFFF, base + offset); |
@@ -516,11 +533,77 @@ static int ehrpwm_pwm_remove(struct platform_device *pdev) | |||
516 | return pwmchip_remove(&pc->chip); | 533 | return pwmchip_remove(&pc->chip); |
517 | } | 534 | } |
518 | 535 | ||
536 | void ehrpwm_pwm_save_context(struct ehrpwm_pwm_chip *pc) | ||
537 | { | ||
538 | pm_runtime_get_sync(pc->chip.dev); | ||
539 | pc->ctx.tbctl = ehrpwm_read(pc->mmio_base, TBCTL); | ||
540 | pc->ctx.tbprd = ehrpwm_read(pc->mmio_base, TBPRD); | ||
541 | pc->ctx.cmpa = ehrpwm_read(pc->mmio_base, CMPA); | ||
542 | pc->ctx.cmpb = ehrpwm_read(pc->mmio_base, CMPB); | ||
543 | pc->ctx.aqctla = ehrpwm_read(pc->mmio_base, AQCTLA); | ||
544 | pc->ctx.aqctlb = ehrpwm_read(pc->mmio_base, AQCTLB); | ||
545 | pc->ctx.aqsfrc = ehrpwm_read(pc->mmio_base, AQSFRC); | ||
546 | pc->ctx.aqcsfrc = ehrpwm_read(pc->mmio_base, AQCSFRC); | ||
547 | pm_runtime_put_sync(pc->chip.dev); | ||
548 | } | ||
549 | |||
550 | void ehrpwm_pwm_restore_context(struct ehrpwm_pwm_chip *pc) | ||
551 | { | ||
552 | ehrpwm_write(pc->mmio_base, TBPRD, pc->ctx.tbprd); | ||
553 | ehrpwm_write(pc->mmio_base, CMPA, pc->ctx.cmpa); | ||
554 | ehrpwm_write(pc->mmio_base, CMPB, pc->ctx.cmpb); | ||
555 | ehrpwm_write(pc->mmio_base, AQCTLA, pc->ctx.aqctla); | ||
556 | ehrpwm_write(pc->mmio_base, AQCTLB, pc->ctx.aqctlb); | ||
557 | ehrpwm_write(pc->mmio_base, AQSFRC, pc->ctx.aqsfrc); | ||
558 | ehrpwm_write(pc->mmio_base, AQCSFRC, pc->ctx.aqcsfrc); | ||
559 | ehrpwm_write(pc->mmio_base, TBCTL, pc->ctx.tbctl); | ||
560 | } | ||
561 | |||
562 | static int ehrpwm_pwm_suspend(struct device *dev) | ||
563 | { | ||
564 | struct ehrpwm_pwm_chip *pc = dev_get_drvdata(dev); | ||
565 | int i; | ||
566 | |||
567 | ehrpwm_pwm_save_context(pc); | ||
568 | for (i = 0; i < pc->chip.npwm; i++) { | ||
569 | struct pwm_device *pwm = &pc->chip.pwms[i]; | ||
570 | |||
571 | if (!test_bit(PWMF_ENABLED, &pwm->flags)) | ||
572 | continue; | ||
573 | |||
574 | /* Disable explicitly if PWM is running */ | ||
575 | pm_runtime_put_sync(dev); | ||
576 | } | ||
577 | return 0; | ||
578 | } | ||
579 | |||
580 | static int ehrpwm_pwm_resume(struct device *dev) | ||
581 | { | ||
582 | struct ehrpwm_pwm_chip *pc = dev_get_drvdata(dev); | ||
583 | int i; | ||
584 | |||
585 | for (i = 0; i < pc->chip.npwm; i++) { | ||
586 | struct pwm_device *pwm = &pc->chip.pwms[i]; | ||
587 | |||
588 | if (!test_bit(PWMF_ENABLED, &pwm->flags)) | ||
589 | continue; | ||
590 | |||
591 | /* Enable explicitly if PWM was running */ | ||
592 | pm_runtime_get_sync(dev); | ||
593 | } | ||
594 | ehrpwm_pwm_restore_context(pc); | ||
595 | return 0; | ||
596 | } | ||
597 | |||
598 | static SIMPLE_DEV_PM_OPS(ehrpwm_pwm_pm_ops, ehrpwm_pwm_suspend, | ||
599 | ehrpwm_pwm_resume); | ||
600 | |||
519 | static struct platform_driver ehrpwm_pwm_driver = { | 601 | static struct platform_driver ehrpwm_pwm_driver = { |
520 | .driver = { | 602 | .driver = { |
521 | .name = "ehrpwm", | 603 | .name = "ehrpwm", |
522 | .owner = THIS_MODULE, | 604 | .owner = THIS_MODULE, |
523 | .of_match_table = ehrpwm_of_match, | 605 | .of_match_table = ehrpwm_of_match, |
606 | .pm = &ehrpwm_pwm_pm_ops, | ||
524 | }, | 607 | }, |
525 | .probe = ehrpwm_pwm_probe, | 608 | .probe = ehrpwm_pwm_probe, |
526 | .remove = ehrpwm_pwm_remove, | 609 | .remove = ehrpwm_pwm_remove, |