Lines Matching +full:timer +full:- +full:pwm
1 // SPDX-License-Identifier: GPL-2.0-only
21 #include <linux/pwm.h>
36 unsigned div; /* PWM clock divider */
37 unsigned duty; /* PWM duty expressed in clk cycles */
38 unsigned period; /* PWM period expressed in clk cycles */
69 struct pwm_device *pwm) in atmel_tcb_pwm_request() argument
72 struct atmel_tcb_pwm_device *tcbpwm = &tcbpwmc->pwms[pwm->hwpwm]; in atmel_tcb_pwm_request()
76 ret = clk_prepare_enable(tcbpwmc->clk); in atmel_tcb_pwm_request()
80 tcbpwm->duty = 0; in atmel_tcb_pwm_request()
81 tcbpwm->period = 0; in atmel_tcb_pwm_request()
82 tcbpwm->div = 0; in atmel_tcb_pwm_request()
84 guard(spinlock)(&tcbpwmc->lock); in atmel_tcb_pwm_request()
86 regmap_read(tcbpwmc->regmap, ATMEL_TC_REG(tcbpwmc->channel, CMR), &cmr); in atmel_tcb_pwm_request()
88 * Get init config from Timer Counter registers if in atmel_tcb_pwm_request()
89 * Timer Counter is already configured as a PWM generator. in atmel_tcb_pwm_request()
92 if (pwm->hwpwm == 0) in atmel_tcb_pwm_request()
93 regmap_read(tcbpwmc->regmap, in atmel_tcb_pwm_request()
94 ATMEL_TC_REG(tcbpwmc->channel, RA), in atmel_tcb_pwm_request()
95 &tcbpwm->duty); in atmel_tcb_pwm_request()
97 regmap_read(tcbpwmc->regmap, in atmel_tcb_pwm_request()
98 ATMEL_TC_REG(tcbpwmc->channel, RB), in atmel_tcb_pwm_request()
99 &tcbpwm->duty); in atmel_tcb_pwm_request()
101 tcbpwm->div = cmr & ATMEL_TC_TCCLKS; in atmel_tcb_pwm_request()
102 regmap_read(tcbpwmc->regmap, ATMEL_TC_REG(tcbpwmc->channel, RC), in atmel_tcb_pwm_request()
103 &tcbpwm->period); in atmel_tcb_pwm_request()
110 regmap_write(tcbpwmc->regmap, ATMEL_TC_REG(tcbpwmc->channel, CMR), cmr); in atmel_tcb_pwm_request()
115 static void atmel_tcb_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm) in atmel_tcb_pwm_free() argument
119 clk_disable_unprepare(tcbpwmc->clk); in atmel_tcb_pwm_free()
122 static void atmel_tcb_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm, in atmel_tcb_pwm_disable() argument
126 struct atmel_tcb_pwm_device *tcbpwm = &tcbpwmc->pwms[pwm->hwpwm]; in atmel_tcb_pwm_disable()
130 * If duty is 0 the timer will be stopped and we have to in atmel_tcb_pwm_disable()
132 * - set output to high if PWM_POLARITY_INVERSED in atmel_tcb_pwm_disable()
133 * - set output to low if PWM_POLARITY_NORMAL in atmel_tcb_pwm_disable()
137 if (tcbpwm->duty == 0) in atmel_tcb_pwm_disable()
140 regmap_read(tcbpwmc->regmap, ATMEL_TC_REG(tcbpwmc->channel, CMR), &cmr); in atmel_tcb_pwm_disable()
143 if (pwm->hwpwm == 0) { in atmel_tcb_pwm_disable()
157 regmap_write(tcbpwmc->regmap, ATMEL_TC_REG(tcbpwmc->channel, CMR), cmr); in atmel_tcb_pwm_disable()
161 * If both PWM devices in this group are disabled we stop the clock. in atmel_tcb_pwm_disable()
164 regmap_write(tcbpwmc->regmap, in atmel_tcb_pwm_disable()
165 ATMEL_TC_REG(tcbpwmc->channel, CCR), in atmel_tcb_pwm_disable()
167 tcbpwmc->bkup.enabled = 1; in atmel_tcb_pwm_disable()
169 regmap_write(tcbpwmc->regmap, in atmel_tcb_pwm_disable()
170 ATMEL_TC_REG(tcbpwmc->channel, CCR), in atmel_tcb_pwm_disable()
172 tcbpwmc->bkup.enabled = 0; in atmel_tcb_pwm_disable()
176 static int atmel_tcb_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm, in atmel_tcb_pwm_enable() argument
180 struct atmel_tcb_pwm_device *tcbpwm = &tcbpwmc->pwms[pwm->hwpwm]; in atmel_tcb_pwm_enable()
184 * If duty is 0 the timer will be stopped and we have to in atmel_tcb_pwm_enable()
186 * - set output to high if PWM_POLARITY_INVERSED in atmel_tcb_pwm_enable()
187 * - set output to low if PWM_POLARITY_NORMAL in atmel_tcb_pwm_enable()
191 if (tcbpwm->duty == 0) in atmel_tcb_pwm_enable()
194 regmap_read(tcbpwmc->regmap, ATMEL_TC_REG(tcbpwmc->channel, CMR), &cmr); in atmel_tcb_pwm_enable()
199 if (pwm->hwpwm == 0) { in atmel_tcb_pwm_enable()
221 if (tcbpwm->duty != tcbpwm->period && tcbpwm->duty > 0) { in atmel_tcb_pwm_enable()
222 if (pwm->hwpwm == 0) { in atmel_tcb_pwm_enable()
235 cmr |= (tcbpwm->div & ATMEL_TC_TCCLKS); in atmel_tcb_pwm_enable()
237 regmap_write(tcbpwmc->regmap, ATMEL_TC_REG(tcbpwmc->channel, CMR), cmr); in atmel_tcb_pwm_enable()
239 if (pwm->hwpwm == 0) in atmel_tcb_pwm_enable()
240 regmap_write(tcbpwmc->regmap, in atmel_tcb_pwm_enable()
241 ATMEL_TC_REG(tcbpwmc->channel, RA), in atmel_tcb_pwm_enable()
242 tcbpwm->duty); in atmel_tcb_pwm_enable()
244 regmap_write(tcbpwmc->regmap, in atmel_tcb_pwm_enable()
245 ATMEL_TC_REG(tcbpwmc->channel, RB), in atmel_tcb_pwm_enable()
246 tcbpwm->duty); in atmel_tcb_pwm_enable()
248 regmap_write(tcbpwmc->regmap, ATMEL_TC_REG(tcbpwmc->channel, RC), in atmel_tcb_pwm_enable()
249 tcbpwm->period); in atmel_tcb_pwm_enable()
252 regmap_write(tcbpwmc->regmap, ATMEL_TC_REG(tcbpwmc->channel, CCR), in atmel_tcb_pwm_enable()
254 tcbpwmc->bkup.enabled = 1; in atmel_tcb_pwm_enable()
258 static int atmel_tcb_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, in atmel_tcb_pwm_config() argument
262 struct atmel_tcb_pwm_device *tcbpwm = &tcbpwmc->pwms[pwm->hwpwm]; in atmel_tcb_pwm_config()
263 /* companion PWM sharing register values period and div */ in atmel_tcb_pwm_config()
264 struct atmel_tcb_pwm_device *atcbpwm = &tcbpwmc->pwms[pwm->hwpwm ^ 1]; in atmel_tcb_pwm_config()
269 unsigned rate = clk_get_rate(tcbpwmc->clk); in atmel_tcb_pwm_config()
278 if (tcbpwmc->gclk) in atmel_tcb_pwm_config()
286 max = min << tcbpwmc->width; in atmel_tcb_pwm_config()
297 rate = clk_get_rate(tcbpwmc->slow_clk); in atmel_tcb_pwm_config()
299 max = min << tcbpwmc->width; in atmel_tcb_pwm_config()
303 return -ERANGE; in atmel_tcb_pwm_config()
310 * PWM devices provided by the TCB driver are grouped by 2. in atmel_tcb_pwm_config()
311 * PWM devices in a given group must be configured with the in atmel_tcb_pwm_config()
314 * We're checking the period value of the second PWM device in atmel_tcb_pwm_config()
317 if ((atcbpwm->duty > 0 && atcbpwm->duty != atcbpwm->period) && in atmel_tcb_pwm_config()
318 (atcbpwm->div != i || atcbpwm->period != period)) { in atmel_tcb_pwm_config()
320 "failed to configure period_ns: PWM group already configured with a different value\n"); in atmel_tcb_pwm_config()
321 return -EINVAL; in atmel_tcb_pwm_config()
324 tcbpwm->period = period; in atmel_tcb_pwm_config()
325 tcbpwm->div = i; in atmel_tcb_pwm_config()
326 tcbpwm->duty = duty; in atmel_tcb_pwm_config()
331 static int atmel_tcb_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, in atmel_tcb_pwm_apply() argument
338 guard(spinlock)(&tcbpwmc->lock); in atmel_tcb_pwm_apply()
340 if (!state->enabled) { in atmel_tcb_pwm_apply()
341 atmel_tcb_pwm_disable(chip, pwm, state->polarity); in atmel_tcb_pwm_apply()
345 period = state->period < INT_MAX ? state->period : INT_MAX; in atmel_tcb_pwm_apply()
346 duty_cycle = state->duty_cycle < INT_MAX ? state->duty_cycle : INT_MAX; in atmel_tcb_pwm_apply()
348 ret = atmel_tcb_pwm_config(chip, pwm, duty_cycle, period); in atmel_tcb_pwm_apply()
352 return atmel_tcb_pwm_enable(chip, pwm, state->polarity); in atmel_tcb_pwm_apply()
375 { .compatible = "atmel,at91rm9200-tcb", .data = &tcb_rm9200_config, },
376 { .compatible = "atmel,at91sam9x5-tcb", .data = &tcb_sam9x5_config, },
377 { .compatible = "atmel,sama5d2-tcb", .data = &tcb_sama5d2_config, },
387 struct device_node *np = pdev->dev.of_node; in atmel_tcb_pwm_probe()
392 chip = devm_pwmchip_alloc(&pdev->dev, NPWM, sizeof(*tcbpwmc)); in atmel_tcb_pwm_probe()
399 dev_err(&pdev->dev, in atmel_tcb_pwm_probe()
400 "failed to get Timer Counter Block channel from device tree (error: %d)\n", in atmel_tcb_pwm_probe()
405 tcbpwmc->regmap = syscon_node_to_regmap(np->parent); in atmel_tcb_pwm_probe()
406 if (IS_ERR(tcbpwmc->regmap)) in atmel_tcb_pwm_probe()
407 return PTR_ERR(tcbpwmc->regmap); in atmel_tcb_pwm_probe()
409 tcbpwmc->slow_clk = of_clk_get_by_name(np->parent, "slow_clk"); in atmel_tcb_pwm_probe()
410 if (IS_ERR(tcbpwmc->slow_clk)) in atmel_tcb_pwm_probe()
411 return PTR_ERR(tcbpwmc->slow_clk); in atmel_tcb_pwm_probe()
414 tcbpwmc->clk = of_clk_get_by_name(np->parent, clk_name); in atmel_tcb_pwm_probe()
415 if (IS_ERR(tcbpwmc->clk)) in atmel_tcb_pwm_probe()
416 tcbpwmc->clk = of_clk_get_by_name(np->parent, "t0_clk"); in atmel_tcb_pwm_probe()
417 if (IS_ERR(tcbpwmc->clk)) { in atmel_tcb_pwm_probe()
418 err = PTR_ERR(tcbpwmc->clk); in atmel_tcb_pwm_probe()
422 match = of_match_node(atmel_tcb_of_match, np->parent); in atmel_tcb_pwm_probe()
423 config = match->data; in atmel_tcb_pwm_probe()
425 if (config->has_gclk) { in atmel_tcb_pwm_probe()
426 tcbpwmc->gclk = of_clk_get_by_name(np->parent, "gclk"); in atmel_tcb_pwm_probe()
427 if (IS_ERR(tcbpwmc->gclk)) { in atmel_tcb_pwm_probe()
428 err = PTR_ERR(tcbpwmc->gclk); in atmel_tcb_pwm_probe()
433 chip->ops = &atmel_tcb_pwm_ops; in atmel_tcb_pwm_probe()
434 tcbpwmc->channel = channel; in atmel_tcb_pwm_probe()
435 tcbpwmc->width = config->counter_width; in atmel_tcb_pwm_probe()
437 err = clk_prepare_enable(tcbpwmc->slow_clk); in atmel_tcb_pwm_probe()
441 spin_lock_init(&tcbpwmc->lock); in atmel_tcb_pwm_probe()
452 clk_disable_unprepare(tcbpwmc->slow_clk); in atmel_tcb_pwm_probe()
455 clk_put(tcbpwmc->gclk); in atmel_tcb_pwm_probe()
458 clk_put(tcbpwmc->clk); in atmel_tcb_pwm_probe()
461 clk_put(tcbpwmc->slow_clk); in atmel_tcb_pwm_probe()
473 clk_disable_unprepare(tcbpwmc->slow_clk); in atmel_tcb_pwm_remove()
474 clk_put(tcbpwmc->gclk); in atmel_tcb_pwm_remove()
475 clk_put(tcbpwmc->clk); in atmel_tcb_pwm_remove()
476 clk_put(tcbpwmc->slow_clk); in atmel_tcb_pwm_remove()
480 { .compatible = "atmel,tcb-pwm", },
489 struct atmel_tcb_channel *chan = &tcbpwmc->bkup; in atmel_tcb_pwm_suspend()
490 unsigned int channel = tcbpwmc->channel; in atmel_tcb_pwm_suspend()
492 regmap_read(tcbpwmc->regmap, ATMEL_TC_REG(channel, CMR), &chan->cmr); in atmel_tcb_pwm_suspend()
493 regmap_read(tcbpwmc->regmap, ATMEL_TC_REG(channel, RA), &chan->ra); in atmel_tcb_pwm_suspend()
494 regmap_read(tcbpwmc->regmap, ATMEL_TC_REG(channel, RB), &chan->rb); in atmel_tcb_pwm_suspend()
495 regmap_read(tcbpwmc->regmap, ATMEL_TC_REG(channel, RC), &chan->rc); in atmel_tcb_pwm_suspend()
504 struct atmel_tcb_channel *chan = &tcbpwmc->bkup; in atmel_tcb_pwm_resume()
505 unsigned int channel = tcbpwmc->channel; in atmel_tcb_pwm_resume()
507 regmap_write(tcbpwmc->regmap, ATMEL_TC_REG(channel, CMR), chan->cmr); in atmel_tcb_pwm_resume()
508 regmap_write(tcbpwmc->regmap, ATMEL_TC_REG(channel, RA), chan->ra); in atmel_tcb_pwm_resume()
509 regmap_write(tcbpwmc->regmap, ATMEL_TC_REG(channel, RB), chan->rb); in atmel_tcb_pwm_resume()
510 regmap_write(tcbpwmc->regmap, ATMEL_TC_REG(channel, RC), chan->rc); in atmel_tcb_pwm_resume()
512 if (chan->enabled) in atmel_tcb_pwm_resume()
513 regmap_write(tcbpwmc->regmap, in atmel_tcb_pwm_resume()
525 .name = "atmel-tcb-pwm",
535 MODULE_DESCRIPTION("Atmel Timer Counter Pulse Width Modulation Driver");