Commit 01b2d453 authored by Philip, Avinash's avatar Philip, Avinash Committed by Thierry Reding

pwm: pwm-tiehrpwm: Fix conflicting channel period setting

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: default avatarPhilip, Avinash <avinashphilip@ti.com>
Signed-off-by: default avatarThierry Reding <thierry.reding@avionic-design.de>
parent c06fad9d
...@@ -104,6 +104,7 @@ struct ehrpwm_pwm_chip { ...@@ -104,6 +104,7 @@ struct ehrpwm_pwm_chip {
struct pwm_chip chip; struct pwm_chip chip;
unsigned int clk_rate; unsigned int clk_rate;
void __iomem *mmio_base; 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) static inline struct ehrpwm_pwm_chip *to_ehrpwm_pwm_chip(struct pwm_chip *chip)
...@@ -210,6 +211,7 @@ static int ehrpwm_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, ...@@ -210,6 +211,7 @@ static int ehrpwm_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
unsigned long long c; unsigned long long c;
unsigned long period_cycles, duty_cycles; unsigned long period_cycles, duty_cycles;
unsigned short ps_divval, tb_divval; unsigned short ps_divval, tb_divval;
int i;
if (period_ns < 0 || duty_ns < 0 || period_ns > NSEC_PER_SEC) if (period_ns < 0 || duty_ns < 0 || period_ns > NSEC_PER_SEC)
return -ERANGE; return -ERANGE;
...@@ -229,6 +231,28 @@ static int ehrpwm_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, ...@@ -229,6 +231,28 @@ static int ehrpwm_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
duty_cycles = (unsigned long)c; 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 */ /* Configure clock prescaler to support Low frequency PWM wave */
if (set_prescale_div(period_cycles/PERIOD_MAX, &ps_divval, if (set_prescale_div(period_cycles/PERIOD_MAX, &ps_divval,
&tb_divval)) { &tb_divval)) {
...@@ -320,10 +344,15 @@ static void ehrpwm_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm) ...@@ -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) 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)) { if (test_bit(PWMF_ENABLED, &pwm->flags)) {
dev_warn(chip->dev, "Removing PWM device without disabling\n"); dev_warn(chip->dev, "Removing PWM device without disabling\n");
pm_runtime_put_sync(chip->dev); 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 = { static const struct pwm_ops ehrpwm_pwm_ops = {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment