diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2019-09-18 10:33:46 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2019-09-18 10:33:46 -0700 |
commit | c6b48dad92aedaa9bdc013ee495cb5b1bbdf1f11 (patch) | |
tree | 8d0bbf19d75fc1bf546ed1b05b560ea2df54689e /drivers/usb/chipidea/core.c | |
parent | 1f7d290a7275edb270dbee13212c37cb59940221 (diff) | |
parent | fb9617edf6c0e1b86a6595cd92dd3f84595221d9 (diff) |
Merge tag 'usb-5.4-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb
Pull USB updates from Greg KH:
"Here is the big set of USB patches for 5.4-rc1.
Two major chunks of code are moving out of the tree and into the
staging directory, uwb and wusb (wireless USB support), because there
are no devices that actually use this protocol anymore, and what we
have today probably doesn't work at all given that the maintainers
left many many years ago. So move it to staging where it will be
removed in a few releases if no one screams.
Other than that, lots of little things. The usual gadget and xhci and
usb serial driver updates, along with a bunch of sysfs file cleanups
due to the driver core changes to support that. Nothing really major,
just constant forward progress.
All of these have been in linux-next for a while with no reported
issues"
* tag 'usb-5.4-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb: (159 commits)
USB: usbcore: Fix slab-out-of-bounds bug during device reset
usb: cdns3: Remove redundant dev_err call in cdns3_probe()
USB: rio500: Fix lockdep violation
USB: rio500: simplify locking
usb: mtu3: register a USB Role Switch for dual role mode
usb: common: add USB GPIO based connection detection driver
usb: common: create Kconfig file
usb: roles: get usb-role-switch from parent
usb: roles: Add fwnode_usb_role_switch_get() function
device connection: Add fwnode_connection_find_match()
usb: roles: Introduce stubs for the exiting functions in role.h
dt-bindings: usb: mtu3: add properties about USB Role Switch
dt-bindings: usb: add binding for USB GPIO based connection detection driver
dt-bindings: connector: add optional properties for Type-B
dt-binding: usb: add usb-role-switch property
usbip: Implement SG support to vhci-hcd and stub driver
usb: roles: intel: Enable static DRD mode for role switch
xhci-ext-caps.c: Add property to disable Intel SW switch
usb: dwc3: remove generic PHY calibrate() calls
usb: core: phy: add support for PHY calibration
...
Diffstat (limited to 'drivers/usb/chipidea/core.c')
-rw-r--r-- | drivers/usb/chipidea/core.c | 97 |
1 files changed, 85 insertions, 12 deletions
diff --git a/drivers/usb/chipidea/core.c b/drivers/usb/chipidea/core.c index 26062d610c20..98ee575ee500 100644 --- a/drivers/usb/chipidea/core.c +++ b/drivers/usb/chipidea/core.c @@ -600,6 +600,71 @@ static int ci_cable_notifier(struct notifier_block *nb, unsigned long event, return NOTIFY_DONE; } +static enum usb_role ci_usb_role_switch_get(struct device *dev) +{ + struct ci_hdrc *ci = dev_get_drvdata(dev); + enum usb_role role; + unsigned long flags; + + spin_lock_irqsave(&ci->lock, flags); + role = ci_role_to_usb_role(ci); + spin_unlock_irqrestore(&ci->lock, flags); + + return role; +} + +static int ci_usb_role_switch_set(struct device *dev, enum usb_role role) +{ + struct ci_hdrc *ci = dev_get_drvdata(dev); + struct ci_hdrc_cable *cable = NULL; + enum usb_role current_role = ci_role_to_usb_role(ci); + unsigned long flags; + + if (current_role == role) + return 0; + + pm_runtime_get_sync(ci->dev); + /* Stop current role */ + spin_lock_irqsave(&ci->lock, flags); + if (current_role == USB_ROLE_DEVICE) + cable = &ci->platdata->vbus_extcon; + else if (current_role == USB_ROLE_HOST) + cable = &ci->platdata->id_extcon; + + if (cable) { + cable->changed = true; + cable->connected = false; + ci_irq(ci->irq, ci); + spin_unlock_irqrestore(&ci->lock, flags); + if (ci->wq && role != USB_ROLE_NONE) + flush_workqueue(ci->wq); + spin_lock_irqsave(&ci->lock, flags); + } + + cable = NULL; + + /* Start target role */ + if (role == USB_ROLE_DEVICE) + cable = &ci->platdata->vbus_extcon; + else if (role == USB_ROLE_HOST) + cable = &ci->platdata->id_extcon; + + if (cable) { + cable->changed = true; + cable->connected = true; + ci_irq(ci->irq, ci); + } + spin_unlock_irqrestore(&ci->lock, flags); + pm_runtime_put_sync(ci->dev); + + return 0; +} + +static struct usb_role_switch_desc ci_role_switch = { + .set = ci_usb_role_switch_set, + .get = ci_usb_role_switch_get, +}; + static int ci_get_platdata(struct device *dev, struct ci_hdrc_platform_data *platdata) { @@ -726,6 +791,9 @@ static int ci_get_platdata(struct device *dev, cable->connected = false; } + if (device_property_read_bool(dev, "usb-role-switch")) + ci_role_switch.fwnode = dev->fwnode; + platdata->pctl = devm_pinctrl_get(dev); if (!IS_ERR(platdata->pctl)) { struct pinctrl_state *p; @@ -903,10 +971,7 @@ static struct attribute *ci_attrs[] = { &dev_attr_role.attr, NULL, }; - -static const struct attribute_group ci_attr_group = { - .attrs = ci_attrs, -}; +ATTRIBUTE_GROUPS(ci); static int ci_hdrc_probe(struct platform_device *pdev) { @@ -1008,7 +1073,6 @@ static int ci_hdrc_probe(struct platform_device *pdev) ci->irq = platform_get_irq(pdev, 0); if (ci->irq < 0) { - dev_err(dev, "missing IRQ\n"); ret = ci->irq; goto deinit_phy; } @@ -1051,6 +1115,15 @@ static int ci_hdrc_probe(struct platform_device *pdev) } } + if (ci_role_switch.fwnode) { + ci->role_switch = usb_role_switch_register(dev, + &ci_role_switch); + if (IS_ERR(ci->role_switch)) { + ret = PTR_ERR(ci->role_switch); + goto deinit_otg; + } + } + if (ci->roles[CI_ROLE_HOST] && ci->roles[CI_ROLE_GADGET]) { if (ci->is_otg) { ci->role = ci_otg_role(ci); @@ -1106,15 +1179,12 @@ static int ci_hdrc_probe(struct platform_device *pdev) device_set_wakeup_capable(&pdev->dev, true); dbg_create_files(ci); - ret = sysfs_create_group(&dev->kobj, &ci_attr_group); - if (ret) - goto remove_debug; - return 0; -remove_debug: - dbg_remove_files(ci); stop: + if (ci->role_switch) + usb_role_switch_unregister(ci->role_switch); +deinit_otg: if (ci->is_otg && ci->roles[CI_ROLE_GADGET]) ci_hdrc_otg_destroy(ci); deinit_gadget: @@ -1133,6 +1203,9 @@ static int ci_hdrc_remove(struct platform_device *pdev) { struct ci_hdrc *ci = platform_get_drvdata(pdev); + if (ci->role_switch) + usb_role_switch_unregister(ci->role_switch); + if (ci->supports_runtime_pm) { pm_runtime_get_sync(&pdev->dev); pm_runtime_disable(&pdev->dev); @@ -1140,7 +1213,6 @@ static int ci_hdrc_remove(struct platform_device *pdev) } dbg_remove_files(ci); - sysfs_remove_group(&ci->dev->kobj, &ci_attr_group); ci_role_destroy(ci); ci_hdrc_enter_lpm(ci, true); ci_usb_phy_exit(ci); @@ -1319,6 +1391,7 @@ static struct platform_driver ci_hdrc_driver = { .driver = { .name = "ci_hdrc", .pm = &ci_pm_ops, + .dev_groups = ci_groups, }, }; |