2 * OHCI HCD (Host Controller Driver) for USB.
4 * Copyright (C) 2010 ST Microelectronics.
5 * Deepak Sikri<deepak.sikri@st.com>
7 * Based on various ohci-*.c drivers
9 * This file is licensed under the terms of the GNU General Public
10 * License version 2. This program is licensed "as is" without any
11 * warranty of any kind, whether express or implied.
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/signal.h>
22 #include <linux/usb.h>
23 #include <linux/usb/hcd.h>
27 #define DRIVER_DESC "OHCI SPEAr driver"
29 static const char hcd_name
[] = "SPEAr-ohci";
34 #define to_spear_ohci(hcd) (struct spear_ohci *)(hcd_to_ohci(hcd)->priv)
36 static struct hc_driver __read_mostly ohci_spear_hc_driver
;
38 static int spear_ohci_hcd_drv_probe(struct platform_device
*pdev
)
40 const struct hc_driver
*driver
= &ohci_spear_hc_driver
;
41 struct ohci_hcd
*ohci
;
42 struct usb_hcd
*hcd
= NULL
;
44 struct spear_ohci
*sohci_p
;
48 irq
= platform_get_irq(pdev
, 0);
55 * Right now device-tree probed devices don't get dma_mask set.
56 * Since shared usb code relies on it, set it here for now.
57 * Once we have dma capability bindings this can go away.
59 retval
= dma_coerce_mask_and_coherent(&pdev
->dev
, DMA_BIT_MASK(32));
63 usbh_clk
= devm_clk_get(&pdev
->dev
, NULL
);
64 if (IS_ERR(usbh_clk
)) {
65 dev_err(&pdev
->dev
, "Error getting interface clock\n");
66 retval
= PTR_ERR(usbh_clk
);
70 hcd
= usb_create_hcd(driver
, &pdev
->dev
, dev_name(&pdev
->dev
));
76 res
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
82 hcd
->rsrc_start
= pdev
->resource
[0].start
;
83 hcd
->rsrc_len
= resource_size(res
);
85 hcd
->regs
= devm_ioremap_resource(&pdev
->dev
, res
);
86 if (IS_ERR(hcd
->regs
)) {
87 retval
= PTR_ERR(hcd
->regs
);
91 sohci_p
= to_spear_ohci(hcd
);
92 sohci_p
->clk
= usbh_clk
;
94 clk_prepare_enable(sohci_p
->clk
);
96 ohci
= hcd_to_ohci(hcd
);
98 retval
= usb_add_hcd(hcd
, platform_get_irq(pdev
, 0), 0);
100 device_wakeup_enable(hcd
->self
.controller
);
104 clk_disable_unprepare(sohci_p
->clk
);
108 dev_err(&pdev
->dev
, "init fail, %d\n", retval
);
113 static int spear_ohci_hcd_drv_remove(struct platform_device
*pdev
)
115 struct usb_hcd
*hcd
= platform_get_drvdata(pdev
);
116 struct spear_ohci
*sohci_p
= to_spear_ohci(hcd
);
120 clk_disable_unprepare(sohci_p
->clk
);
126 #if defined(CONFIG_PM)
127 static int spear_ohci_hcd_drv_suspend(struct platform_device
*pdev
,
128 pm_message_t message
)
130 struct usb_hcd
*hcd
= platform_get_drvdata(pdev
);
131 struct ohci_hcd
*ohci
= hcd_to_ohci(hcd
);
132 struct spear_ohci
*sohci_p
= to_spear_ohci(hcd
);
133 bool do_wakeup
= device_may_wakeup(&pdev
->dev
);
136 if (time_before(jiffies
, ohci
->next_statechange
))
138 ohci
->next_statechange
= jiffies
;
140 ret
= ohci_suspend(hcd
, do_wakeup
);
144 clk_disable_unprepare(sohci_p
->clk
);
149 static int spear_ohci_hcd_drv_resume(struct platform_device
*dev
)
151 struct usb_hcd
*hcd
= platform_get_drvdata(dev
);
152 struct ohci_hcd
*ohci
= hcd_to_ohci(hcd
);
153 struct spear_ohci
*sohci_p
= to_spear_ohci(hcd
);
155 if (time_before(jiffies
, ohci
->next_statechange
))
157 ohci
->next_statechange
= jiffies
;
159 clk_prepare_enable(sohci_p
->clk
);
160 ohci_resume(hcd
, false);
165 static struct of_device_id spear_ohci_id_table
[] = {
166 { .compatible
= "st,spear600-ohci", },
170 /* Driver definition to register with the platform bus */
171 static struct platform_driver spear_ohci_hcd_driver
= {
172 .probe
= spear_ohci_hcd_drv_probe
,
173 .remove
= spear_ohci_hcd_drv_remove
,
175 .suspend
= spear_ohci_hcd_drv_suspend
,
176 .resume
= spear_ohci_hcd_drv_resume
,
179 .owner
= THIS_MODULE
,
180 .name
= "spear-ohci",
181 .of_match_table
= spear_ohci_id_table
,
185 static const struct ohci_driver_overrides spear_overrides __initconst
= {
186 .extra_priv_size
= sizeof(struct spear_ohci
),
188 static int __init
ohci_spear_init(void)
193 pr_info("%s: " DRIVER_DESC
"\n", hcd_name
);
195 ohci_init_driver(&ohci_spear_hc_driver
, &spear_overrides
);
196 return platform_driver_register(&spear_ohci_hcd_driver
);
198 module_init(ohci_spear_init
);
200 static void __exit
ohci_spear_cleanup(void)
202 platform_driver_unregister(&spear_ohci_hcd_driver
);
204 module_exit(ohci_spear_cleanup
);
206 MODULE_DESCRIPTION(DRIVER_DESC
);
207 MODULE_AUTHOR("Deepak Sikri");
208 MODULE_LICENSE("GPL v2");
209 MODULE_ALIAS("platform:spear-ohci");