Messages in this thread | | | Subject | Re: [PATCH 11/14] pwm: meson: read the full hardware state in meson_pwm_get_state() | From | Neil Armstrong <> | Date | Mon, 27 May 2019 14:31:00 +0200 |
| |
On 25/05/2019 20:11, Martin Blumenstingl wrote: > Update the meson_pwm_get_state() implementation to take care of all > information in the registers instead of only reading the "enabled" > state. > > The PWM output is only enabled if two conditions are met: > 1. the per-channel clock is enabled > 2. the PWM output is enabled > > Calculate the PWM period and duty cycle using the reverse formula which > we already have in meson_pwm_calc() and update struct pwm_state with the > results. > > As result of this /sys/kernel/debug/pwm now shows the PWM state set by > the bootloader (or firmware) after booting Linux. > > Signed-off-by: Martin Blumenstingl <martin.blumenstingl@googlemail.com> > --- > drivers/pwm/pwm-meson.c | 52 ++++++++++++++++++++++++++++++++++++++--- > 1 file changed, 49 insertions(+), 3 deletions(-) > > diff --git a/drivers/pwm/pwm-meson.c b/drivers/pwm/pwm-meson.c > index 9afa1e5aaebf..010212166d5d 100644 > --- a/drivers/pwm/pwm-meson.c > +++ b/drivers/pwm/pwm-meson.c > @@ -287,19 +287,65 @@ static int meson_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, > return 0; > } > > +static unsigned int meson_pwm_cnt_to_ns(struct pwm_chip *chip, > + struct pwm_device *pwm, u32 cnt) > +{ > + struct meson_pwm *meson = to_meson_pwm(chip); > + struct meson_pwm_channel *channel; > + unsigned long fin_freq; > + u32 fin_ns; > + > + /* to_meson_pwm() can only be used after .get_state() is called */ > + channel = &meson->channels[pwm->hwpwm]; > + > + fin_freq = clk_get_rate(channel->clk); > + if (fin_freq == 0) > + return 0; > + > + fin_ns = div_u64(NSEC_PER_SEC, fin_freq); > + > + return cnt * fin_ns * (channel->pre_div + 1); > +} > + > static void meson_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm, > struct pwm_state *state) > { > struct meson_pwm *meson = to_meson_pwm(chip); > - u32 value, mask; > + struct meson_pwm_channel_data *channel_data; > + struct meson_pwm_channel *channel; > + u32 value, tmp; > > if (!state) > return; > > - mask = meson_pwm_per_channel_data[pwm->hwpwm].pwm_en_mask; > + channel = &meson->channels[pwm->hwpwm]; > + channel_data = &meson_pwm_per_channel_data[pwm->hwpwm]; > > value = readl(meson->base + REG_MISC_AB); > - state->enabled = (value & mask) != 0; > + > + tmp = channel_data->pwm_en_mask | channel_data->clk_en_mask; > + state->enabled = (value & tmp) == tmp; > + > + tmp = value >> channel_data->clk_div_shift; > + channel->pre_div = FIELD_GET(MISC_CLK_DIV_MASK, tmp); > + > + value = readl(meson->base + channel_data->reg_offset); > + > + channel->lo = FIELD_GET(PWM_LOW_MASK, value); > + channel->hi = FIELD_GET(PWM_HIGH_MASK, value); > + > + if (channel->lo == 0) { > + state->period = meson_pwm_cnt_to_ns(chip, pwm, channel->hi); > + state->duty_cycle = state->period; > + } else if (channel->lo >= channel->hi) { > + state->period = meson_pwm_cnt_to_ns(chip, pwm, > + channel->lo + channel->hi); > + state->duty_cycle = meson_pwm_cnt_to_ns(chip, pwm, > + channel->hi); > + } else { > + state->period = 0; > + state->duty_cycle = 0; > + } > } > > static const struct pwm_ops meson_pwm_ops = { >
Thanks for that !!!
Reviewed-by: Neil Armstrong <narmstrong@baylibre.com>
| |