blob: be37b8b710ed0f748a28314f75304f14ebf04a2d [file] [log] [blame]
Barry Wardelld4945dc2006-10-05 10:58:51 +00001/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2002 by Linus Nielsen Feltzing
11 *
12 * iPod driver based on code from the ipodlinux project - http://ipodlinux.org
13 * Adapted for Rockbox in January 2006
14 * Original file: podzilla/usb.c
15 * Copyright (C) 2005 Adam Johnston
16 *
17 * All files in this archive are subject to the GNU General Public License.
18 * See the file COPYING in the source tree root for full license agreement.
19 *
20 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
21 * KIND, either express or implied.
22 *
23 ****************************************************************************/
24#include "config.h"
Barry Wardelld4945dc2006-10-05 10:58:51 +000025#include "system.h"
Barry Wardelld4945dc2006-10-05 10:58:51 +000026#include "usb.h"
Christian Gmeinerf286bde2007-08-27 16:26:56 +000027#include "button.h"
28#include "ata.h"
Christian Gmeiner863ce442007-08-27 16:30:23 +000029#include "string.h"
Dave Chapmana6d52a82007-08-27 21:59:57 +000030#include "arcotg_udc.h"
Dave Chapman4da04b72007-02-04 21:46:01 +000031
Christian Gmeiner8181a0c2007-08-27 16:04:32 +000032#ifdef HAVE_USBSTACK
33#include "usbstack.h"
34#endif
35
Barry Wardelld4945dc2006-10-05 10:58:51 +000036void usb_init_device(void)
37{
Christian Gmeiner1a8f7c52007-09-05 15:52:49 +000038 int r0;
Dave Chapman9551ae92007-08-27 18:21:05 +000039 outl(inl(0x70000084) | 0x200, 0x70000084);
Christian Gmeiner1a8f7c52007-09-05 15:52:49 +000040
Dave Chapman9551ae92007-08-27 18:21:05 +000041 outl(inl(0x7000002C) | 0x3000000, 0x7000002C);
Christian Gmeiner1a8f7c52007-09-05 15:52:49 +000042 DEV_EN |= DEV_USB;
43
Dave Chapman9551ae92007-08-27 18:21:05 +000044 DEV_RS |= DEV_USB; /* reset usb start */
45 DEV_RS &=~DEV_USB;/* reset usb end */
Christian Gmeiner1a8f7c52007-09-05 15:52:49 +000046
47 DEV_INIT |= INIT_USB;
48 while ((inl(0x70000028) & 0x80) == 0);
49
Dave Chapman9551ae92007-08-27 18:21:05 +000050 UDC_PORTSC1 |= PORTSCX_PORT_RESET;
Christian Gmeiner1a8f7c52007-09-05 15:52:49 +000051 while ((UDC_PORTSC1 & PORTSCX_PORT_RESET) != 0);
52
53 UDC_OTGSC |= 0x5F000000;
Dave Chapman9551ae92007-08-27 18:21:05 +000054 if( (UDC_OTGSC & 0x100) == 0) {
Christian Gmeiner1a8f7c52007-09-05 15:52:49 +000055 UDC_USBMODE &=~ USB_MODE_CTRL_MODE_HOST;
56 UDC_USBMODE |= USB_MODE_CTRL_MODE_DEVICE;
57 outl(inl(0x70000028) | 0x4000, 0x70000028);
58 outl(inl(0x70000028) | 0x2, 0x70000028);
59 } else {
60 UDC_USBMODE |= USB_MODE_CTRL_MODE_DEVICE;
61 outl(inl(0x70000028) &~0x4000, 0x70000028);
62 outl(inl(0x70000028) | 0x2, 0x70000028);
63 }
64
65
66 UDC_USBCMD |= USB_CMD_CTRL_RESET;
67 while((UDC_USBCMD & USB_CMD_CTRL_RESET) != 0);
68
69 r0 = UDC_PORTSC1;
70
Dave Chapman9551ae92007-08-27 18:21:05 +000071 /* Note from IPL source (referring to next 5 lines of code:
72 THIS NEEDS TO BE CHANGED ONCE THERE IS KERNEL USB */
Christian Gmeiner1a8f7c52007-09-05 15:52:49 +000073 DEV_INIT |= INIT_USB;
74 DEV_EN |= DEV_USB;
75 while ((inl(0x70000028) & 0x80) == 0);
76 outl(inl(0x70000028) | 0x2, 0x70000028);
Dave Chapman9551ae92007-08-27 18:21:05 +000077
Christian Gmeiner1a8f7c52007-09-05 15:52:49 +000078 udelay(0x186A0);
79
80#ifndef HAVE_USBSTACK
Dave Chapman9551ae92007-08-27 18:21:05 +000081 dr_controller_setup();
82#endif
Jens Arnoldcb896cd2007-08-01 22:44:02 +000083
84#if defined(IPOD_COLOR) || defined(IPOD_4G) \
85 || defined(IPOD_MINI) || defined(IPOD_MINI2G)
86 /* GPIO C bit 1 is firewire detect */
87 GPIOC_ENABLE |= 0x02;
88 GPIOC_OUTPUT_EN &= ~0x02;
89#endif
Barry Wardelld4945dc2006-10-05 10:58:51 +000090}
91
92void usb_enable(bool on)
93{
Peter D'Hoyef2bf0422007-08-28 21:32:28 +000094#ifdef HAVE_USBSTACK
Christian Gmeiner2c30bd92007-09-05 16:16:49 +000095 if (!on) {
96 usb_stack_stop();
97 }
Christian Gmeiner1a8f7c52007-09-05 15:52:49 +000098#else
Barry Wardell4b543022006-12-20 15:28:32 +000099 /* This device specific code will eventually give way to proper USB
Jens Arnoldcb896cd2007-08-01 22:44:02 +0000100 handling, which should be the same for all PP502x targets. */
Barry Wardelld4945dc2006-10-05 10:58:51 +0000101 if (on)
102 {
Daniel Stenberg20a59262007-02-17 21:54:17 +0000103#if defined(IPOD_ARCH) || defined(IRIVER_H10) || defined (IRIVER_H10_5GB)
Barry Wardell4b543022006-12-20 15:28:32 +0000104 /* For the H10 and iPod, we can only do one thing with USB mode - reboot
105 into the flash-based disk-mode. This does not return. */
Barry Wardell4b543022006-12-20 15:28:32 +0000106
107#if defined(IRIVER_H10) || defined (IRIVER_H10_5GB)
108 if(button_status()==BUTTON_RIGHT)
Peter D'Hoyef2bf0422007-08-28 21:32:28 +0000109#endif /* defined(IRIVER_H10) || defined (IRIVER_H10_5GB) */
Barry Wardell4b543022006-12-20 15:28:32 +0000110 {
111 ata_sleepnow(); /* Immediately spindown the disk. */
112 sleep(HZ*2);
Jens Arnoldcb896cd2007-08-01 22:44:02 +0000113
114#ifdef IPOD_ARCH /* The following code is based on ipodlinux */
115#if CONFIG_CPU == PP5020
116 memcpy((void *)0x40017f00, "diskmode\0\0hotstuff\0\0\1", 21);
117#elif CONFIG_CPU == PP5022
118 memcpy((void *)0x4001ff00, "diskmode\0\0hotstuff\0\0\1", 21);
Peter D'Hoyef2bf0422007-08-28 21:32:28 +0000119#endif /* CONFIG_CPU */
120#endif /* IPOD_ARCH */
Jens Arnoldcb896cd2007-08-01 22:44:02 +0000121
Barry Wardell4b543022006-12-20 15:28:32 +0000122 system_reboot(); /* Reboot */
123 }
Peter D'Hoyef2bf0422007-08-28 21:32:28 +0000124#endif /*defined(IPOD_ARCH) || defined(IRIVER_H10) || defined (IRIVER_H10_5GB)*/
Barry Wardelld4945dc2006-10-05 10:58:51 +0000125 }
Peter D'Hoyef2bf0422007-08-28 21:32:28 +0000126#endif /* !HAVE_USBSTACK */
Barry Wardelld4945dc2006-10-05 10:58:51 +0000127}
128
Dave Chapman16723502007-09-04 08:03:07 +0000129int usb_detect(void)
Barry Wardelld4945dc2006-10-05 10:58:51 +0000130{
Dave Chapman16723502007-09-04 08:03:07 +0000131 static int countdown = 0;
132 static int status = USB_EXTRACTED;
Dave Chapman4da04b72007-02-04 21:46:01 +0000133 static bool prev_usbstatus1 = false;
Dave Chapman16723502007-09-04 08:03:07 +0000134 bool usbstatus1, usbstatus2;
Barry Wardelld4945dc2006-10-05 10:58:51 +0000135
Jens Arnoldcb896cd2007-08-01 22:44:02 +0000136#if defined(IPOD_COLOR) || defined(IPOD_4G) \
137 || defined(IPOD_MINI) || defined(IPOD_MINI2G)
138 /* GPIO C bit 1 is firewire detect */
139 if (!(GPIOC_INPUT_VAL & 0x02))
Dave Chapman16723502007-09-04 08:03:07 +0000140 return USB_INSERTED;
Jens Arnoldcb896cd2007-08-01 22:44:02 +0000141#endif
142
Dave Chapman16723502007-09-04 08:03:07 +0000143 if (countdown > 0)
144 {
145 countdown--;
146
147 usbstatus2 = (UDC_PORTSC1 & PORTSCX_CURRENT_CONNECT_STATUS) ? true : false;
148 if ((countdown == 0) || usbstatus2)
149 {
150 countdown = 0;
151 status = usbstatus2 ? USB_INSERTED : USB_POWERED;
Christian Gmeinere267bc72007-09-04 23:29:42 +0000152#ifndef HAVE_USBSTACK
Dave Chapman16723502007-09-04 08:03:07 +0000153 dr_controller_stop();
Dave Chapman16723502007-09-04 08:03:07 +0000154#endif
155 }
156 return status;
157 }
158
Barry Wardell3a6d4792007-02-16 22:13:21 +0000159 /* UDC_ID should have the bit format:
Barry Wardell4b543022006-12-20 15:28:32 +0000160 [31:24] = 0x0
161 [23:16] = 0x22 (Revision number)
162 [15:14] = 0x3 (Reserved)
163 [13:8] = 0x3a (NID - 1's compliment of ID)
164 [7:6] = 0x0 (Reserved)
165 [5:0] = 0x05 (ID) */
Barry Wardell3a6d4792007-02-16 22:13:21 +0000166 if (UDC_ID != 0x22FA05) {
Dave Chapman16723502007-09-04 08:03:07 +0000167 /* This should never occur - do we even need to test? */
168 return USB_EXTRACTED;
Barry Wardelld4945dc2006-10-05 10:58:51 +0000169 }
Dave Chapman4da04b72007-02-04 21:46:01 +0000170
Barry Wardell3a6d4792007-02-16 22:13:21 +0000171 usbstatus1 = (UDC_OTGSC & 0x800) ? true : false;
Dave Chapman4da04b72007-02-04 21:46:01 +0000172
Dave Chapman16723502007-09-04 08:03:07 +0000173 if (usbstatus1 == prev_usbstatus1)
174 {
175 /* Nothing has changed, so just return previous status */
176 return status;
Dave Chapman4da04b72007-02-04 21:46:01 +0000177 }
Dave Chapman16723502007-09-04 08:03:07 +0000178 prev_usbstatus1 = usbstatus1;
179
180 if (!usbstatus1)
181 { /* We have just been disconnected */
182 status = USB_EXTRACTED;
Dave Chapman16723502007-09-04 08:03:07 +0000183 return status;
184 }
185
186 /* We now know that we have just been connected to either a charger
187 or a computer */
188
189 if((button_status() & ~USBPOWER_BTN_IGNORE) == USBPOWER_BUTTON)
190 {
191 /* The user wants to charge, so it doesn't matter what we are
192 connected to. */
193
194 status = USB_POWERED;
195 return status;
196 }
197
198 /* Run the USB controller for long enough to detect if we're connected
199 to a computer, then stop it again. */
200
Christian Gmeiner1a8f7c52007-09-05 15:52:49 +0000201#ifndef HAVE_USBSTACK
Dave Chapman16723502007-09-04 08:03:07 +0000202 dr_controller_run();
Christian Gmeiner1a8f7c52007-09-05 15:52:49 +0000203#else
204 usb_stack_start();
Christian Gmeinere267bc72007-09-04 23:29:42 +0000205#endif
Dave Chapman16723502007-09-04 08:03:07 +0000206
207 /* Wait for 50 ticks (500ms) before deciding there is no computer
208 attached. The required value varied a lot between different users
209 when this feature was being tested. */
210
211 countdown = 50;
212
213 return status;
Barry Wardelld4945dc2006-10-05 10:58:51 +0000214}