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);
92 case ClearPortFeature
:
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 irq
= platform_get_irq(pdev
, 0);
158 dev_err(&pdev
->dev
, "Failed to get platform irq\n");
162 hcd
= usb_create_hcd(&ohci_jz4740_hc_driver
, &pdev
->dev
, "jz4740");
164 dev_err(&pdev
->dev
, "Failed to create hcd.\n");
168 jz4740_ohci
= hcd_to_jz4740_hcd(hcd
);
170 res
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
171 hcd
->regs
= devm_ioremap_resource(&pdev
->dev
, res
);
172 if (IS_ERR(hcd
->regs
)) {
173 ret
= PTR_ERR(hcd
->regs
);
176 hcd
->rsrc_start
= res
->start
;
177 hcd
->rsrc_len
= resource_size(res
);
179 jz4740_ohci
->clk
= devm_clk_get(&pdev
->dev
, "uhc");
180 if (IS_ERR(jz4740_ohci
->clk
)) {
181 ret
= PTR_ERR(jz4740_ohci
->clk
);
182 dev_err(&pdev
->dev
, "Failed to get clock: %d\n", ret
);
186 jz4740_ohci
->vbus
= devm_regulator_get(&pdev
->dev
, "vbus");
187 if (IS_ERR(jz4740_ohci
->vbus
))
188 jz4740_ohci
->vbus
= NULL
;
191 clk_set_rate(jz4740_ohci
->clk
, 48000000);
192 clk_enable(jz4740_ohci
->clk
);
193 if (jz4740_ohci
->vbus
)
194 ohci_jz4740_set_vbus_power(jz4740_ohci
, true);
196 platform_set_drvdata(pdev
, hcd
);
198 ohci_hcd_init(hcd_to_ohci(hcd
));
200 ret
= usb_add_hcd(hcd
, irq
, 0);
202 dev_err(&pdev
->dev
, "Failed to add hcd: %d\n", ret
);
205 device_wakeup_enable(hcd
->self
.controller
);
210 if (jz4740_ohci
->vbus
)
211 regulator_disable(jz4740_ohci
->vbus
);
212 clk_disable(jz4740_ohci
->clk
);
220 static int jz4740_ohci_remove(struct platform_device
*pdev
)
222 struct usb_hcd
*hcd
= platform_get_drvdata(pdev
);
223 struct jz4740_ohci_hcd
*jz4740_ohci
= hcd_to_jz4740_hcd(hcd
);
227 if (jz4740_ohci
->vbus
)
228 regulator_disable(jz4740_ohci
->vbus
);
230 clk_disable(jz4740_ohci
->clk
);
237 static struct platform_driver ohci_hcd_jz4740_driver
= {
238 .probe
= jz4740_ohci_probe
,
239 .remove
= jz4740_ohci_remove
,
241 .name
= "jz4740-ohci",
245 MODULE_ALIAS("platform:jz4740-ohci");