Skip to content

Commit 590c061

Browse files
committed
pinctrl: Also look for GPIO chips without aliases
Some platforms have additional GPIO chips that currently lack gpio<n> aliases. Use sysfs to look for them, in case we support them. Signed-off-by: Phil Elwell <[email protected]>
1 parent 2ae6377 commit 590c061

File tree

1 file changed

+88
-34
lines changed

1 file changed

+88
-34
lines changed

pinctrl/gpiolib.c

Lines changed: 88 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#define _FILE_OFFSET_BITS 64
22
#include <assert.h>
3+
#include <dirent.h>
34
#include <errno.h>
45
#include <inttypes.h>
56
#include <fcntl.h>
@@ -51,14 +52,24 @@ static GPIO_CHIP_INSTANCE_T *gpio_create_instance(const GPIO_CHIP_T *chip,
5152
const char *name,
5253
const char *dtnode)
5354
{
54-
GPIO_CHIP_INSTANCE_T *inst = &gpio_chips[num_gpio_chips];
55+
GPIO_CHIP_INSTANCE_T *inst;
56+
unsigned i;
57+
58+
// Skip it if already discovered
59+
for (i = 0; i < num_gpio_chips; i++)
60+
{
61+
if (!strcmp(gpio_chips[i].dtnode, dtnode))
62+
return NULL;
63+
}
5564

5665
if (num_gpio_chips >= MAX_GPIO_CHIPS)
5766
{
5867
assert(0);
5968
return NULL;
6069
}
6170

71+
inst = &gpio_chips[num_gpio_chips];
72+
6273
inst->chip = chip;
6374
inst->name = name ? name : chip->name;
6475
inst->dtnode = dtnode;
@@ -411,19 +422,66 @@ static const GPIO_CHIP_T *gpio_find_chip(const char *name)
411422
return NULL;
412423
}
413424

425+
static GPIO_CHIP_INSTANCE_T *gpio_add_chip_instance(const char *dtnode, const char *gpiomem_idx)
426+
{
427+
char pathbuf[FILENAME_MAX];
428+
GPIO_CHIP_INSTANCE_T *inst;
429+
const GPIO_CHIP_T *chip;
430+
uint64_t phys_addr;
431+
char *compatible;
432+
433+
compatible = dt_read_prop(dtnode, "compatible", NULL);
434+
if (!compatible)
435+
{
436+
sprintf(pathbuf, "%s/..", dtnode);
437+
compatible = dt_read_prop(pathbuf, "compatible", NULL);
438+
}
439+
440+
chip = gpio_find_chip(compatible);
441+
dt_free(compatible);
442+
443+
// Skip unknown gpio chips
444+
if (!chip)
445+
return NULL;
446+
447+
if (chip->size)
448+
{
449+
phys_addr = dt_parse_addr(dtnode);
450+
if (phys_addr == INVALID_ADDRESS)
451+
return NULL;
452+
}
453+
else
454+
{
455+
phys_addr = 0;
456+
}
457+
458+
inst = gpio_create_instance(chip, phys_addr, NULL, dtnode);
459+
// Skip duplicates (or if there is an error)
460+
if (!inst)
461+
return NULL;
462+
463+
sprintf(pathbuf, "/dev/gpiomem%s", gpiomem_idx);
464+
inst->mem_fd = open(pathbuf, O_RDWR|O_SYNC);
465+
return inst;
466+
}
467+
414468
int gpiolib_init(void)
415469
{
416470
const GPIO_CHIP_T *chip;
417471
GPIO_CHIP_INSTANCE_T *inst;
418472
char pathbuf[FILENAME_MAX];
419473
char gpiomem_idx[4];
420-
const char *dtpath = "/proc/device-tree";
474+
const char *dtpath = "/sys/firmware/devicetree/base";
475+
const char *ofnode_prefix = dtpath + 4;
476+
const char *gpiopath = "/sys/bus/gpio/devices";
477+
DIR *dir;
478+
struct dirent *de;
421479
const char *p;
422-
char *alias = NULL, *names, *end, *compatible;
423-
uint64_t phys_addr;
480+
char *alias = NULL, *names, *end;
424481
size_t names_len;
425482
unsigned gpio_base;
426483
unsigned pin, i;
484+
int prefix_len, len;
427485

428486
for (pin = 0; pin <= NUM_HDR_PINS; pin++)
429487
hdr_gpios[pin] = GPIO_INVALID;
@@ -447,6 +505,7 @@ int gpiolib_init(void)
447505

448506
dt_set_path(dtpath);
449507

508+
// Scan the gpio<n> aliases, stopping at the first absence
450509
for (i = 0; ; i++)
451510
{
452511
sprintf(pathbuf, "gpio%d", i);
@@ -459,40 +518,32 @@ int gpiolib_init(void)
459518
}
460519
if (!alias)
461520
break;
462-
463-
compatible = dt_read_prop(alias, "compatible", NULL);
464-
if (!compatible)
465-
{
466-
sprintf(pathbuf, "%s/..", alias);
467-
compatible = dt_read_prop(pathbuf, "compatible", NULL);
468-
}
469-
470-
chip = gpio_find_chip(compatible);
471-
dt_free(compatible);
472-
473-
if (!chip)
474-
{
475-
// Skip the unknown gpio chip
476-
dt_free(alias);
477-
continue;
478-
}
479-
480-
phys_addr = dt_parse_addr(alias);
481-
if (phys_addr == INVALID_ADDRESS)
482-
{
521+
if (!gpio_add_chip_instance(alias, gpiomem_idx))
483522
dt_free(alias);
484-
return -1;
485-
}
523+
}
486524

487-
inst = gpio_create_instance(chip, phys_addr, NULL, alias);
488-
if (!inst)
525+
// Now look for other gpio chips without aliases
526+
dir = opendir(gpiopath);
527+
prefix_len = strlen(ofnode_prefix);
528+
while (dir && ((de = readdir(dir)) != NULL))
529+
{
530+
if (de->d_name[0] != '.')
489531
{
490-
dt_free(alias);
491-
return -1;
532+
char symlink[FILENAME_MAX];
533+
char *match;
534+
char *dtnode;
535+
sprintf(pathbuf, "%s/%s/of_node", gpiopath, de->d_name);
536+
len = readlink(pathbuf, symlink, sizeof(symlink));
537+
if (len < 0)
538+
continue;
539+
symlink[len] = '\0';
540+
match = strstr(symlink, ofnode_prefix);
541+
if (!match)
542+
continue;
543+
dtnode = strdup(match + prefix_len);
544+
if (dtnode && !gpio_add_chip_instance(dtnode, gpiomem_idx))
545+
free(dtnode);
492546
}
493-
494-
sprintf(pathbuf, "/dev/gpiomem%s", gpiomem_idx);
495-
inst->mem_fd = open(pathbuf, O_RDWR|O_SYNC);
496547
}
497548

498549
gpio_base = 0;
@@ -663,6 +714,9 @@ int gpiolib_mmap(void)
663714
inst = &gpio_chips[i];
664715
chip = inst->chip;
665716

717+
if (!chip->interface->gpio_probe_instance || !chip->size)
718+
continue;
719+
666720
align = inst->phys_addr & (pagesize - 1);
667721

668722
if (inst->mem_fd >= 0)

0 commit comments

Comments
 (0)