summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEmanuele Ghidoli <emanuele.ghidoli@toradex.com>2023-03-13 17:50:39 +0100
committerFrancesco Dolcini <francesco.dolcini@toradex.com>2023-03-17 10:16:41 +0100
commit60cedd8dc9bf5c47c660af776eec0313a59ce0e1 (patch)
tree09bb2179db0965a66f21e64268c8f94de947a2a3
parentf2afde288ac8c16c707b9daf205b3474e2002666 (diff)
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 | Upstream-Status: Submitted [https://lore.kernel.org/all/20230313165039.255579-1-francesco@dolcini.it/] 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> [fdolcini: backport: fixed error path on IS_ERR(hub->bypass)] Signed-off-by: Francesco Dolcini <francesco.dolcini@toradex.com>
-rw-r--r--drivers/usb/misc/usb3503.c20
-rw-r--r--include/linux/platform_data/usb3503.h1
2 files changed, 20 insertions, 1 deletions
diff --git a/drivers/usb/misc/usb3503.c b/drivers/usb/misc/usb3503.c
index 32f797af0779..8204a242d59e 100644
--- a/drivers/usb/misc/usb3503.c
+++ b/drivers/usb/misc/usb3503.c
@@ -46,6 +46,7 @@ struct usb3503 {
struct device *dev;
struct clk *clk;
u8 port_off_mask;
+ struct gpio_desc *bypass;
struct gpio_desc *intn;
struct gpio_desc *reset;
struct gpio_desc *connect;
@@ -109,18 +110,25 @@ static int usb3503_connect(struct usb3503 *hub)
static int usb3503_switch_mode(struct usb3503 *hub, enum usb3503_mode mode)
{
struct device *dev = hub->dev;
- int rst, conn;
+ int rst, bypass, conn;
switch (mode) {
case USB3503_MODE_HUB:
conn = 1;
rst = 0;
+ bypass = 0;
break;
case USB3503_MODE_STANDBY:
conn = 0;
rst = 1;
+ bypass = 1;
dev_info(dev, "switched to STANDBY mode\n");
break;
+ case USB3503_MODE_BYPASS:
+ conn = 0;
+ rst = 0;
+ bypass = 1;
+ break;
default:
dev_err(dev, "unknown mode is requested\n");
return -EINVAL;
@@ -132,6 +140,9 @@ static int usb3503_switch_mode(struct usb3503 *hub, enum usb3503_mode mode)
if (hub->reset)
gpiod_set_value_cansleep(hub->reset, rst);
+ if (hub->bypass)
+ gpiod_set_value_cansleep(hub->bypass, bypass);
+
if (conn) {
/* Wait T_HUBINIT == 4ms for hub logic to stabilize */
usleep_range(4000, 10000);
@@ -241,6 +252,12 @@ static int usb3503_probe(struct usb3503 *hub)
if (hub->connect)
gpiod_set_consumer_name(hub->connect, "usb3503 connect");
+ hub->bypass = devm_gpiod_get_optional(dev, "bypass", GPIOD_OUT_HIGH);
+ if (IS_ERR(hub->bypass))
+ return PTR_ERR(hub->bypass);
+ if (hub->bypass)
+ gpiod_set_consumer_name(hub->bypass, "usb3503 bypass");
+
hub->reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH);
if (IS_ERR(hub->reset))
return PTR_ERR(hub->reset);
@@ -372,6 +389,7 @@ MODULE_DEVICE_TABLE(i2c, usb3503_id);
static const struct of_device_id usb3503_of_match[] = {
{ .compatible = "smsc,usb3503", },
{ .compatible = "smsc,usb3503a", },
+ { .compatible = "smsc,usb3803", },
{},
};
MODULE_DEVICE_TABLE(of, usb3503_of_match);
diff --git a/include/linux/platform_data/usb3503.h b/include/linux/platform_data/usb3503.h
index d01ef97ddf36..f3c942f396f8 100644
--- a/include/linux/platform_data/usb3503.h
+++ b/include/linux/platform_data/usb3503.h
@@ -12,6 +12,7 @@ enum usb3503_mode {
USB3503_MODE_UNKNOWN,
USB3503_MODE_HUB,
USB3503_MODE_STANDBY,
+ USB3503_MODE_BYPASS,
};
struct usb3503_platform_data {