Skip to content

Commit daa3736

Browse files
Linus WalleijLee Jones
authored andcommitted
backlight: ktd253: Stabilize backlight
Remove interrupt disablement during backlight setting. It is way to dangerous and makes platforms instable by having it miss vblank IRQs leading to the graphics derailing. The code is using ndelay() which is not available on platforms such as ARM and will result in 32 * udelay(1) which is substantial. Add some code to detect if an interrupt occurs during the tight loop and in that case just redo it from the top. Fixes: 5317f37 ("backlight: Add Kinetic KTD253 backlight driver") Cc: Stephan Gerhold <stephan@gerhold.net> Reported-by: newbyte@disroot.org Reviewed-by: Daniel Thompson <daniel.thompson@linaro.org> Signed-off-by: Linus Walleij <linus.walleij@linaro.org> Signed-off-by: Lee Jones <lee.jones@linaro.org>
1 parent e73f0f0 commit daa3736

1 file changed

Lines changed: 55 additions & 20 deletions

File tree

drivers/video/backlight/ktd253-backlight.c

Lines changed: 55 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525

2626
#define KTD253_T_LOW_NS (200 + 10) /* Additional 10ns as safety factor */
2727
#define KTD253_T_HIGH_NS (200 + 10) /* Additional 10ns as safety factor */
28+
#define KTD253_T_OFF_CRIT_NS 100000 /* 100 us, now it doesn't look good */
2829
#define KTD253_T_OFF_MS 3
2930

3031
struct ktd253_backlight {
@@ -34,13 +35,50 @@ struct ktd253_backlight {
3435
u16 ratio;
3536
};
3637

38+
static void ktd253_backlight_set_max_ratio(struct ktd253_backlight *ktd253)
39+
{
40+
gpiod_set_value_cansleep(ktd253->gpiod, 1);
41+
ndelay(KTD253_T_HIGH_NS);
42+
/* We always fall back to this when we power on */
43+
}
44+
45+
static int ktd253_backlight_stepdown(struct ktd253_backlight *ktd253)
46+
{
47+
/*
48+
* These GPIO operations absolutely can NOT sleep so no _cansleep
49+
* suffixes, and no using GPIO expanders on slow buses for this!
50+
*
51+
* The maximum number of cycles of the loop is 32 so the time taken
52+
* should nominally be:
53+
* (T_LOW_NS + T_HIGH_NS + loop_time) * 32
54+
*
55+
* Architectures do not always support ndelay() and we will get a few us
56+
* instead. If we get to a critical time limit an interrupt has likely
57+
* occured in the low part of the loop and we need to restart from the
58+
* top so we have the backlight in a known state.
59+
*/
60+
u64 ns;
61+
62+
ns = ktime_get_ns();
63+
gpiod_set_value(ktd253->gpiod, 0);
64+
ndelay(KTD253_T_LOW_NS);
65+
gpiod_set_value(ktd253->gpiod, 1);
66+
ns = ktime_get_ns() - ns;
67+
if (ns >= KTD253_T_OFF_CRIT_NS) {
68+
dev_err(ktd253->dev, "PCM on backlight took too long (%llu ns)\n", ns);
69+
return -EAGAIN;
70+
}
71+
ndelay(KTD253_T_HIGH_NS);
72+
return 0;
73+
}
74+
3775
static int ktd253_backlight_update_status(struct backlight_device *bl)
3876
{
3977
struct ktd253_backlight *ktd253 = bl_get_data(bl);
4078
int brightness = backlight_get_brightness(bl);
4179
u16 target_ratio;
4280
u16 current_ratio = ktd253->ratio;
43-
unsigned long flags;
81+
int ret;
4482

4583
dev_dbg(ktd253->dev, "new brightness/ratio: %d/32\n", brightness);
4684

@@ -62,37 +100,34 @@ static int ktd253_backlight_update_status(struct backlight_device *bl)
62100
}
63101

64102
if (current_ratio == 0) {
65-
gpiod_set_value_cansleep(ktd253->gpiod, 1);
66-
ndelay(KTD253_T_HIGH_NS);
67-
/* We always fall back to this when we power on */
103+
ktd253_backlight_set_max_ratio(ktd253);
68104
current_ratio = KTD253_MAX_RATIO;
69105
}
70106

71-
/*
72-
* WARNING:
73-
* The loop to set the correct current level is performed
74-
* with interrupts disabled as it is timing critical.
75-
* The maximum number of cycles of the loop is 32
76-
* so the time taken will be (T_LOW_NS + T_HIGH_NS + loop_time) * 32,
77-
*/
78-
local_irq_save(flags);
79107
while (current_ratio != target_ratio) {
80108
/*
81109
* These GPIO operations absolutely can NOT sleep so no
82110
* _cansleep suffixes, and no using GPIO expanders on
83111
* slow buses for this!
84112
*/
85-
gpiod_set_value(ktd253->gpiod, 0);
86-
ndelay(KTD253_T_LOW_NS);
87-
gpiod_set_value(ktd253->gpiod, 1);
88-
ndelay(KTD253_T_HIGH_NS);
89-
/* After 1/32 we loop back to 32/32 */
90-
if (current_ratio == KTD253_MIN_RATIO)
113+
ret = ktd253_backlight_stepdown(ktd253);
114+
if (ret == -EAGAIN) {
115+
/*
116+
* Something disturbed the backlight setting code when
117+
* running so we need to bring the PWM back to a known
118+
* state. This shouldn't happen too much.
119+
*/
120+
gpiod_set_value_cansleep(ktd253->gpiod, 0);
121+
msleep(KTD253_T_OFF_MS);
122+
ktd253_backlight_set_max_ratio(ktd253);
123+
current_ratio = KTD253_MAX_RATIO;
124+
} else if (current_ratio == KTD253_MIN_RATIO) {
125+
/* After 1/32 we loop back to 32/32 */
91126
current_ratio = KTD253_MAX_RATIO;
92-
else
127+
} else {
93128
current_ratio--;
129+
}
94130
}
95-
local_irq_restore(flags);
96131
ktd253->ratio = current_ratio;
97132

98133
dev_dbg(ktd253->dev, "new ratio set to %d/32\n", target_ratio);

0 commit comments

Comments
 (0)