Lines Matching +full:pc +full:- +full:ack

1 // SPDX-License-Identifier: GPL-2.0-or-later
5 * Copyright (C) 2013-2016 STMicroelectronics (R&D) Limited
59 * Each capture input can be programmed to detect rising-edge, falling-edge,
116 static int sti_pwm_get_prescale(struct sti_pwm_chip *pc, unsigned long period, in sti_pwm_get_prescale() argument
123 clk_rate = clk_get_rate(pc->pwm_clk); in sti_pwm_get_prescale()
125 dev_err(pc->dev, "failed to get clock rate\n"); in sti_pwm_get_prescale()
126 return -EINVAL; in sti_pwm_get_prescale()
130 * prescale = ((period_ns * clk_rate) / (10^9 * (max_pwm_cnt + 1)) - 1 in sti_pwm_get_prescale()
133 value *= pc->max_pwm_cnt + 1; in sti_pwm_get_prescale()
136 return -EINVAL; in sti_pwm_get_prescale()
138 ps = period / value - 1; in sti_pwm_get_prescale()
139 if (ps > pc->max_prescale) in sti_pwm_get_prescale()
140 return -EINVAL; in sti_pwm_get_prescale()
159 struct sti_pwm_chip *pc = to_sti_pwmchip(chip); in sti_pwm_config() local
161 struct pwm_device *cur = pc->cur; in sti_pwm_config()
162 struct device *dev = pc->dev; in sti_pwm_config()
166 ncfg = hweight_long(pc->configured); in sti_pwm_config()
183 ((ncfg == 1) && (pwm->hwpwm == cur->hwpwm)) || in sti_pwm_config()
184 ((ncfg == 1) && (pwm->hwpwm != cur->hwpwm) && period_same) || in sti_pwm_config()
187 ret = clk_enable(pc->pwm_clk); in sti_pwm_config()
191 ret = clk_enable(pc->cpt_clk); in sti_pwm_config()
196 ret = sti_pwm_get_prescale(pc, period_ns, &prescale); in sti_pwm_config()
202 ret = regmap_field_write(pc->prescale_low, value); in sti_pwm_config()
208 ret = regmap_field_write(pc->prescale_high, value); in sti_pwm_config()
219 value = pc->max_pwm_cnt * duty_ns / period_ns; in sti_pwm_config()
221 ret = regmap_write(pc->regmap, PWM_OUT_VAL(pwm->hwpwm), value); in sti_pwm_config()
225 ret = regmap_field_write(pc->pwm_cpt_int_en, 0); in sti_pwm_config()
227 set_bit(pwm->hwpwm, &pc->configured); in sti_pwm_config()
228 pc->cur = pwm; in sti_pwm_config()
233 return -EINVAL; in sti_pwm_config()
237 clk_disable(pc->pwm_clk); in sti_pwm_config()
238 clk_disable(pc->cpt_clk); in sti_pwm_config()
244 struct sti_pwm_chip *pc = to_sti_pwmchip(chip); in sti_pwm_enable() local
245 struct device *dev = pc->dev; in sti_pwm_enable()
253 if (!pc->en_count) { in sti_pwm_enable()
254 ret = clk_enable(pc->pwm_clk); in sti_pwm_enable()
258 ret = clk_enable(pc->cpt_clk); in sti_pwm_enable()
262 ret = regmap_field_write(pc->pwm_out_en, 1); in sti_pwm_enable()
265 pwm->hwpwm, ret); in sti_pwm_enable()
270 pc->en_count++; in sti_pwm_enable()
277 struct sti_pwm_chip *pc = to_sti_pwmchip(chip); in sti_pwm_disable() local
279 if (--pc->en_count) in sti_pwm_disable()
282 regmap_field_write(pc->pwm_out_en, 0); in sti_pwm_disable()
284 clk_disable(pc->pwm_clk); in sti_pwm_disable()
285 clk_disable(pc->cpt_clk); in sti_pwm_disable()
290 struct sti_pwm_chip *pc = to_sti_pwmchip(chip); in sti_pwm_free() local
292 clear_bit(pwm->hwpwm, &pc->configured); in sti_pwm_free()
298 struct sti_pwm_chip *pc = to_sti_pwmchip(chip); in sti_pwm_capture() local
299 struct sti_cpt_ddata *ddata = &pc->ddata[pwm->hwpwm]; in sti_pwm_capture()
300 struct device *dev = pc->dev; in sti_pwm_capture()
305 if (pwm->hwpwm >= pc->cpt_num_devs) { in sti_pwm_capture()
306 dev_err(dev, "device %u is not valid\n", pwm->hwpwm); in sti_pwm_capture()
307 return -EINVAL; in sti_pwm_capture()
310 mutex_lock(&ddata->lock); in sti_pwm_capture()
311 ddata->index = 0; in sti_pwm_capture()
314 regmap_write(pc->regmap, PWM_CPT_EDGE(pwm->hwpwm), CPT_EDGE_RISING); in sti_pwm_capture()
315 regmap_field_write(pc->pwm_cpt_int_en, BIT(pwm->hwpwm)); in sti_pwm_capture()
318 ret = regmap_field_write(pc->pwm_cpt_en, 1); in sti_pwm_capture()
321 pwm->hwpwm, ret); in sti_pwm_capture()
325 ret = wait_event_interruptible_timeout(ddata->wait, ddata->index > 1, in sti_pwm_capture()
328 regmap_write(pc->regmap, PWM_CPT_EDGE(pwm->hwpwm), CPT_EDGE_DISABLED); in sti_pwm_capture()
330 if (ret == -ERESTARTSYS) in sti_pwm_capture()
333 switch (ddata->index) { in sti_pwm_capture()
338 * - input signal is constant of less than 1 Hz in sti_pwm_capture()
339 * - there is no input signal at all in sti_pwm_capture()
343 result->period = 0; in sti_pwm_capture()
344 result->duty_cycle = 0; in sti_pwm_capture()
350 high = ddata->snapshot[1] - ddata->snapshot[0]; in sti_pwm_capture()
351 low = ddata->snapshot[2] - ddata->snapshot[1]; in sti_pwm_capture()
353 effective_ticks = clk_get_rate(pc->cpt_clk); in sti_pwm_capture()
355 result->period = (high + low) * NSEC_PER_SEC; in sti_pwm_capture()
356 result->period /= effective_ticks; in sti_pwm_capture()
358 result->duty_cycle = high * NSEC_PER_SEC; in sti_pwm_capture()
359 result->duty_cycle /= effective_ticks; in sti_pwm_capture()
370 regmap_field_write(pc->pwm_cpt_en, 0); in sti_pwm_capture()
372 mutex_unlock(&ddata->lock); in sti_pwm_capture()
379 struct sti_pwm_chip *pc = to_sti_pwmchip(chip); in sti_pwm_apply() local
380 struct device *dev = pc->dev; in sti_pwm_apply()
383 if (pwm->hwpwm >= pc->pwm_num_devs) { in sti_pwm_apply()
385 pwm->hwpwm); in sti_pwm_apply()
386 return -EINVAL; in sti_pwm_apply()
389 if (state->polarity != PWM_POLARITY_NORMAL) in sti_pwm_apply()
390 return -EINVAL; in sti_pwm_apply()
392 if (!state->enabled) { in sti_pwm_apply()
393 if (pwm->state.enabled) in sti_pwm_apply()
399 err = sti_pwm_config(chip, pwm, state->duty_cycle, state->period); in sti_pwm_apply()
403 if (!pwm->state.enabled) in sti_pwm_apply()
417 struct sti_pwm_chip *pc = data; in sti_pwm_interrupt() local
418 struct device *dev = pc->dev; in sti_pwm_interrupt()
425 ret = regmap_field_read(pc->pwm_cpt_int_stat, &cpt_int_stat); in sti_pwm_interrupt()
430 devicenum = ffs(cpt_int_stat) - 1; in sti_pwm_interrupt()
432 ddata = &pc->ddata[devicenum]; in sti_pwm_interrupt()
450 regmap_read(pc->regmap, in sti_pwm_interrupt()
452 &ddata->snapshot[ddata->index]); in sti_pwm_interrupt()
454 switch (ddata->index) { in sti_pwm_interrupt()
457 regmap_read(pc->regmap, PWM_CPT_EDGE(devicenum), &reg); in sti_pwm_interrupt()
459 regmap_write(pc->regmap, PWM_CPT_EDGE(devicenum), reg); in sti_pwm_interrupt()
461 ddata->index++; in sti_pwm_interrupt()
465 regmap_write(pc->regmap, in sti_pwm_interrupt()
468 wake_up(&ddata->wait); in sti_pwm_interrupt()
480 /* Just ACK everything */ in sti_pwm_interrupt()
481 regmap_write(pc->regmap, PWM_INT_ACK, PWM_INT_ACK_MASK); in sti_pwm_interrupt()
486 static int sti_pwm_probe_regmap(struct sti_pwm_chip *pc) in sti_pwm_probe_regmap() argument
488 struct device *dev = pc->dev; in sti_pwm_probe_regmap()
490 pc->prescale_low = devm_regmap_field_alloc(dev, pc->regmap, in sti_pwm_probe_regmap()
492 if (IS_ERR(pc->prescale_low)) in sti_pwm_probe_regmap()
493 return PTR_ERR(pc->prescale_low); in sti_pwm_probe_regmap()
495 pc->prescale_high = devm_regmap_field_alloc(dev, pc->regmap, in sti_pwm_probe_regmap()
497 if (IS_ERR(pc->prescale_high)) in sti_pwm_probe_regmap()
498 return PTR_ERR(pc->prescale_high); in sti_pwm_probe_regmap()
500 pc->pwm_out_en = devm_regmap_field_alloc(dev, pc->regmap, in sti_pwm_probe_regmap()
502 if (IS_ERR(pc->pwm_out_en)) in sti_pwm_probe_regmap()
503 return PTR_ERR(pc->pwm_out_en); in sti_pwm_probe_regmap()
505 pc->pwm_cpt_en = devm_regmap_field_alloc(dev, pc->regmap, in sti_pwm_probe_regmap()
507 if (IS_ERR(pc->pwm_cpt_en)) in sti_pwm_probe_regmap()
508 return PTR_ERR(pc->pwm_cpt_en); in sti_pwm_probe_regmap()
510 pc->pwm_cpt_int_en = devm_regmap_field_alloc(dev, pc->regmap, in sti_pwm_probe_regmap()
512 if (IS_ERR(pc->pwm_cpt_int_en)) in sti_pwm_probe_regmap()
513 return PTR_ERR(pc->pwm_cpt_int_en); in sti_pwm_probe_regmap()
515 pc->pwm_cpt_int_stat = devm_regmap_field_alloc(dev, pc->regmap, in sti_pwm_probe_regmap()
517 if (PTR_ERR_OR_ZERO(pc->pwm_cpt_int_stat)) in sti_pwm_probe_regmap()
518 return PTR_ERR(pc->pwm_cpt_int_stat); in sti_pwm_probe_regmap()
531 struct device *dev = &pdev->dev; in sti_pwm_probe()
532 struct device_node *np = dev->of_node; in sti_pwm_probe()
537 struct sti_pwm_chip *pc; in sti_pwm_probe() local
541 ret = of_property_read_u32(np, "st,pwm-num-chan", &num_devs); in sti_pwm_probe()
545 ret = of_property_read_u32(np, "st,capture-num-chan", &num_devs); in sti_pwm_probe()
550 return dev_err_probe(dev, -EINVAL, "No channels configured\n"); in sti_pwm_probe()
552 chip = devm_pwmchip_alloc(dev, max(pwm_num_devs, cpt_num_devs), sizeof(*pc)); in sti_pwm_probe()
555 pc = to_sti_pwmchip(chip); in sti_pwm_probe()
557 pc->mmio = devm_platform_ioremap_resource(pdev, 0); in sti_pwm_probe()
558 if (IS_ERR(pc->mmio)) in sti_pwm_probe()
559 return PTR_ERR(pc->mmio); in sti_pwm_probe()
561 pc->regmap = devm_regmap_init_mmio(dev, pc->mmio, in sti_pwm_probe()
563 if (IS_ERR(pc->regmap)) in sti_pwm_probe()
564 return dev_err_probe(dev, PTR_ERR(pc->regmap), in sti_pwm_probe()
571 ret = devm_request_irq(&pdev->dev, irq, sti_pwm_interrupt, 0, in sti_pwm_probe()
572 pdev->name, pc); in sti_pwm_probe()
574 dev_err_probe(&pdev->dev, ret, "Failed to request IRQ\n"); in sti_pwm_probe()
580 pc->max_prescale = 0xff; in sti_pwm_probe()
581 pc->max_pwm_cnt = 255; in sti_pwm_probe()
582 pc->pwm_num_devs = pwm_num_devs; in sti_pwm_probe()
583 pc->cpt_num_devs = cpt_num_devs; in sti_pwm_probe()
585 pc->dev = dev; in sti_pwm_probe()
586 pc->en_count = 0; in sti_pwm_probe()
588 ret = sti_pwm_probe_regmap(pc); in sti_pwm_probe()
593 pc->pwm_clk = devm_clk_get_prepared(dev, "pwm"); in sti_pwm_probe()
594 if (IS_ERR(pc->pwm_clk)) in sti_pwm_probe()
595 return dev_err_probe(dev, PTR_ERR(pc->pwm_clk), in sti_pwm_probe()
600 pc->cpt_clk = devm_clk_get_prepared(dev, "capture"); in sti_pwm_probe()
601 if (IS_ERR(pc->cpt_clk)) in sti_pwm_probe()
602 return dev_err_probe(dev, PTR_ERR(pc->cpt_clk), in sti_pwm_probe()
605 pc->ddata = devm_kcalloc(dev, cpt_num_devs, in sti_pwm_probe()
606 sizeof(*pc->ddata), GFP_KERNEL); in sti_pwm_probe()
607 if (!pc->ddata) in sti_pwm_probe()
608 return -ENOMEM; in sti_pwm_probe()
611 struct sti_cpt_ddata *ddata = &pc->ddata[i]; in sti_pwm_probe()
613 init_waitqueue_head(&ddata->wait); in sti_pwm_probe()
614 mutex_init(&ddata->lock); in sti_pwm_probe()
618 chip->ops = &sti_pwm_ops; in sti_pwm_probe()
628 { .compatible = "st,sti-pwm", },
635 .name = "sti-pwm",