1 /*
2  * SAMSUNG S5P USB HOST EHCI Controller
3  *
4  * Copyright (C) 2011 Samsung Electronics Co.Ltd
5  * Author: Jingoo Han <jg1.han@samsung.com>
6  * Author: Joonyoung Shim <jy0922.shim@samsung.com>
7  *
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.
12  *
13  */
14 
15 #include <linux/clk.h>
16 #include <linux/platform_device.h>
17 #include <plat/ehci.h>
18 #include <plat/usb-phy.h>
19 
20 #define EHCI_INSNREG00(base)			(base + 0x90)
21 #define EHCI_INSNREG00_ENA_INCR16		(0x1 << 25)
22 #define EHCI_INSNREG00_ENA_INCR8		(0x1 << 24)
23 #define EHCI_INSNREG00_ENA_INCR4		(0x1 << 23)
24 #define EHCI_INSNREG00_ENA_INCRX_ALIGN		(0x1 << 22)
25 #define EHCI_INSNREG00_ENABLE_DMA_BURST	\
26 	(EHCI_INSNREG00_ENA_INCR16 | EHCI_INSNREG00_ENA_INCR8 |	\
27 	 EHCI_INSNREG00_ENA_INCR4 | EHCI_INSNREG00_ENA_INCRX_ALIGN)
28 
29 struct s5p_ehci_hcd {
30 	struct device *dev;
31 	struct usb_hcd *hcd;
32 	struct clk *clk;
33 };
34 
35 static const struct hc_driver s5p_ehci_hc_driver = {
36 	.description		= hcd_name,
37 	.product_desc		= "S5P EHCI Host Controller",
38 	.hcd_priv_size		= sizeof(struct ehci_hcd),
39 
40 	.irq			= ehci_irq,
41 	.flags			= HCD_MEMORY | HCD_USB2,
42 
43 	.reset			= ehci_init,
44 	.start			= ehci_run,
45 	.stop			= ehci_stop,
46 	.shutdown		= ehci_shutdown,
47 
48 	.get_frame_number	= ehci_get_frame,
49 
50 	.urb_enqueue		= ehci_urb_enqueue,
51 	.urb_dequeue		= ehci_urb_dequeue,
52 	.endpoint_disable	= ehci_endpoint_disable,
53 	.endpoint_reset		= ehci_endpoint_reset,
54 
55 	.hub_status_data	= ehci_hub_status_data,
56 	.hub_control		= ehci_hub_control,
57 	.bus_suspend		= ehci_bus_suspend,
58 	.bus_resume		= ehci_bus_resume,
59 
60 	.relinquish_port	= ehci_relinquish_port,
61 	.port_handed_over	= ehci_port_handed_over,
62 
63 	.clear_tt_buffer_complete	= ehci_clear_tt_buffer_complete,
64 };
65 
s5p_ehci_probe(struct platform_device * pdev)66 static int __devinit s5p_ehci_probe(struct platform_device *pdev)
67 {
68 	struct s5p_ehci_platdata *pdata;
69 	struct s5p_ehci_hcd *s5p_ehci;
70 	struct usb_hcd *hcd;
71 	struct ehci_hcd *ehci;
72 	struct resource *res;
73 	int irq;
74 	int err;
75 
76 	pdata = pdev->dev.platform_data;
77 	if (!pdata) {
78 		dev_err(&pdev->dev, "No platform data defined\n");
79 		return -EINVAL;
80 	}
81 
82 	s5p_ehci = kzalloc(sizeof(struct s5p_ehci_hcd), GFP_KERNEL);
83 	if (!s5p_ehci)
84 		return -ENOMEM;
85 
86 	s5p_ehci->dev = &pdev->dev;
87 
88 	hcd = usb_create_hcd(&s5p_ehci_hc_driver, &pdev->dev,
89 					dev_name(&pdev->dev));
90 	if (!hcd) {
91 		dev_err(&pdev->dev, "Unable to create HCD\n");
92 		err = -ENOMEM;
93 		goto fail_hcd;
94 	}
95 
96 	s5p_ehci->hcd = hcd;
97 	s5p_ehci->clk = clk_get(&pdev->dev, "usbhost");
98 
99 	if (IS_ERR(s5p_ehci->clk)) {
100 		dev_err(&pdev->dev, "Failed to get usbhost clock\n");
101 		err = PTR_ERR(s5p_ehci->clk);
102 		goto fail_clk;
103 	}
104 
105 	err = clk_enable(s5p_ehci->clk);
106 	if (err)
107 		goto fail_clken;
108 
109 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
110 	if (!res) {
111 		dev_err(&pdev->dev, "Failed to get I/O memory\n");
112 		err = -ENXIO;
113 		goto fail_io;
114 	}
115 
116 	hcd->rsrc_start = res->start;
117 	hcd->rsrc_len = resource_size(res);
118 	hcd->regs = ioremap(res->start, resource_size(res));
119 	if (!hcd->regs) {
120 		dev_err(&pdev->dev, "Failed to remap I/O memory\n");
121 		err = -ENOMEM;
122 		goto fail_io;
123 	}
124 
125 	irq = platform_get_irq(pdev, 0);
126 	if (!irq) {
127 		dev_err(&pdev->dev, "Failed to get IRQ\n");
128 		err = -ENODEV;
129 		goto fail;
130 	}
131 
132 	if (pdata->phy_init)
133 		pdata->phy_init(pdev, S5P_USB_PHY_HOST);
134 
135 	ehci = hcd_to_ehci(hcd);
136 	ehci->caps = hcd->regs;
137 	ehci->regs = hcd->regs +
138 		HC_LENGTH(ehci, readl(&ehci->caps->hc_capbase));
139 
140 	/* DMA burst Enable */
141 	writel(EHCI_INSNREG00_ENABLE_DMA_BURST, EHCI_INSNREG00(hcd->regs));
142 
143 	dbg_hcs_params(ehci, "reset");
144 	dbg_hcc_params(ehci, "reset");
145 
146 	/* cache this readonly data; minimize chip reads */
147 	ehci->hcs_params = readl(&ehci->caps->hcs_params);
148 
149 	ehci_reset(ehci);
150 
151 	err = usb_add_hcd(hcd, irq, IRQF_SHARED);
152 	if (err) {
153 		dev_err(&pdev->dev, "Failed to add USB HCD\n");
154 		goto fail;
155 	}
156 
157 	platform_set_drvdata(pdev, s5p_ehci);
158 
159 	return 0;
160 
161 fail:
162 	iounmap(hcd->regs);
163 fail_io:
164 	clk_disable(s5p_ehci->clk);
165 fail_clken:
166 	clk_put(s5p_ehci->clk);
167 fail_clk:
168 	usb_put_hcd(hcd);
169 fail_hcd:
170 	kfree(s5p_ehci);
171 	return err;
172 }
173 
s5p_ehci_remove(struct platform_device * pdev)174 static int __devexit s5p_ehci_remove(struct platform_device *pdev)
175 {
176 	struct s5p_ehci_platdata *pdata = pdev->dev.platform_data;
177 	struct s5p_ehci_hcd *s5p_ehci = platform_get_drvdata(pdev);
178 	struct usb_hcd *hcd = s5p_ehci->hcd;
179 
180 	usb_remove_hcd(hcd);
181 
182 	if (pdata && pdata->phy_exit)
183 		pdata->phy_exit(pdev, S5P_USB_PHY_HOST);
184 
185 	iounmap(hcd->regs);
186 
187 	clk_disable(s5p_ehci->clk);
188 	clk_put(s5p_ehci->clk);
189 
190 	usb_put_hcd(hcd);
191 	kfree(s5p_ehci);
192 
193 	return 0;
194 }
195 
s5p_ehci_shutdown(struct platform_device * pdev)196 static void s5p_ehci_shutdown(struct platform_device *pdev)
197 {
198 	struct s5p_ehci_hcd *s5p_ehci = platform_get_drvdata(pdev);
199 	struct usb_hcd *hcd = s5p_ehci->hcd;
200 
201 	if (hcd->driver->shutdown)
202 		hcd->driver->shutdown(hcd);
203 }
204 
205 #ifdef CONFIG_PM
s5p_ehci_suspend(struct device * dev)206 static int s5p_ehci_suspend(struct device *dev)
207 {
208 	struct s5p_ehci_hcd *s5p_ehci = dev_get_drvdata(dev);
209 	struct usb_hcd *hcd = s5p_ehci->hcd;
210 	struct ehci_hcd *ehci = hcd_to_ehci(hcd);
211 	struct platform_device *pdev = to_platform_device(dev);
212 	struct s5p_ehci_platdata *pdata = pdev->dev.platform_data;
213 	unsigned long flags;
214 	int rc = 0;
215 
216 	if (time_before(jiffies, ehci->next_statechange))
217 		msleep(20);
218 
219 	/*
220 	 * Root hub was already suspended. Disable irq emission and
221 	 * mark HW unaccessible.  The PM and USB cores make sure that
222 	 * the root hub is either suspended or stopped.
223 	 */
224 	ehci_prepare_ports_for_controller_suspend(ehci, device_may_wakeup(dev));
225 	spin_lock_irqsave(&ehci->lock, flags);
226 	ehci_writel(ehci, 0, &ehci->regs->intr_enable);
227 	(void)ehci_readl(ehci, &ehci->regs->intr_enable);
228 
229 	clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
230 	spin_unlock_irqrestore(&ehci->lock, flags);
231 
232 	if (pdata && pdata->phy_exit)
233 		pdata->phy_exit(pdev, S5P_USB_PHY_HOST);
234 
235 	return rc;
236 }
237 
s5p_ehci_resume(struct device * dev)238 static int s5p_ehci_resume(struct device *dev)
239 {
240 	struct s5p_ehci_hcd *s5p_ehci = dev_get_drvdata(dev);
241 	struct usb_hcd *hcd = s5p_ehci->hcd;
242 	struct ehci_hcd *ehci = hcd_to_ehci(hcd);
243 	struct platform_device *pdev = to_platform_device(dev);
244 	struct s5p_ehci_platdata *pdata = pdev->dev.platform_data;
245 
246 	if (pdata && pdata->phy_init)
247 		pdata->phy_init(pdev, S5P_USB_PHY_HOST);
248 
249 	/* DMA burst Enable */
250 	writel(EHCI_INSNREG00_ENABLE_DMA_BURST, EHCI_INSNREG00(hcd->regs));
251 
252 	if (time_before(jiffies, ehci->next_statechange))
253 		msleep(100);
254 
255 	/* Mark hardware accessible again as we are out of D3 state by now */
256 	set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
257 
258 	if (ehci_readl(ehci, &ehci->regs->configured_flag) == FLAG_CF) {
259 		int	mask = INTR_MASK;
260 
261 		ehci_prepare_ports_for_controller_resume(ehci);
262 		if (!hcd->self.root_hub->do_remote_wakeup)
263 			mask &= ~STS_PCD;
264 		ehci_writel(ehci, mask, &ehci->regs->intr_enable);
265 		ehci_readl(ehci, &ehci->regs->intr_enable);
266 		return 0;
267 	}
268 
269 	usb_root_hub_lost_power(hcd->self.root_hub);
270 
271 	(void) ehci_halt(ehci);
272 	(void) ehci_reset(ehci);
273 
274 	/* emptying the schedule aborts any urbs */
275 	spin_lock_irq(&ehci->lock);
276 	if (ehci->reclaim)
277 		end_unlink_async(ehci);
278 	ehci_work(ehci);
279 	spin_unlock_irq(&ehci->lock);
280 
281 	ehci_writel(ehci, ehci->command, &ehci->regs->command);
282 	ehci_writel(ehci, FLAG_CF, &ehci->regs->configured_flag);
283 	ehci_readl(ehci, &ehci->regs->command);	/* unblock posted writes */
284 
285 	/* here we "know" root ports should always stay powered */
286 	ehci_port_power(ehci, 1);
287 
288 	ehci->rh_state = EHCI_RH_SUSPENDED;
289 
290 	return 0;
291 }
292 #else
293 #define s5p_ehci_suspend	NULL
294 #define s5p_ehci_resume		NULL
295 #endif
296 
297 static const struct dev_pm_ops s5p_ehci_pm_ops = {
298 	.suspend	= s5p_ehci_suspend,
299 	.resume		= s5p_ehci_resume,
300 };
301 
302 static struct platform_driver s5p_ehci_driver = {
303 	.probe		= s5p_ehci_probe,
304 	.remove		= __devexit_p(s5p_ehci_remove),
305 	.shutdown	= s5p_ehci_shutdown,
306 	.driver = {
307 		.name	= "s5p-ehci",
308 		.owner	= THIS_MODULE,
309 		.pm	= &s5p_ehci_pm_ops,
310 	}
311 };
312 
313 MODULE_ALIAS("platform:s5p-ehci");
314