| .. | .. |
|---|
| 12 | 12 | |
|---|
| 13 | 13 | #include <linux/delay.h> |
|---|
| 14 | 14 | #include <linux/gpio/consumer.h> |
|---|
| 15 | +#include <linux/gpio/driver.h> |
|---|
| 15 | 16 | #include <linux/i2c.h> |
|---|
| 16 | 17 | #include <linux/module.h> |
|---|
| 17 | 18 | #include <linux/nls.h> |
|---|
| 18 | 19 | #include <linux/of_device.h> |
|---|
| 20 | +#include <linux/regulator/consumer.h> |
|---|
| 19 | 21 | #include <linux/slab.h> |
|---|
| 20 | 22 | |
|---|
| 21 | 23 | /* Internal Register Set Addresses & Default Values acc. to DS00001692C */ |
|---|
| .. | .. |
|---|
| 25 | 27 | |
|---|
| 26 | 28 | #define USB251XB_ADDR_PRODUCT_ID_LSB 0x02 |
|---|
| 27 | 29 | #define USB251XB_ADDR_PRODUCT_ID_MSB 0x03 |
|---|
| 28 | | -#define USB251XB_DEF_PRODUCT_ID_12 0x2512 /* USB2512B/12Bi */ |
|---|
| 29 | | -#define USB251XB_DEF_PRODUCT_ID_13 0x2513 /* USB2513B/13Bi */ |
|---|
| 30 | | -#define USB251XB_DEF_PRODUCT_ID_14 0x2514 /* USB2514B/14Bi */ |
|---|
| 31 | | -#define USB251XB_DEF_PRODUCT_ID_17 0x2517 /* USB2517/17i */ |
|---|
| 32 | 30 | |
|---|
| 33 | 31 | #define USB251XB_ADDR_DEVICE_ID_LSB 0x04 |
|---|
| 34 | 32 | #define USB251XB_ADDR_DEVICE_ID_MSB 0x05 |
|---|
| .. | .. |
|---|
| 73 | 71 | |
|---|
| 74 | 72 | #define USB251XB_ADDR_PRODUCT_STRING_LEN 0x14 |
|---|
| 75 | 73 | #define USB251XB_ADDR_PRODUCT_STRING 0x54 |
|---|
| 76 | | -#define USB251XB_DEF_PRODUCT_STRING "USB251xB/xBi/7i" |
|---|
| 77 | 74 | |
|---|
| 78 | 75 | #define USB251XB_ADDR_SERIAL_STRING_LEN 0x15 |
|---|
| 79 | 76 | #define USB251XB_ADDR_SERIAL_STRING 0x92 |
|---|
| .. | .. |
|---|
| 115 | 112 | struct usb251xb { |
|---|
| 116 | 113 | struct device *dev; |
|---|
| 117 | 114 | struct i2c_client *i2c; |
|---|
| 115 | + struct regulator *vdd; |
|---|
| 118 | 116 | u8 skip_config; |
|---|
| 119 | 117 | struct gpio_desc *gpio_reset; |
|---|
| 120 | 118 | u16 vendor_id; |
|---|
| .. | .. |
|---|
| 156 | 154 | bool led_support; |
|---|
| 157 | 155 | bool bat_support; |
|---|
| 158 | 156 | char product_str[USB251XB_STRING_BUFSIZE / 2]; /* ASCII string */ |
|---|
| 157 | +}; |
|---|
| 158 | + |
|---|
| 159 | +static const struct usb251xb_data usb2422_data = { |
|---|
| 160 | + .product_id = 0x2422, |
|---|
| 161 | + .port_cnt = 2, |
|---|
| 162 | + .led_support = false, |
|---|
| 163 | + .bat_support = true, |
|---|
| 164 | + .product_str = "USB2422", |
|---|
| 159 | 165 | }; |
|---|
| 160 | 166 | |
|---|
| 161 | 167 | static const struct usb251xb_data usb2512b_data = { |
|---|
| .. | .. |
|---|
| 222 | 228 | .product_str = "USB2517i", |
|---|
| 223 | 229 | }; |
|---|
| 224 | 230 | |
|---|
| 225 | | -static void usb251xb_reset(struct usb251xb *hub, int state) |
|---|
| 231 | +#ifdef CONFIG_GPIOLIB |
|---|
| 232 | +static int usb251xb_check_dev_children(struct device *dev, void *child) |
|---|
| 233 | +{ |
|---|
| 234 | + if (dev->type == &i2c_adapter_type) { |
|---|
| 235 | + return device_for_each_child(dev, child, |
|---|
| 236 | + usb251xb_check_dev_children); |
|---|
| 237 | + } |
|---|
| 238 | + |
|---|
| 239 | + return (dev == child); |
|---|
| 240 | +} |
|---|
| 241 | + |
|---|
| 242 | +static int usb251x_check_gpio_chip(struct usb251xb *hub) |
|---|
| 243 | +{ |
|---|
| 244 | + struct gpio_chip *gc = gpiod_to_chip(hub->gpio_reset); |
|---|
| 245 | + struct i2c_adapter *adap = hub->i2c->adapter; |
|---|
| 246 | + int ret; |
|---|
| 247 | + |
|---|
| 248 | + if (!hub->gpio_reset) |
|---|
| 249 | + return 0; |
|---|
| 250 | + |
|---|
| 251 | + if (!gc) |
|---|
| 252 | + return -EINVAL; |
|---|
| 253 | + |
|---|
| 254 | + ret = usb251xb_check_dev_children(&adap->dev, gc->parent); |
|---|
| 255 | + if (ret) { |
|---|
| 256 | + dev_err(hub->dev, "Reset GPIO chip is at the same i2c-bus\n"); |
|---|
| 257 | + return -EINVAL; |
|---|
| 258 | + } |
|---|
| 259 | + |
|---|
| 260 | + return 0; |
|---|
| 261 | +} |
|---|
| 262 | +#else |
|---|
| 263 | +static int usb251x_check_gpio_chip(struct usb251xb *hub) |
|---|
| 264 | +{ |
|---|
| 265 | + return 0; |
|---|
| 266 | +} |
|---|
| 267 | +#endif |
|---|
| 268 | + |
|---|
| 269 | +static void usb251xb_reset(struct usb251xb *hub) |
|---|
| 226 | 270 | { |
|---|
| 227 | 271 | if (!hub->gpio_reset) |
|---|
| 228 | 272 | return; |
|---|
| 229 | 273 | |
|---|
| 230 | | - gpiod_set_value_cansleep(hub->gpio_reset, state); |
|---|
| 274 | + i2c_lock_bus(hub->i2c->adapter, I2C_LOCK_SEGMENT); |
|---|
| 275 | + |
|---|
| 276 | + gpiod_set_value_cansleep(hub->gpio_reset, 1); |
|---|
| 277 | + usleep_range(1, 10); /* >=1us RESET_N asserted */ |
|---|
| 278 | + gpiod_set_value_cansleep(hub->gpio_reset, 0); |
|---|
| 231 | 279 | |
|---|
| 232 | 280 | /* wait for hub recovery/stabilization */ |
|---|
| 233 | | - if (!state) |
|---|
| 234 | | - usleep_range(500, 750); /* >=500us at power on */ |
|---|
| 235 | | - else |
|---|
| 236 | | - usleep_range(1, 10); /* >=1us at power down */ |
|---|
| 281 | + usleep_range(500, 750); /* >=500us after RESET_N deasserted */ |
|---|
| 282 | + |
|---|
| 283 | + i2c_unlock_bus(hub->i2c->adapter, I2C_LOCK_SEGMENT); |
|---|
| 237 | 284 | } |
|---|
| 238 | 285 | |
|---|
| 239 | 286 | static int usb251xb_connect(struct usb251xb *hub) |
|---|
| .. | .. |
|---|
| 249 | 296 | i2c_wb[0] = 0x01; |
|---|
| 250 | 297 | i2c_wb[1] = USB251XB_STATUS_COMMAND_ATTACH; |
|---|
| 251 | 298 | |
|---|
| 252 | | - usb251xb_reset(hub, 0); |
|---|
| 299 | + usb251xb_reset(hub); |
|---|
| 253 | 300 | |
|---|
| 254 | 301 | err = i2c_smbus_write_i2c_block_data(hub->i2c, |
|---|
| 255 | 302 | USB251XB_ADDR_STATUS_COMMAND, 2, i2c_wb); |
|---|
| .. | .. |
|---|
| 299 | 346 | i2c_wb[USB251XB_ADDR_PORT_MAP_7] = hub->port_map7; |
|---|
| 300 | 347 | i2c_wb[USB251XB_ADDR_STATUS_COMMAND] = USB251XB_STATUS_COMMAND_ATTACH; |
|---|
| 301 | 348 | |
|---|
| 302 | | - usb251xb_reset(hub, 0); |
|---|
| 349 | + usb251xb_reset(hub); |
|---|
| 303 | 350 | |
|---|
| 304 | 351 | /* write registers */ |
|---|
| 305 | 352 | for (i = 0; i < (USB251XB_I2C_REG_SZ / USB251XB_I2C_WRITE_SZ); i++) { |
|---|
| .. | .. |
|---|
| 331 | 378 | } |
|---|
| 332 | 379 | |
|---|
| 333 | 380 | #ifdef CONFIG_OF |
|---|
| 381 | +static void usb251xb_get_ports_field(struct usb251xb *hub, |
|---|
| 382 | + const char *prop_name, u8 port_cnt, |
|---|
| 383 | + bool ds_only, u8 *fld) |
|---|
| 384 | +{ |
|---|
| 385 | + struct device *dev = hub->dev; |
|---|
| 386 | + struct property *prop; |
|---|
| 387 | + const __be32 *p; |
|---|
| 388 | + u32 port; |
|---|
| 389 | + |
|---|
| 390 | + of_property_for_each_u32(dev->of_node, prop_name, prop, p, port) { |
|---|
| 391 | + if ((port >= ds_only ? 1 : 0) && (port <= port_cnt)) |
|---|
| 392 | + *fld |= BIT(port); |
|---|
| 393 | + else |
|---|
| 394 | + dev_warn(dev, "port %u doesn't exist\n", port); |
|---|
| 395 | + } |
|---|
| 396 | +} |
|---|
| 397 | + |
|---|
| 334 | 398 | static int usb251xb_get_ofdata(struct usb251xb *hub, |
|---|
| 335 | 399 | struct usb251xb_data *data) |
|---|
| 336 | 400 | { |
|---|
| 337 | 401 | struct device *dev = hub->dev; |
|---|
| 338 | 402 | struct device_node *np = dev->of_node; |
|---|
| 339 | | - int len, err, i; |
|---|
| 403 | + int len, err; |
|---|
| 340 | 404 | u32 property_u32 = 0; |
|---|
| 341 | | - const u32 *cproperty_u32; |
|---|
| 342 | 405 | const char *cproperty_char; |
|---|
| 343 | 406 | char str[USB251XB_STRING_BUFSIZE / 2]; |
|---|
| 344 | 407 | |
|---|
| .. | .. |
|---|
| 442 | 505 | hub->conf_data3 |= BIT(0); |
|---|
| 443 | 506 | |
|---|
| 444 | 507 | hub->non_rem_dev = USB251XB_DEF_NON_REMOVABLE_DEVICES; |
|---|
| 445 | | - cproperty_u32 = of_get_property(np, "non-removable-ports", &len); |
|---|
| 446 | | - if (cproperty_u32 && (len / sizeof(u32)) > 0) { |
|---|
| 447 | | - for (i = 0; i < len / sizeof(u32); i++) { |
|---|
| 448 | | - u32 port = be32_to_cpu(cproperty_u32[i]); |
|---|
| 449 | | - |
|---|
| 450 | | - if ((port >= 1) && (port <= data->port_cnt)) |
|---|
| 451 | | - hub->non_rem_dev |= BIT(port); |
|---|
| 452 | | - else |
|---|
| 453 | | - dev_warn(dev, "NRD port %u doesn't exist\n", |
|---|
| 454 | | - port); |
|---|
| 455 | | - } |
|---|
| 456 | | - } |
|---|
| 508 | + usb251xb_get_ports_field(hub, "non-removable-ports", data->port_cnt, |
|---|
| 509 | + true, &hub->non_rem_dev); |
|---|
| 457 | 510 | |
|---|
| 458 | 511 | hub->port_disable_sp = USB251XB_DEF_PORT_DISABLE_SELF; |
|---|
| 459 | | - cproperty_u32 = of_get_property(np, "sp-disabled-ports", &len); |
|---|
| 460 | | - if (cproperty_u32 && (len / sizeof(u32)) > 0) { |
|---|
| 461 | | - for (i = 0; i < len / sizeof(u32); i++) { |
|---|
| 462 | | - u32 port = be32_to_cpu(cproperty_u32[i]); |
|---|
| 463 | | - |
|---|
| 464 | | - if ((port >= 1) && (port <= data->port_cnt)) |
|---|
| 465 | | - hub->port_disable_sp |= BIT(port); |
|---|
| 466 | | - else |
|---|
| 467 | | - dev_warn(dev, "PDS port %u doesn't exist\n", |
|---|
| 468 | | - port); |
|---|
| 469 | | - } |
|---|
| 470 | | - } |
|---|
| 512 | + usb251xb_get_ports_field(hub, "sp-disabled-ports", data->port_cnt, |
|---|
| 513 | + true, &hub->port_disable_sp); |
|---|
| 471 | 514 | |
|---|
| 472 | 515 | hub->port_disable_bp = USB251XB_DEF_PORT_DISABLE_BUS; |
|---|
| 473 | | - cproperty_u32 = of_get_property(np, "bp-disabled-ports", &len); |
|---|
| 474 | | - if (cproperty_u32 && (len / sizeof(u32)) > 0) { |
|---|
| 475 | | - for (i = 0; i < len / sizeof(u32); i++) { |
|---|
| 476 | | - u32 port = be32_to_cpu(cproperty_u32[i]); |
|---|
| 477 | | - |
|---|
| 478 | | - if ((port >= 1) && (port <= data->port_cnt)) |
|---|
| 479 | | - hub->port_disable_bp |= BIT(port); |
|---|
| 480 | | - else |
|---|
| 481 | | - dev_warn(dev, "PDB port %u doesn't exist\n", |
|---|
| 482 | | - port); |
|---|
| 483 | | - } |
|---|
| 484 | | - } |
|---|
| 516 | + usb251xb_get_ports_field(hub, "bp-disabled-ports", data->port_cnt, |
|---|
| 517 | + true, &hub->port_disable_bp); |
|---|
| 485 | 518 | |
|---|
| 486 | 519 | hub->max_power_sp = USB251XB_DEF_MAX_POWER_SELF; |
|---|
| 487 | 520 | if (!of_property_read_u32(np, "sp-max-total-current-microamp", |
|---|
| .. | .. |
|---|
| 539 | 572 | (wchar_t *)hub->serial, |
|---|
| 540 | 573 | USB251XB_STRING_BUFSIZE); |
|---|
| 541 | 574 | |
|---|
| 575 | + /* |
|---|
| 576 | + * The datasheet documents the register as 'Port Swap' but in real the |
|---|
| 577 | + * register controls the USB DP/DM signal swapping for each port. |
|---|
| 578 | + */ |
|---|
| 579 | + hub->port_swap = USB251XB_DEF_PORT_SWAP; |
|---|
| 580 | + usb251xb_get_ports_field(hub, "swap-dx-lanes", data->port_cnt, |
|---|
| 581 | + false, &hub->port_swap); |
|---|
| 582 | + |
|---|
| 542 | 583 | /* The following parameters are currently not exposed to devicetree, but |
|---|
| 543 | 584 | * may be as soon as needed. |
|---|
| 544 | 585 | */ |
|---|
| .. | .. |
|---|
| 546 | 587 | hub->boost_up = USB251XB_DEF_BOOST_UP; |
|---|
| 547 | 588 | hub->boost_57 = USB251XB_DEF_BOOST_57; |
|---|
| 548 | 589 | hub->boost_14 = USB251XB_DEF_BOOST_14; |
|---|
| 549 | | - hub->port_swap = USB251XB_DEF_PORT_SWAP; |
|---|
| 550 | 590 | hub->port_map12 = USB251XB_DEF_PORT_MAP_12; |
|---|
| 551 | 591 | hub->port_map34 = USB251XB_DEF_PORT_MAP_34; |
|---|
| 552 | 592 | hub->port_map56 = USB251XB_DEF_PORT_MAP_56; |
|---|
| .. | .. |
|---|
| 557 | 597 | |
|---|
| 558 | 598 | static const struct of_device_id usb251xb_of_match[] = { |
|---|
| 559 | 599 | { |
|---|
| 600 | + .compatible = "microchip,usb2422", |
|---|
| 601 | + .data = &usb2422_data, |
|---|
| 602 | + }, { |
|---|
| 560 | 603 | .compatible = "microchip,usb2512b", |
|---|
| 561 | 604 | .data = &usb2512b_data, |
|---|
| 562 | 605 | }, { |
|---|
| .. | .. |
|---|
| 593 | 636 | } |
|---|
| 594 | 637 | #endif /* CONFIG_OF */ |
|---|
| 595 | 638 | |
|---|
| 639 | +static void usb251xb_regulator_disable_action(void *data) |
|---|
| 640 | +{ |
|---|
| 641 | + struct usb251xb *hub = data; |
|---|
| 642 | + |
|---|
| 643 | + regulator_disable(hub->vdd); |
|---|
| 644 | +} |
|---|
| 645 | + |
|---|
| 596 | 646 | static int usb251xb_probe(struct usb251xb *hub) |
|---|
| 597 | 647 | { |
|---|
| 598 | 648 | struct device *dev = hub->dev; |
|---|
| .. | .. |
|---|
| 609 | 659 | return err; |
|---|
| 610 | 660 | } |
|---|
| 611 | 661 | } |
|---|
| 662 | + |
|---|
| 663 | + /* |
|---|
| 664 | + * usb251x SMBus-slave SCL lane is muxed with CFG_SEL0 pin. So if anyone |
|---|
| 665 | + * tries to work with the bus at the moment the hub reset is released, |
|---|
| 666 | + * it may cause an invalid config being latched by usb251x. Particularly |
|---|
| 667 | + * one of the config modes makes the hub loading a default registers |
|---|
| 668 | + * value without SMBus-slave interface activation. If the hub |
|---|
| 669 | + * accidentally gets this mode, this will cause the driver SMBus- |
|---|
| 670 | + * functions failure. Normally we could just lock the SMBus-segment the |
|---|
| 671 | + * hub i2c-interface resides for the device-specific reset timing. But |
|---|
| 672 | + * the GPIO controller, which is used to handle the hub reset, might be |
|---|
| 673 | + * placed at the same i2c-bus segment. In this case an error should be |
|---|
| 674 | + * returned since we can't safely use the GPIO controller to clear the |
|---|
| 675 | + * reset state (it may affect the hub configuration) and we can't lock |
|---|
| 676 | + * the i2c-bus segment (it will cause a deadlock). |
|---|
| 677 | + */ |
|---|
| 678 | + err = usb251x_check_gpio_chip(hub); |
|---|
| 679 | + if (err) |
|---|
| 680 | + return err; |
|---|
| 681 | + |
|---|
| 682 | + hub->vdd = devm_regulator_get(dev, "vdd"); |
|---|
| 683 | + if (IS_ERR(hub->vdd)) |
|---|
| 684 | + return PTR_ERR(hub->vdd); |
|---|
| 685 | + |
|---|
| 686 | + err = regulator_enable(hub->vdd); |
|---|
| 687 | + if (err) |
|---|
| 688 | + return err; |
|---|
| 689 | + |
|---|
| 690 | + err = devm_add_action_or_reset(dev, |
|---|
| 691 | + usb251xb_regulator_disable_action, hub); |
|---|
| 692 | + if (err) |
|---|
| 693 | + return err; |
|---|
| 612 | 694 | |
|---|
| 613 | 695 | err = usb251xb_connect(hub); |
|---|
| 614 | 696 | if (err) { |
|---|
| .. | .. |
|---|
| 637 | 719 | return usb251xb_probe(hub); |
|---|
| 638 | 720 | } |
|---|
| 639 | 721 | |
|---|
| 722 | +static int __maybe_unused usb251xb_suspend(struct device *dev) |
|---|
| 723 | +{ |
|---|
| 724 | + struct i2c_client *client = to_i2c_client(dev); |
|---|
| 725 | + struct usb251xb *hub = i2c_get_clientdata(client); |
|---|
| 726 | + |
|---|
| 727 | + return regulator_disable(hub->vdd); |
|---|
| 728 | +} |
|---|
| 729 | + |
|---|
| 730 | +static int __maybe_unused usb251xb_resume(struct device *dev) |
|---|
| 731 | +{ |
|---|
| 732 | + struct i2c_client *client = to_i2c_client(dev); |
|---|
| 733 | + struct usb251xb *hub = i2c_get_clientdata(client); |
|---|
| 734 | + int err; |
|---|
| 735 | + |
|---|
| 736 | + err = regulator_enable(hub->vdd); |
|---|
| 737 | + if (err) |
|---|
| 738 | + return err; |
|---|
| 739 | + |
|---|
| 740 | + return usb251xb_connect(hub); |
|---|
| 741 | +} |
|---|
| 742 | + |
|---|
| 743 | +static SIMPLE_DEV_PM_OPS(usb251xb_pm_ops, usb251xb_suspend, usb251xb_resume); |
|---|
| 744 | + |
|---|
| 640 | 745 | static const struct i2c_device_id usb251xb_id[] = { |
|---|
| 746 | + { "usb2422", 0 }, |
|---|
| 641 | 747 | { "usb2512b", 0 }, |
|---|
| 642 | 748 | { "usb2512bi", 0 }, |
|---|
| 643 | 749 | { "usb2513b", 0 }, |
|---|
| .. | .. |
|---|
| 654 | 760 | .driver = { |
|---|
| 655 | 761 | .name = DRIVER_NAME, |
|---|
| 656 | 762 | .of_match_table = of_match_ptr(usb251xb_of_match), |
|---|
| 763 | + .pm = &usb251xb_pm_ops, |
|---|
| 657 | 764 | }, |
|---|
| 658 | 765 | .probe = usb251xb_i2c_probe, |
|---|
| 659 | 766 | .id_table = usb251xb_id, |
|---|