blob: f98afe4906fbf5258ac47b7e7cbd11f6209b5573 [file] [log] [blame]
Lee Jones378fe112014-07-14 15:33:27 +01001/*
2 * PWM device driver for ST SoCs.
3 * Author: Ajit Pal Singh <ajitpal.singh@st.com>
4 *
5 * Copyright (C) 2013-2014 STMicroelectronics (R&D) Limited
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 */
12
13#include <linux/bsearch.h>
14#include <linux/clk.h>
15#include <linux/math64.h>
16#include <linux/mfd/syscon.h>
17#include <linux/module.h>
18#include <linux/of.h>
19#include <linux/platform_device.h>
20#include <linux/pwm.h>
21#include <linux/regmap.h>
22#include <linux/slab.h>
23#include <linux/time.h>
24
25#define STI_DS_REG(ch) (4 * (ch)) /* Channel's Duty Cycle register */
26#define STI_PWMCR 0x50 /* Control/Config register */
27#define STI_INTEN 0x54 /* Interrupt Enable/Disable register */
Ajit Pal Singhbf9cc802014-07-14 15:33:29 +010028#define PWM_PRESCALE_LOW_MASK 0x0f
29#define PWM_PRESCALE_HIGH_MASK 0xf0
Lee Jones378fe112014-07-14 15:33:27 +010030
31/* Regfield IDs */
32enum {
Ajit Pal Singhbf9cc802014-07-14 15:33:29 +010033 PWMCLK_PRESCALE_LOW,
34 PWMCLK_PRESCALE_HIGH,
Lee Jones378fe112014-07-14 15:33:27 +010035 PWM_EN,
36 PWM_INT_EN,
37
38 /* Keep last */
39 MAX_REGFIELDS
40};
41
42struct sti_pwm_compat_data {
43 const struct reg_field *reg_fields;
44 unsigned int num_chan;
45 unsigned int max_pwm_cnt;
46 unsigned int max_prescale;
47};
48
49struct sti_pwm_chip {
50 struct device *dev;
51 struct clk *clk;
52 unsigned long clk_rate;
53 struct regmap *regmap;
54 struct sti_pwm_compat_data *cdata;
Ajit Pal Singhbf9cc802014-07-14 15:33:29 +010055 struct regmap_field *prescale_low;
56 struct regmap_field *prescale_high;
Lee Jones378fe112014-07-14 15:33:27 +010057 struct regmap_field *pwm_en;
58 struct regmap_field *pwm_int_en;
59 unsigned long *pwm_periods;
60 struct pwm_chip chip;
Ajit Pal Singh51651662014-07-14 15:33:30 +010061 struct pwm_device *cur;
Ajit Pal Singh6ad6b832014-07-14 15:33:31 +010062 unsigned int en_count;
63 struct mutex sti_pwm_lock; /* To sync between enable/disable calls */
Lee Jones378fe112014-07-14 15:33:27 +010064 void __iomem *mmio;
65};
66
67static const struct reg_field sti_pwm_regfields[MAX_REGFIELDS] = {
Ajit Pal Singhbf9cc802014-07-14 15:33:29 +010068 [PWMCLK_PRESCALE_LOW] = REG_FIELD(STI_PWMCR, 0, 3),
69 [PWMCLK_PRESCALE_HIGH] = REG_FIELD(STI_PWMCR, 11, 14),
Lee Jones378fe112014-07-14 15:33:27 +010070 [PWM_EN] = REG_FIELD(STI_PWMCR, 9, 9),
71 [PWM_INT_EN] = REG_FIELD(STI_INTEN, 0, 0),
72};
73
74static inline struct sti_pwm_chip *to_sti_pwmchip(struct pwm_chip *chip)
75{
76 return container_of(chip, struct sti_pwm_chip, chip);
77}
78
79/*
80 * Calculate the period values supported by the PWM for the
81 * current clock rate.
82 */
83static void sti_pwm_calc_periods(struct sti_pwm_chip *pc)
84{
85 struct sti_pwm_compat_data *cdata = pc->cdata;
86 struct device *dev = pc->dev;
87 unsigned long val;
88 int i;
89
90 /*
91 * period_ns = (10^9 * (prescaler + 1) * (MAX_PWM_COUNT + 1)) / CLK_RATE
92 */
93 val = NSEC_PER_SEC / pc->clk_rate;
94 val *= cdata->max_pwm_cnt + 1;
95
96 dev_dbg(dev, "possible periods for clkrate[HZ]:%lu\n", pc->clk_rate);
97
98 for (i = 0; i <= cdata->max_prescale; i++) {
99 pc->pwm_periods[i] = val * (i + 1);
100 dev_dbg(dev, "prescale:%d, period[ns]:%lu\n",
101 i, pc->pwm_periods[i]);
102 }
103}
104
Ajit Pal Singh51651662014-07-14 15:33:30 +0100105/* Calculate the number of PWM devices configured with a period. */
106static unsigned int sti_pwm_count_configured(struct pwm_chip *chip)
107{
108 struct pwm_device *pwm;
109 unsigned int ncfg = 0;
110 unsigned int i;
111
112 for (i = 0; i < chip->npwm; i++) {
113 pwm = &chip->pwms[i];
114 if (test_bit(PWMF_REQUESTED, &pwm->flags)) {
115 if (pwm_get_period(pwm))
116 ncfg++;
117 }
118 }
119
120 return ncfg;
121}
122
Lee Jones378fe112014-07-14 15:33:27 +0100123static int sti_pwm_cmp_periods(const void *key, const void *elt)
124{
125 unsigned long i = *(unsigned long *)key;
126 unsigned long j = *(unsigned long *)elt;
127
128 if (i < j)
129 return -1;
130 else
131 return i == j ? 0 : 1;
132}
133
134/*
135 * For STiH4xx PWM IP, the PWM period is fixed to 256 local clock cycles.
136 * The only way to change the period (apart from changing the PWM input clock)
137 * is to change the PWM clock prescaler.
Ajit Pal Singhbf9cc802014-07-14 15:33:29 +0100138 * The prescaler is of 8 bits, so 256 prescaler values and hence
139 * 256 possible period values are supported (for a particular clock rate).
Lee Jones378fe112014-07-14 15:33:27 +0100140 * The requested period will be applied only if it matches one of these
Ajit Pal Singhbf9cc802014-07-14 15:33:29 +0100141 * 256 values.
Lee Jones378fe112014-07-14 15:33:27 +0100142 */
143static int sti_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
144 int duty_ns, int period_ns)
145{
146 struct sti_pwm_chip *pc = to_sti_pwmchip(chip);
147 struct sti_pwm_compat_data *cdata = pc->cdata;
Ajit Pal Singh51651662014-07-14 15:33:30 +0100148 struct pwm_device *cur = pc->cur;
Lee Jones378fe112014-07-14 15:33:27 +0100149 struct device *dev = pc->dev;
Ajit Pal Singh51651662014-07-14 15:33:30 +0100150 unsigned int prescale = 0, pwmvalx;
Lee Jones378fe112014-07-14 15:33:27 +0100151 unsigned long *found;
152 int ret;
Ajit Pal Singh51651662014-07-14 15:33:30 +0100153 unsigned int ncfg;
154 bool period_same = false;
Lee Jones378fe112014-07-14 15:33:27 +0100155
Ajit Pal Singh51651662014-07-14 15:33:30 +0100156 ncfg = sti_pwm_count_configured(chip);
157 if (ncfg)
158 period_same = (period_ns == pwm_get_period(cur));
159
160 /* Allow configuration changes if one of the
161 * following conditions satisfy.
162 * 1. No channels have been configured.
163 * 2. Only one channel has been configured and the new request
164 * is for the same channel.
165 * 3. Only one channel has been configured and the new request is
166 * for a new channel and period of the new channel is same as
167 * the current configured period.
168 * 4. More than one channels are configured and period of the new
169 * requestis the same as the current period.
Lee Jones378fe112014-07-14 15:33:27 +0100170 */
Ajit Pal Singh51651662014-07-14 15:33:30 +0100171 if (!ncfg ||
172 ((ncfg == 1) && (pwm->hwpwm == cur->hwpwm)) ||
173 ((ncfg == 1) && (pwm->hwpwm != cur->hwpwm) && period_same) ||
174 ((ncfg > 1) && period_same)) {
175 /* Enable clock before writing to PWM registers. */
176 ret = clk_enable(pc->clk);
177 if (ret)
178 return ret;
179
180 if (!period_same) {
181 /*
182 * Search for matching period value.
183 * The corresponding index is our prescale value.
184 */
185 found = bsearch(&period_ns, &pc->pwm_periods[0],
186 cdata->max_prescale + 1,
187 sizeof(unsigned long),
188 sti_pwm_cmp_periods);
189 if (!found) {
190 dev_err(dev,
191 "failed to find matching period\n");
192 ret = -EINVAL;
193 goto clk_dis;
194 }
195 prescale = found - &pc->pwm_periods[0];
196
197 ret =
198 regmap_field_write(pc->prescale_low,
199 prescale & PWM_PRESCALE_LOW_MASK);
200 if (ret)
201 goto clk_dis;
202
203 ret =
204 regmap_field_write(pc->prescale_high,
205 (prescale & PWM_PRESCALE_HIGH_MASK) >> 4);
206 if (ret)
207 goto clk_dis;
208 }
209
210 /*
211 * When PWMVal == 0, PWM pulse = 1 local clock cycle.
212 * When PWMVal == max_pwm_count,
213 * PWM pulse = (max_pwm_count + 1) local cycles,
214 * that is continuous pulse: signal never goes low.
215 */
216 pwmvalx = cdata->max_pwm_cnt * duty_ns / period_ns;
217
218 ret = regmap_write(pc->regmap, STI_DS_REG(pwm->hwpwm), pwmvalx);
219 if (ret)
220 goto clk_dis;
221
222 ret = regmap_field_write(pc->pwm_int_en, 0);
223
224 pc->cur = pwm;
225
226 dev_dbg(dev, "prescale:%u, period:%i, duty:%i, pwmvalx:%u\n",
227 prescale, period_ns, duty_ns, pwmvalx);
228 } else {
Lee Jones378fe112014-07-14 15:33:27 +0100229 return -EINVAL;
230 }
231
Lee Jones378fe112014-07-14 15:33:27 +0100232clk_dis:
233 clk_disable(pc->clk);
234 return ret;
235}
236
237static int sti_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
238{
239 struct sti_pwm_chip *pc = to_sti_pwmchip(chip);
240 struct device *dev = pc->dev;
Ajit Pal Singh6ad6b832014-07-14 15:33:31 +0100241 int ret = 0;
Lee Jones378fe112014-07-14 15:33:27 +0100242
Ajit Pal Singh6ad6b832014-07-14 15:33:31 +0100243 /*
244 * Since we have a common enable for all PWM channels,
245 * do not enable if already enabled.
246 */
247 mutex_lock(&pc->sti_pwm_lock);
248 if (!pc->en_count) {
249 ret = clk_enable(pc->clk);
250 if (ret)
251 goto out;
Lee Jones378fe112014-07-14 15:33:27 +0100252
Ajit Pal Singh6ad6b832014-07-14 15:33:31 +0100253 ret = regmap_field_write(pc->pwm_en, 1);
254 if (ret) {
255 dev_err(dev, "failed to enable PWM device:%d\n",
256 pwm->hwpwm);
257 goto out;
258 }
259 }
260 pc->en_count++;
261out:
262 mutex_unlock(&pc->sti_pwm_lock);
Lee Jones378fe112014-07-14 15:33:27 +0100263 return ret;
264}
265
266static void sti_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
267{
268 struct sti_pwm_chip *pc = to_sti_pwmchip(chip);
Lee Jones378fe112014-07-14 15:33:27 +0100269
Ajit Pal Singh6ad6b832014-07-14 15:33:31 +0100270 mutex_lock(&pc->sti_pwm_lock);
271 if (--pc->en_count) {
272 mutex_unlock(&pc->sti_pwm_lock);
273 return;
274 }
Lee Jones378fe112014-07-14 15:33:27 +0100275 regmap_field_write(pc->pwm_en, 0);
276
Lee Jones378fe112014-07-14 15:33:27 +0100277 clk_disable(pc->clk);
Ajit Pal Singh6ad6b832014-07-14 15:33:31 +0100278 mutex_unlock(&pc->sti_pwm_lock);
Lee Jones378fe112014-07-14 15:33:27 +0100279}
280
281static const struct pwm_ops sti_pwm_ops = {
282 .config = sti_pwm_config,
283 .enable = sti_pwm_enable,
284 .disable = sti_pwm_disable,
285 .owner = THIS_MODULE,
286};
287
288static int sti_pwm_probe_dt(struct sti_pwm_chip *pc)
289{
290 struct device *dev = pc->dev;
291 const struct reg_field *reg_fields;
292 struct device_node *np = dev->of_node;
293 struct sti_pwm_compat_data *cdata = pc->cdata;
294 u32 num_chan;
295
296 of_property_read_u32(np, "st,pwm-num-chan", &num_chan);
297 if (num_chan)
298 cdata->num_chan = num_chan;
299
300 reg_fields = cdata->reg_fields;
301
Ajit Pal Singhbf9cc802014-07-14 15:33:29 +0100302 pc->prescale_low = devm_regmap_field_alloc(dev, pc->regmap,
303 reg_fields[PWMCLK_PRESCALE_LOW]);
304 if (IS_ERR(pc->prescale_low))
305 return PTR_ERR(pc->prescale_low);
306
307 pc->prescale_high = devm_regmap_field_alloc(dev, pc->regmap,
308 reg_fields[PWMCLK_PRESCALE_HIGH]);
309 if (IS_ERR(pc->prescale_high))
310 return PTR_ERR(pc->prescale_high);
Lee Jones378fe112014-07-14 15:33:27 +0100311
312 pc->pwm_en = devm_regmap_field_alloc(dev, pc->regmap,
313 reg_fields[PWM_EN]);
314 if (IS_ERR(pc->pwm_en))
315 return PTR_ERR(pc->pwm_en);
316
317 pc->pwm_int_en = devm_regmap_field_alloc(dev, pc->regmap,
318 reg_fields[PWM_INT_EN]);
319 if (IS_ERR(pc->pwm_int_en))
320 return PTR_ERR(pc->pwm_int_en);
321
322 return 0;
323}
324
325static const struct regmap_config sti_pwm_regmap_config = {
326 .reg_bits = 32,
327 .val_bits = 32,
328 .reg_stride = 4,
329};
330
331static int sti_pwm_probe(struct platform_device *pdev)
332{
333 struct device *dev = &pdev->dev;
334 struct sti_pwm_compat_data *cdata;
335 struct sti_pwm_chip *pc;
336 struct resource *res;
337 int ret;
338
339 pc = devm_kzalloc(dev, sizeof(*pc), GFP_KERNEL);
340 if (!pc)
341 return -ENOMEM;
342
343 cdata = devm_kzalloc(dev, sizeof(*cdata), GFP_KERNEL);
344 if (!cdata)
345 return -ENOMEM;
346
347 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
348
349 pc->mmio = devm_ioremap_resource(dev, res);
350 if (IS_ERR(pc->mmio))
351 return PTR_ERR(pc->mmio);
352
353 pc->regmap = devm_regmap_init_mmio(dev, pc->mmio,
354 &sti_pwm_regmap_config);
355 if (IS_ERR(pc->regmap))
356 return PTR_ERR(pc->regmap);
357
358 /*
359 * Setup PWM data with default values: some values could be replaced
360 * with specific ones provided from Device Tree.
361 */
362 cdata->reg_fields = &sti_pwm_regfields[0];
363 cdata->max_prescale = 0xff;
364 cdata->max_pwm_cnt = 255;
365 cdata->num_chan = 1;
366
367 pc->cdata = cdata;
368 pc->dev = dev;
Ajit Pal Singh6ad6b832014-07-14 15:33:31 +0100369 pc->en_count = 0;
370 mutex_init(&pc->sti_pwm_lock);
Lee Jones378fe112014-07-14 15:33:27 +0100371
372 ret = sti_pwm_probe_dt(pc);
373 if (ret)
374 return ret;
375
376 pc->pwm_periods = devm_kzalloc(dev,
377 sizeof(unsigned long) * (pc->cdata->max_prescale + 1),
378 GFP_KERNEL);
379 if (!pc->pwm_periods)
380 return -ENOMEM;
381
382 pc->clk = of_clk_get_by_name(dev->of_node, "pwm");
383 if (IS_ERR(pc->clk)) {
384 dev_err(dev, "failed to get PWM clock\n");
385 return PTR_ERR(pc->clk);
386 }
387
388 pc->clk_rate = clk_get_rate(pc->clk);
389 if (!pc->clk_rate) {
390 dev_err(dev, "failed to get clock rate\n");
391 return -EINVAL;
392 }
393
394 ret = clk_prepare(pc->clk);
395 if (ret) {
396 dev_err(dev, "failed to prepare clock\n");
397 return ret;
398 }
399
400 sti_pwm_calc_periods(pc);
401
402 pc->chip.dev = dev;
403 pc->chip.ops = &sti_pwm_ops;
404 pc->chip.base = -1;
405 pc->chip.npwm = pc->cdata->num_chan;
406 pc->chip.can_sleep = true;
407
408 ret = pwmchip_add(&pc->chip);
409 if (ret < 0) {
410 clk_unprepare(pc->clk);
411 return ret;
412 }
413
414 platform_set_drvdata(pdev, pc);
415
416 return 0;
417}
418
419static int sti_pwm_remove(struct platform_device *pdev)
420{
421 struct sti_pwm_chip *pc = platform_get_drvdata(pdev);
422 unsigned int i;
423
424 for (i = 0; i < pc->cdata->num_chan; i++)
425 pwm_disable(&pc->chip.pwms[i]);
426
427 clk_unprepare(pc->clk);
428
429 return pwmchip_remove(&pc->chip);
430}
431
432static const struct of_device_id sti_pwm_of_match[] = {
433 { .compatible = "st,sti-pwm", },
434 { /* sentinel */ }
435};
436MODULE_DEVICE_TABLE(of, sti_pwm_of_match);
437
438static struct platform_driver sti_pwm_driver = {
439 .driver = {
440 .name = "sti-pwm",
441 .of_match_table = sti_pwm_of_match,
442 },
443 .probe = sti_pwm_probe,
444 .remove = sti_pwm_remove,
445};
446module_platform_driver(sti_pwm_driver);
447
448MODULE_AUTHOR("Ajit Pal Singh <ajitpal.singh@st.com>");
449MODULE_DESCRIPTION("STMicroelectronics ST PWM driver");
450MODULE_LICENSE("GPL");