Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

leds: expresswire: Fix chip state breakage

It is possible to put the KTD2801 chip in an unknown/undefined state by
changing the brightness very rapidly (for example, with a brightness
slider). When this happens, the brightness is stuck on max and cannot be
changed until the chip is power cycled.

Fix this by disabling interrupts while talking to the chip. While at it,
make expresswire_power_off() use fsleep() and also unexport some
functions meant to be internal.

Fixes: 1368d06dd2c9 ("leds: Introduce ExpressWire library")
Tested-by: Karel Balej <balejk@matfyz.cz>
Signed-off-by: Duje Mihanović <duje@dujemihanovic.xyz>
Link: https://patch.msgid.link/20251217-expresswire-fix-v2-1-4a02b10acd96@dujemihanovic.xyz
Signed-off-by: Lee Jones <lee@kernel.org>

authored by

Duje Mihanović and committed by
Lee Jones
f4b830a5 393d56d4

+17 -10
+17 -7
drivers/leds/leds-expresswire.c
··· 9 9 #include <linux/delay.h> 10 10 #include <linux/export.h> 11 11 #include <linux/gpio/consumer.h> 12 + #include <linux/irqflags.h> 12 13 #include <linux/types.h> 13 14 14 15 #include <linux/leds-expresswire.h> ··· 17 16 void expresswire_power_off(struct expresswire_common_props *props) 18 17 { 19 18 gpiod_set_value_cansleep(props->ctrl_gpio, 0); 20 - usleep_range(props->timing.poweroff_us, props->timing.poweroff_us * 2); 19 + fsleep(props->timing.poweroff_us); 21 20 } 22 21 EXPORT_SYMBOL_NS_GPL(expresswire_power_off, "EXPRESSWIRE"); 23 22 24 23 void expresswire_enable(struct expresswire_common_props *props) 25 24 { 25 + unsigned long flags; 26 + 27 + local_irq_save(flags); 28 + 26 29 gpiod_set_value(props->ctrl_gpio, 1); 27 30 udelay(props->timing.detect_delay_us); 28 31 gpiod_set_value(props->ctrl_gpio, 0); 29 32 udelay(props->timing.detect_us); 30 33 gpiod_set_value(props->ctrl_gpio, 1); 34 + 35 + local_irq_restore(flags); 31 36 } 32 37 EXPORT_SYMBOL_NS_GPL(expresswire_enable, "EXPRESSWIRE"); 33 38 34 - void expresswire_start(struct expresswire_common_props *props) 39 + static void expresswire_start(struct expresswire_common_props *props) 35 40 { 36 41 gpiod_set_value(props->ctrl_gpio, 1); 37 42 udelay(props->timing.data_start_us); 38 43 } 39 - EXPORT_SYMBOL_NS_GPL(expresswire_start, "EXPRESSWIRE"); 40 44 41 - void expresswire_end(struct expresswire_common_props *props) 45 + static void expresswire_end(struct expresswire_common_props *props) 42 46 { 43 47 gpiod_set_value(props->ctrl_gpio, 0); 44 48 udelay(props->timing.end_of_data_low_us); 45 49 gpiod_set_value(props->ctrl_gpio, 1); 46 50 udelay(props->timing.end_of_data_high_us); 47 51 } 48 - EXPORT_SYMBOL_NS_GPL(expresswire_end, "EXPRESSWIRE"); 49 52 50 - void expresswire_set_bit(struct expresswire_common_props *props, bool bit) 53 + static void expresswire_set_bit(struct expresswire_common_props *props, bool bit) 51 54 { 52 55 if (bit) { 53 56 gpiod_set_value(props->ctrl_gpio, 0); ··· 65 60 udelay(props->timing.short_bitset_us); 66 61 } 67 62 } 68 - EXPORT_SYMBOL_NS_GPL(expresswire_set_bit, "EXPRESSWIRE"); 69 63 70 64 void expresswire_write_u8(struct expresswire_common_props *props, u8 val) 71 65 { 66 + unsigned long flags; 67 + 68 + local_irq_save(flags); 69 + 72 70 expresswire_start(props); 73 71 for (int i = 7; i >= 0; i--) 74 72 expresswire_set_bit(props, val & BIT(i)); 75 73 expresswire_end(props); 74 + 75 + local_irq_restore(flags); 76 76 } 77 77 EXPORT_SYMBOL_NS_GPL(expresswire_write_u8, "EXPRESSWIRE");
-3
include/linux/leds-expresswire.h
··· 30 30 31 31 void expresswire_power_off(struct expresswire_common_props *props); 32 32 void expresswire_enable(struct expresswire_common_props *props); 33 - void expresswire_start(struct expresswire_common_props *props); 34 - void expresswire_end(struct expresswire_common_props *props); 35 - void expresswire_set_bit(struct expresswire_common_props *props, bool bit); 36 33 void expresswire_write_u8(struct expresswire_common_props *props, u8 val); 37 34 38 35 #endif /* _LEDS_EXPRESSWIRE_H */