/* Number of bits for the CWORD value */ #define CWORD_BIT_SIZE 16
/* * Maximum control word value allowed when variable-frequency PWM is used as a * clock for the constant-frequency PMW.
*/ #define CONST_VAR_F_MAX 32768 #define CONST_VAR_F_MIN 1
/* * Fv is derived from the variable frequency output. The variable frequency * output is configured using this formula: * * W = cword, if cword < 2 ^ 15 else 16-bit 2's complement of cword * * Fv = W x 2 ^ -16 x 27Mhz (reference clock) * * The period is: (period + 1) / Fv and "on" time is on / (period + 1) * * The PWM core framework specifies that the "duty_ns" parameter is in fact the * "on" time, so this translates directly into our HW programming here.
*/ staticint brcmstb_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
u64 duty_ns, u64 period_ns)
{ struct brcmstb_pwm *p = to_brcmstb_pwm(chip); unsignedlong pc, dc, cword = CONST_VAR_F_MAX; unsignedint channel = pwm->hwpwm;
u32 value;
/* * If asking for a duty_ns equal to period_ns, we need to substract * the period value by 1 to make it shorter than the "on" time and * produce a flat 100% duty cycle signal, and max out the "on" time
*/ if (duty_ns == period_ns) {
dc = PWM_ON_PERIOD_MAX;
pc = PWM_ON_PERIOD_MAX - 1; goto done;
}
while (1) {
u64 rate;
/* * Calculate the base rate from base frequency and current * cword
*/
rate = (u64)clk_get_rate(p->clk) * (u64)cword;
rate >>= CWORD_BIT_SIZE;
pc = mul_u64_u64_div_u64(period_ns, rate, NSEC_PER_SEC);
dc = mul_u64_u64_div_u64(duty_ns + 1, rate, NSEC_PER_SEC);
/* * We can be called with separate duty and period updates, * so do not reject dc == 0 right away
*/ if (pc == PWM_PERIOD_MIN || (dc < PWM_ON_MIN && duty_ns)) return -EINVAL;
/* We converged on a calculation */ if (pc <= PWM_ON_PERIOD_MAX && dc <= PWM_ON_PERIOD_MAX) break;
/* * The cword needs to be a power of 2 for the variable * frequency generator to output a 50% duty cycle variable * frequency which is used as input clock to the fixed * frequency generator.
*/
cword >>= 1;
/* * Desired periods are too large, we do not have a divider * for them
*/ if (cword < CONST_VAR_F_MIN) return -EINVAL;
}
done: /* * Configure the defined "cword" value to have the variable frequency * generator output a base frequency for the constant frequency * generator to derive from.
*/
brcmstb_pwm_writel(p, cword >> 8, PWM_CWORD_MSB(channel));
brcmstb_pwm_writel(p, cword & 0xff, PWM_CWORD_LSB(channel));
/* Select constant frequency signal output */
value = brcmstb_pwm_readl(p, PWM_CTRL2);
value |= CTRL2_OUT_SELECT << (channel * CTRL_CHAN_OFFS);
brcmstb_pwm_writel(p, value, PWM_CTRL2);
/* Configure on and period value */
brcmstb_pwm_writel(p, pc, PWM_PERIOD(channel));
brcmstb_pwm_writel(p, dc, PWM_ON(channel));
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.