pwm: sti: Add new driver for ST's PWM IP
[linux-block.git] / drivers / pwm / pwm-sti.c
CommitLineData
378fe115
LJ
1/*
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 */
28
29/* Regfield IDs */
30enum {
31 PWMCLK_PRESCALE,
32 PWM_EN,
33 PWM_INT_EN,
34
35 /* Keep last */
36 MAX_REGFIELDS
37};
38
39struct sti_pwm_compat_data {
40 const struct reg_field *reg_fields;
41 unsigned int num_chan;
42 unsigned int max_pwm_cnt;
43 unsigned int max_prescale;
44};
45
46struct sti_pwm_chip {
47 struct device *dev;
48 struct clk *clk;
49 unsigned long clk_rate;
50 struct regmap *regmap;
51 struct sti_pwm_compat_data *cdata;
52 struct regmap_field *prescale;
53 struct regmap_field *pwm_en;
54 struct regmap_field *pwm_int_en;
55 unsigned long *pwm_periods;
56 struct pwm_chip chip;
57 void __iomem *mmio;
58};
59
60static const struct reg_field sti_pwm_regfields[MAX_REGFIELDS] = {
61 [PWMCLK_PRESCALE] = REG_FIELD(STI_PWMCR, 0, 3),
62 [PWM_EN] = REG_FIELD(STI_PWMCR, 9, 9),
63 [PWM_INT_EN] = REG_FIELD(STI_INTEN, 0, 0),
64};
65
66static inline struct sti_pwm_chip *to_sti_pwmchip(struct pwm_chip *chip)
67{
68 return container_of(chip, struct sti_pwm_chip, chip);
69}
70
71/*
72 * Calculate the period values supported by the PWM for the
73 * current clock rate.
74 */
75static void sti_pwm_calc_periods(struct sti_pwm_chip *pc)
76{
77 struct sti_pwm_compat_data *cdata = pc->cdata;
78 struct device *dev = pc->dev;
79 unsigned long val;
80 int i;
81
82 /*
83 * period_ns = (10^9 * (prescaler + 1) * (MAX_PWM_COUNT + 1)) / CLK_RATE
84 */
85 val = NSEC_PER_SEC / pc->clk_rate;
86 val *= cdata->max_pwm_cnt + 1;
87
88 dev_dbg(dev, "possible periods for clkrate[HZ]:%lu\n", pc->clk_rate);
89
90 for (i = 0; i <= cdata->max_prescale; i++) {
91 pc->pwm_periods[i] = val * (i + 1);
92 dev_dbg(dev, "prescale:%d, period[ns]:%lu\n",
93 i, pc->pwm_periods[i]);
94 }
95}
96
97static int sti_pwm_cmp_periods(const void *key, const void *elt)
98{
99 unsigned long i = *(unsigned long *)key;
100 unsigned long j = *(unsigned long *)elt;
101
102 if (i < j)
103 return -1;
104 else
105 return i == j ? 0 : 1;
106}
107
108/*
109 * For STiH4xx PWM IP, the PWM period is fixed to 256 local clock cycles.
110 * The only way to change the period (apart from changing the PWM input clock)
111 * is to change the PWM clock prescaler.
112 * The prescaler is of 4 bits, so only 16 prescaler values and hence only
113 * 16 possible period values are supported (for a particular clock rate).
114 * The requested period will be applied only if it matches one of these
115 * 16 values.
116 */
117static int sti_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
118 int duty_ns, int period_ns)
119{
120 struct sti_pwm_chip *pc = to_sti_pwmchip(chip);
121 struct sti_pwm_compat_data *cdata = pc->cdata;
122 struct device *dev = pc->dev;
123 unsigned int prescale, pwmvalx;
124 unsigned long *found;
125 int ret;
126
127 /*
128 * Search for matching period value. The corresponding index is our
129 * prescale value
130 */
131 found = bsearch(&period_ns, &pc->pwm_periods[0],
132 cdata->max_prescale + 1, sizeof(unsigned long),
133 sti_pwm_cmp_periods);
134 if (!found) {
135 dev_err(dev, "failed to find matching period\n");
136 return -EINVAL;
137 }
138
139 prescale = found - &pc->pwm_periods[0];
140
141 /*
142 * When PWMVal == 0, PWM pulse = 1 local clock cycle.
143 * When PWMVal == max_pwm_count,
144 * PWM pulse = (max_pwm_count + 1) local cycles,
145 * that is continuous pulse: signal never goes low.
146 */
147 pwmvalx = cdata->max_pwm_cnt * duty_ns / period_ns;
148
149 dev_dbg(dev, "prescale:%u, period:%i, duty:%i, pwmvalx:%u\n",
150 prescale, period_ns, duty_ns, pwmvalx);
151
152 /* Enable clock before writing to PWM registers */
153 ret = clk_enable(pc->clk);
154 if (ret)
155 return ret;
156
157 ret = regmap_field_write(pc->prescale, prescale);
158 if (ret)
159 goto clk_dis;
160
161 ret = regmap_write(pc->regmap, STI_PWMVAL(pwm->hwpwm), pwmvalx);
162 if (ret)
163 goto clk_dis;
164
165 ret = regmap_field_write(pc->pwm_int_en, 0);
166
167clk_dis:
168 clk_disable(pc->clk);
169 return ret;
170}
171
172static int sti_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
173{
174 struct sti_pwm_chip *pc = to_sti_pwmchip(chip);
175 struct device *dev = pc->dev;
176 int ret;
177
178 ret = clk_enable(pc->clk);
179 if (ret)
180 return ret;
181
182 ret = regmap_field_write(pc->pwm_en, 1);
183 if (ret)
184 dev_err(dev, "%s,pwm_en write failed\n", __func__);
185
186 return ret;
187}
188
189static void sti_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
190{
191 struct sti_pwm_chip *pc = to_sti_pwmchip(chip);
192 struct device *dev = pc->dev;
193 unsigned int val;
194
195 regmap_field_write(pc->pwm_en, 0);
196
197 regmap_read(pc->regmap, STI_CNT, &val);
198
199 dev_dbg(dev, "pwm counter :%u\n", val);
200
201 clk_disable(pc->clk);
202}
203
204static const struct pwm_ops sti_pwm_ops = {
205 .config = sti_pwm_config,
206 .enable = sti_pwm_enable,
207 .disable = sti_pwm_disable,
208 .owner = THIS_MODULE,
209};
210
211static int sti_pwm_probe_dt(struct sti_pwm_chip *pc)
212{
213 struct device *dev = pc->dev;
214 const struct reg_field *reg_fields;
215 struct device_node *np = dev->of_node;
216 struct sti_pwm_compat_data *cdata = pc->cdata;
217 u32 num_chan;
218
219 of_property_read_u32(np, "st,pwm-num-chan", &num_chan);
220 if (num_chan)
221 cdata->num_chan = num_chan;
222
223 reg_fields = cdata->reg_fields;
224
225 pc->prescale = devm_regmap_field_alloc(dev, pc->regmap,
226 reg_fields[PWMCLK_PRESCALE]);
227 if (IS_ERR(pc->prescale))
228 return PTR_ERR(pc->prescale);
229
230 pc->pwm_en = devm_regmap_field_alloc(dev, pc->regmap,
231 reg_fields[PWM_EN]);
232 if (IS_ERR(pc->pwm_en))
233 return PTR_ERR(pc->pwm_en);
234
235 pc->pwm_int_en = devm_regmap_field_alloc(dev, pc->regmap,
236 reg_fields[PWM_INT_EN]);
237 if (IS_ERR(pc->pwm_int_en))
238 return PTR_ERR(pc->pwm_int_en);
239
240 return 0;
241}
242
243static const struct regmap_config sti_pwm_regmap_config = {
244 .reg_bits = 32,
245 .val_bits = 32,
246 .reg_stride = 4,
247};
248
249static int sti_pwm_probe(struct platform_device *pdev)
250{
251 struct device *dev = &pdev->dev;
252 struct sti_pwm_compat_data *cdata;
253 struct sti_pwm_chip *pc;
254 struct resource *res;
255 int ret;
256
257 pc = devm_kzalloc(dev, sizeof(*pc), GFP_KERNEL);
258 if (!pc)
259 return -ENOMEM;
260
261 cdata = devm_kzalloc(dev, sizeof(*cdata), GFP_KERNEL);
262 if (!cdata)
263 return -ENOMEM;
264
265 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
266
267 pc->mmio = devm_ioremap_resource(dev, res);
268 if (IS_ERR(pc->mmio))
269 return PTR_ERR(pc->mmio);
270
271 pc->regmap = devm_regmap_init_mmio(dev, pc->mmio,
272 &sti_pwm_regmap_config);
273 if (IS_ERR(pc->regmap))
274 return PTR_ERR(pc->regmap);
275
276 /*
277 * Setup PWM data with default values: some values could be replaced
278 * with specific ones provided from Device Tree.
279 */
280 cdata->reg_fields = &sti_pwm_regfields[0];
281 cdata->max_prescale = 0xff;
282 cdata->max_pwm_cnt = 255;
283 cdata->num_chan = 1;
284
285 pc->cdata = cdata;
286 pc->dev = dev;
287
288 ret = sti_pwm_probe_dt(pc);
289 if (ret)
290 return ret;
291
292 pc->pwm_periods = devm_kzalloc(dev,
293 sizeof(unsigned long) * (pc->cdata->max_prescale + 1),
294 GFP_KERNEL);
295 if (!pc->pwm_periods)
296 return -ENOMEM;
297
298 pc->clk = of_clk_get_by_name(dev->of_node, "pwm");
299 if (IS_ERR(pc->clk)) {
300 dev_err(dev, "failed to get PWM clock\n");
301 return PTR_ERR(pc->clk);
302 }
303
304 pc->clk_rate = clk_get_rate(pc->clk);
305 if (!pc->clk_rate) {
306 dev_err(dev, "failed to get clock rate\n");
307 return -EINVAL;
308 }
309
310 ret = clk_prepare(pc->clk);
311 if (ret) {
312 dev_err(dev, "failed to prepare clock\n");
313 return ret;
314 }
315
316 sti_pwm_calc_periods(pc);
317
318 pc->chip.dev = dev;
319 pc->chip.ops = &sti_pwm_ops;
320 pc->chip.base = -1;
321 pc->chip.npwm = pc->cdata->num_chan;
322 pc->chip.can_sleep = true;
323
324 ret = pwmchip_add(&pc->chip);
325 if (ret < 0) {
326 clk_unprepare(pc->clk);
327 return ret;
328 }
329
330 platform_set_drvdata(pdev, pc);
331
332 return 0;
333}
334
335static int sti_pwm_remove(struct platform_device *pdev)
336{
337 struct sti_pwm_chip *pc = platform_get_drvdata(pdev);
338 unsigned int i;
339
340 for (i = 0; i < pc->cdata->num_chan; i++)
341 pwm_disable(&pc->chip.pwms[i]);
342
343 clk_unprepare(pc->clk);
344
345 return pwmchip_remove(&pc->chip);
346}
347
348static const struct of_device_id sti_pwm_of_match[] = {
349 { .compatible = "st,sti-pwm", },
350 { /* sentinel */ }
351};
352MODULE_DEVICE_TABLE(of, sti_pwm_of_match);
353
354static struct platform_driver sti_pwm_driver = {
355 .driver = {
356 .name = "sti-pwm",
357 .of_match_table = sti_pwm_of_match,
358 },
359 .probe = sti_pwm_probe,
360 .remove = sti_pwm_remove,
361};
362module_platform_driver(sti_pwm_driver);
363
364MODULE_AUTHOR("Ajit Pal Singh <ajitpal.singh@st.com>");
365MODULE_DESCRIPTION("STMicroelectronics ST PWM driver");
366MODULE_LICENSE("GPL");