Skip to content

Commit

Permalink
pwm: pwm-tiehrpwm: Low power sleep support
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Philip Avinash authored and Thierry Reding committed Jan 17, 2013
1 parent 0074b49 commit 0e2feb1
Showing 1 changed file with 83 additions and 0 deletions.
83 changes: 83 additions & 0 deletions drivers/pwm/pwm-tiehrpwm.c
Original file line number Diff line number Diff line change
Expand Up @@ -113,20 +113,37 @@

#define NUM_PWM_CHANNEL 2 /* EHRPWM channels */

struct ehrpwm_context {
u16 tbctl;
u16 tbprd;
u16 cmpa;
u16 cmpb;
u16 aqctla;
u16 aqctlb;
u16 aqsfrc;
u16 aqcsfrc;
};

struct ehrpwm_pwm_chip {
struct pwm_chip chip;
unsigned int clk_rate;
void __iomem *mmio_base;
unsigned long period_cycles[NUM_PWM_CHANNEL];
enum pwm_polarity polarity[NUM_PWM_CHANNEL];
struct clk *tbclk;
struct ehrpwm_context ctx;
};

static inline struct ehrpwm_pwm_chip *to_ehrpwm_pwm_chip(struct pwm_chip *chip)
{
return container_of(chip, struct ehrpwm_pwm_chip, chip);
}

static u16 ehrpwm_read(void *base, int offset)
{
return readw(base + offset);
}

static void ehrpwm_write(void *base, int offset, unsigned int val)
{
writew(val & 0xFFFF, base + offset);
Expand Down Expand Up @@ -516,11 +533,77 @@ static int ehrpwm_pwm_remove(struct platform_device *pdev)
return pwmchip_remove(&pc->chip);
}

void ehrpwm_pwm_save_context(struct ehrpwm_pwm_chip *pc)
{
pm_runtime_get_sync(pc->chip.dev);
pc->ctx.tbctl = ehrpwm_read(pc->mmio_base, TBCTL);
pc->ctx.tbprd = ehrpwm_read(pc->mmio_base, TBPRD);
pc->ctx.cmpa = ehrpwm_read(pc->mmio_base, CMPA);
pc->ctx.cmpb = ehrpwm_read(pc->mmio_base, CMPB);
pc->ctx.aqctla = ehrpwm_read(pc->mmio_base, AQCTLA);
pc->ctx.aqctlb = ehrpwm_read(pc->mmio_base, AQCTLB);
pc->ctx.aqsfrc = ehrpwm_read(pc->mmio_base, AQSFRC);
pc->ctx.aqcsfrc = ehrpwm_read(pc->mmio_base, AQCSFRC);
pm_runtime_put_sync(pc->chip.dev);
}

void ehrpwm_pwm_restore_context(struct ehrpwm_pwm_chip *pc)
{
ehrpwm_write(pc->mmio_base, TBPRD, pc->ctx.tbprd);
ehrpwm_write(pc->mmio_base, CMPA, pc->ctx.cmpa);
ehrpwm_write(pc->mmio_base, CMPB, pc->ctx.cmpb);
ehrpwm_write(pc->mmio_base, AQCTLA, pc->ctx.aqctla);
ehrpwm_write(pc->mmio_base, AQCTLB, pc->ctx.aqctlb);
ehrpwm_write(pc->mmio_base, AQSFRC, pc->ctx.aqsfrc);
ehrpwm_write(pc->mmio_base, AQCSFRC, pc->ctx.aqcsfrc);
ehrpwm_write(pc->mmio_base, TBCTL, pc->ctx.tbctl);
}

static int ehrpwm_pwm_suspend(struct device *dev)
{
struct ehrpwm_pwm_chip *pc = dev_get_drvdata(dev);
int i;

ehrpwm_pwm_save_context(pc);
for (i = 0; i < pc->chip.npwm; i++) {
struct pwm_device *pwm = &pc->chip.pwms[i];

if (!test_bit(PWMF_ENABLED, &pwm->flags))
continue;

/* Disable explicitly if PWM is running */
pm_runtime_put_sync(dev);
}
return 0;
}

static int ehrpwm_pwm_resume(struct device *dev)
{
struct ehrpwm_pwm_chip *pc = dev_get_drvdata(dev);
int i;

for (i = 0; i < pc->chip.npwm; i++) {
struct pwm_device *pwm = &pc->chip.pwms[i];

if (!test_bit(PWMF_ENABLED, &pwm->flags))
continue;

/* Enable explicitly if PWM was running */
pm_runtime_get_sync(dev);
}
ehrpwm_pwm_restore_context(pc);
return 0;
}

static SIMPLE_DEV_PM_OPS(ehrpwm_pwm_pm_ops, ehrpwm_pwm_suspend,
ehrpwm_pwm_resume);

static struct platform_driver ehrpwm_pwm_driver = {
.driver = {
.name = "ehrpwm",
.owner = THIS_MODULE,
.of_match_table = ehrpwm_of_match,
.pm = &ehrpwm_pwm_pm_ops,
},
.probe = ehrpwm_pwm_probe,
.remove = ehrpwm_pwm_remove,
Expand Down

0 comments on commit 0e2feb1

Please sign in to comment.