mirror of
https://github.com/torvalds/linux.git
synced 2026-05-28 17:13:52 +02:00
pwm: mediatek: Implement .get_state() callback
The registers can be read out just fine on an MT8365. In the assumption that this works on all supported devices, a .get_state() callback can be implemented. This enables consumers to make use of pwm_get_state_hw() and improves the usefulness of /sys/kernel/debug/pwm. Signed-off-by: Uwe Kleine-König <u.kleine-koenig@baylibre.com> Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com> Link: https://lore.kernel.org/r/20250725154506.2610172-15-u.kleine-koenig@baylibre.com Signed-off-by: Uwe Kleine-König <ukleinek@kernel.org>
This commit is contained in:
parent
a911f15745
commit
edd6a37e06
|
|
@ -31,6 +31,7 @@
|
|||
#define PWMDWIDTH_PERIOD GENMASK(12, 0)
|
||||
#define PWM45DWIDTH_FIXUP 0x30
|
||||
#define PWMTHRES 0x30
|
||||
#define PWMTHRES_DUTY GENMASK(12, 0)
|
||||
#define PWM45THRES_FIXUP 0x34
|
||||
#define PWM_CK_26M_SEL_V3 0x74
|
||||
#define PWM_CK_26M_SEL 0x210
|
||||
|
|
@ -108,6 +109,13 @@ static inline void pwm_mediatek_writel(struct pwm_mediatek_chip *chip,
|
|||
num * chip->soc->chanreg_width + offset);
|
||||
}
|
||||
|
||||
static inline u32 pwm_mediatek_readl(struct pwm_mediatek_chip *chip,
|
||||
unsigned int num, unsigned int offset)
|
||||
{
|
||||
return readl(chip->regs + chip->soc->chanreg_base +
|
||||
num * chip->soc->chanreg_width + offset);
|
||||
}
|
||||
|
||||
static void pwm_mediatek_enable(struct pwm_chip *chip, struct pwm_device *pwm)
|
||||
{
|
||||
struct pwm_mediatek_chip *pc = to_pwm_mediatek_chip(chip);
|
||||
|
|
@ -228,8 +236,70 @@ static int pwm_mediatek_apply(struct pwm_chip *chip, struct pwm_device *pwm,
|
|||
return err;
|
||||
}
|
||||
|
||||
static int pwm_mediatek_get_state(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
struct pwm_state *state)
|
||||
{
|
||||
struct pwm_mediatek_chip *pc = to_pwm_mediatek_chip(chip);
|
||||
int ret;
|
||||
u32 enable;
|
||||
u32 reg_width = PWMDWIDTH, reg_thres = PWMTHRES;
|
||||
|
||||
if (pc->soc->pwm45_fixup && pwm->hwpwm > 2) {
|
||||
/*
|
||||
* PWM[4,5] has distinct offset for PWMDWIDTH and PWMTHRES
|
||||
* from the other PWMs on MT7623.
|
||||
*/
|
||||
reg_width = PWM45DWIDTH_FIXUP;
|
||||
reg_thres = PWM45THRES_FIXUP;
|
||||
}
|
||||
|
||||
ret = pwm_mediatek_clk_enable(pc, pwm->hwpwm);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
enable = readl(pc->regs);
|
||||
if (enable & BIT(pwm->hwpwm)) {
|
||||
u32 clkdiv, cnt_period, cnt_duty;
|
||||
unsigned long clk_rate;
|
||||
|
||||
clk_rate = clk_get_rate(pc->clk_pwms[pwm->hwpwm]);
|
||||
if (!clk_rate) {
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
state->enabled = true;
|
||||
state->polarity = PWM_POLARITY_NORMAL;
|
||||
|
||||
clkdiv = FIELD_GET(PWMCON_CLKDIV,
|
||||
pwm_mediatek_readl(pc, pwm->hwpwm, PWMCON));
|
||||
cnt_period = FIELD_GET(PWMDWIDTH_PERIOD,
|
||||
pwm_mediatek_readl(pc, pwm->hwpwm, reg_width));
|
||||
cnt_duty = FIELD_GET(PWMTHRES_DUTY,
|
||||
pwm_mediatek_readl(pc, pwm->hwpwm, reg_thres));
|
||||
|
||||
/*
|
||||
* cnt_period is a 13 bit value, NSEC_PER_SEC is 30 bits wide
|
||||
* and clkdiv is less than 8, so the multiplication doesn't
|
||||
* overflow an u64.
|
||||
*/
|
||||
state->period =
|
||||
DIV_ROUND_UP_ULL((u64)cnt_period * NSEC_PER_SEC << clkdiv, clk_rate);
|
||||
state->duty_cycle =
|
||||
DIV_ROUND_UP_ULL((u64)cnt_duty * NSEC_PER_SEC << clkdiv, clk_rate);
|
||||
} else {
|
||||
state->enabled = false;
|
||||
}
|
||||
|
||||
out:
|
||||
pwm_mediatek_clk_disable(pc, pwm->hwpwm);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct pwm_ops pwm_mediatek_ops = {
|
||||
.apply = pwm_mediatek_apply,
|
||||
.get_state = pwm_mediatek_get_state,
|
||||
};
|
||||
|
||||
static int pwm_mediatek_init_used_clks(struct pwm_mediatek_chip *pc)
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user