diff options
Diffstat (limited to 'drivers/usb/core')
-rw-r--r-- | drivers/usb/core/hcd.c | 19 | ||||
-rw-r--r-- | drivers/usb/core/hub.c | 10 | ||||
-rw-r--r-- | drivers/usb/core/phy.c | 93 | ||||
-rw-r--r-- | drivers/usb/core/phy.h | 22 | ||||
-rw-r--r-- | drivers/usb/core/quirks.c | 3 |
5 files changed, 112 insertions, 35 deletions
diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index 777036ae6367..0a42c5df3c0f 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c | |||
@@ -2262,7 +2262,8 @@ int hcd_bus_suspend(struct usb_device *rhdev, pm_message_t msg) | |||
2262 | hcd->state = HC_STATE_SUSPENDED; | 2262 | hcd->state = HC_STATE_SUSPENDED; |
2263 | 2263 | ||
2264 | if (!PMSG_IS_AUTO(msg)) | 2264 | if (!PMSG_IS_AUTO(msg)) |
2265 | usb_phy_roothub_power_off(hcd->phy_roothub); | 2265 | usb_phy_roothub_suspend(hcd->self.sysdev, |
2266 | hcd->phy_roothub); | ||
2266 | 2267 | ||
2267 | /* Did we race with a root-hub wakeup event? */ | 2268 | /* Did we race with a root-hub wakeup event? */ |
2268 | if (rhdev->do_remote_wakeup) { | 2269 | if (rhdev->do_remote_wakeup) { |
@@ -2302,7 +2303,8 @@ int hcd_bus_resume(struct usb_device *rhdev, pm_message_t msg) | |||
2302 | } | 2303 | } |
2303 | 2304 | ||
2304 | if (!PMSG_IS_AUTO(msg)) { | 2305 | if (!PMSG_IS_AUTO(msg)) { |
2305 | status = usb_phy_roothub_power_on(hcd->phy_roothub); | 2306 | status = usb_phy_roothub_resume(hcd->self.sysdev, |
2307 | hcd->phy_roothub); | ||
2306 | if (status) | 2308 | if (status) |
2307 | return status; | 2309 | return status; |
2308 | } | 2310 | } |
@@ -2344,7 +2346,7 @@ int hcd_bus_resume(struct usb_device *rhdev, pm_message_t msg) | |||
2344 | } | 2346 | } |
2345 | } else { | 2347 | } else { |
2346 | hcd->state = old_state; | 2348 | hcd->state = old_state; |
2347 | usb_phy_roothub_power_off(hcd->phy_roothub); | 2349 | usb_phy_roothub_suspend(hcd->self.sysdev, hcd->phy_roothub); |
2348 | dev_dbg(&rhdev->dev, "bus %s fail, err %d\n", | 2350 | dev_dbg(&rhdev->dev, "bus %s fail, err %d\n", |
2349 | "resume", status); | 2351 | "resume", status); |
2350 | if (status != -ESHUTDOWN) | 2352 | if (status != -ESHUTDOWN) |
@@ -2377,6 +2379,7 @@ void usb_hcd_resume_root_hub (struct usb_hcd *hcd) | |||
2377 | 2379 | ||
2378 | spin_lock_irqsave (&hcd_root_hub_lock, flags); | 2380 | spin_lock_irqsave (&hcd_root_hub_lock, flags); |
2379 | if (hcd->rh_registered) { | 2381 | if (hcd->rh_registered) { |
2382 | pm_wakeup_event(&hcd->self.root_hub->dev, 0); | ||
2380 | set_bit(HCD_FLAG_WAKEUP_PENDING, &hcd->flags); | 2383 | set_bit(HCD_FLAG_WAKEUP_PENDING, &hcd->flags); |
2381 | queue_work(pm_wq, &hcd->wakeup_work); | 2384 | queue_work(pm_wq, &hcd->wakeup_work); |
2382 | } | 2385 | } |
@@ -2758,12 +2761,16 @@ int usb_add_hcd(struct usb_hcd *hcd, | |||
2758 | } | 2761 | } |
2759 | 2762 | ||
2760 | if (!hcd->skip_phy_initialization && usb_hcd_is_primary_hcd(hcd)) { | 2763 | if (!hcd->skip_phy_initialization && usb_hcd_is_primary_hcd(hcd)) { |
2761 | hcd->phy_roothub = usb_phy_roothub_init(hcd->self.sysdev); | 2764 | hcd->phy_roothub = usb_phy_roothub_alloc(hcd->self.sysdev); |
2762 | if (IS_ERR(hcd->phy_roothub)) { | 2765 | if (IS_ERR(hcd->phy_roothub)) { |
2763 | retval = PTR_ERR(hcd->phy_roothub); | 2766 | retval = PTR_ERR(hcd->phy_roothub); |
2764 | goto err_phy_roothub_init; | 2767 | goto err_phy_roothub_alloc; |
2765 | } | 2768 | } |
2766 | 2769 | ||
2770 | retval = usb_phy_roothub_init(hcd->phy_roothub); | ||
2771 | if (retval) | ||
2772 | goto err_phy_roothub_alloc; | ||
2773 | |||
2767 | retval = usb_phy_roothub_power_on(hcd->phy_roothub); | 2774 | retval = usb_phy_roothub_power_on(hcd->phy_roothub); |
2768 | if (retval) | 2775 | if (retval) |
2769 | goto err_usb_phy_roothub_power_on; | 2776 | goto err_usb_phy_roothub_power_on; |
@@ -2936,7 +2943,7 @@ err_create_buf: | |||
2936 | usb_phy_roothub_power_off(hcd->phy_roothub); | 2943 | usb_phy_roothub_power_off(hcd->phy_roothub); |
2937 | err_usb_phy_roothub_power_on: | 2944 | err_usb_phy_roothub_power_on: |
2938 | usb_phy_roothub_exit(hcd->phy_roothub); | 2945 | usb_phy_roothub_exit(hcd->phy_roothub); |
2939 | err_phy_roothub_init: | 2946 | err_phy_roothub_alloc: |
2940 | if (hcd->remove_phy && hcd->usb_phy) { | 2947 | if (hcd->remove_phy && hcd->usb_phy) { |
2941 | usb_phy_shutdown(hcd->usb_phy); | 2948 | usb_phy_shutdown(hcd->usb_phy); |
2942 | usb_put_phy(hcd->usb_phy); | 2949 | usb_put_phy(hcd->usb_phy); |
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index f6ea16e9f6bb..aa9968d90a48 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c | |||
@@ -653,12 +653,17 @@ void usb_wakeup_notification(struct usb_device *hdev, | |||
653 | unsigned int portnum) | 653 | unsigned int portnum) |
654 | { | 654 | { |
655 | struct usb_hub *hub; | 655 | struct usb_hub *hub; |
656 | struct usb_port *port_dev; | ||
656 | 657 | ||
657 | if (!hdev) | 658 | if (!hdev) |
658 | return; | 659 | return; |
659 | 660 | ||
660 | hub = usb_hub_to_struct_hub(hdev); | 661 | hub = usb_hub_to_struct_hub(hdev); |
661 | if (hub) { | 662 | if (hub) { |
663 | port_dev = hub->ports[portnum - 1]; | ||
664 | if (port_dev && port_dev->child) | ||
665 | pm_wakeup_event(&port_dev->child->dev, 0); | ||
666 | |||
662 | set_bit(portnum, hub->wakeup_bits); | 667 | set_bit(portnum, hub->wakeup_bits); |
663 | kick_hub_wq(hub); | 668 | kick_hub_wq(hub); |
664 | } | 669 | } |
@@ -3434,8 +3439,11 @@ int usb_port_resume(struct usb_device *udev, pm_message_t msg) | |||
3434 | 3439 | ||
3435 | /* Skip the initial Clear-Suspend step for a remote wakeup */ | 3440 | /* Skip the initial Clear-Suspend step for a remote wakeup */ |
3436 | status = hub_port_status(hub, port1, &portstatus, &portchange); | 3441 | status = hub_port_status(hub, port1, &portstatus, &portchange); |
3437 | if (status == 0 && !port_is_suspended(hub, portstatus)) | 3442 | if (status == 0 && !port_is_suspended(hub, portstatus)) { |
3443 | if (portchange & USB_PORT_STAT_C_SUSPEND) | ||
3444 | pm_wakeup_event(&udev->dev, 0); | ||
3438 | goto SuspendCleared; | 3445 | goto SuspendCleared; |
3446 | } | ||
3439 | 3447 | ||
3440 | /* see 7.1.7.7; affects power usage, but not budgeting */ | 3448 | /* see 7.1.7.7; affects power usage, but not budgeting */ |
3441 | if (hub_is_superspeed(hub->hdev)) | 3449 | if (hub_is_superspeed(hub->hdev)) |
diff --git a/drivers/usb/core/phy.c b/drivers/usb/core/phy.c index 09b7c43c0ea4..9879767452a2 100644 --- a/drivers/usb/core/phy.c +++ b/drivers/usb/core/phy.c | |||
@@ -19,19 +19,6 @@ struct usb_phy_roothub { | |||
19 | struct list_head list; | 19 | struct list_head list; |
20 | }; | 20 | }; |
21 | 21 | ||
22 | static struct usb_phy_roothub *usb_phy_roothub_alloc(struct device *dev) | ||
23 | { | ||
24 | struct usb_phy_roothub *roothub_entry; | ||
25 | |||
26 | roothub_entry = devm_kzalloc(dev, sizeof(*roothub_entry), GFP_KERNEL); | ||
27 | if (!roothub_entry) | ||
28 | return ERR_PTR(-ENOMEM); | ||
29 | |||
30 | INIT_LIST_HEAD(&roothub_entry->list); | ||
31 | |||
32 | return roothub_entry; | ||
33 | } | ||
34 | |||
35 | static int usb_phy_roothub_add_phy(struct device *dev, int index, | 22 | static int usb_phy_roothub_add_phy(struct device *dev, int index, |
36 | struct list_head *list) | 23 | struct list_head *list) |
37 | { | 24 | { |
@@ -45,9 +32,11 @@ static int usb_phy_roothub_add_phy(struct device *dev, int index, | |||
45 | return PTR_ERR(phy); | 32 | return PTR_ERR(phy); |
46 | } | 33 | } |
47 | 34 | ||
48 | roothub_entry = usb_phy_roothub_alloc(dev); | 35 | roothub_entry = devm_kzalloc(dev, sizeof(*roothub_entry), GFP_KERNEL); |
49 | if (IS_ERR(roothub_entry)) | 36 | if (!roothub_entry) |
50 | return PTR_ERR(roothub_entry); | 37 | return -ENOMEM; |
38 | |||
39 | INIT_LIST_HEAD(&roothub_entry->list); | ||
51 | 40 | ||
52 | roothub_entry->phy = phy; | 41 | roothub_entry->phy = phy; |
53 | 42 | ||
@@ -56,28 +45,44 @@ static int usb_phy_roothub_add_phy(struct device *dev, int index, | |||
56 | return 0; | 45 | return 0; |
57 | } | 46 | } |
58 | 47 | ||
59 | struct usb_phy_roothub *usb_phy_roothub_init(struct device *dev) | 48 | struct usb_phy_roothub *usb_phy_roothub_alloc(struct device *dev) |
60 | { | 49 | { |
61 | struct usb_phy_roothub *phy_roothub; | 50 | struct usb_phy_roothub *phy_roothub; |
62 | struct usb_phy_roothub *roothub_entry; | ||
63 | struct list_head *head; | ||
64 | int i, num_phys, err; | 51 | int i, num_phys, err; |
65 | 52 | ||
53 | if (!IS_ENABLED(CONFIG_GENERIC_PHY)) | ||
54 | return NULL; | ||
55 | |||
66 | num_phys = of_count_phandle_with_args(dev->of_node, "phys", | 56 | num_phys = of_count_phandle_with_args(dev->of_node, "phys", |
67 | "#phy-cells"); | 57 | "#phy-cells"); |
68 | if (num_phys <= 0) | 58 | if (num_phys <= 0) |
69 | return NULL; | 59 | return NULL; |
70 | 60 | ||
71 | phy_roothub = usb_phy_roothub_alloc(dev); | 61 | phy_roothub = devm_kzalloc(dev, sizeof(*phy_roothub), GFP_KERNEL); |
72 | if (IS_ERR(phy_roothub)) | 62 | if (!phy_roothub) |
73 | return phy_roothub; | 63 | return ERR_PTR(-ENOMEM); |
64 | |||
65 | INIT_LIST_HEAD(&phy_roothub->list); | ||
74 | 66 | ||
75 | for (i = 0; i < num_phys; i++) { | 67 | for (i = 0; i < num_phys; i++) { |
76 | err = usb_phy_roothub_add_phy(dev, i, &phy_roothub->list); | 68 | err = usb_phy_roothub_add_phy(dev, i, &phy_roothub->list); |
77 | if (err) | 69 | if (err) |
78 | goto err_out; | 70 | return ERR_PTR(err); |
79 | } | 71 | } |
80 | 72 | ||
73 | return phy_roothub; | ||
74 | } | ||
75 | EXPORT_SYMBOL_GPL(usb_phy_roothub_alloc); | ||
76 | |||
77 | int usb_phy_roothub_init(struct usb_phy_roothub *phy_roothub) | ||
78 | { | ||
79 | struct usb_phy_roothub *roothub_entry; | ||
80 | struct list_head *head; | ||
81 | int err; | ||
82 | |||
83 | if (!phy_roothub) | ||
84 | return 0; | ||
85 | |||
81 | head = &phy_roothub->list; | 86 | head = &phy_roothub->list; |
82 | 87 | ||
83 | list_for_each_entry(roothub_entry, head, list) { | 88 | list_for_each_entry(roothub_entry, head, list) { |
@@ -86,14 +91,13 @@ struct usb_phy_roothub *usb_phy_roothub_init(struct device *dev) | |||
86 | goto err_exit_phys; | 91 | goto err_exit_phys; |
87 | } | 92 | } |
88 | 93 | ||
89 | return phy_roothub; | 94 | return 0; |
90 | 95 | ||
91 | err_exit_phys: | 96 | err_exit_phys: |
92 | list_for_each_entry_continue_reverse(roothub_entry, head, list) | 97 | list_for_each_entry_continue_reverse(roothub_entry, head, list) |
93 | phy_exit(roothub_entry->phy); | 98 | phy_exit(roothub_entry->phy); |
94 | 99 | ||
95 | err_out: | 100 | return err; |
96 | return ERR_PTR(err); | ||
97 | } | 101 | } |
98 | EXPORT_SYMBOL_GPL(usb_phy_roothub_init); | 102 | EXPORT_SYMBOL_GPL(usb_phy_roothub_init); |
99 | 103 | ||
@@ -111,7 +115,7 @@ int usb_phy_roothub_exit(struct usb_phy_roothub *phy_roothub) | |||
111 | list_for_each_entry(roothub_entry, head, list) { | 115 | list_for_each_entry(roothub_entry, head, list) { |
112 | err = phy_exit(roothub_entry->phy); | 116 | err = phy_exit(roothub_entry->phy); |
113 | if (err) | 117 | if (err) |
114 | ret = ret; | 118 | ret = err; |
115 | } | 119 | } |
116 | 120 | ||
117 | return ret; | 121 | return ret; |
@@ -156,3 +160,38 @@ void usb_phy_roothub_power_off(struct usb_phy_roothub *phy_roothub) | |||
156 | phy_power_off(roothub_entry->phy); | 160 | phy_power_off(roothub_entry->phy); |
157 | } | 161 | } |
158 | EXPORT_SYMBOL_GPL(usb_phy_roothub_power_off); | 162 | EXPORT_SYMBOL_GPL(usb_phy_roothub_power_off); |
163 | |||
164 | int usb_phy_roothub_suspend(struct device *controller_dev, | ||
165 | struct usb_phy_roothub *phy_roothub) | ||
166 | { | ||
167 | usb_phy_roothub_power_off(phy_roothub); | ||
168 | |||
169 | /* keep the PHYs initialized so the device can wake up the system */ | ||
170 | if (device_may_wakeup(controller_dev)) | ||
171 | return 0; | ||
172 | |||
173 | return usb_phy_roothub_exit(phy_roothub); | ||
174 | } | ||
175 | EXPORT_SYMBOL_GPL(usb_phy_roothub_suspend); | ||
176 | |||
177 | int usb_phy_roothub_resume(struct device *controller_dev, | ||
178 | struct usb_phy_roothub *phy_roothub) | ||
179 | { | ||
180 | int err; | ||
181 | |||
182 | /* if the device can't wake up the system _exit was called */ | ||
183 | if (!device_may_wakeup(controller_dev)) { | ||
184 | err = usb_phy_roothub_init(phy_roothub); | ||
185 | if (err) | ||
186 | return err; | ||
187 | } | ||
188 | |||
189 | err = usb_phy_roothub_power_on(phy_roothub); | ||
190 | |||
191 | /* undo _init if _power_on failed */ | ||
192 | if (err && !device_may_wakeup(controller_dev)) | ||
193 | usb_phy_roothub_exit(phy_roothub); | ||
194 | |||
195 | return err; | ||
196 | } | ||
197 | EXPORT_SYMBOL_GPL(usb_phy_roothub_resume); | ||
diff --git a/drivers/usb/core/phy.h b/drivers/usb/core/phy.h index 6fde59bfbff8..88a3c037e9df 100644 --- a/drivers/usb/core/phy.h +++ b/drivers/usb/core/phy.h | |||
@@ -1,7 +1,27 @@ | |||
1 | /* SPDX-License-Identifier: GPL-2.0+ */ | ||
2 | /* | ||
3 | * USB roothub wrapper | ||
4 | * | ||
5 | * Copyright (C) 2018 Martin Blumenstingl <martin.blumenstingl@googlemail.com> | ||
6 | */ | ||
7 | |||
8 | #ifndef __USB_CORE_PHY_H_ | ||
9 | #define __USB_CORE_PHY_H_ | ||
10 | |||
11 | struct device; | ||
1 | struct usb_phy_roothub; | 12 | struct usb_phy_roothub; |
2 | 13 | ||
3 | struct usb_phy_roothub *usb_phy_roothub_init(struct device *dev); | 14 | struct usb_phy_roothub *usb_phy_roothub_alloc(struct device *dev); |
15 | |||
16 | int usb_phy_roothub_init(struct usb_phy_roothub *phy_roothub); | ||
4 | int usb_phy_roothub_exit(struct usb_phy_roothub *phy_roothub); | 17 | int usb_phy_roothub_exit(struct usb_phy_roothub *phy_roothub); |
5 | 18 | ||
6 | int usb_phy_roothub_power_on(struct usb_phy_roothub *phy_roothub); | 19 | int usb_phy_roothub_power_on(struct usb_phy_roothub *phy_roothub); |
7 | void usb_phy_roothub_power_off(struct usb_phy_roothub *phy_roothub); | 20 | void usb_phy_roothub_power_off(struct usb_phy_roothub *phy_roothub); |
21 | |||
22 | int usb_phy_roothub_suspend(struct device *controller_dev, | ||
23 | struct usb_phy_roothub *phy_roothub); | ||
24 | int usb_phy_roothub_resume(struct device *controller_dev, | ||
25 | struct usb_phy_roothub *phy_roothub); | ||
26 | |||
27 | #endif /* __USB_CORE_PHY_H_ */ | ||
diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c index 920f48a49a87..c55def2f1320 100644 --- a/drivers/usb/core/quirks.c +++ b/drivers/usb/core/quirks.c | |||
@@ -186,6 +186,9 @@ static const struct usb_device_id usb_quirk_list[] = { | |||
186 | { USB_DEVICE(0x03f0, 0x0701), .driver_info = | 186 | { USB_DEVICE(0x03f0, 0x0701), .driver_info = |
187 | USB_QUIRK_STRING_FETCH_255 }, | 187 | USB_QUIRK_STRING_FETCH_255 }, |
188 | 188 | ||
189 | /* HP v222w 16GB Mini USB Drive */ | ||
190 | { USB_DEVICE(0x03f0, 0x3f40), .driver_info = USB_QUIRK_DELAY_INIT }, | ||
191 | |||
189 | /* Creative SB Audigy 2 NX */ | 192 | /* Creative SB Audigy 2 NX */ |
190 | { USB_DEVICE(0x041e, 0x3020), .driver_info = USB_QUIRK_RESET_RESUME }, | 193 | { USB_DEVICE(0x041e, 0x3020), .driver_info = USB_QUIRK_RESET_RESUME }, |
191 | 194 | ||