diff options
author | Fabio Baltieri <fabio.baltieri@linaro.org> | 2013-03-07 21:27:09 -0500 |
---|---|---|
committer | Felipe Balbi <balbi@ti.com> | 2013-03-18 08:41:33 -0400 |
commit | af6882be363d3a7bf0f72dd17ac2a639c4da0059 (patch) | |
tree | 5b652ffd6e7980c1de44517dceac3db55cd4a863 /drivers/usb/phy | |
parent | 73f226cbd79adb5f3f25ee14c18900bb4a9acd15 (diff) |
usb: phy: ab8500-usb: update irq handling code
Update irq handling code to notify all possible link status changes of
AB8500 and AB8505 to the ux500-musb glue driver. The additional event
codes will be used for pm-runtime implementation, and are defined in a
separate ux500-specific header.
This also modify the irq registration code to use devm_* helpers and
drop all non necessary fail path code.
Acked-by: Linus Walleij <linus.walleij@linaro.org>
Signed-off-by: Fabio Baltieri <fabio.baltieri@linaro.org>
Signed-off-by: Felipe Balbi <balbi@ti.com>
Diffstat (limited to 'drivers/usb/phy')
-rw-r--r-- | drivers/usb/phy/phy-ab8500-usb.c | 440 |
1 files changed, 347 insertions, 93 deletions
diff --git a/drivers/usb/phy/phy-ab8500-usb.c b/drivers/usb/phy/phy-ab8500-usb.c index 9f5e0e4ab02a..351b0369a611 100644 --- a/drivers/usb/phy/phy-ab8500-usb.c +++ b/drivers/usb/phy/phy-ab8500-usb.c | |||
@@ -31,9 +31,11 @@ | |||
31 | #include <linux/delay.h> | 31 | #include <linux/delay.h> |
32 | #include <linux/mfd/abx500.h> | 32 | #include <linux/mfd/abx500.h> |
33 | #include <linux/mfd/abx500/ab8500.h> | 33 | #include <linux/mfd/abx500/ab8500.h> |
34 | #include <linux/usb/musb-ux500.h> | ||
34 | 35 | ||
35 | #define AB8500_MAIN_WD_CTRL_REG 0x01 | 36 | #define AB8500_MAIN_WD_CTRL_REG 0x01 |
36 | #define AB8500_USB_LINE_STAT_REG 0x80 | 37 | #define AB8500_USB_LINE_STAT_REG 0x80 |
38 | #define AB8505_USB_LINE_STAT_REG 0x94 | ||
37 | #define AB8500_USB_PHY_CTRL_REG 0x8A | 39 | #define AB8500_USB_PHY_CTRL_REG 0x8A |
38 | 40 | ||
39 | #define AB8500_BIT_OTG_STAT_ID (1 << 0) | 41 | #define AB8500_BIT_OTG_STAT_ID (1 << 0) |
@@ -44,36 +46,76 @@ | |||
44 | 46 | ||
45 | #define AB8500_WD_KICK_DELAY_US 100 /* usec */ | 47 | #define AB8500_WD_KICK_DELAY_US 100 /* usec */ |
46 | #define AB8500_WD_V11_DISABLE_DELAY_US 100 /* usec */ | 48 | #define AB8500_WD_V11_DISABLE_DELAY_US 100 /* usec */ |
49 | #define AB8500_V20_31952_DISABLE_DELAY_US 100 /* usec */ | ||
47 | 50 | ||
48 | /* Usb line status register */ | 51 | /* Usb line status register */ |
49 | enum ab8500_usb_link_status { | 52 | enum ab8500_usb_link_status { |
50 | USB_LINK_NOT_CONFIGURED = 0, | 53 | USB_LINK_NOT_CONFIGURED_8500 = 0, |
51 | USB_LINK_STD_HOST_NC, | 54 | USB_LINK_STD_HOST_NC_8500, |
52 | USB_LINK_STD_HOST_C_NS, | 55 | USB_LINK_STD_HOST_C_NS_8500, |
53 | USB_LINK_STD_HOST_C_S, | 56 | USB_LINK_STD_HOST_C_S_8500, |
54 | USB_LINK_HOST_CHG_NM, | 57 | USB_LINK_HOST_CHG_NM_8500, |
55 | USB_LINK_HOST_CHG_HS, | 58 | USB_LINK_HOST_CHG_HS_8500, |
56 | USB_LINK_HOST_CHG_HS_CHIRP, | 59 | USB_LINK_HOST_CHG_HS_CHIRP_8500, |
57 | USB_LINK_DEDICATED_CHG, | 60 | USB_LINK_DEDICATED_CHG_8500, |
58 | USB_LINK_ACA_RID_A, | 61 | USB_LINK_ACA_RID_A_8500, |
59 | USB_LINK_ACA_RID_B, | 62 | USB_LINK_ACA_RID_B_8500, |
60 | USB_LINK_ACA_RID_C_NM, | 63 | USB_LINK_ACA_RID_C_NM_8500, |
61 | USB_LINK_ACA_RID_C_HS, | 64 | USB_LINK_ACA_RID_C_HS_8500, |
62 | USB_LINK_ACA_RID_C_HS_CHIRP, | 65 | USB_LINK_ACA_RID_C_HS_CHIRP_8500, |
63 | USB_LINK_HM_IDGND, | 66 | USB_LINK_HM_IDGND_8500, |
64 | USB_LINK_RESERVED, | 67 | USB_LINK_RESERVED_8500, |
65 | USB_LINK_NOT_VALID_LINK | 68 | USB_LINK_NOT_VALID_LINK_8500, |
69 | }; | ||
70 | |||
71 | enum ab8505_usb_link_status { | ||
72 | USB_LINK_NOT_CONFIGURED_8505 = 0, | ||
73 | USB_LINK_STD_HOST_NC_8505, | ||
74 | USB_LINK_STD_HOST_C_NS_8505, | ||
75 | USB_LINK_STD_HOST_C_S_8505, | ||
76 | USB_LINK_CDP_8505, | ||
77 | USB_LINK_RESERVED0_8505, | ||
78 | USB_LINK_RESERVED1_8505, | ||
79 | USB_LINK_DEDICATED_CHG_8505, | ||
80 | USB_LINK_ACA_RID_A_8505, | ||
81 | USB_LINK_ACA_RID_B_8505, | ||
82 | USB_LINK_ACA_RID_C_NM_8505, | ||
83 | USB_LINK_RESERVED2_8505, | ||
84 | USB_LINK_RESERVED3_8505, | ||
85 | USB_LINK_HM_IDGND_8505, | ||
86 | USB_LINK_CHARGERPORT_NOT_OK_8505, | ||
87 | USB_LINK_CHARGER_DM_HIGH_8505, | ||
88 | USB_LINK_PHYEN_NO_VBUS_NO_IDGND_8505, | ||
89 | USB_LINK_STD_UPSTREAM_NO_IDGNG_NO_VBUS_8505, | ||
90 | USB_LINK_STD_UPSTREAM_8505, | ||
91 | USB_LINK_CHARGER_SE1_8505, | ||
92 | USB_LINK_CARKIT_CHGR_1_8505, | ||
93 | USB_LINK_CARKIT_CHGR_2_8505, | ||
94 | USB_LINK_ACA_DOCK_CHGR_8505, | ||
95 | USB_LINK_SAMSUNG_BOOT_CBL_PHY_EN_8505, | ||
96 | USB_LINK_SAMSUNG_BOOT_CBL_PHY_DISB_8505, | ||
97 | USB_LINK_SAMSUNG_UART_CBL_PHY_EN_8505, | ||
98 | USB_LINK_SAMSUNG_UART_CBL_PHY_DISB_8505, | ||
99 | USB_LINK_MOTOROLA_FACTORY_CBL_PHY_EN_8505, | ||
100 | }; | ||
101 | |||
102 | enum ab8500_usb_mode { | ||
103 | USB_IDLE = 0, | ||
104 | USB_PERIPHERAL, | ||
105 | USB_HOST, | ||
106 | USB_DEDICATED_CHG | ||
66 | }; | 107 | }; |
67 | 108 | ||
68 | struct ab8500_usb { | 109 | struct ab8500_usb { |
69 | struct usb_phy phy; | 110 | struct usb_phy phy; |
70 | struct device *dev; | 111 | struct device *dev; |
71 | struct ab8500 *ab8500; | 112 | struct ab8500 *ab8500; |
72 | int irq_num_link_status; | ||
73 | unsigned vbus_draw; | 113 | unsigned vbus_draw; |
74 | struct delayed_work dwork; | 114 | struct delayed_work dwork; |
75 | struct work_struct phy_dis_work; | 115 | struct work_struct phy_dis_work; |
76 | unsigned long link_status_wait; | 116 | unsigned long link_status_wait; |
117 | enum ab8500_usb_mode mode; | ||
118 | int previous_link_status_state; | ||
77 | }; | 119 | }; |
78 | 120 | ||
79 | static inline struct ab8500_usb *phy_to_ab(struct usb_phy *x) | 121 | static inline struct ab8500_usb *phy_to_ab(struct usb_phy *x) |
@@ -104,6 +146,17 @@ static void ab8500_usb_wd_workaround(struct ab8500_usb *ab) | |||
104 | 0); | 146 | 0); |
105 | } | 147 | } |
106 | 148 | ||
149 | static void ab8500_usb_wd_linkstatus(struct ab8500_usb *ab, u8 bit) | ||
150 | { | ||
151 | /* Workaround for v2.0 bug # 31952 */ | ||
152 | if (is_ab8500_2p0(ab->ab8500)) { | ||
153 | abx500_mask_and_set_register_interruptible(ab->dev, | ||
154 | AB8500_USB, AB8500_USB_PHY_CTRL_REG, | ||
155 | bit, bit); | ||
156 | udelay(AB8500_V20_31952_DISABLE_DELAY_US); | ||
157 | } | ||
158 | } | ||
159 | |||
107 | static void ab8500_usb_phy_ctrl(struct ab8500_usb *ab, bool sel_host, | 160 | static void ab8500_usb_phy_ctrl(struct ab8500_usb *ab, bool sel_host, |
108 | bool enable) | 161 | bool enable) |
109 | { | 162 | { |
@@ -139,92 +192,276 @@ static void ab8500_usb_phy_ctrl(struct ab8500_usb *ab, bool sel_host, | |||
139 | #define ab8500_usb_peri_phy_en(ab) ab8500_usb_phy_ctrl(ab, false, true) | 192 | #define ab8500_usb_peri_phy_en(ab) ab8500_usb_phy_ctrl(ab, false, true) |
140 | #define ab8500_usb_peri_phy_dis(ab) ab8500_usb_phy_ctrl(ab, false, false) | 193 | #define ab8500_usb_peri_phy_dis(ab) ab8500_usb_phy_ctrl(ab, false, false) |
141 | 194 | ||
142 | static int ab8500_usb_link_status_update(struct ab8500_usb *ab) | 195 | static int ab8505_usb_link_status_update(struct ab8500_usb *ab, |
196 | enum ab8505_usb_link_status lsts) | ||
143 | { | 197 | { |
144 | u8 reg; | 198 | enum ux500_musb_vbus_id_status event = 0; |
145 | enum ab8500_usb_link_status lsts; | ||
146 | void *v = NULL; | ||
147 | enum usb_phy_events event; | ||
148 | 199 | ||
149 | abx500_get_register_interruptible(ab->dev, | 200 | dev_dbg(ab->dev, "ab8505_usb_link_status_update %d\n", lsts); |
150 | AB8500_USB, | ||
151 | AB8500_USB_LINE_STAT_REG, | ||
152 | ®); | ||
153 | 201 | ||
154 | lsts = (reg >> 3) & 0x0F; | 202 | /* |
203 | * Spurious link_status interrupts are seen at the time of | ||
204 | * disconnection of a device in RIDA state | ||
205 | */ | ||
206 | if (ab->previous_link_status_state == USB_LINK_ACA_RID_A_8505 && | ||
207 | (lsts == USB_LINK_STD_HOST_NC_8505)) | ||
208 | return 0; | ||
209 | |||
210 | ab->previous_link_status_state = lsts; | ||
155 | 211 | ||
156 | switch (lsts) { | 212 | switch (lsts) { |
157 | case USB_LINK_NOT_CONFIGURED: | 213 | case USB_LINK_ACA_RID_B_8505: |
158 | case USB_LINK_RESERVED: | 214 | event = UX500_MUSB_RIDB; |
159 | case USB_LINK_NOT_VALID_LINK: | 215 | case USB_LINK_NOT_CONFIGURED_8505: |
160 | /* TODO: Disable regulators. */ | 216 | case USB_LINK_RESERVED0_8505: |
161 | ab8500_usb_host_phy_dis(ab); | 217 | case USB_LINK_RESERVED1_8505: |
162 | ab8500_usb_peri_phy_dis(ab); | 218 | case USB_LINK_RESERVED2_8505: |
163 | ab->phy.state = OTG_STATE_B_IDLE; | 219 | case USB_LINK_RESERVED3_8505: |
220 | ab->mode = USB_IDLE; | ||
164 | ab->phy.otg->default_a = false; | 221 | ab->phy.otg->default_a = false; |
165 | ab->vbus_draw = 0; | 222 | ab->vbus_draw = 0; |
166 | event = USB_EVENT_NONE; | 223 | if (event != UX500_MUSB_RIDB) |
224 | event = UX500_MUSB_NONE; | ||
225 | /* | ||
226 | * Fallback to default B_IDLE as nothing | ||
227 | * is connected | ||
228 | */ | ||
229 | ab->phy.state = OTG_STATE_B_IDLE; | ||
167 | break; | 230 | break; |
168 | 231 | ||
169 | case USB_LINK_STD_HOST_NC: | 232 | case USB_LINK_ACA_RID_C_NM_8505: |
170 | case USB_LINK_STD_HOST_C_NS: | 233 | event = UX500_MUSB_RIDC; |
171 | case USB_LINK_STD_HOST_C_S: | 234 | case USB_LINK_STD_HOST_NC_8505: |
172 | case USB_LINK_HOST_CHG_NM: | 235 | case USB_LINK_STD_HOST_C_NS_8505: |
173 | case USB_LINK_HOST_CHG_HS: | 236 | case USB_LINK_STD_HOST_C_S_8505: |
174 | case USB_LINK_HOST_CHG_HS_CHIRP: | 237 | case USB_LINK_CDP_8505: |
175 | if (ab->phy.otg->gadget) { | 238 | if (ab->mode == USB_IDLE) { |
176 | /* TODO: Enable regulators. */ | 239 | ab->mode = USB_PERIPHERAL; |
177 | ab8500_usb_peri_phy_en(ab); | 240 | ab8500_usb_peri_phy_en(ab); |
178 | v = ab->phy.otg->gadget; | 241 | atomic_notifier_call_chain(&ab->phy.notifier, |
242 | UX500_MUSB_PREPARE, &ab->vbus_draw); | ||
179 | } | 243 | } |
180 | event = USB_EVENT_VBUS; | 244 | if (event != UX500_MUSB_RIDC) |
245 | event = UX500_MUSB_VBUS; | ||
181 | break; | 246 | break; |
182 | 247 | ||
183 | case USB_LINK_HM_IDGND: | 248 | case USB_LINK_ACA_RID_A_8505: |
184 | if (ab->phy.otg->host) { | 249 | case USB_LINK_ACA_DOCK_CHGR_8505: |
185 | /* TODO: Enable regulators. */ | 250 | event = UX500_MUSB_RIDA; |
251 | case USB_LINK_HM_IDGND_8505: | ||
252 | if (ab->mode == USB_IDLE) { | ||
253 | ab->mode = USB_HOST; | ||
186 | ab8500_usb_host_phy_en(ab); | 254 | ab8500_usb_host_phy_en(ab); |
187 | v = ab->phy.otg->host; | 255 | atomic_notifier_call_chain(&ab->phy.notifier, |
256 | UX500_MUSB_PREPARE, &ab->vbus_draw); | ||
188 | } | 257 | } |
189 | ab->phy.state = OTG_STATE_A_IDLE; | ||
190 | ab->phy.otg->default_a = true; | 258 | ab->phy.otg->default_a = true; |
191 | event = USB_EVENT_ID; | 259 | if (event != UX500_MUSB_RIDA) |
260 | event = UX500_MUSB_ID; | ||
261 | atomic_notifier_call_chain(&ab->phy.notifier, | ||
262 | event, &ab->vbus_draw); | ||
192 | break; | 263 | break; |
193 | 264 | ||
194 | case USB_LINK_ACA_RID_A: | 265 | case USB_LINK_DEDICATED_CHG_8505: |
195 | case USB_LINK_ACA_RID_B: | 266 | ab->mode = USB_DEDICATED_CHG; |
196 | /* TODO */ | 267 | event = UX500_MUSB_CHARGER; |
197 | case USB_LINK_ACA_RID_C_NM: | 268 | atomic_notifier_call_chain(&ab->phy.notifier, |
198 | case USB_LINK_ACA_RID_C_HS: | 269 | event, &ab->vbus_draw); |
199 | case USB_LINK_ACA_RID_C_HS_CHIRP: | 270 | break; |
200 | case USB_LINK_DEDICATED_CHG: | 271 | |
201 | /* TODO: vbus_draw */ | 272 | default: |
202 | event = USB_EVENT_CHARGER; | ||
203 | break; | 273 | break; |
204 | } | 274 | } |
205 | 275 | ||
206 | atomic_notifier_call_chain(&ab->phy.notifier, event, v); | 276 | return 0; |
277 | } | ||
278 | |||
279 | static int ab8500_usb_link_status_update(struct ab8500_usb *ab, | ||
280 | enum ab8500_usb_link_status lsts) | ||
281 | { | ||
282 | enum ux500_musb_vbus_id_status event = 0; | ||
283 | |||
284 | dev_dbg(ab->dev, "ab8500_usb_link_status_update %d\n", lsts); | ||
285 | |||
286 | /* | ||
287 | * Spurious link_status interrupts are seen in case of a | ||
288 | * disconnection of a device in IDGND and RIDA stage | ||
289 | */ | ||
290 | if (ab->previous_link_status_state == USB_LINK_HM_IDGND_8500 && | ||
291 | (lsts == USB_LINK_STD_HOST_C_NS_8500 || | ||
292 | lsts == USB_LINK_STD_HOST_NC_8500)) | ||
293 | return 0; | ||
294 | |||
295 | if (ab->previous_link_status_state == USB_LINK_ACA_RID_A_8500 && | ||
296 | lsts == USB_LINK_STD_HOST_NC_8500) | ||
297 | return 0; | ||
298 | |||
299 | ab->previous_link_status_state = lsts; | ||
300 | |||
301 | switch (lsts) { | ||
302 | case USB_LINK_ACA_RID_B_8500: | ||
303 | event = UX500_MUSB_RIDB; | ||
304 | case USB_LINK_NOT_CONFIGURED_8500: | ||
305 | case USB_LINK_NOT_VALID_LINK_8500: | ||
306 | ab->mode = USB_IDLE; | ||
307 | ab->phy.otg->default_a = false; | ||
308 | ab->vbus_draw = 0; | ||
309 | if (event != UX500_MUSB_RIDB) | ||
310 | event = UX500_MUSB_NONE; | ||
311 | /* Fallback to default B_IDLE as nothing is connected */ | ||
312 | ab->phy.state = OTG_STATE_B_IDLE; | ||
313 | break; | ||
314 | |||
315 | case USB_LINK_ACA_RID_C_NM_8500: | ||
316 | case USB_LINK_ACA_RID_C_HS_8500: | ||
317 | case USB_LINK_ACA_RID_C_HS_CHIRP_8500: | ||
318 | event = UX500_MUSB_RIDC; | ||
319 | case USB_LINK_STD_HOST_NC_8500: | ||
320 | case USB_LINK_STD_HOST_C_NS_8500: | ||
321 | case USB_LINK_STD_HOST_C_S_8500: | ||
322 | case USB_LINK_HOST_CHG_NM_8500: | ||
323 | case USB_LINK_HOST_CHG_HS_8500: | ||
324 | case USB_LINK_HOST_CHG_HS_CHIRP_8500: | ||
325 | if (ab->mode == USB_IDLE) { | ||
326 | ab->mode = USB_PERIPHERAL; | ||
327 | ab8500_usb_peri_phy_en(ab); | ||
328 | atomic_notifier_call_chain(&ab->phy.notifier, | ||
329 | UX500_MUSB_PREPARE, &ab->vbus_draw); | ||
330 | } | ||
331 | if (event != UX500_MUSB_RIDC) | ||
332 | event = UX500_MUSB_VBUS; | ||
333 | break; | ||
334 | |||
335 | case USB_LINK_ACA_RID_A_8500: | ||
336 | event = UX500_MUSB_RIDA; | ||
337 | case USB_LINK_HM_IDGND_8500: | ||
338 | if (ab->mode == USB_IDLE) { | ||
339 | ab->mode = USB_HOST; | ||
340 | ab8500_usb_host_phy_en(ab); | ||
341 | atomic_notifier_call_chain(&ab->phy.notifier, | ||
342 | UX500_MUSB_PREPARE, &ab->vbus_draw); | ||
343 | } | ||
344 | ab->phy.otg->default_a = true; | ||
345 | if (event != UX500_MUSB_RIDA) | ||
346 | event = UX500_MUSB_ID; | ||
347 | atomic_notifier_call_chain(&ab->phy.notifier, | ||
348 | event, &ab->vbus_draw); | ||
349 | break; | ||
350 | |||
351 | case USB_LINK_DEDICATED_CHG_8500: | ||
352 | ab->mode = USB_DEDICATED_CHG; | ||
353 | event = UX500_MUSB_CHARGER; | ||
354 | atomic_notifier_call_chain(&ab->phy.notifier, | ||
355 | event, &ab->vbus_draw); | ||
356 | break; | ||
357 | |||
358 | case USB_LINK_RESERVED_8500: | ||
359 | break; | ||
360 | } | ||
207 | 361 | ||
208 | return 0; | 362 | return 0; |
209 | } | 363 | } |
210 | 364 | ||
211 | static void ab8500_usb_delayed_work(struct work_struct *work) | 365 | /* |
366 | * Connection Sequence: | ||
367 | * 1. Link Status Interrupt | ||
368 | * 2. Enable AB clock | ||
369 | * 3. Enable AB regulators | ||
370 | * 4. Enable USB phy | ||
371 | * 5. Reset the musb controller | ||
372 | * 6. Switch the ULPI GPIO pins to fucntion mode | ||
373 | * 7. Enable the musb Peripheral5 clock | ||
374 | * 8. Restore MUSB context | ||
375 | */ | ||
376 | static int abx500_usb_link_status_update(struct ab8500_usb *ab) | ||
212 | { | 377 | { |
213 | struct ab8500_usb *ab = container_of(work, struct ab8500_usb, | 378 | u8 reg; |
214 | dwork.work); | 379 | int ret = 0; |
380 | |||
381 | if (is_ab8500(ab->ab8500)) { | ||
382 | enum ab8500_usb_link_status lsts; | ||
383 | |||
384 | abx500_get_register_interruptible(ab->dev, | ||
385 | AB8500_USB, AB8500_USB_LINE_STAT_REG, ®); | ||
386 | lsts = (reg >> 3) & 0x0F; | ||
387 | ret = ab8500_usb_link_status_update(ab, lsts); | ||
388 | } else if (is_ab8505(ab->ab8500)) { | ||
389 | enum ab8505_usb_link_status lsts; | ||
390 | |||
391 | abx500_get_register_interruptible(ab->dev, | ||
392 | AB8500_USB, AB8505_USB_LINE_STAT_REG, ®); | ||
393 | lsts = (reg >> 3) & 0x1F; | ||
394 | ret = ab8505_usb_link_status_update(ab, lsts); | ||
395 | } | ||
396 | |||
397 | return ret; | ||
398 | } | ||
399 | |||
400 | /* | ||
401 | * Disconnection Sequence: | ||
402 | * 1. Disconect Interrupt | ||
403 | * 2. Disable regulators | ||
404 | * 3. Disable AB clock | ||
405 | * 4. Disable the Phy | ||
406 | * 5. Link Status Interrupt | ||
407 | * 6. Disable Musb Clock | ||
408 | */ | ||
409 | static irqreturn_t ab8500_usb_disconnect_irq(int irq, void *data) | ||
410 | { | ||
411 | struct ab8500_usb *ab = (struct ab8500_usb *) data; | ||
412 | enum usb_phy_events event = UX500_MUSB_NONE; | ||
413 | |||
414 | /* Link status will not be updated till phy is disabled. */ | ||
415 | if (ab->mode == USB_HOST) { | ||
416 | ab->phy.otg->default_a = false; | ||
417 | ab->vbus_draw = 0; | ||
418 | atomic_notifier_call_chain(&ab->phy.notifier, | ||
419 | event, &ab->vbus_draw); | ||
420 | ab8500_usb_host_phy_dis(ab); | ||
421 | ab->mode = USB_IDLE; | ||
422 | } | ||
423 | |||
424 | if (ab->mode == USB_PERIPHERAL) { | ||
425 | atomic_notifier_call_chain(&ab->phy.notifier, | ||
426 | event, &ab->vbus_draw); | ||
427 | ab8500_usb_peri_phy_dis(ab); | ||
428 | atomic_notifier_call_chain(&ab->phy.notifier, | ||
429 | UX500_MUSB_CLEAN, &ab->vbus_draw); | ||
430 | ab->mode = USB_IDLE; | ||
431 | ab->phy.otg->default_a = false; | ||
432 | ab->vbus_draw = 0; | ||
433 | } | ||
434 | |||
435 | if (is_ab8500_2p0(ab->ab8500)) { | ||
436 | if (ab->mode == USB_DEDICATED_CHG) { | ||
437 | ab8500_usb_wd_linkstatus(ab, | ||
438 | AB8500_BIT_PHY_CTRL_DEVICE_EN); | ||
439 | abx500_mask_and_set_register_interruptible(ab->dev, | ||
440 | AB8500_USB, AB8500_USB_PHY_CTRL_REG, | ||
441 | AB8500_BIT_PHY_CTRL_DEVICE_EN, 0); | ||
442 | } | ||
443 | } | ||
215 | 444 | ||
216 | ab8500_usb_link_status_update(ab); | 445 | return IRQ_HANDLED; |
217 | } | 446 | } |
218 | 447 | ||
219 | static irqreturn_t ab8500_usb_v20_irq(int irq, void *data) | 448 | static irqreturn_t ab8500_usb_link_status_irq(int irq, void *data) |
220 | { | 449 | { |
221 | struct ab8500_usb *ab = (struct ab8500_usb *) data; | 450 | struct ab8500_usb *ab = (struct ab8500_usb *) data; |
222 | 451 | ||
223 | ab8500_usb_link_status_update(ab); | 452 | abx500_usb_link_status_update(ab); |
224 | 453 | ||
225 | return IRQ_HANDLED; | 454 | return IRQ_HANDLED; |
226 | } | 455 | } |
227 | 456 | ||
457 | static void ab8500_usb_delayed_work(struct work_struct *work) | ||
458 | { | ||
459 | struct ab8500_usb *ab = container_of(work, struct ab8500_usb, | ||
460 | dwork.work); | ||
461 | |||
462 | abx500_usb_link_status_update(ab); | ||
463 | } | ||
464 | |||
228 | static void ab8500_usb_phy_disable_work(struct work_struct *work) | 465 | static void ab8500_usb_phy_disable_work(struct work_struct *work) |
229 | { | 466 | { |
230 | struct ab8500_usb *ab = container_of(work, struct ab8500_usb, | 467 | struct ab8500_usb *ab = container_of(work, struct ab8500_usb, |
@@ -250,7 +487,7 @@ static int ab8500_usb_set_power(struct usb_phy *phy, unsigned mA) | |||
250 | 487 | ||
251 | if (mA) | 488 | if (mA) |
252 | atomic_notifier_call_chain(&ab->phy.notifier, | 489 | atomic_notifier_call_chain(&ab->phy.notifier, |
253 | USB_EVENT_ENUMERATED, ab->phy.otg->gadget); | 490 | UX500_MUSB_ENUMERATED, ab->phy.otg->gadget); |
254 | return 0; | 491 | return 0; |
255 | } | 492 | } |
256 | 493 | ||
@@ -327,30 +564,48 @@ static int ab8500_usb_set_host(struct usb_otg *otg, struct usb_bus *host) | |||
327 | return 0; | 564 | return 0; |
328 | } | 565 | } |
329 | 566 | ||
330 | static void ab8500_usb_irq_free(struct ab8500_usb *ab) | 567 | static int ab8500_usb_irq_setup(struct platform_device *pdev, |
331 | { | 568 | struct ab8500_usb *ab) |
332 | free_irq(ab->irq_num_link_status, ab); | ||
333 | } | ||
334 | |||
335 | static int ab8500_usb_v2_res_setup(struct platform_device *pdev, | ||
336 | struct ab8500_usb *ab) | ||
337 | { | 569 | { |
338 | int err; | 570 | int err; |
571 | int irq; | ||
339 | 572 | ||
340 | ab->irq_num_link_status = platform_get_irq_byname(pdev, | 573 | irq = platform_get_irq_byname(pdev, "USB_LINK_STATUS"); |
341 | "USB_LINK_STATUS"); | 574 | if (irq < 0) { |
342 | if (ab->irq_num_link_status < 0) { | ||
343 | dev_err(&pdev->dev, "Link status irq not found\n"); | 575 | dev_err(&pdev->dev, "Link status irq not found\n"); |
344 | return ab->irq_num_link_status; | 576 | return irq; |
577 | } | ||
578 | err = devm_request_threaded_irq(&pdev->dev, irq, NULL, | ||
579 | ab8500_usb_link_status_irq, | ||
580 | IRQF_NO_SUSPEND | IRQF_SHARED, "usb-link-status", ab); | ||
581 | if (err < 0) { | ||
582 | dev_err(ab->dev, "request_irq failed for link status irq\n"); | ||
583 | return err; | ||
345 | } | 584 | } |
346 | 585 | ||
347 | err = request_threaded_irq(ab->irq_num_link_status, NULL, | 586 | irq = platform_get_irq_byname(pdev, "ID_WAKEUP_F"); |
348 | ab8500_usb_v20_irq, | 587 | if (irq < 0) { |
349 | IRQF_NO_SUSPEND | IRQF_SHARED, | 588 | dev_err(&pdev->dev, "ID fall irq not found\n"); |
350 | "usb-link-status", ab); | 589 | return irq; |
590 | } | ||
591 | err = devm_request_threaded_irq(&pdev->dev, irq, NULL, | ||
592 | ab8500_usb_disconnect_irq, | ||
593 | IRQF_NO_SUSPEND | IRQF_SHARED, "usb-id-fall", ab); | ||
351 | if (err < 0) { | 594 | if (err < 0) { |
352 | dev_err(ab->dev, | 595 | dev_err(ab->dev, "request_irq failed for ID fall irq\n"); |
353 | "request_irq failed for link status irq\n"); | 596 | return err; |
597 | } | ||
598 | |||
599 | irq = platform_get_irq_byname(pdev, "VBUS_DET_F"); | ||
600 | if (irq < 0) { | ||
601 | dev_err(&pdev->dev, "VBUS fall irq not found\n"); | ||
602 | return irq; | ||
603 | } | ||
604 | err = devm_request_threaded_irq(&pdev->dev, irq, NULL, | ||
605 | ab8500_usb_disconnect_irq, | ||
606 | IRQF_NO_SUSPEND | IRQF_SHARED, "usb-vbus-fall", ab); | ||
607 | if (err < 0) { | ||
608 | dev_err(ab->dev, "request_irq failed for Vbus fall irq\n"); | ||
354 | return err; | 609 | return err; |
355 | } | 610 | } |
356 | 611 | ||
@@ -408,22 +663,23 @@ static int ab8500_usb_probe(struct platform_device *pdev) | |||
408 | /* all: Disable phy when called from set_host and set_peripheral */ | 663 | /* all: Disable phy when called from set_host and set_peripheral */ |
409 | INIT_WORK(&ab->phy_dis_work, ab8500_usb_phy_disable_work); | 664 | INIT_WORK(&ab->phy_dis_work, ab8500_usb_phy_disable_work); |
410 | 665 | ||
411 | err = ab8500_usb_v2_res_setup(pdev, ab); | 666 | err = ab8500_usb_irq_setup(pdev, ab); |
412 | if (err < 0) | 667 | if (err < 0) |
413 | goto fail0; | 668 | goto fail; |
414 | 669 | ||
415 | err = usb_add_phy(&ab->phy, USB_PHY_TYPE_USB2); | 670 | err = usb_add_phy(&ab->phy, USB_PHY_TYPE_USB2); |
416 | if (err) { | 671 | if (err) { |
417 | dev_err(&pdev->dev, "Can't register transceiver\n"); | 672 | dev_err(&pdev->dev, "Can't register transceiver\n"); |
418 | goto fail1; | 673 | goto fail; |
419 | } | 674 | } |
420 | 675 | ||
676 | /* Needed to enable ID detection. */ | ||
677 | ab8500_usb_wd_workaround(ab); | ||
678 | |||
421 | dev_info(&pdev->dev, "revision 0x%2x driver initialized\n", rev); | 679 | dev_info(&pdev->dev, "revision 0x%2x driver initialized\n", rev); |
422 | 680 | ||
423 | return 0; | 681 | return 0; |
424 | fail1: | 682 | fail: |
425 | ab8500_usb_irq_free(ab); | ||
426 | fail0: | ||
427 | kfree(otg); | 683 | kfree(otg); |
428 | kfree(ab); | 684 | kfree(ab); |
429 | return err; | 685 | return err; |
@@ -433,8 +689,6 @@ static int ab8500_usb_remove(struct platform_device *pdev) | |||
433 | { | 689 | { |
434 | struct ab8500_usb *ab = platform_get_drvdata(pdev); | 690 | struct ab8500_usb *ab = platform_get_drvdata(pdev); |
435 | 691 | ||
436 | ab8500_usb_irq_free(ab); | ||
437 | |||
438 | cancel_delayed_work_sync(&ab->dwork); | 692 | cancel_delayed_work_sync(&ab->dwork); |
439 | 693 | ||
440 | cancel_work_sync(&ab->phy_dis_work); | 694 | cancel_work_sync(&ab->phy_dis_work); |