aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pwm/pwm-atmel.c
diff options
context:
space:
mode:
authorClaudiu Beznea <claudiu.beznea@microchip.com>2017-03-22 09:29:34 -0400
committerThierry Reding <thierry.reding@gmail.com>2017-04-06 11:45:02 -0400
commit1a722aad587967985f927e4ec2650ca64632c3e1 (patch)
tree1a9998faf3c23bbffa68f7d48c6300b126781355 /drivers/pwm/pwm-atmel.c
parentf9bb9da7c09d76f00c9abdf34cbeaec65e50d78b (diff)
pwm: atmel: Switch to atomic PWM
The currently Atmel PWM controllers supported by this driver could change period or duty factor without channel disable, for regular channels (sama5d3 support this by using period or duty factor update registers, sam9rl support this by writing channel update register and select the corresponding update: period or duty factor). The chip doesn't support run time changings of signal polarity. To take advantage of atomic PWM framework and let controller works without glitches, in this patch only the duty factor could be changed without disabling PWM channel. For period and signal polarity the atomic PWM is simulated by disabling + enabling the right PWM channel. Signed-off-by: Claudiu Beznea <claudiu.beznea@microchip.com> Reviewed-by: Boris Brezillon <boris.brezillon@free-electrons.com> Signed-off-by: Thierry Reding <thierry.reding@gmail.com>
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