4 Commits
0.0.1 ... 0.0.2

Author SHA1 Message Date
Arnaud Ferraris
a8a1c8d161 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.
2020-12-10 17:07:36 +01:00
Arnaud Ferraris
47b2f71b6f 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.
2020-12-10 17:05:44 +01:00
Arnaud Ferraris
1170a2c7f7 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.
2020-12-10 17:03:11 +01:00
Arnaud Ferraris
e3387e85ca manager: destroy at/gpio modules after the main loop exits 2020-12-10 16:56:18 +01:00
4 changed files with 93 additions and 28 deletions

View File

@@ -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;

View File

@@ -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);

View File

@@ -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;
}

View File

@@ -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);