blob: 82f90303bb7094a57ccd88f3b49ae02bc8b2c47f [file] [log] [blame]
Sean Anderson985c5672021-04-20 10:50:57 -04001// 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
Rasmus Villemoeseb194592023-03-10 11:58:03 +010060 for (i = 0; ; i++) {
Sean Anderson985c5672021-04-20 10:50:57 -040061 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;
Rasmus Villemoeseb194592023-03-10 11:58:03 +010083 }
84 default:
Sean Anderson985c5672021-04-20 10:50:57 -040085 return -EINVAL;
86 };
87}
88
89static const struct sysinfo_ops sysinfo_gpio_ops = {
90 .detect = sysinfo_gpio_detect,
91 .get_int = sysinfo_gpio_get_int,
92 .get_str = sysinfo_gpio_get_str,
93};
94
95static int sysinfo_gpio_probe(struct udevice *dev)
96{
97 int ret;
98 struct sysinfo_gpio_priv *priv = dev_get_priv(dev);
99
100 priv->gpio_num = gpio_get_list_count(dev, "gpios");
101 if (priv->gpio_num < 0) {
102 dev_err(dev, "could not get gpios length (err = %d)\n",
103 priv->gpio_num);
104 return priv->gpio_num;
105 }
106
107 priv->gpios = calloc(priv->gpio_num, sizeof(*priv->gpios));
108 if (!priv->gpios) {
109 dev_err(dev, "could not allocate memory for %d gpios\n",
110 priv->gpio_num);
111 return -ENOMEM;
112 }
113
114 ret = gpio_request_list_by_name(dev, "gpios", priv->gpios,
115 priv->gpio_num, GPIOD_IS_IN);
116 if (ret != priv->gpio_num) {
117 dev_err(dev, "could not get gpios (err = %d)\n",
118 priv->gpio_num);
119 return ret;
120 }
121
122 if (!dev_read_bool(dev, "revisions") || !dev_read_bool(dev, "names")) {
123 dev_err(dev, "revisions or names properties missing\n");
124 return -ENOENT;
125 }
126
127 return 0;
128}
129
130static const struct udevice_id sysinfo_gpio_ids[] = {
131 { .compatible = "gpio-sysinfo" },
132 { /* sentinel */ }
133};
134
135U_BOOT_DRIVER(sysinfo_gpio) = {
136 .name = "sysinfo_gpio",
137 .id = UCLASS_SYSINFO,
138 .of_match = sysinfo_gpio_ids,
139 .ops = &sysinfo_gpio_ops,
140 .priv_auto = sizeof(struct sysinfo_gpio_priv),
141 .probe = sysinfo_gpio_probe,
142};