[linux-sunxi] [PATCH 6/6] pwm: sun4i: don't delay if the PWM is already off
Signed-off-by: Roman Beranek --- drivers/pwm/pwm-sun4i.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/pwm/pwm-sun4i.c b/drivers/pwm/pwm-sun4i.c index 6ab06b9749d0..88bd90498d1f 100644 --- a/drivers/pwm/pwm-sun4i.c +++ b/drivers/pwm/pwm-sun4i.c @@ -304,7 +304,7 @@ static int sun4i_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, sun4i_pwm_writel(sun4i_pwm, ctrl, PWM_CTRL_REG); - if (state->enabled) { + if (state->enabled || !cstate.enabled) { mutex_unlock(_pwm->ctrl_lock); return 0; } -- 2.31.1 -- You received this message because you are subscribed to the Google Groups "linux-sunxi" group. To unsubscribe from this group and stop receiving emails from it, send an email to linux-sunxi+unsubscr...@googlegroups.com. To view this discussion on the web, visit https://groups.google.com/d/msgid/linux-sunxi/20210531044608.1006024-7-roman.beranek%40prusa3d.com.
[linux-sunxi] [PATCH 5/6] pwm: sun4i: shorten the delay to 2 cycles
As Emil Lenngren has previously shown, actually only 1-2 cycles of the prescaler-divided clock are necessary to pass before the PWM turns off (instead of a full period). I was able to reproduce his observation on a A64 using a logic analyzer. Suggested-by: Emil Lenngren Suggested-by: Pascal Roeleven Signed-off-by: Roman Beranek --- drivers/pwm/pwm-sun4i.c | 13 - 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/drivers/pwm/pwm-sun4i.c b/drivers/pwm/pwm-sun4i.c index 8218173ce3f6..6ab06b9749d0 100644 --- a/drivers/pwm/pwm-sun4i.c +++ b/drivers/pwm/pwm-sun4i.c @@ -71,7 +71,7 @@ static const u32 prescaler_table[] = { 72000, 0, 0, - 0, /* Actually 1 but tested separately */ + 1, /* Tested separately */ }; struct sun4i_pwm_data { @@ -240,7 +240,7 @@ static int sun4i_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, struct pwm_state cstate; u32 ctrl, duty = 0, period = 0, val; int ret; - unsigned int prescaler = 0; + unsigned int cycle_ns, current_prescaler, prescaler = 0; bool bypass; pwm_get_state(pwm, ); @@ -277,7 +277,8 @@ static int sun4i_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, ctrl &= ~BIT_CH(PWM_BYPASS, pwm->hwpwm); } - if (PWM_REG_PRESCAL(ctrl, pwm->hwpwm) != prescaler) { + current_prescaler = PWM_REG_PRESCAL(ctrl, pwm->hwpwm); + if (current_prescaler != prescaler) { /* Prescaler changed, the clock has to be gated */ ctrl &= ~BIT_CH(PWM_CLK_GATING, pwm->hwpwm); sun4i_pwm_writel(sun4i_pwm, ctrl, PWM_CTRL_REG); @@ -308,8 +309,10 @@ static int sun4i_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, return 0; } - /* We need a full period to elapse before disabling the channel. */ - fsleep(cstate.period / NSEC_PER_USEC + 1); + /* We need to wait 1-2 cycles before disabling the channel. */ + cycle_ns = DIV_ROUND_UP(NSEC_PER_SEC, clk_get_rate(sun4i_pwm->clk)) + * prescaler_table[current_prescaler]; + fsleep(DIV_ROUND_UP(cycle_ns * 2, NSEC_PER_USEC)); ctrl &= ~BIT_CH(PWM_CLK_GATING, pwm->hwpwm); sun4i_pwm_writel(sun4i_pwm, ctrl, PWM_CTRL_REG); -- 2.31.1 -- You received this message because you are subscribed to the Google Groups "linux-sunxi" group. To unsubscribe from this group and stop receiving emails from it, send an email to linux-sunxi+unsubscr...@googlegroups.com. To view this discussion on the web, visit https://groups.google.com/d/msgid/linux-sunxi/20210531044608.1006024-6-roman.beranek%40prusa3d.com.
[linux-sunxi] [PATCH 2/6] pwm: sun4i: disable EN bit prior to the delay
The reason why we wait before gating the clock is to allow for the PWM to finish its cycle and stop. But it won't stop unless the EN bit is disabled. Signed-off-by: Roman Beranek --- drivers/pwm/pwm-sun4i.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/pwm/pwm-sun4i.c b/drivers/pwm/pwm-sun4i.c index 3721b9894cf6..2777abe66f79 100644 --- a/drivers/pwm/pwm-sun4i.c +++ b/drivers/pwm/pwm-sun4i.c @@ -303,6 +303,8 @@ static int sun4i_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, if (state->enabled) ctrl |= BIT_CH(PWM_EN, pwm->hwpwm); + else + ctrl &= ~BIT_CH(PWM_EN, pwm->hwpwm); sun4i_pwm_writel(sun4i_pwm, ctrl, PWM_CTRL_REG); @@ -325,7 +327,6 @@ static int sun4i_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, spin_lock(_pwm->ctrl_lock); ctrl = sun4i_pwm_readl(sun4i_pwm, PWM_CTRL_REG); ctrl &= ~BIT_CH(PWM_CLK_GATING, pwm->hwpwm); - ctrl &= ~BIT_CH(PWM_EN, pwm->hwpwm); sun4i_pwm_writel(sun4i_pwm, ctrl, PWM_CTRL_REG); spin_unlock(_pwm->ctrl_lock); -- 2.31.1 -- You received this message because you are subscribed to the Google Groups "linux-sunxi" group. To unsubscribe from this group and stop receiving emails from it, send an email to linux-sunxi+unsubscr...@googlegroups.com. To view this discussion on the web, visit https://groups.google.com/d/msgid/linux-sunxi/20210531044608.1006024-3-roman.beranek%40prusa3d.com.
[linux-sunxi] [PATCH 4/6] pwm: sun4i: simplify calculation of the delay time
There's no reason to expect a single jiffy has passed since writing the CTRL register except if a preemption has occured in the meantime. Avoid introducing unnecessary complexity and simply wait for the whole period. Signed-off-by: Roman Beranek --- drivers/pwm/pwm-sun4i.c | 17 ++--- 1 file changed, 2 insertions(+), 15 deletions(-) diff --git a/drivers/pwm/pwm-sun4i.c b/drivers/pwm/pwm-sun4i.c index b3ec59a83d00..8218173ce3f6 100644 --- a/drivers/pwm/pwm-sun4i.c +++ b/drivers/pwm/pwm-sun4i.c @@ -14,7 +14,6 @@ #include #include #include -#include #include #include #include @@ -89,7 +88,6 @@ struct sun4i_pwm_chip { void __iomem *base; struct mutex ctrl_lock; const struct sun4i_pwm_data *data; - unsigned long next_period[2]; }; static inline struct sun4i_pwm_chip *to_sun4i_pwm_chip(struct pwm_chip *chip) @@ -242,8 +240,7 @@ static int sun4i_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, struct pwm_state cstate; u32 ctrl, duty = 0, period = 0, val; int ret; - unsigned int delay_us, prescaler = 0; - unsigned long now; + unsigned int prescaler = 0; bool bypass; pwm_get_state(pwm, ); @@ -291,8 +288,6 @@ static int sun4i_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, val = (duty & PWM_DTY_MASK) | PWM_PRD(period); sun4i_pwm_writel(sun4i_pwm, val, PWM_CH_PRD(pwm->hwpwm)); - sun4i_pwm->next_period[pwm->hwpwm] = jiffies + - nsecs_to_jiffies(cstate.period + 1000); if (state->polarity != PWM_POLARITY_NORMAL) ctrl &= ~BIT_CH(PWM_ACT_STATE, pwm->hwpwm); @@ -314,15 +309,7 @@ static int sun4i_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, } /* We need a full period to elapse before disabling the channel. */ - now = jiffies; - if (time_before(now, sun4i_pwm->next_period[pwm->hwpwm])) { - delay_us = jiffies_to_usecs(sun4i_pwm->next_period[pwm->hwpwm] - - now); - if ((delay_us / 500) > MAX_UDELAY_MS) - msleep(delay_us / 1000 + 1); - else - usleep_range(delay_us, delay_us * 2); - } + fsleep(cstate.period / NSEC_PER_USEC + 1); ctrl &= ~BIT_CH(PWM_CLK_GATING, pwm->hwpwm); sun4i_pwm_writel(sun4i_pwm, ctrl, PWM_CTRL_REG); -- 2.31.1 -- You received this message because you are subscribed to the Google Groups "linux-sunxi" group. To unsubscribe from this group and stop receiving emails from it, send an email to linux-sunxi+unsubscr...@googlegroups.com. To view this discussion on the web, visit https://groups.google.com/d/msgid/linux-sunxi/20210531044608.1006024-5-roman.beranek%40prusa3d.com.
[linux-sunxi] [PATCH 3/6] pwm: sun4i: replace spinlock with a mutex
Releasing ctrl_lock for the duration of the delay is not desirable as it allows re-enabling the PWM before the delay is over. Instead, substitute the spinlock with a mutex so that we can sleep while holding it. Signed-off-by: Roman Beranek --- drivers/pwm/pwm-sun4i.c | 20 +--- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/drivers/pwm/pwm-sun4i.c b/drivers/pwm/pwm-sun4i.c index 2777abe66f79..b3ec59a83d00 100644 --- a/drivers/pwm/pwm-sun4i.c +++ b/drivers/pwm/pwm-sun4i.c @@ -16,13 +16,13 @@ #include #include #include +#include #include #include #include #include #include #include -#include #include #define PWM_CTRL_REG 0x0 @@ -87,7 +87,7 @@ struct sun4i_pwm_chip { struct clk *clk; struct reset_control *rst; void __iomem *base; - spinlock_t ctrl_lock; + struct mutex ctrl_lock; const struct sun4i_pwm_data *data; unsigned long next_period[2]; }; @@ -265,7 +265,7 @@ static int sun4i_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, return ret; } - spin_lock(_pwm->ctrl_lock); + mutex_lock(_pwm->ctrl_lock); ctrl = sun4i_pwm_readl(sun4i_pwm, PWM_CTRL_REG); if (sun4i_pwm->data->has_direct_mod_clk_output) { @@ -273,7 +273,7 @@ static int sun4i_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, ctrl |= BIT_CH(PWM_BYPASS, pwm->hwpwm); /* We can skip other parameter */ sun4i_pwm_writel(sun4i_pwm, ctrl, PWM_CTRL_REG); - spin_unlock(_pwm->ctrl_lock); + mutex_unlock(_pwm->ctrl_lock); return 0; } @@ -308,10 +308,10 @@ static int sun4i_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, sun4i_pwm_writel(sun4i_pwm, ctrl, PWM_CTRL_REG); - spin_unlock(_pwm->ctrl_lock); - - if (state->enabled) + if (state->enabled) { + mutex_unlock(_pwm->ctrl_lock); return 0; + } /* We need a full period to elapse before disabling the channel. */ now = jiffies; @@ -324,11 +324,9 @@ static int sun4i_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, usleep_range(delay_us, delay_us * 2); } - spin_lock(_pwm->ctrl_lock); - ctrl = sun4i_pwm_readl(sun4i_pwm, PWM_CTRL_REG); ctrl &= ~BIT_CH(PWM_CLK_GATING, pwm->hwpwm); sun4i_pwm_writel(sun4i_pwm, ctrl, PWM_CTRL_REG); - spin_unlock(_pwm->ctrl_lock); + mutex_unlock(_pwm->ctrl_lock); clk_disable_unprepare(sun4i_pwm->clk); @@ -471,7 +469,7 @@ static int sun4i_pwm_probe(struct platform_device *pdev) pwm->chip.of_xlate = of_pwm_xlate_with_flags; pwm->chip.of_pwm_n_cells = 3; - spin_lock_init(>ctrl_lock); + mutex_init(>ctrl_lock); ret = pwmchip_add(>chip); if (ret < 0) { -- 2.31.1 -- You received this message because you are subscribed to the Google Groups "linux-sunxi" group. To unsubscribe from this group and stop receiving emails from it, send an email to linux-sunxi+unsubscr...@googlegroups.com. To view this discussion on the web, visit https://groups.google.com/d/msgid/linux-sunxi/20210531044608.1006024-4-roman.beranek%40prusa3d.com.
[linux-sunxi] [PATCH 1/6] pwm: sun4i: enable clk prior to getting its rate
Ensure the PWM clock is enabled prior to retrieving its rate, as is already being done in sun4i_pwm_apply. Signed-off-by: Roman Beranek --- drivers/pwm/pwm-sun4i.c | 7 +++ 1 file changed, 7 insertions(+) diff --git a/drivers/pwm/pwm-sun4i.c b/drivers/pwm/pwm-sun4i.c index e01becd102c0..3721b9894cf6 100644 --- a/drivers/pwm/pwm-sun4i.c +++ b/drivers/pwm/pwm-sun4i.c @@ -117,8 +117,15 @@ static void sun4i_pwm_get_state(struct pwm_chip *chip, u64 clk_rate, tmp; u32 val; unsigned int prescaler; + int ret; + ret = clk_prepare_enable(sun4i_pwm->clk); + if (ret) { + dev_err(chip->dev, "failed to enable PWM clock\n"); + return; + } clk_rate = clk_get_rate(sun4i_pwm->clk); + clk_disable_unprepare(sun4i_pwm->clk); val = sun4i_pwm_readl(sun4i_pwm, PWM_CTRL_REG); -- 2.31.1 -- You received this message because you are subscribed to the Google Groups "linux-sunxi" group. To unsubscribe from this group and stop receiving emails from it, send an email to linux-sunxi+unsubscr...@googlegroups.com. To view this discussion on the web, visit https://groups.google.com/d/msgid/linux-sunxi/20210531044608.1006024-2-roman.beranek%40prusa3d.com.
[linux-sunxi] [PATCH 0/6] pwm: sun4i: only wait 2 cycles prior to disabling
As Emil Lenngren has previously shown [1], actually only 1-2 cycles of the prescaler-divided clock are necessary to pass before the PWM turns off, not a full period. To avoid having the PWM re-enabled from another thread while asleep, ctrl_lock spinlock was converted to a mutex so that it can be released only after the clock gate has finally been turned on. [1] https://linux-sunxi.org/PWM_Controller_Register_Guide Roman Beranek (6): pwm: sun4i: enable clk prior to getting its rate pwm: sun4i: disable EN bit prior to the delay pwm: sun4i: replace spinlock with a mutex pwm: sun4i: simplify calculation of the delay time pwm: sun4i: shorten the delay to 2 cycles pwm: sun4i: don't delay if the PWM is already off drivers/pwm/pwm-sun4i.c | 56 +++-- 1 file changed, 26 insertions(+), 30 deletions(-) -- 2.31.1 -- You received this message because you are subscribed to the Google Groups "linux-sunxi" group. To unsubscribe from this group and stop receiving emails from it, send an email to linux-sunxi+unsubscr...@googlegroups.com. To view this discussion on the web, visit https://groups.google.com/d/msgid/linux-sunxi/20210531044608.1006024-1-roman.beranek%40prusa3d.com.
[linux-sunxi] Pull request: u-boot-sunxi/master for v2021.07
Hi Tom, please pull the master branch from u-boot-sunxi, containing the fix to bring back the SD card as MMC0. In the long run we are looking into a more robust solution, but for now we need to fix this, as this breaks the user experience left, right, and centre. Also add the one MAINTAINERS path addition from Samuel. Thanks, Andre == The following changes since commit ffd810487ec2ff6095edf3f3d058d7ed6eb85ff3: Merge tag 'u-boot-stm32-20210528' of https://source.denx.de/u-boot/custodians/u-boot-stm (2021-05-28 14:11:06 -0400) are available in the Git repository at: https://source.denx.de/u-boot/custodians/u-boot-sunxi.git master for you to fetch changes up to f264e796c06d7ce6c039bfc7255390309cbc5191: MAINTAINERS: Add allwinner/sunxi driver directories (2021-05-31 00:39:54 +0100) Andre Przywara (1): sunxi: Bring back SD card as MMC device 0 Samuel Holland (1): MAINTAINERS: Add allwinner/sunxi driver directories MAINTAINERS| 3 +++ arch/arm/dts/sunxi-u-boot.dtsi | 1 + 2 files changed, 4 insertions(+) -- You received this message because you are subscribed to the Google Groups "linux-sunxi" group. To unsubscribe from this group and stop receiving emails from it, send an email to linux-sunxi+unsubscr...@googlegroups.com. To view this discussion on the web, visit https://groups.google.com/d/msgid/linux-sunxi/20210531002345.1335-1-andre.przywara%40arm.com.