diff --git a/src/gpio.c b/src/gpio.c index bfe505c..95973e5 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); @@ -49,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"); @@ -83,7 +95,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,45 +104,87 @@ 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; } +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 d50aae6..3156652 100644 --- a/src/manager.c +++ b/src/manager.c @@ -22,12 +22,19 @@ 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; } +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..."); @@ -36,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); } @@ -140,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); @@ -156,5 +160,8 @@ int main(int argc, char *argv[]) g_main_loop_run(manager.loop); + at_destroy(&manager); + gpio_destroy(&manager); + 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);