]> Git Repo - linux.git/blob - drivers/pwm/pwm-omap-dmtimer.c
Merge tag 'percpu-for-6.8' of git://git.kernel.org/pub/scm/linux/kernel/git/dennis...
[linux.git] / drivers / pwm / pwm-omap-dmtimer.c
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Copyright (c) 2015 Neil Armstrong <[email protected]>
4  * Copyright (c) 2014 Joachim Eastwood <[email protected]>
5  * Copyright (c) 2012 NeilBrown <[email protected]>
6  * Heavily based on earlier code which is:
7  * Copyright (c) 2010 Grant Erickson <[email protected]>
8  *
9  * Also based on pwm-samsung.c
10  *
11  * Description:
12  *   This file is the core OMAP support for the generic, Linux
13  *   PWM driver / controller, using the OMAP's dual-mode timers
14  *   with a timer counter that goes up. When it overflows it gets
15  *   reloaded with the load value and the pwm output goes up.
16  *   When counter matches with match register, the output goes down.
17  *   Reference Manual: https://www.ti.com/lit/ug/spruh73q/spruh73q.pdf
18  *
19  * Limitations:
20  * - When PWM is stopped, timer counter gets stopped immediately. This
21  *   doesn't allow the current PWM period to complete and stops abruptly.
22  * - When PWM is running and changing both duty cycle and period,
23  *   we cannot prevent in software that the output might produce
24  *   a period with mixed settings. Especially when period/duty_cyle
25  *   is updated while the pwm pin is high, current pwm period/duty_cycle
26  *   can get updated as below based on the current timer counter:
27  *      - period for current cycle =  current_period + new period
28  *      - duty_cycle for current period = current period + new duty_cycle.
29  * - PWM OMAP DM timer cannot change the polarity when pwm is active. When
30  *   user requests a change in polarity when in active state:
31  *      - PWM is stopped abruptly(without completing the current cycle)
32  *      - Polarity is changed
33  *      - A fresh cycle is started.
34  */
35
36 #include <linux/clk.h>
37 #include <linux/err.h>
38 #include <linux/kernel.h>
39 #include <linux/module.h>
40 #include <linux/of.h>
41 #include <linux/of_platform.h>
42 #include <clocksource/timer-ti-dm.h>
43 #include <linux/platform_data/dmtimer-omap.h>
44 #include <linux/platform_device.h>
45 #include <linux/pm_runtime.h>
46 #include <linux/pwm.h>
47 #include <linux/slab.h>
48 #include <linux/time.h>
49
50 #define DM_TIMER_LOAD_MIN 0xfffffffe
51 #define DM_TIMER_MAX      0xffffffff
52
53 /**
54  * struct pwm_omap_dmtimer_chip - Structure representing a pwm chip
55  *                                corresponding to omap dmtimer.
56  * @chip:               PWM chip structure representing PWM controller
57  * @dm_timer:           Pointer to omap dm timer.
58  * @pdata:              Pointer to omap dm timer ops.
59  * @dm_timer_pdev:      Pointer to omap dm timer platform device
60  */
61 struct pwm_omap_dmtimer_chip {
62         struct pwm_chip chip;
63         /* Mutex to protect pwm apply state */
64         struct omap_dm_timer *dm_timer;
65         const struct omap_dm_timer_ops *pdata;
66         struct platform_device *dm_timer_pdev;
67 };
68
69 static inline struct pwm_omap_dmtimer_chip *
70 to_pwm_omap_dmtimer_chip(struct pwm_chip *chip)
71 {
72         return container_of(chip, struct pwm_omap_dmtimer_chip, chip);
73 }
74
75 /**
76  * pwm_omap_dmtimer_get_clock_cycles() - Get clock cycles in a time frame
77  * @clk_rate:   pwm timer clock rate
78  * @ns:         time frame in nano seconds.
79  *
80  * Return number of clock cycles in a given period(ins ns).
81  */
82 static u32 pwm_omap_dmtimer_get_clock_cycles(unsigned long clk_rate, int ns)
83 {
84         return DIV_ROUND_CLOSEST_ULL((u64)clk_rate * ns, NSEC_PER_SEC);
85 }
86
87 /**
88  * pwm_omap_dmtimer_start() - Start the pwm omap dm timer in pwm mode
89  * @omap:       Pointer to pwm omap dm timer chip
90  */
91 static void pwm_omap_dmtimer_start(struct pwm_omap_dmtimer_chip *omap)
92 {
93         /*
94          * According to OMAP 4 TRM section 22.2.4.10 the counter should be
95          * started at 0xFFFFFFFE when overflow and match is used to ensure
96          * that the PWM line is toggled on the first event.
97          *
98          * Note that omap_dm_timer_enable/disable is for register access and
99          * not the timer counter itself.
100          */
101         omap->pdata->enable(omap->dm_timer);
102         omap->pdata->write_counter(omap->dm_timer, DM_TIMER_LOAD_MIN);
103         omap->pdata->disable(omap->dm_timer);
104
105         omap->pdata->start(omap->dm_timer);
106 }
107
108 /**
109  * pwm_omap_dmtimer_is_enabled() -  Detect if the pwm is enabled.
110  * @omap:       Pointer to pwm omap dm timer chip
111  *
112  * Return true if pwm is enabled else false.
113  */
114 static bool pwm_omap_dmtimer_is_enabled(struct pwm_omap_dmtimer_chip *omap)
115 {
116         u32 status;
117
118         status = omap->pdata->get_pwm_status(omap->dm_timer);
119
120         return !!(status & OMAP_TIMER_CTRL_ST);
121 }
122
123 /**
124  * pwm_omap_dmtimer_polarity() -  Detect the polarity of pwm.
125  * @omap:       Pointer to pwm omap dm timer chip
126  *
127  * Return the polarity of pwm.
128  */
129 static int pwm_omap_dmtimer_polarity(struct pwm_omap_dmtimer_chip *omap)
130 {
131         u32 status;
132
133         status = omap->pdata->get_pwm_status(omap->dm_timer);
134
135         return !!(status & OMAP_TIMER_CTRL_SCPWM);
136 }
137
138 /**
139  * pwm_omap_dmtimer_config() - Update the configuration of pwm omap dm timer
140  * @chip:       Pointer to PWM controller
141  * @pwm:        Pointer to PWM channel
142  * @duty_ns:    New duty cycle in nano seconds
143  * @period_ns:  New period in nano seconds
144  *
145  * Return 0 if successfully changed the period/duty_cycle else appropriate
146  * error.
147  */
148 static int pwm_omap_dmtimer_config(struct pwm_chip *chip,
149                                    struct pwm_device *pwm,
150                                    int duty_ns, int period_ns)
151 {
152         struct pwm_omap_dmtimer_chip *omap = to_pwm_omap_dmtimer_chip(chip);
153         u32 period_cycles, duty_cycles;
154         u32 load_value, match_value;
155         unsigned long clk_rate;
156         struct clk *fclk;
157
158         dev_dbg(chip->dev, "requested duty cycle: %d ns, period: %d ns\n",
159                 duty_ns, period_ns);
160
161         if (duty_ns == pwm_get_duty_cycle(pwm) &&
162             period_ns == pwm_get_period(pwm))
163                 return 0;
164
165         fclk = omap->pdata->get_fclk(omap->dm_timer);
166         if (!fclk) {
167                 dev_err(chip->dev, "invalid pmtimer fclk\n");
168                 return -EINVAL;
169         }
170
171         clk_rate = clk_get_rate(fclk);
172         if (!clk_rate) {
173                 dev_err(chip->dev, "invalid pmtimer fclk rate\n");
174                 return -EINVAL;
175         }
176
177         dev_dbg(chip->dev, "clk rate: %luHz\n", clk_rate);
178
179         /*
180          * Calculate the appropriate load and match values based on the
181          * specified period and duty cycle. The load value determines the
182          * period time and the match value determines the duty time.
183          *
184          * The period lasts for (DM_TIMER_MAX-load_value+1) clock cycles.
185          * Similarly, the active time lasts (match_value-load_value+1) cycles.
186          * The non-active time is the remainder: (DM_TIMER_MAX-match_value)
187          * clock cycles.
188          *
189          * NOTE: It is required that: load_value <= match_value < DM_TIMER_MAX
190          *
191          * References:
192          *   OMAP4430/60/70 TRM sections 22.2.4.10 and 22.2.4.11
193          *   AM335x Sitara TRM sections 20.1.3.5 and 20.1.3.6
194          */
195         period_cycles = pwm_omap_dmtimer_get_clock_cycles(clk_rate, period_ns);
196         duty_cycles = pwm_omap_dmtimer_get_clock_cycles(clk_rate, duty_ns);
197
198         if (period_cycles < 2) {
199                 dev_info(chip->dev,
200                          "period %d ns too short for clock rate %lu Hz\n",
201                          period_ns, clk_rate);
202                 return -EINVAL;
203         }
204
205         if (duty_cycles < 1) {
206                 dev_dbg(chip->dev,
207                         "duty cycle %d ns is too short for clock rate %lu Hz\n",
208                         duty_ns, clk_rate);
209                 dev_dbg(chip->dev, "using minimum of 1 clock cycle\n");
210                 duty_cycles = 1;
211         } else if (duty_cycles >= period_cycles) {
212                 dev_dbg(chip->dev,
213                         "duty cycle %d ns is too long for period %d ns at clock rate %lu Hz\n",
214                         duty_ns, period_ns, clk_rate);
215                 dev_dbg(chip->dev, "using maximum of 1 clock cycle less than period\n");
216                 duty_cycles = period_cycles - 1;
217         }
218
219         dev_dbg(chip->dev, "effective duty cycle: %lld ns, period: %lld ns\n",
220                 DIV_ROUND_CLOSEST_ULL((u64)NSEC_PER_SEC * duty_cycles,
221                                       clk_rate),
222                 DIV_ROUND_CLOSEST_ULL((u64)NSEC_PER_SEC * period_cycles,
223                                       clk_rate));
224
225         load_value = (DM_TIMER_MAX - period_cycles) + 1;
226         match_value = load_value + duty_cycles - 1;
227
228         omap->pdata->set_load(omap->dm_timer, load_value);
229         omap->pdata->set_match(omap->dm_timer, true, match_value);
230
231         dev_dbg(chip->dev, "load value: %#08x (%d), match value: %#08x (%d)\n",
232                 load_value, load_value, match_value, match_value);
233
234         return 0;
235 }
236
237 /**
238  * pwm_omap_dmtimer_set_polarity() - Changes the polarity of the pwm dm timer.
239  * @chip:       Pointer to PWM controller
240  * @pwm:        Pointer to PWM channel
241  * @polarity:   New pwm polarity to be set
242  */
243 static void pwm_omap_dmtimer_set_polarity(struct pwm_chip *chip,
244                                           struct pwm_device *pwm,
245                                           enum pwm_polarity polarity)
246 {
247         struct pwm_omap_dmtimer_chip *omap = to_pwm_omap_dmtimer_chip(chip);
248         bool enabled;
249
250         /* Disable the PWM before changing the polarity. */
251         enabled = pwm_omap_dmtimer_is_enabled(omap);
252         if (enabled)
253                 omap->pdata->stop(omap->dm_timer);
254
255         omap->pdata->set_pwm(omap->dm_timer,
256                              polarity == PWM_POLARITY_INVERSED,
257                              true, OMAP_TIMER_TRIGGER_OVERFLOW_AND_COMPARE,
258                              true);
259
260         if (enabled)
261                 pwm_omap_dmtimer_start(omap);
262 }
263
264 /**
265  * pwm_omap_dmtimer_apply() - Changes the state of the pwm omap dm timer.
266  * @chip:       Pointer to PWM controller
267  * @pwm:        Pointer to PWM channel
268  * @state:      New state to apply
269  *
270  * Return 0 if successfully changed the state else appropriate error.
271  */
272 static int pwm_omap_dmtimer_apply(struct pwm_chip *chip,
273                                   struct pwm_device *pwm,
274                                   const struct pwm_state *state)
275 {
276         struct pwm_omap_dmtimer_chip *omap = to_pwm_omap_dmtimer_chip(chip);
277         int ret;
278
279         if (pwm_omap_dmtimer_is_enabled(omap) && !state->enabled) {
280                 omap->pdata->stop(omap->dm_timer);
281                 return 0;
282         }
283
284         if (pwm_omap_dmtimer_polarity(omap) != state->polarity)
285                 pwm_omap_dmtimer_set_polarity(chip, pwm, state->polarity);
286
287         ret = pwm_omap_dmtimer_config(chip, pwm, state->duty_cycle,
288                                       state->period);
289         if (ret)
290                 return ret;
291
292         if (!pwm_omap_dmtimer_is_enabled(omap) && state->enabled) {
293                 omap->pdata->set_pwm(omap->dm_timer,
294                                      state->polarity == PWM_POLARITY_INVERSED,
295                                      true,
296                                      OMAP_TIMER_TRIGGER_OVERFLOW_AND_COMPARE,
297                                      true);
298                 pwm_omap_dmtimer_start(omap);
299         }
300
301         return 0;
302 }
303
304 static const struct pwm_ops pwm_omap_dmtimer_ops = {
305         .apply = pwm_omap_dmtimer_apply,
306 };
307
308 static int pwm_omap_dmtimer_probe(struct platform_device *pdev)
309 {
310         struct device_node *np = pdev->dev.of_node;
311         struct dmtimer_platform_data *timer_pdata;
312         const struct omap_dm_timer_ops *pdata;
313         struct platform_device *timer_pdev;
314         struct pwm_omap_dmtimer_chip *omap;
315         struct omap_dm_timer *dm_timer;
316         struct device_node *timer;
317         int ret = 0;
318         u32 v;
319
320         timer = of_parse_phandle(np, "ti,timers", 0);
321         if (!timer)
322                 return -ENODEV;
323
324         timer_pdev = of_find_device_by_node(timer);
325         if (!timer_pdev) {
326                 dev_err(&pdev->dev, "Unable to find Timer pdev\n");
327                 ret = -ENODEV;
328                 goto err_find_timer_pdev;
329         }
330
331         timer_pdata = dev_get_platdata(&timer_pdev->dev);
332         if (!timer_pdata) {
333                 dev_dbg(&pdev->dev,
334                          "dmtimer pdata structure NULL, deferring probe\n");
335                 ret = -EPROBE_DEFER;
336                 goto err_platdata;
337         }
338
339         pdata = timer_pdata->timer_ops;
340
341         if (!pdata || !pdata->request_by_node ||
342             !pdata->free ||
343             !pdata->enable ||
344             !pdata->disable ||
345             !pdata->get_fclk ||
346             !pdata->start ||
347             !pdata->stop ||
348             !pdata->set_load ||
349             !pdata->set_match ||
350             !pdata->set_pwm ||
351             !pdata->get_pwm_status ||
352             !pdata->set_prescaler ||
353             !pdata->write_counter) {
354                 dev_err(&pdev->dev, "Incomplete dmtimer pdata structure\n");
355                 ret = -EINVAL;
356                 goto err_platdata;
357         }
358
359         if (!of_get_property(timer, "ti,timer-pwm", NULL)) {
360                 dev_err(&pdev->dev, "Missing ti,timer-pwm capability\n");
361                 ret = -ENODEV;
362                 goto err_timer_property;
363         }
364
365         dm_timer = pdata->request_by_node(timer);
366         if (!dm_timer) {
367                 ret = -EPROBE_DEFER;
368                 goto err_request_timer;
369         }
370
371         omap = devm_kzalloc(&pdev->dev, sizeof(*omap), GFP_KERNEL);
372         if (!omap) {
373                 ret = -ENOMEM;
374                 goto err_alloc_omap;
375         }
376
377         omap->pdata = pdata;
378         omap->dm_timer = dm_timer;
379         omap->dm_timer_pdev = timer_pdev;
380
381         /*
382          * Ensure that the timer is stopped before we allow PWM core to call
383          * pwm_enable.
384          */
385         if (pm_runtime_active(&omap->dm_timer_pdev->dev))
386                 omap->pdata->stop(omap->dm_timer);
387
388         if (!of_property_read_u32(pdev->dev.of_node, "ti,prescaler", &v))
389                 omap->pdata->set_prescaler(omap->dm_timer, v);
390
391         /* setup dmtimer clock source */
392         if (!of_property_read_u32(pdev->dev.of_node, "ti,clock-source", &v))
393                 omap->pdata->set_source(omap->dm_timer, v);
394
395         omap->chip.dev = &pdev->dev;
396         omap->chip.ops = &pwm_omap_dmtimer_ops;
397         omap->chip.npwm = 1;
398
399         ret = pwmchip_add(&omap->chip);
400         if (ret < 0) {
401                 dev_err(&pdev->dev, "failed to register PWM\n");
402                 goto err_pwmchip_add;
403         }
404
405         of_node_put(timer);
406
407         platform_set_drvdata(pdev, omap);
408
409         return 0;
410
411 err_pwmchip_add:
412
413         /*
414          * *omap is allocated using devm_kzalloc,
415          * so no free necessary here
416          */
417 err_alloc_omap:
418
419         pdata->free(dm_timer);
420 err_request_timer:
421
422 err_timer_property:
423 err_platdata:
424
425         put_device(&timer_pdev->dev);
426 err_find_timer_pdev:
427
428         of_node_put(timer);
429
430         return ret;
431 }
432
433 static void pwm_omap_dmtimer_remove(struct platform_device *pdev)
434 {
435         struct pwm_omap_dmtimer_chip *omap = platform_get_drvdata(pdev);
436
437         pwmchip_remove(&omap->chip);
438
439         if (pm_runtime_active(&omap->dm_timer_pdev->dev))
440                 omap->pdata->stop(omap->dm_timer);
441
442         omap->pdata->free(omap->dm_timer);
443
444         put_device(&omap->dm_timer_pdev->dev);
445 }
446
447 static const struct of_device_id pwm_omap_dmtimer_of_match[] = {
448         {.compatible = "ti,omap-dmtimer-pwm"},
449         {}
450 };
451 MODULE_DEVICE_TABLE(of, pwm_omap_dmtimer_of_match);
452
453 static struct platform_driver pwm_omap_dmtimer_driver = {
454         .driver = {
455                 .name = "omap-dmtimer-pwm",
456                 .of_match_table = pwm_omap_dmtimer_of_match,
457         },
458         .probe = pwm_omap_dmtimer_probe,
459         .remove_new = pwm_omap_dmtimer_remove,
460 };
461 module_platform_driver(pwm_omap_dmtimer_driver);
462
463 MODULE_AUTHOR("Grant Erickson <[email protected]>");
464 MODULE_AUTHOR("NeilBrown <[email protected]>");
465 MODULE_AUTHOR("Neil Armstrong <[email protected]>");
466 MODULE_LICENSE("GPL v2");
467 MODULE_DESCRIPTION("OMAP PWM Driver using Dual-mode Timers");
This page took 0.060701 seconds and 4 git commands to generate.