Commit | Line | Data |
---|---|---|
5fd54ace | 1 | // SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) |
5b9974b1 MK |
2 | /* |
3 | * platform.c - DesignWare HS OTG Controller platform driver | |
4 | * | |
5 | * Copyright (C) Matthijs Kooijman <matthijs@stdin.nl> | |
5b9974b1 MK |
6 | */ |
7 | ||
8 | #include <linux/kernel.h> | |
9 | #include <linux/module.h> | |
10 | #include <linux/slab.h> | |
09a75e85 | 11 | #include <linux/clk.h> |
5b9974b1 MK |
12 | #include <linux/device.h> |
13 | #include <linux/dma-mapping.h> | |
484468fb | 14 | #include <linux/of.h> |
7ad8096e | 15 | #include <linux/mutex.h> |
5b9974b1 | 16 | #include <linux/platform_device.h> |
09a75e85 MS |
17 | #include <linux/phy/phy.h> |
18 | #include <linux/platform_data/s3c-hsotg.h> | |
83f8da56 | 19 | #include <linux/reset.h> |
5b9974b1 | 20 | |
c0155b9d KY |
21 | #include <linux/usb/of.h> |
22 | ||
5b9974b1 MK |
23 | #include "core.h" |
24 | #include "hcd.h" | |
f91eea44 | 25 | #include "debug.h" |
5b9974b1 MK |
26 | |
27 | static const char dwc2_driver_name[] = "dwc2"; | |
28 | ||
5268ed9d JY |
29 | /* |
30 | * Check the dr_mode against the module configuration and hardware | |
31 | * capabilities. | |
32 | * | |
33 | * The hardware, module, and dr_mode, can each be set to host, device, | |
34 | * or otg. Check that all these values are compatible and adjust the | |
35 | * value of dr_mode if possible. | |
36 | * | |
37 | * actual | |
38 | * HW MOD dr_mode dr_mode | |
39 | * ------------------------------ | |
40 | * HST HST any : HST | |
41 | * HST DEV any : --- | |
42 | * HST OTG any : HST | |
43 | * | |
44 | * DEV HST any : --- | |
45 | * DEV DEV any : DEV | |
46 | * DEV OTG any : DEV | |
47 | * | |
48 | * OTG HST any : HST | |
49 | * OTG DEV any : DEV | |
50 | * OTG OTG any : dr_mode | |
51 | */ | |
52 | static int dwc2_get_dr_mode(struct dwc2_hsotg *hsotg) | |
53 | { | |
54 | enum usb_dr_mode mode; | |
55 | ||
56 | hsotg->dr_mode = usb_get_dr_mode(hsotg->dev); | |
57 | if (hsotg->dr_mode == USB_DR_MODE_UNKNOWN) | |
58 | hsotg->dr_mode = USB_DR_MODE_OTG; | |
59 | ||
60 | mode = hsotg->dr_mode; | |
61 | ||
62 | if (dwc2_hw_is_device(hsotg)) { | |
63 | if (IS_ENABLED(CONFIG_USB_DWC2_HOST)) { | |
64 | dev_err(hsotg->dev, | |
65 | "Controller does not support host mode.\n"); | |
66 | return -EINVAL; | |
67 | } | |
68 | mode = USB_DR_MODE_PERIPHERAL; | |
69 | } else if (dwc2_hw_is_host(hsotg)) { | |
70 | if (IS_ENABLED(CONFIG_USB_DWC2_PERIPHERAL)) { | |
71 | dev_err(hsotg->dev, | |
72 | "Controller does not support device mode.\n"); | |
73 | return -EINVAL; | |
74 | } | |
75 | mode = USB_DR_MODE_HOST; | |
76 | } else { | |
77 | if (IS_ENABLED(CONFIG_USB_DWC2_HOST)) | |
78 | mode = USB_DR_MODE_HOST; | |
79 | else if (IS_ENABLED(CONFIG_USB_DWC2_PERIPHERAL)) | |
80 | mode = USB_DR_MODE_PERIPHERAL; | |
81 | } | |
82 | ||
83 | if (mode != hsotg->dr_mode) { | |
84 | dev_warn(hsotg->dev, | |
9da51974 | 85 | "Configuration mismatch. dr_mode forced to %s\n", |
5268ed9d JY |
86 | mode == USB_DR_MODE_HOST ? "host" : "device"); |
87 | ||
88 | hsotg->dr_mode = mode; | |
89 | } | |
90 | ||
91 | return 0; | |
92 | } | |
93 | ||
09a75e85 MS |
94 | static int __dwc2_lowlevel_hw_enable(struct dwc2_hsotg *hsotg) |
95 | { | |
96 | struct platform_device *pdev = to_platform_device(hsotg->dev); | |
97 | int ret; | |
98 | ||
99 | ret = regulator_bulk_enable(ARRAY_SIZE(hsotg->supplies), | |
100 | hsotg->supplies); | |
101 | if (ret) | |
102 | return ret; | |
103 | ||
02329ade FG |
104 | if (hsotg->utmi_clk) { |
105 | ret = clk_prepare_enable(hsotg->utmi_clk); | |
106 | if (ret) | |
107 | goto err_dis_reg; | |
108 | } | |
109 | ||
8aa90cf2 SW |
110 | if (hsotg->clk) { |
111 | ret = clk_prepare_enable(hsotg->clk); | |
112 | if (ret) | |
02329ade | 113 | goto err_dis_utmi_clk; |
8aa90cf2 | 114 | } |
09a75e85 | 115 | |
34c0887f | 116 | if (hsotg->uphy) { |
09a75e85 | 117 | ret = usb_phy_init(hsotg->uphy); |
34c0887f | 118 | } else if (hsotg->plat && hsotg->plat->phy_init) { |
09a75e85 | 119 | ret = hsotg->plat->phy_init(pdev, hsotg->plat->phy_type); |
34c0887f | 120 | } else { |
f9b995b4 | 121 | ret = phy_init(hsotg->phy); |
236d8353 | 122 | if (ret == 0) { |
f9b995b4 | 123 | ret = phy_power_on(hsotg->phy); |
236d8353 FG |
124 | if (ret) |
125 | phy_exit(hsotg->phy); | |
126 | } | |
09a75e85 MS |
127 | } |
128 | ||
236d8353 FG |
129 | if (ret) |
130 | goto err_dis_clk; | |
131 | ||
132 | return 0; | |
133 | ||
134 | err_dis_clk: | |
135 | if (hsotg->clk) | |
136 | clk_disable_unprepare(hsotg->clk); | |
137 | ||
02329ade FG |
138 | err_dis_utmi_clk: |
139 | if (hsotg->utmi_clk) | |
140 | clk_disable_unprepare(hsotg->utmi_clk); | |
141 | ||
236d8353 FG |
142 | err_dis_reg: |
143 | regulator_bulk_disable(ARRAY_SIZE(hsotg->supplies), hsotg->supplies); | |
144 | ||
09a75e85 MS |
145 | return ret; |
146 | } | |
147 | ||
148 | /** | |
149 | * dwc2_lowlevel_hw_enable - enable platform lowlevel hw resources | |
150 | * @hsotg: The driver state | |
151 | * | |
152 | * A wrapper for platform code responsible for controlling | |
153 | * low-level USB platform resources (phy, clock, regulators) | |
154 | */ | |
155 | int dwc2_lowlevel_hw_enable(struct dwc2_hsotg *hsotg) | |
156 | { | |
157 | int ret = __dwc2_lowlevel_hw_enable(hsotg); | |
158 | ||
159 | if (ret == 0) | |
160 | hsotg->ll_hw_enabled = true; | |
161 | return ret; | |
162 | } | |
163 | ||
164 | static int __dwc2_lowlevel_hw_disable(struct dwc2_hsotg *hsotg) | |
165 | { | |
166 | struct platform_device *pdev = to_platform_device(hsotg->dev); | |
167 | int ret = 0; | |
168 | ||
34c0887f | 169 | if (hsotg->uphy) { |
09a75e85 | 170 | usb_phy_shutdown(hsotg->uphy); |
34c0887f | 171 | } else if (hsotg->plat && hsotg->plat->phy_exit) { |
09a75e85 | 172 | ret = hsotg->plat->phy_exit(pdev, hsotg->plat->phy_type); |
34c0887f | 173 | } else { |
f9b995b4 | 174 | ret = phy_power_off(hsotg->phy); |
09a75e85 | 175 | if (ret == 0) |
f9b995b4 | 176 | ret = phy_exit(hsotg->phy); |
09a75e85 MS |
177 | } |
178 | if (ret) | |
179 | return ret; | |
180 | ||
8aa90cf2 SW |
181 | if (hsotg->clk) |
182 | clk_disable_unprepare(hsotg->clk); | |
09a75e85 | 183 | |
02329ade FG |
184 | if (hsotg->utmi_clk) |
185 | clk_disable_unprepare(hsotg->utmi_clk); | |
186 | ||
f7473132 | 187 | return regulator_bulk_disable(ARRAY_SIZE(hsotg->supplies), hsotg->supplies); |
09a75e85 MS |
188 | } |
189 | ||
190 | /** | |
191 | * dwc2_lowlevel_hw_disable - disable platform lowlevel hw resources | |
192 | * @hsotg: The driver state | |
193 | * | |
194 | * A wrapper for platform code responsible for controlling | |
195 | * low-level USB platform resources (phy, clock, regulators) | |
196 | */ | |
197 | int dwc2_lowlevel_hw_disable(struct dwc2_hsotg *hsotg) | |
198 | { | |
199 | int ret = __dwc2_lowlevel_hw_disable(hsotg); | |
200 | ||
201 | if (ret == 0) | |
202 | hsotg->ll_hw_enabled = false; | |
203 | return ret; | |
204 | } | |
205 | ||
ada050c6 CJ |
206 | static void dwc2_reset_control_assert(void *data) |
207 | { | |
208 | reset_control_assert(data); | |
209 | } | |
210 | ||
09a75e85 MS |
211 | static int dwc2_lowlevel_hw_init(struct dwc2_hsotg *hsotg) |
212 | { | |
213 | int i, ret; | |
214 | ||
83f8da56 | 215 | hsotg->reset = devm_reset_control_get_optional(hsotg->dev, "dwc2"); |
856d3624 AD |
216 | if (IS_ERR(hsotg->reset)) |
217 | return dev_err_probe(hsotg->dev, PTR_ERR(hsotg->reset), | |
218 | "error getting reset control\n"); | |
83f8da56 | 219 | |
8ec32c38 | 220 | reset_control_deassert(hsotg->reset); |
ada050c6 CJ |
221 | ret = devm_add_action_or_reset(hsotg->dev, dwc2_reset_control_assert, |
222 | hsotg->reset); | |
223 | if (ret) | |
224 | return ret; | |
83f8da56 | 225 | |
f2830ad4 | 226 | hsotg->reset_ecc = devm_reset_control_get_optional(hsotg->dev, "dwc2-ecc"); |
856d3624 AD |
227 | if (IS_ERR(hsotg->reset_ecc)) |
228 | return dev_err_probe(hsotg->dev, PTR_ERR(hsotg->reset_ecc), | |
229 | "error getting reset control for ecc\n"); | |
f2830ad4 DN |
230 | |
231 | reset_control_deassert(hsotg->reset_ecc); | |
ada050c6 CJ |
232 | ret = devm_add_action_or_reset(hsotg->dev, dwc2_reset_control_assert, |
233 | hsotg->reset_ecc); | |
234 | if (ret) | |
235 | return ret; | |
f2830ad4 | 236 | |
09a75e85 MS |
237 | /* |
238 | * Attempt to find a generic PHY, then look for an old style | |
239 | * USB PHY and then fall back to pdata | |
240 | */ | |
241 | hsotg->phy = devm_phy_get(hsotg->dev, "usb2-phy"); | |
242 | if (IS_ERR(hsotg->phy)) { | |
6c2dad69 SW |
243 | ret = PTR_ERR(hsotg->phy); |
244 | switch (ret) { | |
245 | case -ENODEV: | |
246 | case -ENOSYS: | |
247 | hsotg->phy = NULL; | |
248 | break; | |
6c2dad69 | 249 | default: |
856d3624 | 250 | return dev_err_probe(hsotg->dev, ret, "error getting phy\n"); |
6c2dad69 SW |
251 | } |
252 | } | |
253 | ||
254 | if (!hsotg->phy) { | |
09a75e85 | 255 | hsotg->uphy = devm_usb_get_phy(hsotg->dev, USB_PHY_TYPE_USB2); |
6c2dad69 SW |
256 | if (IS_ERR(hsotg->uphy)) { |
257 | ret = PTR_ERR(hsotg->uphy); | |
258 | switch (ret) { | |
259 | case -ENODEV: | |
260 | case -ENXIO: | |
261 | hsotg->uphy = NULL; | |
262 | break; | |
6c2dad69 | 263 | default: |
856d3624 | 264 | return dev_err_probe(hsotg->dev, ret, "error getting usb phy\n"); |
6c2dad69 SW |
265 | } |
266 | } | |
09a75e85 MS |
267 | } |
268 | ||
6c2dad69 SW |
269 | hsotg->plat = dev_get_platdata(hsotg->dev); |
270 | ||
09a75e85 | 271 | /* Clock */ |
60722c4e | 272 | hsotg->clk = devm_clk_get_optional(hsotg->dev, "otg"); |
856d3624 AD |
273 | if (IS_ERR(hsotg->clk)) |
274 | return dev_err_probe(hsotg->dev, PTR_ERR(hsotg->clk), "cannot get otg clock\n"); | |
09a75e85 | 275 | |
02329ade FG |
276 | hsotg->utmi_clk = devm_clk_get_optional(hsotg->dev, "utmi"); |
277 | if (IS_ERR(hsotg->utmi_clk)) | |
278 | return dev_err_probe(hsotg->dev, PTR_ERR(hsotg->utmi_clk), | |
279 | "cannot get utmi clock\n"); | |
280 | ||
09a75e85 MS |
281 | /* Regulators */ |
282 | for (i = 0; i < ARRAY_SIZE(hsotg->supplies); i++) | |
283 | hsotg->supplies[i].supply = dwc2_hsotg_supply_names[i]; | |
284 | ||
285 | ret = devm_regulator_bulk_get(hsotg->dev, ARRAY_SIZE(hsotg->supplies), | |
286 | hsotg->supplies); | |
856d3624 AD |
287 | if (ret) |
288 | return dev_err_probe(hsotg->dev, ret, "failed to request supplies\n"); | |
289 | ||
09a75e85 MS |
290 | return 0; |
291 | } | |
292 | ||
5b9974b1 MK |
293 | /** |
294 | * dwc2_driver_remove() - Called when the DWC_otg core is unregistered with the | |
295 | * DWC_otg driver | |
296 | * | |
297 | * @dev: Platform device | |
298 | * | |
299 | * This routine is called, for example, when the rmmod command is executed. The | |
300 | * device may or may not be electrically present. If it is present, the driver | |
301 | * stops device processing. Any resources used on behalf of this device are | |
302 | * freed. | |
303 | */ | |
b519f44b | 304 | static void dwc2_driver_remove(struct platform_device *dev) |
5b9974b1 MK |
305 | { |
306 | struct dwc2_hsotg *hsotg = platform_get_drvdata(dev); | |
a94f0181 | 307 | struct dwc2_gregs_backup *gr; |
b46b1ef7 AP |
308 | int ret = 0; |
309 | ||
a94f0181 AP |
310 | gr = &hsotg->gr_backup; |
311 | ||
312 | /* Exit Hibernation when driver is removed. */ | |
313 | if (hsotg->hibernated) { | |
314 | if (gr->gotgctl & GOTGCTL_CURMODE_HOST) | |
315 | ret = dwc2_exit_hibernation(hsotg, 0, 0, 1); | |
316 | else | |
317 | ret = dwc2_exit_hibernation(hsotg, 0, 0, 0); | |
318 | ||
319 | if (ret) | |
320 | dev_err(hsotg->dev, | |
321 | "exit hibernation failed.\n"); | |
322 | } | |
323 | ||
b46b1ef7 AP |
324 | /* Exit Partial Power Down when driver is removed. */ |
325 | if (hsotg->in_ppd) { | |
326 | ret = dwc2_exit_partial_power_down(hsotg, 0, true); | |
327 | if (ret) | |
328 | dev_err(hsotg->dev, | |
329 | "exit partial_power_down failed\n"); | |
330 | } | |
5b9974b1 | 331 | |
401411bb AP |
332 | /* Exit clock gating when driver is removed. */ |
333 | if (hsotg->params.power_down == DWC2_POWER_DOWN_PARAM_NONE && | |
31f42da3 | 334 | hsotg->bus_suspended && !hsotg->params.no_clock_gating) { |
401411bb AP |
335 | if (dwc2_is_device_mode(hsotg)) |
336 | dwc2_gadget_exit_clock_gating(hsotg, 0); | |
337 | else | |
338 | dwc2_host_exit_clock_gating(hsotg, 0); | |
339 | } | |
340 | ||
f91eea44 | 341 | dwc2_debugfs_exit(hsotg); |
e39af88f MS |
342 | if (hsotg->hcd_enabled) |
343 | dwc2_hcd_remove(hsotg); | |
344 | if (hsotg->gadget_enabled) | |
1f91b4cc | 345 | dwc2_hsotg_remove(hsotg); |
5b9974b1 | 346 | |
17f93402 AD |
347 | dwc2_drd_exit(hsotg); |
348 | ||
a415083a AD |
349 | if (hsotg->params.activate_stm_id_vb_detection) |
350 | regulator_disable(hsotg->usb33d); | |
351 | ||
09a75e85 MS |
352 | if (hsotg->ll_hw_enabled) |
353 | dwc2_lowlevel_hw_disable(hsotg); | |
5b9974b1 MK |
354 | } |
355 | ||
a40a0031 HS |
356 | /** |
357 | * dwc2_driver_shutdown() - Called on device shutdown | |
358 | * | |
359 | * @dev: Platform device | |
360 | * | |
361 | * In specific conditions (involving usb hubs) dwc2 devices can create a | |
362 | * lot of interrupts, even to the point of overwhelming devices running | |
363 | * at low frequencies. Some devices need to do special clock handling | |
364 | * at shutdown-time which may bring the system clock below the threshold | |
365 | * of being able to handle the dwc2 interrupts. Disabling dwc2-irqs | |
366 | * prevents reboots/poweroffs from getting stuck in such cases. | |
367 | */ | |
368 | static void dwc2_driver_shutdown(struct platform_device *dev) | |
369 | { | |
370 | struct dwc2_hsotg *hsotg = platform_get_drvdata(dev); | |
371 | ||
4fdf228c MH |
372 | dwc2_disable_global_interrupts(hsotg); |
373 | synchronize_irq(hsotg->irq); | |
a40a0031 HS |
374 | } |
375 | ||
fe369e18 GS |
376 | /** |
377 | * dwc2_check_core_endianness() - Returns true if core and AHB have | |
378 | * opposite endianness. | |
379 | * @hsotg: Programming view of the DWC_otg controller. | |
380 | */ | |
381 | static bool dwc2_check_core_endianness(struct dwc2_hsotg *hsotg) | |
382 | { | |
383 | u32 snpsid; | |
384 | ||
385 | snpsid = ioread32(hsotg->regs + GSNPSID); | |
386 | if ((snpsid & GSNPSID_ID_MASK) == DWC2_OTG_ID || | |
387 | (snpsid & GSNPSID_ID_MASK) == DWC2_FS_IOT_ID || | |
388 | (snpsid & GSNPSID_ID_MASK) == DWC2_HS_IOT_ID) | |
389 | return false; | |
390 | return true; | |
391 | } | |
392 | ||
65dc2e72 | 393 | /** |
c1fb8640 | 394 | * dwc2_check_core_version() - Check core version |
65dc2e72 MH |
395 | * |
396 | * @hsotg: Programming view of the DWC_otg controller | |
397 | * | |
398 | */ | |
399 | int dwc2_check_core_version(struct dwc2_hsotg *hsotg) | |
400 | { | |
401 | struct dwc2_hw_params *hw = &hsotg->hw_params; | |
402 | ||
403 | /* | |
404 | * Attempt to ensure this device is really a DWC_otg Controller. | |
405 | * Read and verify the GSNPSID register contents. The value should be | |
406 | * 0x45f4xxxx, 0x5531xxxx or 0x5532xxxx | |
407 | */ | |
408 | ||
409 | hw->snpsid = dwc2_readl(hsotg, GSNPSID); | |
410 | if ((hw->snpsid & GSNPSID_ID_MASK) != DWC2_OTG_ID && | |
411 | (hw->snpsid & GSNPSID_ID_MASK) != DWC2_FS_IOT_ID && | |
412 | (hw->snpsid & GSNPSID_ID_MASK) != DWC2_HS_IOT_ID) { | |
413 | dev_err(hsotg->dev, "Bad value for GSNPSID: 0x%08x\n", | |
414 | hw->snpsid); | |
415 | return -ENODEV; | |
416 | } | |
417 | ||
418 | dev_dbg(hsotg->dev, "Core Release: %1x.%1x%1x%1x (snpsid=%x)\n", | |
419 | hw->snpsid >> 12 & 0xf, hw->snpsid >> 8 & 0xf, | |
420 | hw->snpsid >> 4 & 0xf, hw->snpsid & 0xf, hw->snpsid); | |
421 | return 0; | |
422 | } | |
423 | ||
5b9974b1 MK |
424 | /** |
425 | * dwc2_driver_probe() - Called when the DWC_otg core is bound to the DWC_otg | |
426 | * driver | |
427 | * | |
428 | * @dev: Platform device | |
429 | * | |
430 | * This routine creates the driver components required to control the device | |
431 | * (core, HCD, and PCD) and initializes the device. The driver components are | |
432 | * stored in a dwc2_hsotg structure. A reference to the dwc2_hsotg is saved | |
433 | * in the device private data. This allows the driver to access the dwc2_hsotg | |
434 | * structure on subsequent calls to driver methods for this device. | |
435 | */ | |
436 | static int dwc2_driver_probe(struct platform_device *dev) | |
437 | { | |
438 | struct dwc2_hsotg *hsotg; | |
439 | struct resource *res; | |
440 | int retval; | |
5b9974b1 | 441 | |
5b9974b1 MK |
442 | hsotg = devm_kzalloc(&dev->dev, sizeof(*hsotg), GFP_KERNEL); |
443 | if (!hsotg) | |
444 | return -ENOMEM; | |
445 | ||
446 | hsotg->dev = &dev->dev; | |
447 | ||
642f2ecc MK |
448 | /* |
449 | * Use reasonable defaults so platforms don't have to provide these. | |
450 | */ | |
451 | if (!dev->dev.dma_mask) | |
452 | dev->dev.dma_mask = &dev->dev.coherent_dma_mask; | |
4cdbb4ff | 453 | retval = dma_set_coherent_mask(&dev->dev, DMA_BIT_MASK(32)); |
42c6a252 SW |
454 | if (retval) { |
455 | dev_err(&dev->dev, "can't set coherent DMA mask: %d\n", retval); | |
4cdbb4ff | 456 | return retval; |
42c6a252 | 457 | } |
642f2ecc | 458 | |
5bf7e288 | 459 | hsotg->regs = devm_platform_get_and_ioremap_resource(dev, 0, &res); |
5b9974b1 MK |
460 | if (IS_ERR(hsotg->regs)) |
461 | return PTR_ERR(hsotg->regs); | |
462 | ||
463 | dev_dbg(&dev->dev, "mapped PA %08lx to VA %p\n", | |
464 | (unsigned long)res->start, hsotg->regs); | |
465 | ||
09a75e85 | 466 | retval = dwc2_lowlevel_hw_init(hsotg); |
ecb176c6 MYK |
467 | if (retval) |
468 | return retval; | |
469 | ||
09a75e85 MS |
470 | spin_lock_init(&hsotg->lock); |
471 | ||
a40a0031 | 472 | hsotg->irq = platform_get_irq(dev, 0); |
b33f3706 | 473 | if (hsotg->irq < 0) |
a40a0031 | 474 | return hsotg->irq; |
f74875dc SW |
475 | |
476 | dev_dbg(hsotg->dev, "registering common handler for irq%d\n", | |
a40a0031 HS |
477 | hsotg->irq); |
478 | retval = devm_request_irq(hsotg->dev, hsotg->irq, | |
f74875dc SW |
479 | dwc2_handle_common_intr, IRQF_SHARED, |
480 | dev_name(hsotg->dev), hsotg); | |
481 | if (retval) | |
482 | return retval; | |
483 | ||
e0f681c2 FG |
484 | hsotg->vbus_supply = devm_regulator_get_optional(hsotg->dev, "vbus"); |
485 | if (IS_ERR(hsotg->vbus_supply)) { | |
486 | retval = PTR_ERR(hsotg->vbus_supply); | |
487 | hsotg->vbus_supply = NULL; | |
488 | if (retval != -ENODEV) | |
489 | return retval; | |
490 | } | |
491 | ||
09a75e85 MS |
492 | retval = dwc2_lowlevel_hw_enable(hsotg); |
493 | if (retval) | |
494 | return retval; | |
495 | ||
d9707490 BMH |
496 | hsotg->needs_byte_swap = dwc2_check_core_endianness(hsotg); |
497 | ||
5268ed9d JY |
498 | retval = dwc2_get_dr_mode(hsotg); |
499 | if (retval) | |
a6ef3e02 | 500 | goto error; |
5268ed9d | 501 | |
c846b03f DA |
502 | hsotg->need_phy_for_wake = |
503 | of_property_read_bool(dev->dev.of_node, | |
504 | "snps,need-phy-for-wake"); | |
505 | ||
65dc2e72 MH |
506 | /* |
507 | * Before performing any core related operations | |
508 | * check core version. | |
509 | */ | |
510 | retval = dwc2_check_core_version(hsotg); | |
511 | if (retval) | |
512 | goto error; | |
513 | ||
03b32e4c JY |
514 | /* |
515 | * Reset before dwc2_get_hwparams() then it could get power-on real | |
516 | * reset value form registers. | |
517 | */ | |
13b1f8e2 VM |
518 | retval = dwc2_core_reset(hsotg, false); |
519 | if (retval) | |
520 | goto error; | |
03b32e4c JY |
521 | |
522 | /* Detect config values from hardware */ | |
09a75e85 MS |
523 | retval = dwc2_get_hwparams(hsotg); |
524 | if (retval) | |
525 | goto error; | |
526 | ||
13b1f8e2 VM |
527 | /* |
528 | * For OTG cores, set the force mode bits to reflect the value | |
529 | * of dr_mode. Force mode bits should not be touched at any | |
530 | * other time after this. | |
531 | */ | |
25362d31 | 532 | dwc2_force_dr_mode(hsotg); |
263b7fb5 | 533 | |
334bbd4e JY |
534 | retval = dwc2_init_params(hsotg); |
535 | if (retval) | |
536 | goto error; | |
537 | ||
a415083a AD |
538 | if (hsotg->params.activate_stm_id_vb_detection) { |
539 | u32 ggpio; | |
540 | ||
541 | hsotg->usb33d = devm_regulator_get(hsotg->dev, "usb33d"); | |
542 | if (IS_ERR(hsotg->usb33d)) { | |
543 | retval = PTR_ERR(hsotg->usb33d); | |
856d3624 | 544 | dev_err_probe(hsotg->dev, retval, "failed to request usb33d supply\n"); |
a415083a AD |
545 | goto error; |
546 | } | |
547 | retval = regulator_enable(hsotg->usb33d); | |
548 | if (retval) { | |
856d3624 | 549 | dev_err_probe(hsotg->dev, retval, "failed to enable usb33d supply\n"); |
a415083a AD |
550 | goto error; |
551 | } | |
552 | ||
553 | ggpio = dwc2_readl(hsotg, GGPIO); | |
554 | ggpio |= GGPIO_STM32_OTG_GCCFG_IDEN; | |
555 | ggpio |= GGPIO_STM32_OTG_GCCFG_VBDEN; | |
556 | dwc2_writel(hsotg, ggpio, GGPIO); | |
fac6bf87 AD |
557 | |
558 | /* ID/VBUS detection startup time */ | |
559 | usleep_range(5000, 7000); | |
a415083a AD |
560 | } |
561 | ||
17f93402 AD |
562 | retval = dwc2_drd_init(hsotg); |
563 | if (retval) { | |
856d3624 | 564 | dev_err_probe(hsotg->dev, retval, "failed to initialize dual-role\n"); |
17f93402 AD |
565 | goto error_init; |
566 | } | |
567 | ||
e39af88f | 568 | if (hsotg->dr_mode != USB_DR_MODE_HOST) { |
f3768997 | 569 | retval = dwc2_gadget_init(hsotg); |
e39af88f | 570 | if (retval) |
17f93402 | 571 | goto error_drd; |
e39af88f MS |
572 | hsotg->gadget_enabled = 1; |
573 | } | |
574 | ||
c846b03f DA |
575 | /* |
576 | * If we need PHY for wakeup we must be wakeup capable. | |
577 | * When we have a device that can wake without the PHY we | |
578 | * can adjust this condition. | |
579 | */ | |
580 | if (hsotg->need_phy_for_wake) | |
581 | device_set_wakeup_capable(&dev->dev, true); | |
582 | ||
c40cf770 DA |
583 | hsotg->reset_phy_on_wake = |
584 | of_property_read_bool(dev->dev.of_node, | |
585 | "snps,reset-phy-on-wake"); | |
586 | if (hsotg->reset_phy_on_wake && !hsotg->phy) { | |
587 | dev_warn(hsotg->dev, | |
588 | "Quirk reset-phy-on-wake only supports generic PHYs\n"); | |
589 | hsotg->reset_phy_on_wake = false; | |
590 | } | |
591 | ||
e39af88f | 592 | if (hsotg->dr_mode != USB_DR_MODE_PERIPHERAL) { |
4fe160d5 | 593 | retval = dwc2_hcd_init(hsotg); |
e39af88f MS |
594 | if (retval) { |
595 | if (hsotg->gadget_enabled) | |
1f91b4cc | 596 | dwc2_hsotg_remove(hsotg); |
17f93402 | 597 | goto error_drd; |
e39af88f MS |
598 | } |
599 | hsotg->hcd_enabled = 1; | |
600 | } | |
5b9974b1 MK |
601 | |
602 | platform_set_drvdata(dev, hsotg); | |
20fe4409 | 603 | hsotg->hibernated = 0; |
5b9974b1 | 604 | |
f91eea44 MYK |
605 | dwc2_debugfs_init(hsotg); |
606 | ||
09a75e85 | 607 | /* Gadget code manages lowlevel hw on its own */ |
50213832 | 608 | if (hsotg->dr_mode == USB_DR_MODE_PERIPHERAL) |
09a75e85 MS |
609 | dwc2_lowlevel_hw_disable(hsotg); |
610 | ||
207324a3 MH |
611 | #if IS_ENABLED(CONFIG_USB_DWC2_PERIPHERAL) || \ |
612 | IS_ENABLED(CONFIG_USB_DWC2_DUAL_ROLE) | |
613 | /* Postponed adding a new gadget to the udc class driver list */ | |
614 | if (hsotg->gadget_enabled) { | |
615 | retval = usb_add_gadget_udc(hsotg->dev, &hsotg->gadget); | |
616 | if (retval) { | |
33a06f13 | 617 | hsotg->gadget.udc = NULL; |
207324a3 | 618 | dwc2_hsotg_remove(hsotg); |
e1c08cf2 | 619 | goto error_debugfs; |
207324a3 MH |
620 | } |
621 | } | |
622 | #endif /* CONFIG_USB_DWC2_PERIPHERAL || CONFIG_USB_DWC2_DUAL_ROLE */ | |
09a75e85 MS |
623 | return 0; |
624 | ||
190bb01b MB |
625 | #if IS_ENABLED(CONFIG_USB_DWC2_PERIPHERAL) || \ |
626 | IS_ENABLED(CONFIG_USB_DWC2_DUAL_ROLE) | |
e1c08cf2 MB |
627 | error_debugfs: |
628 | dwc2_debugfs_exit(hsotg); | |
629 | if (hsotg->hcd_enabled) | |
630 | dwc2_hcd_remove(hsotg); | |
190bb01b | 631 | #endif |
17f93402 AD |
632 | error_drd: |
633 | dwc2_drd_exit(hsotg); | |
634 | ||
a415083a AD |
635 | error_init: |
636 | if (hsotg->params.activate_stm_id_vb_detection) | |
637 | regulator_disable(hsotg->usb33d); | |
09a75e85 | 638 | error: |
f7473132 | 639 | if (hsotg->ll_hw_enabled) |
33a06f13 | 640 | dwc2_lowlevel_hw_disable(hsotg); |
5b9974b1 MK |
641 | return retval; |
642 | } | |
643 | ||
da9f3289 | 644 | static int __maybe_unused dwc2_suspend(struct device *dev) |
117777b2 | 645 | { |
bcc06078 | 646 | struct dwc2_hsotg *dwc2 = dev_get_drvdata(dev); |
c846b03f | 647 | bool is_device_mode = dwc2_is_device_mode(dwc2); |
117777b2 DN |
648 | int ret = 0; |
649 | ||
c846b03f | 650 | if (is_device_mode) |
09a75e85 MS |
651 | dwc2_hsotg_suspend(dwc2); |
652 | ||
17f93402 AD |
653 | dwc2_drd_suspend(dwc2); |
654 | ||
a415083a AD |
655 | if (dwc2->params.activate_stm_id_vb_detection) { |
656 | unsigned long flags; | |
657 | u32 ggpio, gotgctl; | |
658 | ||
659 | /* | |
660 | * Need to force the mode to the current mode to avoid Mode | |
661 | * Mismatch Interrupt when ID detection will be disabled. | |
662 | */ | |
663 | dwc2_force_mode(dwc2, !is_device_mode); | |
664 | ||
665 | spin_lock_irqsave(&dwc2->lock, flags); | |
666 | gotgctl = dwc2_readl(dwc2, GOTGCTL); | |
667 | /* bypass debounce filter, enable overrides */ | |
668 | gotgctl |= GOTGCTL_DBNCE_FLTR_BYPASS; | |
669 | gotgctl |= GOTGCTL_BVALOEN | GOTGCTL_AVALOEN; | |
670 | /* Force A / B session if needed */ | |
671 | if (gotgctl & GOTGCTL_ASESVLD) | |
672 | gotgctl |= GOTGCTL_AVALOVAL; | |
673 | if (gotgctl & GOTGCTL_BSESVLD) | |
674 | gotgctl |= GOTGCTL_BVALOVAL; | |
675 | dwc2_writel(dwc2, gotgctl, GOTGCTL); | |
676 | spin_unlock_irqrestore(&dwc2->lock, flags); | |
677 | ||
678 | ggpio = dwc2_readl(dwc2, GGPIO); | |
679 | ggpio &= ~GGPIO_STM32_OTG_GCCFG_IDEN; | |
680 | ggpio &= ~GGPIO_STM32_OTG_GCCFG_VBDEN; | |
681 | dwc2_writel(dwc2, ggpio, GGPIO); | |
682 | ||
683 | regulator_disable(dwc2->usb33d); | |
684 | } | |
685 | ||
c846b03f DA |
686 | if (dwc2->ll_hw_enabled && |
687 | (is_device_mode || dwc2_host_can_poweroff_phy(dwc2))) { | |
09a75e85 | 688 | ret = __dwc2_lowlevel_hw_disable(dwc2); |
c846b03f DA |
689 | dwc2->phy_off_for_suspend = true; |
690 | } | |
135b3c43 | 691 | |
117777b2 DN |
692 | return ret; |
693 | } | |
694 | ||
da9f3289 | 695 | static int __maybe_unused dwc2_resume(struct device *dev) |
117777b2 | 696 | { |
bcc06078 | 697 | struct dwc2_hsotg *dwc2 = dev_get_drvdata(dev); |
117777b2 DN |
698 | int ret = 0; |
699 | ||
c846b03f | 700 | if (dwc2->phy_off_for_suspend && dwc2->ll_hw_enabled) { |
09a75e85 MS |
701 | ret = __dwc2_lowlevel_hw_enable(dwc2); |
702 | if (ret) | |
703 | return ret; | |
704 | } | |
c846b03f | 705 | dwc2->phy_off_for_suspend = false; |
09a75e85 | 706 | |
a415083a AD |
707 | if (dwc2->params.activate_stm_id_vb_detection) { |
708 | unsigned long flags; | |
709 | u32 ggpio, gotgctl; | |
710 | ||
711 | ret = regulator_enable(dwc2->usb33d); | |
712 | if (ret) | |
713 | return ret; | |
714 | ||
715 | ggpio = dwc2_readl(dwc2, GGPIO); | |
716 | ggpio |= GGPIO_STM32_OTG_GCCFG_IDEN; | |
717 | ggpio |= GGPIO_STM32_OTG_GCCFG_VBDEN; | |
718 | dwc2_writel(dwc2, ggpio, GGPIO); | |
719 | ||
720 | /* ID/VBUS detection startup time */ | |
721 | usleep_range(5000, 7000); | |
722 | ||
723 | spin_lock_irqsave(&dwc2->lock, flags); | |
724 | gotgctl = dwc2_readl(dwc2, GOTGCTL); | |
725 | gotgctl &= ~GOTGCTL_DBNCE_FLTR_BYPASS; | |
726 | gotgctl &= ~(GOTGCTL_BVALOEN | GOTGCTL_AVALOEN | | |
727 | GOTGCTL_BVALOVAL | GOTGCTL_AVALOVAL); | |
728 | dwc2_writel(dwc2, gotgctl, GOTGCTL); | |
729 | spin_unlock_irqrestore(&dwc2->lock, flags); | |
730 | } | |
731 | ||
3ad02e0e FG |
732 | if (!dwc2->role_sw) { |
733 | /* Need to restore FORCEDEVMODE/FORCEHOSTMODE */ | |
734 | dwc2_force_dr_mode(dwc2); | |
735 | } else { | |
736 | dwc2_drd_resume(dwc2); | |
737 | } | |
17f93402 | 738 | |
09a75e85 | 739 | if (dwc2_is_device_mode(dwc2)) |
1f91b4cc | 740 | ret = dwc2_hsotg_resume(dwc2); |
135b3c43 | 741 | |
117777b2 DN |
742 | return ret; |
743 | } | |
744 | ||
bcc06078 DN |
745 | static const struct dev_pm_ops dwc2_dev_pm_ops = { |
746 | SET_SYSTEM_SLEEP_PM_OPS(dwc2_suspend, dwc2_resume) | |
747 | }; | |
748 | ||
5b9974b1 MK |
749 | static struct platform_driver dwc2_platform_driver = { |
750 | .driver = { | |
1c126bc6 | 751 | .name = dwc2_driver_name, |
5b9974b1 | 752 | .of_match_table = dwc2_of_match_table, |
2e5db2c0 | 753 | .acpi_match_table = ACPI_PTR(dwc2_acpi_match), |
bcc06078 | 754 | .pm = &dwc2_dev_pm_ops, |
5b9974b1 MK |
755 | }, |
756 | .probe = dwc2_driver_probe, | |
b519f44b | 757 | .remove_new = dwc2_driver_remove, |
a40a0031 | 758 | .shutdown = dwc2_driver_shutdown, |
5b9974b1 MK |
759 | }; |
760 | ||
761 | module_platform_driver(dwc2_platform_driver); |