]> Git Repo - J-u-boot.git/blame - drivers/gpio/turris_omnia_mcu.c
gpio: turris_omnia_mcu: Use byteorder conversion functions
[J-u-boot.git] / drivers / gpio / turris_omnia_mcu.c
CommitLineData
5e4d24cc
T
1// SPDX-License-Identifier: GPL-2.0+
2// (C) 2022 Pali Rohár <[email protected]>
3
4#include <common.h>
5#include <dm.h>
6#include <i2c.h>
b555148f 7#include <turris-omnia-mcu-interface.h>
c07206fb 8#include <asm/byteorder.h>
5e4d24cc
T
9#include <asm/gpio.h>
10#include <linux/log2.h>
11
5e4d24cc
T
12struct turris_omnia_mcu_info {
13 u16 features;
14};
15
16static int turris_omnia_mcu_get_function(struct udevice *dev, uint offset)
17{
18 struct turris_omnia_mcu_info *info = dev_get_plat(dev);
19
20 switch (offset) {
21 /* bank 0 */
22 case 0 ... 15:
23 switch (offset) {
24 case ilog2(STS_USB30_PWRON):
25 case ilog2(STS_USB31_PWRON):
26 case ilog2(STS_ENABLE_4V5):
27 case ilog2(STS_BUTTON_MODE):
28 return GPIOF_OUTPUT;
29 default:
30 return GPIOF_INPUT;
31 }
32
33 /* bank 1 - supported only when FEAT_EXT_CMDS is set */
34 case (16 + 0) ... (16 + 31):
35 if (!(info->features & FEAT_EXT_CMDS))
36 return -EINVAL;
37 return GPIOF_INPUT;
38
54bcd84a 39 /* bank 2 - supported only when FEAT_EXT_CMDS and FEAT_PERIPH_MCU is set */
5e4d24cc
T
40 case (16 + 32 + 0) ... (16 + 32 + 15):
41 if (!(info->features & FEAT_EXT_CMDS))
42 return -EINVAL;
54bcd84a
T
43 if (!(info->features & FEAT_PERIPH_MCU))
44 return -EINVAL;
5e4d24cc
T
45 return GPIOF_OUTPUT;
46
47 default:
48 return -EINVAL;
49 }
50}
51
52static int turris_omnia_mcu_get_value(struct udevice *dev, uint offset)
53{
54 struct turris_omnia_mcu_info *info = dev_get_plat(dev);
c07206fb
MB
55 u32 val32;
56 u16 val16;
5e4d24cc
T
57 int ret;
58
59 switch (offset) {
60 /* bank 0 */
61 case 0 ... 15:
c07206fb
MB
62 ret = dm_i2c_read(dev, CMD_GET_STATUS_WORD, (void *)&val16,
63 sizeof(val16));
5e4d24cc
T
64 if (ret)
65 return ret;
c07206fb
MB
66
67 return !!(le16_to_cpu(val16) & BIT(offset));
5e4d24cc
T
68
69 /* bank 1 - supported only when FEAT_EXT_CMDS is set */
70 case (16 + 0) ... (16 + 31):
71 if (!(info->features & FEAT_EXT_CMDS))
72 return -EINVAL;
c07206fb
MB
73
74 ret = dm_i2c_read(dev, CMD_GET_EXT_STATUS_DWORD, (void *)&val32,
75 sizeof(val32));
5e4d24cc
T
76 if (ret)
77 return ret;
c07206fb
MB
78
79 return !!(le32_to_cpu(val32) & BIT(offset - 16));
5e4d24cc 80
54bcd84a 81 /* bank 2 - supported only when FEAT_EXT_CMDS and FEAT_PERIPH_MCU is set */
5e4d24cc
T
82 case (16 + 32 + 0) ... (16 + 32 + 15):
83 if (!(info->features & FEAT_EXT_CMDS))
84 return -EINVAL;
54bcd84a
T
85 if (!(info->features & FEAT_PERIPH_MCU))
86 return -EINVAL;
c07206fb
MB
87
88 ret = dm_i2c_read(dev, CMD_GET_EXT_CONTROL_STATUS,
89 (void *)&val16, sizeof(val16));
5e4d24cc
T
90 if (ret)
91 return ret;
c07206fb
MB
92
93 return !!(le16_to_cpu(val16) & BIT(offset - 16 - 32));
5e4d24cc
T
94
95 default:
96 return -EINVAL;
97 }
98}
99
100static int turris_omnia_mcu_set_value(struct udevice *dev, uint offset, int value)
101{
102 struct turris_omnia_mcu_info *info = dev_get_plat(dev);
c07206fb
MB
103 u16 valmask16[2];
104 u8 valmask8[2];
5e4d24cc
T
105
106 switch (offset) {
107 /* bank 0 */
c959374e
T
108 case 0 ... 15:
109 switch (offset) {
110 case ilog2(STS_USB30_PWRON):
c07206fb 111 valmask8[1] = CTL_USB30_PWRON;
c959374e
T
112 break;
113 case ilog2(STS_USB31_PWRON):
c07206fb 114 valmask8[1] = CTL_USB31_PWRON;
c959374e
T
115 break;
116 case ilog2(STS_ENABLE_4V5):
c07206fb 117 valmask8[1] = CTL_ENABLE_4V5;
c959374e
T
118 break;
119 case ilog2(STS_BUTTON_MODE):
c07206fb 120 valmask8[1] = CTL_BUTTON_MODE;
c959374e
T
121 break;
122 default:
123 return -EINVAL;
124 }
c07206fb
MB
125
126 valmask8[0] = value ? valmask8[1] : 0;
127
128 return dm_i2c_write(dev, CMD_GENERAL_CONTROL, valmask8,
129 sizeof(valmask8));
5e4d24cc 130
54bcd84a 131 /* bank 2 - supported only when FEAT_EXT_CMDS and FEAT_PERIPH_MCU is set */
5e4d24cc
T
132 case (16 + 32 + 0) ... (16 + 32 + 15):
133 if (!(info->features & FEAT_EXT_CMDS))
134 return -EINVAL;
54bcd84a
T
135 if (!(info->features & FEAT_PERIPH_MCU))
136 return -EINVAL;
c07206fb
MB
137
138 valmask16[1] = cpu_to_le16(BIT(offset - 16 - 32));
139 valmask16[0] = value ? valmask16[1] : 0;
140
141 return dm_i2c_write(dev, CMD_EXT_CONTROL, (void *)valmask16,
142 sizeof(valmask16));
5e4d24cc
T
143
144 default:
145 return -EINVAL;
146 }
5e4d24cc
T
147}
148
149static int turris_omnia_mcu_direction_input(struct udevice *dev, uint offset)
150{
151 int ret;
152
153 ret = turris_omnia_mcu_get_function(dev, offset);
154 if (ret < 0)
155 return ret;
156 else if (ret != GPIOF_INPUT)
157 return -EOPNOTSUPP;
158
159 return 0;
160}
161
162static int turris_omnia_mcu_direction_output(struct udevice *dev, uint offset, int value)
163{
164 int ret;
165
166 ret = turris_omnia_mcu_get_function(dev, offset);
167 if (ret < 0)
168 return ret;
169 else if (ret != GPIOF_OUTPUT)
170 return -EOPNOTSUPP;
171
172 return turris_omnia_mcu_set_value(dev, offset, value);
173}
174
175static int turris_omnia_mcu_xlate(struct udevice *dev, struct gpio_desc *desc,
176 struct ofnode_phandle_args *args)
177{
178 uint bank, gpio, flags, offset;
179 int ret;
180
181 if (args->args_count != 3)
182 return -EINVAL;
183
184 bank = args->args[0];
185 gpio = args->args[1];
186 flags = args->args[2];
187
188 switch (bank) {
189 case 0:
190 if (gpio >= 16)
191 return -EINVAL;
192 offset = gpio;
193 break;
194 case 1:
195 if (gpio >= 32)
196 return -EINVAL;
197 offset = 16 + gpio;
198 break;
199 case 2:
200 if (gpio >= 16)
201 return -EINVAL;
202 offset = 16 + 32 + gpio;
203 break;
204 default:
205 return -EINVAL;
206 }
207
208 ret = turris_omnia_mcu_get_function(dev, offset);
209 if (ret < 0)
210 return ret;
211
212 desc->offset = offset;
213 desc->flags = gpio_flags_xlate(flags);
214
215 return 0;
216}
217
218static const struct dm_gpio_ops turris_omnia_mcu_ops = {
219 .direction_input = turris_omnia_mcu_direction_input,
220 .direction_output = turris_omnia_mcu_direction_output,
221 .get_value = turris_omnia_mcu_get_value,
222 .set_value = turris_omnia_mcu_set_value,
223 .get_function = turris_omnia_mcu_get_function,
224 .xlate = turris_omnia_mcu_xlate,
225};
226
227static int turris_omnia_mcu_probe(struct udevice *dev)
228{
229 struct turris_omnia_mcu_info *info = dev_get_plat(dev);
230 struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
c07206fb 231 u16 val;
5e4d24cc
T
232 int ret;
233
c07206fb
MB
234 ret = dm_i2c_read(dev, CMD_GET_STATUS_WORD, (void *)&val, sizeof(val));
235 if (ret < 0) {
236 printf("Error: turris_omnia_mcu CMD_GET_STATUS_WORD failed: %d\n",
237 ret);
5e4d24cc
T
238 return ret;
239 }
240
c07206fb
MB
241 if (le16_to_cpu(val) & STS_FEATURES_SUPPORTED) {
242 ret = dm_i2c_read(dev, CMD_GET_FEATURES, (void *)&val,
243 sizeof(val));
244 if (ret < 0) {
245 printf("Error: turris_omnia_mcu CMD_GET_FEATURES failed: %d\n",
246 ret);
5e4d24cc
T
247 return ret;
248 }
c07206fb 249 info->features = le16_to_cpu(val);
5e4d24cc
T
250 }
251
252 uc_priv->bank_name = "mcu_";
253
54bcd84a 254 if ((info->features & FEAT_EXT_CMDS) && (info->features & FEAT_PERIPH_MCU))
5e4d24cc 255 uc_priv->gpio_count = 16 + 32 + 16;
54bcd84a
T
256 else if (info->features & FEAT_EXT_CMDS)
257 uc_priv->gpio_count = 16 + 32;
5e4d24cc
T
258 else
259 uc_priv->gpio_count = 16;
260
261 return 0;
262}
263
264static const struct udevice_id turris_omnia_mcu_ids[] = {
265 { .compatible = "cznic,turris-omnia-mcu" },
266 { }
267};
268
269U_BOOT_DRIVER(turris_omnia_mcu) = {
270 .name = "turris-omnia-mcu",
271 .id = UCLASS_GPIO,
272 .ops = &turris_omnia_mcu_ops,
273 .probe = turris_omnia_mcu_probe,
274 .plat_auto = sizeof(struct turris_omnia_mcu_info),
275 .of_match = turris_omnia_mcu_ids,
276};
This page took 0.12506 seconds and 4 git commands to generate.