// SPDX-License-Identifier: GPL-2.0-only/* * Driver for onboard USB devices * * Copyright (c) 2022, Google LLC */ #include <linux/clk.h>#include <linux/device.h>#include <linux/export.h>#include <linux/err.h>#include <linux/gpio/consumer.h>#include <linux/init.h>#include <linux/i2c.h>#include <linux/kernel.h>#include <linux/list.h>#include <linux/module.h>#include <linux/mutex.h>#include <linux/of.h>#include <linux/of_platform.h>#include <linux/platform_device.h>#include <linux/regulator/consumer.h>#include <linux/slab.h>#include <linux/suspend.h>#include <linux/sysfs.h>#include <linux/usb.h>#include <linux/usb/hcd.h>#include <linux/usb/onboard_dev.h>#include <linux/workqueue.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) static void onboard_dev_attach_usb_driver(struct work_struct *work); static struct usb_device_driver onboard_dev_usbdev_driver;static DECLARE_WORK(attach_usb_driver_work, onboard_dev_attach_usb_driver); /************************** Platform driver **************************/ struct usbdev_node { struct usb_device *udev; struct list_head list;}; struct onboard_dev { struct regulator_bulk_data supplies[MAX_SUPPLIES]; struct device *dev; const struct onboard_dev_pdata *pdata; struct gpio_desc *reset_gpio; bool always_powered_in_suspend; bool is_powered_on; bool going_away; struct list_head udev_list; struct mutex lock; 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 = devm_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; } fsleep(onboard_dev->pdata->reset_us); gpiod_set_value_cansleep(onboard_dev->reset_gpio, 0); fsleep(onboard_dev->pdata->power_on_delay_us); onboard_dev->is_powered_on = true; 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); onboard_dev->is_powered_on = false; return 0;} static int __maybe_unused onboard_dev_suspend(struct device *dev){ struct onboard_dev *onboard_dev = dev_get_drvdata(dev); struct usbdev_node *node; bool power_off = true; if (onboard_dev->always_powered_in_suspend) return 0; mutex_lock(&onboard_dev->lock); list_for_each_entry(node, &onboard_dev->udev_list, list) { if (!device_may_wakeup(node->udev->bus->controller)) continue; if (usb_wakeup_enabled_descendants(node->udev)) { power_off = false; break; } } mutex_unlock(&onboard_dev->lock); if (!power_off) return 0; return onboard_dev_power_off(onboard_dev);} static int __maybe_unused onboard_dev_resume(struct device *dev){ struct onboard_dev *onboard_dev = dev_get_drvdata(dev); if (onboard_dev->is_powered_on) return 0; return onboard_dev_power_on(onboard_dev);} static inline void get_udev_link_name(const struct usb_device *udev, char *buf, size_t size){ snprintf(buf, size, "usb_dev.%s", dev_name(&udev->dev));} static int onboard_dev_add_usbdev(struct onboard_dev *onboard_dev, struct usb_device *udev){ struct usbdev_node *node; char link_name[64]; int err; mutex_lock(&onboard_dev->lock); if (onboard_dev->going_away) { err = -EINVAL; goto error; } node = kzalloc_obj(*node); if (!node) { err = -ENOMEM; goto error; } node->udev = udev; list_add(&node->list, &onboard_dev->udev_list); mutex_unlock(&onboard_dev->lock); get_udev_link_name(udev, link_name, sizeof(link_name)); WARN_ON(sysfs_create_link(&onboard_dev->dev->kobj, &udev->dev.kobj, link_name)); return 0; error: mutex_unlock(&onboard_dev->lock); return err;} static void onboard_dev_remove_usbdev(struct onboard_dev *onboard_dev, const struct usb_device *udev){ struct usbdev_node *node; char link_name[64]; get_udev_link_name(udev, link_name, sizeof(link_name)); sysfs_remove_link(&onboard_dev->dev->kobj, link_name); mutex_lock(&onboard_dev->lock); list_for_each_entry(node, &onboard_dev->udev_list, list) { if (node->udev == udev) { list_del(&node->list); kfree(node); break; } } mutex_unlock(&onboard_dev->lock);} static ssize_t always_powered_in_suspend_show(struct device *dev, struct device_attribute *attr, char *buf){ const struct onboard_dev *onboard_dev = dev_get_drvdata(dev); return sysfs_emit(buf, "%d\n", onboard_dev->always_powered_in_suspend);} static ssize_t always_powered_in_suspend_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count){ struct onboard_dev *onboard_dev = dev_get_drvdata(dev); bool val; int ret; ret = kstrtobool(buf, &val); if (ret < 0) return ret; onboard_dev->always_powered_in_suspend = val; return count;}static DEVICE_ATTR_RW(always_powered_in_suspend); static struct attribute *onboard_dev_attrs[] = { &dev_attr_always_powered_in_suspend.attr, NULL,}; static umode_t onboard_dev_attrs_are_visible(struct kobject *kobj, struct attribute *attr, int n){ struct device *dev = kobj_to_dev(kobj); struct onboard_dev *onboard_dev = dev_get_drvdata(dev); if (attr == &dev_attr_always_powered_in_suspend.attr && !onboard_dev->pdata->is_hub) return 0; return attr->mode;} static const struct attribute_group onboard_dev_group = { .is_visible = onboard_dev_attrs_are_visible, .attrs = onboard_dev_attrs,};__ATTRIBUTE_GROUPS(onboard_dev); static void onboard_dev_attach_usb_driver(struct work_struct *work){ int err; err = driver_attach(&onboard_dev_usbdev_driver.driver); if (err) pr_err("Failed to attach USB driver: %pe\n", ERR_PTR(err));} #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, ®); 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;}#elsestatic int onboard_dev_5744_i2c_init(struct i2c_client *client){ return -ENODEV;}#endif static int onboard_dev_probe(struct platform_device *pdev){ struct device *dev = &pdev->dev; struct onboard_dev *onboard_dev; struct device_node *i2c_node; int err; 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; if (!onboard_dev->pdata->is_hub) onboard_dev->always_powered_in_suspend = true; onboard_dev->dev = dev; err = onboard_dev_get_regulators(onboard_dev); if (err) return err; onboard_dev->clk = devm_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 = devm_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"); mutex_init(&onboard_dev->lock); INIT_LIST_HEAD(&onboard_dev->udev_list); dev_set_drvdata(dev, onboard_dev); err = onboard_dev_power_on(onboard_dev); if (err) return err; i2c_node = of_parse_phandle(pdev->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(pdev->dev.of_node, "usb424,2744") || of_device_is_compatible(pdev->dev.of_node, "usb424,5744")) { err = onboard_dev_5744_i2c_init(client); onboard_dev->always_powered_in_suspend = true; } put_device(&client->dev); if (err < 0) goto err_power_off; } /* * The USB driver might have been detached from the USB devices by * onboard_dev_remove() (e.g. through an 'unbind' by userspace), * make sure to re-attach it if needed.Lines 1–500 of 732. Load more
// SPDX-License-Identifier: GPL-2.0-only /* * Driver for onboard USB devices * * Copyright (c) 2022, Google LLC */ #include <linux/clk.h> #include <linux/device.h> #include <linux/export.h> #include <linux/err.h> #include <linux/gpio/consumer.h> #include <linux/init.h> #include <linux/i2c.h> #include <linux/kernel.h> #include <linux/list.h> #include <linux/module.h> #include <linux/mutex.h> #include <linux/of.h> #include <linux/of_platform.h> #include <linux/platform_device.h> #include <linux/regulator/consumer.h> #include <linux/slab.h> #include <linux/suspend.h> #include <linux/sysfs.h> #include <linux/usb.h> #include <linux/usb/hcd.h> #include <linux/usb/onboard_dev.h> #include <linux/workqueue.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) static void onboard_dev_attach_usb_driver(struct work_struct *work); static struct usb_device_driver onboard_dev_usbdev_driver; static DECLARE_WORK(attach_usb_driver_work, onboard_dev_attach_usb_driver); /************************** Platform driver **************************/ struct usbdev_node { struct usb_device *udev; struct list_head list; }; struct onboard_dev { struct regulator_bulk_data supplies[MAX_SUPPLIES]; struct device *dev; const struct onboard_dev_pdata *pdata; struct gpio_desc *reset_gpio; bool always_powered_in_suspend; bool is_powered_on; bool going_away; struct list_head udev_list; struct mutex lock; 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 = devm_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; } fsleep(onboard_dev->pdata->reset_us); gpiod_set_value_cansleep(onboard_dev->reset_gpio, 0); fsleep(onboard_dev->pdata->power_on_delay_us); onboard_dev->is_powered_on = true; 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); onboard_dev->is_powered_on = false; return 0; } static int __maybe_unused onboard_dev_suspend(struct device *dev) { struct onboard_dev *onboard_dev = dev_get_drvdata(dev); struct usbdev_node *node; bool power_off = true; if (onboard_dev->always_powered_in_suspend) return 0; mutex_lock(&onboard_dev->lock); list_for_each_entry(node, &onboard_dev->udev_list, list) { if (!device_may_wakeup(node->udev->bus->controller)) continue; if (usb_wakeup_enabled_descendants(node->udev)) { power_off = false; break; } } mutex_unlock(&onboard_dev->lock); if (!power_off) return 0; return onboard_dev_power_off(onboard_dev); } static int __maybe_unused onboard_dev_resume(struct device *dev) { struct onboard_dev *onboard_dev = dev_get_drvdata(dev); if (onboard_dev->is_powered_on) return 0; return onboard_dev_power_on(onboard_dev); } static inline void get_udev_link_name(const struct usb_device *udev, char *buf, size_t size) { snprintf(buf, size, "usb_dev.%s", dev_name(&udev->dev)); } static int onboard_dev_add_usbdev(struct onboard_dev *onboard_dev, struct usb_device *udev) { struct usbdev_node *node; char link_name[64]; int err; mutex_lock(&onboard_dev->lock); if (onboard_dev->going_away) { err = -EINVAL; goto error; } node = kzalloc_obj(*node); if (!node) { err = -ENOMEM; goto error; } node->udev = udev; list_add(&node->list, &onboard_dev->udev_list); mutex_unlock(&onboard_dev->lock); get_udev_link_name(udev, link_name, sizeof(link_name)); WARN_ON(sysfs_create_link(&onboard_dev->dev->kobj, &udev->dev.kobj, link_name)); return 0; error: mutex_unlock(&onboard_dev->lock); return err; } static void onboard_dev_remove_usbdev(struct onboard_dev *onboard_dev, const struct usb_device *udev) { struct usbdev_node *node; char link_name[64]; get_udev_link_name(udev, link_name, sizeof(link_name)); sysfs_remove_link(&onboard_dev->dev->kobj, link_name); mutex_lock(&onboard_dev->lock); list_for_each_entry(node, &onboard_dev->udev_list, list) { if (node->udev == udev) { list_del(&node->list); kfree(node); break; } } mutex_unlock(&onboard_dev->lock); } static ssize_t always_powered_in_suspend_show(struct device *dev, struct device_attribute *attr, char *buf) { const struct onboard_dev *onboard_dev = dev_get_drvdata(dev); return sysfs_emit(buf, "%d\n", onboard_dev->always_powered_in_suspend); } static ssize_t always_powered_in_suspend_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct onboard_dev *onboard_dev = dev_get_drvdata(dev); bool val; int ret; ret = kstrtobool(buf, &val); if (ret < 0) return ret; onboard_dev->always_powered_in_suspend = val; return count; } static DEVICE_ATTR_RW(always_powered_in_suspend); static struct attribute *onboard_dev_attrs[] = { &dev_attr_always_powered_in_suspend.attr, NULL, }; static umode_t onboard_dev_attrs_are_visible(struct kobject *kobj, struct attribute *attr, int n) { struct device *dev = kobj_to_dev(kobj); struct onboard_dev *onboard_dev = dev_get_drvdata(dev); if (attr == &dev_attr_always_powered_in_suspend.attr && !onboard_dev->pdata->is_hub) return 0; return attr->mode; } static const struct attribute_group onboard_dev_group = { .is_visible = onboard_dev_attrs_are_visible, .attrs = onboard_dev_attrs, }; __ATTRIBUTE_GROUPS(onboard_dev); static void onboard_dev_attach_usb_driver(struct work_struct *work) { int err; err = driver_attach(&onboard_dev_usbdev_driver.driver); if (err) pr_err("Failed to attach USB driver: %pe\n", ERR_PTR(err)); } #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, ®); 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 platform_device *pdev) { struct device *dev = &pdev->dev; struct onboard_dev *onboard_dev; struct device_node *i2c_node; int err; 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; if (!onboard_dev->pdata->is_hub) onboard_dev->always_powered_in_suspend = true; onboard_dev->dev = dev; err = onboard_dev_get_regulators(onboard_dev); if (err) return err; onboard_dev->clk = devm_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 = devm_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"); mutex_init(&onboard_dev->lock); INIT_LIST_HEAD(&onboard_dev->udev_list); dev_set_drvdata(dev, onboard_dev); err = onboard_dev_power_on(onboard_dev); if (err) return err; i2c_node = of_parse_phandle(pdev->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(pdev->dev.of_node, "usb424,2744") || of_device_is_compatible(pdev->dev.of_node, "usb424,5744")) { err = onboard_dev_5744_i2c_init(client); onboard_dev->always_powered_in_suspend = true; } put_device(&client->dev); if (err < 0) goto err_power_off; } /* * The USB driver might have been detached from the USB devices by * onboard_dev_remove() (e.g. through an 'unbind' by userspace), * make sure to re-attach it if needed.