diff options
author | Holmes Chou <holmeschou@google.com> | 2022-12-30 11:58:28 +0000 |
---|---|---|
committer | Holmes Chou <holmeschou@google.com> | 2023-02-23 06:53:19 +0000 |
commit | 557b4f33d28798f87a5feccd83eb6dc6cbbf2b0c (patch) | |
tree | 5798104dad9cfb83f0942bfcdc77cde898e41f30 | |
parent | 64a6cff96bc31a57231b1fd33790fcb6db769a1e (diff) | |
download | lwis-557b4f33d28798f87a5feccd83eb6dc6cbbf2b0c.tar.gz |
LWIS: Handle shared GPIO device power down
Handover the GPIO handler to the other device that is still enabled.
It'd prevent the error when we disable a shared GPIO device.
Bug: 263340379
Test: GCA
Change-Id: I033b4f29e0f924155ee6d5a336ea80e584da1db7
Signed-off-by: Holmes Chou <holmeschou@google.com>
-rw-r--r-- | lwis_device.c | 38 | ||||
-rw-r--r-- | lwis_dt.c | 17 | ||||
-rw-r--r-- | lwis_gpio.h | 2 |
3 files changed, 56 insertions, 1 deletions
diff --git a/lwis_device.c b/lwis_device.c index 7e64435..c0f65fb 100644 --- a/lwis_device.c +++ b/lwis_device.c @@ -441,6 +441,7 @@ int lwis_dev_process_power_sequence(struct lwis_device *lwis_dev, } else if (strcmp(list->seq_info[i].type, "gpio") == 0) { struct lwis_gpios_info *gpios_info = NULL; int set_value = 0; + bool set_state = true; gpios_info = lwis_gpios_get_info_by_name(lwis_dev->gpios_list, list->seq_info[i].name); @@ -500,6 +501,41 @@ int lwis_dev_process_power_sequence(struct lwis_device *lwis_dev, set_value = 0; } + if (gpios_info->is_shared && !set_active) { + struct lwis_device *lwis_dev_it; + struct lwis_gpios_info *gpios_info_it; + + /* Look up if gpio it's already acquired */ + mutex_lock(&core.lock); + list_for_each_entry (lwis_dev_it, &core.lwis_dev_list, dev_list) { + if ((lwis_dev->id != lwis_dev_it->id) && + lwis_dev_it->enabled && lwis_dev_it->gpios_list) { + gpios_info_it = lwis_gpios_get_info_by_name( + lwis_dev_it->gpios_list, + list->seq_info[i].name); + if (IS_ERR(gpios_info_it)) { + continue; + } + if (gpios_info_it->id == gpios_info->id && + gpios_info_it->gpios == NULL) { + dev_info(lwis_dev->dev, + "Handover shared GPIO to %s\n", + lwis_dev_it->name); + gpios_info_it->gpios = gpios_info->gpios; + gpios_info_it->hold_dev = + gpios_info->hold_dev; + set_state = false; + gpios_info->gpios = NULL; + } + break; + } + } + mutex_unlock(&core.lock); + } + if (!set_state) { + continue; + } + if (gpios_info->is_pulse) { ret = lwis_gpio_list_set_output_value(gpios_info->gpios, 1 - set_value); @@ -523,7 +559,7 @@ int lwis_dev_process_power_sequence(struct lwis_device *lwis_dev, if (!set_active) { /* Release "ownership" of the GPIO pins */ - lwis_gpio_list_put(gpios_info->gpios, &lwis_dev->plat_dev->dev); + lwis_gpio_list_put(gpios_info->gpios, gpios_info->hold_dev); gpios_info->gpios = NULL; } } else if (strcmp(list->seq_info[i].type, "pinctrl") == 0) { @@ -971,6 +971,8 @@ static int parse_power_seqs(struct lwis_device *lwis_dev, const char *seq_name, for (i = 0; i < power_seq_count; ++i) { struct lwis_gpios_info *gpios_info; char *seq_item_name; + struct device *dev; + struct gpio_descs *descs; if (strcmp((*list)->seq_info[i].type, "gpio") != 0) { continue; @@ -978,6 +980,21 @@ static int parse_power_seqs(struct lwis_device *lwis_dev, const char *seq_name, gpios_info = &lwis_dev->gpios_list->gpios_info[type_gpio_count]; seq_item_name = (*list)->seq_info[i].name; + dev = &lwis_dev->plat_dev->dev; + descs = lwis_gpio_list_get(dev, seq_item_name); + if (IS_ERR(descs)) { + pr_err("Error parsing GPIO list %s (%ld)\n", seq_item_name, + PTR_ERR(descs)); + ret = PTR_ERR(descs); + goto error_parse_power_seqs; + } + gpios_info->id = desc_to_gpio(descs->desc[0]); + gpios_info->hold_dev = dev; + /* + * The GPIO pins are valid, release the list as we do not need to hold + * on to the pins yet + */ + lwis_gpio_list_put(descs, dev); gpios_info->gpios = NULL; gpios_info->irq_list = NULL; diff --git a/lwis_gpio.h b/lwis_gpio.h index 2dc0ea3..52817e7 100644 --- a/lwis_gpio.h +++ b/lwis_gpio.h @@ -20,6 +20,8 @@ * This structure is to store the gpios information */ struct lwis_gpios_info { + int id; + struct device *hold_dev; char name[LWIS_MAX_NAME_STRING_LEN]; bool is_shared; bool is_pulse; |