aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pwm
diff options
context:
space:
mode:
authorDavid Rivshin <drivshin@allworx.com>2016-01-29 23:26:52 -0500
committerThierry Reding <thierry.reding@gmail.com>2016-03-23 12:11:46 -0400
commitcd378881426379a62a7fe67f34b8cbe738302022 (patch)
treea8753c450bfb1c1124ee7f32b6a74d17a58b9529 /drivers/pwm
parentf8caa792261c0edded20eba2b8fcc899a1b91819 (diff)
pwm: omap-dmtimer: Add sanity checking for load and match values
Add sanity checking to ensure that we do not program load or match values that are out of range if a user requests period or duty_cycle values which are not achievable. The match value cannot be less than the load value (but can be equal), and neither can be 0xffffffff. This means that there must be at least one fclk cycle between load and match, and another between match and overflow. Fixes: 6604c6556db9 ("pwm: Add PWM driver for OMAP using dual-mode timers") Signed-off-by: David Rivshin <drivshin@allworx.com> Acked-by: Neil Armstrong <narmstrong@baylibre.com> [thierry.reding@gmail.com: minor coding style cleanups] Signed-off-by: Thierry Reding <thierry.reding@gmail.com>
Diffstat (limited to 'drivers/pwm')
-rw-r--r--drivers/pwm/pwm-omap-dmtimer.c34
1 files changed, 30 insertions, 4 deletions
diff --git a/drivers/pwm/pwm-omap-dmtimer.c b/drivers/pwm/pwm-omap-dmtimer.c
index 0083e75d950f..54641e45f45b 100644
--- a/drivers/pwm/pwm-omap-dmtimer.c
+++ b/drivers/pwm/pwm-omap-dmtimer.c
@@ -119,15 +119,13 @@ static int pwm_omap_dmtimer_config(struct pwm_chip *chip,
119 fclk = omap->pdata->get_fclk(omap->dm_timer); 119 fclk = omap->pdata->get_fclk(omap->dm_timer);
120 if (!fclk) { 120 if (!fclk) {
121 dev_err(chip->dev, "invalid pmtimer fclk\n"); 121 dev_err(chip->dev, "invalid pmtimer fclk\n");
122 mutex_unlock(&omap->mutex); 122 goto err_einval;
123 return -EINVAL;
124 } 123 }
125 124
126 clk_rate = clk_get_rate(fclk); 125 clk_rate = clk_get_rate(fclk);
127 if (!clk_rate) { 126 if (!clk_rate) {
128 dev_err(chip->dev, "invalid pmtimer fclk rate\n"); 127 dev_err(chip->dev, "invalid pmtimer fclk rate\n");
129 mutex_unlock(&omap->mutex); 128 goto err_einval;
130 return -EINVAL;
131 } 129 }
132 130
133 dev_dbg(chip->dev, "clk rate: %luHz\n", clk_rate); 131 dev_dbg(chip->dev, "clk rate: %luHz\n", clk_rate);
@@ -142,6 +140,8 @@ static int pwm_omap_dmtimer_config(struct pwm_chip *chip,
142 * The non-active time is the remainder: (DM_TIMER_MAX-match_value) 140 * The non-active time is the remainder: (DM_TIMER_MAX-match_value)
143 * clock cycles. 141 * clock cycles.
144 * 142 *
143 * NOTE: It is required that: load_value <= match_value < DM_TIMER_MAX
144 *
145 * References: 145 * References:
146 * OMAP4430/60/70 TRM sections 22.2.4.10 and 22.2.4.11 146 * OMAP4430/60/70 TRM sections 22.2.4.10 and 22.2.4.11
147 * AM335x Sitara TRM sections 20.1.3.5 and 20.1.3.6 147 * AM335x Sitara TRM sections 20.1.3.5 and 20.1.3.6
@@ -149,6 +149,27 @@ static int pwm_omap_dmtimer_config(struct pwm_chip *chip,
149 period_cycles = pwm_omap_dmtimer_get_clock_cycles(clk_rate, period_ns); 149 period_cycles = pwm_omap_dmtimer_get_clock_cycles(clk_rate, period_ns);
150 duty_cycles = pwm_omap_dmtimer_get_clock_cycles(clk_rate, duty_ns); 150 duty_cycles = pwm_omap_dmtimer_get_clock_cycles(clk_rate, duty_ns);
151 151
152 if (period_cycles < 2) {
153 dev_info(chip->dev,
154 "period %d ns too short for clock rate %lu Hz\n",
155 period_ns, clk_rate);
156 goto err_einval;
157 }
158
159 if (duty_cycles < 1) {
160 dev_dbg(chip->dev,
161 "duty cycle %d ns is too short for clock rate %lu Hz\n",
162 duty_ns, clk_rate);
163 dev_dbg(chip->dev, "using minimum of 1 clock cycle\n");
164 duty_cycles = 1;
165 } else if (duty_cycles >= period_cycles) {
166 dev_dbg(chip->dev,
167 "duty cycle %d ns is too long for period %d ns at clock rate %lu Hz\n",
168 duty_ns, period_ns, clk_rate);
169 dev_dbg(chip->dev, "using maximum of 1 clock cycle less than period\n");
170 duty_cycles = period_cycles - 1;
171 }
172
152 load_value = (DM_TIMER_MAX - period_cycles) + 1; 173 load_value = (DM_TIMER_MAX - period_cycles) + 1;
153 match_value = load_value + duty_cycles - 1; 174 match_value = load_value + duty_cycles - 1;
154 175
@@ -179,6 +200,11 @@ static int pwm_omap_dmtimer_config(struct pwm_chip *chip,
179 mutex_unlock(&omap->mutex); 200 mutex_unlock(&omap->mutex);
180 201
181 return 0; 202 return 0;
203
204err_einval:
205 mutex_unlock(&omap->mutex);
206
207 return -EINVAL;
182} 208}
183 209
184static int pwm_omap_dmtimer_set_polarity(struct pwm_chip *chip, 210static int pwm_omap_dmtimer_set_polarity(struct pwm_chip *chip,