Date:2010-04-24 17:18:49 (10 years 2 months ago)
Author:Lars C.
Commit:0e349d2491fafb9788921e42503906e404555f43
Message:Add jz4740 ohci driver

Files: drivers/usb/Kconfig (1 diff)
drivers/usb/host/ohci-hcd.c (1 diff)
drivers/usb/host/ohci-jz4740.c (1 diff)

Change Details

drivers/usb/Kconfig
4646    default y if PPC_MPC52xx
4747    # MIPS:
4848    default y if SOC_AU1X00
49    default y if SOC_JZ4740
4950    # SH:
5051    default y if CPU_SUBTYPE_SH7720
5152    default y if CPU_SUBTYPE_SH7721
drivers/usb/host/ohci-hcd.c
10901090#define TMIO_OHCI_DRIVER ohci_hcd_tmio_driver
10911091#endif
10921092
1093#ifdef CONFIG_SOC_JZ4740
1094#include "ohci-jz4740.c"
1095#define PLATFORM_DRIVER ohci_hcd_jz4740_driver
1096#endif
1097
10931098#if !defined(PCI_DRIVER) && \
10941099    !defined(PLATFORM_DRIVER) && \
10951100    !defined(OF_PLATFORM_DRIVER) && \
drivers/usb/host/ohci-jz4740.c
1
2#include <linux/platform_device.h>
3#include <linux/clk.h>
4#include <linux/regulator/consumer.h>
5
6struct jz4740_ohci_hcd {
7    struct ohci_hcd ohci_hcd;
8
9    struct regulator *vbus;
10    bool vbus_enabled;
11    struct clk *clk;
12};
13
14static inline struct jz4740_ohci_hcd *hcd_to_jz4740_hcd(struct usb_hcd *hcd)
15{
16    return (struct jz4740_ohci_hcd *)(hcd->hcd_priv);
17}
18
19static inline struct usb_hcd *jz4740_hcd_to_hcd(struct jz4740_ohci_hcd *jz4740_ohci)
20{
21    return container_of ((void *) jz4740_ohci, struct usb_hcd, hcd_priv);
22}
23
24
25static int ohci_jz4740_start(struct usb_hcd *hcd)
26{
27    struct ohci_hcd *ohci = hcd_to_ohci(hcd);
28    int ret;
29
30    ret = ohci_init(ohci);
31    if (ret < 0)
32        return ret;
33
34    ohci->num_ports = 1;
35
36    ret = ohci_run(ohci);
37    if (ret < 0) {
38        dev_err(hcd->self.controller, "Can not start %s",
39            hcd->self.bus_name);
40        ohci_stop(hcd);
41        return ret;
42    }
43    return 0;
44}
45
46static int ohci_jz4740_set_vbus_power(struct jz4740_ohci_hcd *jz4740_ohci,
47    bool enabled)
48{
49    int ret = 0;
50
51    if (enabled && !jz4740_ohci->vbus_enabled) {
52        ret = regulator_enable(jz4740_ohci->vbus);
53        if (ret)
54            dev_err(jz4740_hcd_to_hcd(jz4740_ohci)->self.controller,
55                "Could not power vbus\n");
56    } else if(!enabled && jz4740_ohci->vbus_enabled) {
57        ret = regulator_disable(jz4740_ohci->vbus);
58    }
59
60    if (ret == 0)
61        jz4740_ohci->vbus_enabled = enabled;
62
63    return ret;
64}
65
66static int ohci_jz4740_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
67    u16 wIndex, char *buf, u16 wLength)
68{
69    struct jz4740_ohci_hcd *jz4740_ohci = hcd_to_jz4740_hcd(hcd);
70    int ret;
71
72    if (jz4740_ohci->vbus) {
73        switch (typeReq) {
74        case SetHubFeature:
75            if (wValue == USB_PORT_FEAT_POWER)
76                ret = ohci_jz4740_set_vbus_power(jz4740_ohci, true);
77            break;
78        case ClearHubFeature:
79            if (wValue == USB_PORT_FEAT_POWER)
80                ret = ohci_jz4740_set_vbus_power(jz4740_ohci, false);
81            break;
82        }
83    }
84
85    if (ret)
86        return ret;
87
88    return ohci_hub_control(hcd, typeReq, wValue, wIndex, buf, wLength);
89}
90
91
92static const struct hc_driver ohci_jz4740_hc_driver = {
93    .description = hcd_name,
94    .product_desc = "JZ4740 OHCI",
95    .hcd_priv_size = sizeof(struct jz4740_ohci_hcd),
96
97    /*
98     * generic hardware linkage
99     */
100    .irq = ohci_irq,
101    .flags = HCD_USB11 | HCD_MEMORY,
102
103    /*
104     * basic lifecycle operations
105     */
106    .start = ohci_jz4740_start,
107    .stop = ohci_stop,
108    .shutdown = ohci_shutdown,
109
110    /*
111     * managing i/o requests and associated device resources
112     */
113    .urb_enqueue = ohci_urb_enqueue,
114    .urb_dequeue = ohci_urb_dequeue,
115    .endpoint_disable = ohci_endpoint_disable,
116
117    /*
118     * scheduling support
119     */
120    .get_frame_number = ohci_get_frame,
121
122    /*
123     * root hub support
124     */
125    .hub_status_data = ohci_hub_status_data,
126    .hub_control = ohci_jz4740_hub_control,
127#ifdef CONFIG_PM
128    .bus_suspend = ohci_bus_suspend,
129    .bus_resume = ohci_bus_resume,
130#endif
131    .start_port_reset = ohci_start_port_reset,
132};
133
134
135static __devinit int jz4740_ohci_probe(struct platform_device *pdev)
136{
137    int ret;
138    struct usb_hcd *hcd;
139    struct jz4740_ohci_hcd *jz4740_ohci;
140    struct resource *res;
141    int irq;
142
143    res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
144
145    if (!res) {
146        dev_err(&pdev->dev, "Failed to get platform resource\n");
147        return -ENOENT;
148    }
149
150    irq = platform_get_irq(pdev, 0);
151    if (irq < 0) {
152        dev_err(&pdev->dev, "Failed to get platform irq\n");
153        return irq;
154    }
155
156    hcd = usb_create_hcd(&ohci_jz4740_hc_driver, &pdev->dev, "jz4740");
157    if (!hcd) {
158        dev_err(&pdev->dev, "Failed to create hcd.\n");
159        return -ENOMEM;
160    }
161
162    jz4740_ohci = hcd_to_jz4740_hcd(hcd);
163
164    res = request_mem_region(res->start, resource_size(res), hcd_name);
165
166    if (!res) {
167        dev_err(&pdev->dev, "Failed to request mem region.\n");
168        ret = -EBUSY;
169        goto err_free;
170    }
171
172    hcd->rsrc_start = res->start;
173    hcd->rsrc_len = resource_size(res);
174    hcd->regs = ioremap(res->start, resource_size(res));
175
176    if (!hcd->regs) {
177        dev_err(&pdev->dev, "Failed to ioremap registers.\n");
178        ret = -EBUSY;
179        goto err_release_mem;
180    }
181
182    jz4740_ohci->clk = clk_get(&pdev->dev, "uhc");
183    if (IS_ERR(jz4740_ohci->clk)) {
184        ret = PTR_ERR(jz4740_ohci->clk);
185        dev_err(&pdev->dev, "Failed to get clock: %d\n", ret);
186        goto err_iounmap;
187    }
188
189    jz4740_ohci->vbus = regulator_get(&pdev->dev, "vbus");
190    if (IS_ERR(jz4740_ohci->vbus))
191        jz4740_ohci->vbus = NULL;
192
193
194    clk_set_rate(jz4740_ohci->clk, 48000000);
195    clk_enable(jz4740_ohci->clk);
196    if (jz4740_ohci->vbus)
197        ohci_jz4740_set_vbus_power(jz4740_ohci, true);
198
199    platform_set_drvdata(pdev, hcd);
200
201    ohci_hcd_init(hcd_to_ohci(hcd));
202
203    ret = usb_add_hcd(hcd, irq, IRQF_DISABLED);
204    if (ret) {
205        dev_err(&pdev->dev, "Failed to add hcd: %d\n", ret);
206        goto err_disable;
207    }
208
209    return 0;
210
211err_disable:
212    platform_set_drvdata(pdev, NULL);
213    if (jz4740_ohci->vbus) {
214        regulator_disable(jz4740_ohci->vbus);
215        regulator_put(jz4740_ohci->vbus);
216    }
217    clk_disable(jz4740_ohci->clk);
218
219    clk_put(jz4740_ohci->clk);
220err_iounmap:
221    iounmap(hcd->regs);
222err_release_mem:
223    release_mem_region(res->start, resource_size(res));
224err_free:
225    usb_put_hcd(hcd);
226
227    return ret;
228}
229
230static __devexit int jz4740_ohci_remove(struct platform_device *pdev)
231{
232    struct usb_hcd *hcd = platform_get_drvdata(pdev);
233    struct jz4740_ohci_hcd *jz4740_ohci = hcd_to_jz4740_hcd(hcd);
234
235    usb_remove_hcd(hcd);
236
237    platform_set_drvdata(pdev, NULL);
238
239    if (jz4740_ohci->vbus) {
240        regulator_disable(jz4740_ohci->vbus);
241        regulator_put(jz4740_ohci->vbus);
242    }
243
244    clk_disable(jz4740_ohci->clk);
245    clk_put(jz4740_ohci->clk);
246
247    iounmap(hcd->regs);
248    release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
249
250    usb_put_hcd(hcd);
251
252    return 0;
253}
254
255static struct platform_driver ohci_hcd_jz4740_driver = {
256    .probe = jz4740_ohci_probe,
257    .remove = __devexit_p(jz4740_ohci_remove),
258    .driver = {
259        .name = "jz4740-ohci",
260        .owner = THIS_MODULE,
261    },
262};
263
264MODULE_ALIAS("platfrom:jz4740-ohci");

Archive Download the corresponding diff file



interactive