Skip to content

Commit 83466c2

Browse files
fabiobaltierihenrikbrixandersen
authored andcommitted
input: gpio_keys: fix suspend race condition
Change the suspend/resume code to ensure that the interrupt are disabled before changing the pin configuration. The current sequence has been reported to cause spurious readouts on some platforms, this takes the existing code and duplicates for the suspend and resume case, but swaps the interrupt disable and configure for the suspend case. Signed-off-by: Fabio Baltieri <[email protected]> (cherry picked from commit d0a8c41)
1 parent 78aaf1d commit 83466c2

File tree

1 file changed

+41
-33
lines changed

1 file changed

+41
-33
lines changed

drivers/input/input_gpio_keys.c

Lines changed: 41 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -207,51 +207,59 @@ static int gpio_keys_pm_action(const struct device *dev,
207207
const struct gpio_keys_config *cfg = dev->config;
208208
struct gpio_keys_data *data = dev->data;
209209
struct gpio_keys_pin_data *pin_data = cfg->pin_data;
210-
gpio_flags_t gpio_flags;
211-
gpio_flags_t int_flags;
212210
int ret;
213211

214212
switch (action) {
215213
case PM_DEVICE_ACTION_SUSPEND:
216-
gpio_flags = GPIO_DISCONNECTED;
217-
int_flags = GPIO_INT_DISABLE;
218214
atomic_set(&data->suspended, 1);
219-
break;
220-
case PM_DEVICE_ACTION_RESUME:
221-
gpio_flags = GPIO_INPUT;
222-
int_flags = GPIO_INT_EDGE_BOTH;
223-
atomic_set(&data->suspended, 0);
224-
break;
225-
default:
226-
return -ENOTSUP;
227-
}
228215

229-
for (int i = 0; i < cfg->num_keys; i++) {
230-
const struct gpio_dt_spec *gpio = &cfg->pin_cfg[i].spec;
231-
232-
ret = gpio_pin_configure_dt(gpio, gpio_flags);
233-
if (ret != 0) {
234-
LOG_ERR("Pin %d configuration failed: %d", i, ret);
235-
return ret;
216+
for (int i = 0; i < cfg->num_keys; i++) {
217+
const struct gpio_dt_spec *gpio = &cfg->pin_cfg[i].spec;
218+
219+
if (!cfg->polling_mode) {
220+
ret = gpio_pin_interrupt_configure_dt(gpio, GPIO_INT_DISABLE);
221+
if (ret < 0) {
222+
LOG_ERR("interrupt configuration failed: %d", ret);
223+
return ret;
224+
}
225+
}
226+
227+
ret = gpio_pin_configure_dt(gpio, GPIO_DISCONNECTED);
228+
if (ret != 0) {
229+
LOG_ERR("Pin %d configuration failed: %d", i, ret);
230+
return ret;
231+
}
236232
}
237233

238-
if (cfg->polling_mode) {
239-
continue;
240-
}
234+
return 0;
235+
case PM_DEVICE_ACTION_RESUME:
236+
atomic_set(&data->suspended, 0);
241237

242-
ret = gpio_pin_interrupt_configure_dt(gpio, int_flags);
243-
if (ret < 0) {
244-
LOG_ERR("interrupt configuration failed: %d", ret);
245-
return ret;
238+
for (int i = 0; i < cfg->num_keys; i++) {
239+
const struct gpio_dt_spec *gpio = &cfg->pin_cfg[i].spec;
240+
241+
ret = gpio_pin_configure_dt(gpio, GPIO_INPUT);
242+
if (ret != 0) {
243+
LOG_ERR("Pin %d configuration failed: %d", i, ret);
244+
return ret;
245+
}
246+
247+
if (cfg->polling_mode) {
248+
k_work_reschedule(&pin_data[0].work,
249+
K_MSEC(cfg->debounce_interval_ms));
250+
} else {
251+
ret = gpio_pin_interrupt_configure_dt(gpio, GPIO_INT_EDGE_BOTH);
252+
if (ret < 0) {
253+
LOG_ERR("interrupt configuration failed: %d", ret);
254+
return ret;
255+
}
256+
}
246257
}
247-
}
248258

249-
if (action == PM_DEVICE_ACTION_RESUME && cfg->polling_mode) {
250-
k_work_reschedule(&pin_data[0].work,
251-
K_MSEC(cfg->debounce_interval_ms));
259+
return 0;
260+
default:
261+
return -ENOTSUP;
252262
}
253-
254-
return 0;
255263
}
256264
#endif
257265

0 commit comments

Comments
 (0)