The barebox driver was ported before Linux learnt about multiple
supplies, a clock and the I2C-configured USB5744, and its device table
has fallen behind.

Resync with Linux 7.3 drivers/usb/misc/onboard_usb_dev.c and .h.

Signed-off-by: Ahmad Fatoum <[email protected]>
---
 drivers/usb/misc/Kconfig           |  11 +
 drivers/usb/misc/onboard_usb_dev.c | 377 +++++++++++++++++++++++------
 drivers/usb/misc/onboard_usb_dev.h | 132 +++++++++-
 3 files changed, 446 insertions(+), 74 deletions(-)

diff --git a/drivers/usb/misc/Kconfig b/drivers/usb/misc/Kconfig
index 6fe80a0f176b..eb8d3a208149 100644
--- a/drivers/usb/misc/Kconfig
+++ b/drivers/usb/misc/Kconfig
@@ -24,3 +24,14 @@ config USB_ONBOARD_DEV
          but need some non-trivial form of initialization, such as
          enabling a power regulator. An example for such device is the
          Realtek RTS5411 hub.
+
+config USB_ONBOARD_DEV_USB5744
+       bool "Onboard USB Microchip usb5744 hub with SMBus support"
+       depends on USB_ONBOARD_DEV && I2C
+       help
+         Say Y here if you want to support onboard USB Microchip usb5744
+         hub that requires SMBus initialization.
+
+         This options enables usb5744 i2c default initialization sequence
+         during hub start-up configuration stage. Without it, a hub that
+         has an i2c-bus is not powered.
diff --git a/drivers/usb/misc/onboard_usb_dev.c 
b/drivers/usb/misc/onboard_usb_dev.c
index 730f443dfefe..bb1b5ffd6e1e 100644
--- a/drivers/usb/misc/onboard_usb_dev.c
+++ b/drivers/usb/misc/onboard_usb_dev.c
@@ -1,22 +1,326 @@
 // SPDX-License-Identifier: GPL-2.0-only
+// SPDX-Comment: Origin-URL: 
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/drivers/usb/misc/onboard_usb_dev.c?id=a174da76d3625a5e32f816ee27924ad5d6c1f19f
 /*
  * Driver for onboard USB devices
  *
  * Copyright (c) 2022, Google LLC
  */
 
-#include <driver.h>
+#include <linux/clk.h>
+#include <linux/device.h>
+#include <linux/export.h>
+#include <linux/err.h>
 #include <linux/gpio/consumer.h>
 #include <init.h>
+#include <i2c/i2c.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
 #include <of.h>
-#include <linux/printk.h>
-#include <of_device.h>
+#include <driver.h>
 #include <regulator.h>
-#include <xfuncs.h>
+#include <linux/slab.h>
 #include <linux/usb/usb.h>
 
 #include "onboard_usb_dev.h"
 
