in pwm-fsl-ftm.c [228:298]
static int fsl_pwm_apply_config(struct fsl_pwm_chip *fpc,
struct pwm_device *pwm,
const struct pwm_state *newstate)
{
unsigned int duty;
u32 reg_polarity;
struct fsl_pwm_periodcfg periodcfg;
bool do_write_period = false;
if (!fsl_pwm_calculate_period(fpc, newstate->period, &periodcfg)) {
dev_err(fpc->chip.dev, "failed to calculate new period\n");
return -EINVAL;
}
if (!fsl_pwm_is_any_pwm_enabled(fpc, pwm))
do_write_period = true;
/*
* The Freescale FTM controller supports only a single period for
* all PWM channels, therefore verify if the newly computed period
* is different than the current period being used. In such case
* we allow to change the period only if no other pwm is running.
*/
else if (!fsl_pwm_periodcfg_are_equal(&fpc->period, &periodcfg)) {
if (fsl_pwm_is_other_pwm_enabled(fpc, pwm)) {
dev_err(fpc->chip.dev,
"Cannot change period for PWM %u, disable other PWMs first\n",
pwm->hwpwm);
return -EBUSY;
}
if (fpc->period.clk_select != periodcfg.clk_select) {
int ret;
enum fsl_pwm_clk oldclk = fpc->period.clk_select;
enum fsl_pwm_clk newclk = periodcfg.clk_select;
ret = clk_prepare_enable(fpc->clk[newclk]);
if (ret)
return ret;
clk_disable_unprepare(fpc->clk[oldclk]);
}
do_write_period = true;
}
ftm_clear_write_protection(fpc);
if (do_write_period) {
regmap_update_bits(fpc->regmap, FTM_SC, FTM_SC_CLK_MASK,
FTM_SC_CLK(periodcfg.clk_select));
regmap_update_bits(fpc->regmap, FTM_SC, FTM_SC_PS_MASK,
periodcfg.clk_ps);
regmap_write(fpc->regmap, FTM_MOD, periodcfg.mod_period);
fpc->period = periodcfg;
}
duty = fsl_pwm_calculate_duty(fpc, newstate->duty_cycle);
regmap_write(fpc->regmap, FTM_CSC(pwm->hwpwm),
FTM_CSC_MSB | FTM_CSC_ELSB);
regmap_write(fpc->regmap, FTM_CV(pwm->hwpwm), duty);
reg_polarity = 0;
if (newstate->polarity == PWM_POLARITY_INVERSED)
reg_polarity = BIT(pwm->hwpwm);
regmap_update_bits(fpc->regmap, FTM_POL, BIT(pwm->hwpwm), reg_polarity);
ftm_set_write_protection(fpc);
return 0;
}