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
[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"

View File

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

View File

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

View File

@@ -9,9 +9,9 @@
#include <unistd.h>
/* 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,6 +144,75 @@ 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!");
/*
* 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;
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 < 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);
}
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);
@@ -137,17 +237,9 @@ int gpio_init(struct EG25Manager *manager, toml_table_t *config[])
chipidx = 1;
}
manager->gpio_out[i] = gpiod_chip_get_line(manager->gpiochip[chipidx], offset);
if (!manager->gpio_out[i]) {
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);
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);
return 1;
}
}
for (i = 0; i < GPIO_IN_COUNT; i++) {
@@ -162,16 +254,9 @@ int gpio_init(struct EG25Manager *manager, toml_table_t *config[])
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;
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);
}
}