1 // SPDX-License-Identifier: GPL-2.0+
3 * Copyright (C) 2011 Marvell International Ltd. All rights reserved.
4 * Author: Chao Xie <chao.xie@marvell.com>
5 * Neil Zhang <zhangwm@marvell.com>
8 #include <linux/kernel.h>
9 #include <linux/module.h>
10 #include <linux/platform_device.h>
11 #include <linux/clk.h>
12 #include <linux/err.h>
13 #include <linux/usb/otg.h>
14 #include <linux/usb/of.h>
15 #include <linux/platform_data/mv_usb.h>
18 #include <linux/usb/hcd.h>
23 #define U2x_CAPREGS_OFFSET 0x100
25 #define CAPLENGTH_MASK (0xff)
27 #define hcd_to_ehci_hcd_mv(h) ((struct ehci_hcd_mv *)hcd_to_ehci(h)->priv)
30 /* Which mode does this ehci running OTG/Host ? */
34 void __iomem
*cap_regs
;
35 void __iomem
*op_regs
;
42 int (*set_vbus
)(unsigned int vbus
);
45 static void ehci_clock_enable(struct ehci_hcd_mv
*ehci_mv
)
47 clk_prepare_enable(ehci_mv
->clk
);
50 static void ehci_clock_disable(struct ehci_hcd_mv
*ehci_mv
)
52 clk_disable_unprepare(ehci_mv
->clk
);
55 static int mv_ehci_enable(struct ehci_hcd_mv
*ehci_mv
)
57 ehci_clock_enable(ehci_mv
);
58 return phy_init(ehci_mv
->phy
);
61 static void mv_ehci_disable(struct ehci_hcd_mv
*ehci_mv
)
63 phy_exit(ehci_mv
->phy
);
64 ehci_clock_disable(ehci_mv
);
67 static int mv_ehci_reset(struct usb_hcd
*hcd
)
69 struct device
*dev
= hcd
->self
.controller
;
70 struct ehci_hcd_mv
*ehci_mv
= hcd_to_ehci_hcd_mv(hcd
);
71 struct ehci_hcd
*ehci
= hcd_to_ehci(hcd
);
75 if (ehci_mv
== NULL
) {
76 dev_err(dev
, "Can not find private ehci data\n");
82 retval
= ehci_setup(hcd
);
84 dev_err(dev
, "ehci_setup failed %d\n", retval
);
86 if (of_usb_get_phy_mode(dev
->of_node
) == USBPHY_INTERFACE_MODE_HSIC
) {
87 status
= ehci_readl(ehci
, &ehci
->regs
->port_status
[0]);
88 status
|= PORT_TEST_FORCE
;
89 ehci_writel(ehci
, status
, &ehci
->regs
->port_status
[0]);
90 status
&= ~PORT_TEST_FORCE
;
91 ehci_writel(ehci
, status
, &ehci
->regs
->port_status
[0]);
97 static struct hc_driver __read_mostly ehci_platform_hc_driver
;
99 static const struct ehci_driver_overrides platform_overrides __initconst
= {
100 .reset
= mv_ehci_reset
,
101 .extra_priv_size
= sizeof(struct ehci_hcd_mv
),
104 static int mv_ehci_probe(struct platform_device
*pdev
)
106 struct mv_usb_platform_data
*pdata
= dev_get_platdata(&pdev
->dev
);
108 struct ehci_hcd
*ehci
;
109 struct ehci_hcd_mv
*ehci_mv
;
111 int retval
= -ENODEV
;
118 hcd
= usb_create_hcd(&ehci_platform_hc_driver
, &pdev
->dev
, dev_name(&pdev
->dev
));
122 platform_set_drvdata(pdev
, hcd
);
123 ehci_mv
= hcd_to_ehci_hcd_mv(hcd
);
125 ehci_mv
->mode
= MV_USB_MODE_HOST
;
127 ehci_mv
->mode
= pdata
->mode
;
128 ehci_mv
->set_vbus
= pdata
->set_vbus
;
131 ehci_mv
->phy
= devm_phy_optional_get(&pdev
->dev
, "usb");
132 if (IS_ERR(ehci_mv
->phy
)) {
133 retval
= PTR_ERR(ehci_mv
->phy
);
134 if (retval
!= -EPROBE_DEFER
)
135 dev_err(&pdev
->dev
, "Failed to get phy.\n");
139 ehci_mv
->clk
= devm_clk_get(&pdev
->dev
, NULL
);
140 if (IS_ERR(ehci_mv
->clk
)) {
141 dev_err(&pdev
->dev
, "error getting clock\n");
142 retval
= PTR_ERR(ehci_mv
->clk
);
148 r
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
149 ehci_mv
->base
= devm_ioremap_resource(&pdev
->dev
, r
);
150 if (IS_ERR(ehci_mv
->base
)) {
151 retval
= PTR_ERR(ehci_mv
->base
);
155 retval
= mv_ehci_enable(ehci_mv
);
157 dev_err(&pdev
->dev
, "init phy error %d\n", retval
);
162 (void __iomem
*) ((unsigned long) ehci_mv
->base
+ U2x_CAPREGS_OFFSET
);
163 offset
= readl(ehci_mv
->cap_regs
) & CAPLENGTH_MASK
;
165 (void __iomem
*) ((unsigned long) ehci_mv
->cap_regs
+ offset
);
167 hcd
->rsrc_start
= r
->start
;
168 hcd
->rsrc_len
= resource_size(r
);
169 hcd
->regs
= ehci_mv
->op_regs
;
171 hcd
->irq
= platform_get_irq(pdev
, 0);
173 dev_err(&pdev
->dev
, "Cannot get irq.");
175 goto err_disable_clk
;
178 ehci
= hcd_to_ehci(hcd
);
179 ehci
->caps
= (struct ehci_caps __iomem
*) ehci_mv
->cap_regs
;
181 if (ehci_mv
->mode
== MV_USB_MODE_OTG
) {
182 ehci_mv
->otg
= devm_usb_get_phy(&pdev
->dev
, USB_PHY_TYPE_USB2
);
183 if (IS_ERR(ehci_mv
->otg
)) {
184 retval
= PTR_ERR(ehci_mv
->otg
);
186 if (retval
== -ENXIO
)
187 dev_info(&pdev
->dev
, "MV_USB_MODE_OTG "
188 "must have CONFIG_USB_PHY enabled\n");
191 "unable to find transceiver\n");
192 goto err_disable_clk
;
195 retval
= otg_set_host(ehci_mv
->otg
->otg
, &hcd
->self
);
198 "unable to register with transceiver\n");
200 goto err_disable_clk
;
202 /* otg will enable clock before use as host */
203 mv_ehci_disable(ehci_mv
);
205 if (ehci_mv
->set_vbus
)
206 ehci_mv
->set_vbus(1);
208 retval
= usb_add_hcd(hcd
, hcd
->irq
, IRQF_SHARED
);
211 "failed to add hcd with err %d\n", retval
);
214 device_wakeup_enable(hcd
->self
.controller
);
217 if (of_usb_get_phy_mode(pdev
->dev
.of_node
) == USBPHY_INTERFACE_MODE_HSIC
) {
218 status
= ehci_readl(ehci
, &ehci
->regs
->port_status
[0]);
219 /* These "reserved" bits actually enable HSIC mode. */
221 status
&= ~GENMASK(31, 30);
222 ehci_writel(ehci
, status
, &ehci
->regs
->port_status
[0]);
226 "successful find EHCI device with regs 0x%p irq %d"
227 " working in %s mode\n", hcd
->regs
, hcd
->irq
,
228 ehci_mv
->mode
== MV_USB_MODE_OTG
? "OTG" : "Host");
233 if (ehci_mv
->set_vbus
)
234 ehci_mv
->set_vbus(0);
236 mv_ehci_disable(ehci_mv
);
243 static int mv_ehci_remove(struct platform_device
*pdev
)
245 struct usb_hcd
*hcd
= platform_get_drvdata(pdev
);
246 struct ehci_hcd_mv
*ehci_mv
= hcd_to_ehci_hcd_mv(hcd
);
248 if (hcd
->rh_registered
)
251 if (!IS_ERR_OR_NULL(ehci_mv
->otg
))
252 otg_set_host(ehci_mv
->otg
->otg
, NULL
);
254 if (ehci_mv
->mode
== MV_USB_MODE_HOST
) {
255 if (ehci_mv
->set_vbus
)
256 ehci_mv
->set_vbus(0);
258 mv_ehci_disable(ehci_mv
);
266 MODULE_ALIAS("mv-ehci");
268 static const struct platform_device_id ehci_id_table
[] = {
274 static void mv_ehci_shutdown(struct platform_device
*pdev
)
276 struct usb_hcd
*hcd
= platform_get_drvdata(pdev
);
278 if (!hcd
->rh_registered
)
281 if (hcd
->driver
->shutdown
)
282 hcd
->driver
->shutdown(hcd
);
285 static const struct of_device_id ehci_mv_dt_ids
[] = {
286 { .compatible
= "marvell,pxau2o-ehci", },
290 static struct platform_driver ehci_mv_driver
= {
291 .probe
= mv_ehci_probe
,
292 .remove
= mv_ehci_remove
,
293 .shutdown
= mv_ehci_shutdown
,
296 .bus
= &platform_bus_type
,
297 .of_match_table
= ehci_mv_dt_ids
,
299 .id_table
= ehci_id_table
,
302 static int __init
ehci_platform_init(void)
307 ehci_init_driver(&ehci_platform_hc_driver
, &platform_overrides
);
308 return platform_driver_register(&ehci_mv_driver
);
310 module_init(ehci_platform_init
);
312 static void __exit
ehci_platform_cleanup(void)
314 platform_driver_unregister(&ehci_mv_driver
);
316 module_exit(ehci_platform_cleanup
);
318 MODULE_DESCRIPTION("Marvell EHCI driver");
319 MODULE_AUTHOR("Chao Xie <chao.xie@marvell.com>");
320 MODULE_AUTHOR("Neil Zhang <zhangwm@marvell.com>");
321 MODULE_ALIAS("mv-ehci");
322 MODULE_LICENSE("GPL");
323 MODULE_DEVICE_TABLE(of
, ehci_mv_dt_ids
);