diff --git a/data/pine64,pinephone-1.0.toml b/data/pine64,pinephone-1.0.toml index 8b91a88..10dbc1e 100644 --- a/data/pine64,pinephone-1.0.toml +++ b/data/pine64,pinephone-1.0.toml @@ -13,11 +13,12 @@ poweron_delay = 100000 #recovery_timeout = 9 [gpio] -dtr = 358 -pwrkey = 35 -reset = 68 -apready = 231 -disable = 232 +chips = [ "1c20800.pinctrl", "1f02c00.pinctrl" ] +dtr = { chip = 1, line = 6 } +pwrkey = { chip = 0, line = 35 } +reset = { chip = 0, line = 68 } +apready = { chip = 0, line = 231 } +disable = { chip = 0, line = 232 } [at] uart = "/dev/ttyS2" diff --git a/data/pine64,pinephone-1.1.toml b/data/pine64,pinephone-1.1.toml index fd09462..9242a91 100644 --- a/data/pine64,pinephone-1.1.toml +++ b/data/pine64,pinephone-1.1.toml @@ -13,11 +13,12 @@ poweron_delay = 100000 #recovery_timeout = 9 [gpio] -dtr = 358 -pwrkey = 35 -reset = 68 -apready = 231 -disable = 232 +chips = [ "1c20800.pinctrl", "1f02c00.pinctrl" ] +dtr = { chip = 1, line = 6 } +pwrkey = { chip = 0, line = 35 } +reset = { chip = 0, line = 68 } +apready = { chip = 0, line = 231 } +disable = { chip = 0, line = 232 } [at] uart = "/dev/ttyS2" diff --git a/data/pine64,pinephone-1.2.toml b/data/pine64,pinephone-1.2.toml index 4244bee..3754274 100644 --- a/data/pine64,pinephone-1.2.toml +++ b/data/pine64,pinephone-1.2.toml @@ -9,12 +9,13 @@ poweron_delay = 100000 #recovery_timeout = 9 [gpio] -dtr = 34 -pwrkey = 35 -reset = 68 -apready = 231 -disable = 232 -status = 233 +chips = [ "1c20800.pinctrl" ] +dtr = { chip = 0, line = 34 } +pwrkey = { chip = 0, line = 35 } +reset = { chip = 0, line = 68 } +apready = { chip = 0, line = 231 } +disable = { chip = 0, line = 232 } +status = { chip = 0, line = 233 } [at] uart = "/dev/ttyS2" diff --git a/src/gpio.c b/src/gpio.c index c7cfc53..f9e707c 100644 --- a/src/gpio.c +++ b/src/gpio.c @@ -9,9 +9,9 @@ #include +/* Those defines are used for legacy config files only */ #define GPIO_CHIP1_LABEL "1c20800.pinctrl" #define GPIO_CHIP2_LABEL "1f02c00.pinctrl" - #define MAX_GPIOCHIP_LINES 352 enum { @@ -101,10 +101,41 @@ int gpio_sequence_sleep(struct EG25Manager *manager) return 0; } +struct gpiod_line *gpio_get_output_line(struct EG25Manager *manager, int chip, int line) +{ + struct gpiod_line *gpio_line; + + gpio_line = gpiod_chip_get_line(manager->gpiochip[chip], line); + if (!gpio_line) + return NULL; + + if (gpiod_line_request_output(gpio_line, "eg25manager", 0) < 0) { + gpiod_line_release(gpio_line); + return NULL; + } + + return gpio_line; +} + +struct gpiod_line *gpio_get_input_line(struct EG25Manager *manager, int chip, int line) +{ + struct gpiod_line *gpio_line; + + gpio_line = gpiod_chip_get_line(manager->gpiochip[chip], line); + if (!gpio_line) + return NULL; + + if (gpiod_line_request_input(gpio_line, "eg25manager") < 0) { + gpiod_line_release(gpio_line); + return NULL; + } + + return gpio_line; +} + int gpio_init(struct EG25Manager *manager, toml_table_t *config[]) { - int i, ret; - guint offset, chipidx, gpio_idx; + int i; toml_table_t *gpio_config[EG25_CONFIG_COUNT]; for (i = 0; i < EG25_CONFIG_COUNT; i++) @@ -113,65 +144,119 @@ int gpio_init(struct EG25Manager *manager, toml_table_t *config[]) if (!gpio_config[EG25_CONFIG_SYS]) g_error("Default config file lacks the 'gpio' section!"); - manager->gpiochip[0] = gpiod_chip_open_by_label(GPIO_CHIP1_LABEL); - if (!manager->gpiochip[0]) { - g_critical("Unable to open GPIO chip " GPIO_CHIP1_LABEL); - return 1; - } + /* + * The system config could have the `chips` key, but the user one + * could still use the old format! In order to avoid problems, we + * should use the new format only if: + * - there's no user config file + or + * - the user config file contains the `chips` key + * Otherwise we might start parsing the system config with the new + * format, but error out if user config overrides gpios using the + * old format + */ + if (!gpio_config[EG25_CONFIG_USER] || toml_array_in(gpio_config[EG25_CONFIG_USER], "chips")) + { + int numchips; + toml_array_t *chipslist = NULL; - 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; - } + config_get_array(gpio_config, "chips", &chipslist); + numchips = toml_array_nelem(chipslist); + if (numchips > 2) + g_error("Requesting too many GPIO chips!"); - for (i = 0; i < GPIO_OUT_COUNT; i++) { - if (!config_get_uint(gpio_config, gpio_out_names[i], &gpio_idx)) - g_error("Unable to get config for output GPIO '%s'", gpio_out_names[i]); - - if (gpio_idx < MAX_GPIOCHIP_LINES) { - offset = gpio_idx; - chipidx = 0; - } else { - offset = gpio_idx - MAX_GPIOCHIP_LINES; - chipidx = 1; + for (i = 0; i < numchips; i++) { + toml_datum_t data = toml_string_at(chipslist, i); + if (!data.ok) + continue; + manager->gpiochip[i] = gpiod_chip_open_by_label(data.u.s); } - manager->gpio_out[i] = gpiod_chip_get_line(manager->gpiochip[chipidx], offset); - if (!manager->gpio_out[i]) { - g_error("Unable to get output GPIO %d", i); + for (i = 0; i < GPIO_OUT_COUNT; i++) { + toml_table_t *table; + toml_datum_t chip, line; + if (!config_get_table(gpio_config, gpio_out_names[i], &table)) + g_error("Unable to get config for output GPIO '%s'", gpio_out_names[i]); + + chip = toml_int_in(table, "chip"); + if (!chip.ok || chip.u.i < 0 || chip.u.i > 2) + g_error("Wrong chip ID for output GPIO '%s'", gpio_out_names[i]); + + line = toml_int_in(table, "line"); + if (!line.ok || line.u.i < 0 || line.u.i > gpiod_chip_num_lines(manager->gpiochip[chip.u.i])) + g_error("Wrong chip ID for output GPIO '%s'", gpio_out_names[i]); + + manager->gpio_out[i] = gpio_get_output_line(manager, chip.u.i, line.u.i); + if (!manager->gpio_out[i]) + g_error("Unable to get output GPIO %d", i); + } + + for (i = 0; i < GPIO_IN_COUNT; i++) { + toml_table_t *table; + toml_datum_t chip, line; + if (!config_get_table(gpio_config, gpio_in_names[i], &table)) + g_error("Unable to get config for input GPIO '%s'", gpio_in_names[i]); + + chip = toml_int_in(table, "chip"); + if (!chip.ok || chip.u.i < 0 || chip.u.i > 2) + g_error("Wrong chip ID for input GPIO '%s'", gpio_in_names[i]); + + line = toml_int_in(table, "line"); + if (!line.ok || line.u.i < 0 || line.u.i > gpiod_chip_num_lines(manager->gpiochip[chip.u.i])) + g_error("Wrong chip ID for input GPIO '%s'", gpio_in_names[i]); + + manager->gpio_in[i] = gpio_get_input_line(manager, chip.u.i, line.u.i); + if (!manager->gpio_in[i]) + g_error("Unable to get input GPIO %d", i); + } + } else { + guint offset, chipidx, gpio_idx; + + /* Legacy config file, only used on the OG PinePhone */ + manager->gpiochip[0] = gpiod_chip_open_by_label(GPIO_CHIP1_LABEL); + if (!manager->gpiochip[0]) { + g_critical("Unable to open GPIO chip " GPIO_CHIP1_LABEL); return 1; } - ret = gpiod_line_request_output(manager->gpio_out[i], "eg25manager", 0); - if (ret < 0) { - g_error("Unable to request output GPIO %d", i); + 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; } - } - for (i = 0; i < GPIO_IN_COUNT; i++) { - if (!config_get_uint(gpio_config, gpio_in_names[i], &gpio_idx)) - continue; + for (i = 0; i < GPIO_OUT_COUNT; i++) { + if (!config_get_uint(gpio_config, gpio_out_names[i], &gpio_idx)) + g_error("Unable to get config for output GPIO '%s'", gpio_out_names[i]); - if (gpio_idx < MAX_GPIOCHIP_LINES) { - offset = gpio_idx; - chipidx = 0; - } else { - offset = gpio_idx - MAX_GPIOCHIP_LINES; - chipidx = 1; + if (gpio_idx < MAX_GPIOCHIP_LINES) { + offset = gpio_idx; + chipidx = 0; + } else { + offset = gpio_idx - MAX_GPIOCHIP_LINES; + chipidx = 1; + } + + manager->gpio_out[i] = gpio_get_input_line(manager, chipidx, offset); + if (!manager->gpio_out[i]) + g_error("Unable to get output GPIO %d", i); } - 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; - } + for (i = 0; i < GPIO_IN_COUNT; i++) { + if (!config_get_uint(gpio_config, gpio_in_names[i], &gpio_idx)) + 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; + if (gpio_idx < MAX_GPIOCHIP_LINES) { + offset = gpio_idx; + chipidx = 0; + } else { + offset = gpio_idx - MAX_GPIOCHIP_LINES; + chipidx = 1; + } + + manager->gpio_in[i] = gpio_get_input_line(manager, chipidx, offset); + if (!manager->gpio_in[i]) + g_error("Unable to get input GPIO %d", i); } }