1 // SPDX-License-Identifier: GPL-2.0
3 * OHCI HCD (Host Controller Driver) for USB.
5 * Copyright (C) 2010 ST Microelectronics.
6 * Deepak Sikri<deepak.sikri@st.com>
8 * Based on various ohci-*.c drivers
11 #include <linux/clk.h>
12 #include <linux/dma-mapping.h>
14 #include <linux/kernel.h>
15 #include <linux/module.h>
17 #include <linux/platform_device.h>
18 #include <linux/signal.h>
19 #include <linux/usb.h>
20 #include <linux/usb/hcd.h>
24 #define DRIVER_DESC "OHCI SPEAr driver"
26 static const char hcd_name
[] = "SPEAr-ohci";
31 #define to_spear_ohci(hcd) (struct spear_ohci *)(hcd_to_ohci(hcd)->priv)
33 static struct hc_driver __read_mostly ohci_spear_hc_driver
;
35 static int spear_ohci_hcd_drv_probe(struct platform_device
*pdev
)
37 const struct hc_driver
*driver
= &ohci_spear_hc_driver
;
38 struct usb_hcd
*hcd
= NULL
;
40 struct spear_ohci
*sohci_p
;
44 irq
= platform_get_irq(pdev
, 0);
51 * Right now device-tree probed devices don't get dma_mask set.
52 * Since shared usb code relies on it, set it here for now.
53 * Once we have dma capability bindings this can go away.
55 retval
= dma_coerce_mask_and_coherent(&pdev
->dev
, DMA_BIT_MASK(32));
59 usbh_clk
= devm_clk_get(&pdev
->dev
, NULL
);
60 if (IS_ERR(usbh_clk
)) {
61 dev_err(&pdev
->dev
, "Error getting interface clock\n");
62 retval
= PTR_ERR(usbh_clk
);
66 hcd
= usb_create_hcd(driver
, &pdev
->dev
, dev_name(&pdev
->dev
));
72 res
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
73 hcd
->regs
= devm_ioremap_resource(&pdev
->dev
, res
);
74 if (IS_ERR(hcd
->regs
)) {
75 retval
= PTR_ERR(hcd
->regs
);
79 hcd
->rsrc_start
= pdev
->resource
[0].start
;
80 hcd
->rsrc_len
= resource_size(res
);
82 sohci_p
= to_spear_ohci(hcd
);
83 sohci_p
->clk
= usbh_clk
;
85 clk_prepare_enable(sohci_p
->clk
);
87 retval
= usb_add_hcd(hcd
, platform_get_irq(pdev
, 0), 0);
89 device_wakeup_enable(hcd
->self
.controller
);
93 clk_disable_unprepare(sohci_p
->clk
);
97 dev_err(&pdev
->dev
, "init fail, %d\n", retval
);
102 static int spear_ohci_hcd_drv_remove(struct platform_device
*pdev
)
104 struct usb_hcd
*hcd
= platform_get_drvdata(pdev
);
105 struct spear_ohci
*sohci_p
= to_spear_ohci(hcd
);
109 clk_disable_unprepare(sohci_p
->clk
);
115 #if defined(CONFIG_PM)
116 static int spear_ohci_hcd_drv_suspend(struct platform_device
*pdev
,
117 pm_message_t message
)
119 struct usb_hcd
*hcd
= platform_get_drvdata(pdev
);
120 struct ohci_hcd
*ohci
= hcd_to_ohci(hcd
);
121 struct spear_ohci
*sohci_p
= to_spear_ohci(hcd
);
122 bool do_wakeup
= device_may_wakeup(&pdev
->dev
);
125 if (time_before(jiffies
, ohci
->next_statechange
))
127 ohci
->next_statechange
= jiffies
;
129 ret
= ohci_suspend(hcd
, do_wakeup
);
133 clk_disable_unprepare(sohci_p
->clk
);
138 static int spear_ohci_hcd_drv_resume(struct platform_device
*dev
)
140 struct usb_hcd
*hcd
= platform_get_drvdata(dev
);
141 struct ohci_hcd
*ohci
= hcd_to_ohci(hcd
);
142 struct spear_ohci
*sohci_p
= to_spear_ohci(hcd
);
144 if (time_before(jiffies
, ohci
->next_statechange
))
146 ohci
->next_statechange
= jiffies
;
148 clk_prepare_enable(sohci_p
->clk
);
149 ohci_resume(hcd
, false);
154 static const struct of_device_id spear_ohci_id_table
[] = {
155 { .compatible
= "st,spear600-ohci", },
158 MODULE_DEVICE_TABLE(of
, spear_ohci_id_table
);
160 /* Driver definition to register with the platform bus */
161 static struct platform_driver spear_ohci_hcd_driver
= {
162 .probe
= spear_ohci_hcd_drv_probe
,
163 .remove
= spear_ohci_hcd_drv_remove
,
165 .suspend
= spear_ohci_hcd_drv_suspend
,
166 .resume
= spear_ohci_hcd_drv_resume
,
169 .name
= "spear-ohci",
170 .of_match_table
= spear_ohci_id_table
,
174 static const struct ohci_driver_overrides spear_overrides __initconst
= {
175 .extra_priv_size
= sizeof(struct spear_ohci
),
177 static int __init
ohci_spear_init(void)
182 pr_info("%s: " DRIVER_DESC
"\n", hcd_name
);
184 ohci_init_driver(&ohci_spear_hc_driver
, &spear_overrides
);
185 return platform_driver_register(&spear_ohci_hcd_driver
);
187 module_init(ohci_spear_init
);
189 static void __exit
ohci_spear_cleanup(void)
191 platform_driver_unregister(&spear_ohci_hcd_driver
);
193 module_exit(ohci_spear_cleanup
);
195 MODULE_DESCRIPTION(DRIVER_DESC
);
196 MODULE_AUTHOR("Deepak Sikri");
197 MODULE_LICENSE("GPL v2");
198 MODULE_ALIAS("platform:spear-ohci");