gpio: make more generic

Instead of assuming we're running on the PinePhone (and therefore
hardcoding gpiochip labels and line numbers), make all of those
configurable. Legacy config files will still be parsed as long as they
lack the `chips` key.

Existing config files are also updated to match the new config format.
This commit is contained in:
Arnaud Ferraris
2021-11-24 01:17:57 +01:00
parent f8b3e28434
commit abf60b793a
4 changed files with 152 additions and 64 deletions

View File

@@ -13,11 +13,12 @@ poweron_delay = 100000
#recovery_timeout = 9 #recovery_timeout = 9
[gpio] [gpio]
dtr = 358 chips = [ "1c20800.pinctrl", "1f02c00.pinctrl" ]
pwrkey = 35 dtr = { chip = 1, line = 6 }
reset = 68 pwrkey = { chip = 0, line = 35 }
apready = 231 reset = { chip = 0, line = 68 }
disable = 232 apready = { chip = 0, line = 231 }
disable = { chip = 0, line = 232 }
[at] [at]
uart = "/dev/ttyS2" uart = "/dev/ttyS2"

View File

@@ -13,11 +13,12 @@ poweron_delay = 100000
#recovery_timeout = 9 #recovery_timeout = 9
[gpio] [gpio]
dtr = 358 chips = [ "1c20800.pinctrl", "1f02c00.pinctrl" ]
pwrkey = 35 dtr = { chip = 1, line = 6 }
reset = 68 pwrkey = { chip = 0, line = 35 }
apready = 231 reset = { chip = 0, line = 68 }
disable = 232 apready = { chip = 0, line = 231 }
disable = { chip = 0, line = 232 }
[at] [at]
uart = "/dev/ttyS2" uart = "/dev/ttyS2"

View File

@@ -9,12 +9,13 @@ poweron_delay = 100000
#recovery_timeout = 9 #recovery_timeout = 9
[gpio] [gpio]
dtr = 34 chips = [ "1c20800.pinctrl" ]
pwrkey = 35 dtr = { chip = 0, line = 34 }
reset = 68 pwrkey = { chip = 0, line = 35 }
apready = 231 reset = { chip = 0, line = 68 }
disable = 232 apready = { chip = 0, line = 231 }
status = 233 disable = { chip = 0, line = 232 }
status = { chip = 0, line = 233 }
[at] [at]
uart = "/dev/ttyS2" uart = "/dev/ttyS2"

View File

@@ -9,9 +9,9 @@
#include <unistd.h> #include <unistd.h>
/* Those defines are used for legacy config files only */
#define GPIO_CHIP1_LABEL "1c20800.pinctrl" #define GPIO_CHIP1_LABEL "1c20800.pinctrl"
#define GPIO_CHIP2_LABEL "1f02c00.pinctrl" #define GPIO_CHIP2_LABEL "1f02c00.pinctrl"
#define MAX_GPIOCHIP_LINES 352 #define MAX_GPIOCHIP_LINES 352
enum { enum {
@@ -101,10 +101,41 @@ int gpio_sequence_sleep(struct EG25Manager *manager)
return 0; 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 gpio_init(struct EG25Manager *manager, toml_table_t *config[])
{ {
int i, ret; int i;
guint offset, chipidx, gpio_idx;
toml_table_t *gpio_config[EG25_CONFIG_COUNT]; toml_table_t *gpio_config[EG25_CONFIG_COUNT];
for (i = 0; i < EG25_CONFIG_COUNT; i++) 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]) if (!gpio_config[EG25_CONFIG_SYS])
g_error("Default config file lacks the 'gpio' section!"); g_error("Default config file lacks the 'gpio' section!");
manager->gpiochip[0] = gpiod_chip_open_by_label(GPIO_CHIP1_LABEL); /*
if (!manager->gpiochip[0]) { * The system config could have the `chips` key, but the user one
g_critical("Unable to open GPIO chip " GPIO_CHIP1_LABEL); * could still use the old format! In order to avoid problems, we
return 1; * 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); config_get_array(gpio_config, "chips", &chipslist);
if (!manager->gpiochip[1]) { numchips = toml_array_nelem(chipslist);
g_critical("Unable to open GPIO chip " GPIO_CHIP2_LABEL); if (numchips > 2)
return 1; g_error("Requesting too many GPIO chips!");
}
for (i = 0; i < GPIO_OUT_COUNT; i++) { for (i = 0; i < numchips; i++) {
if (!config_get_uint(gpio_config, gpio_out_names[i], &gpio_idx)) toml_datum_t data = toml_string_at(chipslist, i);
g_error("Unable to get config for output GPIO '%s'", gpio_out_names[i]); if (!data.ok)
continue;
if (gpio_idx < MAX_GPIOCHIP_LINES) { manager->gpiochip[i] = gpiod_chip_open_by_label(data.u.s);
offset = gpio_idx;
chipidx = 0;
} else {
offset = gpio_idx - MAX_GPIOCHIP_LINES;
chipidx = 1;
} }
manager->gpio_out[i] = gpiod_chip_get_line(manager->gpiochip[chipidx], offset); for (i = 0; i < GPIO_OUT_COUNT; i++) {
if (!manager->gpio_out[i]) { toml_table_t *table;
g_error("Unable to get output GPIO %d", i); 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; return 1;
} }
ret = gpiod_line_request_output(manager->gpio_out[i], "eg25manager", 0); manager->gpiochip[1] = gpiod_chip_open_by_label(GPIO_CHIP2_LABEL);
if (ret < 0) { if (!manager->gpiochip[1]) {
g_error("Unable to request output GPIO %d", i); g_critical("Unable to open GPIO chip " GPIO_CHIP2_LABEL);
return 1; return 1;
} }
}
for (i = 0; i < GPIO_IN_COUNT; i++) { for (i = 0; i < GPIO_OUT_COUNT; i++) {
if (!config_get_uint(gpio_config, gpio_in_names[i], &gpio_idx)) if (!config_get_uint(gpio_config, gpio_out_names[i], &gpio_idx))
continue; g_error("Unable to get config for output GPIO '%s'", gpio_out_names[i]);
if (gpio_idx < MAX_GPIOCHIP_LINES) { if (gpio_idx < MAX_GPIOCHIP_LINES) {
offset = gpio_idx; offset = gpio_idx;
chipidx = 0; chipidx = 0;
} else { } else {
offset = gpio_idx - MAX_GPIOCHIP_LINES; offset = gpio_idx - MAX_GPIOCHIP_LINES;
chipidx = 1; 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); for (i = 0; i < GPIO_IN_COUNT; i++) {
if (!manager->gpio_in[i]) { if (!config_get_uint(gpio_config, gpio_in_names[i], &gpio_idx))
g_warning("Unable to get input GPIO %d", i); continue;
continue;
}
ret = gpiod_line_request_input(manager->gpio_in[i], "eg25manager"); if (gpio_idx < MAX_GPIOCHIP_LINES) {
if (ret < 0) { offset = gpio_idx;
g_warning("Unable to request input GPIO %d", i); chipidx = 0;
manager->gpio_in[i] = NULL; } 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);
} }
} }