]>
Commit | Line | Data |
---|---|---|
54aa07fd SA |
1 | // SPDX-License-Identifier: GPL-2.0+ |
2 | /* | |
3 | * Copyright (C) 2021 Sean Anderson <[email protected]> | |
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 | */ | |
19 | struct sysinfo_gpio_priv { | |
20 | struct gpio_desc *gpios; | |
21 | int gpio_num, revision; | |
22 | }; | |
23 | ||
24 | static 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 | ||
37 | static 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 | ||
50 | static 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 | ||
19213d7a | 60 | for (i = 0; ; i++) { |
54aa07fd SA |
61 | 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; | |
19213d7a RV |
83 | } |
84 | default: | |
54aa07fd SA |
85 | return -EINVAL; |
86 | }; | |
87 | } | |
88 | ||
89 | static 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 | ||
95 | static 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 | ||
130 | static const struct udevice_id sysinfo_gpio_ids[] = { | |
131 | { .compatible = "gpio-sysinfo" }, | |
132 | { /* sentinel */ } | |
133 | }; | |
134 | ||
135 | U_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 | }; |