2 * Copyright (C) 2010, Lars-Peter Clausen <lars@metafoo.de>
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License as published by the
6 * Free Software Foundation; either version 2 of the License, or (at your
7 * option) any later version.
9 * You should have received a copy of the GNU General Public License along
10 * with this program; if not, write to the Free Software Foundation, Inc.,
11 * 675 Mass Ave, Cambridge, MA 02139, USA.
15 #include <linux/platform_device.h>
16 #include <linux/clk.h>
17 #include <linux/regulator/consumer.h>
19 struct jz4740_ohci_hcd
{
20 struct ohci_hcd ohci_hcd
;
22 struct regulator
*vbus
;
27 static inline struct jz4740_ohci_hcd
*hcd_to_jz4740_hcd(struct usb_hcd
*hcd
)
29 return (struct jz4740_ohci_hcd
*)(hcd
->hcd_priv
);
32 static inline struct usb_hcd
*jz4740_hcd_to_hcd(struct jz4740_ohci_hcd
*jz4740_ohci
)
34 return container_of((void *)jz4740_ohci
, struct usb_hcd
, hcd_priv
);
37 static int ohci_jz4740_start(struct usb_hcd
*hcd
)
39 struct ohci_hcd
*ohci
= hcd_to_ohci(hcd
);
42 ret
= ohci_init(ohci
);
50 dev_err(hcd
->self
.controller
, "Can not start %s",
58 static int ohci_jz4740_set_vbus_power(struct jz4740_ohci_hcd
*jz4740_ohci
,
63 if (!jz4740_ohci
->vbus
)
66 if (enabled
&& !jz4740_ohci
->vbus_enabled
) {
67 ret
= regulator_enable(jz4740_ohci
->vbus
);
69 dev_err(jz4740_hcd_to_hcd(jz4740_ohci
)->self
.controller
,
70 "Could not power vbus\n");
71 } else if (!enabled
&& jz4740_ohci
->vbus_enabled
) {
72 ret
= regulator_disable(jz4740_ohci
->vbus
);
76 jz4740_ohci
->vbus_enabled
= enabled
;
81 static int ohci_jz4740_hub_control(struct usb_hcd
*hcd
, u16 typeReq
, u16 wValue
,
82 u16 wIndex
, char *buf
, u16 wLength
)
84 struct jz4740_ohci_hcd
*jz4740_ohci
= hcd_to_jz4740_hcd(hcd
);
89 if (wValue
== USB_PORT_FEAT_POWER
)
90 ret
= ohci_jz4740_set_vbus_power(jz4740_ohci
, true);
93 if (wValue
== USB_PORT_FEAT_POWER
)
94 ret
= ohci_jz4740_set_vbus_power(jz4740_ohci
, false);
101 return ohci_hub_control(hcd
, typeReq
, wValue
, wIndex
, buf
, wLength
);
105 static const struct hc_driver ohci_jz4740_hc_driver
= {
106 .description
= hcd_name
,
107 .product_desc
= "JZ4740 OHCI",
108 .hcd_priv_size
= sizeof(struct jz4740_ohci_hcd
),
111 * generic hardware linkage
114 .flags
= HCD_USB11
| HCD_MEMORY
,
117 * basic lifecycle operations
119 .start
= ohci_jz4740_start
,
121 .shutdown
= ohci_shutdown
,
124 * managing i/o requests and associated device resources
126 .urb_enqueue
= ohci_urb_enqueue
,
127 .urb_dequeue
= ohci_urb_dequeue
,
128 .endpoint_disable
= ohci_endpoint_disable
,
133 .get_frame_number
= ohci_get_frame
,
138 .hub_status_data
= ohci_hub_status_data
,
139 .hub_control
= ohci_jz4740_hub_control
,
141 .bus_suspend
= ohci_bus_suspend
,
142 .bus_resume
= ohci_bus_resume
,
144 .start_port_reset
= ohci_start_port_reset
,
148 static int jz4740_ohci_probe(struct platform_device
*pdev
)
152 struct jz4740_ohci_hcd
*jz4740_ohci
;
153 struct resource
*res
;
156 res
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
159 dev_err(&pdev
->dev
, "Failed to get platform resource\n");
163 irq
= platform_get_irq(pdev
, 0);
165 dev_err(&pdev
->dev
, "Failed to get platform irq\n");
169 hcd
= usb_create_hcd(&ohci_jz4740_hc_driver
, &pdev
->dev
, "jz4740");
171 dev_err(&pdev
->dev
, "Failed to create hcd.\n");
175 jz4740_ohci
= hcd_to_jz4740_hcd(hcd
);
177 res
= request_mem_region(res
->start
, resource_size(res
), hcd_name
);
179 dev_err(&pdev
->dev
, "Failed to request mem region.\n");
184 hcd
->rsrc_start
= res
->start
;
185 hcd
->rsrc_len
= resource_size(res
);
186 hcd
->regs
= ioremap(res
->start
, resource_size(res
));
189 dev_err(&pdev
->dev
, "Failed to ioremap registers.\n");
191 goto err_release_mem
;
194 jz4740_ohci
->clk
= clk_get(&pdev
->dev
, "uhc");
195 if (IS_ERR(jz4740_ohci
->clk
)) {
196 ret
= PTR_ERR(jz4740_ohci
->clk
);
197 dev_err(&pdev
->dev
, "Failed to get clock: %d\n", ret
);
201 jz4740_ohci
->vbus
= regulator_get(&pdev
->dev
, "vbus");
202 if (IS_ERR(jz4740_ohci
->vbus
))
203 jz4740_ohci
->vbus
= NULL
;
206 clk_set_rate(jz4740_ohci
->clk
, 48000000);
207 clk_enable(jz4740_ohci
->clk
);
208 if (jz4740_ohci
->vbus
)
209 ohci_jz4740_set_vbus_power(jz4740_ohci
, true);
211 platform_set_drvdata(pdev
, hcd
);
213 ohci_hcd_init(hcd_to_ohci(hcd
));
215 ret
= usb_add_hcd(hcd
, irq
, 0);
217 dev_err(&pdev
->dev
, "Failed to add hcd: %d\n", ret
);
224 platform_set_drvdata(pdev
, NULL
);
225 if (jz4740_ohci
->vbus
) {
226 regulator_disable(jz4740_ohci
->vbus
);
227 regulator_put(jz4740_ohci
->vbus
);
229 clk_disable(jz4740_ohci
->clk
);
231 clk_put(jz4740_ohci
->clk
);
235 release_mem_region(res
->start
, resource_size(res
));
242 static int jz4740_ohci_remove(struct platform_device
*pdev
)
244 struct usb_hcd
*hcd
= platform_get_drvdata(pdev
);
245 struct jz4740_ohci_hcd
*jz4740_ohci
= hcd_to_jz4740_hcd(hcd
);
249 platform_set_drvdata(pdev
, NULL
);
251 if (jz4740_ohci
->vbus
) {
252 regulator_disable(jz4740_ohci
->vbus
);
253 regulator_put(jz4740_ohci
->vbus
);
256 clk_disable(jz4740_ohci
->clk
);
257 clk_put(jz4740_ohci
->clk
);
260 release_mem_region(hcd
->rsrc_start
, hcd
->rsrc_len
);
267 static struct platform_driver ohci_hcd_jz4740_driver
= {
268 .probe
= jz4740_ohci_probe
,
269 .remove
= jz4740_ohci_remove
,
271 .name
= "jz4740-ohci",
272 .owner
= THIS_MODULE
,
276 MODULE_ALIAS("platform:jz4740-ohci");