Skip to content

Commit c97267a

Browse files
Lee Jonesthierryreding
authored andcommitted
pwm: sti: Add PWM capture callback
Once a PWM capture has been initiated, the capture call enables a rising edge detection interrupt, then waits. Once each of the 3 phase changes have been recorded the thread then wakes. The remaining part of the call carries out the relevant calculations and returns a structure filled out with the capture data. Signed-off-by: Lee Jones <[email protected]> Signed-off-by: Thierry Reding <[email protected]>
1 parent 25eb538 commit c97267a

File tree

1 file changed

+88
-0
lines changed

1 file changed

+88
-0
lines changed

drivers/pwm/pwm-sti.c

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -305,7 +305,90 @@ static void sti_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm)
305305
clear_bit(pwm->hwpwm, &pc->configured);
306306
}
307307

308+
static int sti_pwm_capture(struct pwm_chip *chip, struct pwm_device *pwm,
309+
struct pwm_capture *result, unsigned long timeout)
310+
{
311+
struct sti_pwm_chip *pc = to_sti_pwmchip(chip);
312+
struct sti_pwm_compat_data *cdata = pc->cdata;
313+
struct sti_cpt_ddata *ddata = pwm_get_chip_data(pwm);
314+
struct device *dev = pc->dev;
315+
unsigned int effective_ticks;
316+
unsigned long long high, low;
317+
int ret;
318+
319+
if (pwm->hwpwm >= cdata->cpt_num_devs) {
320+
dev_err(dev, "device %u is not valid\n", pwm->hwpwm);
321+
return -EINVAL;
322+
}
323+
324+
mutex_lock(&ddata->lock);
325+
ddata->index = 0;
326+
327+
/* Prepare capture measurement */
328+
regmap_write(pc->regmap, PWM_CPT_EDGE(pwm->hwpwm), CPT_EDGE_RISING);
329+
regmap_field_write(pc->pwm_cpt_int_en, BIT(pwm->hwpwm));
330+
331+
/* Enable capture */
332+
ret = regmap_field_write(pc->pwm_cpt_en, 1);
333+
if (ret) {
334+
dev_err(dev, "failed to enable PWM capture %u: %d\n",
335+
pwm->hwpwm, ret);
336+
goto out;
337+
}
338+
339+
ret = wait_event_interruptible_timeout(ddata->wait, ddata->index > 1,
340+
msecs_to_jiffies(timeout));
341+
342+
regmap_write(pc->regmap, PWM_CPT_EDGE(pwm->hwpwm), CPT_EDGE_DISABLED);
343+
344+
if (ret == -ERESTARTSYS)
345+
goto out;
346+
347+
switch (ddata->index) {
348+
case 0:
349+
case 1:
350+
/*
351+
* Getting here could mean:
352+
* - input signal is constant of less than 1 Hz
353+
* - there is no input signal at all
354+
*
355+
* In such case the frequency is rounded down to 0
356+
*/
357+
result->period = 0;
358+
result->duty_cycle = 0;
359+
360+
break;
361+
362+
case 2:
363+
/* We have everying we need */
364+
high = ddata->snapshot[1] - ddata->snapshot[0];
365+
low = ddata->snapshot[2] - ddata->snapshot[1];
366+
367+
effective_ticks = clk_get_rate(pc->cpt_clk);
368+
369+
result->period = (high + low) * NSEC_PER_SEC;
370+
result->period /= effective_ticks;
371+
372+
result->duty_cycle = high * NSEC_PER_SEC;
373+
result->duty_cycle /= effective_ticks;
374+
375+
break;
376+
377+
default:
378+
dev_err(dev, "internal error\n");
379+
break;
380+
}
381+
382+
out:
383+
/* Disable capture */
384+
regmap_field_write(pc->pwm_cpt_en, 0);
385+
386+
mutex_unlock(&ddata->lock);
387+
return ret;
388+
}
389+
308390
static const struct pwm_ops sti_pwm_ops = {
391+
.capture = sti_pwm_capture,
309392
.config = sti_pwm_config,
310393
.enable = sti_pwm_enable,
311394
.disable = sti_pwm_disable,
@@ -418,6 +501,11 @@ static int sti_pwm_probe_dt(struct sti_pwm_chip *pc)
418501
if (IS_ERR(pc->pwm_out_en))
419502
return PTR_ERR(pc->pwm_out_en);
420503

504+
pc->pwm_cpt_en = devm_regmap_field_alloc(dev, pc->regmap,
505+
reg_fields[PWM_CPT_EN]);
506+
if (IS_ERR(pc->pwm_cpt_en))
507+
return PTR_ERR(pc->pwm_cpt_en);
508+
421509
pc->pwm_cpt_int_en = devm_regmap_field_alloc(dev, pc->regmap,
422510
reg_fields[PWM_CPT_INT_EN]);
423511
if (IS_ERR(pc->pwm_cpt_int_en))

0 commit comments

Comments
 (0)