Add the rt linux 4.1.3-rt3 as base
[kvmfornfv.git] / kernel / drivers / usb / host / fhci-hub.c
1 /*
2  * Freescale QUICC Engine USB Host Controller Driver
3  *
4  * Copyright (c) Freescale Semicondutor, Inc. 2006.
5  *               Shlomi Gridish <gridish@freescale.com>
6  *               Jerry Huang <Chang-Ming.Huang@freescale.com>
7  * Copyright (c) Logic Product Development, Inc. 2007
8  *               Peter Barada <peterb@logicpd.com>
9  * Copyright (c) MontaVista Software, Inc. 2008.
10  *               Anton Vorontsov <avorontsov@ru.mvista.com>
11  *
12  * This program is free software; you can redistribute  it and/or modify it
13  * under  the terms of  the GNU General  Public License as published by the
14  * Free Software Foundation;  either version 2 of the  License, or (at your
15  * option) any later version.
16  */
17
18 #include <linux/kernel.h>
19 #include <linux/types.h>
20 #include <linux/spinlock.h>
21 #include <linux/delay.h>
22 #include <linux/errno.h>
23 #include <linux/io.h>
24 #include <linux/usb.h>
25 #include <linux/usb/hcd.h>
26 #include <linux/gpio.h>
27 #include <asm/qe.h>
28 #include "fhci.h"
29
30 /* virtual root hub specific descriptor */
31 static u8 root_hub_des[] = {
32         0x09, /* blength */
33         USB_DT_HUB, /* bDescriptorType;hub-descriptor */
34         0x01, /* bNbrPorts */
35         HUB_CHAR_INDV_PORT_LPSM | HUB_CHAR_NO_OCPM, /* wHubCharacteristics */
36         0x00, /* per-port power, no overcurrent */
37         0x01, /* bPwrOn2pwrGood;2ms */
38         0x00, /* bHubContrCurrent;0mA */
39         0x00, /* DeviceRemoveable */
40         0xff, /* PortPwrCtrlMask */
41 };
42
43 static void fhci_gpio_set_value(struct fhci_hcd *fhci, int gpio_nr, bool on)
44 {
45         int gpio = fhci->gpios[gpio_nr];
46         bool alow = fhci->alow_gpios[gpio_nr];
47
48         if (!gpio_is_valid(gpio))
49                 return;
50
51         gpio_set_value(gpio, on ^ alow);
52         mdelay(5);
53 }
54
55 void fhci_config_transceiver(struct fhci_hcd *fhci,
56                              enum fhci_port_status status)
57 {
58         fhci_dbg(fhci, "-> %s: %d\n", __func__, status);
59
60         switch (status) {
61         case FHCI_PORT_POWER_OFF:
62                 fhci_gpio_set_value(fhci, GPIO_POWER, false);
63                 break;
64         case FHCI_PORT_DISABLED:
65         case FHCI_PORT_WAITING:
66                 fhci_gpio_set_value(fhci, GPIO_POWER, true);
67                 break;
68         case FHCI_PORT_LOW:
69                 fhci_gpio_set_value(fhci, GPIO_SPEED, false);
70                 break;
71         case FHCI_PORT_FULL:
72                 fhci_gpio_set_value(fhci, GPIO_SPEED, true);
73                 break;
74         default:
75                 WARN_ON(1);
76                 break;
77         }
78
79         fhci_dbg(fhci, "<- %s: %d\n", __func__, status);
80 }
81
82 /* disable the USB port by clearing the EN bit in the USBMOD register */
83 void fhci_port_disable(struct fhci_hcd *fhci)
84 {
85         struct fhci_usb *usb = (struct fhci_usb *)fhci->usb_lld;
86         enum fhci_port_status port_status;
87
88         fhci_dbg(fhci, "-> %s\n", __func__);
89
90         fhci_stop_sof_timer(fhci);
91
92         fhci_flush_all_transmissions(usb);
93
94         fhci_usb_disable_interrupt((struct fhci_usb *)fhci->usb_lld);
95         port_status = usb->port_status;
96         usb->port_status = FHCI_PORT_DISABLED;
97
98         /* Enable IDLE since we want to know if something comes along */
99         usb->saved_msk |= USB_E_IDLE_MASK;
100         out_be16(&usb->fhci->regs->usb_usbmr, usb->saved_msk);
101
102         /* check if during the disconnection process attached new device */
103         if (port_status == FHCI_PORT_WAITING)
104                 fhci_device_connected_interrupt(fhci);
105         usb->vroot_hub->port.wPortStatus &= ~USB_PORT_STAT_ENABLE;
106         usb->vroot_hub->port.wPortChange |= USB_PORT_STAT_C_ENABLE;
107         fhci_usb_enable_interrupt((struct fhci_usb *)fhci->usb_lld);
108
109         fhci_dbg(fhci, "<- %s\n", __func__);
110 }
111
112 /* enable the USB port by setting the EN bit in the USBMOD register */
113 void fhci_port_enable(void *lld)
114 {
115         struct fhci_usb *usb = (struct fhci_usb *)lld;
116         struct fhci_hcd *fhci = usb->fhci;
117
118         fhci_dbg(fhci, "-> %s\n", __func__);
119
120         fhci_config_transceiver(fhci, usb->port_status);
121
122         if ((usb->port_status != FHCI_PORT_FULL) &&
123                         (usb->port_status != FHCI_PORT_LOW))
124                 fhci_start_sof_timer(fhci);
125
126         usb->vroot_hub->port.wPortStatus |= USB_PORT_STAT_ENABLE;
127         usb->vroot_hub->port.wPortChange |= USB_PORT_STAT_C_ENABLE;
128
129         fhci_dbg(fhci, "<- %s\n", __func__);
130 }
131
132 void fhci_io_port_generate_reset(struct fhci_hcd *fhci)
133 {
134         fhci_dbg(fhci, "-> %s\n", __func__);
135
136         gpio_direction_output(fhci->gpios[GPIO_USBOE], 0);
137         gpio_direction_output(fhci->gpios[GPIO_USBTP], 0);
138         gpio_direction_output(fhci->gpios[GPIO_USBTN], 0);
139
140         mdelay(5);
141
142         qe_pin_set_dedicated(fhci->pins[PIN_USBOE]);
143         qe_pin_set_dedicated(fhci->pins[PIN_USBTP]);
144         qe_pin_set_dedicated(fhci->pins[PIN_USBTN]);
145
146         fhci_dbg(fhci, "<- %s\n", __func__);
147 }
148
149 /* generate the RESET condition on the bus */
150 void fhci_port_reset(void *lld)
151 {
152         struct fhci_usb *usb = (struct fhci_usb *)lld;
153         struct fhci_hcd *fhci = usb->fhci;
154         u8 mode;
155         u16 mask;
156
157         fhci_dbg(fhci, "-> %s\n", __func__);
158
159         fhci_stop_sof_timer(fhci);
160         /* disable the USB controller */
161         mode = in_8(&fhci->regs->usb_usmod);
162         out_8(&fhci->regs->usb_usmod, mode & (~USB_MODE_EN));
163
164         /* disable idle interrupts */
165         mask = in_be16(&fhci->regs->usb_usbmr);
166         out_be16(&fhci->regs->usb_usbmr, mask & (~USB_E_IDLE_MASK));
167
168         fhci_io_port_generate_reset(fhci);
169
170         /* enable interrupt on this endpoint */
171         out_be16(&fhci->regs->usb_usbmr, mask);
172
173         /* enable the USB controller */
174         mode = in_8(&fhci->regs->usb_usmod);
175         out_8(&fhci->regs->usb_usmod, mode | USB_MODE_EN);
176         fhci_start_sof_timer(fhci);
177
178         fhci_dbg(fhci, "<- %s\n", __func__);
179 }
180
181 int fhci_hub_status_data(struct usb_hcd *hcd, char *buf)
182 {
183         struct fhci_hcd *fhci = hcd_to_fhci(hcd);
184         int ret = 0;
185         unsigned long flags;
186
187         fhci_dbg(fhci, "-> %s\n", __func__);
188
189         spin_lock_irqsave(&fhci->lock, flags);
190
191         if (fhci->vroot_hub->port.wPortChange & (USB_PORT_STAT_C_CONNECTION |
192                         USB_PORT_STAT_C_ENABLE | USB_PORT_STAT_C_SUSPEND |
193                         USB_PORT_STAT_C_RESET | USB_PORT_STAT_C_OVERCURRENT)) {
194                 *buf = 1 << 1;
195                 ret = 1;
196                 fhci_dbg(fhci, "-- %s\n", __func__);
197         }
198
199         spin_unlock_irqrestore(&fhci->lock, flags);
200
201         fhci_dbg(fhci, "<- %s\n", __func__);
202
203         return ret;
204 }
205
206 int fhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
207                             u16 wIndex, char *buf, u16 wLength)
208 {
209         struct fhci_hcd *fhci = hcd_to_fhci(hcd);
210         int retval = 0;
211         struct usb_hub_status *hub_status;
212         struct usb_port_status *port_status;
213         unsigned long flags;
214
215         spin_lock_irqsave(&fhci->lock, flags);
216
217         fhci_dbg(fhci, "-> %s\n", __func__);
218
219         switch (typeReq) {
220         case ClearHubFeature:
221                 switch (wValue) {
222                 case C_HUB_LOCAL_POWER:
223                 case C_HUB_OVER_CURRENT:
224                         break;
225                 default:
226                         goto error;
227                 }
228                 break;
229         case ClearPortFeature:
230                 fhci->vroot_hub->feature &= (1 << wValue);
231
232                 switch (wValue) {
233                 case USB_PORT_FEAT_ENABLE:
234                         fhci->vroot_hub->port.wPortStatus &=
235                             ~USB_PORT_STAT_ENABLE;
236                         fhci_port_disable(fhci);
237                         break;
238                 case USB_PORT_FEAT_C_ENABLE:
239                         fhci->vroot_hub->port.wPortChange &=
240                             ~USB_PORT_STAT_C_ENABLE;
241                         break;
242                 case USB_PORT_FEAT_SUSPEND:
243                         fhci->vroot_hub->port.wPortStatus &=
244                             ~USB_PORT_STAT_SUSPEND;
245                         fhci_stop_sof_timer(fhci);
246                         break;
247                 case USB_PORT_FEAT_C_SUSPEND:
248                         fhci->vroot_hub->port.wPortChange &=
249                             ~USB_PORT_STAT_C_SUSPEND;
250                         break;
251                 case USB_PORT_FEAT_POWER:
252                         fhci->vroot_hub->port.wPortStatus &=
253                             ~USB_PORT_STAT_POWER;
254                         fhci_config_transceiver(fhci, FHCI_PORT_POWER_OFF);
255                         break;
256                 case USB_PORT_FEAT_C_CONNECTION:
257                         fhci->vroot_hub->port.wPortChange &=
258                             ~USB_PORT_STAT_C_CONNECTION;
259                         break;
260                 case USB_PORT_FEAT_C_OVER_CURRENT:
261                         fhci->vroot_hub->port.wPortChange &=
262                             ~USB_PORT_STAT_C_OVERCURRENT;
263                         break;
264                 case USB_PORT_FEAT_C_RESET:
265                         fhci->vroot_hub->port.wPortChange &=
266                             ~USB_PORT_STAT_C_RESET;
267                         break;
268                 default:
269                         goto error;
270                 }
271                 break;
272         case GetHubDescriptor:
273                 memcpy(buf, root_hub_des, sizeof(root_hub_des));
274                 break;
275         case GetHubStatus:
276                 hub_status = (struct usb_hub_status *)buf;
277                 hub_status->wHubStatus =
278                     cpu_to_le16(fhci->vroot_hub->hub.wHubStatus);
279                 hub_status->wHubChange =
280                     cpu_to_le16(fhci->vroot_hub->hub.wHubChange);
281                 break;
282         case GetPortStatus:
283                 port_status = (struct usb_port_status *)buf;
284                 port_status->wPortStatus =
285                     cpu_to_le16(fhci->vroot_hub->port.wPortStatus);
286                 port_status->wPortChange =
287                     cpu_to_le16(fhci->vroot_hub->port.wPortChange);
288                 break;
289         case SetHubFeature:
290                 switch (wValue) {
291                 case C_HUB_OVER_CURRENT:
292                 case C_HUB_LOCAL_POWER:
293                         break;
294                 default:
295                         goto error;
296                 }
297                 break;
298         case SetPortFeature:
299                 fhci->vroot_hub->feature |= (1 << wValue);
300
301                 switch (wValue) {
302                 case USB_PORT_FEAT_ENABLE:
303                         fhci->vroot_hub->port.wPortStatus |=
304                             USB_PORT_STAT_ENABLE;
305                         fhci_port_enable(fhci->usb_lld);
306                         break;
307                 case USB_PORT_FEAT_SUSPEND:
308                         fhci->vroot_hub->port.wPortStatus |=
309                             USB_PORT_STAT_SUSPEND;
310                         fhci_stop_sof_timer(fhci);
311                         break;
312                 case USB_PORT_FEAT_RESET:
313                         fhci->vroot_hub->port.wPortStatus |=
314                             USB_PORT_STAT_RESET;
315                         fhci_port_reset(fhci->usb_lld);
316                         fhci->vroot_hub->port.wPortStatus |=
317                             USB_PORT_STAT_ENABLE;
318                         fhci->vroot_hub->port.wPortStatus &=
319                             ~USB_PORT_STAT_RESET;
320                         break;
321                 case USB_PORT_FEAT_POWER:
322                         fhci->vroot_hub->port.wPortStatus |=
323                             USB_PORT_STAT_POWER;
324                         fhci_config_transceiver(fhci, FHCI_PORT_WAITING);
325                         break;
326                 default:
327                         goto error;
328                 }
329                 break;
330         default:
331 error:
332                 retval = -EPIPE;
333         }
334
335         fhci_dbg(fhci, "<- %s\n", __func__);
336
337         spin_unlock_irqrestore(&fhci->lock, flags);
338
339         return retval;
340 }