diff options
author | Martin Blumenstingl <martin.blumenstingl@googlemail.com> | 2019-06-12 15:59:08 -0400 |
---|---|---|
committer | Thierry Reding <thierry.reding@gmail.com> | 2019-06-26 05:39:10 -0400 |
commit | c375bcbaabdb92f0c007a044cda90450eef5ab43 (patch) | |
tree | c8277ee6344419db7213bc09cb3a30015457bf2e | |
parent | fb2081e870e9d59a0e6d076989e04c932c3ba23d (diff) |
pwm: meson: Read the full hardware state in meson_pwm_get_state()
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.
Reviewed-by: Neil Armstrong <narmstrong@baylibre.com>
Signed-off-by: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
Signed-off-by: Thierry Reding <thierry.reding@gmail.com>
-rw-r--r-- | drivers/pwm/pwm-meson.c | 52 |
1 files changed, 49 insertions, 3 deletions
diff --git a/drivers/pwm/pwm-meson.c b/drivers/pwm/pwm-meson.c index 99815b26f6b2..fd40bb1e4207 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, | |||
287 | return 0; | 287 | return 0; |
288 | } | 288 | } |
289 | 289 | ||
290 | static unsigned int meson_pwm_cnt_to_ns(struct pwm_chip *chip, | ||
291 | struct pwm_device *pwm, u32 cnt) | ||
292 | { | ||
293 | struct meson_pwm *meson = to_meson_pwm(chip); | ||
294 | struct meson_pwm_channel *channel; | ||
295 | unsigned long fin_freq; | ||
296 | u32 fin_ns; | ||
297 | |||
298 | /* to_meson_pwm() can only be used after .get_state() is called */ | ||
299 | channel = &meson->channels[pwm->hwpwm]; | ||
300 | |||
301 | fin_freq = clk_get_rate(channel->clk); | ||
302 | if (fin_freq == 0) | ||
303 | return 0; | ||
304 | |||
305 | fin_ns = div_u64(NSEC_PER_SEC, fin_freq); | ||
306 | |||
307 | return cnt * fin_ns * (channel->pre_div + 1); | ||
308 | } | ||
309 | |||
290 | static void meson_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm, | 310 | static void meson_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm, |
291 | struct pwm_state *state) | 311 | struct pwm_state *state) |
292 | { | 312 | { |
293 | struct meson_pwm *meson = to_meson_pwm(chip); | 313 | struct meson_pwm *meson = to_meson_pwm(chip); |
294 | u32 value, mask; | 314 | struct meson_pwm_channel_data *channel_data; |
315 | struct meson_pwm_channel *channel; | ||
316 | u32 value, tmp; | ||
295 | 317 | ||
296 | if (!state) | 318 | if (!state) |
297 | return; | 319 | return; |
298 | 320 | ||
299 | mask = meson_pwm_per_channel_data[pwm->hwpwm].pwm_en_mask; | 321 | channel = &meson->channels[pwm->hwpwm]; |
322 | channel_data = &meson_pwm_per_channel_data[pwm->hwpwm]; | ||
300 | 323 | ||
301 | value = readl(meson->base + REG_MISC_AB); | 324 | value = readl(meson->base + REG_MISC_AB); |
302 | state->enabled = (value & mask) != 0; | 325 | |
326 | tmp = channel_data->pwm_en_mask | channel_data->clk_en_mask; | ||
327 | state->enabled = (value & tmp) == tmp; | ||
328 | |||
329 | tmp = value >> channel_data->clk_div_shift; | ||
330 | channel->pre_div = FIELD_GET(MISC_CLK_DIV_MASK, tmp); | ||
331 | |||
332 | value = readl(meson->base + channel_data->reg_offset); | ||
333 | |||
334 | channel->lo = FIELD_GET(PWM_LOW_MASK, value); | ||
335 | channel->hi = FIELD_GET(PWM_HIGH_MASK, value); | ||
336 | |||
337 | if (channel->lo == 0) { | ||
338 | state->period = meson_pwm_cnt_to_ns(chip, pwm, channel->hi); | ||
339 | state->duty_cycle = state->period; | ||
340 | } else if (channel->lo >= channel->hi) { | ||
341 | state->period = meson_pwm_cnt_to_ns(chip, pwm, | ||
342 | channel->lo + channel->hi); | ||
343 | state->duty_cycle = meson_pwm_cnt_to_ns(chip, pwm, | ||
344 | channel->hi); | ||
345 | } else { | ||
346 | state->period = 0; | ||
347 | state->duty_cycle = 0; | ||
348 | } | ||
303 | } | 349 | } |
304 | 350 | ||
305 | static const struct pwm_ops meson_pwm_ops = { | 351 | static const struct pwm_ops meson_pwm_ops = { |