2 * SAMSUNG EXYNOS USB HOST OHCI Controller
4 * Copyright (C) 2011 Samsung Electronics Co.Ltd
5 * Author: Jingoo Han <jg1.han@samsung.com>
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation; either version 2 of the License, or (at your
10 * option) any later version.
14 #include <linux/clk.h>
15 #include <linux/dma-mapping.h>
17 #include <linux/kernel.h>
18 #include <linux/module.h>
20 #include <linux/platform_device.h>
21 #include <linux/usb/phy.h>
22 #include <linux/usb/samsung_usb_phy.h>
23 #include <linux/usb.h>
24 #include <linux/usb/hcd.h>
25 #include <linux/usb/otg.h>
29 #define DRIVER_DESC "OHCI EXYNOS driver"
31 static const char hcd_name
[] = "ohci-exynos";
32 static struct hc_driver __read_mostly exynos_ohci_hc_driver
;
34 #define to_exynos_ohci(hcd) (struct exynos_ohci_hcd *)(hcd_to_ohci(hcd)->priv)
36 struct exynos_ohci_hcd
{
42 static void exynos_ohci_phy_enable(struct platform_device
*pdev
)
44 struct usb_hcd
*hcd
= platform_get_drvdata(pdev
);
45 struct exynos_ohci_hcd
*exynos_ohci
= to_exynos_ohci(hcd
);
48 usb_phy_init(exynos_ohci
->phy
);
51 static void exynos_ohci_phy_disable(struct platform_device
*pdev
)
53 struct usb_hcd
*hcd
= platform_get_drvdata(pdev
);
54 struct exynos_ohci_hcd
*exynos_ohci
= to_exynos_ohci(hcd
);
57 usb_phy_shutdown(exynos_ohci
->phy
);
60 static int exynos_ohci_probe(struct platform_device
*pdev
)
62 struct exynos_ohci_hcd
*exynos_ohci
;
70 * Right now device-tree probed devices don't get dma_mask set.
71 * Since shared usb code relies on it, set it here for now.
72 * Once we move to full device tree support this will vanish off.
74 err
= dma_coerce_mask_and_coherent(&pdev
->dev
, DMA_BIT_MASK(32));
78 hcd
= usb_create_hcd(&exynos_ohci_hc_driver
,
79 &pdev
->dev
, dev_name(&pdev
->dev
));
81 dev_err(&pdev
->dev
, "Unable to create HCD\n");
85 exynos_ohci
= to_exynos_ohci(hcd
);
87 if (of_device_is_compatible(pdev
->dev
.of_node
,
88 "samsung,exynos5440-ohci"))
91 phy
= devm_usb_get_phy(&pdev
->dev
, USB_PHY_TYPE_USB2
);
94 dev_warn(&pdev
->dev
, "no platform data or transceiver defined\n");
97 exynos_ohci
->phy
= phy
;
98 exynos_ohci
->otg
= phy
->otg
;
102 exynos_ohci
->clk
= devm_clk_get(&pdev
->dev
, "usbhost");
104 if (IS_ERR(exynos_ohci
->clk
)) {
105 dev_err(&pdev
->dev
, "Failed to get usbhost clock\n");
106 err
= PTR_ERR(exynos_ohci
->clk
);
110 err
= clk_prepare_enable(exynos_ohci
->clk
);
114 res
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
116 dev_err(&pdev
->dev
, "Failed to get I/O memory\n");
121 hcd
->rsrc_start
= res
->start
;
122 hcd
->rsrc_len
= resource_size(res
);
123 hcd
->regs
= devm_ioremap(&pdev
->dev
, res
->start
, hcd
->rsrc_len
);
125 dev_err(&pdev
->dev
, "Failed to remap I/O memory\n");
130 irq
= platform_get_irq(pdev
, 0);
132 dev_err(&pdev
->dev
, "Failed to get IRQ\n");
137 if (exynos_ohci
->otg
)
138 exynos_ohci
->otg
->set_host(exynos_ohci
->otg
, &hcd
->self
);
140 platform_set_drvdata(pdev
, hcd
);
142 exynos_ohci_phy_enable(pdev
);
144 err
= usb_add_hcd(hcd
, irq
, IRQF_SHARED
);
146 dev_err(&pdev
->dev
, "Failed to add USB HCD\n");
149 device_wakeup_enable(hcd
->self
.controller
);
153 exynos_ohci_phy_disable(pdev
);
155 clk_disable_unprepare(exynos_ohci
->clk
);
161 static int exynos_ohci_remove(struct platform_device
*pdev
)
163 struct usb_hcd
*hcd
= platform_get_drvdata(pdev
);
164 struct exynos_ohci_hcd
*exynos_ohci
= to_exynos_ohci(hcd
);
168 if (exynos_ohci
->otg
)
169 exynos_ohci
->otg
->set_host(exynos_ohci
->otg
, &hcd
->self
);
171 exynos_ohci_phy_disable(pdev
);
173 clk_disable_unprepare(exynos_ohci
->clk
);
180 static void exynos_ohci_shutdown(struct platform_device
*pdev
)
182 struct usb_hcd
*hcd
= platform_get_drvdata(pdev
);
184 if (hcd
->driver
->shutdown
)
185 hcd
->driver
->shutdown(hcd
);
189 static int exynos_ohci_suspend(struct device
*dev
)
191 struct usb_hcd
*hcd
= dev_get_drvdata(dev
);
192 struct exynos_ohci_hcd
*exynos_ohci
= to_exynos_ohci(hcd
);
193 struct ohci_hcd
*ohci
= hcd_to_ohci(hcd
);
194 struct platform_device
*pdev
= to_platform_device(dev
);
195 bool do_wakeup
= device_may_wakeup(dev
);
197 int rc
= ohci_suspend(hcd
, do_wakeup
);
202 spin_lock_irqsave(&ohci
->lock
, flags
);
204 if (exynos_ohci
->otg
)
205 exynos_ohci
->otg
->set_host(exynos_ohci
->otg
, &hcd
->self
);
207 exynos_ohci_phy_disable(pdev
);
209 clk_disable_unprepare(exynos_ohci
->clk
);
211 spin_unlock_irqrestore(&ohci
->lock
, flags
);
216 static int exynos_ohci_resume(struct device
*dev
)
218 struct usb_hcd
*hcd
= dev_get_drvdata(dev
);
219 struct exynos_ohci_hcd
*exynos_ohci
= to_exynos_ohci(hcd
);
220 struct platform_device
*pdev
= to_platform_device(dev
);
222 clk_prepare_enable(exynos_ohci
->clk
);
224 if (exynos_ohci
->otg
)
225 exynos_ohci
->otg
->set_host(exynos_ohci
->otg
, &hcd
->self
);
227 exynos_ohci_phy_enable(pdev
);
229 ohci_resume(hcd
, false);
234 #define exynos_ohci_suspend NULL
235 #define exynos_ohci_resume NULL
238 static const struct ohci_driver_overrides exynos_overrides __initconst
= {
239 .extra_priv_size
= sizeof(struct exynos_ohci_hcd
),
242 static const struct dev_pm_ops exynos_ohci_pm_ops
= {
243 .suspend
= exynos_ohci_suspend
,
244 .resume
= exynos_ohci_resume
,
248 static const struct of_device_id exynos_ohci_match
[] = {
249 { .compatible
= "samsung,exynos4210-ohci" },
250 { .compatible
= "samsung,exynos5440-ohci" },
253 MODULE_DEVICE_TABLE(of
, exynos_ohci_match
);
256 static struct platform_driver exynos_ohci_driver
= {
257 .probe
= exynos_ohci_probe
,
258 .remove
= exynos_ohci_remove
,
259 .shutdown
= exynos_ohci_shutdown
,
261 .name
= "exynos-ohci",
262 .owner
= THIS_MODULE
,
263 .pm
= &exynos_ohci_pm_ops
,
264 .of_match_table
= of_match_ptr(exynos_ohci_match
),
267 static int __init
ohci_exynos_init(void)
272 pr_info("%s: " DRIVER_DESC
"\n", hcd_name
);
273 ohci_init_driver(&exynos_ohci_hc_driver
, &exynos_overrides
);
274 return platform_driver_register(&exynos_ohci_driver
);
276 module_init(ohci_exynos_init
);
278 static void __exit
ohci_exynos_cleanup(void)
280 platform_driver_unregister(&exynos_ohci_driver
);
282 module_exit(ohci_exynos_cleanup
);
284 MODULE_ALIAS("platform:exynos-ohci");
285 MODULE_AUTHOR("Jingoo Han <jg1.han@samsung.com>");
286 MODULE_LICENSE("GPL v2");