[PATCH] pwm: stm32: handle polarity change when PWM is enabled

Sean Nyekjaer sean at geanix.com
Wed Jan 7 22:44:06 PST 2026


Hi Uwe,

On Thu, Jan 08, 2026 at 07:05:15AM +0100, Uwe Kleine-König wrote:
> On Wed, Jan 07, 2026 at 04:05:56PM +0000, Sean Nyekjaer wrote:
> > On Wed, Jan 07, 2026 at 04:54:46PM +0100, Uwe Kleine-König wrote:
> > > On Tue, Jan 06, 2026 at 11:30:34AM +0000, Sean Nyekjaer wrote:
> > > > On Tue, Jan 06, 2026 at 11:22:57AM +0100, Uwe Kleine-König wrote:
> > > > > On Tue, Jan 06, 2026 at 08:01:57AM +0100, Sean Nyekjaer wrote:
> > > > > > After commit 7346e7a058a2 ("pwm: stm32: Always do lazy disabling"),
> > > > > > polarity changes are ignored. Updates to the TIMx_CCER CCxP bits are
> > > > > > ignored by the hardware when the master output is enabled via the
> > > > > > TIMx_BDTR MOE bit.
> > > > > [...]
> > > > > I have hardware using this driver, will set it up later this week for
> > > > > testing.
> > > > 
> > > > Very cool, looking forward to hear if you can re-produce.
> > > 
> > > I cannot. I have:
> > > 
> > > 	# uname -r
> > > 	6.11.0-rc1-00028-geb18504ca5cf-dirty
> > > 
> > > (the -dirty is only from enabling the pwm for my machine, no driver
> > > changes)
> > > 
> > > 	# cat /sys/kernel/debug/pwm
> > > 	0: platform/40001000.timer:pwm, 4 PWM devices
> > > 	...
> > > 	 pwm-3   (sysfs               ): requested enabled period: 313720 ns duty: 10000 ns polarity: normal
> > > 
> > > and pulseview/sigrok detects 3.187251% with a period of 313.8 µs.
> > > 
> > > After
> > > 
> > > 	echo inversed > /sys/class/pwm/pwmchip0/pwm3/polarity
> > > 
> > > the output changes to
> > > 
> > > 	# cat /sys/kernel/debug/pwm
> > > 	0: platform/40001000.timer:pwm, 4 PWM devices
> > > 	...
> > > 	 pwm-3   (sysfs               ): requested enabled period: 313720 ns duty: 10000 ns polarity: inverse
> > > 
> > > and pulseview/sigrok claims 96.812749% with a period of 313.8 µs.
> > > So the polarity change happend as expected.
> > > 
> > > This is on an st,stm32mp135f-dk board.
> > > 
> > > Where is the difference to your observations?
> > > 
> > 
> > Thanks for taking a look!
> > I'm using the PWM for a backlight. With this [0] in my dts:
> > 
> > [0]:
> > 	backlight: backlight {
> > 		compatible = "pwm-backlight";
> > 		pwms = <&pwm4 0 125000 PWM_POLARITY_INVERTED>;
> > 		brightness-levels = <102 235 255>;
> > 		default-brightness-level = <80>;
> > 		num-interpolated-steps = <100>;
> > 		enable-gpios = <&gpiof 12 GPIO_ACTIVE_LOW>;
> > 	status = "okay";
> > 	};
> > 
> > Maybe that is doing something differently.
> 
> What is the actual problem you have? I assume it's the backlight being
> off after boot? Does it start working if you disable and reenable?

Yes, no backlight at default brightness. But the range is inverted so a low brightness
setting i get maximum brightness.
No, it never enters stm32_pwm_set_polarity().

> 
> Can you please boot with
> 
> 	trace_event=pwm
> 
> on the command line and provide /sys/kernel/debug/tracing/trace from
> after the problem happend?

Tracing output is the same before and after this patch:
# tracer: nop
#
# entries-in-buffer/entries-written: 2/2   #P:2
#
#                                _-----=> irqs-off/BH-disabled
#                               / _----=> need-resched
#                              | / _---=> hardirq/softirq
#                              || / _--=> preempt-depth
#                              ||| / _-=> migrate-disable
#                              |||| /     delay
#           TASK-PID     CPU#  |||||  TIMESTAMP  FUNCTION
#              | |         |   |||||     |         |
    kworker/u5:0-24      [000] .....     1.867389: pwm_apply: 482f1c0e: period=125000 duty_cycle=0 polarity=1 enabled=0 err=0
     kworker/1:0-22      [001] .....     1.984044: pwm_apply: 482f1c0e: period=125000 duty_cycle=101960 polarity=1 enabled=1 err=0

I have added this diff to the kernel to show what happens:
diff --git a/drivers/pwm/pwm-stm32.c b/drivers/pwm/pwm-stm32.c
index 67414b97ef4d..94f6d0f33365 100644
--- a/drivers/pwm/pwm-stm32.c
+++ b/drivers/pwm/pwm-stm32.c
@@ -394,6 +394,7 @@ static int stm32_pwm_set_polarity(struct stm32_pwm *priv, int ch,
 {
 	u32 mask;

+	printk("stm32_pwm_set_polarity: %d\n", polarity);
 	mask = TIM_CCER_CC1P << (ch * 4);
 	if (priv->have_complementary_output)
 		mask |= TIM_CCER_CC1NP << (ch * 4);
@@ -455,6 +456,7 @@ static int stm32_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
 	int ret;

 	enabled = pwm->state.enabled;
+	printk("stm32_pwm_apply: enabled %d, state->polarity %d, pwm->state.polarity %d\n", enabled, state->polarity, pwm->state.polarity);

 	if (!state->enabled) {
 		if (enabled)

Before this patch:
root at localhost:~# journalctl -k | grep pwm
Jan 8 7:30:33 localhost kernel: stm32_pwm_apply: enabled 0, state->polarity 1, pwm->state.polarity 0
Jan 8 7:30:33 localhost kernel: stm32_pwm_apply: enabled 0, state->polarity 1, pwm->state.polarity 1

After this patch:
root at localhost:~# journalctl -k | grep pwm
Jan 8 7:38:33 localhost kernel: stm32_pwm_apply: enabled 0, state->polarity 1, pwm->state.polarity 0
Jan 8 7:38:33 localhost kernel: stm32_pwm_set_polarity: 1
Jan 8 7:38:33 localhost kernel: stm32_pwm_apply: enabled 0, state->polarity 1, pwm->state.polarity 1

I hope that clarifies things :)

/Sean




More information about the linux-arm-kernel mailing list