Messages in this thread Patch in this message | | | From | Trevor Gamblin <> | Subject | [PATCH 2/2 v2] pwm: axi-pwmgen: add duty offset support | Date | Tue, 9 Apr 2024 13:41:26 -0400 |
| |
Enable duty_offset feature now that it is supported in the pwm subsystem. Related macros and struct fields related to duty_offset are renamed to be consistent.
Signed-off-by: Trevor Gamblin <tgamblin@baylibre.com> --- v2 changes: * Address feedback for driver in v1: * Remove line setting supports_offset flag in pwm_chip, since that has been removed from the struct in core.c.
--- drivers/pwm/pwm-axi-pwmgen.c | 34 ++++++++++++++++++++++++++-------- 1 file changed, 26 insertions(+), 8 deletions(-)
diff --git a/drivers/pwm/pwm-axi-pwmgen.c b/drivers/pwm/pwm-axi-pwmgen.c index 539625c404ac..25a083003432 100644 --- a/drivers/pwm/pwm-axi-pwmgen.c +++ b/drivers/pwm/pwm-axi-pwmgen.c @@ -6,9 +6,9 @@ * Copyright 2024 Baylibre SAS * * Limitations: - * - The writes to registers for period and duty are shadowed until - * LOAD_CONFIG is written to AXI_PWMGEN_REG_CONFIG at the end of the - * current period. + * - The writes to registers for period, duty, and duty_offset are + * shadowed until LOAD_CONFIG is written to AXI_PWMGEN_REG_CONFIG at + * the end of the current period. * - Writing LOAD_CONFIG also has the effect of re-synchronizing all * enabled channels, which could cause glitching on other channels. It * is therefore expected that channels are assigned harmonic periods @@ -34,7 +34,7 @@ #define AXI_PWMGEN_REG_NPWM 0x14 #define AXI_PWMGEN_CHX_PERIOD(v, ch) ((v)->period_base + (v)->ch_step * (ch)) #define AXI_PWMGEN_CHX_DUTY(v, ch) ((v)->duty_base + (v)->ch_step * (ch)) -#define AXI_PWMGEN_CHX_OFFSET(v, ch) ((v)->offset_base + (v)->ch_step * (ch)) +#define AXI_PWMGEN_CHX_DUTY_OFFSET(v, ch) ((v)->duty_offset_base + (v)->ch_step * (ch)) #define AXI_PWMGEN_REG_CORE_MAGIC_VAL 0x601A3471 /* Identification number to test during setup */ #define AXI_PWMGEN_LOAD_CONFIG BIT(1) #define AXI_PWMGEN_RESET BIT(0) @@ -42,7 +42,7 @@ struct axi_pwm_variant { u8 period_base; u8 duty_base; - u8 offset_base; + u8 duty_offset_base; u8 major_version; u8 ch_step; }; @@ -62,7 +62,7 @@ static const struct regmap_config axi_pwmgen_regmap_config = { static const struct axi_pwm_variant pwmgen_1_00_variant = { .period_base = 0x40, .duty_base = 0x44, - .offset_base = 0x48, + .duty_offset_base = 0x48, .major_version = 1, .ch_step = 12, }; @@ -70,7 +70,7 @@ static const struct axi_pwm_variant pwmgen_1_00_variant = { static const struct axi_pwm_variant pwmgen_2_00_variant = { .period_base = 0x40, .duty_base = 0x80, - .offset_base = 0xC0, + .duty_offset_base = 0xC0, .major_version = 2, .ch_step = 4, }; @@ -83,7 +83,7 @@ static int axi_pwmgen_apply(struct pwm_chip *chip, struct pwm_device *pwm, unsigned int ch = pwm->hwpwm; struct regmap *regmap = ddata->regmap; const struct axi_pwm_variant *variant = ddata->variant; - u64 period_cnt, duty_cnt; + u64 period_cnt, duty_cnt, duty_offset_cnt; int ret; if (state->polarity != PWM_POLARITY_NORMAL) @@ -108,6 +108,14 @@ static int axi_pwmgen_apply(struct pwm_chip *chip, struct pwm_device *pwm, ret = regmap_write(regmap, AXI_PWMGEN_CHX_DUTY(variant, ch), duty_cnt); if (ret) return ret; + + duty_offset_cnt = mul_u64_u64_div_u64(state->duty_offset, ddata->clk_rate_hz, NSEC_PER_SEC); + if (duty_offset_cnt > UINT_MAX) + duty_offset_cnt = UINT_MAX; + + ret = regmap_write(regmap, AXI_PWMGEN_CHX_DUTY_OFFSET(variant, ch), duty_offset_cnt); + if (ret) + return ret; } else { ret = regmap_write(regmap, AXI_PWMGEN_CHX_PERIOD(variant, ch), 0); if (ret) @@ -116,6 +124,10 @@ static int axi_pwmgen_apply(struct pwm_chip *chip, struct pwm_device *pwm, ret = regmap_write(regmap, AXI_PWMGEN_CHX_DUTY(variant, ch), 0); if (ret) return ret; + + ret = regmap_write(regmap, AXI_PWMGEN_CHX_DUTY_OFFSET(variant, ch), 0); + if (ret) + return ret; } return regmap_write(regmap, AXI_PWMGEN_REG_CONFIG, AXI_PWMGEN_LOAD_CONFIG); @@ -145,6 +157,12 @@ static int axi_pwmgen_get_state(struct pwm_chip *chip, struct pwm_device *pwm, state->duty_cycle = DIV_ROUND_UP_ULL((u64)cnt * NSEC_PER_SEC, ddata->clk_rate_hz); + ret = regmap_read(regmap, AXI_PWMGEN_CHX_DUTY_OFFSET(variant, ch), &cnt); + if (ret) + return ret; + + state->duty_offset = DIV_ROUND_UP_ULL((u64)cnt * NSEC_PER_SEC, ddata->clk_rate_hz); + state->polarity = PWM_POLARITY_NORMAL; return 0; -- 2.44.0
| |