Add preliminary RouterBoard RB1xx support
[openwrt.git] / target / linux / rb1xx-2.6 / files / drivers / usb / host / adm5120-hcd.c
1 /*
2  *      HCD driver for ADM5120 SoC
3  *
4  *      Copyright (C) 2005 Jeroen Vreeken (pe1rxq@amsat.org)
5  *
6  *      Based on the ADMtek 2.4 driver 
7  *      (C) Copyright 2003 Junius Chen <juniusc@admtek.com.tw>
8  *      Which again was based on the ohci and uhci drivers.
9  */
10
11 #include <linux/autoconf.h>
12 #include <linux/moduleparam.h>
13 #include <linux/kernel.h>
14 #include <linux/errno.h>
15 #include <linux/interrupt.h>
16 #include <linux/usb.h>
17 #include <linux/platform_device.h>
18
19 #include "../core/hcd.h"
20
21 MODULE_DESCRIPTION("ADM5120 USB Host Controller Driver");
22 MODULE_LICENSE("GPL");
23 MODULE_AUTHOR("Jeroen Vreeken (pe1rxq@amsat.org)");
24
25 #define ADMHCD_REG_CONTROL              0x00
26 #define ADMHCD_REG_INTSTATUS            0x04
27 #define ADMHCD_REG_INTENABLE            0x08
28 #define ADMHCD_REG_HOSTCONTROL          0x10
29 #define ADMHCD_REG_FMINTERVAL           0x18
30 #define ADMHCD_REG_FMNUMBER             0x1c
31 #define ADMHCD_REG_LSTHRESH             0x70
32 #define ADMHCD_REG_RHDESCR              0x74
33 #define ADMHCD_REG_PORTSTATUS0          0x78
34 #define ADMHCD_REG_PORTSTATUS1          0x7c
35 #define ADMHCD_REG_HOSTHEAD             0x80
36
37
38 #define ADMHCD_NUMPORTS         2
39
40 #define ADMHCD_HOST_EN          0x00000001      /* Host enable */
41 #define ADMHCD_SW_INTREQ        0x00000002      /* request software int */
42 #define ADMHCD_SW_RESET         0x00000008      /* Reset */
43
44 #define ADMHCD_INT_TD           0x00100000      /* TD completed */
45 #define ADMHCD_INT_SW           0x20000000      /* software interrupt */
46 #define ADMHCD_INT_FATAL        0x40000000      /* Fatal interrupt */
47 #define ADMHCD_INT_ACT          0x80000000      /* Interrupt active */
48
49 #define ADMHCD_STATE_RST        0x00000000      /* bus state reset */
50 #define ADMHCD_STATE_RES        0x00000001      /* bus state resume */
51 #define ADMHCD_STATE_OP         0x00000002      /* bus state operational */
52 #define ADMHCD_STATE_SUS        0x00000003      /* bus state suspended */
53 #define ADMHCD_DMA_EN           0x00000004      /* enable dma engine */
54
55 #define ADMHCD_NPS              0x00000020      /* No Power Switch */
56 #define ADMHCD_LPSC             0x04000000      /* Local power switch change */
57
58 #define ADMHCD_CCS              0x00000001      /* current connect status */
59 #define ADMHCD_PES              0x00000002      /* port enable status */
60 #define ADMHCD_PSS              0x00000004      /* port suspend status */
61 #define ADMHCD_POCI             0x00000008      /* port overcurrent indicator */
62 #define ADMHCD_PRS              0x00000010      /* port reset status */
63 #define ADMHCD_PPS              0x00000100      /* port power status */
64 #define ADMHCD_LSDA             0x00000200      /* low speed device attached */
65 #define ADMHCD_CSC              0x00010000      /* connect status change */
66 #define ADMHCD_PESC             0x00020000      /* enable status change */
67 #define ADMHCD_PSSC             0x00040000      /* suspend status change */
68 #define ADMHCD_OCIC             0x00080000      /* overcurrent change*/
69 #define ADMHCD_PRSC             0x00100000      /* reset status change */
70
71
72 struct admhcd_ed {
73         /* Don't change first four, they used for DMA */
74         u32                             control;
75         struct admhcd_td                *tail;
76         struct admhcd_td                *head;
77         struct admhcd_ed                *next;
78         /* the rest is for the driver only: */
79         struct admhcd_td                *cur;
80         struct usb_host_endpoint        *ep;
81         struct urb                      *urb;
82         struct admhcd_ed                *real;
83 } __attribute__ ((packed));
84
85 #define ADMHCD_ED_EPSHIFT       7               /* Shift for endpoint number */
86 #define ADMHCD_ED_INT           0x00000800      /* Is this an int endpoint */
87 #define ADMHCD_ED_SPEED         0x00002000      /* Is it a high speed dev? */
88 #define ADMHCD_ED_SKIP          0x00004000      /* Skip this ED */
89 #define ADMHCD_ED_FORMAT        0x00008000      /* Is this an isoc endpoint */
90 #define ADMHCD_ED_MAXSHIFT      16              /* Shift for max packet size */
91
92 struct admhcd_td {
93         /* Don't change first four, they are used for DMA */
94         u32                     control;
95         u32                     buffer;
96         u32                     buflen;
97         struct admhcd_td        *next;
98         /* the rest is for the driver only: */
99         struct urb              *urb;
100         struct admhcd_td        *real;
101 } __attribute__ ((packed));
102
103 #define ADMHCD_TD_OWN           0x80000000
104 #define ADMHCD_TD_TOGGLE        0x00000000
105 #define ADMHCD_TD_DATA0         0x01000000
106 #define ADMHCD_TD_DATA1         0x01800000
107 #define ADMHCD_TD_OUT           0x00200000
108 #define ADMHCD_TD_IN            0x00400000
109 #define ADMHCD_TD_SETUP         0x00000000
110 #define ADMHCD_TD_ISO           0x00010000
111 #define ADMHCD_TD_R             0x00040000
112 #define ADMHCD_TD_INTEN         0x00010000
113
114 static int admhcd_td_err[16] = {
115         0,              /* No */
116         -EREMOTEIO,             /* CRC */
117         -EREMOTEIO,     /* bit stuff */
118         -EREMOTEIO,             /* data toggle */
119         -EPIPE,         /* stall */
120         -ETIMEDOUT,     /* timeout */
121         -EPROTO,        /* pid err */
122         -EPROTO,        /* unexpected pid */
123         -EREMOTEIO,     /* data overrun */
124         -EREMOTEIO,     /* data underrun */
125         -ETIMEDOUT,     /* 1010 */
126         -ETIMEDOUT,     /* 1011 */
127         -EREMOTEIO,     /* buffer overrun */
128         -EREMOTEIO,     /* buffer underrun */
129         -ETIMEDOUT,     /* 1110 */
130         -ETIMEDOUT,     /* 1111 */
131 };
132
133 #define ADMHCD_TD_ERRMASK       0x38000000
134 #define ADMHCD_TD_ERRSHIFT      27
135
136 #define TD(td)  ((struct admhcd_td *)(((u32)(td)) & ~0xf))
137 #define ED(ed)  ((struct admhcd_ed *)(((u32)(ed)) & ~0xf))
138
139 struct admhcd {
140         u32             base;
141         u32             dma_en;
142         spinlock_t      lock;
143         unsigned long   flags;
144 };
145
146 #define hcd_to_admhcd(hcd) ((struct admhcd *)(hcd)->hcd_priv)
147
148 static char hcd_name[] = "adm5120-hcd";
149
150 static u32 admhcd_reg_get(struct admhcd *ahcd, int reg)
151 {
152         return *(volatile u32 *)KSEG1ADDR(ahcd->base+reg);
153 }
154
155 static void admhcd_reg_set(struct admhcd *ahcd, int reg, u32 val)
156 {
157         *(volatile u32 *)KSEG1ADDR(ahcd->base+reg) = val;
158 }
159
160 static void admhcd_lock(struct admhcd *ahcd)
161 {
162         spin_lock_irqsave(&ahcd->lock, ahcd->flags);
163         ahcd->dma_en = admhcd_reg_get(ahcd, ADMHCD_REG_HOSTCONTROL) &
164             ADMHCD_DMA_EN;
165         admhcd_reg_set(ahcd, ADMHCD_REG_HOSTCONTROL, ADMHCD_STATE_OP);
166 }
167
168 static void admhcd_unlock(struct admhcd *ahcd)
169 {
170         admhcd_reg_set(ahcd, ADMHCD_REG_HOSTCONTROL,
171             ADMHCD_STATE_OP | ahcd->dma_en);
172         spin_unlock_irqrestore(&ahcd->lock, ahcd->flags);
173 }
174
175 static struct admhcd_td *admhcd_td_alloc(struct admhcd_ed *ed, struct urb *urb)
176 {
177         struct admhcd_td *tdn, *td;
178
179         tdn = kmalloc(sizeof(struct admhcd_td), GFP_ATOMIC);
180         if (!tdn)
181                 return NULL;
182         tdn->real = tdn;
183         tdn = (struct admhcd_td *)KSEG1ADDR(tdn);
184         memset(tdn, 0, sizeof(struct admhcd_td));
185         if (ed->cur == NULL) {
186                 ed->cur = tdn;
187                 ed->head = tdn;
188                 ed->tail = tdn; 
189                 td = tdn;
190         } else {
191                 /* Supply back the old tail and link in new td as tail */
192                 td = TD(ed->tail);
193                 TD(ed->tail)->next = tdn;
194                 ed->tail = tdn;
195         }
196         td->urb = urb;
197
198         return td;
199 }
200
201 static void admhcd_td_free(struct admhcd_ed *ed, struct urb *urb)
202 {
203         struct admhcd_td *td, **tdp;
204
205         if (urb == NULL)
206                 ed->control |= ADMHCD_ED_SKIP;
207         tdp = &ed->cur;
208         td = ed->cur;
209         do {
210                 if (td->urb == urb)
211                         break;
212                 tdp = &td->next;
213                 td = TD(td->next);
214         } while (td);
215         while (td && td->urb == urb) {
216                 *tdp = TD(td->next);
217                 kfree(td->real);
218                 td = *tdp;
219         }
220 }
221
222 /* Find an endpoint's descriptor, if needed allocate a new one and link it
223    in the DMA chain
224  */
225 static struct admhcd_ed *admhcd_get_ed(struct admhcd *ahcd,
226     struct usb_host_endpoint *ep, struct urb *urb)
227 {
228         struct admhcd_ed *hosthead;
229         struct admhcd_ed *found = NULL, *ed = NULL;
230         unsigned int pipe = urb->pipe;
231
232         admhcd_lock(ahcd);
233         hosthead = (struct admhcd_ed *)admhcd_reg_get(ahcd, ADMHCD_REG_HOSTHEAD);
234         if (hosthead) {
235                 for (ed = hosthead;; ed = ED(ed->next)) {
236                         if (ed->ep == ep) {
237                                 found = ed;
238                                 break;
239                         }
240                         if (ED(ed->next) == hosthead)
241                                 break;
242                 }
243         }
244         if (!found) {
245                 found = kmalloc(sizeof(struct admhcd_ed), GFP_ATOMIC);
246                 if (!found)
247                         goto out;
248                 memset(found, 0, sizeof(struct admhcd_ed));
249                 found->real = found;
250                 found->ep = ep;
251                 found = (struct admhcd_ed *)KSEG1ADDR(found);
252                 found->control = usb_pipedevice(pipe) |
253                     (usb_pipeendpoint(pipe) << ADMHCD_ED_EPSHIFT) |
254                     (usb_pipeint(pipe) ? ADMHCD_ED_INT : 0) |
255                     (urb->dev->speed == USB_SPEED_FULL ? ADMHCD_ED_SPEED : 0) |
256                     (usb_pipeisoc(pipe) ? ADMHCD_ED_FORMAT : 0) |
257                     (usb_maxpacket(urb->dev, pipe, usb_pipeout(pipe)) << ADMHCD_ED_MAXSHIFT);
258                 /* Alloc first dummy td */
259                 admhcd_td_alloc(found, NULL);
260                 if (hosthead) {
261                         found->next = hosthead;
262                         ed->next = found;
263                 } else {
264                         found->next = found;
265                         admhcd_reg_set(ahcd, ADMHCD_REG_HOSTHEAD, (u32)found);
266                 }
267         }
268 out:
269         admhcd_unlock(ahcd);
270         return found;
271 }
272
273 static struct admhcd_td *admhcd_td_fill(u32 control, struct admhcd_td *td,
274     dma_addr_t data, int len)
275 {
276         td->buffer = data;
277         td->buflen = len;
278         td->control = control;
279         return TD(td->next);
280 }
281
282 static void admhcd_ed_start(struct admhcd *ahcd, struct admhcd_ed *ed)
283 {
284         struct admhcd_td *td = ed->cur;
285
286         if (ed->urb)
287                 return;
288         if (td->urb) {
289                 ed->urb = td->urb;
290                 while (1) {
291                         td->control |= ADMHCD_TD_OWN;
292                         if (TD(td->next)->urb != td->urb) {
293                                 td->buflen |= ADMHCD_TD_INTEN;
294                                 break;
295                         }
296                         td = TD(td->next);
297                 }
298         }
299         ed->head = TD(ed->head);
300         ahcd->dma_en |= ADMHCD_DMA_EN;
301 }
302
303 static irqreturn_t adm5120hcd_irq(int irq, void *ptr, struct pt_regs *regs)
304 {
305         struct usb_hcd *hcd = (struct usb_hcd *)ptr;
306         struct admhcd *ahcd = hcd_to_admhcd(hcd);
307         u32 intstatus;
308
309         intstatus = admhcd_reg_get(ahcd, ADMHCD_REG_INTSTATUS);
310         if (intstatus & ADMHCD_INT_FATAL) {
311                 admhcd_reg_set(ahcd, ADMHCD_REG_INTSTATUS, ADMHCD_INT_FATAL);
312                 //
313         }
314         if (intstatus & ADMHCD_INT_SW) {
315                 admhcd_reg_set(ahcd, ADMHCD_REG_INTSTATUS, ADMHCD_INT_SW);
316                 //
317         }
318         if (intstatus & ADMHCD_INT_TD) {
319                 struct admhcd_ed *ed, *head;
320                 
321                 admhcd_reg_set(ahcd, ADMHCD_REG_INTSTATUS, ADMHCD_INT_TD);
322
323                 head = (struct admhcd_ed *)admhcd_reg_get(ahcd, ADMHCD_REG_HOSTHEAD);
324                 ed = head;
325                 if (ed) do {
326                         /* Is it a finished TD? */
327                         if (ed->urb && !(ed->cur->control & ADMHCD_TD_OWN)) {
328                                 struct admhcd_td *td;
329                                 int error;
330                                 
331                                 td = ed->cur;
332                                 error = (td->control & ADMHCD_TD_ERRMASK) >>
333                                     ADMHCD_TD_ERRSHIFT;
334                                 ed->urb->status = admhcd_td_err[error];
335                                 admhcd_td_free(ed, ed->urb);
336                                 // Calculate real length!!!
337                                 ed->urb->actual_length = ed->urb->transfer_buffer_length;
338                                 ed->urb->hcpriv = NULL;
339                                 usb_hcd_giveback_urb(hcd, ed->urb);
340                                 ed->urb = NULL;
341                         }
342                         admhcd_ed_start(ahcd, ed);
343                         ed = ED(ed->next);
344                 } while (ed != head);
345         }
346
347         return IRQ_HANDLED;
348 }
349
350 static int admhcd_urb_enqueue(struct usb_hcd *hcd, struct usb_host_endpoint *ep,
351     struct urb *urb, int mem_flags)
352 {
353         struct admhcd *ahcd = hcd_to_admhcd(hcd);
354         struct admhcd_ed *ed;
355         struct admhcd_td *td;
356         int size = 0, i, zero = 0, ret = 0;
357         unsigned int pipe = urb->pipe, toggle = 0;
358         dma_addr_t data = (dma_addr_t)urb->transfer_buffer;
359         int data_len = urb->transfer_buffer_length;
360
361         ed = admhcd_get_ed(ahcd, ep, urb);
362         if (!ed)
363                 return -ENOMEM;
364
365         switch(usb_pipetype(pipe)) {
366                 case PIPE_CONTROL:
367                         size = 2;
368                 case PIPE_INTERRUPT:
369                 case PIPE_BULK:
370                 default:
371                         size += urb->transfer_buffer_length / 4096;
372                         if (urb->transfer_buffer_length % 4096)
373                                 size++;
374                         if (size == 0)
375                                 size++;
376                         else if (urb->transfer_flags & URB_ZERO_PACKET &&
377                             !(urb->transfer_buffer_length %
378                               usb_maxpacket(urb->dev, pipe, usb_pipeout(pipe)))) {
379                                 size++;
380                                 zero = 1;
381                         }
382                         break;
383                 case PIPE_ISOCHRONOUS:
384                         size = urb->number_of_packets;
385                         break;
386         }
387
388         admhcd_lock(ahcd);
389         /* Remember the first td */
390         td = admhcd_td_alloc(ed, urb);
391         if (!td) {
392                 ret = -ENOMEM;
393                 goto out;
394         }
395         /* Allocate additionall tds first */
396         for (i = 1; i < size; i++) {
397                 if (admhcd_td_alloc(ed, urb) == NULL) {
398                         admhcd_td_free(ed, urb);
399                         ret = -ENOMEM;
400                         goto out;
401                 }
402         }
403
404         if (usb_gettoggle(urb->dev, usb_pipeendpoint(pipe), usb_pipeout(pipe)))
405                 toggle = ADMHCD_TD_TOGGLE;
406         else {
407                 toggle = ADMHCD_TD_DATA0;
408                 usb_settoggle(urb->dev, usb_pipeendpoint(pipe),
409                     usb_pipeout(pipe), 1);
410         }
411
412         switch(usb_pipetype(pipe)) {
413                 case PIPE_CONTROL:
414                         td = admhcd_td_fill(ADMHCD_TD_SETUP | ADMHCD_TD_DATA0,
415                             td, (dma_addr_t)urb->setup_packet, 8);
416                         while (data_len > 0) {
417                                 td = admhcd_td_fill(ADMHCD_TD_DATA1 
418                                     | ADMHCD_TD_R |
419                                     (usb_pipeout(pipe) ?
420                                     ADMHCD_TD_OUT : ADMHCD_TD_IN), td,
421                                     data, data_len % 4097);
422                                 data_len -= 4096;
423                         }
424                         admhcd_td_fill(ADMHCD_TD_DATA1 | (usb_pipeout(pipe) ?
425                             ADMHCD_TD_IN : ADMHCD_TD_OUT), td,
426                             data, 0);
427                         break;
428                 case PIPE_INTERRUPT:
429                 case PIPE_BULK:
430                         //info ok for interrupt?
431                         i = 0;
432                         while(data_len > 4096) {
433                                 td = admhcd_td_fill((usb_pipeout(pipe) ?
434                                     ADMHCD_TD_OUT : 
435                                     ADMHCD_TD_IN | ADMHCD_TD_R) |
436                                     (i ? ADMHCD_TD_TOGGLE : toggle), td,
437                                     data, 4096);
438                                 data += 4096;
439                                 data_len -= 4096;
440                                 i++;
441                         }
442                         td = admhcd_td_fill((usb_pipeout(pipe) ? 
443                             ADMHCD_TD_OUT : ADMHCD_TD_IN) |
444                             (i ? ADMHCD_TD_TOGGLE : toggle), td, data, data_len);
445                         i++;
446                         if (zero)
447                                 admhcd_td_fill((usb_pipeout(pipe) ?
448                                     ADMHCD_TD_OUT : ADMHCD_TD_IN) |
449                                     (i ? ADMHCD_TD_TOGGLE : toggle), td, 0, 0);
450                         break;
451                 case PIPE_ISOCHRONOUS:
452                         for (i = 0; i < urb->number_of_packets; i++) {
453                                 td = admhcd_td_fill(ADMHCD_TD_ISO |
454                                     ((urb->start_frame + i) & 0xffff), td,
455                                     data + urb->iso_frame_desc[i].offset,
456                                     urb->iso_frame_desc[i].length);
457                         }
458                         break;
459         }
460         urb->hcpriv = ed;
461         admhcd_ed_start(ahcd, ed);
462 out:
463         admhcd_unlock(ahcd);
464         return ret;
465 }
466
467 static int admhcd_urb_dequeue(struct usb_hcd *hcd, struct urb *urb)
468 {
469         struct admhcd *ahcd = hcd_to_admhcd(hcd);
470         struct admhcd_ed *ed;
471
472         admhcd_lock(ahcd);
473
474         ed = urb->hcpriv;
475         if (ed && ed->urb != urb)
476                 admhcd_td_free(ed, urb);
477
478         admhcd_unlock(ahcd);
479         return 0;
480 }
481
482 static void admhcd_endpoint_disable(struct usb_hcd *hcd, struct usb_host_endpoint *ep)
483 {
484         struct admhcd *ahcd = hcd_to_admhcd(hcd);
485         struct admhcd_ed *ed, *edt, *head;
486
487         admhcd_lock(ahcd);
488
489         head = (struct admhcd_ed *)admhcd_reg_get(ahcd, ADMHCD_REG_HOSTHEAD);
490         if (!head)
491                 goto out;
492         for (ed = head; ED(ed->next) != head; ed = ED(ed->next))
493                 if (ed->ep == ep)
494                         break;
495         if (ed->ep != ep)
496                 goto out;
497         while (ed->cur)
498                 admhcd_td_free(ed, ed->cur->urb);
499         if (head == ed) {
500                 if (ED(ed->next) == ed) {
501                         admhcd_reg_set(ahcd, ADMHCD_REG_HOSTHEAD, 0);
502                         ahcd->dma_en = 0;
503                         goto out_free;
504                 }
505                 head = ED(ed->next);
506                 for (edt = head; ED(edt->next) != head; edt = ED(edt->next));
507                 edt->next = ED(ed->next);
508                 admhcd_reg_set(ahcd, ADMHCD_REG_HOSTHEAD, (u32)ed->next);
509                 goto out_free;
510         }
511         for (edt = head; edt->next != ed; edt = edt->next);
512         edt->next = ed->next;
513 out_free:
514         kfree(ed->real);
515 out:
516         admhcd_unlock(ahcd);
517 }
518
519 static int admhcd_get_frame_number(struct usb_hcd *hcd)
520 {
521         struct admhcd *ahcd = hcd_to_admhcd(hcd);
522
523         return admhcd_reg_get(ahcd, ADMHCD_REG_FMNUMBER) & 0x0000ffff;
524 }
525
526 static int admhcd_hub_status_data(struct usb_hcd *hcd, char *buf)
527 {
528         struct admhcd *ahcd = hcd_to_admhcd(hcd);
529         int port;
530
531         *buf = 0;
532         for (port = 0; port < ADMHCD_NUMPORTS; port++) {
533                 if (admhcd_reg_get(ahcd, ADMHCD_REG_PORTSTATUS0 + port*4) &
534                     (ADMHCD_CSC | ADMHCD_PESC | ADMHCD_PSSC | ADMHCD_OCIC |
535                      ADMHCD_PRSC))
536                         *buf |= (1 << (port + 1));
537         }
538         return !!*buf;
539 }
540
541 static __u8 root_hub_hub_des[] = {
542         0x09,           /* __u8  bLength; */
543         0x29,           /* __u8  bDescriptorType; Hub-descriptor */
544         0x02,           /* __u8  bNbrPorts; */
545         0x0a, 0x00,     /* __u16 wHubCharacteristics; */
546         0x01,           /* __u8  bPwrOn2pwrGood; 2ms */
547         0x00,           /* __u8  bHubContrCurrent; 0mA */
548         0x00,           /* __u8  DeviceRemovable; */
549         0xff,           /* __u8  PortPwrCtrlMask; */
550 };
551
552 static int admhcd_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
553     u16 wIndex, char *buf, u16 wLength)
554 {
555         struct admhcd *ahcd = hcd_to_admhcd(hcd);
556         int retval = 0, len;
557         unsigned int port = wIndex -1;
558
559         switch (typeReq) {
560
561         case GetHubStatus:
562                 *(__le32 *)buf = cpu_to_le32(0);
563                 break;
564         case GetPortStatus:
565                 if (port >= ADMHCD_NUMPORTS)
566                         goto err;
567                 *(__le32 *)buf = cpu_to_le32(
568                     admhcd_reg_get(ahcd, ADMHCD_REG_PORTSTATUS0 + port*4));
569                 break;
570         case SetHubFeature:             /* We don't implement these */
571         case ClearHubFeature:
572                 switch (wValue) {
573                 case C_HUB_OVER_CURRENT:
574                 case C_HUB_LOCAL_POWER:
575                         break;
576                 default:
577                         goto err;
578                 }
579         case SetPortFeature:
580                 if (port >= ADMHCD_NUMPORTS)
581                         goto err;
582
583                 switch (wValue) {
584                 case USB_PORT_FEAT_SUSPEND:
585                         admhcd_reg_set(ahcd, ADMHCD_REG_PORTSTATUS0 + port*4,
586                             ADMHCD_PSS);
587                         break;
588                 case USB_PORT_FEAT_RESET:
589                         if (admhcd_reg_get(ahcd, ADMHCD_REG_PORTSTATUS0 + port*4)
590                             & ADMHCD_CCS) {
591                                 admhcd_reg_set(ahcd, 
592                                     ADMHCD_REG_PORTSTATUS0 + port*4,
593                                     ADMHCD_PRS | ADMHCD_CSC);
594                                 mdelay(50);
595                                 admhcd_reg_set(ahcd,
596                                     ADMHCD_REG_PORTSTATUS0 + port*4,
597                                     ADMHCD_PES | ADMHCD_CSC);
598                         }
599                         break;
600                 case USB_PORT_FEAT_POWER:
601                         admhcd_reg_set(ahcd, ADMHCD_REG_PORTSTATUS0 + port*4,
602                             ADMHCD_PPS);
603                         break;
604                 default:
605                         goto err;
606                 }
607                 break;
608         case ClearPortFeature:
609                 if (port >= ADMHCD_NUMPORTS)
610                         goto err;
611
612                 switch (wValue) {
613                 case USB_PORT_FEAT_ENABLE:
614                         admhcd_reg_set(ahcd, ADMHCD_REG_PORTSTATUS0 + port*4,
615                             ADMHCD_CCS);
616                         break;
617                 case USB_PORT_FEAT_C_ENABLE:
618                         admhcd_reg_set(ahcd, ADMHCD_REG_PORTSTATUS0 + port*4,
619                             ADMHCD_PESC);
620                         break;
621                 case USB_PORT_FEAT_SUSPEND:
622                         admhcd_reg_set(ahcd, ADMHCD_REG_PORTSTATUS0 + port*4,
623                             ADMHCD_POCI);
624                         break;
625                 case USB_PORT_FEAT_C_SUSPEND:
626                         admhcd_reg_set(ahcd, ADMHCD_REG_PORTSTATUS0 + port*4,
627                             ADMHCD_PSSC);
628                 case USB_PORT_FEAT_POWER:
629                         admhcd_reg_set(ahcd, ADMHCD_REG_PORTSTATUS0 + port*4,
630                             ADMHCD_LSDA);
631                         break;
632                 case USB_PORT_FEAT_C_CONNECTION:
633                         admhcd_reg_set(ahcd, ADMHCD_REG_PORTSTATUS0 + port*4,
634                             ADMHCD_CSC);
635                         break;
636                 case USB_PORT_FEAT_C_OVER_CURRENT:
637                         admhcd_reg_set(ahcd, ADMHCD_REG_PORTSTATUS0 + port*4,
638                             ADMHCD_OCIC);
639                         break;
640                 case USB_PORT_FEAT_C_RESET:
641                         admhcd_reg_set(ahcd, ADMHCD_REG_PORTSTATUS0 + port*4,
642                             ADMHCD_PRSC);
643                         break;
644                 default:
645                         goto err;
646                 }
647                 break;
648         case GetHubDescriptor:
649                 len = min_t(unsigned int, sizeof(root_hub_hub_des), wLength);
650                 memcpy(buf, root_hub_hub_des, len);
651                 break;
652         default:
653 err:
654                 retval = -EPIPE;
655         }
656
657         return retval;
658 }
659
660 static struct hc_driver adm5120_hc_driver = {
661         .description =          hcd_name,
662         .product_desc =         "ADM5120 HCD",
663         .hcd_priv_size =        sizeof(struct admhcd),
664         .flags =                HCD_USB11,
665         .urb_enqueue =          admhcd_urb_enqueue,
666         .urb_dequeue =          admhcd_urb_dequeue,
667         .endpoint_disable =     admhcd_endpoint_disable,
668         .get_frame_number =     admhcd_get_frame_number,
669         .hub_status_data =      admhcd_hub_status_data,
670         .hub_control =          admhcd_hub_control,
671 };
672
673 static int __init adm5120hcd_probe(struct platform_device *pdev)
674 {
675         struct usb_hcd *hcd;
676         struct admhcd *ahcd;
677         struct usb_device *udev;
678         int err = 0;
679
680         if (!request_mem_region(pdev->resource[0].start,
681             pdev->resource[0].end - pdev->resource[0].start, hcd_name)) {
682                 pr_debug("couldn't request mem\n");
683                 err = -EBUSY;
684                 goto out;
685         }
686
687         //hcd = usb_create_hcd(&adm5120_hc_driver, pdev, pdev->bus_id);
688         if (!hcd)
689                 goto out_mem;
690
691         ahcd = hcd_to_admhcd(hcd);
692         dev_set_drvdata(pdev, ahcd);
693         hcd->self.controller = pdev;
694         //hcd->self.bus_name = pdev->bus_id;
695         hcd->irq = pdev->resource[1].start;
696         hcd->regs = (void *)pdev->resource[0].start;
697         hcd->product_desc = hcd_name;
698         ahcd->base = pdev->resource[0].start;
699
700         if (request_irq(pdev->resource[1].start, adm5120hcd_irq, 0, hcd_name,
701             hcd)) {
702                 pr_debug("couldn't request irq\n");
703                 err = -EBUSY;
704                 goto out_hcd;
705         }
706
707         //err = usb_register_bus(&hcd->self);
708         //if (err < 0)
709         //      goto out_irq;
710
711         spin_lock_init(&ahcd->lock);
712
713         admhcd_reg_set(ahcd, ADMHCD_REG_INTENABLE, 0);
714         mdelay(10);
715         admhcd_reg_set(ahcd, ADMHCD_REG_CONTROL, ADMHCD_SW_RESET);
716         while (admhcd_reg_get(ahcd, ADMHCD_REG_CONTROL) & ADMHCD_SW_RESET)
717                 mdelay(1);
718
719         admhcd_reg_set(ahcd, ADMHCD_REG_CONTROL, ADMHCD_HOST_EN);
720         admhcd_reg_set(ahcd, ADMHCD_REG_HOSTHEAD, 0x00000000);
721         admhcd_reg_set(ahcd, ADMHCD_REG_FMINTERVAL, 0x20002edf);
722         admhcd_reg_set(ahcd, ADMHCD_REG_LSTHRESH, 0x628);
723         admhcd_reg_set(ahcd, ADMHCD_REG_INTENABLE,
724             ADMHCD_INT_ACT | ADMHCD_INT_FATAL | ADMHCD_INT_SW | ADMHCD_INT_TD);
725         admhcd_reg_set(ahcd, ADMHCD_REG_INTSTATUS,
726             ADMHCD_INT_ACT | ADMHCD_INT_FATAL | ADMHCD_INT_SW | ADMHCD_INT_TD);
727         admhcd_reg_set(ahcd, ADMHCD_REG_RHDESCR, ADMHCD_NPS | ADMHCD_LPSC);
728         admhcd_reg_set(ahcd, ADMHCD_REG_HOSTCONTROL, ADMHCD_STATE_OP);
729
730         udev = usb_alloc_dev(NULL, &hcd->self, 0);
731         if (!udev) {
732                 err = -ENOMEM;
733                 goto out_bus;
734         }
735
736         udev->speed = USB_SPEED_FULL;
737         hcd->state = HC_STATE_RUNNING;
738
739         //err = hcd_register_root(udev, hcd);
740         //if (err != 0) {
741         //      usb_put_dev(udev);
742         //      goto out_dev;
743         //}
744
745         return 0;
746
747 out_dev:
748         usb_put_dev(udev);
749 out_bus:
750         //usb_deregister_bus(&hcd->self);
751 out_irq:
752         free_irq(pdev->resource[1].start, hcd);
753 out_hcd:
754         usb_put_hcd(hcd);
755 out_mem:
756         release_mem_region(pdev->resource[0].start,
757             pdev->resource[0].end - pdev->resource[0].start);
758 out:
759         return err;
760 }
761
762 static int __init_or_module adm5120hcd_remove(struct platform_device *pdev)
763 {
764         device_init_wakeup(&pdev->dev, 0);
765 }
766
767 static struct platform_driver adm5120hcd_driver = {
768         .probe =        adm5120hcd_probe,
769         .remove =       adm5120hcd_remove,
770         .driver =       {
771                 .name   = "adm5120-hcd",
772                 .owner  = THIS_MODULE,
773         },
774 };
775
776 static int __init adm5120hcd_init(void)
777 {
778         if (usb_disabled())
779                 return -ENODEV;
780
781         return platform_driver_register(&adm5120hcd_driver);
782 }
783
784 static void __exit adm5120hcd_exit(void)
785 {
786         platform_driver_unregister(&adm5120hcd_driver);
787 }
788
789 module_init(adm5120hcd_init);
790 module_exit(adm5120hcd_exit);