From e3387e85ca11aafc72544d2923573d62bac9537f Mon Sep 17 00:00:00 2001 From: Arnaud Ferraris Date: Thu, 10 Dec 2020 16:56:18 +0100 Subject: [PATCH 1/4] manager: destroy at/gpio modules after the main loop exits --- src/manager.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/manager.c b/src/manager.c index d50aae6..ac04cad 100644 --- a/src/manager.c +++ b/src/manager.c @@ -22,9 +22,6 @@ static gboolean quit_timeout_cb(struct EG25Manager *manager) g_message("Modem down, quitting..."); g_main_loop_quit(manager->loop); - at_destroy(manager); - gpio_destroy(manager); - return FALSE; } @@ -156,5 +153,8 @@ int main(int argc, char *argv[]) g_main_loop_run(manager.loop); + at_destroy(&manager); + gpio_destroy(&manager); + return 0; } From 1170a2c7f7d74016e5068f5dd290076feb4d617f Mon Sep 17 00:00:00 2001 From: Arnaud Ferraris Date: Thu, 10 Dec 2020 17:03:11 +0100 Subject: [PATCH 2/4] gpio: configure STATUS input gpio RI won't be accessible due to it being used by the kernel as an interrupt source, so we can check the STATUS pin (CE only) which will allow us to know precisely when the modem is shut down. --- src/gpio.c | 77 ++++++++++++++++++++++++++++++++++++++++----------- src/manager.h | 1 + 2 files changed, 62 insertions(+), 16 deletions(-) diff --git a/src/gpio.c b/src/gpio.c index bfe505c..d424b6e 100644 --- a/src/gpio.c +++ b/src/gpio.c @@ -11,6 +11,8 @@ #define MAX_GPIOCHIP_LINES 352 +#define GPIO_IDX_INVAL 0xffff + enum { GPIO_OUT_DTR = 0, GPIO_OUT_PWRKEY, @@ -20,7 +22,7 @@ enum { GPIO_OUT_COUNT }; -static unsigned gpio_idx_bh[] = { +static unsigned gpio_out_idx_bh[] = { 358, 35, 68, @@ -28,7 +30,7 @@ static unsigned gpio_idx_bh[] = { 232 }; -static unsigned gpio_idx_ce[] = { +static unsigned gpio_out_idx_ce[] = { 34, 35, 68, @@ -36,6 +38,19 @@ static unsigned gpio_idx_ce[] = { 232 }; +enum { + GPIO_IN_STATUS = 0, + GPIO_IN_COUNT +}; + +static unsigned gpio_in_idx_bh[] = { + GPIO_IDX_INVAL, +}; + +static unsigned gpio_in_idx_ce[] = { + 233, +}; + int gpio_sequence_poweron(struct EG25Manager *manager) { gpiod_line_set_value(manager->gpio_out[GPIO_OUT_PWRKEY], 1); @@ -83,7 +98,8 @@ int gpio_sequence_resume(struct EG25Manager *manager) int gpio_init(struct EG25Manager *manager) { int i, ret; - unsigned *gpio_idx; + unsigned *gpio_in_idx; + unsigned *gpio_out_idx; manager->gpiochip[0] = gpiod_chip_open_by_label(GPIO_CHIP1_LABEL); if (!manager->gpiochip[0]) { @@ -91,42 +107,71 @@ int gpio_init(struct EG25Manager *manager) return 1; } + manager->gpiochip[1] = gpiod_chip_open_by_label(GPIO_CHIP2_LABEL); + if (!manager->gpiochip[1]) { + g_critical("Unable to open GPIO chip " GPIO_CHIP2_LABEL); + return 1; + } + if (manager->braveheart) { - // BH have DTR on the 2nd gpiochip - manager->gpiochip[1] = gpiod_chip_open_by_label(GPIO_CHIP2_LABEL); - if (!manager->gpiochip[1]) { - g_critical("Unable to open GPIO chip " GPIO_CHIP2_LABEL); - return 1; - } - gpio_idx = gpio_idx_bh; + gpio_in_idx = gpio_in_idx_bh; + gpio_out_idx = gpio_out_idx_bh; } else { - gpio_idx = gpio_idx_ce; + gpio_in_idx = gpio_in_idx_ce; + gpio_out_idx = gpio_out_idx_ce; } for (i = 0; i < GPIO_OUT_COUNT; i++) { unsigned int offset, chipidx; - if (gpio_idx[i] < MAX_GPIOCHIP_LINES) { - offset = gpio_idx[i]; + if (gpio_out_idx[i] < MAX_GPIOCHIP_LINES) { + offset = gpio_out_idx[i]; chipidx = 0; } else { - offset = gpio_idx[i] - MAX_GPIOCHIP_LINES; + offset = gpio_out_idx[i] - MAX_GPIOCHIP_LINES; chipidx = 1; } manager->gpio_out[i] = gpiod_chip_get_line(manager->gpiochip[chipidx], offset); if (!manager->gpio_out[i]) { - g_critical("Unable to get line %d", i); + g_critical("Unable to get output GPIO %d", i); return 1; } ret = gpiod_line_request_output(manager->gpio_out[i], "eg25manager", 0); if (ret < 0) { - g_critical("Unable to request line %d", i); + g_critical("Unable to request output GPIO %d", i); return 1; } } + for (i = 0; i < GPIO_IN_COUNT; i++) { + unsigned int offset, chipidx; + + if (gpio_in_idx[i] == GPIO_IDX_INVAL) + continue; + + if (gpio_in_idx[i] < MAX_GPIOCHIP_LINES) { + offset = gpio_in_idx[i]; + chipidx = 0; + } else { + offset = gpio_in_idx[i] - MAX_GPIOCHIP_LINES; + chipidx = 1; + } + + manager->gpio_in[i] = gpiod_chip_get_line(manager->gpiochip[chipidx], offset); + if (!manager->gpio_in[i]) { + g_warning("Unable to get input GPIO %d", i); + continue; + } + + ret = gpiod_line_request_input(manager->gpio_in[i], "eg25manager"); + if (ret < 0) { + g_warning("Unable to request input GPIO %d", i); + manager->gpio_in[i] = NULL; + } + } + return 0; } diff --git a/src/manager.h b/src/manager.h index e44e6a0..714a812 100644 --- a/src/manager.h +++ b/src/manager.h @@ -46,6 +46,7 @@ struct EG25Manager { struct gpiod_chip *gpiochip[2]; struct gpiod_line *gpio_out[5]; + struct gpiod_line *gpio_in[2]; }; void modem_configure(struct EG25Manager *data); From 47b2f71b6f1ba21b0eed26e3008db6c2fd52787c Mon Sep 17 00:00:00 2001 From: Arnaud Ferraris Date: Thu, 10 Dec 2020 17:05:44 +0100 Subject: [PATCH 3/4] improve poweroff sequence When powering off the modem, we must assert the RESET line only when the modem has shut down (otherwise it'll cause a hard reset and won't allow the modem to shut down properly). This commit also polls the STATUS pin during poweroff and quits immediately once this pin goes high. --- src/gpio.c | 18 ++++++++++++++---- src/gpio.h | 2 ++ src/manager.c | 15 +++++++++++---- 3 files changed, 27 insertions(+), 8 deletions(-) diff --git a/src/gpio.c b/src/gpio.c index d424b6e..95973e5 100644 --- a/src/gpio.c +++ b/src/gpio.c @@ -64,11 +64,8 @@ int gpio_sequence_poweron(struct EG25Manager *manager) int gpio_sequence_shutdown(struct EG25Manager *manager) { - gpiod_line_set_value(manager->gpio_out[GPIO_OUT_RESET], 1); gpiod_line_set_value(manager->gpio_out[GPIO_OUT_DISABLE], 1); - gpiod_line_set_value(manager->gpio_out[GPIO_OUT_PWRKEY], 1); - sleep(1); - gpiod_line_set_value(manager->gpio_out[GPIO_OUT_PWRKEY], 0); + gpio_sequence_poweron(manager); g_message("Executed power-off sequence"); @@ -175,6 +172,19 @@ int gpio_init(struct EG25Manager *manager) return 0; } +gboolean gpio_check_poweroff(struct EG25Manager *manager) +{ + if (manager->gpio_in[GPIO_IN_STATUS] && + gpiod_line_get_value(manager->gpio_in[GPIO_IN_STATUS]) == 1) { + + // Asserting RESET line to prevent modem from rebooting + gpiod_line_set_value(manager->gpio_out[GPIO_OUT_RESET], 1); + return TRUE; + } + + return FALSE; +} + void gpio_destroy(struct EG25Manager *manager) { int i; diff --git a/src/gpio.h b/src/gpio.h index 52291af..a31c1ce 100644 --- a/src/gpio.h +++ b/src/gpio.h @@ -15,3 +15,5 @@ int gpio_sequence_poweron(struct EG25Manager *state); int gpio_sequence_shutdown(struct EG25Manager *state); int gpio_sequence_suspend(struct EG25Manager *state); int gpio_sequence_resume(struct EG25Manager *state); + +gboolean gpio_check_poweroff(struct EG25Manager *manager); diff --git a/src/manager.c b/src/manager.c index ac04cad..f07c0e8 100644 --- a/src/manager.c +++ b/src/manager.c @@ -25,6 +25,16 @@ static gboolean quit_timeout_cb(struct EG25Manager *manager) return FALSE; } +static gboolean gpio_poll_cb(struct EG25Manager *manager) +{ + if (gpio_check_poweroff(manager)) { + quit_timeout_cb(manager); + return FALSE; + } + + return TRUE; +} + static gboolean quit_app(struct EG25Manager *manager) { g_message("Request to quit..."); @@ -33,10 +43,7 @@ static gboolean quit_app(struct EG25Manager *manager) g_message("Powering down the modem..."); gpio_sequence_shutdown(manager); manager->modem_state = EG25_STATE_FINISHING; - /* - * TODO: add a polling function to check STATUS and RI pins state - * (that way we could reduce the poweroff delay) - */ + g_timeout_add(500, G_SOURCE_FUNC(gpio_poll_cb), manager); g_timeout_add_seconds(30, G_SOURCE_FUNC(quit_timeout_cb), manager); } From a8a1c8d1615055ab731111f8369c0e252a35ca84 Mon Sep 17 00:00:00 2001 From: Arnaud Ferraris Date: Thu, 10 Dec 2020 17:07:36 +0100 Subject: [PATCH 4/4] manager: improve BH/CE detection `Developer edition` phones have a different compatible string but should be considered identical to BraveHeart edition here. Therefore BH is the default phone, unless the compatible is that of a CE phone. --- src/manager.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/manager.c b/src/manager.c index f07c0e8..3156652 100644 --- a/src/manager.c +++ b/src/manager.c @@ -144,7 +144,7 @@ int main(int argc, char *argv[]) return 1; } read(fd, compatible, sizeof(compatible)); - if (strstr(compatible, "pine64,pinephone-1.1")) + if (!strstr(compatible, "pine64,pinephone-1.2")) manager.braveheart = TRUE; close(fd);