diff options
Diffstat (limited to 'drivers/usb/misc/usb251xb.c')
-rw-r--r-- | drivers/usb/misc/usb251xb.c | 135 |
1 files changed, 90 insertions, 45 deletions
diff --git a/drivers/usb/misc/usb251xb.c b/drivers/usb/misc/usb251xb.c index 04684849d683..4d6ae3795a88 100644 --- a/drivers/usb/misc/usb251xb.c +++ b/drivers/usb/misc/usb251xb.c | |||
@@ -12,6 +12,7 @@ | |||
12 | 12 | ||
13 | #include <linux/delay.h> | 13 | #include <linux/delay.h> |
14 | #include <linux/gpio/consumer.h> | 14 | #include <linux/gpio/consumer.h> |
15 | #include <linux/gpio/driver.h> | ||
15 | #include <linux/i2c.h> | 16 | #include <linux/i2c.h> |
16 | #include <linux/module.h> | 17 | #include <linux/module.h> |
17 | #include <linux/nls.h> | 18 | #include <linux/nls.h> |
@@ -222,11 +223,51 @@ static const struct usb251xb_data usb2517i_data = { | |||
222 | .product_str = "USB2517i", | 223 | .product_str = "USB2517i", |
223 | }; | 224 | }; |
224 | 225 | ||
226 | #ifdef CONFIG_GPIOLIB | ||
227 | static int usb251xb_check_dev_children(struct device *dev, void *child) | ||
228 | { | ||
229 | if (dev->type == &i2c_adapter_type) { | ||
230 | return device_for_each_child(dev, child, | ||
231 | usb251xb_check_dev_children); | ||
232 | } | ||
233 | |||
234 | return (dev == child); | ||
235 | } | ||
236 | |||
237 | static int usb251x_check_gpio_chip(struct usb251xb *hub) | ||
238 | { | ||
239 | struct gpio_chip *gc = gpiod_to_chip(hub->gpio_reset); | ||
240 | struct i2c_adapter *adap = hub->i2c->adapter; | ||
241 | int ret; | ||
242 | |||
243 | if (!hub->gpio_reset) | ||
244 | return 0; | ||
245 | |||
246 | if (!gc) | ||
247 | return -EINVAL; | ||
248 | |||
249 | ret = usb251xb_check_dev_children(&adap->dev, gc->parent); | ||
250 | if (ret) { | ||
251 | dev_err(hub->dev, "Reset GPIO chip is at the same i2c-bus\n"); | ||
252 | return -EINVAL; | ||
253 | } | ||
254 | |||
255 | return 0; | ||
256 | } | ||
257 | #else | ||
258 | static int usb251x_check_gpio_chip(struct usb251xb *hub) | ||
259 | { | ||
260 | return 0; | ||
261 | } | ||
262 | #endif | ||
263 | |||
225 | static void usb251xb_reset(struct usb251xb *hub, int state) | 264 | static void usb251xb_reset(struct usb251xb *hub, int state) |
226 | { | 265 | { |
227 | if (!hub->gpio_reset) | 266 | if (!hub->gpio_reset) |
228 | return; | 267 | return; |
229 | 268 | ||
269 | i2c_lock_bus(hub->i2c->adapter, I2C_LOCK_SEGMENT); | ||
270 | |||
230 | gpiod_set_value_cansleep(hub->gpio_reset, state); | 271 | gpiod_set_value_cansleep(hub->gpio_reset, state); |
231 | 272 | ||
232 | /* wait for hub recovery/stabilization */ | 273 | /* wait for hub recovery/stabilization */ |
@@ -234,6 +275,8 @@ static void usb251xb_reset(struct usb251xb *hub, int state) | |||
234 | usleep_range(500, 750); /* >=500us at power on */ | 275 | usleep_range(500, 750); /* >=500us at power on */ |
235 | else | 276 | else |
236 | usleep_range(1, 10); /* >=1us at power down */ | 277 | usleep_range(1, 10); /* >=1us at power down */ |
278 | |||
279 | i2c_unlock_bus(hub->i2c->adapter, I2C_LOCK_SEGMENT); | ||
237 | } | 280 | } |
238 | 281 | ||
239 | static int usb251xb_connect(struct usb251xb *hub) | 282 | static int usb251xb_connect(struct usb251xb *hub) |
@@ -331,18 +374,31 @@ out_err: | |||
331 | } | 374 | } |
332 | 375 | ||
333 | #ifdef CONFIG_OF | 376 | #ifdef CONFIG_OF |
377 | static void usb251xb_get_ports_field(struct usb251xb *hub, | ||
378 | const char *prop_name, u8 port_cnt, u8 *fld) | ||
379 | { | ||
380 | struct device *dev = hub->dev; | ||
381 | struct property *prop; | ||
382 | const __be32 *p; | ||
383 | u32 port; | ||
384 | |||
385 | of_property_for_each_u32(dev->of_node, prop_name, prop, p, port) { | ||
386 | if ((port >= 1) && (port <= port_cnt)) | ||
387 | *fld |= BIT(port); | ||
388 | else | ||
389 | dev_warn(dev, "port %u doesn't exist\n", port); | ||
390 | } | ||
391 | } | ||
392 | |||
334 | static int usb251xb_get_ofdata(struct usb251xb *hub, | 393 | static int usb251xb_get_ofdata(struct usb251xb *hub, |
335 | struct usb251xb_data *data) | 394 | struct usb251xb_data *data) |
336 | { | 395 | { |
337 | struct device *dev = hub->dev; | 396 | struct device *dev = hub->dev; |
338 | struct device_node *np = dev->of_node; | 397 | struct device_node *np = dev->of_node; |
339 | int len, err, i; | 398 | int len, err; |
340 | u32 port, property_u32 = 0; | 399 | u32 property_u32 = 0; |
341 | const u32 *cproperty_u32; | ||
342 | const char *cproperty_char; | 400 | const char *cproperty_char; |
343 | char str[USB251XB_STRING_BUFSIZE / 2]; | 401 | char str[USB251XB_STRING_BUFSIZE / 2]; |
344 | struct property *prop; | ||
345 | const __be32 *p; | ||
346 | 402 | ||
347 | if (!np) { | 403 | if (!np) { |
348 | dev_err(dev, "failed to get ofdata\n"); | 404 | dev_err(dev, "failed to get ofdata\n"); |
@@ -444,46 +500,16 @@ static int usb251xb_get_ofdata(struct usb251xb *hub, | |||
444 | hub->conf_data3 |= BIT(0); | 500 | hub->conf_data3 |= BIT(0); |
445 | 501 | ||
446 | hub->non_rem_dev = USB251XB_DEF_NON_REMOVABLE_DEVICES; | 502 | hub->non_rem_dev = USB251XB_DEF_NON_REMOVABLE_DEVICES; |
447 | cproperty_u32 = of_get_property(np, "non-removable-ports", &len); | 503 | usb251xb_get_ports_field(hub, "non-removable-ports", data->port_cnt, |
448 | if (cproperty_u32 && (len / sizeof(u32)) > 0) { | 504 | &hub->non_rem_dev); |
449 | for (i = 0; i < len / sizeof(u32); i++) { | ||
450 | u32 port = be32_to_cpu(cproperty_u32[i]); | ||
451 | |||
452 | if ((port >= 1) && (port <= data->port_cnt)) | ||
453 | hub->non_rem_dev |= BIT(port); | ||
454 | else | ||
455 | dev_warn(dev, "NRD port %u doesn't exist\n", | ||
456 | port); | ||
457 | } | ||
458 | } | ||
459 | 505 | ||
460 | hub->port_disable_sp = USB251XB_DEF_PORT_DISABLE_SELF; | 506 | hub->port_disable_sp = USB251XB_DEF_PORT_DISABLE_SELF; |
461 | cproperty_u32 = of_get_property(np, "sp-disabled-ports", &len); | 507 | usb251xb_get_ports_field(hub, "sp-disabled-ports", data->port_cnt, |
462 | if (cproperty_u32 && (len / sizeof(u32)) > 0) { | 508 | &hub->port_disable_sp); |
463 | for (i = 0; i < len / sizeof(u32); i++) { | ||
464 | u32 port = be32_to_cpu(cproperty_u32[i]); | ||
465 | |||
466 | if ((port >= 1) && (port <= data->port_cnt)) | ||
467 | hub->port_disable_sp |= BIT(port); | ||
468 | else | ||
469 | dev_warn(dev, "PDS port %u doesn't exist\n", | ||
470 | port); | ||
471 | } | ||
472 | } | ||
473 | 509 | ||
474 | hub->port_disable_bp = USB251XB_DEF_PORT_DISABLE_BUS; | 510 | hub->port_disable_bp = USB251XB_DEF_PORT_DISABLE_BUS; |
475 | cproperty_u32 = of_get_property(np, "bp-disabled-ports", &len); | 511 | usb251xb_get_ports_field(hub, "bp-disabled-ports", data->port_cnt, |
476 | if (cproperty_u32 && (len / sizeof(u32)) > 0) { | 512 | &hub->port_disable_bp); |
477 | for (i = 0; i < len / sizeof(u32); i++) { | ||
478 | u32 port = be32_to_cpu(cproperty_u32[i]); | ||
479 | |||
480 | if ((port >= 1) && (port <= data->port_cnt)) | ||
481 | hub->port_disable_bp |= BIT(port); | ||
482 | else | ||
483 | dev_warn(dev, "PDB port %u doesn't exist\n", | ||
484 | port); | ||
485 | } | ||
486 | } | ||
487 | 513 | ||
488 | hub->max_power_sp = USB251XB_DEF_MAX_POWER_SELF; | 514 | hub->max_power_sp = USB251XB_DEF_MAX_POWER_SELF; |
489 | if (!of_property_read_u32(np, "sp-max-total-current-microamp", | 515 | if (!of_property_read_u32(np, "sp-max-total-current-microamp", |
@@ -546,10 +572,10 @@ static int usb251xb_get_ofdata(struct usb251xb *hub, | |||
546 | * register controls the USB DP/DM signal swapping for each port. | 572 | * register controls the USB DP/DM signal swapping for each port. |
547 | */ | 573 | */ |
548 | hub->port_swap = USB251XB_DEF_PORT_SWAP; | 574 | hub->port_swap = USB251XB_DEF_PORT_SWAP; |
549 | of_property_for_each_u32(np, "swap-dx-lanes", prop, p, port) { | 575 | usb251xb_get_ports_field(hub, "swap-dx-lanes", data->port_cnt, |
550 | if (port <= data->port_cnt) | 576 | &hub->port_swap); |
551 | hub->port_swap |= BIT(port); | 577 | if (of_get_property(np, "swap-us-lanes", NULL)) |
552 | } | 578 | hub->port_swap |= BIT(0); |
553 | 579 | ||
554 | /* The following parameters are currently not exposed to devicetree, but | 580 | /* The following parameters are currently not exposed to devicetree, but |
555 | * may be as soon as needed. | 581 | * may be as soon as needed. |
@@ -621,6 +647,25 @@ static int usb251xb_probe(struct usb251xb *hub) | |||
621 | } | 647 | } |
622 | } | 648 | } |
623 | 649 | ||
650 | /* | ||
651 | * usb251x SMBus-slave SCL lane is muxed with CFG_SEL0 pin. So if anyone | ||
652 | * tries to work with the bus at the moment the hub reset is released, | ||
653 | * it may cause an invalid config being latched by usb251x. Particularly | ||
654 | * one of the config modes makes the hub loading a default registers | ||
655 | * value without SMBus-slave interface activation. If the hub | ||
656 | * accidentally gets this mode, this will cause the driver SMBus- | ||
657 | * functions failure. Normally we could just lock the SMBus-segment the | ||
658 | * hub i2c-interface resides for the device-specific reset timing. But | ||
659 | * the GPIO controller, which is used to handle the hub reset, might be | ||
660 | * placed at the same i2c-bus segment. In this case an error should be | ||
661 | * returned since we can't safely use the GPIO controller to clear the | ||
662 | * reset state (it may affect the hub configuration) and we can't lock | ||
663 | * the i2c-bus segment (it will cause a deadlock). | ||
664 | */ | ||
665 | err = usb251x_check_gpio_chip(hub); | ||
666 | if (err) | ||
667 | return err; | ||
668 | |||
624 | err = usb251xb_connect(hub); | 669 | err = usb251xb_connect(hub); |
625 | if (err) { | 670 | if (err) { |
626 | dev_err(dev, "Failed to connect hub (%d)\n", err); | 671 | dev_err(dev, "Failed to connect hub (%d)\n", err); |