Skip to content

Commit

Permalink
gpio: add support for node label based lookup in the shell
Browse files Browse the repository at this point in the history
Use some new kernel features to make the experience of finding and
dealing with GPIO devices much more ergonomic by allowing the use of
devicetree node labels to identify GPIO devices by default.

Users who wish to avoid the associated footprint penalty can set
CONFIG_DEVICE_DT_METADATA=n by hand, but I think the convenience is
worth the price as a default. If we're running a shell, then we've
already paid a heavy footprint penalty.

Example output for qemu_cortex_m3:

    uart:~$ gpio devices
    Device           Other names
    gpio@40004000    gpio0
    gpio@40005000    gpio1
    gpio@40006000    gpio2
    gpio@40007000    gpio3
    gpio@40024000    gpio4
    gpio@40025000    gpio5
    gpio@40026000    gpio6

Signed-off-by: Martí Bolívar <[email protected]>
  • Loading branch information
mbolivar-ampere authored and aescolar committed Jun 12, 2024
1 parent 15c9d37 commit 48a14dc
Show file tree
Hide file tree
Showing 2 changed files with 62 additions and 2 deletions.
1 change: 1 addition & 0 deletions drivers/gpio/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ source "subsys/logging/Kconfig.template.log_config"
config GPIO_SHELL
bool "GPIO Shell"
depends on SHELL
imply DEVICE_DT_METADATA
help
Enable GPIO Shell for testing.

Expand Down
63 changes: 61 additions & 2 deletions drivers/gpio/gpio_shell.c
Original file line number Diff line number Diff line change
Expand Up @@ -134,16 +134,43 @@ DT_FOREACH_STATUS_OKAY_NODE(IS_GPIO_CTRL_PIN_GET)

static const struct gpio_ctrl gpio_list[] = {DT_FOREACH_STATUS_OKAY_NODE(IS_GPIO_CTRL_LIST)};

static const struct gpio_ctrl *get_gpio_ctrl(char *name)
static const struct gpio_ctrl *get_gpio_ctrl_helper(const struct device *dev)
{
const struct device *dev = device_get_binding(name);
size_t i;

if (dev == NULL) {
return NULL;
}

for (i = 0; i < ARRAY_SIZE(gpio_list); i++) {
if (gpio_list[i].dev == dev) {
return &gpio_list[i];
}
}

return NULL;
}

/* Look up a device by some human-readable string identifier. We
* always search among device names. If the feature is available, we
* search by node label as well.
*/
static const struct gpio_ctrl *get_gpio_ctrl(char *id)
{
const struct gpio_ctrl *ctrl;

ctrl = get_gpio_ctrl_helper(device_get_binding(id));
if (ctrl != NULL) {
return ctrl;
}

#ifdef CONFIG_DEVICE_DT_METADATA
ctrl = get_gpio_ctrl_helper(device_get_by_dt_nodelabel(id));
if (ctrl != NULL) {
return ctrl;
}
#endif /* CONFIG_DEVICE_DT_METADATA */

return NULL;
}

Expand Down Expand Up @@ -401,6 +428,35 @@ static int cmd_gpio_toggle(const struct shell *sh, size_t argc, char **argv)
return 0;
}

static int cmd_gpio_devices(const struct shell *sh, size_t argc, char **argv)
{
size_t i;

shell_fprintf(sh, SHELL_NORMAL, "%-16s Other names\n", "Device");

for (i = 0; i < ARRAY_SIZE(gpio_list); i++) {
const struct device *dev = gpio_list[i].dev;

shell_fprintf(sh, SHELL_NORMAL, "%-16s", dev->name);

#ifdef CONFIG_DEVICE_DT_METADATA
const struct device_dt_nodelabels *nl = device_get_dt_nodelabels(dev);

if (nl->num_nodelabels > 0) {
for (size_t j = 0; j < nl->num_nodelabels; j++) {
const char *nodelabel = nl->nodelabels[j];

shell_fprintf(sh, SHELL_NORMAL, " %s", nodelabel);
}
}
#endif

shell_fprintf(sh, SHELL_NORMAL, "\n");
}

return 0;
}

/* 500 msec = 1/2 sec */
#define SLEEP_TIME_MS 500

Expand Down Expand Up @@ -618,6 +674,9 @@ SHELL_STATIC_SUBCMD_SET_CREATE(sub_gpio,
SHELL_COND_CMD_ARG(CONFIG_GPIO_SHELL_TOGGLE_CMD, toggle, &sub_gpio_dev,
"Toggle GPIO pin\n"
"Usage: gpio toggle <device> <pin>", cmd_gpio_toggle, 3, 0),
SHELL_CMD(devices, NULL,
"List all GPIO devices\n"
"Usage: gpio devices", cmd_gpio_devices),
SHELL_COND_CMD_ARG(CONFIG_GPIO_SHELL_BLINK_CMD, blink, &sub_gpio_dev,
"Blink GPIO pin\n"
"Usage: gpio blink <device> <pin>", cmd_gpio_blink, 3, 0),
Expand Down

0 comments on commit 48a14dc

Please sign in to comment.