aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pwm/pwm-stm32.c
diff options
context:
space:
mode:
authorBenjamin Gaignard <benjamin.gaignard@linaro.org>2017-01-20 04:15:05 -0500
committerLee Jones <lee.jones@linaro.org>2017-01-25 11:11:55 -0500
commit7edf7369205baa158b08dea9efa2764bee41ab03 (patch)
treeaa768136cff90e478d3f2a3fa70d55470deee133 /drivers/pwm/pwm-stm32.c
parentcd9a99c2f8e890e84c593e393796b12ba7743128 (diff)
pwm: Add driver for STM32 plaftorm
This driver adds support for PWM driver on STM32 platform. The SoC have multiple instances of the hardware IP and each of them could have small differences: number of channels, complementary output, auto reload register size... version 9: - fix commit message header - remove one space MODULE_ALIAS version 8: - fix comments done by Thierry on version 7 version 6: - change st,breakinput parameter to make it usuable for stm32f7 too. version 4: - detect at probe time hardware capabilities - fix comments done on v2 and v3 - use PWM atomic ops version 2: - only keep one comptatible - use DT parameters to discover hardware block configuration Signed-off-by: Benjamin Gaignard <benjamin.gaignard@st.com> Acked-by: Thierry Reding <treding@nvidia.com> Signed-off-by: Lee Jones <lee.jones@linaro.org>
Diffstat (limited to 'drivers/pwm/pwm-stm32.c')
-rw-r--r--drivers/pwm/pwm-stm32.c397
1 files changed, 397 insertions, 0 deletions
diff --git a/drivers/pwm/pwm-stm32.c b/drivers/pwm/pwm-stm32.c
new file mode 100644
index 000000000000..6139512aab7b
--- /dev/null
+++ b/drivers/pwm/pwm-stm32.c
@@ -0,0 +1,397 @@
1/*
2 * Copyright (C) STMicroelectronics 2016
3 *
4 * Author: Gerald Baeza <gerald.baeza@st.com>
5 *
6 * License terms: GNU General Public License (GPL), version 2
7 *
8 * Inspired by timer-stm32.c from Maxime Coquelin
9 * pwm-atmel.c from Bo Shen
10 */
11
12#include <linux/mfd/stm32-timers.h>
13#include <linux/module.h>
14#include <linux/of.h>
15#include <linux/platform_device.h>
16#include <linux/pwm.h>
17
18#define CCMR_CHANNEL_SHIFT 8
19#define CCMR_CHANNEL_MASK 0xFF
20#define MAX_BREAKINPUT 2
21
22struct stm32_pwm {
23 struct pwm_chip chip;
24 struct device *dev;
25 struct clk *clk;
26 struct regmap *regmap;
27 u32 max_arr;
28 bool have_complementary_output;
29};
30
31struct stm32_breakinput {
32 u32 index;
33 u32 level;
34 u32 filter;
35};
36
37static inline struct stm32_pwm *to_stm32_pwm_dev(struct pwm_chip *chip)
38{
39 return container_of(chip, struct stm32_pwm, chip);
40}
41
42static u32 active_channels(struct stm32_pwm *dev)
43{
44 u32 ccer;
45
46 regmap_read(dev->regmap, TIM_CCER, &ccer);
47
48 return ccer & TIM_CCER_CCXE;
49}
50
51static int write_ccrx(struct stm32_pwm *dev, int ch, u32 value)
52{
53 switch (ch) {
54 case 0:
55 return regmap_write(dev->regmap, TIM_CCR1, value);
56 case 1:
57 return regmap_write(dev->regmap, TIM_CCR2, value);
58 case 2:
59 return regmap_write(dev->regmap, TIM_CCR3, value);
60 case 3:
61 return regmap_write(dev->regmap, TIM_CCR4, value);
62 }
63 return -EINVAL;
64}
65
66static int stm32_pwm_config(struct stm32_pwm *priv, int ch,
67 int duty_ns, int period_ns)
68{
69 unsigned long long prd, div, dty;
70 unsigned int prescaler = 0;
71 u32 ccmr, mask, shift;
72
73 /* Period and prescaler values depends on clock rate */
74 div = (unsigned long long)clk_get_rate(priv->clk) * period_ns;
75
76 do_div(div, NSEC_PER_SEC);
77 prd = div;
78
79 while (div > priv->max_arr) {
80 prescaler++;
81 div = prd;
82 do_div(div, prescaler + 1);
83 }
84
85 prd = div;
86
87 if (prescaler > MAX_TIM_PSC)
88 return -EINVAL;
89
90 /*
91 * All channels share the same prescaler and counter so when two
92 * channels are active at the same time we can't change them
93 */
94 if (active_channels(priv) & ~(1 << ch * 4)) {
95 u32 psc, arr;
96
97 regmap_read(priv->regmap, TIM_PSC, &psc);
98 regmap_read(priv->regmap, TIM_ARR, &arr);
99
100 if ((psc != prescaler) || (arr != prd - 1))
101 return -EBUSY;
102 }
103
104 regmap_write(priv->regmap, TIM_PSC, prescaler);
105 regmap_write(priv->regmap, TIM_ARR, prd - 1);
106 regmap_update_bits(priv->regmap, TIM_CR1, TIM_CR1_ARPE, TIM_CR1_ARPE);
107
108 /* Calculate the duty cycles */
109 dty = prd * duty_ns;
110 do_div(dty, period_ns);
111
112 write_ccrx(priv, ch, dty);
113
114 /* Configure output mode */
115 shift = (ch & 0x1) * CCMR_CHANNEL_SHIFT;
116 ccmr = (TIM_CCMR_PE | TIM_CCMR_M1) << shift;
117 mask = CCMR_CHANNEL_MASK << shift;
118
119 if (ch < 2)
120 regmap_update_bits(priv->regmap, TIM_CCMR1, mask, ccmr);
121 else
122 regmap_update_bits(priv->regmap, TIM_CCMR2, mask, ccmr);
123
124 regmap_update_bits(priv->regmap, TIM_BDTR,
125 TIM_BDTR_MOE | TIM_BDTR_AOE,
126 TIM_BDTR_MOE | TIM_BDTR_AOE);
127
128 return 0;
129}
130
131static int stm32_pwm_set_polarity(struct stm32_pwm *priv, int ch,
132 enum pwm_polarity polarity)
133{
134 u32 mask;
135
136 mask = TIM_CCER_CC1P << (ch * 4);
137 if (priv->have_complementary_output)
138 mask |= TIM_CCER_CC1NP << (ch * 4);
139
140 regmap_update_bits(priv->regmap, TIM_CCER, mask,
141 polarity == PWM_POLARITY_NORMAL ? 0 : mask);
142
143 return 0;
144}
145
146static int stm32_pwm_enable(struct stm32_pwm *priv, int ch)
147{
148 u32 mask;
149 int ret;
150
151 ret = clk_enable(priv->clk);
152 if (ret)
153 return ret;
154
155 /* Enable channel */
156 mask = TIM_CCER_CC1E << (ch * 4);
157 if (priv->have_complementary_output)
158 mask |= TIM_CCER_CC1NE << (ch * 4);
159
160 regmap_update_bits(priv->regmap, TIM_CCER, mask, mask);
161
162 /* Make sure that registers are updated */
163 regmap_update_bits(priv->regmap, TIM_EGR, TIM_EGR_UG, TIM_EGR_UG);
164
165 /* Enable controller */
166 regmap_update_bits(priv->regmap, TIM_CR1, TIM_CR1_CEN, TIM_CR1_CEN);
167
168 return 0;
169}
170
171static void stm32_pwm_disable(struct stm32_pwm *priv, int ch)
172{
173 u32 mask;
174
175 /* Disable channel */
176 mask = TIM_CCER_CC1E << (ch * 4);
177 if (priv->have_complementary_output)
178 mask |= TIM_CCER_CC1NE << (ch * 4);
179
180 regmap_update_bits(priv->regmap, TIM_CCER, mask, 0);
181
182 /* When all channels are disabled, we can disable the controller */
183 if (!active_channels(priv))
184 regmap_update_bits(priv->regmap, TIM_CR1, TIM_CR1_CEN, 0);
185
186 clk_disable(priv->clk);
187}
188
189static int stm32_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
190 struct pwm_state *state)
191{
192 bool enabled;
193 struct stm32_pwm *priv = to_stm32_pwm_dev(chip);
194 int ret;
195
196 enabled = pwm->state.enabled;
197
198 if (enabled && !state->enabled) {
199 stm32_pwm_disable(priv, pwm->hwpwm);
200 return 0;
201 }
202
203 if (state->polarity != pwm->state.polarity)
204 stm32_pwm_set_polarity(priv, pwm->hwpwm, state->polarity);
205
206 ret = stm32_pwm_config(priv, pwm->hwpwm,
207 state->duty_cycle, state->period);
208 if (ret)
209 return ret;
210
211 if (!enabled && state->enabled)
212 ret = stm32_pwm_enable(priv, pwm->hwpwm);
213
214 return ret;
215}
216
217static const struct pwm_ops stm32pwm_ops = {
218 .owner = THIS_MODULE,
219 .apply = stm32_pwm_apply,
220};
221
222static int stm32_pwm_set_breakinput(struct stm32_pwm *priv,
223 int index, int level, int filter)
224{
225 u32 bke = (index == 0) ? TIM_BDTR_BKE : TIM_BDTR_BK2E;
226 int shift = (index == 0) ? TIM_BDTR_BKF_SHIFT : TIM_BDTR_BK2F_SHIFT;
227 u32 mask = (index == 0) ? TIM_BDTR_BKE | TIM_BDTR_BKP | TIM_BDTR_BKF
228 : TIM_BDTR_BK2E | TIM_BDTR_BK2P | TIM_BDTR_BK2F;
229 u32 bdtr = bke;
230
231 /*
232 * The both bits could be set since only one will be wrote
233 * due to mask value.
234 */
235 if (level)
236 bdtr |= TIM_BDTR_BKP | TIM_BDTR_BK2P;
237
238 bdtr |= (filter & TIM_BDTR_BKF_MASK) << shift;
239
240 regmap_update_bits(priv->regmap, TIM_BDTR, mask, bdtr);
241
242 regmap_read(priv->regmap, TIM_BDTR, &bdtr);
243
244 return (bdtr & bke) ? 0 : -EINVAL;
245}
246
247static int stm32_pwm_apply_breakinputs(struct stm32_pwm *priv,
248 struct device_node *np)
249{
250 struct stm32_breakinput breakinput[MAX_BREAKINPUT];
251 int nb, ret, i, array_size;
252
253 nb = of_property_count_elems_of_size(np, "st,breakinput",
254 sizeof(struct stm32_breakinput));
255
256 /*
257 * Because "st,breakinput" parameter is optional do not make probe
258 * failed if it doesn't exist.
259 */
260 if (nb <= 0)
261 return 0;
262
263 if (nb > MAX_BREAKINPUT)
264 return -EINVAL;
265
266 array_size = nb * sizeof(struct stm32_breakinput) / sizeof(u32);
267 ret = of_property_read_u32_array(np, "st,breakinput",
268 (u32 *)breakinput, array_size);
269 if (ret)
270 return ret;
271
272 for (i = 0; i < nb && !ret; i++) {
273 ret = stm32_pwm_set_breakinput(priv,
274 breakinput[i].index,
275 breakinput[i].level,
276 breakinput[i].filter);
277 }
278
279 return ret;
280}
281
282static void stm32_pwm_detect_complementary(struct stm32_pwm *priv)
283{
284 u32 ccer;
285
286 /*
287 * If complementary bit doesn't exist writing 1 will have no
288 * effect so we can detect it.
289 */
290 regmap_update_bits(priv->regmap,
291 TIM_CCER, TIM_CCER_CC1NE, TIM_CCER_CC1NE);
292 regmap_read(priv->regmap, TIM_CCER, &ccer);
293 regmap_update_bits(priv->regmap, TIM_CCER, TIM_CCER_CC1NE, 0);
294
295 priv->have_complementary_output = (ccer != 0);
296}
297
298static int stm32_pwm_detect_channels(struct stm32_pwm *priv)
299{
300 u32 ccer;
301 int npwm = 0;
302
303 /*
304 * If channels enable bits don't exist writing 1 will have no
305 * effect so we can detect and count them.
306 */
307 regmap_update_bits(priv->regmap,
308 TIM_CCER, TIM_CCER_CCXE, TIM_CCER_CCXE);
309 regmap_read(priv->regmap, TIM_CCER, &ccer);
310 regmap_update_bits(priv->regmap, TIM_CCER, TIM_CCER_CCXE, 0);
311
312 if (ccer & TIM_CCER_CC1E)
313 npwm++;
314
315 if (ccer & TIM_CCER_CC2E)
316 npwm++;
317
318 if (ccer & TIM_CCER_CC3E)
319 npwm++;
320
321 if (ccer & TIM_CCER_CC4E)
322 npwm++;
323
324 return npwm;
325}
326
327static int stm32_pwm_probe(struct platform_device *pdev)
328{
329 struct device *dev = &pdev->dev;
330 struct device_node *np = dev->of_node;
331 struct stm32_timers *ddata = dev_get_drvdata(pdev->dev.parent);
332 struct stm32_pwm *priv;
333 int ret;
334
335 priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
336 if (!priv)
337 return -ENOMEM;
338
339 priv->regmap = ddata->regmap;
340 priv->clk = ddata->clk;
341 priv->max_arr = ddata->max_arr;
342
343 if (!priv->regmap || !priv->clk)
344 return -EINVAL;
345
346 ret = stm32_pwm_apply_breakinputs(priv, np);
347 if (ret)
348 return ret;
349
350 stm32_pwm_detect_complementary(priv);
351
352 priv->chip.base = -1;
353 priv->chip.dev = dev;
354 priv->chip.ops = &stm32pwm_ops;
355 priv->chip.npwm = stm32_pwm_detect_channels(priv);
356
357 ret = pwmchip_add(&priv->chip);
358 if (ret < 0)
359 return ret;
360
361 platform_set_drvdata(pdev, priv);
362
363 return 0;
364}
365
366static int stm32_pwm_remove(struct platform_device *pdev)
367{
368 struct stm32_pwm *priv = platform_get_drvdata(pdev);
369 unsigned int i;
370
371 for (i = 0; i < priv->chip.npwm; i++)
372 pwm_disable(&priv->chip.pwms[i]);
373
374 pwmchip_remove(&priv->chip);
375
376 return 0;
377}
378
379static const struct of_device_id stm32_pwm_of_match[] = {
380 { .compatible = "st,stm32-pwm", },
381 { /* end node */ },
382};
383MODULE_DEVICE_TABLE(of, stm32_pwm_of_match);
384
385static struct platform_driver stm32_pwm_driver = {
386 .probe = stm32_pwm_probe,
387 .remove = stm32_pwm_remove,
388 .driver = {
389 .name = "stm32-pwm",
390 .of_match_table = stm32_pwm_of_match,
391 },
392};
393module_platform_driver(stm32_pwm_driver);
394
395MODULE_ALIAS("platform:stm32-pwm");
396MODULE_DESCRIPTION("STMicroelectronics STM32 PWM driver");
397MODULE_LICENSE("GPL v2");