[adm5120] cleanup files using checkpatch.pl
[openwrt.git] / target / linux / adm5120 / files / drivers / usb / host / adm5120-hub.c
1 /*
2  * ADM5120 HCD (Host Controller Driver) for USB
3  *
4  * Copyright (C) 2007-2008 Gabor Juhos <juhosg@openwrt.org>
5  *
6  * This file was derived from: drivers/usb/host/ohci-hub.c
7  *   (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>
8  *   (C) Copyright 2000-2004 David Brownell <dbrownell@users.sourceforge.net>
9  *
10  *  This program is free software; you can redistribute it and/or modify it
11  *  under the terms of the GNU General Public License version 2 as published
12  *  by the Free Software Foundation.
13  *
14  */
15
16 /*-------------------------------------------------------------------------*/
17
18 /*
19  * ADM5120 Root Hub ... the nonsharable stuff
20  */
21
22 #define dbg_port(hc, label, num, value) \
23         admhc_dbg(hc, \
24                 "%s port%d " \
25                 "= 0x%08x%s%s%s%s%s%s%s%s%s%s%s%s\n", \
26                 label, num, value, \
27                 (value & ADMHC_PS_PRSC) ? " PRSC" : "", \
28                 (value & ADMHC_PS_OCIC) ? " OCIC" : "", \
29                 (value & ADMHC_PS_PSSC) ? " PSSC" : "", \
30                 (value & ADMHC_PS_PESC) ? " PESC" : "", \
31                 (value & ADMHC_PS_CSC) ? " CSC" : "", \
32                 \
33                 (value & ADMHC_PS_LSDA) ? " LSDA" : "", \
34                 (value & ADMHC_PS_PPS) ? " PPS" : "", \
35                 (value & ADMHC_PS_PRS) ? " PRS" : "", \
36                 (value & ADMHC_PS_POCI) ? " POCI" : "", \
37                 (value & ADMHC_PS_PSS) ? " PSS" : "", \
38                 \
39                 (value & ADMHC_PS_PES) ? " PES" : "", \
40                 (value & ADMHC_PS_CCS) ? " CCS" : "" \
41                 );
42
43 #define dbg_port_write(hc, label, num, value) \
44         admhc_dbg(hc, \
45                 "%s port%d " \
46                 "= 0x%08x%s%s%s%s%s%s%s%s%s%s%s%s\n", \
47                 label, num, value, \
48                 (value & ADMHC_PS_PRSC) ? " PRSC" : "", \
49                 (value & ADMHC_PS_OCIC) ? " OCIC" : "", \
50                 (value & ADMHC_PS_PSSC) ? " PSSC" : "", \
51                 (value & ADMHC_PS_PESC) ? " PESC" : "", \
52                 (value & ADMHC_PS_CSC) ? " CSC" : "", \
53                 \
54                 (value & ADMHC_PS_CPP) ? " CPP" : "", \
55                 (value & ADMHC_PS_SPP) ? " SPP" : "", \
56                 (value & ADMHC_PS_SPR) ? " SPR" : "", \
57                 (value & ADMHC_PS_CPS) ? " CPS" : "", \
58                 (value & ADMHC_PS_SPS) ? " SPS" : "", \
59                 \
60                 (value & ADMHC_PS_SPE) ? " SPE" : "", \
61                 (value & ADMHC_PS_CPE) ? " CPE" : "" \
62                 );
63
64 /*-------------------------------------------------------------------------*/
65
66 /* build "status change" packet (one or two bytes) from HC registers */
67
68 static int
69 admhc_hub_status_data(struct usb_hcd *hcd, char *buf)
70 {
71         struct admhcd   *ahcd = hcd_to_admhcd(hcd);
72         int             i, changed = 0, length = 1;
73         int             any_connected = 0;
74         unsigned long   flags;
75         u32             status;
76
77         spin_lock_irqsave(&ahcd->lock, flags);
78         if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags))
79                 goto done;
80
81         /* init status */
82         status = admhc_read_rhdesc(ahcd);
83         if (status & (ADMHC_RH_LPSC | ADMHC_RH_OCIC))
84                 buf[0] = changed = 1;
85         else
86                 buf[0] = 0;
87         if (ahcd->num_ports > 7) {
88                 buf[1] = 0;
89                 length++;
90         }
91
92         /* look at each port */
93         for (i = 0; i < ahcd->num_ports; i++) {
94                 status = admhc_read_portstatus(ahcd, i);
95
96                 /* can't autostop if ports are connected */
97                 any_connected |= (status & ADMHC_PS_CCS);
98
99                 if (status & (ADMHC_PS_CSC | ADMHC_PS_PESC | ADMHC_PS_PSSC
100                                 | ADMHC_PS_OCIC | ADMHC_PS_PRSC)) {
101                         changed = 1;
102                         if (i < 7)
103                                 buf[0] |= 1 << (i + 1);
104                         else
105                                 buf[1] |= 1 << (i - 7);
106                 }
107         }
108
109         hcd->poll_rh = admhc_root_hub_state_changes(ahcd, changed,
110                         any_connected);
111
112 done:
113         spin_unlock_irqrestore(&ahcd->lock, flags);
114
115         return changed ? length : 0;
116 }
117
118 /*-------------------------------------------------------------------------*/
119
120 static int admhc_get_hub_descriptor(struct admhcd *ahcd, char *buf)
121 {
122         struct usb_hub_descriptor *desc = (struct usb_hub_descriptor *)buf;
123         u32 rh = admhc_read_rhdesc(ahcd);
124         u16 temp;
125
126         desc->bDescriptorType = USB_DT_HUB;     /* Hub-descriptor */
127         desc->bPwrOn2PwrGood = ADMHC_POTPGT/2;  /* use default value */
128         desc->bHubContrCurrent = 0x00;          /* 0mA */
129
130         desc->bNbrPorts = ahcd->num_ports;
131         temp = 1 + (ahcd->num_ports / 8);
132         desc->bDescLength = USB_DT_HUB_NONVAR_SIZE + 2 * temp;
133
134         /* FIXME */
135         temp = 0;
136         if (rh & ADMHC_RH_NPS)          /* no power switching? */
137             temp |= 0x0002;
138         if (rh & ADMHC_RH_PSM)          /* per-port power switching? */
139             temp |= 0x0001;
140         if (rh & ADMHC_RH_NOCP)         /* no overcurrent reporting? */
141             temp |= 0x0010;
142         else if (rh & ADMHC_RH_OCPM)    /* per-port overcurrent reporting? */
143             temp |= 0x0008;
144         desc->wHubCharacteristics = (__force __u16)cpu_to_hc16(ahcd, temp);
145
146         /* two bitmaps:  ports removable, and usb 1.0 legacy PortPwrCtrlMask */
147         desc->bitmap[0] = 0;
148         desc->bitmap[0] = ~0;
149
150         return 0;
151 }
152
153 static int admhc_get_hub_status(struct admhcd *ahcd, char *buf)
154 {
155         struct usb_hub_status *hs = (struct usb_hub_status *)buf;
156         u32 t = admhc_read_rhdesc(ahcd);
157         u16 status, change;
158
159         status = 0;
160         status |= (t & ADMHC_RH_LPS) ? HUB_STATUS_LOCAL_POWER : 0;
161         status |= (t & ADMHC_RH_OCI) ? HUB_STATUS_OVERCURRENT : 0;
162
163         change = 0;
164         change |= (t & ADMHC_RH_LPSC) ? HUB_CHANGE_LOCAL_POWER : 0;
165         change |= (t & ADMHC_RH_OCIC) ? HUB_CHANGE_OVERCURRENT : 0;
166
167         hs->wHubStatus = (__force __u16)cpu_to_hc16(ahcd, status);
168         hs->wHubChange = (__force __u16)cpu_to_hc16(ahcd, change);
169
170         return 0;
171 }
172
173 static int admhc_get_port_status(struct admhcd *ahcd, unsigned port, char *buf)
174 {
175         struct usb_port_status *ps = (struct usb_port_status *)buf;
176         u32 t = admhc_read_portstatus(ahcd, port);
177         u16 status, change;
178
179         status = 0;
180         status |= (t & ADMHC_PS_CCS) ? USB_PORT_STAT_CONNECTION : 0;
181         status |= (t & ADMHC_PS_PES) ? USB_PORT_STAT_ENABLE : 0;
182         status |= (t & ADMHC_PS_PSS) ? USB_PORT_STAT_SUSPEND : 0;
183         status |= (t & ADMHC_PS_POCI) ? USB_PORT_STAT_OVERCURRENT : 0;
184         status |= (t & ADMHC_PS_PRS) ? USB_PORT_STAT_RESET : 0;
185         status |= (t & ADMHC_PS_PPS) ? USB_PORT_STAT_POWER : 0;
186         status |= (t & ADMHC_PS_LSDA) ? USB_PORT_STAT_LOW_SPEED : 0;
187
188         change = 0;
189         change |= (t & ADMHC_PS_CSC) ? USB_PORT_STAT_C_CONNECTION : 0;
190         change |= (t & ADMHC_PS_PESC) ? USB_PORT_STAT_C_ENABLE : 0;
191         change |= (t & ADMHC_PS_PSSC) ? USB_PORT_STAT_C_SUSPEND : 0;
192         change |= (t & ADMHC_PS_OCIC) ? USB_PORT_STAT_C_OVERCURRENT : 0;
193         change |= (t & ADMHC_PS_PRSC) ? USB_PORT_STAT_C_RESET : 0;
194
195         ps->wPortStatus = (__force __u16)cpu_to_hc16(ahcd, status);
196         ps->wPortChange = (__force __u16)cpu_to_hc16(ahcd, change);
197
198         return 0;
199 }
200
201 /*-------------------------------------------------------------------------*/
202
203 #ifdef  CONFIG_USB_OTG
204
205 static int admhc_start_port_reset(struct usb_hcd *hcd, unsigned port)
206 {
207         struct admhcd   *ahcd = hcd_to_admhcd(hcd);
208         u32                     status;
209
210         if (!port)
211                 return -EINVAL;
212         port--;
213
214         /* start port reset before HNP protocol times out */
215         status = admhc_read_portstatus(ahcd, port);
216         if (!(status & ADMHC_PS_CCS))
217                 return -ENODEV;
218
219         /* khubd will finish the reset later */
220         admhc_write_portstatus(ahcd, port, ADMHC_PS_PRS);
221         return 0;
222 }
223
224 static void start_hnp(struct admhcd *ahcd);
225
226 #else
227
228 #define admhc_start_port_reset          NULL
229
230 #endif
231
232 /*-------------------------------------------------------------------------*/
233
234
235 /* See usb 7.1.7.5:  root hubs must issue at least 50 msec reset signaling,
236  * not necessarily continuous ... to guard against resume signaling.
237  * The short timeout is safe for non-root hubs, and is backward-compatible
238  * with earlier Linux hosts.
239  */
240 #ifdef  CONFIG_USB_SUSPEND
241 #define PORT_RESET_MSEC         50
242 #else
243 #define PORT_RESET_MSEC         10
244 #endif
245
246 /* this timer value might be vendor-specific ... */
247 #define PORT_RESET_HW_MSEC      10
248
249 /* wrap-aware logic morphed from <linux/jiffies.h> */
250 #define tick_before(t1, t2) ((s16)(((s16)(t1)) - ((s16)(t2))) < 0)
251
252 /* called from some task, normally khubd */
253 static inline int admhc_port_reset(struct admhcd *ahcd, unsigned port)
254 {
255         u32 t;
256
257         admhc_vdbg(ahcd, "reset port%d\n", port);
258         t = admhc_read_portstatus(ahcd, port);
259         if (!(t & ADMHC_PS_CCS))
260                 return -ENODEV;
261
262         admhc_write_portstatus(ahcd, port, ADMHC_PS_SPR);
263         mdelay(10);
264         admhc_write_portstatus(ahcd, port, (ADMHC_PS_SPE | ADMHC_PS_CSC));
265         mdelay(100);
266
267         return 0;
268 }
269
270 static inline int admhc_port_enable(struct admhcd *ahcd, unsigned port)
271 {
272         u32 t;
273
274         admhc_vdbg(ahcd, "enable port%d\n", port);
275         t = admhc_read_portstatus(ahcd, port);
276         if (!(t & ADMHC_PS_CCS))
277                 return -ENODEV;
278
279         admhc_write_portstatus(ahcd, port, ADMHC_PS_SPE);
280
281         return 0;
282 }
283
284 static inline int admhc_port_disable(struct admhcd *ahcd, unsigned port)
285 {
286         u32 t;
287
288         admhc_vdbg(ahcd, "disable port%d\n", port);
289         t = admhc_read_portstatus(ahcd, port);
290         if (!(t & ADMHC_PS_CCS))
291                 return -ENODEV;
292
293         admhc_write_portstatus(ahcd, port, ADMHC_PS_CPE);
294
295         return 0;
296 }
297
298 static inline int admhc_port_write(struct admhcd *ahcd, unsigned port,
299                 u32 val)
300 {
301 #ifdef ADMHC_VERBOSE_DEBUG
302         dbg_port_write(ahcd, "write", port, val);
303 #endif
304         admhc_write_portstatus(ahcd, port, val);
305
306         return 0;
307 }
308
309 static int admhc_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
310                 u16 wIndex, char *buf, u16 wLength)
311 {
312         struct admhcd   *ahcd = hcd_to_admhcd(hcd);
313         int             ports = hcd_to_bus(hcd)->root_hub->maxchild;
314         int             ret = 0;
315
316         if (unlikely(!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)))
317                 return -ESHUTDOWN;
318
319         switch (typeReq) {
320         case ClearHubFeature:
321                 switch (wValue) {
322                 case C_HUB_OVER_CURRENT:
323 #if 0                   /* FIXME */
324                         admhc_writel(ahcd, ADMHC_RH_OCIC,
325                                         &ahcd->regs->roothub.status);
326 #endif
327                 case C_HUB_LOCAL_POWER:
328                         break;
329                 default:
330                         goto error;
331                 }
332                 break;
333         case ClearPortFeature:
334                 if (!wIndex || wIndex > ports)
335                         goto error;
336                 wIndex--;
337
338                 switch (wValue) {
339                 case USB_PORT_FEAT_ENABLE:
340                         ret = admhc_port_disable(ahcd, wIndex);
341                         break;
342                 case USB_PORT_FEAT_SUSPEND:
343                         ret = admhc_port_write(ahcd, wIndex, ADMHC_PS_CPS);
344                         break;
345                 case USB_PORT_FEAT_POWER:
346                         ret = admhc_port_write(ahcd, wIndex, ADMHC_PS_CPP);
347                         break;
348                 case USB_PORT_FEAT_C_CONNECTION:
349                         ret = admhc_port_write(ahcd, wIndex, ADMHC_PS_CSC);
350                         break;
351                 case USB_PORT_FEAT_C_ENABLE:
352                         ret = admhc_port_write(ahcd, wIndex, ADMHC_PS_PESC);
353                         break;
354                 case USB_PORT_FEAT_C_SUSPEND:
355                         ret = admhc_port_write(ahcd, wIndex, ADMHC_PS_PSSC);
356                         break;
357                 case USB_PORT_FEAT_C_OVER_CURRENT:
358                         ret = admhc_port_write(ahcd, wIndex, ADMHC_PS_OCIC);
359                         break;
360                 case USB_PORT_FEAT_C_RESET:
361                         ret = admhc_port_write(ahcd, wIndex, ADMHC_PS_PRSC);
362                         break;
363                 default:
364                         goto error;
365                 }
366                 break;
367         case GetHubDescriptor:
368                 ret = admhc_get_hub_descriptor(ahcd, buf);
369                 break;
370         case GetHubStatus:
371                 ret = admhc_get_hub_status(ahcd, buf);
372                 break;
373         case GetPortStatus:
374                 if (!wIndex || wIndex > ports)
375                         goto error;
376                 wIndex--;
377
378                 ret = admhc_get_port_status(ahcd, wIndex, buf);
379                 break;
380         case SetHubFeature:
381                 switch (wValue) {
382                 case C_HUB_OVER_CURRENT:
383                         /* FIXME:  this can be cleared, yes? */
384                 case C_HUB_LOCAL_POWER:
385                         break;
386                 default:
387                         goto error;
388                 }
389                 break;
390         case SetPortFeature:
391                 if (!wIndex || wIndex > ports)
392                         goto error;
393                 wIndex--;
394
395                 switch (wValue) {
396                 case USB_PORT_FEAT_ENABLE:
397                         ret = admhc_port_enable(ahcd, wIndex);
398                         break;
399                 case USB_PORT_FEAT_RESET:
400                         ret = admhc_port_reset(ahcd, wIndex);
401                         break;
402                 case USB_PORT_FEAT_SUSPEND:
403 #ifdef  CONFIG_USB_OTG
404                         if (hcd->self.otg_port == (wIndex + 1)
405                                         && hcd->self.b_hnp_enable)
406                                 start_hnp(ahcd);
407                         else
408 #endif
409                         ret = admhc_port_write(ahcd, wIndex, ADMHC_PS_SPS);
410                         break;
411                 case USB_PORT_FEAT_POWER:
412                         ret = admhc_port_write(ahcd, wIndex, ADMHC_PS_SPP);
413                         break;
414                 default:
415                         goto error;
416                 }
417                 break;
418
419         default:
420 error:
421                 /* "protocol stall" on error */
422                 ret = -EPIPE;
423         }
424
425         return ret;
426 }
427