Skip to content

Commit

Permalink
pwm: pwm-tiehrpwm: Fix conflicting channel period setting
Browse files Browse the repository at this point in the history
EHRPWM hardware supports 2 independent PWM channels. However the device
uses only one register to handle period setting for both channels. So
both channels should be configured for same period (in nsec).

Fix the same by returning error for conflicting period values.

However, allow
1. Configuration of period settings if not conflicting with other
channels
2. Re-configuring of period settings if no other channels being
configured

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 Sep 10, 2012
1 parent c06fad9 commit 01b2d45
Showing 1 changed file with 29 additions and 0 deletions.
29 changes: 29 additions & 0 deletions drivers/pwm/pwm-tiehrpwm.c
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ struct ehrpwm_pwm_chip {
struct pwm_chip chip;
unsigned int clk_rate;
void __iomem *mmio_base;
unsigned long period_cycles[NUM_PWM_CHANNEL];
};

static inline struct ehrpwm_pwm_chip *to_ehrpwm_pwm_chip(struct pwm_chip *chip)
Expand Down Expand Up @@ -210,6 +211,7 @@ static int ehrpwm_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
unsigned long long c;
unsigned long period_cycles, duty_cycles;
unsigned short ps_divval, tb_divval;
int i;

if (period_ns < 0 || duty_ns < 0 || period_ns > NSEC_PER_SEC)
return -ERANGE;
Expand All @@ -229,6 +231,28 @@ static int ehrpwm_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
duty_cycles = (unsigned long)c;
}

/*
* Period values should be same for multiple PWM channels as IP uses
* same period register for multiple channels.
*/
for (i = 0; i < NUM_PWM_CHANNEL; i++) {
if (pc->period_cycles[i] &&
(pc->period_cycles[i] != period_cycles)) {
/*
* Allow channel to reconfigure period if no other
* channels being configured.
*/
if (i == pwm->hwpwm)
continue;

dev_err(chip->dev, "Period value conflicts with channel %d\n",
i);
return -EINVAL;
}
}

pc->period_cycles[pwm->hwpwm] = period_cycles;

/* Configure clock prescaler to support Low frequency PWM wave */
if (set_prescale_div(period_cycles/PERIOD_MAX, &ps_divval,
&tb_divval)) {
Expand Down Expand Up @@ -320,10 +344,15 @@ static void ehrpwm_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)

static void ehrpwm_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm)
{
struct ehrpwm_pwm_chip *pc = to_ehrpwm_pwm_chip(chip);

if (test_bit(PWMF_ENABLED, &pwm->flags)) {
dev_warn(chip->dev, "Removing PWM device without disabling\n");
pm_runtime_put_sync(chip->dev);
}

/* set period value to zero on free */
pc->period_cycles[pwm->hwpwm] = 0;
}

static const struct pwm_ops ehrpwm_pwm_ops = {
Expand Down

0 comments on commit 01b2d45

Please sign in to comment.