aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pwm/pwm-lpss.c
diff options
context:
space:
mode:
authorMika Westerberg <mika.westerberg@linux.intel.com>2016-06-10 08:43:21 -0400
committerThierry Reding <thierry.reding@gmail.com>2016-07-11 06:07:24 -0400
commitab248b603960a4b6effaa9e16fc1ea84a33210c7 (patch)
tree116a0ba4981a5e54960d934e0b5339809f089b99 /drivers/pwm/pwm-lpss.c
parente5ca42458b6278b7d5866e08dae7c45349af2157 (diff)
pwm: lpss: Prevent on_time_div overflow on lower frequencies
If duty_ns is large enough multiplying it by 255 overflows and results wrong duty cycle value being programmed. For example with 10ms duty when period is 20ms (50%) we get 255 * 10000000 / 20000000 = -87 because 255 * 10000000 overlows int. Whereas correct value should be 255 * 10000000 / 20000000 = 127 Fix this by using unsigned long long as type for on_time_div and changing integer literals to use proper type annotation. Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com> Signed-off-by: Thierry Reding <thierry.reding@gmail.com>
Diffstat (limited to 'drivers/pwm/pwm-lpss.c')
-rw-r--r--drivers/pwm/pwm-lpss.c6
1 files changed, 4 insertions, 2 deletions
diff --git a/drivers/pwm/pwm-lpss.c b/drivers/pwm/pwm-lpss.c
index 98dc8b80b79d..be4658b42882 100644
--- a/drivers/pwm/pwm-lpss.c
+++ b/drivers/pwm/pwm-lpss.c
@@ -91,7 +91,7 @@ static int pwm_lpss_config(struct pwm_chip *chip, struct pwm_device *pwm,
91 int duty_ns, int period_ns) 91 int duty_ns, int period_ns)
92{ 92{
93 struct pwm_lpss_chip *lpwm = to_lpwm(chip); 93 struct pwm_lpss_chip *lpwm = to_lpwm(chip);
94 u8 on_time_div; 94 unsigned long long on_time_div;
95 unsigned long c, base_unit_range; 95 unsigned long c, base_unit_range;
96 unsigned long long base_unit, freq = NSEC_PER_SEC; 96 unsigned long long base_unit, freq = NSEC_PER_SEC;
97 u32 ctrl; 97 u32 ctrl;
@@ -113,7 +113,9 @@ static int pwm_lpss_config(struct pwm_chip *chip, struct pwm_device *pwm,
113 113
114 if (duty_ns <= 0) 114 if (duty_ns <= 0)
115 duty_ns = 1; 115 duty_ns = 1;
116 on_time_div = 255 - (255 * duty_ns / period_ns); 116 on_time_div = 255ULL * duty_ns;
117 do_div(on_time_div, period_ns);
118 on_time_div = 255ULL - on_time_div;
117 119
118 pm_runtime_get_sync(chip->dev); 120 pm_runtime_get_sync(chip->dev);
119 121