2 * SAMSUNG S5P USB HOST EHCI Controller
4 * Copyright (C) 2011 Samsung Electronics Co.Ltd
5 * Author: Jingoo Han <jg1.han@samsung.com>
6 * Author: Joonyoung Shim <jy0922.shim@samsung.com>
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the
10 * Free Software Foundation; either version 2 of the License, or (at your
11 * option) any later version.
15 #include <linux/clk.h>
16 #include <linux/dma-mapping.h>
18 #include <linux/kernel.h>
19 #include <linux/module.h>
21 #include <linux/of_gpio.h>
22 #include <linux/platform_device.h>
23 #include <linux/platform_data/usb-ehci-s5p.h>
24 #include <linux/usb/phy.h>
25 #include <linux/usb/samsung_usb_phy.h>
26 #include <linux/usb.h>
27 #include <linux/usb/hcd.h>
28 #include <linux/usb/otg.h>
32 #define DRIVER_DESC "EHCI s5p driver"
34 #define EHCI_INSNREG00(base) (base + 0x90)
35 #define EHCI_INSNREG00_ENA_INCR16 (0x1 << 25)
36 #define EHCI_INSNREG00_ENA_INCR8 (0x1 << 24)
37 #define EHCI_INSNREG00_ENA_INCR4 (0x1 << 23)
38 #define EHCI_INSNREG00_ENA_INCRX_ALIGN (0x1 << 22)
39 #define EHCI_INSNREG00_ENABLE_DMA_BURST \
40 (EHCI_INSNREG00_ENA_INCR16 | EHCI_INSNREG00_ENA_INCR8 | \
41 EHCI_INSNREG00_ENA_INCR4 | EHCI_INSNREG00_ENA_INCRX_ALIGN)
43 static const char hcd_name
[] = "ehci-s5p";
44 static struct hc_driver __read_mostly s5p_ehci_hc_driver
;
50 struct s5p_ehci_platdata
*pdata
;
53 #define to_s5p_ehci(hcd) (struct s5p_ehci_hcd *)(hcd_to_ehci(hcd)->priv)
55 static void s5p_setup_vbus_gpio(struct platform_device
*pdev
)
57 struct device
*dev
= &pdev
->dev
;
64 gpio
= of_get_named_gpio(dev
->of_node
, "samsung,vbus-gpio", 0);
65 if (!gpio_is_valid(gpio
))
68 err
= devm_gpio_request_one(dev
, gpio
, GPIOF_OUT_INIT_HIGH
,
71 dev_err(dev
, "can't request ehci vbus gpio %d", gpio
);
74 static int s5p_ehci_probe(struct platform_device
*pdev
)
76 struct s5p_ehci_platdata
*pdata
= pdev
->dev
.platform_data
;
77 struct s5p_ehci_hcd
*s5p_ehci
;
79 struct ehci_hcd
*ehci
;
86 * Right now device-tree probed devices don't get dma_mask set.
87 * Since shared usb code relies on it, set it here for now.
88 * Once we move to full device tree support this will vanish off.
90 if (!pdev
->dev
.dma_mask
)
91 pdev
->dev
.dma_mask
= &pdev
->dev
.coherent_dma_mask
;
92 if (!pdev
->dev
.coherent_dma_mask
)
93 pdev
->dev
.coherent_dma_mask
= DMA_BIT_MASK(32);
95 s5p_setup_vbus_gpio(pdev
);
97 hcd
= usb_create_hcd(&s5p_ehci_hc_driver
,
98 &pdev
->dev
, dev_name(&pdev
->dev
));
100 dev_err(&pdev
->dev
, "Unable to create HCD\n");
103 s5p_ehci
= to_s5p_ehci(hcd
);
104 phy
= devm_usb_get_phy(&pdev
->dev
, USB_PHY_TYPE_USB2
);
106 /* Fallback to pdata */
109 dev_warn(&pdev
->dev
, "no platform data or transceiver defined\n");
110 return -EPROBE_DEFER
;
112 s5p_ehci
->pdata
= pdata
;
116 s5p_ehci
->otg
= phy
->otg
;
119 s5p_ehci
->clk
= devm_clk_get(&pdev
->dev
, "usbhost");
121 if (IS_ERR(s5p_ehci
->clk
)) {
122 dev_err(&pdev
->dev
, "Failed to get usbhost clock\n");
123 err
= PTR_ERR(s5p_ehci
->clk
);
127 err
= clk_prepare_enable(s5p_ehci
->clk
);
131 res
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
133 dev_err(&pdev
->dev
, "Failed to get I/O memory\n");
138 hcd
->rsrc_start
= res
->start
;
139 hcd
->rsrc_len
= resource_size(res
);
140 hcd
->regs
= devm_ioremap(&pdev
->dev
, res
->start
, hcd
->rsrc_len
);
142 dev_err(&pdev
->dev
, "Failed to remap I/O memory\n");
147 irq
= platform_get_irq(pdev
, 0);
149 dev_err(&pdev
->dev
, "Failed to get IRQ\n");
155 s5p_ehci
->otg
->set_host(s5p_ehci
->otg
, &hcd
->self
);
158 usb_phy_init(s5p_ehci
->phy
);
159 else if (s5p_ehci
->pdata
->phy_init
)
160 s5p_ehci
->pdata
->phy_init(pdev
, USB_PHY_TYPE_HOST
);
162 ehci
= hcd_to_ehci(hcd
);
163 ehci
->caps
= hcd
->regs
;
165 /* DMA burst Enable */
166 writel(EHCI_INSNREG00_ENABLE_DMA_BURST
, EHCI_INSNREG00(hcd
->regs
));
168 err
= usb_add_hcd(hcd
, irq
, IRQF_SHARED
);
170 dev_err(&pdev
->dev
, "Failed to add USB HCD\n");
174 platform_set_drvdata(pdev
, hcd
);
180 usb_phy_shutdown(s5p_ehci
->phy
);
181 else if (s5p_ehci
->pdata
->phy_exit
)
182 s5p_ehci
->pdata
->phy_exit(pdev
, USB_PHY_TYPE_HOST
);
184 clk_disable_unprepare(s5p_ehci
->clk
);
190 static int s5p_ehci_remove(struct platform_device
*pdev
)
192 struct usb_hcd
*hcd
= platform_get_drvdata(pdev
);
193 struct s5p_ehci_hcd
*s5p_ehci
= to_s5p_ehci(hcd
);
198 s5p_ehci
->otg
->set_host(s5p_ehci
->otg
, &hcd
->self
);
201 usb_phy_shutdown(s5p_ehci
->phy
);
202 else if (s5p_ehci
->pdata
->phy_exit
)
203 s5p_ehci
->pdata
->phy_exit(pdev
, USB_PHY_TYPE_HOST
);
205 clk_disable_unprepare(s5p_ehci
->clk
);
212 static void s5p_ehci_shutdown(struct platform_device
*pdev
)
214 struct usb_hcd
*hcd
= platform_get_drvdata(pdev
);
216 if (hcd
->driver
->shutdown
)
217 hcd
->driver
->shutdown(hcd
);
221 static int s5p_ehci_suspend(struct device
*dev
)
223 struct usb_hcd
*hcd
= dev_get_drvdata(dev
);
224 struct s5p_ehci_hcd
*s5p_ehci
= to_s5p_ehci(hcd
);
225 struct platform_device
*pdev
= to_platform_device(dev
);
227 bool do_wakeup
= device_may_wakeup(dev
);
230 rc
= ehci_suspend(hcd
, do_wakeup
);
233 s5p_ehci
->otg
->set_host(s5p_ehci
->otg
, &hcd
->self
);
236 usb_phy_shutdown(s5p_ehci
->phy
);
237 else if (s5p_ehci
->pdata
->phy_exit
)
238 s5p_ehci
->pdata
->phy_exit(pdev
, USB_PHY_TYPE_HOST
);
240 clk_disable_unprepare(s5p_ehci
->clk
);
245 static int s5p_ehci_resume(struct device
*dev
)
247 struct usb_hcd
*hcd
= dev_get_drvdata(dev
);
248 struct s5p_ehci_hcd
*s5p_ehci
= to_s5p_ehci(hcd
);
249 struct platform_device
*pdev
= to_platform_device(dev
);
251 clk_prepare_enable(s5p_ehci
->clk
);
254 s5p_ehci
->otg
->set_host(s5p_ehci
->otg
, &hcd
->self
);
257 usb_phy_init(s5p_ehci
->phy
);
258 else if (s5p_ehci
->pdata
->phy_init
)
259 s5p_ehci
->pdata
->phy_init(pdev
, USB_PHY_TYPE_HOST
);
261 /* DMA burst Enable */
262 writel(EHCI_INSNREG00_ENABLE_DMA_BURST
, EHCI_INSNREG00(hcd
->regs
));
264 ehci_resume(hcd
, false);
268 #define s5p_ehci_suspend NULL
269 #define s5p_ehci_resume NULL
272 static const struct dev_pm_ops s5p_ehci_pm_ops
= {
273 .suspend
= s5p_ehci_suspend
,
274 .resume
= s5p_ehci_resume
,
278 static const struct of_device_id exynos_ehci_match
[] = {
279 { .compatible
= "samsung,exynos4210-ehci" },
282 MODULE_DEVICE_TABLE(of
, exynos_ehci_match
);
285 static struct platform_driver s5p_ehci_driver
= {
286 .probe
= s5p_ehci_probe
,
287 .remove
= s5p_ehci_remove
,
288 .shutdown
= s5p_ehci_shutdown
,
291 .owner
= THIS_MODULE
,
292 .pm
= &s5p_ehci_pm_ops
,
293 .of_match_table
= of_match_ptr(exynos_ehci_match
),
296 static const struct ehci_driver_overrides s5p_overrides __initdata
= {
297 .extra_priv_size
= sizeof(struct s5p_ehci_hcd
),
300 static int __init
ehci_s5p_init(void)
305 pr_info("%s: " DRIVER_DESC
"\n", hcd_name
);
306 ehci_init_driver(&s5p_ehci_hc_driver
, &s5p_overrides
);
307 return platform_driver_register(&s5p_ehci_driver
);
309 module_init(ehci_s5p_init
);
311 static void __exit
ehci_s5p_cleanup(void)
313 platform_driver_unregister(&s5p_ehci_driver
);
315 module_exit(ehci_s5p_cleanup
);
317 MODULE_DESCRIPTION(DRIVER_DESC
);
318 MODULE_ALIAS("platform:s5p-ehci");
319 MODULE_AUTHOR("Jingoo Han");
320 MODULE_AUTHOR("Joonyoung Shim");
321 MODULE_LICENSE("GPL v2");