2 * MIPS CI13320A EHCI Host Controller driver
3 * Based on "ehci-au1xxx.c" by K.Boge <karsten.boge@amd.com>
5 * Copyright (C) 2012 MIPS Technologies, Inc.
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.
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software Foundation,
19 * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 #include <linux/platform_device.h>
24 static int ehci_sead3_setup(struct usb_hcd
*hcd
)
27 struct ehci_hcd
*ehci
= hcd_to_ehci(hcd
);
29 ehci
->caps
= hcd
->regs
+ 0x100;
32 ehci
->big_endian_mmio
= 1;
33 ehci
->big_endian_desc
= 1;
36 ret
= ehci_setup(hcd
);
40 ehci
->need_io_watchdog
= 0;
42 /* Set burst length to 16 words. */
43 ehci_writel(ehci
, 0x1010, &ehci
->regs
->reserved
[1]);
48 const struct hc_driver ehci_sead3_hc_driver
= {
49 .description
= hcd_name
,
50 .product_desc
= "SEAD-3 EHCI",
51 .hcd_priv_size
= sizeof(struct ehci_hcd
),
54 * generic hardware linkage
57 .flags
= HCD_MEMORY
| HCD_USB2
,
60 * basic lifecycle operations
63 .reset
= ehci_sead3_setup
,
66 .shutdown
= ehci_shutdown
,
69 * managing i/o requests and associated device resources
71 .urb_enqueue
= ehci_urb_enqueue
,
72 .urb_dequeue
= ehci_urb_dequeue
,
73 .endpoint_disable
= ehci_endpoint_disable
,
74 .endpoint_reset
= ehci_endpoint_reset
,
79 .get_frame_number
= ehci_get_frame
,
84 .hub_status_data
= ehci_hub_status_data
,
85 .hub_control
= ehci_hub_control
,
86 .bus_suspend
= ehci_bus_suspend
,
87 .bus_resume
= ehci_bus_resume
,
88 .relinquish_port
= ehci_relinquish_port
,
89 .port_handed_over
= ehci_port_handed_over
,
91 .clear_tt_buffer_complete
= ehci_clear_tt_buffer_complete
,
94 static int ehci_hcd_sead3_drv_probe(struct platform_device
*pdev
)
103 if (pdev
->resource
[1].flags
!= IORESOURCE_IRQ
) {
104 pr_debug("resource[1] is not IORESOURCE_IRQ");
107 hcd
= usb_create_hcd(&ehci_sead3_hc_driver
, &pdev
->dev
, "SEAD-3");
111 res
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
112 hcd
->rsrc_start
= res
->start
;
113 hcd
->rsrc_len
= resource_size(res
);
115 if (!request_mem_region(hcd
->rsrc_start
, hcd
->rsrc_len
, hcd_name
)) {
116 pr_debug("request_mem_region failed");
121 hcd
->regs
= ioremap(hcd
->rsrc_start
, hcd
->rsrc_len
);
123 pr_debug("ioremap failed");
128 /* Root hub has integrated TT. */
131 ret
= usb_add_hcd(hcd
, pdev
->resource
[1].start
,
134 platform_set_drvdata(pdev
, hcd
);
140 release_mem_region(hcd
->rsrc_start
, hcd
->rsrc_len
);
146 static int ehci_hcd_sead3_drv_remove(struct platform_device
*pdev
)
148 struct usb_hcd
*hcd
= platform_get_drvdata(pdev
);
152 release_mem_region(hcd
->rsrc_start
, hcd
->rsrc_len
);
154 platform_set_drvdata(pdev
, NULL
);
160 static int ehci_hcd_sead3_drv_suspend(struct device
*dev
)
162 struct usb_hcd
*hcd
= dev_get_drvdata(dev
);
163 struct ehci_hcd
*ehci
= hcd_to_ehci(hcd
);
167 if (time_before(jiffies
, ehci
->next_statechange
))
170 /* Root hub was already suspended. Disable irq emission and
171 * mark HW unaccessible. The PM and USB cores make sure that
172 * the root hub is either suspended or stopped.
174 ehci_prepare_ports_for_controller_suspend(ehci
, device_may_wakeup(dev
));
175 spin_lock_irqsave(&ehci
->lock
, flags
);
176 ehci_writel(ehci
, 0, &ehci
->regs
->intr_enable
);
177 (void)ehci_readl(ehci
, &ehci
->regs
->intr_enable
);
179 clear_bit(HCD_FLAG_HW_ACCESSIBLE
, &hcd
->flags
);
180 spin_unlock_irqrestore(&ehci
->lock
, flags
);
182 /* could save FLADJ in case of Vaux power loss
183 * ... we'd only use it to handle clock skew
189 static int ehci_hcd_sead3_drv_resume(struct device
*dev
)
191 struct usb_hcd
*hcd
= dev_get_drvdata(dev
);
192 struct ehci_hcd
*ehci
= hcd_to_ehci(hcd
);
194 /* maybe restore FLADJ. */
196 if (time_before(jiffies
, ehci
->next_statechange
))
199 /* Mark hardware accessible again as we are out of D3 state by now */
200 set_bit(HCD_FLAG_HW_ACCESSIBLE
, &hcd
->flags
);
202 /* If CF is still set, we maintained PCI Vaux power.
203 * Just undo the effect of ehci_pci_suspend().
205 if (ehci_readl(ehci
, &ehci
->regs
->configured_flag
) == FLAG_CF
) {
206 int mask
= INTR_MASK
;
208 ehci_prepare_ports_for_controller_resume(ehci
);
209 if (!hcd
->self
.root_hub
->do_remote_wakeup
)
211 ehci_writel(ehci
, mask
, &ehci
->regs
->intr_enable
);
212 ehci_readl(ehci
, &ehci
->regs
->intr_enable
);
216 ehci_dbg(ehci
, "lost power, restarting\n");
217 usb_root_hub_lost_power(hcd
->self
.root_hub
);
219 /* Else reset, to cope with power loss or flush-to-storage
220 * style "resume" having let BIOS kick in during reboot.
222 (void) ehci_halt(ehci
);
223 (void) ehci_reset(ehci
);
225 /* emptying the schedule aborts any urbs */
226 spin_lock_irq(&ehci
->lock
);
228 end_unlink_async(ehci
);
230 spin_unlock_irq(&ehci
->lock
);
232 ehci_writel(ehci
, ehci
->command
, &ehci
->regs
->command
);
233 ehci_writel(ehci
, FLAG_CF
, &ehci
->regs
->configured_flag
);
234 ehci_readl(ehci
, &ehci
->regs
->command
); /* unblock posted writes */
236 /* here we "know" root ports should always stay powered */
237 ehci_port_power(ehci
, 1);
239 ehci
->rh_state
= EHCI_RH_SUSPENDED
;
244 static const struct dev_pm_ops sead3_ehci_pmops
= {
245 .suspend
= ehci_hcd_sead3_drv_suspend
,
246 .resume
= ehci_hcd_sead3_drv_resume
,
249 #define SEAD3_EHCI_PMOPS (&sead3_ehci_pmops)
252 #define SEAD3_EHCI_PMOPS NULL
255 static struct platform_driver ehci_hcd_sead3_driver
= {
256 .probe
= ehci_hcd_sead3_drv_probe
,
257 .remove
= ehci_hcd_sead3_drv_remove
,
258 .shutdown
= usb_hcd_platform_shutdown
,
260 .name
= "sead3-ehci",
261 .owner
= THIS_MODULE
,
262 .pm
= SEAD3_EHCI_PMOPS
,
266 MODULE_ALIAS("platform:sead3-ehci");