/* * Set duty > period. This trick allows the TCU channels in TCU2 mode to * properly return to their init level.
*/
regmap_write(jz->map, TCU_REG_TDHRc(pwm->hwpwm), 0xffff);
regmap_write(jz->map, TCU_REG_TDFRc(pwm->hwpwm), 0x0);
/* * Disable PWM output. * In TCU2 mode (channel 1/2 on JZ4750+), this must be done before the * counter is stopped, while in TCU1 mode the order does not matter.
*/
regmap_clear_bits(jz->map, TCU_REG_TCSRc(pwm->hwpwm), TCU_TCSR_PWM_EN);
/* * Limit the clock to a maximum rate that still gives us a period value * which fits in 16 bits.
*/
do_div(tmp, state->period);
/* * /!\ IMPORTANT NOTE: * ------------------- * This code relies on the fact that clk_round_rate() will always round * down, which is not a valid assumption given by the clk API, but only * happens to be true with the clk drivers used for Ingenic SoCs. * * Right now, there is no alternative as the clk API does not have a * round-down function (and won't have one for a while), but if it ever * comes to light, a round-down function should be used instead.
*/
rate = clk_round_rate(clk, tmp); if (rate < 0) {
dev_err(pwmchip_parent(chip), "Unable to round rate: %ld\n", rate); return rate;
}
/* Calculate period value */
tmp = (unsignedlonglong)rate * state->period;
do_div(tmp, NSEC_PER_SEC);
period = tmp;
err = clk_set_rate(clk, rate); if (err) {
dev_err(pwmchip_parent(chip), "Unable to set rate: %d\n", err); return err;
}
/* Reset counter to 0 */
regmap_write(jz->map, TCU_REG_TCNTc(pwm->hwpwm), 0);
/* Set duty */
regmap_write(jz->map, TCU_REG_TDHRc(pwm->hwpwm), duty);
/* Set period */
regmap_write(jz->map, TCU_REG_TDFRc(pwm->hwpwm), period);
/* Set abrupt shutdown */
regmap_set_bits(jz->map, TCU_REG_TCSRc(pwm->hwpwm),
TCU_TCSR_PWM_SD);
/* * Set polarity. * * The PWM starts in inactive state until the internal timer reaches the * duty value, then becomes active until the timer reaches the period * value. In theory, we should then use (period - duty) as the real duty * value, as a high duty value would otherwise result in the PWM pin * being inactive most of the time. * * Here, we don't do that, and instead invert the polarity of the PWM * when it is active. This trick makes the PWM start with its active * state instead of its inactive state.
*/ if ((state->polarity == PWM_POLARITY_NORMAL) ^ state->enabled)
regmap_clear_bits(jz->map, TCU_REG_TCSRc(pwm->hwpwm),
TCU_TCSR_PWM_INITL_HIGH); else
regmap_set_bits(jz->map, TCU_REG_TCSRc(pwm->hwpwm),
TCU_TCSR_PWM_INITL_HIGH);
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.