mirror of
https://github.com/brain-hackers/u-boot-brain
synced 2024-09-27 23:20:26 +09: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
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
|
one which provides a way to specify this SMBIOS information in the
|
||||||
devicetree, without needing any board-specific functionality.
|
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
|
endif
|
||||||
|
@ -4,5 +4,6 @@
|
|||||||
# Mario Six, Guntermann & Drunck GmbH, mario.six@gdsys.cc
|
# Mario Six, Guntermann & Drunck GmbH, mario.six@gdsys.cc
|
||||||
obj-y += sysinfo-uclass.o
|
obj-y += sysinfo-uclass.o
|
||||||
obj-$(CONFIG_SYSINFO_GAZERBEAM) += gazerbeam.o
|
obj-$(CONFIG_SYSINFO_GAZERBEAM) += gazerbeam.o
|
||||||
|
obj-$(CONFIG_SYSINFO_GPIO) += gpio.o
|
||||||
obj-$(CONFIG_SYSINFO_SANDBOX) += sandbox.o
|
obj-$(CONFIG_SYSINFO_SANDBOX) += sandbox.o
|
||||||
obj-$(CONFIG_SYSINFO_SMBIOS) += smbios.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…
Reference in New Issue
Block a user