aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pwm/pwm-atmel.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/pwm/pwm-atmel.c')
-rw-r--r--drivers/pwm/pwm-atmel.c273
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
61struct atmel_pwm_registers {
62 u8 period;
63 u8 period_upd;
64 u8 duty;
65 u8 duty_upd;
66};
67
61struct atmel_pwm_chip { 68struct 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
74static inline struct atmel_pwm_chip *to_atmel_pwm_chip(struct pwm_chip *chip) 79static 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
108static int atmel_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, 113static 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
163static void atmel_pwm_config_v1(struct pwm_chip *chip, struct pwm_device *pwm, 137static 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
190static void atmel_pwm_config_v2(struct pwm_chip *chip, struct pwm_device *pwm, 147static 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
211static 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
238static int atmel_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm) 164static 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
254static void atmel_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm) 176static 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
212static 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
288static const struct pwm_ops atmel_pwm_ops = { 275static 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
296struct atmel_pwm_data { 280static 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,
301static const struct atmel_pwm_data atmel_pwm_data_v1 = {
302 .config = atmel_pwm_config_v1,
303}; 285};
304 286
305static const struct atmel_pwm_data atmel_pwm_data_v2 = { 287static 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
309static const struct platform_device_id atmel_pwm_devtypes[] = { 294static 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);
322static const struct of_device_id atmel_pwm_dt_ids[] = { 307static 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};
333MODULE_DEVICE_TABLE(of, atmel_pwm_dt_ids); 318MODULE_DEVICE_TABLE(of, atmel_pwm_dt_ids);
334 319
335static inline const struct atmel_pwm_data * 320static inline const struct atmel_pwm_registers *
336atmel_pwm_get_driver_data(struct platform_device *pdev) 321atmel_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
348static int atmel_pwm_probe(struct platform_device *pdev) 333static 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