1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3 * Driver for onboard USB hubs
4 *
5 * Copyright (C) 2022, STMicroelectronics - All Rights Reserved
6 *
7 * Mostly inspired by Linux kernel v6.1 onboard_usb_hub driver
8 */
9
10 #include <asm/gpio.h>
11 #include <dm.h>
12 #include <dm/device_compat.h>
13 #include <dm/uclass-internal.h>
14 #include <i2c.h>
15 #include <linux/delay.h>
16 #include <power/regulator.h>
17
18 #define USB5744_COMMAND_ATTACH 0x0056
19 #define USB5744_COMMAND_ATTACH_LSB 0xAA
20 #define USB5744_CONFIG_REG_ACCESS 0x0037
21 #define USB5744_CONFIG_REG_ACCESS_LSB 0x99
22
23 #define MAX_SUPPLIES 2
24
25 struct onboard_hub {
26 struct udevice *vdd[MAX_SUPPLIES];
27 struct gpio_desc *reset_gpio;
28 };
29
30 struct onboard_hub_data {
31 unsigned long reset_us;
32 unsigned long power_on_delay_us;
33 unsigned int num_supplies;
34 const char * const supply_names[MAX_SUPPLIES];
35 int (*init)(struct udevice *dev);
36 };
37
usb5744_i2c_init(struct udevice * dev)38 static int usb5744_i2c_init(struct udevice *dev)
39 {
40 /*
41 * Prevent the MCU from the putting the HUB in suspend mode through register write.
42 * The BYPASS_UDC_SUSPEND bit (Bit 3) of the RuntimeFlags2 register at address
43 * 0x411D controls this aspect of the hub.
44 * Format to write to hub registers via SMBus- 2D 00 00 05 00 01 41 1D 08
45 * Byte 0: Address of slave 2D
46 * Byte 1: Memory address 00
47 * Byte 2: Memory address 00
48 * Byte 3: Number of bytes to write to memory
49 * Byte 4: Write configuration register (00)
50 * Byte 5: Write the number of data bytes (01- 1 data byte)
51 * Byte 6: LSB of register address 0x41
52 * Byte 7: MSB of register address 0x1D
53 * Byte 8: value to be written to the register
54 */
55 u8 data_buf[8] = {0x0, 0x5, 0x0, 0x1, 0x41, 0x1D, 0x08};
56 u8 config_reg_access_buf = USB5744_CONFIG_REG_ACCESS;
57 struct udevice *i2c_bus = NULL, *i2c_dev;
58 struct ofnode_phandle_args phandle;
59 u8 buf = USB5744_COMMAND_ATTACH;
60 struct dm_i2c_chip *i2c_chip;
61 int ret, slave_addr;
62
63 ret = dev_read_phandle_with_args(dev, "i2c-bus", NULL, 0, 0, &phandle);
64 if (ret) {
65 dev_err(dev, "i2c-bus not specified\n");
66 return ret;
67 }
68
69 ret = device_get_global_by_ofnode(ofnode_get_parent(phandle.node), &i2c_bus);
70 if (ret) {
71 dev_err(dev, "Failed to get i2c node, err: %d\n", ret);
72 return ret;
73 }
74
75 ret = ofnode_read_u32(phandle.node, "reg", &slave_addr);
76 if (ret)
77 return ret;
78
79 ret = i2c_get_chip(i2c_bus, slave_addr, 1, &i2c_dev);
80 if (ret) {
81 dev_err(dev, "%s: can't find i2c chip device for addr 0x%x\n", __func__,
82 slave_addr);
83 return ret;
84 }
85
86 i2c_chip = dev_get_parent_plat(i2c_dev);
87 if (!i2c_chip) {
88 dev_err(dev, "parent platform data not found\n");
89 return -EINVAL;
90 }
91
92 i2c_chip->flags &= ~DM_I2C_CHIP_WR_ADDRESS;
93 /* SMBus write command */
94 ret = dm_i2c_write(i2c_dev, 0, (uint8_t *)&data_buf, 8);
95 if (ret) {
96 dev_err(dev, "data_buf i2c_write failed, err:%d\n", ret);
97 return ret;
98 }
99
100 /* Configuration register access command */
101 ret = dm_i2c_write(i2c_dev, USB5744_CONFIG_REG_ACCESS_LSB,
102 &config_reg_access_buf, 2);
103 if (ret) {
104 dev_err(dev, "config_reg_access i2c_write failed, err: %d\n", ret);
105 return ret;
106 }
107
108 /* USB Attach with SMBus */
109 ret = dm_i2c_write(i2c_dev, USB5744_COMMAND_ATTACH_LSB, &buf, 2);
110 if (ret) {
111 dev_err(dev, "usb_attach i2c_write failed, err: %d\n", ret);
112 return ret;
113 }
114
115 return 0;
116 }
117
usb_onboard_hub_reset(struct udevice * dev)118 int usb_onboard_hub_reset(struct udevice *dev)
119 {
120 struct onboard_hub_data *data =
121 (struct onboard_hub_data *)dev_get_driver_data(dev);
122 struct onboard_hub *hub = dev_get_priv(dev);
123 int ret;
124
125 hub->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_IS_OUT);
126
127 /* property is optional, don't return error! */
128 if (!hub->reset_gpio)
129 return 0;
130
131 ret = dm_gpio_set_value(hub->reset_gpio, 1);
132 if (ret)
133 return ret;
134
135 udelay(data->reset_us);
136
137 ret = dm_gpio_set_value(hub->reset_gpio, 0);
138 if (ret)
139 return ret;
140
141 udelay(data->power_on_delay_us);
142
143 return 0;
144 }
145
usb_onboard_hub_power_off(struct udevice * dev)146 static int usb_onboard_hub_power_off(struct udevice *dev)
147 {
148 struct onboard_hub_data *data =
149 (struct onboard_hub_data *)dev_get_driver_data(dev);
150 struct onboard_hub *hub = dev_get_priv(dev);
151 int ret = 0, ret2;
152 unsigned int i;
153
154 for (i = data->num_supplies; i > 0; i--) {
155 if (hub->vdd[i-1]) {
156 ret2 = regulator_set_enable_if_allowed(hub->vdd[i-1], false);
157 if (ret2 && ret2 != -ENOSYS) {
158 dev_err(dev, "can't disable %s: %d\n", data->supply_names[i-1], ret2);
159 ret |= ret2;
160 }
161 }
162 }
163
164 return ret;
165 }
166
usb_onboard_hub_probe(struct udevice * dev)167 static int usb_onboard_hub_probe(struct udevice *dev)
168 {
169 struct onboard_hub_data *data =
170 (struct onboard_hub_data *)dev_get_driver_data(dev);
171 struct onboard_hub *hub = dev_get_priv(dev);
172 unsigned int i;
173 int ret;
174
175 if (data->num_supplies > MAX_SUPPLIES) {
176 dev_err(dev, "invalid supplies number, max supported: %d\n", MAX_SUPPLIES);
177 return -EINVAL;
178 }
179
180 for (i = 0; i < data->num_supplies; i++) {
181 ret = device_get_supply_regulator(dev, data->supply_names[i], &hub->vdd[i]);
182 if (ret && ret != -ENOENT && ret != -ENOSYS) {
183 dev_err(dev, "can't get %s: %d\n", data->supply_names[i], ret);
184 goto err_supply;
185 }
186
187 if (hub->vdd[i]) {
188 ret = regulator_set_enable_if_allowed(hub->vdd[i], true);
189 if (ret && ret != -ENOSYS) {
190 dev_err(dev, "can't enable %s: %d\n", data->supply_names[i], ret);
191 goto err_supply;
192 }
193 }
194 }
195
196 ret = usb_onboard_hub_reset(dev);
197 if (ret)
198 goto err_supply;
199
200 if (data->init) {
201 ret = data->init(dev);
202 if (ret) {
203 dev_err(dev, "onboard i2c init failed: %d\n", ret);
204 goto err;
205 }
206 }
207 return 0;
208 err:
209 dm_gpio_set_value(hub->reset_gpio, 0);
210 err_supply:
211 usb_onboard_hub_power_off(dev);
212 return ret;
213 }
214
usb_onboard_hub_bind(struct udevice * dev)215 static int usb_onboard_hub_bind(struct udevice *dev)
216 {
217 struct ofnode_phandle_args phandle;
218 struct udevice *peerdev;
219 int ret;
220
221 ret = dev_read_phandle_with_args(dev, "peer-hub", NULL, 0, 0, &phandle);
222 if (ret == -ENOENT) {
223 dev_dbg(dev, "peer-hub property not present\n");
224 return 0;
225 }
226
227 if (ret) {
228 dev_err(dev, "peer-hub not specified\n");
229 return ret;
230 }
231
232 ret = uclass_find_device_by_ofnode(UCLASS_USB_HUB, phandle.node, &peerdev);
233 if (ret) {
234 dev_dbg(dev, "binding before peer-hub %s\n",
235 ofnode_get_name(phandle.node));
236 return 0;
237 }
238
239 dev_dbg(dev, "peer-hub %s has been bound\n", peerdev->name);
240
241 return -ENODEV;
242 }
243
usb_onboard_hub_remove(struct udevice * dev)244 static int usb_onboard_hub_remove(struct udevice *dev)
245 {
246 struct onboard_hub *hub = dev_get_priv(dev);
247 int ret = 0;
248
249 if (hub->reset_gpio) {
250 ret = dm_gpio_set_value(hub->reset_gpio, 1);
251 if (ret)
252 dev_err(dev, "can't set gpio %s: %d\n", hub->reset_gpio->dev->name,
253 ret);
254 }
255
256 ret |= usb_onboard_hub_power_off(dev);
257 return ret;
258 }
259
260 static const struct onboard_hub_data usb2514_data = {
261 .power_on_delay_us = 500,
262 .reset_us = 1,
263 .num_supplies = 1,
264 .supply_names = { "vdd-supply" },
265 };
266
267 static const struct onboard_hub_data usb5744_data = {
268 .init = usb5744_i2c_init,
269 .power_on_delay_us = 1000,
270 .reset_us = 5,
271 .num_supplies = 1,
272 .supply_names = { "vdd-supply" },
273 };
274
275 static const struct onboard_hub_data usbhx3_data = {
276 .reset_us = 10000,
277 .num_supplies = 2,
278 .supply_names = { "vdd-supply", "vdd2-supply" },
279 };
280
281 static const struct udevice_id usb_onboard_hub_ids[] = {
282 /* Use generic usbVID,PID dt-bindings (usb-device.yaml) */
283 { .compatible = "usb424,2514", /* USB2514B USB 2.0 */
284 .data = (ulong)&usb2514_data,
285 }, {
286 .compatible = "usb424,2744", /* USB2744 USB 2.0 */
287 .data = (ulong)&usb5744_data,
288 }, {
289 .compatible = "usb424,5744", /* USB5744 USB 3.0 */
290 .data = (ulong)&usb5744_data,
291 }, {
292 .compatible = "usb4b4,6504", /* Cypress HX3 USB 3.0 */
293 .data = (ulong)&usbhx3_data,
294 }, {
295 .compatible = "usb4b4,6506", /* Cypress HX3 USB 2.0 */
296 .data = (ulong)&usbhx3_data,
297 },
298 { /* sentinel */ }
299 };
300
301 U_BOOT_DRIVER(usb_onboard_hub) = {
302 .name = "usb_onboard_hub",
303 .id = UCLASS_USB_HUB,
304 .bind = usb_onboard_hub_bind,
305 .probe = usb_onboard_hub_probe,
306 .remove = usb_onboard_hub_remove,
307 .of_match = usb_onboard_hub_ids,
308 .priv_auto = sizeof(struct onboard_hub),
309 };
310