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