/* * PWM period is specified with a timebase register, * in number of step periods. The PWM duty cycle is also * specified in step periods, in the [0, $timebase] range. * In other words, the timebase imposes the duty cycle * resolution. Therefore, let's constraint the timebase to * a minimum value to allow a sane range of duty cycle values. * Imposing a minimum timebase, will impose a maximum PWM frequency. * * The value chosen is completely arbitrary.
*/ #define MIN_TMBASE_STEPS 16
if (period_ns < imgchip->min_period_ns ||
period_ns > imgchip->max_period_ns) {
dev_err(pwmchip_parent(chip), "configured period not in range\n"); return -ERANGE;
}
ret = clk_prepare_enable(imgchip->sys_clk); if (ret < 0) {
dev_err(dev, "could not prepare or enable sys clock\n"); return ret;
}
ret = clk_prepare_enable(imgchip->pwm_clk); if (ret < 0) {
dev_err(dev, "could not prepare or enable pwm clock\n");
clk_disable_unprepare(imgchip->sys_clk); return ret;
}
imgchip->periph_regs = syscon_regmap_lookup_by_phandle(pdev->dev.of_node, "img,cr-periph"); if (IS_ERR(imgchip->periph_regs)) return PTR_ERR(imgchip->periph_regs);
imgchip->sys_clk = devm_clk_get(&pdev->dev, "sys"); if (IS_ERR(imgchip->sys_clk)) {
dev_err(&pdev->dev, "failed to get system clock\n"); return PTR_ERR(imgchip->sys_clk);
}
imgchip->pwm_clk = devm_clk_get(&pdev->dev, "pwm"); if (IS_ERR(imgchip->pwm_clk)) {
dev_err(&pdev->dev, "failed to get pwm clock\n"); return PTR_ERR(imgchip->pwm_clk);
}
platform_set_drvdata(pdev, chip);
pm_runtime_set_autosuspend_delay(&pdev->dev, IMG_PWM_PM_TIMEOUT);
pm_runtime_use_autosuspend(&pdev->dev);
pm_runtime_enable(&pdev->dev); if (!pm_runtime_enabled(&pdev->dev)) {
ret = img_pwm_runtime_resume(&pdev->dev); if (ret) goto err_pm_disable;
}
clk_rate = clk_get_rate(imgchip->pwm_clk); if (!clk_rate) {
dev_err(&pdev->dev, "imgchip clock has no frequency\n");
ret = -EINVAL; goto err_suspend;
}
/* The maximum input clock divider is 512 */
val = (u64)NSEC_PER_SEC * 512 * imgchip->data->max_timebase;
do_div(val, clk_rate);
imgchip->max_period_ns = val;
val = (u64)NSEC_PER_SEC * MIN_TMBASE_STEPS;
do_div(val, clk_rate);
imgchip->min_period_ns = val;
chip->ops = &img_pwm_ops;
ret = pwmchip_add(chip); if (ret < 0) {
dev_err(&pdev->dev, "pwmchip_add failed: %d\n", ret); goto err_suspend;
}
return 0;
err_suspend: if (!pm_runtime_enabled(&pdev->dev))
img_pwm_runtime_suspend(&pdev->dev);
err_pm_disable:
pm_runtime_disable(&pdev->dev);
pm_runtime_dont_use_autosuspend(&pdev->dev); return ret;
}
for (i = 0; i < chip->npwm; i++) if (imgchip->suspend_ctrl_cfg & BIT(i))
regmap_clear_bits(imgchip->periph_regs,
PERIP_PWM_PDM_CONTROL,
PERIP_PWM_PDM_CONTROL_CH_MASK <<
PERIP_PWM_PDM_CONTROL_CH_SHIFT(i));
if (pm_runtime_status_suspended(dev))
img_pwm_runtime_suspend(dev);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.