25
25
26
26
#define KTD253_T_LOW_NS (200 + 10) /* Additional 10ns as safety factor */
27
27
#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 */
28
29
#define KTD253_T_OFF_MS 3
29
30
30
31
struct ktd253_backlight {
@@ -34,13 +35,50 @@ struct ktd253_backlight {
34
35
u16 ratio ;
35
36
};
36
37
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
+
37
75
static int ktd253_backlight_update_status (struct backlight_device * bl )
38
76
{
39
77
struct ktd253_backlight * ktd253 = bl_get_data (bl );
40
78
int brightness = backlight_get_brightness (bl );
41
79
u16 target_ratio ;
42
80
u16 current_ratio = ktd253 -> ratio ;
43
- unsigned long flags ;
81
+ int ret ;
44
82
45
83
dev_dbg (ktd253 -> dev , "new brightness/ratio: %d/32\n" , brightness );
46
84
@@ -62,37 +100,34 @@ static int ktd253_backlight_update_status(struct backlight_device *bl)
62
100
}
63
101
64
102
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 );
68
104
current_ratio = KTD253_MAX_RATIO ;
69
105
}
70
106
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 );
79
107
while (current_ratio != target_ratio ) {
80
108
/*
81
109
* These GPIO operations absolutely can NOT sleep so no
82
110
* _cansleep suffixes, and no using GPIO expanders on
83
111
* slow buses for this!
84
112
*/
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 */
91
126
current_ratio = KTD253_MAX_RATIO ;
92
- else
127
+ } else {
93
128
current_ratio -- ;
129
+ }
94
130
}
95
- local_irq_restore (flags );
96
131
ktd253 -> ratio = current_ratio ;
97
132
98
133
dev_dbg (ktd253 -> dev , "new ratio set to %d/32\n" , target_ratio );
0 commit comments