.. | .. |
---|
18 | 18 | #include <linux/clk.h> |
---|
19 | 19 | #include <linux/dma-mapping.h> |
---|
20 | 20 | #include <linux/err.h> |
---|
21 | | -#include <linux/gpio.h> |
---|
| 21 | +#include <linux/gpio/consumer.h> |
---|
22 | 22 | #include <linux/io.h> |
---|
23 | 23 | #include <linux/jiffies.h> |
---|
24 | 24 | #include <linux/kernel.h> |
---|
.. | .. |
---|
53 | 53 | |
---|
54 | 54 | #define DRIVER_DESC "OHCI OMAP driver" |
---|
55 | 55 | |
---|
56 | | -#ifdef CONFIG_TPS65010 |
---|
57 | | -#include <linux/mfd/tps65010.h> |
---|
58 | | -#else |
---|
59 | | - |
---|
60 | | -#define LOW 0 |
---|
61 | | -#define HIGH 1 |
---|
62 | | - |
---|
63 | | -#define GPIO1 1 |
---|
64 | | - |
---|
65 | | -static inline int tps65010_set_gpio_out_value(unsigned gpio, unsigned value) |
---|
66 | | -{ |
---|
67 | | - return 0; |
---|
68 | | -} |
---|
69 | | - |
---|
70 | | -#endif |
---|
71 | | - |
---|
72 | | -static struct clk *usb_host_ck; |
---|
73 | | -static struct clk *usb_dc_ck; |
---|
| 56 | +struct ohci_omap_priv { |
---|
| 57 | + struct clk *usb_host_ck; |
---|
| 58 | + struct clk *usb_dc_ck; |
---|
| 59 | + struct gpio_desc *power; |
---|
| 60 | + struct gpio_desc *overcurrent; |
---|
| 61 | +}; |
---|
74 | 62 | |
---|
75 | 63 | static const char hcd_name[] = "ohci-omap"; |
---|
76 | 64 | static struct hc_driver __read_mostly ohci_omap_hc_driver; |
---|
77 | 65 | |
---|
78 | | -static void omap_ohci_clock_power(int on) |
---|
| 66 | +#define hcd_to_ohci_omap_priv(h) \ |
---|
| 67 | + ((struct ohci_omap_priv *)hcd_to_ohci(h)->priv) |
---|
| 68 | + |
---|
| 69 | +static void omap_ohci_clock_power(struct ohci_omap_priv *priv, int on) |
---|
79 | 70 | { |
---|
80 | 71 | if (on) { |
---|
81 | | - clk_enable(usb_dc_ck); |
---|
82 | | - clk_enable(usb_host_ck); |
---|
| 72 | + clk_enable(priv->usb_dc_ck); |
---|
| 73 | + clk_enable(priv->usb_host_ck); |
---|
83 | 74 | /* guesstimate for T5 == 1x 32K clock + APLL lock time */ |
---|
84 | 75 | udelay(100); |
---|
85 | 76 | } else { |
---|
86 | | - clk_disable(usb_host_ck); |
---|
87 | | - clk_disable(usb_dc_ck); |
---|
| 77 | + clk_disable(priv->usb_host_ck); |
---|
| 78 | + clk_disable(priv->usb_dc_ck); |
---|
88 | 79 | } |
---|
89 | 80 | } |
---|
90 | 81 | |
---|
.. | .. |
---|
92 | 83 | * Board specific gang-switched transceiver power on/off. |
---|
93 | 84 | * NOTE: OSK supplies power from DC, not battery. |
---|
94 | 85 | */ |
---|
95 | | -static int omap_ohci_transceiver_power(int on) |
---|
| 86 | +static int omap_ohci_transceiver_power(struct ohci_omap_priv *priv, int on) |
---|
96 | 87 | { |
---|
97 | 88 | if (on) { |
---|
98 | 89 | if (machine_is_omap_innovator() && cpu_is_omap1510()) |
---|
99 | 90 | __raw_writeb(__raw_readb(INNOVATOR_FPGA_CAM_USB_CONTROL) |
---|
100 | 91 | | ((1 << 5/*usb1*/) | (1 << 3/*usb2*/)), |
---|
101 | 92 | INNOVATOR_FPGA_CAM_USB_CONTROL); |
---|
102 | | - else if (machine_is_omap_osk()) |
---|
103 | | - tps65010_set_gpio_out_value(GPIO1, LOW); |
---|
| 93 | + else if (priv->power) |
---|
| 94 | + gpiod_set_value_cansleep(priv->power, 0); |
---|
104 | 95 | } else { |
---|
105 | 96 | if (machine_is_omap_innovator() && cpu_is_omap1510()) |
---|
106 | 97 | __raw_writeb(__raw_readb(INNOVATOR_FPGA_CAM_USB_CONTROL) |
---|
107 | 98 | & ~((1 << 5/*usb1*/) | (1 << 3/*usb2*/)), |
---|
108 | 99 | INNOVATOR_FPGA_CAM_USB_CONTROL); |
---|
109 | | - else if (machine_is_omap_osk()) |
---|
110 | | - tps65010_set_gpio_out_value(GPIO1, HIGH); |
---|
| 100 | + else if (priv->power) |
---|
| 101 | + gpiod_set_value_cansleep(priv->power, 1); |
---|
111 | 102 | } |
---|
112 | 103 | |
---|
113 | 104 | return 0; |
---|
.. | .. |
---|
196 | 187 | { |
---|
197 | 188 | struct ohci_hcd *ohci = hcd_to_ohci(hcd); |
---|
198 | 189 | struct omap_usb_config *config = dev_get_platdata(hcd->self.controller); |
---|
| 190 | + struct ohci_omap_priv *priv = hcd_to_ohci_omap_priv(hcd); |
---|
199 | 191 | int need_transceiver = (config->otg != 0); |
---|
200 | 192 | int ret; |
---|
201 | 193 | |
---|
.. | .. |
---|
235 | 227 | } |
---|
236 | 228 | #endif |
---|
237 | 229 | |
---|
238 | | - omap_ohci_clock_power(1); |
---|
| 230 | + omap_ohci_clock_power(priv, 1); |
---|
239 | 231 | |
---|
240 | 232 | if (cpu_is_omap15xx()) { |
---|
241 | 233 | omap_1510_local_bus_power(1); |
---|
.. | .. |
---|
266 | 258 | |
---|
267 | 259 | /* gpio9 for overcurrent detction */ |
---|
268 | 260 | omap_cfg_reg(W8_1610_GPIO9); |
---|
269 | | - gpio_request(9, "OHCI overcurrent"); |
---|
270 | | - gpio_direction_input(9); |
---|
271 | 261 | |
---|
272 | 262 | /* for paranoia's sake: disable USB.PUEN */ |
---|
273 | 263 | omap_cfg_reg(W4_USB_HIGHZ); |
---|
.. | .. |
---|
281 | 271 | } |
---|
282 | 272 | |
---|
283 | 273 | /* FIXME hub_wq hub requests should manage power switching */ |
---|
284 | | - omap_ohci_transceiver_power(1); |
---|
| 274 | + omap_ohci_transceiver_power(priv, 1); |
---|
285 | 275 | |
---|
286 | 276 | /* board init will have already handled HMC and mux setup. |
---|
287 | 277 | * any external transceiver should already be initialized |
---|
.. | .. |
---|
305 | 295 | { |
---|
306 | 296 | int retval, irq; |
---|
307 | 297 | struct usb_hcd *hcd = 0; |
---|
| 298 | + struct ohci_omap_priv *priv; |
---|
308 | 299 | |
---|
309 | 300 | if (pdev->num_resources != 2) { |
---|
310 | 301 | dev_err(&pdev->dev, "invalid num_resources: %i\n", |
---|
.. | .. |
---|
318 | 309 | return -ENODEV; |
---|
319 | 310 | } |
---|
320 | 311 | |
---|
321 | | - usb_host_ck = clk_get(&pdev->dev, "usb_hhc_ck"); |
---|
322 | | - if (IS_ERR(usb_host_ck)) |
---|
323 | | - return PTR_ERR(usb_host_ck); |
---|
324 | | - |
---|
325 | | - if (!cpu_is_omap15xx()) |
---|
326 | | - usb_dc_ck = clk_get(&pdev->dev, "usb_dc_ck"); |
---|
327 | | - else |
---|
328 | | - usb_dc_ck = clk_get(&pdev->dev, "lb_ck"); |
---|
329 | | - |
---|
330 | | - if (IS_ERR(usb_dc_ck)) { |
---|
331 | | - clk_put(usb_host_ck); |
---|
332 | | - return PTR_ERR(usb_dc_ck); |
---|
333 | | - } |
---|
334 | | - |
---|
335 | | - |
---|
336 | 312 | hcd = usb_create_hcd(&ohci_omap_hc_driver, &pdev->dev, |
---|
337 | 313 | dev_name(&pdev->dev)); |
---|
338 | | - if (!hcd) { |
---|
339 | | - retval = -ENOMEM; |
---|
340 | | - goto err0; |
---|
341 | | - } |
---|
| 314 | + if (!hcd) |
---|
| 315 | + return -ENOMEM; |
---|
| 316 | + |
---|
342 | 317 | hcd->rsrc_start = pdev->resource[0].start; |
---|
343 | 318 | hcd->rsrc_len = pdev->resource[0].end - pdev->resource[0].start + 1; |
---|
| 319 | + priv = hcd_to_ohci_omap_priv(hcd); |
---|
| 320 | + |
---|
| 321 | + /* Obtain two optional GPIO lines */ |
---|
| 322 | + priv->power = devm_gpiod_get_optional(&pdev->dev, "power", GPIOD_ASIS); |
---|
| 323 | + if (IS_ERR(priv->power)) { |
---|
| 324 | + retval = PTR_ERR(priv->power); |
---|
| 325 | + goto err_put_hcd; |
---|
| 326 | + } |
---|
| 327 | + if (priv->power) |
---|
| 328 | + gpiod_set_consumer_name(priv->power, "OHCI power"); |
---|
| 329 | + |
---|
| 330 | + /* |
---|
| 331 | + * This "overcurrent" GPIO line isn't really used in the code, |
---|
| 332 | + * but has a designated hardware function. |
---|
| 333 | + * TODO: implement proper overcurrent handling. |
---|
| 334 | + */ |
---|
| 335 | + priv->overcurrent = devm_gpiod_get_optional(&pdev->dev, "overcurrent", |
---|
| 336 | + GPIOD_IN); |
---|
| 337 | + if (IS_ERR(priv->overcurrent)) { |
---|
| 338 | + retval = PTR_ERR(priv->overcurrent); |
---|
| 339 | + goto err_put_hcd; |
---|
| 340 | + } |
---|
| 341 | + if (priv->overcurrent) |
---|
| 342 | + gpiod_set_consumer_name(priv->overcurrent, "OHCI overcurrent"); |
---|
| 343 | + |
---|
| 344 | + priv->usb_host_ck = clk_get(&pdev->dev, "usb_hhc_ck"); |
---|
| 345 | + if (IS_ERR(priv->usb_host_ck)) { |
---|
| 346 | + retval = PTR_ERR(priv->usb_host_ck); |
---|
| 347 | + goto err_put_hcd; |
---|
| 348 | + } |
---|
| 349 | + |
---|
| 350 | + if (!cpu_is_omap15xx()) |
---|
| 351 | + priv->usb_dc_ck = clk_get(&pdev->dev, "usb_dc_ck"); |
---|
| 352 | + else |
---|
| 353 | + priv->usb_dc_ck = clk_get(&pdev->dev, "lb_ck"); |
---|
| 354 | + |
---|
| 355 | + if (IS_ERR(priv->usb_dc_ck)) { |
---|
| 356 | + retval = PTR_ERR(priv->usb_dc_ck); |
---|
| 357 | + goto err_put_host_ck; |
---|
| 358 | + } |
---|
344 | 359 | |
---|
345 | 360 | if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) { |
---|
346 | 361 | dev_dbg(&pdev->dev, "request_mem_region failed\n"); |
---|
347 | 362 | retval = -EBUSY; |
---|
348 | | - goto err1; |
---|
| 363 | + goto err_put_dc_ck; |
---|
349 | 364 | } |
---|
350 | 365 | |
---|
351 | 366 | hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len); |
---|
.. | .. |
---|
370 | 385 | iounmap(hcd->regs); |
---|
371 | 386 | err2: |
---|
372 | 387 | release_mem_region(hcd->rsrc_start, hcd->rsrc_len); |
---|
373 | | -err1: |
---|
| 388 | +err_put_dc_ck: |
---|
| 389 | + clk_put(priv->usb_dc_ck); |
---|
| 390 | +err_put_host_ck: |
---|
| 391 | + clk_put(priv->usb_host_ck); |
---|
| 392 | +err_put_hcd: |
---|
374 | 393 | usb_put_hcd(hcd); |
---|
375 | | -err0: |
---|
376 | | - clk_put(usb_dc_ck); |
---|
377 | | - clk_put(usb_host_ck); |
---|
378 | 394 | return retval; |
---|
379 | 395 | } |
---|
380 | 396 | |
---|
.. | .. |
---|
393 | 409 | static int ohci_hcd_omap_remove(struct platform_device *pdev) |
---|
394 | 410 | { |
---|
395 | 411 | struct usb_hcd *hcd = platform_get_drvdata(pdev); |
---|
| 412 | + struct ohci_omap_priv *priv = hcd_to_ohci_omap_priv(hcd); |
---|
396 | 413 | |
---|
397 | 414 | dev_dbg(hcd->self.controller, "stopping USB Controller\n"); |
---|
398 | 415 | usb_remove_hcd(hcd); |
---|
399 | | - omap_ohci_clock_power(0); |
---|
| 416 | + omap_ohci_clock_power(priv, 0); |
---|
400 | 417 | if (!IS_ERR_OR_NULL(hcd->usb_phy)) { |
---|
401 | 418 | (void) otg_set_host(hcd->usb_phy->otg, 0); |
---|
402 | 419 | usb_put_phy(hcd->usb_phy); |
---|
403 | 420 | } |
---|
404 | | - if (machine_is_omap_osk()) |
---|
405 | | - gpio_free(9); |
---|
406 | 421 | iounmap(hcd->regs); |
---|
407 | 422 | release_mem_region(hcd->rsrc_start, hcd->rsrc_len); |
---|
| 423 | + clk_put(priv->usb_dc_ck); |
---|
| 424 | + clk_put(priv->usb_host_ck); |
---|
408 | 425 | usb_put_hcd(hcd); |
---|
409 | | - clk_put(usb_dc_ck); |
---|
410 | | - clk_put(usb_host_ck); |
---|
411 | 426 | return 0; |
---|
412 | 427 | } |
---|
413 | 428 | |
---|
.. | .. |
---|
419 | 434 | { |
---|
420 | 435 | struct usb_hcd *hcd = platform_get_drvdata(pdev); |
---|
421 | 436 | struct ohci_hcd *ohci = hcd_to_ohci(hcd); |
---|
| 437 | + struct ohci_omap_priv *priv = hcd_to_ohci_omap_priv(hcd); |
---|
422 | 438 | bool do_wakeup = device_may_wakeup(&pdev->dev); |
---|
423 | 439 | int ret; |
---|
424 | 440 | |
---|
.. | .. |
---|
430 | 446 | if (ret) |
---|
431 | 447 | return ret; |
---|
432 | 448 | |
---|
433 | | - omap_ohci_clock_power(0); |
---|
| 449 | + omap_ohci_clock_power(priv, 0); |
---|
434 | 450 | return ret; |
---|
435 | 451 | } |
---|
436 | 452 | |
---|
.. | .. |
---|
438 | 454 | { |
---|
439 | 455 | struct usb_hcd *hcd = platform_get_drvdata(dev); |
---|
440 | 456 | struct ohci_hcd *ohci = hcd_to_ohci(hcd); |
---|
| 457 | + struct ohci_omap_priv *priv = hcd_to_ohci_omap_priv(hcd); |
---|
441 | 458 | |
---|
442 | 459 | if (time_before(jiffies, ohci->next_statechange)) |
---|
443 | 460 | msleep(5); |
---|
444 | 461 | ohci->next_statechange = jiffies; |
---|
445 | 462 | |
---|
446 | | - omap_ohci_clock_power(1); |
---|
| 463 | + omap_ohci_clock_power(priv, 1); |
---|
447 | 464 | ohci_resume(hcd, false); |
---|
448 | 465 | return 0; |
---|
449 | 466 | } |
---|
.. | .. |
---|
470 | 487 | |
---|
471 | 488 | static const struct ohci_driver_overrides omap_overrides __initconst = { |
---|
472 | 489 | .product_desc = "OMAP OHCI", |
---|
473 | | - .reset = ohci_omap_reset |
---|
| 490 | + .reset = ohci_omap_reset, |
---|
| 491 | + .extra_priv_size = sizeof(struct ohci_omap_priv), |
---|
474 | 492 | }; |
---|
475 | 493 | |
---|
476 | 494 | static int __init ohci_omap_init(void) |
---|