
On 3/1/21 3:46 PM, Sean Anderson wrote:
This uses the newly-added dm_gpio_get_values_as_int_base3 function to implement a sysinfo device. The revision map is stored in the device tree.
Signed-off-by: Sean Anderson sean.anderson@seco.com
.../sysinfo/gpio-sysinfo.txt | 37 +++++ drivers/sysinfo/Kconfig | 8 + drivers/sysinfo/Makefile | 1 + drivers/sysinfo/gpio.c | 138 ++++++++++++++++++ 4 files changed, 184 insertions(+) create mode 100644 doc/device-tree-bindings/sysinfo/gpio-sysinfo.txt create mode 100644 drivers/sysinfo/gpio.c
diff --git a/doc/device-tree-bindings/sysinfo/gpio-sysinfo.txt b/doc/device-tree-bindings/sysinfo/gpio-sysinfo.txt new file mode 100644 index 0000000000..b5739d94e9 --- /dev/null +++ b/doc/device-tree-bindings/sysinfo/gpio-sysinfo.txt @@ -0,0 +1,37 @@ +GPIO-based Sysinfo device
+This binding describes several GPIOs which specify a board revision. Each GPIO +forms a digit in a ternary revision number. This revision is then mapped to a +name using the revisions and names properties.
+Each GPIO may be floating, pulled-up, or pulled-down, mapping to digits 2, 1, +and 0, respectively. The first GPIO forms the least-significant digit of the +revision. For example, consider the property
- gpios = <&gpio 0>, <&gpio 1>, <&gpio 2>;
+If GPIO 0 is pulled-up, GPIO 1 is pulled-down, and GPIO 2 is floating, then the +revision would be
- 0t201 = 2*9 + 0*3 + 1*3 = 19
+If instead GPIO 0 is floating, GPIO 1 is pulled-up, and GPIO 2 is pulled-down, +then the revision would be
- 0t012 = 0*9 + 1*3 + 2*1 = 5
+Required properties: +- compatible: should be "gpio-sysinfo". +- gpios: should be a list of gpios forming the revision number,
- least-significant-digit first
+- revisions: a list of known revisions; any revisions not present will have the
- name "unknown"
+- names: the name of each revision in revisions
+Example: +sysinfo {
- compatible = "gpio-sysinfo";
- gpios = <&gpio_a 15>, <&gpio_a 16>, <&gpio_a 17>;
- revisions = <19>, <5>;
- names = "rev_a", "foo";
+}; diff --git a/drivers/sysinfo/Kconfig b/drivers/sysinfo/Kconfig index 85c1e81e41..381dcd8844 100644 --- a/drivers/sysinfo/Kconfig +++ b/drivers/sysinfo/Kconfig @@ -30,4 +30,12 @@ config SYSINFO_SMBIOS one which provides a way to specify this SMBIOS information in the devicetree, without needing any board-specific functionality.
+config SYSINFO_GPIO
- bool "Enable gpio sysinfo driver"
- help
Support querying gpios to determine board revision. This uses gpios to
form a ternary number (when they are pulled-up, -down, or floating).
This ternary number is then mapped to a board revision name using
device tree properties.
- endif
diff --git a/drivers/sysinfo/Makefile b/drivers/sysinfo/Makefile index 6d04fcba1d..d9f708b7ea 100644 --- a/drivers/sysinfo/Makefile +++ b/drivers/sysinfo/Makefile @@ -4,5 +4,6 @@ # Mario Six, Guntermann & Drunck GmbH, mario.six@gdsys.cc obj-y += sysinfo-uclass.o obj-$(CONFIG_SYSINFO_GAZERBEAM) += gazerbeam.o +obj-$(CONFIG_SYSINFO_GPIO) += gpio.o obj-$(CONFIG_SYSINFO_SANDBOX) += sandbox.o obj-$(CONFIG_SYSINFO_SMBIOS) += smbios.o diff --git a/drivers/sysinfo/gpio.c b/drivers/sysinfo/gpio.c new file mode 100644 index 0000000000..6a0eff3ec9 --- /dev/null +++ b/drivers/sysinfo/gpio.c @@ -0,0 +1,138 @@ +// SPDX-License-Identifier: GPL-2.0+ +/*
- Copyright (C) 2021 Sean Anderson sean.anderson@seco.com
- */
+#include <common.h> +#include <dm.h> +#include <dm/device_compat.h> +#include <log.h> +#include <sysinfo.h> +#include <asm/gpio.h>
+struct sysinfo_gpio_priv {
- struct gpio_desc *gpios;
- int gpio_num, revision;
+};
+static int sysinfo_gpio_detect(struct udevice *dev) +{
- struct sysinfo_gpio_priv *priv = dev_get_priv(dev);
- priv->revision = dm_gpio_get_values_as_int_base3(priv->gpios,
priv->gpio_num);
- return priv->revision < 0 ? priv->revision : 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 SYSINFO_ID_REVISION:
if (priv->revision < 0) {
Looks like I forgot to remove this brace. Will be fixed in v2.
--Sean
return priv->revision;
*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 SYSINFO_ID_REVISION: {
const char *name = NULL;
int i, ret;
u32 revision;
if (priv->revision < 0)
return priv->revision;
for (i = 0; i < priv->gpio_num; 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;
- }
- priv->revision = -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,
+};