diff options
Diffstat (limited to 'drivers/usb/misc/usb3503.c')
-rw-r--r-- | drivers/usb/misc/usb3503.c | 47 |
1 files changed, 45 insertions, 2 deletions
diff --git a/drivers/usb/misc/usb3503.c b/drivers/usb/misc/usb3503.c index 03be5d574f23..77127466f32e 100644 --- a/drivers/usb/misc/usb3503.c +++ b/drivers/usb/misc/usb3503.c @@ -59,7 +59,9 @@ struct usb3503 { struct regmap *regmap; struct device *dev; struct clk *clk; + u8 port_nrd; u8 port_off_mask; + int gpio_bypass; int gpio_intn; int gpio_reset; int gpio_connect; @@ -74,6 +76,9 @@ static int usb3503_reset(struct usb3503 *hub, int state) if (gpio_is_valid(hub->gpio_reset)) gpio_set_value_cansleep(hub->gpio_reset, state); + if (gpio_is_valid(hub->gpio_bypass)) + gpio_set_value_cansleep(hub->gpio_bypass, state); + /* Wait T_HUBINIT == 4ms for hub logic to stabilize */ if (state) usleep_range(4000, 10000); @@ -100,8 +105,7 @@ static int usb3503_connect(struct usb3503 *hub) /* PDS : Set the ports which are disabled in self-powered mode. */ if (hub->port_off_mask) { - err = regmap_update_bits(hub->regmap, USB3503_PDS, - hub->port_off_mask, + err = regmap_write(hub->regmap, USB3503_PDS, hub->port_off_mask); if (err < 0) { dev_err(dev, "PDS failed (%d)\n", err); @@ -118,6 +122,16 @@ static int usb3503_connect(struct usb3503 *hub) return err; } + /* NRD : Set non removable ports. */ + if (hub->port_nrd) { + err = regmap_write(hub->regmap, USB3503_NRD, + hub->port_nrd); + if (err < 0) { + dev_err(dev, "NRD failed (%d)\n", err); + return err; + } + } + /* SP_LOCK: clear connect_n, config_n for hub connect */ err = regmap_update_bits(hub->regmap, USB3503_SP_ILOCK, (USB3503_SPILOCK_CONNECT @@ -179,7 +193,9 @@ static int usb3503_probe(struct usb3503 *hub) int len; if (pdata) { + hub->port_nrd = pdata->port_nrd; hub->port_off_mask = pdata->port_off_mask; + hub->gpio_bypass = pdata->gpio_bypass; hub->gpio_intn = pdata->gpio_intn; hub->gpio_connect = pdata->gpio_connect; hub->gpio_reset = pdata->gpio_reset; @@ -244,17 +260,32 @@ static int usb3503_probe(struct usb3503 *hub) int i; for (i = 0; i < len / sizeof(u32); i++) { u32 port = be32_to_cpu(property[i]); + dev_dbg(dev, "disabled-ports, port: %d\n", port); if ((1 <= port) && (port <= 3)) hub->port_off_mask |= (1 << port); } } + property = of_get_property(np, "non-removable-devices", &len); + if (property && (len / sizeof(u32)) > 0) { + int i; + for (i = 0; i < len / sizeof(u32); i++) { + u32 port = be32_to_cpu(property[i]); + dev_dbg(dev, "non-removable-devices, port: %d\n", port); + if ((1 <= port) && (port <= 3)) + hub->port_nrd |= (1 << port); + } + } + hub->gpio_intn = of_get_named_gpio(np, "intn-gpios", 0); if (hub->gpio_intn == -EPROBE_DEFER) return -EPROBE_DEFER; hub->gpio_connect = of_get_named_gpio(np, "connect-gpios", 0); if (hub->gpio_connect == -EPROBE_DEFER) return -EPROBE_DEFER; + hub->gpio_bypass = of_get_named_gpio(np, "bypass-gpios", 0); + if (hub->gpio_bypass == -EPROBE_DEFER) + return -EPROBE_DEFER; hub->gpio_reset = of_get_named_gpio(np, "reset-gpios", 0); if (hub->gpio_reset == -EPROBE_DEFER) return -EPROBE_DEFER; @@ -289,6 +320,17 @@ static int usb3503_probe(struct usb3503 *hub) } } + if (gpio_is_valid(hub->gpio_bypass)) { + err = devm_gpio_request_one(dev, hub->gpio_bypass, + GPIOF_OUT_INIT_LOW, "usb3503 bypass"); + if (err) { + dev_err(dev, + "unable to request GPIO %d as bypass pin (%d)\n", + hub->gpio_bypass, err); + return err; + } + } + if (gpio_is_valid(hub->gpio_reset)) { err = devm_gpio_request_one(dev, hub->gpio_reset, GPIOF_OUT_INIT_LOW, "usb3503 reset"); @@ -408,6 +450,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); |