diff options
Diffstat (limited to 'drivers/pwm/pwm-atmel.c')
-rw-r--r-- | drivers/pwm/pwm-atmel.c | 273 |
1 files changed, 129 insertions, 144 deletions
diff --git a/drivers/pwm/pwm-atmel.c b/drivers/pwm/pwm-atmel.c index 67a7023be5c2..f147154d9cb2 100644 --- a/drivers/pwm/pwm-atmel.c +++ b/drivers/pwm/pwm-atmel.c | |||
@@ -58,17 +58,22 @@ | |||
58 | #define PWM_MAX_PRD 0xFFFF | 58 | #define PWM_MAX_PRD 0xFFFF |
59 | #define PRD_MAX_PRES 10 | 59 | #define PRD_MAX_PRES 10 |
60 | 60 | ||
61 | struct atmel_pwm_registers { | ||
62 | u8 period; | ||
63 | u8 period_upd; | ||
64 | u8 duty; | ||
65 | u8 duty_upd; | ||
66 | }; | ||
67 | |||
61 | struct atmel_pwm_chip { | 68 | struct atmel_pwm_chip { |
62 | struct pwm_chip chip; | 69 | struct pwm_chip chip; |
63 | struct clk *clk; | 70 | struct clk *clk; |
64 | void __iomem *base; | 71 | void __iomem *base; |
72 | const struct atmel_pwm_registers *regs; | ||
65 | 73 | ||
66 | unsigned int updated_pwms; | 74 | unsigned int updated_pwms; |
67 | /* ISR is cleared when read, ensure only one thread does that */ | 75 | /* ISR is cleared when read, ensure only one thread does that */ |
68 | struct mutex isr_lock; | 76 | struct mutex isr_lock; |
69 | |||
70 | void (*config)(struct pwm_chip *chip, struct pwm_device *pwm, | ||
71 | unsigned long dty, unsigned long prd); | ||
72 | }; | 77 | }; |
73 | 78 | ||
74 | static inline struct atmel_pwm_chip *to_atmel_pwm_chip(struct pwm_chip *chip) | 79 | static inline struct atmel_pwm_chip *to_atmel_pwm_chip(struct pwm_chip *chip) |
@@ -105,153 +110,71 @@ static inline void atmel_pwm_ch_writel(struct atmel_pwm_chip *chip, | |||
105 | writel_relaxed(val, chip->base + base + offset); | 110 | writel_relaxed(val, chip->base + base + offset); |
106 | } | 111 | } |
107 | 112 | ||
108 | static int atmel_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, | 113 | static int atmel_pwm_calculate_cprd_and_pres(struct pwm_chip *chip, |
109 | int duty_ns, int period_ns) | 114 | const struct pwm_state *state, |
115 | unsigned long *cprd, u32 *pres) | ||
110 | { | 116 | { |
111 | struct atmel_pwm_chip *atmel_pwm = to_atmel_pwm_chip(chip); | 117 | struct atmel_pwm_chip *atmel_pwm = to_atmel_pwm_chip(chip); |
112 | unsigned long prd, dty; | 118 | unsigned long long cycles = state->period; |
113 | unsigned long long div; | ||
114 | unsigned int pres = 0; | ||
115 | u32 val; | ||
116 | int ret; | ||
117 | |||
118 | if (pwm_is_enabled(pwm) && (period_ns != pwm_get_period(pwm))) { | ||
119 | dev_err(chip->dev, "cannot change PWM period while enabled\n"); | ||
120 | return -EBUSY; | ||
121 | } | ||
122 | 119 | ||
123 | /* Calculate the period cycles and prescale value */ | 120 | /* Calculate the period cycles and prescale value */ |
124 | div = (unsigned long long)clk_get_rate(atmel_pwm->clk) * period_ns; | 121 | cycles *= clk_get_rate(atmel_pwm->clk); |
125 | do_div(div, NSEC_PER_SEC); | 122 | do_div(cycles, NSEC_PER_SEC); |
126 | 123 | ||
127 | while (div > PWM_MAX_PRD) { | 124 | for (*pres = 0; cycles > PWM_MAX_PRD; cycles >>= 1) |
128 | div >>= 1; | 125 | (*pres)++; |
129 | pres++; | ||
130 | } | ||
131 | 126 | ||
132 | if (pres > PRD_MAX_PRES) { | 127 | if (*pres > PRD_MAX_PRES) { |
133 | dev_err(chip->dev, "pres exceeds the maximum value\n"); | 128 | dev_err(chip->dev, "pres exceeds the maximum value\n"); |
134 | return -EINVAL; | 129 | return -EINVAL; |
135 | } | 130 | } |
136 | 131 | ||
137 | /* Calculate the duty cycles */ | 132 | *cprd = cycles; |
138 | prd = div; | ||
139 | div *= duty_ns; | ||
140 | do_div(div, period_ns); | ||
141 | dty = prd - div; | ||
142 | |||
143 | ret = clk_enable(atmel_pwm->clk); | ||
144 | if (ret) { | ||
145 | dev_err(chip->dev, "failed to enable PWM clock\n"); | ||
146 | return ret; | ||
147 | } | ||
148 | |||
149 | /* It is necessary to preserve CPOL, inside CMR */ | ||
150 | val = atmel_pwm_ch_readl(atmel_pwm, pwm->hwpwm, PWM_CMR); | ||
151 | val = (val & ~PWM_CMR_CPRE_MSK) | (pres & PWM_CMR_CPRE_MSK); | ||
152 | atmel_pwm_ch_writel(atmel_pwm, pwm->hwpwm, PWM_CMR, val); | ||
153 | atmel_pwm->config(chip, pwm, dty, prd); | ||
154 | mutex_lock(&atmel_pwm->isr_lock); | ||
155 | atmel_pwm->updated_pwms |= atmel_pwm_readl(atmel_pwm, PWM_ISR); | ||
156 | atmel_pwm->updated_pwms &= ~(1 << pwm->hwpwm); | ||
157 | mutex_unlock(&atmel_pwm->isr_lock); | ||
158 | 133 | ||
159 | clk_disable(atmel_pwm->clk); | 134 | return 0; |
160 | return ret; | ||
161 | } | 135 | } |
162 | 136 | ||
163 | static void atmel_pwm_config_v1(struct pwm_chip *chip, struct pwm_device *pwm, | 137 | static void atmel_pwm_calculate_cdty(const struct pwm_state *state, |
164 | unsigned long dty, unsigned long prd) | 138 | unsigned long cprd, unsigned long *cdty) |
165 | { | 139 | { |
166 | struct atmel_pwm_chip *atmel_pwm = to_atmel_pwm_chip(chip); | 140 | unsigned long long cycles = state->duty_cycle; |
167 | unsigned int val; | ||
168 | 141 | ||
169 | 142 | cycles *= cprd; | |
170 | atmel_pwm_ch_writel(atmel_pwm, pwm->hwpwm, PWMV1_CUPD, dty); | 143 | do_div(cycles, state->period); |
171 | 144 | *cdty = cprd - cycles; | |
172 | val = atmel_pwm_ch_readl(atmel_pwm, pwm->hwpwm, PWM_CMR); | ||
173 | val &= ~PWM_CMR_UPD_CDTY; | ||
174 | atmel_pwm_ch_writel(atmel_pwm, pwm->hwpwm, PWM_CMR, val); | ||
175 | |||
176 | /* | ||
177 | * If the PWM channel is enabled, only update CDTY by using the update | ||
178 | * register, it needs to set bit 10 of CMR to 0 | ||
179 | */ | ||
180 | if (pwm_is_enabled(pwm)) | ||
181 | return; | ||
182 | /* | ||
183 | * If the PWM channel is disabled, write value to duty and period | ||
184 | * registers directly. | ||
185 | */ | ||
186 | atmel_pwm_ch_writel(atmel_pwm, pwm->hwpwm, PWMV1_CDTY, dty); | ||
187 | atmel_pwm_ch_writel(atmel_pwm, pwm->hwpwm, PWMV1_CPRD, prd); | ||
188 | } | 145 | } |
189 | 146 | ||
190 | static void atmel_pwm_config_v2(struct pwm_chip *chip, struct pwm_device *pwm, | 147 | static void atmel_pwm_update_cdty(struct pwm_chip *chip, struct pwm_device *pwm, |
191 | unsigned long dty, unsigned long prd) | 148 | unsigned long cdty) |
192 | { | ||
193 | struct atmel_pwm_chip *atmel_pwm = to_atmel_pwm_chip(chip); | ||
194 | |||
195 | if (pwm_is_enabled(pwm)) { | ||
196 | /* | ||
197 | * If the PWM channel is enabled, using the duty update register | ||
198 | * to update the value. | ||
199 | */ | ||
200 | atmel_pwm_ch_writel(atmel_pwm, pwm->hwpwm, PWMV2_CDTYUPD, dty); | ||
201 | } else { | ||
202 | /* | ||
203 | * If the PWM channel is disabled, write value to duty and | ||
204 | * period registers directly. | ||
205 | */ | ||
206 | atmel_pwm_ch_writel(atmel_pwm, pwm->hwpwm, PWMV2_CDTY, dty); | ||
207 | atmel_pwm_ch_writel(atmel_pwm, pwm->hwpwm, PWMV2_CPRD, prd); | ||
208 | } | ||
209 | } | ||
210 | |||
211 | static int atmel_pwm_set_polarity(struct pwm_chip *chip, struct pwm_device *pwm, | ||
212 | enum pwm_polarity polarity) | ||
213 | { | 149 | { |
214 | struct atmel_pwm_chip *atmel_pwm = to_atmel_pwm_chip(chip); | 150 | struct atmel_pwm_chip *atmel_pwm = to_atmel_pwm_chip(chip); |
215 | u32 val; | 151 | u32 val; |
216 | int ret; | ||
217 | |||
218 | val = atmel_pwm_ch_readl(atmel_pwm, pwm->hwpwm, PWM_CMR); | ||
219 | 152 | ||
220 | if (polarity == PWM_POLARITY_NORMAL) | 153 | if (atmel_pwm->regs->duty_upd == |
221 | val &= ~PWM_CMR_CPOL; | 154 | atmel_pwm->regs->period_upd) { |
222 | else | 155 | val = atmel_pwm_ch_readl(atmel_pwm, pwm->hwpwm, PWM_CMR); |
223 | val |= PWM_CMR_CPOL; | 156 | val &= ~PWM_CMR_UPD_CDTY; |
224 | 157 | atmel_pwm_ch_writel(atmel_pwm, pwm->hwpwm, PWM_CMR, val); | |
225 | ret = clk_enable(atmel_pwm->clk); | ||
226 | if (ret) { | ||
227 | dev_err(chip->dev, "failed to enable PWM clock\n"); | ||
228 | return ret; | ||
229 | } | 158 | } |
230 | 159 | ||
231 | atmel_pwm_ch_writel(atmel_pwm, pwm->hwpwm, PWM_CMR, val); | 160 | atmel_pwm_ch_writel(atmel_pwm, pwm->hwpwm, |
232 | 161 | atmel_pwm->regs->duty_upd, cdty); | |
233 | clk_disable(atmel_pwm->clk); | ||
234 | |||
235 | return 0; | ||
236 | } | 162 | } |
237 | 163 | ||
238 | static int atmel_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm) | 164 | static void atmel_pwm_set_cprd_cdty(struct pwm_chip *chip, |
165 | struct pwm_device *pwm, | ||
166 | unsigned long cprd, unsigned long cdty) | ||
239 | { | 167 | { |
240 | struct atmel_pwm_chip *atmel_pwm = to_atmel_pwm_chip(chip); | 168 | struct atmel_pwm_chip *atmel_pwm = to_atmel_pwm_chip(chip); |
241 | int ret; | ||
242 | |||
243 | ret = clk_enable(atmel_pwm->clk); | ||
244 | if (ret) { | ||
245 | dev_err(chip->dev, "failed to enable PWM clock\n"); | ||
246 | return ret; | ||
247 | } | ||
248 | 169 | ||
249 | atmel_pwm_writel(atmel_pwm, PWM_ENA, 1 << pwm->hwpwm); | 170 | atmel_pwm_ch_writel(atmel_pwm, pwm->hwpwm, |
250 | 171 | atmel_pwm->regs->duty, cdty); | |
251 | return 0; | 172 | atmel_pwm_ch_writel(atmel_pwm, pwm->hwpwm, |
173 | atmel_pwm->regs->period, cprd); | ||
252 | } | 174 | } |
253 | 175 | ||
254 | static void atmel_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm) | 176 | static void atmel_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm, |
177 | bool disable_clk) | ||
255 | { | 178 | { |
256 | struct atmel_pwm_chip *atmel_pwm = to_atmel_pwm_chip(chip); | 179 | struct atmel_pwm_chip *atmel_pwm = to_atmel_pwm_chip(chip); |
257 | unsigned long timeout = jiffies + 2 * HZ; | 180 | unsigned long timeout = jiffies + 2 * HZ; |
@@ -282,37 +205,99 @@ static void atmel_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm) | |||
282 | time_before(jiffies, timeout)) | 205 | time_before(jiffies, timeout)) |
283 | usleep_range(10, 100); | 206 | usleep_range(10, 100); |
284 | 207 | ||
285 | clk_disable(atmel_pwm->clk); | 208 | if (disable_clk) |
209 | clk_disable(atmel_pwm->clk); | ||
210 | } | ||
211 | |||
212 | static int atmel_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, | ||
213 | struct pwm_state *state) | ||
214 | { | ||
215 | struct atmel_pwm_chip *atmel_pwm = to_atmel_pwm_chip(chip); | ||
216 | struct pwm_state cstate; | ||
217 | unsigned long cprd, cdty; | ||
218 | u32 pres, val; | ||
219 | int ret; | ||
220 | |||
221 | pwm_get_state(pwm, &cstate); | ||
222 | |||
223 | if (state->enabled) { | ||
224 | if (cstate.enabled && | ||
225 | cstate.polarity == state->polarity && | ||
226 | cstate.period == state->period) { | ||
227 | cprd = atmel_pwm_ch_readl(atmel_pwm, pwm->hwpwm, | ||
228 | atmel_pwm->regs->period); | ||
229 | atmel_pwm_calculate_cdty(state, cprd, &cdty); | ||
230 | atmel_pwm_update_cdty(chip, pwm, cdty); | ||
231 | return 0; | ||
232 | } | ||
233 | |||
234 | ret = atmel_pwm_calculate_cprd_and_pres(chip, state, &cprd, | ||
235 | &pres); | ||
236 | if (ret) { | ||
237 | dev_err(chip->dev, | ||
238 | "failed to calculate cprd and prescaler\n"); | ||
239 | return ret; | ||
240 | } | ||
241 | |||
242 | atmel_pwm_calculate_cdty(state, cprd, &cdty); | ||
243 | |||
244 | if (cstate.enabled) { | ||
245 | atmel_pwm_disable(chip, pwm, false); | ||
246 | } else { | ||
247 | ret = clk_enable(atmel_pwm->clk); | ||
248 | if (ret) { | ||
249 | dev_err(chip->dev, "failed to enable clock\n"); | ||
250 | return ret; | ||
251 | } | ||
252 | } | ||
253 | |||
254 | /* It is necessary to preserve CPOL, inside CMR */ | ||
255 | val = atmel_pwm_ch_readl(atmel_pwm, pwm->hwpwm, PWM_CMR); | ||
256 | val = (val & ~PWM_CMR_CPRE_MSK) | (pres & PWM_CMR_CPRE_MSK); | ||
257 | if (state->polarity == PWM_POLARITY_NORMAL) | ||
258 | val &= ~PWM_CMR_CPOL; | ||
259 | else | ||
260 | val |= PWM_CMR_CPOL; | ||
261 | atmel_pwm_ch_writel(atmel_pwm, pwm->hwpwm, PWM_CMR, val); | ||
262 | atmel_pwm_set_cprd_cdty(chip, pwm, cprd, cdty); | ||
263 | mutex_lock(&atmel_pwm->isr_lock); | ||
264 | atmel_pwm->updated_pwms |= atmel_pwm_readl(atmel_pwm, PWM_ISR); | ||
265 | atmel_pwm->updated_pwms &= ~(1 << pwm->hwpwm); | ||
266 | mutex_unlock(&atmel_pwm->isr_lock); | ||
267 | atmel_pwm_writel(atmel_pwm, PWM_ENA, 1 << pwm->hwpwm); | ||
268 | } else if (cstate.enabled) { | ||
269 | atmel_pwm_disable(chip, pwm, true); | ||
270 | } | ||
271 | |||
272 | return 0; | ||
286 | } | 273 | } |
287 | 274 | ||
288 | static const struct pwm_ops atmel_pwm_ops = { | 275 | static const struct pwm_ops atmel_pwm_ops = { |
289 | .config = atmel_pwm_config, | 276 | .apply = atmel_pwm_apply, |
290 | .set_polarity = atmel_pwm_set_polarity, | ||
291 | .enable = atmel_pwm_enable, | ||
292 | .disable = atmel_pwm_disable, | ||
293 | .owner = THIS_MODULE, | 277 | .owner = THIS_MODULE, |
294 | }; | 278 | }; |
295 | 279 | ||
296 | struct atmel_pwm_data { | 280 | static const struct atmel_pwm_registers atmel_pwm_regs_v1 = { |
297 | void (*config)(struct pwm_chip *chip, struct pwm_device *pwm, | 281 | .period = PWMV1_CPRD, |
298 | unsigned long dty, unsigned long prd); | 282 | .period_upd = PWMV1_CUPD, |
299 | }; | 283 | .duty = PWMV1_CDTY, |
300 | 284 | .duty_upd = PWMV1_CUPD, | |
301 | static const struct atmel_pwm_data atmel_pwm_data_v1 = { | ||
302 | .config = atmel_pwm_config_v1, | ||
303 | }; | 285 | }; |
304 | 286 | ||
305 | static const struct atmel_pwm_data atmel_pwm_data_v2 = { | 287 | static const struct atmel_pwm_registers atmel_pwm_regs_v2 = { |
306 | .config = atmel_pwm_config_v2, | 288 | .period = PWMV2_CPRD, |
289 | .period_upd = PWMV2_CPRDUPD, | ||
290 | .duty = PWMV2_CDTY, | ||
291 | .duty_upd = PWMV2_CDTYUPD, | ||
307 | }; | 292 | }; |
308 | 293 | ||
309 | static const struct platform_device_id atmel_pwm_devtypes[] = { | 294 | static const struct platform_device_id atmel_pwm_devtypes[] = { |
310 | { | 295 | { |
311 | .name = "at91sam9rl-pwm", | 296 | .name = "at91sam9rl-pwm", |
312 | .driver_data = (kernel_ulong_t)&atmel_pwm_data_v1, | 297 | .driver_data = (kernel_ulong_t)&atmel_pwm_regs_v1, |
313 | }, { | 298 | }, { |
314 | .name = "sama5d3-pwm", | 299 | .name = "sama5d3-pwm", |
315 | .driver_data = (kernel_ulong_t)&atmel_pwm_data_v2, | 300 | .driver_data = (kernel_ulong_t)&atmel_pwm_regs_v2, |
316 | }, { | 301 | }, { |
317 | /* sentinel */ | 302 | /* sentinel */ |
318 | }, | 303 | }, |
@@ -322,17 +307,17 @@ MODULE_DEVICE_TABLE(platform, atmel_pwm_devtypes); | |||
322 | static const struct of_device_id atmel_pwm_dt_ids[] = { | 307 | static const struct of_device_id atmel_pwm_dt_ids[] = { |
323 | { | 308 | { |
324 | .compatible = "atmel,at91sam9rl-pwm", | 309 | .compatible = "atmel,at91sam9rl-pwm", |
325 | .data = &atmel_pwm_data_v1, | 310 | .data = &atmel_pwm_regs_v1, |
326 | }, { | 311 | }, { |
327 | .compatible = "atmel,sama5d3-pwm", | 312 | .compatible = "atmel,sama5d3-pwm", |
328 | .data = &atmel_pwm_data_v2, | 313 | .data = &atmel_pwm_regs_v2, |
329 | }, { | 314 | }, { |
330 | /* sentinel */ | 315 | /* sentinel */ |
331 | }, | 316 | }, |
332 | }; | 317 | }; |
333 | MODULE_DEVICE_TABLE(of, atmel_pwm_dt_ids); | 318 | MODULE_DEVICE_TABLE(of, atmel_pwm_dt_ids); |
334 | 319 | ||
335 | static inline const struct atmel_pwm_data * | 320 | static inline const struct atmel_pwm_registers * |
336 | atmel_pwm_get_driver_data(struct platform_device *pdev) | 321 | atmel_pwm_get_driver_data(struct platform_device *pdev) |
337 | { | 322 | { |
338 | const struct platform_device_id *id; | 323 | const struct platform_device_id *id; |
@@ -342,18 +327,18 @@ atmel_pwm_get_driver_data(struct platform_device *pdev) | |||
342 | 327 | ||
343 | id = platform_get_device_id(pdev); | 328 | id = platform_get_device_id(pdev); |
344 | 329 | ||
345 | return (struct atmel_pwm_data *)id->driver_data; | 330 | return (struct atmel_pwm_registers *)id->driver_data; |
346 | } | 331 | } |
347 | 332 | ||
348 | static int atmel_pwm_probe(struct platform_device *pdev) | 333 | static int atmel_pwm_probe(struct platform_device *pdev) |
349 | { | 334 | { |
350 | const struct atmel_pwm_data *data; | 335 | const struct atmel_pwm_registers *regs; |
351 | struct atmel_pwm_chip *atmel_pwm; | 336 | struct atmel_pwm_chip *atmel_pwm; |
352 | struct resource *res; | 337 | struct resource *res; |
353 | int ret; | 338 | int ret; |
354 | 339 | ||
355 | data = atmel_pwm_get_driver_data(pdev); | 340 | regs = atmel_pwm_get_driver_data(pdev); |
356 | if (!data) | 341 | if (!regs) |
357 | return -ENODEV; | 342 | return -ENODEV; |
358 | 343 | ||
359 | atmel_pwm = devm_kzalloc(&pdev->dev, sizeof(*atmel_pwm), GFP_KERNEL); | 344 | atmel_pwm = devm_kzalloc(&pdev->dev, sizeof(*atmel_pwm), GFP_KERNEL); |
@@ -385,7 +370,7 @@ static int atmel_pwm_probe(struct platform_device *pdev) | |||
385 | 370 | ||
386 | atmel_pwm->chip.base = -1; | 371 | atmel_pwm->chip.base = -1; |
387 | atmel_pwm->chip.npwm = 4; | 372 | atmel_pwm->chip.npwm = 4; |
388 | atmel_pwm->config = data->config; | 373 | atmel_pwm->regs = regs; |
389 | atmel_pwm->updated_pwms = 0; | 374 | atmel_pwm->updated_pwms = 0; |
390 | mutex_init(&atmel_pwm->isr_lock); | 375 | mutex_init(&atmel_pwm->isr_lock); |
391 | 376 | ||