Created
April 29, 2024 15:52
-
-
Save apritzel/5c7b131acab80d7e6340a7e066e2a954 to your computer and use it in GitHub Desktop.
Allwinner D1 PWM driver refactoring patch to accommodate H616 PWM IP
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Author: Andre Przywara <[email protected]> | |
Date: Wed Sep 6 21:04:05 2023 +0100 | |
pwm: sun20i: Refactor channel enablement | |
When enabling or disabling a PWM channel, we also ungate and gate the | |
respective clock at the same time. | |
Factor this out into a separate function, to simplify extending the | |
driver to other SoCs, where the clock gate is located in a different | |
register. | |
Signed-off-by: Andre Przywara <[email protected]> | |
diff --git a/drivers/pwm/pwm-sun20i.c b/drivers/pwm/pwm-sun20i.c | |
index eca14b36eaf44..4edb57c33f6b9 100644 | |
--- a/drivers/pwm/pwm-sun20i.c | |
+++ b/drivers/pwm/pwm-sun20i.c | |
@@ -68,6 +68,40 @@ static inline void sun20i_pwm_writel(struct sun20i_pwm_chip *chip, | |
writel(val, chip->base + offset); | |
} | |
+/* | |
+ * Enables or disables a channel, taking care of the respective clock gating | |
+ * on the way: The old PWM uses a shared clock gate per channel pair, whereas | |
+ * the new PWM has a separate clock gate per channel. | |
+ * | |
+ * Returns the status of the *neighbouring* channel. | |
+ */ | |
+static bool pwm_sun20i_enable_chan(struct pwm_device *pwm, bool set) | |
+{ | |
+ struct pwm_chip *chip = pwm->chip; | |
+ struct sun20i_pwm_chip *sun20i_chip = to_sun20i_pwm_chip(chip); | |
+ int chan = pwm->hwpwm; | |
+ u32 clk_gate, enable; | |
+ bool ret; | |
+ | |
+ enable = readl(sun20i_chip->base + PWM_ENABLE); | |
+ clk_gate = readl(sun20i_chip->base + PWM_CLK_GATE); | |
+ | |
+ ret = enable & PWM_ENABLE_EN(chan ^ 1); | |
+ | |
+ if (set) { | |
+ clk_gate |= PWM_ENABLE_EN(chan); | |
+ enable |= PWM_ENABLE_EN(chan); | |
+ } else { | |
+ clk_gate &= ~PWM_ENABLE_EN(chan); | |
+ enable &= ~PWM_ENABLE_EN(chan); | |
+ } | |
+ | |
+ writel(clk_gate, sun20i_chip->base + PWM_CLK_GATE); | |
+ writel(enable, sun20i_chip->base + PWM_ENABLE); | |
+ | |
+ return ret; | |
+} | |
+ | |
static int sun20i_pwm_get_state(struct pwm_chip *chip, | |
struct pwm_device *pwm, | |
struct pwm_state *state) | |
@@ -119,25 +153,19 @@ static int sun20i_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, | |
const struct pwm_state *state) | |
{ | |
struct sun20i_pwm_chip *sun20i_chip = to_sun20i_pwm_chip(chip); | |
- u32 clk_gate, clk_cfg, pwm_en, ctl, period; | |
+ u32 clk_cfg, ctl, period; | |
u64 bus_rate, hosc_rate, clk_div, val; | |
u32 prescaler, div_m; | |
- bool use_bus_clk; | |
+ bool other_chan, use_bus_clk; | |
int ret = 0; | |
mutex_lock(&sun20i_chip->mutex); | |
- pwm_en = sun20i_pwm_readl(sun20i_chip, PWM_ENABLE); | |
- | |
- if (state->enabled != pwm->state.enabled) | |
- clk_gate = sun20i_pwm_readl(sun20i_chip, PWM_CLK_GATE); | |
- | |
- if (state->enabled != pwm->state.enabled && !state->enabled) { | |
- clk_gate &= ~PWM_CLK_GATE_GATING(pwm->hwpwm); | |
- pwm_en &= ~PWM_ENABLE_EN(pwm->hwpwm); | |
- sun20i_pwm_writel(sun20i_chip, pwm_en, PWM_ENABLE); | |
- sun20i_pwm_writel(sun20i_chip, clk_gate, PWM_CLK_GATE); | |
- } | |
+ if (state->enabled != pwm->state.enabled && !state->enabled) | |
+ other_chan = pwm_sun20i_enable_chan(pwm, false); | |
+ else | |
+ other_chan = sun20i_pwm_readl(sun20i_chip, PWM_ENABLE) & | |
+ PWM_ENABLE_EN(pwm->hwpwm ^ 1); | |
if (state->polarity != pwm->state.polarity || | |
state->duty_cycle != pwm->state.duty_cycle || | |
@@ -146,7 +174,7 @@ static int sun20i_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, | |
clk_cfg = sun20i_pwm_readl(sun20i_chip, PWM_CLK_CFG(pwm->hwpwm)); | |
hosc_rate = clk_get_rate(sun20i_chip->clk_hosc); | |
bus_rate = clk_get_rate(sun20i_chip->clk_apb0); | |
- if (pwm_en & PWM_ENABLE_EN(pwm->hwpwm ^ 1)) { | |
+ if (other_chan) { | |
/* if the neighbor channel is enable, check period only */ | |
use_bus_clk = FIELD_GET(PWM_CLK_CFG_SRC, clk_cfg) != 0; | |
val = state->period * (use_bus_clk ? bus_rate : hosc_rate); | |
@@ -221,13 +249,8 @@ static int sun20i_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, | |
sun20i_pwm_writel(sun20i_chip, ctl, PWM_CTL(pwm->hwpwm)); | |
} | |
- if (state->enabled != pwm->state.enabled && state->enabled) { | |
- clk_gate &= ~PWM_CLK_GATE_BYPASS(pwm->hwpwm); | |
- clk_gate |= PWM_CLK_GATE_GATING(pwm->hwpwm); | |
- pwm_en |= PWM_ENABLE_EN(pwm->hwpwm); | |
- sun20i_pwm_writel(sun20i_chip, pwm_en, PWM_ENABLE); | |
- sun20i_pwm_writel(sun20i_chip, clk_gate, PWM_CLK_GATE); | |
- } | |
+ if (state->enabled != pwm->state.enabled && state->enabled) | |
+ pwm_sun20i_enable_chan(pwm, true); | |
unlock_mutex: | |
mutex_unlock(&sun20i_chip->mutex); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment