Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

usb: misc: usb3503: support usb3803 and bypass mode

Add support for USB3803 and bypass mode, with this change
is also possible to move the component out of bypass mode.

In bypass mode the downstream port 3 is connected to the
upstream port with low switch resistance R_on.

Controlling mode of operations:

| RESET_N | BYPASS_N | Mode |
--------------------------------
| 0 | 0 | standby |
| 1 | 0 | bypass |
| 1 | 1 | hub |

Datasheet: https://ww1.microchip.com/downloads/aemDocuments/documents/UNG/ProductDocuments/DataSheets/00001691D.pdf
Signed-off-by: Emanuele Ghidoli <emanuele.ghidoli@toradex.com>
Signed-off-by: Francesco Dolcini <francesco.dolcini@toradex.com>
Link: https://lore.kernel.org/r/20230313165039.255579-4-francesco@dolcini.it
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Emanuele Ghidoli and committed by
Greg Kroah-Hartman
b91e6107 b04b32cd

+22 -1
+21 -1
drivers/usb/misc/usb3503.c
··· 46 46 struct device *dev; 47 47 struct clk *clk; 48 48 u8 port_off_mask; 49 + struct gpio_desc *bypass; 49 50 struct gpio_desc *intn; 50 51 struct gpio_desc *reset; 51 52 struct gpio_desc *connect; ··· 110 109 static int usb3503_switch_mode(struct usb3503 *hub, enum usb3503_mode mode) 111 110 { 112 111 struct device *dev = hub->dev; 113 - int rst, conn; 112 + int rst, bypass, conn; 114 113 115 114 switch (mode) { 116 115 case USB3503_MODE_HUB: 117 116 conn = 1; 118 117 rst = 0; 118 + bypass = 0; 119 119 break; 120 120 case USB3503_MODE_STANDBY: 121 121 conn = 0; 122 122 rst = 1; 123 + bypass = 1; 123 124 dev_info(dev, "switched to STANDBY mode\n"); 125 + break; 126 + case USB3503_MODE_BYPASS: 127 + conn = 0; 128 + rst = 0; 129 + bypass = 1; 124 130 break; 125 131 default: 126 132 dev_err(dev, "unknown mode is requested\n"); ··· 139 131 140 132 if (hub->reset) 141 133 gpiod_set_value_cansleep(hub->reset, rst); 134 + 135 + if (hub->bypass) 136 + gpiod_set_value_cansleep(hub->bypass, bypass); 142 137 143 138 if (conn) { 144 139 /* Wait T_HUBINIT == 4ms for hub logic to stabilize */ ··· 257 246 } 258 247 if (hub->connect) 259 248 gpiod_set_consumer_name(hub->connect, "usb3503 connect"); 249 + 250 + hub->bypass = devm_gpiod_get_optional(dev, "bypass", GPIOD_OUT_HIGH); 251 + if (IS_ERR(hub->bypass)) { 252 + err = PTR_ERR(hub->bypass); 253 + goto err_clk; 254 + } 255 + if (hub->bypass) 256 + gpiod_set_consumer_name(hub->bypass, "usb3503 bypass"); 260 257 261 258 hub->reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH); 262 259 if (IS_ERR(hub->reset)) { ··· 401 382 static const struct of_device_id usb3503_of_match[] = { 402 383 { .compatible = "smsc,usb3503", }, 403 384 { .compatible = "smsc,usb3503a", }, 385 + { .compatible = "smsc,usb3803", }, 404 386 {}, 405 387 }; 406 388 MODULE_DEVICE_TABLE(of, usb3503_of_match);
+1
include/linux/platform_data/usb3503.h
··· 12 12 USB3503_MODE_UNKNOWN, 13 13 USB3503_MODE_HUB, 14 14 USB3503_MODE_STANDBY, 15 + USB3503_MODE_BYPASS, 15 16 }; 16 17 17 18 struct usb3503_platform_data {