aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPhilip, Avinash <avinashphilip@ti.com>2012-09-06 01:14:25 -0400
committerThierry Reding <thierry.reding@avionic-design.de>2012-09-10 11:04:38 -0400
commit01b2d4536f0215c6d97d77e157afee04300ffc90 (patch)
treef0cf06b9c3aaa834a578e0eeda01e72ba51c2653
parentc06fad9d28c95b024ea10455cf1397432b12848d (diff)
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: Philip, Avinash <avinashphilip@ti.com> Signed-off-by: Thierry Reding <thierry.reding@avionic-design.de>
-rw-r--r--drivers/pwm/pwm-tiehrpwm.c29
1 files changed, 29 insertions, 0 deletions
diff --git a/drivers/pwm/pwm-tiehrpwm.c b/drivers/pwm/pwm-tiehrpwm.c
index c3756d1be194..b1996bcd5b78 100644
--- a/drivers/pwm/pwm-tiehrpwm.c
+++ b/drivers/pwm/pwm-tiehrpwm.c
@@ -104,6 +104,7 @@ struct ehrpwm_pwm_chip {
104 struct pwm_chip chip; 104 struct pwm_chip chip;
105 unsigned int clk_rate; 105 unsigned int clk_rate;
106 void __iomem *mmio_base; 106 void __iomem *mmio_base;
107 unsigned long period_cycles[NUM_PWM_CHANNEL];
107}; 108};
108 109
109static inline struct ehrpwm_pwm_chip *to_ehrpwm_pwm_chip(struct pwm_chip *chip) 110static 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 unsigned long long c; 211 unsigned long long c;
211 unsigned long period_cycles, duty_cycles; 212 unsigned long period_cycles, duty_cycles;
212 unsigned short ps_divval, tb_divval; 213 unsigned short ps_divval, tb_divval;
214 int i;
213 215
214 if (period_ns < 0 || duty_ns < 0 || period_ns > NSEC_PER_SEC) 216 if (period_ns < 0 || duty_ns < 0 || period_ns > NSEC_PER_SEC)
215 return -ERANGE; 217 return -ERANGE;
@@ -229,6 +231,28 @@ static int ehrpwm_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
229 duty_cycles = (unsigned long)c; 231 duty_cycles = (unsigned long)c;
230 } 232 }
231 233
234 /*
235 * Period values should be same for multiple PWM channels as IP uses
236 * same period register for multiple channels.
237 */
238 for (i = 0; i < NUM_PWM_CHANNEL; i++) {
239 if (pc->period_cycles[i] &&
240 (pc->period_cycles[i] != period_cycles)) {
241 /*
242 * Allow channel to reconfigure period if no other
243 * channels being configured.
244 */
245 if (i == pwm->hwpwm)
246 continue;
247
248 dev_err(chip->dev, "Period value conflicts with channel %d\n",
249 i);
250 return -EINVAL;
251 }
252 }
253
254 pc->period_cycles[pwm->hwpwm] = period_cycles;
255
232 /* Configure clock prescaler to support Low frequency PWM wave */ 256 /* Configure clock prescaler to support Low frequency PWM wave */
233 if (set_prescale_div(period_cycles/PERIOD_MAX, &ps_divval, 257 if (set_prescale_div(period_cycles/PERIOD_MAX, &ps_divval,
234 &tb_divval)) { 258 &tb_divval)) {
@@ -320,10 +344,15 @@ static void ehrpwm_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
320 344
321static void ehrpwm_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm) 345static void ehrpwm_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm)
322{ 346{
347 struct ehrpwm_pwm_chip *pc = to_ehrpwm_pwm_chip(chip);
348
323 if (test_bit(PWMF_ENABLED, &pwm->flags)) { 349 if (test_bit(PWMF_ENABLED, &pwm->flags)) {
324 dev_warn(chip->dev, "Removing PWM device without disabling\n"); 350 dev_warn(chip->dev, "Removing PWM device without disabling\n");
325 pm_runtime_put_sync(chip->dev); 351 pm_runtime_put_sync(chip->dev);
326 } 352 }
353
354 /* set period value to zero on free */
355 pc->period_cycles[pwm->hwpwm] = 0;
327} 356}
328 357
329static const struct pwm_ops ehrpwm_pwm_ops = { 358static const struct pwm_ops ehrpwm_pwm_ops = {