ehci-w90x900.c 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * linux/driver/usb/host/ehci-w90x900.c
  4. *
  5. * Copyright (c) 2008 Nuvoton technology corporation.
  6. *
  7. * Wan ZongShun <mcuos.com@gmail.com>
  8. */
  9. #include <linux/dma-mapping.h>
  10. #include <linux/io.h>
  11. #include <linux/kernel.h>
  12. #include <linux/module.h>
  13. #include <linux/of.h>
  14. #include <linux/platform_device.h>
  15. #include <linux/usb.h>
  16. #include <linux/usb/hcd.h>
  17. #include "ehci.h"
  18. /* enable phy0 and phy1 for w90p910 */
  19. #define ENPHY (0x01<<8)
  20. #define PHY0_CTR (0xA4)
  21. #define PHY1_CTR (0xA8)
  22. #define DRIVER_DESC "EHCI w90x900 driver"
  23. static const char hcd_name[] = "ehci-w90x900 ";
  24. static struct hc_driver __read_mostly ehci_w90x900_hc_driver;
  25. static int ehci_w90x900_probe(struct platform_device *pdev)
  26. {
  27. struct usb_hcd *hcd;
  28. struct ehci_hcd *ehci;
  29. struct resource *res;
  30. int retval = 0, irq;
  31. unsigned long val;
  32. hcd = usb_create_hcd(&ehci_w90x900_hc_driver,
  33. &pdev->dev, "w90x900 EHCI");
  34. if (!hcd) {
  35. retval = -ENOMEM;
  36. goto err1;
  37. }
  38. res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
  39. hcd->regs = devm_ioremap_resource(&pdev->dev, res);
  40. if (IS_ERR(hcd->regs)) {
  41. retval = PTR_ERR(hcd->regs);
  42. goto err2;
  43. }
  44. hcd->rsrc_start = res->start;
  45. hcd->rsrc_len = resource_size(res);
  46. ehci = hcd_to_ehci(hcd);
  47. ehci->caps = hcd->regs;
  48. ehci->regs = hcd->regs +
  49. HC_LENGTH(ehci, ehci_readl(ehci, &ehci->caps->hc_capbase));
  50. /* enable PHY 0,1,the regs only apply to w90p910
  51. * 0xA4,0xA8 were offsets of PHY0 and PHY1 controller of
  52. * w90p910 IC relative to ehci->regs.
  53. */
  54. val = __raw_readl(ehci->regs+PHY0_CTR);
  55. val |= ENPHY;
  56. __raw_writel(val, ehci->regs+PHY0_CTR);
  57. val = __raw_readl(ehci->regs+PHY1_CTR);
  58. val |= ENPHY;
  59. __raw_writel(val, ehci->regs+PHY1_CTR);
  60. irq = platform_get_irq(pdev, 0);
  61. if (irq < 0) {
  62. retval = irq;
  63. goto err2;
  64. }
  65. retval = usb_add_hcd(hcd, irq, IRQF_SHARED);
  66. if (retval != 0)
  67. goto err2;
  68. device_wakeup_enable(hcd->self.controller);
  69. return retval;
  70. err2:
  71. usb_put_hcd(hcd);
  72. err1:
  73. return retval;
  74. }
  75. static int ehci_w90x900_remove(struct platform_device *pdev)
  76. {
  77. struct usb_hcd *hcd = platform_get_drvdata(pdev);
  78. usb_remove_hcd(hcd);
  79. usb_put_hcd(hcd);
  80. return 0;
  81. }
  82. static struct platform_driver ehci_hcd_w90x900_driver = {
  83. .probe = ehci_w90x900_probe,
  84. .remove = ehci_w90x900_remove,
  85. .driver = {
  86. .name = "w90x900-ehci",
  87. },
  88. };
  89. static int __init ehci_w90X900_init(void)
  90. {
  91. if (usb_disabled())
  92. return -ENODEV;
  93. pr_info("%s: " DRIVER_DESC "\n", hcd_name);
  94. ehci_init_driver(&ehci_w90x900_hc_driver, NULL);
  95. return platform_driver_register(&ehci_hcd_w90x900_driver);
  96. }
  97. module_init(ehci_w90X900_init);
  98. static void __exit ehci_w90X900_cleanup(void)
  99. {
  100. platform_driver_unregister(&ehci_hcd_w90x900_driver);
  101. }
  102. module_exit(ehci_w90X900_cleanup);
  103. MODULE_DESCRIPTION(DRIVER_DESC);
  104. MODULE_AUTHOR("Wan ZongShun <mcuos.com@gmail.com>");
  105. MODULE_ALIAS("platform:w90p910-ehci");
  106. MODULE_LICENSE("GPL v2");