blob: 197b102480225cf8b361903de0e68aa3d53f8ed5 [file] [log] [blame]
Brian Swetland3e7e21a2009-01-19 19:41:24 -08001/*
2 * Copyright (c) 2008, Google Inc.
3 * All rights reserved.
4 *
Shashank Mittal23b8f422010-04-16 19:27:21 -07005 * Copyright (c) 2009-2010, Code Aurora Forum. All rights reserved.
6 *
Brian Swetland3e7e21a2009-01-19 19:41:24 -08007 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * * Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * * Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in
14 * the documentation and/or other materials provided with the
15 * distribution.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
20 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
21 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
23 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
24 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
25 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
26 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
27 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 * SUCH DAMAGE.
29 */
30
31#include <string.h>
32#include <stdlib.h>
33#include <debug.h>
34#include <platform/iomap.h>
35#include <platform/irqs.h>
36#include <platform/interrupts.h>
37#include <kernel/thread.h>
38#include <reg.h>
39
40#include <dev/udc.h>
41
42#include "hsusb.h"
43
Chandan Uddaraju7f5b9012010-02-06 16:37:48 -080044int charger_usb_disconnected(void);
45int charger_usb_i(unsigned current);
46int charger_usb_is_pc_connected(void);
47int charger_usb_is_charger_connected(void);
48
Brian Swetland3e7e21a2009-01-19 19:41:24 -080049/* common code - factor out into a shared file */
50
51struct udc_descriptor {
52 struct udc_descriptor *next;
53 unsigned short tag; /* ((TYPE << 8) | NUM) */
54 unsigned short len; /* total length */
55 unsigned char data[0];
56};
57
58struct udc_descriptor *udc_descriptor_alloc(unsigned type, unsigned num, unsigned len)
59{
60 struct udc_descriptor *desc;
61 if ((len > 255) || (len < 2) || (num > 255) || (type > 255))
62 return 0;
63
64 if(!(desc = malloc(sizeof(struct udc_descriptor) + len)))
65 return 0;
66
67 desc->next = 0;
68 desc->tag = (type << 8) | num;
69 desc->len = len;
70 desc->data[0] = len;
71 desc->data[1] = type;
72
73 return desc;
74}
75
76static struct udc_descriptor *desc_list = 0;
77static unsigned next_string_id = 1;
78
79void udc_descriptor_register(struct udc_descriptor *desc)
80{
81 desc->next = desc_list;
82 desc_list = desc;
83}
84
85unsigned udc_string_desc_alloc(const char *str)
86{
87 unsigned len;
88 struct udc_descriptor *desc;
89 unsigned char *data;
90
91 if (next_string_id > 255)
92 return 0;
93
94 if (!str)
95 return 0;
96
97 len = strlen(str);
98 desc = udc_descriptor_alloc(TYPE_STRING, next_string_id, len * 2 + 2);
99 if (!desc)
100 return 0;
101 next_string_id++;
102
103 /* expand ascii string to utf16 */
104 data = desc->data + 2;
105 while (len-- > 0) {
106 *data++ = *str++;
107 *data++ = 0;
108 }
109
110 udc_descriptor_register(desc);
111 return desc->tag & 0xff;
112}
113
114/* end of common code */
115
116void hsusb_clock_init(void);
117
118#if 1
119#define DBG(x...) do {} while(0)
120#else
121#define DBG(x...) dprintf(INFO, x)
122#endif
123
124#define DBG1(x...) dprintf(INFO, x)
125
126#define usb_status(a,b)
127
128struct usb_request {
129 struct udc_request req;
130 struct ept_queue_item *item;
131};
132
133struct udc_endpoint
134{
135 struct udc_endpoint *next;
136 unsigned bit;
137 struct ept_queue_head *head;
138 struct usb_request *req;
139 unsigned char num;
140 unsigned char in;
141 unsigned short maxpkt;
142};
143
144struct udc_endpoint *ept_list = 0;
145struct ept_queue_head *epts = 0;
146
147static int usb_online = 0;
148static int usb_highspeed = 0;
149
150static struct udc_device *the_device;
151static struct udc_gadget *the_gadget;
152
153struct udc_endpoint *_udc_endpoint_alloc(unsigned num, unsigned in, unsigned max_pkt)
154{
155 struct udc_endpoint *ept;
156 unsigned cfg;
157
158 ept = malloc(sizeof(*ept));
159
160 ept->maxpkt = max_pkt;
161 ept->num = num;
162 ept->in = !!in;
163 ept->req = 0;
164
165 cfg = CONFIG_MAX_PKT(max_pkt) | CONFIG_ZLT;
166
167 if(ept->in) {
168 ept->bit = EPT_TX(ept->num);
169 } else {
170 ept->bit = EPT_RX(ept->num);
171 if(num == 0)
172 cfg |= CONFIG_IOS;
173 }
174
175 ept->head = epts + (num * 2) + (ept->in);
176 ept->head->config = cfg;
177
178 ept->next = ept_list;
179 ept_list = ept;
180
181// arch_clean_invalidate_cache_range(ept->head, 64);
182 DBG("ept%d %s @%p/%p max=%d bit=%x\n",
183 num, in ? "in":"out", ept, ept->head, max_pkt, ept->bit);
184
185 return ept;
186}
187
188static unsigned ept_alloc_table = EPT_TX(0) | EPT_RX(0);
189
190struct udc_endpoint *udc_endpoint_alloc(unsigned type, unsigned maxpkt)
191{
192 struct udc_endpoint *ept;
193 unsigned n;
194 unsigned in;
195
196 if (type == UDC_TYPE_BULK_IN) {
197 in = 1;
198 } else if (type == UDC_TYPE_BULK_OUT) {
199 in = 0;
200 } else {
201 return 0;
202 }
203
204 for (n = 1; n < 16; n++) {
205 unsigned bit = in ? EPT_TX(n) : EPT_RX(n);
206 if (ept_alloc_table & bit)
207 continue;
208 ept = _udc_endpoint_alloc(n, in, maxpkt);
209 if (ept)
210 ept_alloc_table |= bit;
211 return ept;
212 }
213 return 0;
214}
215
216void udc_endpoint_free(struct udc_endpoint *ept)
217{
218 /* todo */
219}
220
221static void endpoint_enable(struct udc_endpoint *ept, unsigned yes)
222{
223 unsigned n = readl(USB_ENDPTCTRL(ept->num));
224
225 if(yes) {
226 if(ept->in) {
227 n |= (CTRL_TXE | CTRL_TXR | CTRL_TXT_BULK);
228 } else {
229 n |= (CTRL_RXE | CTRL_RXR | CTRL_RXT_BULK);
230 }
231
232 if(ept->num != 0) {
233 /* XXX should be more dynamic... */
234 if(usb_highspeed) {
235 ept->head->config = CONFIG_MAX_PKT(512) | CONFIG_ZLT;
236 } else {
237 ept->head->config = CONFIG_MAX_PKT(64) | CONFIG_ZLT;
238 }
239 }
240 }
241 writel(n, USB_ENDPTCTRL(ept->num));
242}
243
244struct udc_request *udc_request_alloc(void)
245{
246 struct usb_request *req;
247 req = malloc(sizeof(*req));
248 req->req.buf = 0;
249 req->req.length = 0;
250 req->item = memalign(32, 32);
251 return &req->req;
252}
253
254void udc_request_free(struct udc_request *req)
255{
256 free(req);
257}
258
259int udc_request_queue(struct udc_endpoint *ept, struct udc_request *_req)
260{
261 struct usb_request *req = (struct usb_request *) _req;
262 struct ept_queue_item *item = req->item;
263 unsigned phys = (unsigned) req->req.buf;
264
265 item->next = TERMINATE;
266 item->info = INFO_BYTES(req->req.length) | INFO_IOC | INFO_ACTIVE;
267 item->page0 = phys;
268 item->page1 = (phys & 0xfffff000) + 0x1000;
269
270 enter_critical_section();
271 ept->head->next = (unsigned) item;
272 ept->head->info = 0;
273 ept->req = req;
274
275// arch_clean_invalidate_cache_range(item, 32);
276// arch_clean_invalidate_cache_range(ept->head, 64);
277// arch_clean_invalidate_cache_range(req->req.buf, req->req.length);
278 DBG("ept%d %s queue req=%p\n",
279 ept->num, ept->in ? "in" : "out", req);
280
281 writel(ept->bit, USB_ENDPTPRIME);
282 exit_critical_section();
283 return 0;
284}
285
286static void handle_ept_complete(struct udc_endpoint *ept)
287{
288 struct ept_queue_item *item;
289 unsigned actual;
290 int status;
291 struct usb_request *req;
292
293 DBG("ept%d %s complete req=%p\n",
294 ept->num, ept->in ? "in" : "out", ept->req);
295
296 req = ept->req;
297 if(req) {
298 ept->req = 0;
299
300 item = req->item;
301
302 /* For some reason we are getting the notification for
303 * transfer completion before the active bit has cleared.
304 * HACK: wait for the ACTIVE bit to clear:
305 */
306 while (readl(&(item->info)) & INFO_ACTIVE) ;
307
308// arch_clean_invalidate_cache_range(item, 32);
309// arch_clean_invalidate_cache_range(req->req.buf, req->req.length);
310
311 if(item->info & 0xff) {
312 actual = 0;
313 status = -1;
314 dprintf(INFO, "EP%d/%s FAIL nfo=%x pg0=%x\n",
315 ept->num, ept->in ? "in" : "out", item->info, item->page0);
316 } else {
317 actual = req->req.length - ((item->info >> 16) & 0x7fff);
318 status = 0;
319 }
320 if(req->req.complete)
321 req->req.complete(&req->req, actual, status);
322 }
323}
324
325static const char *reqname(unsigned r)
326{
327 switch(r) {
328 case GET_STATUS: return "GET_STATUS";
329 case CLEAR_FEATURE: return "CLEAR_FEATURE";
330 case SET_FEATURE: return "SET_FEATURE";
331 case SET_ADDRESS: return "SET_ADDRESS";
332 case GET_DESCRIPTOR: return "GET_DESCRIPTOR";
333 case SET_DESCRIPTOR: return "SET_DESCRIPTOR";
334 case GET_CONFIGURATION: return "GET_CONFIGURATION";
335 case SET_CONFIGURATION: return "SET_CONFIGURATION";
336 case GET_INTERFACE: return "GET_INTERFACE";
337 case SET_INTERFACE: return "SET_INTERFACE";
338 default: return "*UNKNOWN*";
339 }
340}
341
342static struct udc_endpoint *ep0in, *ep0out;
343static struct udc_request *ep0req;
344
345static void setup_ack(void)
346{
347 ep0req->complete = 0;
348 ep0req->length = 0;
349 udc_request_queue(ep0in, ep0req);
350}
351
352static void ep0in_complete(struct udc_request *req, unsigned actual, int status)
353{
354 DBG("ep0in_complete %p %d %d\n", req, actual, status);
355 if(status == 0) {
356 req->length = 0;
357 req->complete = 0;
358 udc_request_queue(ep0out, req);
359 }
360}
361
362static void setup_tx(void *buf, unsigned len)
363{
364 DBG("setup_tx %p %d\n", buf, len);
365 memcpy(ep0req->buf, buf, len);
366 ep0req->complete = ep0in_complete;
367 ep0req->length = len;
368 udc_request_queue(ep0in, ep0req);
369}
370
371static unsigned char usb_config_value = 0;
372
373#define SETUP(type,request) (((type) << 8) | (request))
374
375static void handle_setup(struct udc_endpoint *ept)
376{
377 struct setup_packet s;
378
379 memcpy(&s, ept->head->setup_data, sizeof(s));
380 writel(ept->bit, USB_ENDPTSETUPSTAT);
381
382#if 0
383 DBG("handle_setup type=0x%02x req=0x%02x val=%d idx=%d len=%d (%s)\n",
384 s.type, s.request, s.value, s.index, s.length,
385 reqname(s.request));
386#endif
387 switch (SETUP(s.type,s.request)) {
388 case SETUP(DEVICE_READ, GET_STATUS): {
389 unsigned zero = 0;
390 if (s.length == 2) {
391 setup_tx(&zero, 2);
392 return;
393 }
394 break;
395 }
396 case SETUP(DEVICE_READ, GET_DESCRIPTOR): {
397 struct udc_descriptor *desc;
398 /* usb_highspeed? */
399 for (desc = desc_list; desc; desc = desc->next) {
400 if (desc->tag == s.value) {
401 unsigned len = desc->len;
402 if (len > s.length) len = s.length;
403 setup_tx(desc->data, len);
404 return;
405 }
406 }
407 break;
408 }
409 case SETUP(DEVICE_READ, GET_CONFIGURATION):
410 /* disabling this causes data transaction failures on OSX. Why? */
411 if ((s.value == 0) && (s.index == 0) && (s.length == 1)) {
412 setup_tx(&usb_config_value, 1);
413 return;
414 }
415 break;
416 case SETUP(DEVICE_WRITE, SET_CONFIGURATION):
417 if (s.value == 1) {
418 struct udc_endpoint *ept;
419 /* enable endpoints */
420 for (ept = ept_list; ept; ept = ept->next){
421 if (ept->num == 0)
422 continue;
423 endpoint_enable(ept, s.value);
424 }
425 usb_config_value = 1;
Chandan Uddaraju7f5b9012010-02-06 16:37:48 -0800426#ifdef ENABLE_BATTERY_CHARGING
427 if(HOST_CHARGER == TRUE) {
428 charger_usb_i(500);
429 }
430#endif
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800431 the_gadget->notify(the_gadget, UDC_EVENT_ONLINE);
432 } else {
433 writel(0, USB_ENDPTCTRL(1));
434 usb_config_value = 0;
435 the_gadget->notify(the_gadget, UDC_EVENT_OFFLINE);
436 }
437 setup_ack();
438 usb_online = s.value ? 1 : 0;
439 usb_status(s.value ? 1 : 0, usb_highspeed);
440 return;
441 case SETUP(DEVICE_WRITE, SET_ADDRESS):
442 /* write address delayed (will take effect
443 ** after the next IN txn)
444 */
445 writel((s.value << 25) | (1 << 24), USB_DEVICEADDR);
446 setup_ack();
447 return;
448 case SETUP(INTERFACE_WRITE, SET_INTERFACE):
449 /* if we ack this everything hangs */
450 /* per spec, STALL is valid if there is not alt func */
451 goto stall;
452 case SETUP(ENDPOINT_WRITE, CLEAR_FEATURE): {
453 struct udc_endpoint *ept;
454 unsigned num = s.index & 15;
455 unsigned in = !!(s.index & 0x80);
456
457 if ((s.value == 0) && (s.length == 0)) {
458 DBG("clr feat %d %d\n", num, in);
459 for (ept = ept_list; ept; ept = ept->next) {
460 if ((ept->num == num) && (ept->in == in)) {
461 endpoint_enable(ept, 1);
462 setup_ack();
463 return;
464 }
465 }
466 }
467 break;
468 }
469 }
470
471 dprintf(INFO, "STALL %s %d %d %d %d %d\n",
472 reqname(s.request),
473 s.type, s.request, s.value, s.index, s.length);
474
475stall:
476 writel((1<<16) | (1 << 0), USB_ENDPTCTRL(ept->num));
477}
478
479unsigned ulpi_read(unsigned reg)
480{
481 /* initiate read operation */
482 writel(ULPI_RUN | ULPI_READ | ULPI_ADDR(reg),
483 USB_ULPI_VIEWPORT);
484
485 /* wait for completion */
486 while(readl(USB_ULPI_VIEWPORT) & ULPI_RUN) ;
487
488 return ULPI_DATA_READ(readl(USB_ULPI_VIEWPORT));
489}
490
491void ulpi_write(unsigned val, unsigned reg)
492{
493 /* initiate write operation */
494 writel(ULPI_RUN | ULPI_WRITE |
495 ULPI_ADDR(reg) | ULPI_DATA(val),
496 USB_ULPI_VIEWPORT);
497
498 /* wait for completion */
499 while(readl(USB_ULPI_VIEWPORT) & ULPI_RUN) ;
500}
Ajay Dudani5a1e3302009-12-05 13:19:17 -0800501
Shashank Mittal23b8f422010-04-16 19:27:21 -0700502#define USB_CLK 0x00902910
503#define USB_PHY_CLK 0x00902E20
504#define CLK_RESET_ASSERT 0x1
505#define CLK_RESET_DEASSERT 0x0
506#define CLK_RESET(x,y) writel((y), (x));
507
508static int msm_otg_xceiv_reset()
509{
510 CLK_RESET(USB_CLK, CLK_RESET_ASSERT);
511 CLK_RESET(USB_PHY_CLK, CLK_RESET_ASSERT);
512 mdelay(20);
513 CLK_RESET(USB_PHY_CLK, CLK_RESET_DEASSERT);
514 CLK_RESET(USB_CLK, CLK_RESET_DEASSERT);
515 mdelay(20);
516
517 /* select ULPI phy */
518 writel(0x81000000, USB_PORTSC);
519 return 0;
520}
521#define USB_HS1_XVCR_FS_CLK_MD 0x00902908
522#define USB_HS1_XVCR_FS_CLK_NS 0x0090290C
523void hsusb_8x60_clock_init(void)
524{
525 unsigned int val = 0;
526
527 //Enable PLL8
528 writel(0xF, 0x00903144);
529 writel(0x5, 0x00903148);
530 writel(0x8, 0x0090314C);
531
532 val = readl(0x00903154);
533 val &= ~(0xC30000);
534 val |= 0xC10000;
535 writel(val, 0x00903154);
536
537 val = readl(0x00903140);
538 val &= ~(0x7);
539 val |= 0x7;
540 writel(val, 0x00903140);
541
542
543 //Set 7th bit in NS Register
544 val = 1 << 7;
545 writel(val, USB_HS1_XVCR_FS_CLK_NS);
546
547 //Set rate specific value in MD
548 writel(0x000500DF, USB_HS1_XVCR_FS_CLK_MD);
549
550 //Set value in NS register
551 val = 1 << 7;
552 val |= 0x00E400C3;
553 writel(val, USB_HS1_XVCR_FS_CLK_NS);
554
555 // Clear 7th bit
556 val = 1 << 7;
557 val = ~val;
558 val = val & readl(USB_HS1_XVCR_FS_CLK_NS);
559 writel(val, USB_HS1_XVCR_FS_CLK_NS);
560
561 //set 11th bit
562 val = 1 << 11;
563 val |= readl(USB_HS1_XVCR_FS_CLK_NS);
564 writel(val, USB_HS1_XVCR_FS_CLK_NS);
565
566 //set 9th bit
567 val = 1 << 9;
568 val |= readl(USB_HS1_XVCR_FS_CLK_NS);
569 writel(val, USB_HS1_XVCR_FS_CLK_NS);
570
571 //set 8th bit
572 val = 1 << 8;
573 val |= readl(USB_HS1_XVCR_FS_CLK_NS);
574 writel(val, USB_HS1_XVCR_FS_CLK_NS);
575}
Ajay Dudani5a1e3302009-12-05 13:19:17 -0800576
577void hsusb_clock_init(void)
Ajay Dudani232ce812009-12-02 00:14:11 -0800578{
Ajay Dudani5a1e3302009-12-05 13:19:17 -0800579 // Enable usb clocks from apps processor for 7x30.
580 // USB clocks already initialized for other targets
581 // so skipping proc comm call to enable usb clocks.
582#ifdef PLATFORM_MSM7X30
Ajay Dudani232ce812009-12-02 00:14:11 -0800583 writel(0x00000100, USBH_NS_REG);
584 writel(0x00000900, USBH_NS_REG);
585 writel(0x00000A00, USBH_NS_REG);
586 writel(0x00002A00, USBH_NS_REG);
Shashank Mittal23b8f422010-04-16 19:27:21 -0700587#elif PLATFORM_MSM8X60
588 hsusb_8x60_clock_init();
Ajay Dudani232ce812009-12-02 00:14:11 -0800589#endif
Ajay Dudani5a1e3302009-12-05 13:19:17 -0800590}
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800591
592void board_usb_init(void);
593void board_ulpi_init(void);
594
595int udc_init(struct udc_device *dev)
596{
597 hsusb_clock_init();
598
599 epts = memalign(4096, 4096);
600
601 dprintf(INFO, "USB init ept @ %p\n", epts);
602 memset(epts, 0, 32 * sizeof(struct ept_queue_head));
603
Ajay Dudani232ce812009-12-02 00:14:11 -0800604 //dprintf(INFO, "USB ID %08x\n", readl(USB_ID));
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800605// board_usb_init();
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800606
607 /* select ULPI phy */
Shashank Mittal23b8f422010-04-16 19:27:21 -0700608#ifdef PLATFORM_MSM8X60
609 msm_otg_xceiv_reset();
610#else
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800611 writel(0x81000000, USB_PORTSC);
Shashank Mittal23b8f422010-04-16 19:27:21 -0700612#endif
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800613 /* RESET */
614 writel(0x00080002, USB_USBCMD);
615
616 thread_sleep(20);
617
618// board_ulpi_init();
619
620// arch_clean_invalidate_cache_range(epts, 32 * sizeof(struct ept_queue_head));
621 writel((unsigned) epts, USB_ENDPOINTLISTADDR);
622
623 /* select DEVICE mode */
624 writel(0x02, USB_USBMODE);
625
626 writel(0xffffffff, USB_ENDPTFLUSH);
627 thread_sleep(20);
628
629 ep0out = _udc_endpoint_alloc(0, 0, 64);
630 ep0in = _udc_endpoint_alloc(0, 1, 64);
631 ep0req = udc_request_alloc();
632 ep0req->buf = malloc(4096);
633
634 {
635 /* create and register a language table descriptor */
636 /* language 0x0409 is US English */
637 struct udc_descriptor *desc = udc_descriptor_alloc(TYPE_STRING, 0, 4);
638 desc->data[2] = 0x09;
639 desc->data[3] = 0x04;
640 udc_descriptor_register(desc);
641 }
642
643 the_device = dev;
644 return 0;
645}
646
647enum handler_return udc_interrupt(void *arg)
648{
649 struct udc_endpoint *ept;
650 unsigned ret = INT_NO_RESCHEDULE;
651 unsigned n = readl(USB_USBSTS);
652 writel(n, USB_USBSTS);
653
654 n &= (STS_SLI | STS_URI | STS_PCI | STS_UI | STS_UEI);
655
656 if (n == 0)
657 return ret;
658
659 if (n & STS_URI) {
660 writel(readl(USB_ENDPTCOMPLETE), USB_ENDPTCOMPLETE);
661 writel(readl(USB_ENDPTSETUPSTAT), USB_ENDPTSETUPSTAT);
662 writel(0xffffffff, USB_ENDPTFLUSH);
663 writel(0, USB_ENDPTCTRL(1));
664 DBG1("-- reset --\n");
665 usb_online = 0;
666 usb_config_value = 0;
667 the_gadget->notify(the_gadget, UDC_EVENT_OFFLINE);
668
669 /* error out any pending reqs */
670 for (ept = ept_list; ept; ept = ept->next) {
671 /* ensure that ept_complete considers
672 * this to be an error state
673 */
674 if (ept->req) {
675 ept->req->item->info = INFO_HALTED;
676 handle_ept_complete(ept);
677 }
678 }
679 usb_status(0, usb_highspeed);
680 }
681 if (n & STS_SLI) {
682 DBG1("-- suspend --\n");
Chandan Uddaraju7f5b9012010-02-06 16:37:48 -0800683#ifdef ENABLE_BATTERY_CHARGING
684 if(HOST_CHARGER == TRUE){
685 charger_usb_i(2);
686 }
687#endif
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800688 }
689 if (n & STS_PCI) {
690 DBG1("-- portchange --\n");
691 unsigned spd = (readl(USB_PORTSC) >> 26) & 3;
692 if(spd == 2) {
693 usb_highspeed = 1;
694 } else {
695 usb_highspeed = 0;
696 }
Chandan Uddaraju7f5b9012010-02-06 16:37:48 -0800697#ifdef ENABLE_BATTERY_CHARGING
698 if(HOST_CHARGER == TRUE && usb_config_value){
699 charger_usb_i(500);
700 }
701 if(HOST_CHARGER == TRUE && !usb_config_value){
702 charger_usb_i(100);
703 }
704#endif
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800705 }
706 if (n & STS_UEI) {
707 dprintf(INFO, "<UEI %x>\n", readl(USB_ENDPTCOMPLETE));
708 }
709#if 0
710 DBG("STS: ");
711 if (n & STS_UEI) DBG("ERROR ");
712 if (n & STS_SLI) DBG("SUSPEND ");
713 if (n & STS_URI) DBG("RESET ");
714 if (n & STS_PCI) DBG("PORTCHANGE ");
715 if (n & STS_UI) DBG("USB ");
716 DBG("\n");
717#endif
718 if ((n & STS_UI) || (n & STS_UEI)) {
719 n = readl(USB_ENDPTSETUPSTAT);
720 if (n & EPT_RX(0)) {
721 handle_setup(ep0out);
722 ret = INT_RESCHEDULE;
723 }
724
725 n = readl(USB_ENDPTCOMPLETE);
726 if (n != 0) {
727 writel(n, USB_ENDPTCOMPLETE);
728 }
729
730 for (ept = ept_list; ept; ept = ept->next){
731 if (n & ept->bit) {
732 handle_ept_complete(ept);
733 ret = INT_RESCHEDULE;
734 }
735 }
736 }
737 return ret;
738}
739
740int udc_register_gadget(struct udc_gadget *gadget)
741{
742 if (the_gadget) {
743 dprintf(CRITICAL, "only one gadget supported\n");
744 return -1;
745 }
746 the_gadget = gadget;
747 return 0;
748}
749
750static void udc_ept_desc_fill(struct udc_endpoint *ept, unsigned char *data)
751{
752 data[0] = 7;
753 data[1] = TYPE_ENDPOINT;
754 data[2] = ept->num | (ept->in ? 0x80 : 0x00);
755 data[3] = 0x02; /* bulk -- the only kind we support */
756 data[4] = ept->maxpkt;
757 data[5] = ept->maxpkt >> 8;
758 data[6] = ept->in ? 0x00 : 0x01;
759}
760
761static unsigned udc_ifc_desc_size(struct udc_gadget *g)
762{
763 return 9 + g->ifc_endpoints * 7;
764}
765
766static void udc_ifc_desc_fill(struct udc_gadget *g, unsigned char *data)
767{
768 unsigned n;
769
770 data[0] = 0x09;
771 data[1] = TYPE_INTERFACE;
772 data[2] = 0x00; /* ifc number */
773 data[3] = 0x00; /* alt number */
774 data[4] = g->ifc_endpoints;
775 data[5] = g->ifc_class;
776 data[6] = g->ifc_subclass;
777 data[7] = g->ifc_protocol;
778 data[8] = udc_string_desc_alloc(g->ifc_string);
779
780 data += 9;
781 for (n = 0; n < g->ifc_endpoints; n++) {
782 udc_ept_desc_fill(g->ept[n], data);
783 data += 7;
784 }
785}
786
787int udc_start(void)
788{
789 struct udc_descriptor *desc;
790 unsigned char *data;
791 unsigned size;
792
Chandan Uddaraju40b227d2010-08-03 19:25:41 -0700793 dprintf(ALWAYS, "udc_start()\n");
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800794
795 if (!the_device) {
796 dprintf(CRITICAL, "udc cannot start before init\n");
797 return -1;
798 }
799 if (!the_gadget) {
800 dprintf(CRITICAL, "udc has no gadget registered\n");
801 return -1;
802 }
803
804 /* create our device descriptor */
805 desc = udc_descriptor_alloc(TYPE_DEVICE, 0, 18);
806 data = desc->data;
807 data[2] = 0x10; /* usb spec rev 2.10 */
808 data[3] = 0x02;
809 data[4] = 0x00; /* class */
810 data[5] = 0x00; /* subclass */
811 data[6] = 0x00; /* protocol */
812 data[7] = 0x40; /* max packet size on ept 0 */
813 memcpy(data + 8, &the_device->vendor_id, sizeof(short));
814 memcpy(data + 10, &the_device->product_id, sizeof(short));
815 memcpy(data + 12, &the_device->version_id, sizeof(short));
816 data[14] = udc_string_desc_alloc(the_device->manufacturer);
817 data[15] = udc_string_desc_alloc(the_device->product);
818 data[16] = udc_string_desc_alloc(the_device->serialno);
819 data[17] = 1; /* number of configurations */
820 udc_descriptor_register(desc);
821
822 /* create our configuration descriptor */
823 size = 9 + udc_ifc_desc_size(the_gadget);
824 desc = udc_descriptor_alloc(TYPE_CONFIGURATION, 0, size);
825 data = desc->data;
826 data[0] = 0x09;
827 data[2] = size;
828 data[3] = size >> 8;
829 data[4] = 0x01; /* number of interfaces */
830 data[5] = 0x01; /* configuration value */
831 data[6] = 0x00; /* configuration string */
832 data[7] = 0x80; /* attributes */
833 data[8] = 0x80; /* max power (250ma) -- todo fix this */
834 udc_ifc_desc_fill(the_gadget, data + 9);
835 udc_descriptor_register(desc);
836
837 /* go to RUN mode (D+ pullup enable) */
838 writel(0x00080001, USB_USBCMD);
839 register_int_handler(INT_USB_HS, udc_interrupt, (void*) 0);
840 unmask_interrupt(INT_USB_HS);
841 writel(STS_URI | STS_SLI | STS_UI | STS_PCI, USB_USBINTR);
842 return 0;
843}
844
845int udc_stop(void)
846{
847 writel(0, USB_USBINTR);
848 mask_interrupt(INT_USB_HS);
849
850 /* disable pullup */
Shashank Mittald8c42bf2010-06-09 15:44:28 -0700851 writel(0x00080000, USB_USBCMD);
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800852 thread_sleep(10);
853
854 return 0;
855}
856
Chandan Uddaraju7f5b9012010-02-06 16:37:48 -0800857void usb_stop_charging(unsigned stop_charging)
858{
859 ENABLE_CHARGING = !stop_charging;
860}
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800861
Chandan Uddaraju7f5b9012010-02-06 16:37:48 -0800862static inline unsigned is_usb_charging(void)
863{
864 return ENABLE_CHARGING;
865}
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800866
Chandan Uddaraju7f5b9012010-02-06 16:37:48 -0800867void usb_charger_reset(void)
868{
869 usb_stop_charging(TRUE);
870 charger_usb_disconnected();
871}
872
873/* Charger detection code
874 * Set global flags WALL_CHARGER and
875 * RETURN: type of charger connected
876 * CHG_WALL
877 * CHG_HOST_PC
878 * */
879int usb_chg_detect_type(void)
880{
881 int ret = CHG_UNDEFINED;
882
883 if ((readl(USB_PORTSC) & PORTSC_LS) == PORTSC_LS)
884 {
885 if(charger_usb_is_charger_connected() == TRUE) {
886 WALL_CHARGER = TRUE;
887 HOST_CHARGER = FALSE;
888 charger_usb_i(1500);
889 ret = CHG_WALL;
890 }
891 }
892 else
893 {
894 if(charger_usb_is_pc_connected() == TRUE) {
895 WALL_CHARGER = FALSE;
896 HOST_CHARGER = TRUE;
897 ret = CHG_HOST_PC;
898 }
899 }
900 return ret;
901}
902
903/* check if USB cable is connected
904 *
905 * RETURN: If cable connected return 1
906 * If cable disconnected return 0
907 */
908int is_usb_cable_connected(void)
909{
910 /*Verify B Session Valid Bit to verify vbus status*/
911 if (B_SESSION_VALID & readl(USB_OTGSC)) {
912 return 1;
913 } else {
914 return 0;
915 }
916}
917
Shashank Mittald8c42bf2010-06-09 15:44:28 -0700918/* check for USB connection assuming USB is not pulled up.
919 * It looks for suspend state bit in PORTSC register.
920 *
921 * RETURN: If cable connected return 1
922 * If cable disconnected return 0
923 */
924
925int usb_cable_status(void)
926{
927 unsigned ret = 0;
928 /*Verify B Session Valid Bit to verify vbus status*/
929 writel(0x00080001, USB_USBCMD);
930 thread_sleep(100);
931
932 /*Check reset value of suspend state bit*/
933 if (!((1<<7) & readl(USB_PORTSC))) {
934 ret=1;
935 }
936 udc_stop();
937 return ret;
938}
939
Chandan Uddaraju7f5b9012010-02-06 16:37:48 -0800940void usb_charger_change_state(void)
941{
942 int usb_connected;
943
944 //User might have switched from host pc to wall charger. So keep checking
945 //every time we are in the loop
946
947 if(ENABLE_CHARGING == TRUE)
948 {
949 usb_connected = is_usb_cable_connected();
950
951 if(usb_connected && !charger_connected)
952 {
953 //mdelay(20);
954 thread_sleep(20);
955 /* go to RUN mode (D+ pullup enable) */
956 writel(0x00080001, USB_USBCMD);
957 //mdelay(10);
958 thread_sleep(10);
959 usb_chg_detect_type();
960 charger_connected = TRUE;
961 }
962 else if(!usb_connected && charger_connected)
963 {
964 /* disable D+ pull-up */
965 writel(0x00080000, USB_USBCMD);
966
967 /* Applicable only for 8k target */
968 /*USB Spoof Disconnect Failure
969 Symptoms:
970 In USB peripheral mode, writing '0' to Run/Stop bit of the
971 USBCMD register doesn't cause USB disconnection (spoof disconnect).
972 The PC host doesn't detect the disconnection and the phone remains
973 active on Windows device manager.
974
975 Suggested Workaround:
976 After writing '0' to Run/Stop bit of USBCMD, also write 0x48 to ULPI
977 "Function Control" register. This can be done via the ULPI VIEWPORT
978 register (offset 0x170) by writing a value of 0x60040048.
979 */
980 ulpi_write(0x48, 0x04);
981 //usb_charger_reset();
982 WALL_CHARGER = FALSE;
983 HOST_CHARGER = FALSE;
984 charger_usb_i(0);
985 charger_usb_disconnected();
986 charger_connected = FALSE;
987 }
988 if(WALL_CHARGER == TRUE || HOST_CHARGER == TRUE){
989 //battery_charging_image();
990 }
991 }
992 else if ((readl(USB_USBCMD) & 0x01) == 0){
993 writel(0x00080001, USB_USBCMD);
994 }
995}