Lines Matching +full:omap +full:- +full:dmtimer +full:- +full:pwm

1 // SPDX-License-Identifier: GPL-2.0-only
9 * Also based on pwm-samsung.c
12 * This file is the core OMAP support for the generic, Linux
13 * PWM driver / controller, using the OMAP's dual-mode timers
15 * reloaded with the load value and the pwm output goes up.
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,
25 * is updated while the pwm pin is high, current pwm period/duty_cycle
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
31 * - PWM is stopped abruptly(without completing the current cycle)
32 * - Polarity is changed
33 * - A fresh cycle is started.
42 #include <clocksource/timer-ti-dm.h>
43 #include <linux/platform_data/dmtimer-omap.h>
46 #include <linux/pwm.h>
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
63 /* Mutex to protect pwm apply state */
76 * pwm_omap_dmtimer_get_clock_cycles() - Get clock cycles in a time frame
77 * @clk_rate: pwm timer clock rate
88 * pwm_omap_dmtimer_start() - Start the pwm omap dm timer in pwm mode
89 * @omap: Pointer to pwm omap dm timer chip
91 static void pwm_omap_dmtimer_start(struct pwm_omap_dmtimer_chip *omap) in pwm_omap_dmtimer_start() argument
94 * According to OMAP 4 TRM section 22.2.4.10 the counter should be in pwm_omap_dmtimer_start()
96 * that the PWM line is toggled on the first event. in pwm_omap_dmtimer_start()
101 omap->pdata->enable(omap->dm_timer); in pwm_omap_dmtimer_start()
102 omap->pdata->write_counter(omap->dm_timer, DM_TIMER_LOAD_MIN); in pwm_omap_dmtimer_start()
103 omap->pdata->disable(omap->dm_timer); in pwm_omap_dmtimer_start()
105 omap->pdata->start(omap->dm_timer); in pwm_omap_dmtimer_start()
109 * pwm_omap_dmtimer_is_enabled() - Detect if the pwm is enabled.
110 * @omap: Pointer to pwm omap dm timer chip
112 * Return true if pwm is enabled else false.
114 static bool pwm_omap_dmtimer_is_enabled(struct pwm_omap_dmtimer_chip *omap) in pwm_omap_dmtimer_is_enabled() argument
118 status = omap->pdata->get_pwm_status(omap->dm_timer); in pwm_omap_dmtimer_is_enabled()
124 * pwm_omap_dmtimer_polarity() - Detect the polarity of pwm.
125 * @omap: Pointer to pwm omap dm timer chip
127 * Return the polarity of pwm.
129 static int pwm_omap_dmtimer_polarity(struct pwm_omap_dmtimer_chip *omap) in pwm_omap_dmtimer_polarity() argument
133 status = omap->pdata->get_pwm_status(omap->dm_timer); in pwm_omap_dmtimer_polarity()
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
149 struct pwm_device *pwm, in pwm_omap_dmtimer_config() argument
152 struct pwm_omap_dmtimer_chip *omap = to_pwm_omap_dmtimer_chip(chip); in pwm_omap_dmtimer_config() local
158 dev_dbg(chip->dev, "requested duty cycle: %d ns, period: %d ns\n", in pwm_omap_dmtimer_config()
161 if (duty_ns == pwm_get_duty_cycle(pwm) && in pwm_omap_dmtimer_config()
162 period_ns == pwm_get_period(pwm)) in pwm_omap_dmtimer_config()
165 fclk = omap->pdata->get_fclk(omap->dm_timer); in pwm_omap_dmtimer_config()
167 dev_err(chip->dev, "invalid pmtimer fclk\n"); in pwm_omap_dmtimer_config()
168 return -EINVAL; in pwm_omap_dmtimer_config()
173 dev_err(chip->dev, "invalid pmtimer fclk rate\n"); in pwm_omap_dmtimer_config()
174 return -EINVAL; in pwm_omap_dmtimer_config()
177 dev_dbg(chip->dev, "clk rate: %luHz\n", clk_rate); in pwm_omap_dmtimer_config()
184 * The period lasts for (DM_TIMER_MAX-load_value+1) clock cycles. in pwm_omap_dmtimer_config()
185 * Similarly, the active time lasts (match_value-load_value+1) cycles. in pwm_omap_dmtimer_config()
186 * The non-active time is the remainder: (DM_TIMER_MAX-match_value) in pwm_omap_dmtimer_config()
199 dev_info(chip->dev, in pwm_omap_dmtimer_config()
202 return -EINVAL; in pwm_omap_dmtimer_config()
206 dev_dbg(chip->dev, in pwm_omap_dmtimer_config()
209 dev_dbg(chip->dev, "using minimum of 1 clock cycle\n"); in pwm_omap_dmtimer_config()
212 dev_dbg(chip->dev, in pwm_omap_dmtimer_config()
215 dev_dbg(chip->dev, "using maximum of 1 clock cycle less than period\n"); in pwm_omap_dmtimer_config()
216 duty_cycles = period_cycles - 1; in pwm_omap_dmtimer_config()
219 dev_dbg(chip->dev, "effective duty cycle: %lld ns, period: %lld ns\n", in pwm_omap_dmtimer_config()
225 load_value = (DM_TIMER_MAX - period_cycles) + 1; in pwm_omap_dmtimer_config()
226 match_value = load_value + duty_cycles - 1; in pwm_omap_dmtimer_config()
228 omap->pdata->set_load(omap->dm_timer, load_value); in pwm_omap_dmtimer_config()
229 omap->pdata->set_match(omap->dm_timer, true, match_value); in pwm_omap_dmtimer_config()
231 dev_dbg(chip->dev, "load value: %#08x (%d), match value: %#08x (%d)\n", in pwm_omap_dmtimer_config()
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
244 struct pwm_device *pwm, in pwm_omap_dmtimer_set_polarity() argument
247 struct pwm_omap_dmtimer_chip *omap = to_pwm_omap_dmtimer_chip(chip); in pwm_omap_dmtimer_set_polarity() local
250 /* Disable the PWM before changing the polarity. */ in pwm_omap_dmtimer_set_polarity()
251 enabled = pwm_omap_dmtimer_is_enabled(omap); in pwm_omap_dmtimer_set_polarity()
253 omap->pdata->stop(omap->dm_timer); in pwm_omap_dmtimer_set_polarity()
255 omap->pdata->set_pwm(omap->dm_timer, in pwm_omap_dmtimer_set_polarity()
261 pwm_omap_dmtimer_start(omap); in pwm_omap_dmtimer_set_polarity()
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
273 struct pwm_device *pwm, in pwm_omap_dmtimer_apply() argument
276 struct pwm_omap_dmtimer_chip *omap = to_pwm_omap_dmtimer_chip(chip); in pwm_omap_dmtimer_apply() local
279 if (pwm_omap_dmtimer_is_enabled(omap) && !state->enabled) { in pwm_omap_dmtimer_apply()
280 omap->pdata->stop(omap->dm_timer); in pwm_omap_dmtimer_apply()
284 if (pwm_omap_dmtimer_polarity(omap) != state->polarity) in pwm_omap_dmtimer_apply()
285 pwm_omap_dmtimer_set_polarity(chip, pwm, state->polarity); in pwm_omap_dmtimer_apply()
287 ret = pwm_omap_dmtimer_config(chip, pwm, state->duty_cycle, in pwm_omap_dmtimer_apply()
288 state->period); in pwm_omap_dmtimer_apply()
292 if (!pwm_omap_dmtimer_is_enabled(omap) && state->enabled) { in pwm_omap_dmtimer_apply()
293 omap->pdata->set_pwm(omap->dm_timer, in pwm_omap_dmtimer_apply()
294 state->polarity == PWM_POLARITY_INVERSED, in pwm_omap_dmtimer_apply()
298 pwm_omap_dmtimer_start(omap); in pwm_omap_dmtimer_apply()
310 struct device_node *np = pdev->dev.of_node; in pwm_omap_dmtimer_probe()
314 struct pwm_omap_dmtimer_chip *omap; in pwm_omap_dmtimer_probe() local
322 return -ENODEV; in pwm_omap_dmtimer_probe()
326 dev_err(&pdev->dev, "Unable to find Timer pdev\n"); in pwm_omap_dmtimer_probe()
327 ret = -ENODEV; in pwm_omap_dmtimer_probe()
331 timer_pdata = dev_get_platdata(&timer_pdev->dev); in pwm_omap_dmtimer_probe()
333 dev_dbg(&pdev->dev, in pwm_omap_dmtimer_probe()
334 "dmtimer pdata structure NULL, deferring probe\n"); in pwm_omap_dmtimer_probe()
335 ret = -EPROBE_DEFER; in pwm_omap_dmtimer_probe()
339 pdata = timer_pdata->timer_ops; in pwm_omap_dmtimer_probe()
341 if (!pdata || !pdata->request_by_node || in pwm_omap_dmtimer_probe()
342 !pdata->free || in pwm_omap_dmtimer_probe()
343 !pdata->enable || in pwm_omap_dmtimer_probe()
344 !pdata->disable || in pwm_omap_dmtimer_probe()
345 !pdata->get_fclk || in pwm_omap_dmtimer_probe()
346 !pdata->start || in pwm_omap_dmtimer_probe()
347 !pdata->stop || in pwm_omap_dmtimer_probe()
348 !pdata->set_load || in pwm_omap_dmtimer_probe()
349 !pdata->set_match || in pwm_omap_dmtimer_probe()
350 !pdata->set_pwm || in pwm_omap_dmtimer_probe()
351 !pdata->get_pwm_status || in pwm_omap_dmtimer_probe()
352 !pdata->set_prescaler || in pwm_omap_dmtimer_probe()
353 !pdata->write_counter) { in pwm_omap_dmtimer_probe()
354 dev_err(&pdev->dev, "Incomplete dmtimer pdata structure\n"); in pwm_omap_dmtimer_probe()
355 ret = -EINVAL; in pwm_omap_dmtimer_probe()
359 if (!of_get_property(timer, "ti,timer-pwm", NULL)) { in pwm_omap_dmtimer_probe()
360 dev_err(&pdev->dev, "Missing ti,timer-pwm capability\n"); in pwm_omap_dmtimer_probe()
361 ret = -ENODEV; in pwm_omap_dmtimer_probe()
365 dm_timer = pdata->request_by_node(timer); in pwm_omap_dmtimer_probe()
367 ret = -EPROBE_DEFER; in pwm_omap_dmtimer_probe()
371 omap = devm_kzalloc(&pdev->dev, sizeof(*omap), GFP_KERNEL); in pwm_omap_dmtimer_probe()
372 if (!omap) { in pwm_omap_dmtimer_probe()
373 ret = -ENOMEM; in pwm_omap_dmtimer_probe()
377 omap->pdata = pdata; in pwm_omap_dmtimer_probe()
378 omap->dm_timer = dm_timer; in pwm_omap_dmtimer_probe()
379 omap->dm_timer_pdev = timer_pdev; in pwm_omap_dmtimer_probe()
382 * Ensure that the timer is stopped before we allow PWM core to call in pwm_omap_dmtimer_probe()
385 if (pm_runtime_active(&omap->dm_timer_pdev->dev)) in pwm_omap_dmtimer_probe()
386 omap->pdata->stop(omap->dm_timer); in pwm_omap_dmtimer_probe()
388 if (!of_property_read_u32(pdev->dev.of_node, "ti,prescaler", &v)) in pwm_omap_dmtimer_probe()
389 omap->pdata->set_prescaler(omap->dm_timer, v); in pwm_omap_dmtimer_probe()
391 /* setup dmtimer clock source */ in pwm_omap_dmtimer_probe()
392 if (!of_property_read_u32(pdev->dev.of_node, "ti,clock-source", &v)) in pwm_omap_dmtimer_probe()
393 omap->pdata->set_source(omap->dm_timer, v); in pwm_omap_dmtimer_probe()
395 omap->chip.dev = &pdev->dev; in pwm_omap_dmtimer_probe()
396 omap->chip.ops = &pwm_omap_dmtimer_ops; in pwm_omap_dmtimer_probe()
397 omap->chip.npwm = 1; in pwm_omap_dmtimer_probe()
399 ret = pwmchip_add(&omap->chip); in pwm_omap_dmtimer_probe()
401 dev_err(&pdev->dev, "failed to register PWM\n"); in pwm_omap_dmtimer_probe()
407 platform_set_drvdata(pdev, omap); in pwm_omap_dmtimer_probe()
414 * *omap is allocated using devm_kzalloc, in pwm_omap_dmtimer_probe()
419 pdata->free(dm_timer); in pwm_omap_dmtimer_probe()
425 put_device(&timer_pdev->dev); in pwm_omap_dmtimer_probe()
435 struct pwm_omap_dmtimer_chip *omap = platform_get_drvdata(pdev); in pwm_omap_dmtimer_remove() local
437 pwmchip_remove(&omap->chip); in pwm_omap_dmtimer_remove()
439 if (pm_runtime_active(&omap->dm_timer_pdev->dev)) in pwm_omap_dmtimer_remove()
440 omap->pdata->stop(omap->dm_timer); in pwm_omap_dmtimer_remove()
442 omap->pdata->free(omap->dm_timer); in pwm_omap_dmtimer_remove()
444 put_device(&omap->dm_timer_pdev->dev); in pwm_omap_dmtimer_remove()
448 {.compatible = "ti,omap-dmtimer-pwm"},
455 .name = "omap-dmtimer-pwm",
467 MODULE_DESCRIPTION("OMAP PWM Driver using Dual-mode Timers");