USB: RK3288 USB CTLR initialization
[firefly-linux-kernel-4.4.55.git] / drivers / usb / host / ohci-rk.c
1 /*
2  * ROCKCHIP USB HOST OHCI Controller
3  *
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.
8  *
9  */
10
11 #include <linux/platform_device.h>
12 #include <linux/pm_runtime.h>
13 #include <linux/of.h>
14 #include <linux/clk.h>
15 #include <linux/dma-mapping.h>
16 #include <linux/of_platform.h>
17 #ifdef CONFIG_DWC_OTG_274
18 # include "../dwc_otg/usbdev_rk.h"
19 #endif
20 #ifdef CONFIG_DWC_OTG_310
21 # include "../dwc_otg_310/usbdev_rk.h"
22 #endif
23
24 static struct rkehci_pdata_id rkohci_pdata[] = {
25         {
26                 .name = "rk3188-reserved",
27                 .pdata = NULL,
28         },
29         {       
30                 .name = "rk3288-ohci",
31                 .pdata = &rkohci_pdata_rk3288,
32         },
33         { },
34 };
35
36 static int ohci_rk_init(struct usb_hcd *hcd)
37 {
38         dev_dbg(hcd->self.controller, "starting OHCI controller\n");
39
40         return ohci_init(hcd_to_ohci(hcd));
41 }
42
43 static int ohci_rk_start(struct usb_hcd *hcd)
44 {
45         struct ohci_hcd *ohci = hcd_to_ohci(hcd);
46         int ret;
47
48         /*
49          * RemoteWakeupConnected has to be set explicitly before
50          * calling ohci_run. The reset value of RWC is 0.
51          */
52         ohci->hc_control = OHCI_CTRL_RWC;
53         writel(OHCI_CTRL_RWC, &ohci->regs->control);
54
55         ret = ohci_run(ohci);
56
57         if (ret < 0) {
58                 dev_err(hcd->self.controller, "can't start\n");
59                 ohci_stop(hcd);
60         }
61
62         return ret;
63 }
64
65 static const struct hc_driver ohci_rk_hc_driver = {
66         .description =          hcd_name,
67         .product_desc =         "RK OHCI Host Controller",
68         .hcd_priv_size =        sizeof(struct ohci_hcd),
69
70         /*
71          * generic hardware linkage
72          */
73         .irq =                  ohci_irq,
74         .flags =                HCD_USB11 | HCD_MEMORY,
75
76         /*
77          * basic lifecycle operations
78          */
79         .reset =                ohci_rk_init,
80         .start =                ohci_rk_start,
81         .stop =                 ohci_stop,
82         .shutdown =             ohci_shutdown,
83
84         /*
85          * managing i/o requests and associated device resources
86          */
87         .urb_enqueue =          ohci_urb_enqueue,
88         .urb_dequeue =          ohci_urb_dequeue,
89         .endpoint_disable =     ohci_endpoint_disable,
90
91         /*
92          * scheduling support
93          */
94         .get_frame_number =     ohci_get_frame,
95
96         /*
97          * root hub support
98          */
99         .hub_status_data =      ohci_hub_status_data,
100         .hub_control =          ohci_hub_control,
101 #ifdef  CONFIG_PM
102         .bus_suspend =          ohci_bus_suspend,
103         .bus_resume =           ohci_bus_resume,
104 #endif
105         .start_port_reset =     ohci_start_port_reset,
106 };
107
108 static struct of_device_id rk_ohci_of_match[] = {
109         {
110                 .compatible = "rockchip,rk3288_rk_ohci_host",
111                 .data = &rkohci_pdata[RK3288_USB_CTLR],
112         },
113         { },
114 };
115 MODULE_DEVICE_TABLE(of, rk_ohci_of_match);
116
117 /* ohci_hcd_rk_probe - initialize RK-based HCDs
118  * Allocates basic resources for this USB host controller, and
119  * then invokes the start() method for the HCD associated with it
120  * through the hotplug entry's driver_data.
121  */
122 static int ohci_hcd_rk_probe(struct platform_device *pdev)
123 {
124         struct device           *dev = &pdev->dev;
125         struct usb_hcd          *hcd = NULL;
126         void __iomem            *regs = NULL;
127         struct resource         *res;
128         int                     ret = -ENODEV;
129         int                     irq;
130         struct rkehci_platform_data *pldata;
131         struct device_node      *node = pdev->dev.of_node;
132         struct rkehci_pdata_id *p;
133         const struct of_device_id *match =
134                 of_match_device(of_match_ptr( rk_ohci_of_match ), &pdev->dev);
135
136         dev_dbg(&pdev->dev, "ohci_hcd_rk_probe\n");
137
138         if (usb_disabled())
139                 return -ENODEV;
140
141         if (match){
142                 p = (struct rkehci_pdata_id *)match->data;
143         }else{
144                 dev_err(dev, "ohci_rk match failed\n");
145                 return -EINVAL;
146         }
147
148         dev->platform_data = p->pdata;
149         pldata = dev->platform_data;
150         pldata->dev = dev;
151
152         if (!node) {
153                 dev_err(dev, "device node not found\n");
154                 return -EINVAL;
155         }
156         
157         if(pldata->hw_init)
158                 pldata->hw_init();
159
160         if(pldata->clock_init){
161                 pldata->clock_init(pldata);
162                 pldata->clock_enable(pldata, 1);
163         }
164
165         if(pldata->soft_reset)
166                 pldata->soft_reset();
167
168         irq = platform_get_irq(pdev, 0);
169         if (irq < 0) {
170                 dev_err(dev, "OHCI irq failed\n");
171                 ret = irq;
172                 goto clk_disable;
173         }
174
175         res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
176         if (!res) {
177                 dev_err(dev, "UHH OHCI get resource failed\n");
178                 ret = -ENOMEM;
179                 goto clk_disable;
180         }
181
182         regs = devm_ioremap_resource(dev, res);
183         if (!regs) {
184                 dev_err(dev, "UHH OHCI ioremap failed\n");
185                 ret = -ENOMEM;
186                 goto clk_disable;
187         }
188
189         /*
190          * Right now device-tree probed devices don't get dma_mask set.
191          * Since shared usb code relies on it, set it here for now.
192          * Once we have dma capability bindings this can go away.
193          */
194         if (!dev->dma_mask)
195                 dev->dma_mask = &dev->coherent_dma_mask;
196         if (!dev->coherent_dma_mask)
197                 dev->coherent_dma_mask = DMA_BIT_MASK(32);
198
199         hcd = usb_create_hcd(&ohci_rk_hc_driver, dev,
200                         dev_name(dev));
201         if (!hcd) {
202                 dev_err(dev, "usb_create_hcd failed\n");
203                 ret = -ENOMEM;
204                 goto clk_disable;
205         }
206
207         hcd->rsrc_start = res->start;
208         hcd->rsrc_len = resource_size(res);
209         hcd->regs =  regs;
210
211         ohci_hcd_init(hcd_to_ohci(hcd));
212
213         ret = usb_add_hcd(hcd, irq, 0);
214         if (ret) {
215                 dev_dbg(dev, "failed to add hcd with err %d\n", ret);
216                 goto err_add_hcd;
217         }
218
219         return 0;
220
221 err_add_hcd:
222         usb_put_hcd(hcd);
223
224 clk_disable:
225         if(pldata->clock_enable)
226                 pldata->clock_enable(pldata, 0);
227
228         return ret;
229 }
230
231 static int ohci_hcd_rk_remove(struct platform_device *pdev)
232 {
233         struct device *dev      = &pdev->dev;
234         struct usb_hcd *hcd     = dev_get_drvdata(dev);
235
236         usb_remove_hcd(hcd);
237         usb_put_hcd(hcd);
238         return 0;
239 }
240
241 static void ohci_hcd_rk_shutdown(struct platform_device *pdev)
242 {
243         struct usb_hcd *hcd = dev_get_drvdata(&pdev->dev);
244
245         if (hcd->driver->shutdown)
246                 hcd->driver->shutdown(hcd);
247 }
248
249 static struct platform_driver ohci_hcd_rk_driver = {
250         .probe          = ohci_hcd_rk_probe,
251         .remove         = ohci_hcd_rk_remove,
252         .shutdown       = ohci_hcd_rk_shutdown,
253         .driver         = {
254                 .name   = "ohci-rk",
255                 .of_match_table = of_match_ptr(rk_ohci_of_match),
256         },
257 };
258 MODULE_ALIAS("platform:rockchip-ohci");