mirror of
https://github.com/u-boot/u-boot.git
synced 2025-04-16 09:54:35 +00:00
sysinfo: Add gpio-sysinfo driver
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> Reviewed-by: Simon Glass <sjg@chromium.org>
This commit is contained in:
parent
4d65c6bcd7
commit
54aa07fdfc
4 changed files with 187 additions and 0 deletions
37
doc/device-tree-bindings/sysinfo/gpio-sysinfo.txt
Normal file
37
doc/device-tree-bindings/sysinfo/gpio-sysinfo.txt
Normal file
|
@ -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";
|
||||
};
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
141
drivers/sysinfo/gpio.c
Normal file
141
drivers/sysinfo/gpio.c
Normal file
|
@ -0,0 +1,141 @@
|
|||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Copyright (C) 2021 Sean Anderson <sean.anderson@seco.com>
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#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 SYSINFO_ID_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 SYSINFO_ID_BOARD_MODEL: {
|
||||
const char *name = NULL;
|
||||
int i, ret;
|
||||
u32 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;
|
||||
}
|
||||
|
||||
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,
|
||||
};
|
Loading…
Add table
Reference in a new issue