summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHolmes Chou <holmeschou@google.com>2022-12-30 11:58:28 +0000
committerHolmes Chou <holmeschou@google.com>2023-02-23 06:53:19 +0000
commit557b4f33d28798f87a5feccd83eb6dc6cbbf2b0c (patch)
tree5798104dad9cfb83f0942bfcdc77cde898e41f30
parent64a6cff96bc31a57231b1fd33790fcb6db769a1e (diff)
downloadlwis-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.c38
-rw-r--r--lwis_dt.c17
-rw-r--r--lwis_gpio.h2
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) {
diff --git a/lwis_dt.c b/lwis_dt.c
index 4c263a1..bdfb6ba 100644
--- a/lwis_dt.c
+++ b/lwis_dt.c
@@ -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;