+/* USB5744 register offset and mask */
+#define USB5744_CMD_ATTACH                     0xAA
+#define USB5744_CMD_ATTACH_LSB                 0x56
+#define USB5744_CMD_CREG_ACCESS                        0x99
+#define USB5744_CMD_CREG_ACCESS_LSB            0x37
+#define USB5744_CREG_MEM_ADDR                  0x00
+#define USB5744_CREG_MEM_RD_ADDR               0x04
+#define USB5744_CREG_WRITE                     0x00
+#define USB5744_CREG_READ                      0x01
+#define USB5744_CREG_RUNTIMEFLAGS2             0x411D
+#define USB5744_CREG_BYPASS_UDC_SUSPEND                BIT(3)
+
+/************************** Platform driver **************************/
+
+struct onboard_dev {
+       struct regulator_bulk_data supplies[MAX_SUPPLIES];
+       struct device *dev;
+       const struct onboard_dev_pdata *pdata;
+       struct gpio_desc *reset_gpio;
+       struct clk *clk;
+};
+
+static int onboard_dev_get_regulators(struct onboard_dev *onboard_dev)
+{
+       const char * const *supply_names = onboard_dev->pdata->supply_names;
+       unsigned int num_supplies = onboard_dev->pdata->num_supplies;
+       struct device *dev = onboard_dev->dev;
+       unsigned int i;
+       int err;
+
+       if (num_supplies > MAX_SUPPLIES)
+               return dev_err_probe(dev, -EINVAL, "max %d supplies 
supported!\n",
+                                    MAX_SUPPLIES);
+
+       for (i = 0; i < num_supplies; i++)
+               onboard_dev->supplies[i].supply = supply_names[i];
+
+       err = regulator_bulk_get(dev, num_supplies, onboard_dev->supplies);
+       if (err)
+               dev_err(dev, "Failed to get regulator supplies: %pe\n",
+                       ERR_PTR(err));
+
+       return err;
+}
+
+static int onboard_dev_power_on(struct onboard_dev *onboard_dev)
+{
+       int err;
+
+       err = clk_prepare_enable(onboard_dev->clk);
+       if (err) {
+               dev_err(onboard_dev->dev, "failed to enable clock: %pe\n",
+                       ERR_PTR(err));
+               return err;
+       }
+
+       err = regulator_bulk_enable(onboard_dev->pdata->num_supplies,
+                                   onboard_dev->supplies);
+       if (err) {
+               dev_err(onboard_dev->dev, "failed to enable supplies: %pe\n",
+                       ERR_PTR(err));
+               goto disable_clk;
+       }
+
+       udelay(onboard_dev->pdata->reset_us);
+       gpiod_set_value_cansleep(onboard_dev->reset_gpio, 0);
+       udelay(onboard_dev->pdata->power_on_delay_us);
+
+       return 0;
+
+disable_clk:
+       clk_disable_unprepare(onboard_dev->clk);
+       return err;
+}
+
+static int onboard_dev_power_off(struct onboard_dev *onboard_dev)
+{
+       int err;
+
+       gpiod_set_value_cansleep(onboard_dev->reset_gpio, 1);
+
+       err = regulator_bulk_disable(onboard_dev->pdata->num_supplies,
+                                    onboard_dev->supplies);
+       if (err) {
+               dev_err(onboard_dev->dev, "failed to disable supplies: %pe\n",
+                       ERR_PTR(err));
+               return err;
+       }
+
+       clk_disable_unprepare(onboard_dev->clk);
+
+       return 0;
+}
+
+#if IS_ENABLED(CONFIG_USB_ONBOARD_DEV_USB5744)
+static int onboard_dev_5744_i2c_read_byte(struct i2c_client *client, u16 addr, 
u8 *data)
+{
+       struct i2c_msg msg[2];
+       u8 rd_buf[3];
+       int ret;
+
+       u8 wr_buf[7] = {0, USB5744_CREG_MEM_ADDR, 4,
+                       USB5744_CREG_READ, 1,
+                       addr >> 8 & 0xff,
+                       addr & 0xff};
+       msg[0].addr = client->addr;
+       msg[0].flags = 0;
+       msg[0].len = sizeof(wr_buf);
+       msg[0].buf = wr_buf;
+
+       ret = i2c_transfer(client->adapter, msg, 1);
+       if (ret < 0)
+               return ret;
+
+       wr_buf[0] = USB5744_CMD_CREG_ACCESS;
+       wr_buf[1] = USB5744_CMD_CREG_ACCESS_LSB;
+       wr_buf[2] = 0;
+       msg[0].len = 3;
+
+       ret = i2c_transfer(client->adapter, msg, 1);
+       if (ret < 0)
+               return ret;
+
+       wr_buf[0] = 0;
+       wr_buf[1] = USB5744_CREG_MEM_RD_ADDR;
+       msg[0].len = 2;
+
+       msg[1].addr = client->addr;
+       msg[1].flags = I2C_M_RD;
+       msg[1].len = 2;
+       msg[1].buf = rd_buf;
+
+       ret = i2c_transfer(client->adapter, msg, 2);
+       if (ret < 0)
+               return ret;
+       *data = rd_buf[1];
+
+       return 0;
+}
+
+static int onboard_dev_5744_i2c_write_byte(struct i2c_client *client, u16 
addr, u8 data)
+{
+       struct i2c_msg msg[2];
+       int ret;
+
+       u8 wr_buf[8] = {0, USB5744_CREG_MEM_ADDR, 5,
+                       USB5744_CREG_WRITE, 1,
+                       addr >> 8 & 0xff,
+                       addr & 0xff,
+                       data};
+       msg[0].addr = client->addr;
+       msg[0].flags = 0;
+       msg[0].len = sizeof(wr_buf);
+       msg[0].buf = wr_buf;
+
+       ret = i2c_transfer(client->adapter, msg, 1);
+       if (ret < 0)
+               return ret;
+
+       msg[0].len = 3;
+       wr_buf[0] = USB5744_CMD_CREG_ACCESS;
+       wr_buf[1] = USB5744_CMD_CREG_ACCESS_LSB;
+       wr_buf[2] = 0;
+
+       ret = i2c_transfer(client->adapter, msg, 1);
+       if (ret < 0)
+               return ret;
+
+       return 0;
+}
+
+static int onboard_dev_5744_i2c_init(struct i2c_client *client)
+{
+       struct device *dev = &client->dev;
+       int ret;
+       u8 reg;
+
+       /*
+        * Set BYPASS_UDC_SUSPEND bit to ensure MCU is always enabled
+        * and ready to respond to SMBus runtime commands.
+        * The command writes 5 bytes to memory and single data byte in
+        * configuration register.
+        */
+       ret = onboard_dev_5744_i2c_read_byte(client,
+                                            USB5744_CREG_RUNTIMEFLAGS2, &reg);
+       if (ret)
+               return dev_err_probe(dev, ret, "CREG_RUNTIMEFLAGS2 read 
failed\n");
+
+       reg |= USB5744_CREG_BYPASS_UDC_SUSPEND;
+       ret = onboard_dev_5744_i2c_write_byte(client,
+                                             USB5744_CREG_RUNTIMEFLAGS2, reg);
+       if (ret)
+               return dev_err_probe(dev, ret, "BYPASS_UDC_SUSPEND bit 
configuration failed\n");
+
+       /* Send SMBus command to boot hub. */
+       ret = i2c_smbus_write_word_data(client, USB5744_CMD_ATTACH,
+                                       USB5744_CMD_ATTACH_LSB);
+       if (ret < 0)
+               return dev_err_probe(dev, ret, "USB Attach with SMBus command 
failed\n");
+
+       return ret;
+}
+#else
+static int onboard_dev_5744_i2c_init(struct i2c_client *client)
+{
+       return -ENODEV;
+}
+#endif
+
+static int onboard_dev_probe(struct device *dev)
+{
+       struct onboard_dev *onboard_dev;
+       struct device_node *i2c_node;
+       struct device_node *peer_node;
+       struct device *peer_dev;
+       int err;
+
+       /* the USB 2 and USB 3 halves of one hub share reset and supplies */
+       peer_node = of_parse_phandle(dev->of_node, "peer-hub", 0);
+       if (peer_node) {
+               peer_dev = of_find_device_by_node(peer_node);
+               if (peer_dev && dev_get_drvdata(peer_dev))
+                       return 0;
+       }
+
+       onboard_dev = devm_kzalloc(dev, sizeof(*onboard_dev), GFP_KERNEL);
+       if (!onboard_dev)
+               return -ENOMEM;
+
+       onboard_dev->pdata = device_get_match_data(dev);
+       if (!onboard_dev->pdata)
+               return -EINVAL;
+
+       onboard_dev->dev = dev;
+
+       err = onboard_dev_get_regulators(onboard_dev);
+       if (err)
+               return err;
+
+       onboard_dev->clk = clk_get_optional(dev, NULL);
+       if (IS_ERR(onboard_dev->clk))
+               return dev_err_probe(dev, PTR_ERR(onboard_dev->clk),
+                                    "failed to get clock\n");
+
+       onboard_dev->reset_gpio = gpiod_get_optional(dev, "reset",
+                                                    GPIOD_OUT_HIGH);
+       if (IS_ERR(onboard_dev->reset_gpio))
+               return dev_err_probe(dev, PTR_ERR(onboard_dev->reset_gpio),
+                                    "failed to get reset GPIO\n");
+
+       dev_set_drvdata(dev, onboard_dev);
+
+       err = onboard_dev_power_on(onboard_dev);
+       if (err)
+               return err;
+
+       i2c_node = of_parse_phandle(dev->of_node, "i2c-bus", 0);
+       if (i2c_node) {
+               struct i2c_client *client = NULL;
+
+#if IS_ENABLED(CONFIG_USB_ONBOARD_DEV_USB5744)
+               client = of_find_i2c_device_by_node(i2c_node);
+#endif
+               of_node_put(i2c_node);
+
+               if (!client) {
+                       err = -EPROBE_DEFER;
+                       goto err_power_off;
+               }
+
+               if (of_device_is_compatible(dev->of_node, "usb424,2744") ||
+                   of_device_is_compatible(dev->of_node, "usb424,5744")) {
+                       err = onboard_dev_5744_i2c_init(client);
+               }
+
+               put_device(&client->dev);
+               if (err < 0)
+                       goto err_power_off;
+       }
+
+       return 0;
+
+err_power_off:
+       onboard_dev_power_off(onboard_dev);
+       return err;
+}
+
+MODULE_DEVICE_TABLE(of, onboard_dev_match);
+
+static struct driver onboard_dev_driver = {
+       .probe = onboard_dev_probe,
+       .name = "onboard-usb-dev",
+       .of_match_table = onboard_dev_match,
+};
+device_platform_driver(onboard_dev_driver);
+
 void of_usb_host_probe_devs(struct usb_host *host)
 {
        struct device_node *np;
@@ -28,71 +332,6 @@ void of_usb_host_probe_devs(struct usb_host *host)
        of_platform_populate(np, onboard_dev_match, host->hw_dev);
 }
 
-struct onboard_dev {
-       struct regulator *vdd;
-       struct device *dev;
-       const struct onboard_dev_pdata *pdata;
-       struct gpio_desc *reset_gpio;
-};
-
-static int onboard_dev_power_on(struct onboard_dev *onboard_dev)
-{
-       int err;
-
-       err = regulator_enable(onboard_dev->vdd);
-       if (err) {
-               dev_err(onboard_dev->dev, "failed to enable regulator: %pe\n",
-                       ERR_PTR(err));
-               return err;
-       }
-
-       udelay(onboard_dev->pdata->reset_us);
-       gpiod_set_value(onboard_dev->reset_gpio, 0);
-
-       return 0;
-}
-
-static int onboard_dev_probe(struct device *dev)
-{
-       struct device_node *peer_node;
-       struct device *peer_dev;
-       struct onboard_dev *onboard_dev;
-
-       peer_node = of_parse_phandle(dev->of_node, "peer-hub", 0);
-       if (peer_node) {
-               peer_dev = of_find_device_by_node(peer_node);
-               if (peer_dev && peer_dev->priv)
-                       return 0;
-       }
-
-       onboard_dev = xzalloc(sizeof(*onboard_dev));
-
-       onboard_dev->pdata = device_get_match_data(dev);
-       if (!onboard_dev->pdata)
-               return -EINVAL;
-
-       onboard_dev->vdd = regulator_get(dev, "vdd");
-       if (IS_ERR(onboard_dev->vdd))
-               return PTR_ERR(onboard_dev->vdd);
-
-       onboard_dev->reset_gpio = gpiod_get_optional(dev, "reset", 
GPIOD_OUT_HIGH);
-       if (IS_ERR(onboard_dev->reset_gpio))
-               return dev_errp_probe(dev, onboard_dev->reset_gpio,
-                                    "failed to get reset GPIO\n");
-
-       onboard_dev->dev = dev;
-       dev->priv = onboard_dev;
-
-       return onboard_dev_power_on(onboard_dev);
-}
-
-static struct driver onboard_dev_driver = {
-       .name = "onboard-usb-dev",
-       .probe = onboard_dev_probe,
-       .of_compatible = onboard_dev_match,
-};
-device_platform_driver(onboard_dev_driver);
-
 MODULE_AUTHOR("Matthias Kaehlcke <[email protected]>");
 MODULE_DESCRIPTION("Driver for discrete onboard USB devices");
 MODULE_LICENSE("GPL v2");
diff --git a/drivers/usb/misc/onboard_usb_dev.h 
b/drivers/usb/misc/onboard_usb_dev.h
index edb91485bd83..4adb17867f76 100644
--- a/drivers/usb/misc/onboard_usb_dev.h
+++ b/drivers/usb/misc/onboard_usb_dev.h
@@ -1,4 +1,5 @@
 /* SPDX-License-Identifier: GPL-2.0+ */
+/* SPDX-Comment: Origin-URL: 
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/drivers/usb/misc/onboard_usb_dev.h?id=9a71ac508974d44d42d358f42e6a766ec67a73d1
 */
 /*
  * Copyright (c) 2022, Google LLC
  */
@@ -6,50 +7,171 @@
 #ifndef _USB_MISC_ONBOARD_USB_DEV_H
 #define _USB_MISC_ONBOARD_USB_DEV_H
 
+#define MAX_SUPPLIES 2
+
 struct onboard_dev_pdata {
        unsigned long reset_us;         /* reset pulse width in us */
+       unsigned long power_on_delay_us; /* power on delay in us */
+       unsigned int num_supplies;      /* number of supplies */
+       const char * const supply_names[MAX_SUPPLIES];
+       bool is_hub;
 };
 
 static const struct onboard_dev_pdata microchip_usb424_data = {
        .reset_us = 1,
+       .num_supplies = 1,
+       .supply_names = { "vdd" },
+       .is_hub = true,
+};
+
+static const struct onboard_dev_pdata microchip_usb2514_data = {
+       .reset_us = 1,
+       .num_supplies = 2,
+       .supply_names = { "vdd", "vdda" },
+       .is_hub = true,
+};
+
+static const struct onboard_dev_pdata microchip_usb5744_data = {
+       .reset_us = 0,
+       .power_on_delay_us = 10000,
+       .num_supplies = 2,
+       .supply_names = { "vdd", "vdd2" },
+       .is_hub = true,
+};
+
+static const struct onboard_dev_pdata parade_ps5511_data = {
+       .reset_us = 500,
+       .num_supplies = 2,
+       .supply_names = { "vddd11", "vdd33"},
+       .is_hub = true,
 };
 
 static const struct onboard_dev_pdata realtek_rts5411_data = {
        .reset_us = 0,
+       .num_supplies = 1,
+       .supply_names = { "vdd" },
+       .is_hub = true,
 };
 
-static const struct onboard_dev_pdata ti_tusb8041_data = {
+static const struct onboard_dev_pdata realtek_rtl8188etv_data = {
+       .reset_us = 0,
+       .num_supplies = 1,
+       .supply_names = { "vdd" },
+       .is_hub = false,
+};
+
+static const struct onboard_dev_pdata ti_tusb8020b_data = {
        .reset_us = 3000,
+       .num_supplies = 1,
+       .supply_names = { "vdd" },
+       .is_hub = true,
+};
+
+static const struct onboard_dev_pdata bison_intcamera_data = {
+       .reset_us = 1000,
+       .num_supplies = 1,
+       .supply_names = { "vdd" },
+       .is_hub = false,
+};
+
+static const struct onboard_dev_pdata corechips_sl6341_data = {
+       .reset_us = 10000,
+       .num_supplies = 2,
+       .supply_names = { "vdd1v1", "vdd3v3" },
+       .is_hub = true,
+};
+
+static const struct onboard_dev_pdata cypress_hx3_data = {
+       .reset_us = 10000,
+       .num_supplies = 2,
+       .supply_names = { "vdd", "vdd2" },
+       .is_hub = true,
 };
 
 static const struct onboard_dev_pdata genesys_gl850g_data = {
        .reset_us = 3,
+       .num_supplies = 1,
+       .supply_names = { "vdd" },
+       .is_hub = true,
 };
 
 static const struct onboard_dev_pdata genesys_gl852g_data = {
        .reset_us = 50,
+       .num_supplies = 1,
+       .supply_names = { "vdd" },
+       .is_hub = true,
+};
+
+static const struct onboard_dev_pdata genesys_gl3590_data = {
+       .reset_us = 50,
+       .num_supplies = 2,
+       .supply_names = { "vdd", "vdd12" },
+       .is_hub = true,
+};
+
+static const struct onboard_dev_pdata usb_a_conn_data = {
+       .num_supplies = 1,
+       .supply_names = { "vbus" },
 };
 
 static const struct onboard_dev_pdata vialab_vl817_data = {
        .reset_us = 10,
+       .num_supplies = 1,
+       .supply_names = { "vdd" },
+       .is_hub = true,
+};
+
+static const struct onboard_dev_pdata wch_ch334_data = {
+       .reset_us = 14000,
+       .num_supplies = 2,
+       .supply_names = { "vdd33", "v5" },
+       .is_hub = true,
+};
+
+static const struct onboard_dev_pdata xmos_xvf3500_data = {
+       .reset_us = 1,
+       .num_supplies = 2,
+       .supply_names = { "vdd", "vddio" },
+       .is_hub = false,
 };
 
 static const struct of_device_id onboard_dev_match[] = {
-       { .compatible = "usb424,2514", .data = &microchip_usb424_data, },
+       { .compatible = "usb-a-connector", .data = &usb_a_conn_data, },
+       { .compatible = "usb424,2412", .data = &microchip_usb424_data, },
+       { .compatible = "usb424,2514", .data = &microchip_usb2514_data, },
        { .compatible = "usb424,2517", .data = &microchip_usb424_data, },
-       { .compatible = "usb451,8140", .data = &ti_tusb8041_data, },
-       { .compatible = "usb451,8142", .data = &ti_tusb8041_data, },
+       { .compatible = "usb424,2744", .data = &microchip_usb5744_data, },
+       { .compatible = "usb424,5744", .data = &microchip_usb5744_data, },
+       { .compatible = "usb451,8025", .data = &ti_tusb8020b_data, },
+       { .compatible = "usb451,8027", .data = &ti_tusb8020b_data, },
+       { .compatible = "usb451,8140", .data = &ti_tusb8020b_data, },
+       { .compatible = "usb451,8142", .data = &ti_tusb8020b_data, },
+       { .compatible = "usb451,8440", .data = &ti_tusb8020b_data, },
+       { .compatible = "usb451,8442", .data = &ti_tusb8020b_data, },
+       { .compatible = "usb4b4,6504", .data = &cypress_hx3_data, },
+       { .compatible = "usb4b4,6506", .data = &cypress_hx3_data, },
+       { .compatible = "usb4b4,6570", .data = &microchip_usb424_data, },
        { .compatible = "usb5e3,608", .data = &genesys_gl850g_data, },
        { .compatible = "usb5e3,610", .data = &genesys_gl852g_data, },
        { .compatible = "usb5e3,620", .data = &genesys_gl852g_data, },
+       { .compatible = "usb5e3,625", .data = &genesys_gl3590_data, },
+       { .compatible = "usb5e3,626", .data = &genesys_gl852g_data, },
+       { .compatible = "usbbda,179", .data = &realtek_rtl8188etv_data, },
        { .compatible = "usbbda,411", .data = &realtek_rts5411_data, },
        { .compatible = "usbbda,5411", .data = &realtek_rts5411_data, },
        { .compatible = "usbbda,414", .data = &realtek_rts5411_data, },
        { .compatible = "usbbda,5414", .data = &realtek_rts5411_data, },
+       { .compatible = "usb1a40,0101", .data = &vialab_vl817_data, },
+       { .compatible = "usb1a86,8091", .data = &wch_ch334_data, },
+       { .compatible = "usb1da0,5511", .data = &parade_ps5511_data, },
+       { .compatible = "usb1da0,55a1", .data = &parade_ps5511_data, },
        { .compatible = "usb2109,817", .data = &vialab_vl817_data, },
        { .compatible = "usb2109,2817", .data = &vialab_vl817_data, },
+       { .compatible = "usb20b1,0013", .data = &xmos_xvf3500_data, },
+       { .compatible = "usb3431,6241", .data = &corechips_sl6341_data, },
+       { .compatible = "usb3431,6341", .data = &corechips_sl6341_data, },
+       { .compatible = "usb5986,1198", .data = &bison_intcamera_data, },
        {}
 };
-MODULE_DEVICE_TABLE(of, onboard_dev_match);
 
 #endif /* _USB_MISC_ONBOARD_USB_DEV_H */
-- 
2.47.3


Reply via email to