]> git.proxmox.com Git - mirror_ubuntu-jammy-kernel.git/blame - drivers/usb/host/ehci-spear.c
USB: add SPDX identifiers to all remaining files in drivers/usb/
[mirror_ubuntu-jammy-kernel.git] / drivers / usb / host / ehci-spear.c
CommitLineData
5fd54ace 1// SPDX-License-Identifier: GPL-2.0
c8c38de9 2/*
7675d6ba 3* Driver for EHCI HCD on SPEAr SOC
c8c38de9
DS
4*
5* Copyright (C) 2010 ST Micro Electronics,
6* Deepak Sikri <deepak.sikri@st.com>
7*
8* Based on various ehci-*.c drivers
9*
10* This file is subject to the terms and conditions of the GNU General Public
11* License. See the file COPYING in the main directory of this archive for
12* more details.
13*/
14
c8c38de9 15#include <linux/clk.h>
7675d6ba
MG
16#include <linux/dma-mapping.h>
17#include <linux/io.h>
8c1b3693 18#include <linux/jiffies.h>
7675d6ba
MG
19#include <linux/kernel.h>
20#include <linux/module.h>
56fafb94 21#include <linux/of.h>
8c1b3693
DS
22#include <linux/platform_device.h>
23#include <linux/pm.h>
7675d6ba
MG
24#include <linux/usb.h>
25#include <linux/usb/hcd.h>
c8c38de9 26
7675d6ba 27#include "ehci.h"
c8c38de9 28
7675d6ba 29#define DRIVER_DESC "EHCI SPEAr driver"
c8c38de9 30
7675d6ba 31static const char hcd_name[] = "SPEAr-ehci";
c8c38de9 32
7675d6ba
MG
33struct spear_ehci {
34 struct clk *clk;
35};
c8c38de9 36
7675d6ba 37#define to_spear_ehci(hcd) (struct spear_ehci *)(hcd_to_ehci(hcd)->priv)
c8c38de9 38
7675d6ba 39static struct hc_driver __read_mostly ehci_spear_hc_driver;
c8c38de9 40
ab1f046a 41#ifdef CONFIG_PM_SLEEP
8c1b3693
DS
42static int ehci_spear_drv_suspend(struct device *dev)
43{
44 struct usb_hcd *hcd = dev_get_drvdata(dev);
c5cf9212
AS
45 bool do_wakeup = device_may_wakeup(dev);
46
47 return ehci_suspend(hcd, do_wakeup);
8c1b3693
DS
48}
49
50static int ehci_spear_drv_resume(struct device *dev)
51{
52 struct usb_hcd *hcd = dev_get_drvdata(dev);
8c1b3693 53
c5cf9212 54 ehci_resume(hcd, false);
8c1b3693
DS
55 return 0;
56}
ab1f046a 57#endif /* CONFIG_PM_SLEEP */
8c1b3693
DS
58
59static SIMPLE_DEV_PM_OPS(ehci_spear_pm_ops, ehci_spear_drv_suspend,
60 ehci_spear_drv_resume);
61
c8c38de9
DS
62static int spear_ehci_hcd_drv_probe(struct platform_device *pdev)
63{
64 struct usb_hcd *hcd ;
7675d6ba 65 struct spear_ehci *sehci;
c8c38de9
DS
66 struct resource *res;
67 struct clk *usbh_clk;
68 const struct hc_driver *driver = &ehci_spear_hc_driver;
c8c38de9 69 int irq, retval;
c8c38de9
DS
70
71 if (usb_disabled())
72 return -ENODEV;
73
74 irq = platform_get_irq(pdev, 0);
75 if (irq < 0) {
76 retval = irq;
98515e59 77 goto fail;
c8c38de9
DS
78 }
79
56fafb94
SR
80 /*
81 * Right now device-tree probed devices don't get dma_mask set.
82 * Since shared usb code relies on it, set it here for now.
83 * Once we have dma capability bindings this can go away.
84 */
e1fd7341 85 retval = dma_coerce_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
22d9d8e8
RK
86 if (retval)
87 goto fail;
56fafb94 88
98515e59 89 usbh_clk = devm_clk_get(&pdev->dev, NULL);
c8c38de9
DS
90 if (IS_ERR(usbh_clk)) {
91 dev_err(&pdev->dev, "Error getting interface clock\n");
92 retval = PTR_ERR(usbh_clk);
98515e59 93 goto fail;
c8c38de9
DS
94 }
95
96 hcd = usb_create_hcd(driver, &pdev->dev, dev_name(&pdev->dev));
97 if (!hcd) {
98 retval = -ENOMEM;
98515e59 99 goto fail;
c8c38de9
DS
100 }
101
102 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
e0f77a91
VG
103 hcd->regs = devm_ioremap_resource(&pdev->dev, res);
104 if (IS_ERR(hcd->regs)) {
105 retval = PTR_ERR(hcd->regs);
98515e59 106 goto err_put_hcd;
c8c38de9 107 }
3b59d31d
VB
108 hcd->rsrc_start = res->start;
109 hcd->rsrc_len = resource_size(res);
c8c38de9 110
7675d6ba
MG
111 sehci = to_spear_ehci(hcd);
112 sehci->clk = usbh_clk;
113
114 /* registers start at offset 0x0 */
115 hcd_to_ehci(hcd)->caps = hcd->regs;
c8c38de9 116
7675d6ba 117 clk_prepare_enable(sehci->clk);
b5dd18d8 118 retval = usb_add_hcd(hcd, irq, IRQF_SHARED);
c8c38de9 119 if (retval)
98515e59 120 goto err_stop_ehci;
c8c38de9 121
3c9740a1 122 device_wakeup_enable(hcd->self.controller);
c8c38de9
DS
123 return retval;
124
98515e59 125err_stop_ehci:
7675d6ba 126 clk_disable_unprepare(sehci->clk);
98515e59 127err_put_hcd:
c8c38de9 128 usb_put_hcd(hcd);
98515e59 129fail:
c8c38de9
DS
130 dev_err(&pdev->dev, "init fail, %d\n", retval);
131
132 return retval ;
133}
134
135static int spear_ehci_hcd_drv_remove(struct platform_device *pdev)
136{
137 struct usb_hcd *hcd = platform_get_drvdata(pdev);
7675d6ba 138 struct spear_ehci *sehci = to_spear_ehci(hcd);
c8c38de9 139
c8c38de9
DS
140 usb_remove_hcd(hcd);
141
7675d6ba
MG
142 if (sehci->clk)
143 clk_disable_unprepare(sehci->clk);
c8c38de9
DS
144 usb_put_hcd(hcd);
145
c8c38de9
DS
146 return 0;
147}
148
3632eba5 149static const struct of_device_id spear_ehci_id_table[] = {
56fafb94
SR
150 { .compatible = "st,spear600-ehci", },
151 { },
152};
e76eaefd 153MODULE_DEVICE_TABLE(of, spear_ehci_id_table);
56fafb94 154
c8c38de9
DS
155static struct platform_driver spear_ehci_hcd_driver = {
156 .probe = spear_ehci_hcd_drv_probe,
157 .remove = spear_ehci_hcd_drv_remove,
158 .shutdown = usb_hcd_platform_shutdown,
159 .driver = {
160 .name = "spear-ehci",
8c1b3693
DS
161 .bus = &platform_bus_type,
162 .pm = &ehci_spear_pm_ops,
2c398f3e 163 .of_match_table = spear_ehci_id_table,
c8c38de9
DS
164 }
165};
166
edc8c54b 167static const struct ehci_driver_overrides spear_overrides __initconst = {
7675d6ba
MG
168 .extra_priv_size = sizeof(struct spear_ehci),
169};
170
171static int __init ehci_spear_init(void)
172{
173 if (usb_disabled())
174 return -ENODEV;
175
176 pr_info("%s: " DRIVER_DESC "\n", hcd_name);
177
178 ehci_init_driver(&ehci_spear_hc_driver, &spear_overrides);
179 return platform_driver_register(&spear_ehci_hcd_driver);
180}
181module_init(ehci_spear_init);
182
183static void __exit ehci_spear_cleanup(void)
184{
185 platform_driver_unregister(&spear_ehci_hcd_driver);
186}
187module_exit(ehci_spear_cleanup);
188
189MODULE_DESCRIPTION(DRIVER_DESC);
c8c38de9 190MODULE_ALIAS("platform:spear-ehci");
7675d6ba
MG
191MODULE_AUTHOR("Deepak Sikri");
192MODULE_LICENSE("GPL");