2 * Driver for EHCI UHP on Atmel chips
4 * Copyright (C) 2009 Atmel Corporation,
5 * Nicolas Ferre <nicolas.ferre@atmel.com>
7 * Based on various ehci-*.c drivers
9 * This file is subject to the terms and conditions of the GNU General Public
10 * License. See the file COPYING in the main directory of this archive for
14 #include <linux/clk.h>
15 #include <linux/platform_device.h>
17 /* interface and function clocks */
18 static struct clk
*iclk
, *fclk
;
21 /*-------------------------------------------------------------------------*/
23 static void atmel_start_clock(void)
30 static void atmel_stop_clock(void)
37 static void atmel_start_ehci(struct platform_device
*pdev
)
39 dev_dbg(&pdev
->dev
, "start\n");
43 static void atmel_stop_ehci(struct platform_device
*pdev
)
45 dev_dbg(&pdev
->dev
, "stop\n");
49 /*-------------------------------------------------------------------------*/
51 static int ehci_atmel_setup(struct usb_hcd
*hcd
)
53 struct ehci_hcd
*ehci
= hcd_to_ehci(hcd
);
56 /* registers start at offset 0x0 */
57 ehci
->caps
= hcd
->regs
;
58 ehci
->regs
= hcd
->regs
+
59 HC_LENGTH(ehci_readl(ehci
, &ehci
->caps
->hc_capbase
));
60 dbg_hcs_params(ehci
, "reset");
61 dbg_hcc_params(ehci
, "reset");
63 /* cache this readonly data; minimize chip reads */
64 ehci
->hcs_params
= ehci_readl(ehci
, &ehci
->caps
->hcs_params
);
66 retval
= ehci_halt(ehci
);
70 /* data structure init */
71 retval
= ehci_init(hcd
);
78 ehci_port_power(ehci
, 0);
83 static const struct hc_driver ehci_atmel_hc_driver
= {
84 .description
= hcd_name
,
85 .product_desc
= "Atmel EHCI UHP HS",
86 .hcd_priv_size
= sizeof(struct ehci_hcd
),
88 /* generic hardware linkage */
90 .flags
= HCD_MEMORY
| HCD_USB2
,
92 /* basic lifecycle operations */
93 .reset
= ehci_atmel_setup
,
96 .shutdown
= ehci_shutdown
,
98 /* managing i/o requests and associated device resources */
99 .urb_enqueue
= ehci_urb_enqueue
,
100 .urb_dequeue
= ehci_urb_dequeue
,
101 .endpoint_disable
= ehci_endpoint_disable
,
103 /* scheduling support */
104 .get_frame_number
= ehci_get_frame
,
106 /* root hub support */
107 .hub_status_data
= ehci_hub_status_data
,
108 .hub_control
= ehci_hub_control
,
109 .bus_suspend
= ehci_bus_suspend
,
110 .bus_resume
= ehci_bus_resume
,
111 .relinquish_port
= ehci_relinquish_port
,
112 .port_handed_over
= ehci_port_handed_over
,
115 static int __init
ehci_atmel_drv_probe(struct platform_device
*pdev
)
118 const struct hc_driver
*driver
= &ehci_atmel_hc_driver
;
119 struct resource
*res
;
126 pr_debug("Initializing Atmel-SoC USB Host Controller\n");
128 irq
= platform_get_irq(pdev
, 0);
131 "Found HC with no IRQ. Check %s setup!\n",
132 dev_name(&pdev
->dev
));
134 goto fail_create_hcd
;
137 hcd
= usb_create_hcd(driver
, &pdev
->dev
, dev_name(&pdev
->dev
));
140 goto fail_create_hcd
;
143 res
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
146 "Found HC with no register addr. Check %s setup!\n",
147 dev_name(&pdev
->dev
));
149 goto fail_request_resource
;
151 hcd
->rsrc_start
= res
->start
;
152 hcd
->rsrc_len
= res
->end
- res
->start
+ 1;
154 if (!request_mem_region(hcd
->rsrc_start
, hcd
->rsrc_len
,
155 driver
->description
)) {
156 dev_dbg(&pdev
->dev
, "controller already in use\n");
158 goto fail_request_resource
;
161 hcd
->regs
= ioremap_nocache(hcd
->rsrc_start
, hcd
->rsrc_len
);
162 if (hcd
->regs
== NULL
) {
163 dev_dbg(&pdev
->dev
, "error mapping memory\n");
168 iclk
= clk_get(&pdev
->dev
, "ehci_clk");
170 dev_err(&pdev
->dev
, "Error getting interface clock\n");
174 fclk
= clk_get(&pdev
->dev
, "uhpck");
176 dev_err(&pdev
->dev
, "Error getting function clock\n");
181 atmel_start_ehci(pdev
);
183 retval
= usb_add_hcd(hcd
, irq
, IRQF_SHARED
);
190 atmel_stop_ehci(pdev
);
197 release_mem_region(hcd
->rsrc_start
, hcd
->rsrc_len
);
198 fail_request_resource
:
201 dev_err(&pdev
->dev
, "init %s fail, %d\n",
202 dev_name(&pdev
->dev
), retval
);
207 static int __exit
ehci_atmel_drv_remove(struct platform_device
*pdev
)
209 struct usb_hcd
*hcd
= platform_get_drvdata(pdev
);
214 release_mem_region(hcd
->rsrc_start
, hcd
->rsrc_len
);
217 atmel_stop_ehci(pdev
);
225 static struct platform_driver ehci_atmel_driver
= {
226 .probe
= ehci_atmel_drv_probe
,
227 .remove
= __exit_p(ehci_atmel_drv_remove
),
228 .shutdown
= usb_hcd_platform_shutdown
,
229 .driver
.name
= "atmel-ehci",