]> Pileus Git - ~andy/linux/blob - drivers/usb/host/ehci-ls1x.c
Merge branch 'for-linus' of git://git.linaro.org/people/rmk/linux-arm
[~andy/linux] / drivers / usb / host / ehci-ls1x.c
1 /*
2  *  Bus Glue for Loongson LS1X built-in EHCI controller.
3  *
4  *  Copyright (c) 2012 Zhang, Keguang <keguang.zhang@gmail.com>
5  *
6  *  This program is free software; you can redistribute it and/or modify it
7  *  under the terms of the GNU General Public License version 2 as published
8  *  by the Free Software Foundation.
9  */
10
11
12 #include <linux/platform_device.h>
13
14 static int ehci_ls1x_reset(struct usb_hcd *hcd)
15 {
16         struct ehci_hcd *ehci = hcd_to_ehci(hcd);
17         int ret;
18
19         ehci->caps = hcd->regs;
20
21         ret = ehci_setup(hcd);
22         if (ret)
23                 return ret;
24
25         ehci_port_power(ehci, 0);
26
27         return 0;
28 }
29
30 static const struct hc_driver ehci_ls1x_hc_driver = {
31         .description            = hcd_name,
32         .product_desc           = "LOONGSON1 EHCI",
33         .hcd_priv_size          = sizeof(struct ehci_hcd),
34
35         /*
36          * generic hardware linkage
37          */
38         .irq                    = ehci_irq,
39         .flags                  = HCD_MEMORY | HCD_USB2,
40
41         /*
42          * basic lifecycle operations
43          */
44         .reset                  = ehci_ls1x_reset,
45         .start                  = ehci_run,
46         .stop                   = ehci_stop,
47         .shutdown               = ehci_shutdown,
48
49         /*
50          * managing i/o requests and associated device resources
51          */
52         .urb_enqueue            = ehci_urb_enqueue,
53         .urb_dequeue            = ehci_urb_dequeue,
54         .endpoint_disable       = ehci_endpoint_disable,
55         .endpoint_reset         = ehci_endpoint_reset,
56
57         /*
58          * scheduling support
59          */
60         .get_frame_number       = ehci_get_frame,
61
62         /*
63          * root hub support
64          */
65         .hub_status_data        = ehci_hub_status_data,
66         .hub_control            = ehci_hub_control,
67         .relinquish_port        = ehci_relinquish_port,
68         .port_handed_over       = ehci_port_handed_over,
69
70         .clear_tt_buffer_complete       = ehci_clear_tt_buffer_complete,
71 };
72
73 static int ehci_hcd_ls1x_probe(struct platform_device *pdev)
74 {
75         struct usb_hcd *hcd;
76         struct resource *res;
77         int irq;
78         int ret;
79
80         pr_debug("initializing loongson1 ehci USB Controller\n");
81
82         if (usb_disabled())
83                 return -ENODEV;
84
85         res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
86         if (!res) {
87                 dev_err(&pdev->dev,
88                         "Found HC with no IRQ. Check %s setup!\n",
89                         dev_name(&pdev->dev));
90                 return -ENODEV;
91         }
92         irq = res->start;
93
94         res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
95         if (!res) {
96                 dev_err(&pdev->dev,
97                         "Found HC with no register addr. Check %s setup!\n",
98                         dev_name(&pdev->dev));
99                 return -ENODEV;
100         }
101
102         hcd = usb_create_hcd(&ehci_ls1x_hc_driver, &pdev->dev,
103                                 dev_name(&pdev->dev));
104         if (!hcd)
105                 return -ENOMEM;
106         hcd->rsrc_start = res->start;
107         hcd->rsrc_len   = resource_size(res);
108
109         hcd->regs = devm_request_and_ioremap(&pdev->dev, res);
110         if (hcd->regs == NULL) {
111                 dev_dbg(&pdev->dev, "error mapping memory\n");
112                 ret = -EFAULT;
113                 goto err_put_hcd;
114         }
115
116         ret = usb_add_hcd(hcd, irq, IRQF_SHARED);
117         if (ret)
118                 goto err_put_hcd;
119
120         return ret;
121
122 err_put_hcd:
123         usb_put_hcd(hcd);
124         return ret;
125 }
126
127 static int ehci_hcd_ls1x_remove(struct platform_device *pdev)
128 {
129         struct usb_hcd *hcd = platform_get_drvdata(pdev);
130
131         usb_remove_hcd(hcd);
132         usb_put_hcd(hcd);
133
134         return 0;
135 }
136
137 static struct platform_driver ehci_ls1x_driver = {
138         .probe = ehci_hcd_ls1x_probe,
139         .remove = ehci_hcd_ls1x_remove,
140         .shutdown = usb_hcd_platform_shutdown,
141         .driver = {
142                 .name = "ls1x-ehci",
143                 .owner  = THIS_MODULE,
144         },
145 };
146
147 MODULE_ALIAS(PLATFORM_MODULE_PREFIX "ls1x-ehci");