/* * If duty is 0 the timer will be stopped and we have to * configure the output correctly on software trigger: * - set output to high if PWM_POLARITY_INVERSED * - set output to low if PWM_POLARITY_NORMAL * * This is why we're reverting polarity in this case.
*/ if (tcbpwm->duty == 0)
polarity = !polarity;
/* * Use software trigger to apply the new setting. * If both PWM devices in this group are disabled we stop the clock.
*/ if (!(cmr & (ATMEL_TC_ACPC | ATMEL_TC_BCPC))) {
regmap_write(tcbpwmc->regmap,
ATMEL_TC_REG(tcbpwmc->channel, CCR),
ATMEL_TC_SWTRG | ATMEL_TC_CLKDIS);
tcbpwmc->bkup.enabled = 1;
} else {
regmap_write(tcbpwmc->regmap,
ATMEL_TC_REG(tcbpwmc->channel, CCR),
ATMEL_TC_SWTRG);
tcbpwmc->bkup.enabled = 0;
}
}
/* * If duty is 0 the timer will be stopped and we have to * configure the output correctly on software trigger: * - set output to high if PWM_POLARITY_INVERSED * - set output to low if PWM_POLARITY_NORMAL * * This is why we're reverting polarity in this case.
*/ if (tcbpwm->duty == 0)
polarity = !polarity;
/* flush old setting and set the new one */
cmr &= ~ATMEL_TC_TCCLKS;
if (pwm->hwpwm == 0) {
cmr &= ~ATMEL_TC_ACMR_MASK;
/* Set CMR flags according to given polarity */ if (polarity == PWM_POLARITY_INVERSED)
cmr |= ATMEL_TC_ASWTRG_CLEAR; else
cmr |= ATMEL_TC_ASWTRG_SET;
} else {
cmr &= ~ATMEL_TC_BCMR_MASK; if (polarity == PWM_POLARITY_INVERSED)
cmr |= ATMEL_TC_BSWTRG_CLEAR; else
cmr |= ATMEL_TC_BSWTRG_SET;
}
/* * If duty is 0 or equal to period there's no need to register * a specific action on RA/RB and RC compare. * The output will be configured on software trigger and keep * this config till next config call.
*/ if (tcbpwm->duty != tcbpwm->period && tcbpwm->duty > 0) { if (pwm->hwpwm == 0) { if (polarity == PWM_POLARITY_INVERSED)
cmr |= ATMEL_TC_ACPA_SET | ATMEL_TC_ACPC_CLEAR; else
cmr |= ATMEL_TC_ACPA_CLEAR | ATMEL_TC_ACPC_SET;
} else { if (polarity == PWM_POLARITY_INVERSED)
cmr |= ATMEL_TC_BCPB_SET | ATMEL_TC_BCPC_CLEAR; else
cmr |= ATMEL_TC_BCPB_CLEAR | ATMEL_TC_BCPC_SET;
}
}
/* Use software trigger to apply the new setting */
regmap_write(tcbpwmc->regmap, ATMEL_TC_REG(tcbpwmc->channel, CCR),
ATMEL_TC_SWTRG | ATMEL_TC_CLKEN);
tcbpwmc->bkup.enabled = 1; return 0;
}
staticint atmel_tcb_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, int duty_ns, int period_ns)
{ struct atmel_tcb_pwm_chip *tcbpwmc = to_tcb_chip(chip); struct atmel_tcb_pwm_device *tcbpwm = &tcbpwmc->pwms[pwm->hwpwm]; /* companion PWM sharing register values period and div */ struct atmel_tcb_pwm_device *atcbpwm = &tcbpwmc->pwms[pwm->hwpwm ^ 1]; int i = 0; int slowclk = 0; unsigned period; unsigned duty; unsigned rate = clk_get_rate(tcbpwmc->clk); unsignedlonglong min; unsignedlonglong max;
/* * Find best clk divisor: * the smallest divisor which can fulfill the period_ns requirements. * If there is a gclk, the first divisor is actually the gclk selector
*/ if (tcbpwmc->gclk)
i = 1; for (; i < ARRAY_SIZE(atmel_tcb_divisors); ++i) { if (atmel_tcb_divisors[i] == 0) {
slowclk = i; continue;
}
min = div_u64((u64)NSEC_PER_SEC * atmel_tcb_divisors[i], rate);
max = min << tcbpwmc->width; if (max >= period_ns) break;
}
/* * If none of the divisor are small enough to represent period_ns * take slow clock (32KHz).
*/ if (i == ARRAY_SIZE(atmel_tcb_divisors)) {
i = slowclk;
rate = clk_get_rate(tcbpwmc->slow_clk);
min = div_u64(NSEC_PER_SEC, rate);
max = min << tcbpwmc->width;
/* If period is too big return ERANGE error */ if (max < period_ns) return -ERANGE;
}
duty = div_u64(duty_ns, min);
period = div_u64(period_ns, min);
/* * PWM devices provided by the TCB driver are grouped by 2. * PWM devices in a given group must be configured with the * same period_ns. * * We're checking the period value of the second PWM device * in this group before applying the new config.
*/ if ((atcbpwm->duty > 0 && atcbpwm->duty != atcbpwm->period) &&
(atcbpwm->div != i || atcbpwm->period != period)) {
dev_err(pwmchip_parent(chip), "failed to configure period_ns: PWM group already configured with a different value\n"); return -EINVAL;
}
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.