uboot/drivers/sysinfo/gpio.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * Copyright (C) 2021 Sean Anderson <sean.anderson@seco.com>
   4 */
   5
   6#include <common.h>
   7#include <dm.h>
   8#include <log.h>
   9#include <sysinfo.h>
  10#include <asm/gpio.h>
  11#include <dm/device_compat.h>
  12
  13/**
  14 * struct sysinfo_gpio_priv - GPIO sysinfo private data
  15 * @gpios: List of GPIOs used to detect the revision
  16 * @gpio_num: The number of GPIOs in @gpios
  17 * @revision: The revision as detected from the GPIOs.
  18 */
  19struct sysinfo_gpio_priv {
  20        struct gpio_desc *gpios;
  21        int gpio_num, revision;
  22};
  23
  24static int sysinfo_gpio_detect(struct udevice *dev)
  25{
  26        int ret;
  27        struct sysinfo_gpio_priv *priv = dev_get_priv(dev);
  28
  29        ret = dm_gpio_get_values_as_int_base3(priv->gpios, priv->gpio_num);
  30        if (ret < 0)
  31                return ret;
  32
  33        priv->revision = ret;
  34        return 0;
  35}
  36
  37static int sysinfo_gpio_get_int(struct udevice *dev, int id, int *val)
  38{
  39        struct sysinfo_gpio_priv *priv = dev_get_priv(dev);
  40
  41        switch (id) {
  42        case SYSINFO_ID_BOARD_MODEL:
  43                *val = priv->revision;
  44                return 0;
  45        default:
  46                return -EINVAL;
  47        };
  48}
  49
  50static int sysinfo_gpio_get_str(struct udevice *dev, int id, size_t size, char *val)
  51{
  52        struct sysinfo_gpio_priv *priv = dev_get_priv(dev);
  53
  54        switch (id) {
  55        case SYSINFO_ID_BOARD_MODEL: {
  56                const char *name = NULL;
  57                int i, ret;
  58                u32 revision;
  59
  60                for (i = 0; i < priv->gpio_num; i++) {
  61                        ret = dev_read_u32_index(dev, "revisions", i,
  62                                                 &revision);
  63                        if (ret) {
  64                                if (ret != -EOVERFLOW)
  65                                        return ret;
  66                                break;
  67                        }
  68
  69                        if (revision == priv->revision) {
  70                                ret = dev_read_string_index(dev, "names", i,
  71                                                            &name);
  72                                if (ret < 0)
  73                                        return ret;
  74                                break;
  75                        }
  76                }
  77                if (!name)
  78                        name = "unknown";
  79
  80                strncpy(val, name, size);
  81                val[size - 1] = '\0';
  82                return 0;
  83        } default:
  84                return -EINVAL;
  85        };
  86}
  87
  88static const struct sysinfo_ops sysinfo_gpio_ops = {
  89        .detect = sysinfo_gpio_detect,
  90        .get_int = sysinfo_gpio_get_int,
  91        .get_str = sysinfo_gpio_get_str,
  92};
  93
  94static int sysinfo_gpio_probe(struct udevice *dev)
  95{
  96        int ret;
  97        struct sysinfo_gpio_priv *priv = dev_get_priv(dev);
  98
  99        priv->gpio_num = gpio_get_list_count(dev, "gpios");
 100        if (priv->gpio_num < 0) {
 101                dev_err(dev, "could not get gpios length (err = %d)\n",
 102                        priv->gpio_num);
 103                return priv->gpio_num;
 104        }
 105
 106        priv->gpios = calloc(priv->gpio_num, sizeof(*priv->gpios));
 107        if (!priv->gpios) {
 108                dev_err(dev, "could not allocate memory for %d gpios\n",
 109                        priv->gpio_num);
 110                return -ENOMEM;
 111        }
 112
 113        ret = gpio_request_list_by_name(dev, "gpios", priv->gpios,
 114                                        priv->gpio_num, GPIOD_IS_IN);
 115        if (ret != priv->gpio_num) {
 116                dev_err(dev, "could not get gpios (err = %d)\n",
 117                        priv->gpio_num);
 118                return ret;
 119        }
 120
 121        if (!dev_read_bool(dev, "revisions") || !dev_read_bool(dev, "names")) {
 122                dev_err(dev, "revisions or names properties missing\n");
 123                return -ENOENT;
 124        }
 125
 126        return 0;
 127}
 128
 129static const struct udevice_id sysinfo_gpio_ids[] = {
 130        { .compatible = "gpio-sysinfo" },
 131        { /* sentinel */ }
 132};
 133
 134U_BOOT_DRIVER(sysinfo_gpio) = {
 135        .name           = "sysinfo_gpio",
 136        .id             = UCLASS_SYSINFO,
 137        .of_match       = sysinfo_gpio_ids,
 138        .ops            = &sysinfo_gpio_ops,
 139        .priv_auto      = sizeof(struct sysinfo_gpio_priv),
 140        .probe          = sysinfo_gpio_probe,
 141};
 142