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