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);
77 hcd
->regs
= devm_ioremap_resource(&pdev
->dev
, res
);
78 if (IS_ERR(hcd
->regs
)) {
79 retval
= PTR_ERR(hcd
->regs
);
83 hcd
->rsrc_start
= pdev
->resource
[0].start
;
84 hcd
->rsrc_len
= resource_size(res
);
86 sohci_p
= to_spear_ohci(hcd
);
87 sohci_p
->clk
= usbh_clk
;
89 clk_prepare_enable(sohci_p
->clk
);
91 ohci
= hcd_to_ohci(hcd
);
93 retval
= usb_add_hcd(hcd
, platform_get_irq(pdev
, 0), 0);
95 device_wakeup_enable(hcd
->self
.controller
);
99 clk_disable_unprepare(sohci_p
->clk
);
103 dev_err(&pdev
->dev
, "init fail, %d\n", retval
);
108 static int spear_ohci_hcd_drv_remove(struct platform_device
*pdev
)
110 struct usb_hcd
*hcd
= platform_get_drvdata(pdev
);
111 struct spear_ohci
*sohci_p
= to_spear_ohci(hcd
);
115 clk_disable_unprepare(sohci_p
->clk
);
121 #if defined(CONFIG_PM)
122 static int spear_ohci_hcd_drv_suspend(struct platform_device
*pdev
,
123 pm_message_t message
)
125 struct usb_hcd
*hcd
= platform_get_drvdata(pdev
);
126 struct ohci_hcd
*ohci
= hcd_to_ohci(hcd
);
127 struct spear_ohci
*sohci_p
= to_spear_ohci(hcd
);
128 bool do_wakeup
= device_may_wakeup(&pdev
->dev
);
131 if (time_before(jiffies
, ohci
->next_statechange
))
133 ohci
->next_statechange
= jiffies
;
135 ret
= ohci_suspend(hcd
, do_wakeup
);
139 clk_disable_unprepare(sohci_p
->clk
);
144 static int spear_ohci_hcd_drv_resume(struct platform_device
*dev
)
146 struct usb_hcd
*hcd
= platform_get_drvdata(dev
);
147 struct ohci_hcd
*ohci
= hcd_to_ohci(hcd
);
148 struct spear_ohci
*sohci_p
= to_spear_ohci(hcd
);
150 if (time_before(jiffies
, ohci
->next_statechange
))
152 ohci
->next_statechange
= jiffies
;
154 clk_prepare_enable(sohci_p
->clk
);
155 ohci_resume(hcd
, false);
160 static const struct of_device_id spear_ohci_id_table
[] = {
161 { .compatible
= "st,spear600-ohci", },
164 MODULE_DEVICE_TABLE(of
, spear_ohci_id_table
);
166 /* Driver definition to register with the platform bus */
167 static struct platform_driver spear_ohci_hcd_driver
= {
168 .probe
= spear_ohci_hcd_drv_probe
,
169 .remove
= spear_ohci_hcd_drv_remove
,
171 .suspend
= spear_ohci_hcd_drv_suspend
,
172 .resume
= spear_ohci_hcd_drv_resume
,
175 .name
= "spear-ohci",
176 .of_match_table
= spear_ohci_id_table
,
180 static const struct ohci_driver_overrides spear_overrides __initconst
= {
181 .extra_priv_size
= sizeof(struct spear_ohci
),
183 static int __init
ohci_spear_init(void)
188 pr_info("%s: " DRIVER_DESC
"\n", hcd_name
);
190 ohci_init_driver(&ohci_spear_hc_driver
, &spear_overrides
);
191 return platform_driver_register(&spear_ohci_hcd_driver
);
193 module_init(ohci_spear_init
);
195 static void __exit
ohci_spear_cleanup(void)
197 platform_driver_unregister(&spear_ohci_hcd_driver
);
199 module_exit(ohci_spear_cleanup
);
201 MODULE_DESCRIPTION(DRIVER_DESC
);
202 MODULE_AUTHOR("Deepak Sikri");
203 MODULE_LICENSE("GPL v2");
204 MODULE_ALIAS("platform:spear-ohci");