diff options
Diffstat (limited to 'drivers/pwm/pwm-tiehrpwm.c')
-rw-r--r-- | drivers/pwm/pwm-tiehrpwm.c | 29 |
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 | ||
109 | static inline struct ehrpwm_pwm_chip *to_ehrpwm_pwm_chip(struct pwm_chip *chip) | 110 | 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 | 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 | ||
321 | static void ehrpwm_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm) | 345 | static 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 | ||
329 | static const struct pwm_ops ehrpwm_pwm_ops = { | 358 | static const struct pwm_ops ehrpwm_pwm_ops = { |