diff options
author | Cástor Muñoz <cmvidal@gmail.com> | 2014-12-06 23:13:44 +0100 |
---|---|---|
committer | Cástor Muñoz <cmvidal@gmail.com> | 2015-10-07 06:15:03 +0200 |
commit | efd047a08bf990b9d10be5e5df1bce83968bd4e4 (patch) | |
tree | 8f2ac064275f315741d78e5908a7c10c43937b02 | |
parent | 38ae0d53e834e6538e3820c3fd1977c971a81c15 (diff) | |
download | rockbox-efd047a08bf990b9d10be5e5df1bce83968bd4e4.tar.gz rockbox-efd047a08bf990b9d10be5e5df1bce83968bd4e4.zip |
iPod Classic: implement IPOD_ACCESSORY_PROTOCOL
Change-Id: I0f0950c42ae5bf5c5b4c2c2f097f8c68a92ba4dd
-rw-r--r-- | firmware/export/config/ipod6g.h | 8 | ||||
-rw-r--r-- | firmware/target/arm/s5l8702/ipod6g/powermgmt-ipod6g.c | 4 | ||||
-rw-r--r-- | firmware/target/arm/s5l8702/ipod6g/serial-ipod6g.c | 108 |
3 files changed, 116 insertions, 4 deletions
diff --git a/firmware/export/config/ipod6g.h b/firmware/export/config/ipod6g.h index a885a11144..7e7025e157 100644 --- a/firmware/export/config/ipod6g.h +++ b/firmware/export/config/ipod6g.h | |||
@@ -247,10 +247,14 @@ | |||
247 | #define USB_NUM_ENDPOINTS 6 | 247 | #define USB_NUM_ENDPOINTS 6 |
248 | #define USB_DEVBSS_ATTR __attribute__((aligned(16))) | 248 | #define USB_DEVBSS_ATTR __attribute__((aligned(16))) |
249 | 249 | ||
250 | #define HAVE_SERIAL | ||
251 | /* Disable iAP when LOGF_SERIAL is enabled to avoid conflicts */ | ||
252 | #ifndef LOGF_SERIAL | ||
253 | #define IPOD_ACCESSORY_PROTOCOL | ||
254 | #endif | ||
255 | |||
250 | /* Define this if you can switch on/off the accessory power supply */ | 256 | /* Define this if you can switch on/off the accessory power supply */ |
251 | #define HAVE_ACCESSORY_SUPPLY | 257 | #define HAVE_ACCESSORY_SUPPLY |
252 | //#define IPOD_ACCESSORY_PROTOCOL | ||
253 | #define HAVE_SERIAL | ||
254 | 258 | ||
255 | /* Define this, if you can switch on/off the lineout */ | 259 | /* Define this, if you can switch on/off the lineout */ |
256 | #define HAVE_LINEOUT_POWEROFF | 260 | #define HAVE_LINEOUT_POWEROFF |
diff --git a/firmware/target/arm/s5l8702/ipod6g/powermgmt-ipod6g.c b/firmware/target/arm/s5l8702/ipod6g/powermgmt-ipod6g.c index ace66295f8..4553b03685 100644 --- a/firmware/target/arm/s5l8702/ipod6g/powermgmt-ipod6g.c +++ b/firmware/target/arm/s5l8702/ipod6g/powermgmt-ipod6g.c | |||
@@ -69,12 +69,12 @@ void accessory_supply_set(bool enable) | |||
69 | if (enable) | 69 | if (enable) |
70 | { | 70 | { |
71 | /* Accessory voltage supply on */ | 71 | /* Accessory voltage supply on */ |
72 | //TODO: pmu_ldo_power_on(6); | 72 | pmu_ldo_power_on(6); |
73 | } | 73 | } |
74 | else | 74 | else |
75 | { | 75 | { |
76 | /* Accessory voltage supply off */ | 76 | /* Accessory voltage supply off */ |
77 | //TODO: pmu_ldo_power_off(6); | 77 | pmu_ldo_power_off(6); |
78 | } | 78 | } |
79 | } | 79 | } |
80 | #endif | 80 | #endif |
diff --git a/firmware/target/arm/s5l8702/ipod6g/serial-ipod6g.c b/firmware/target/arm/s5l8702/ipod6g/serial-ipod6g.c index c03ba9bc24..b022fef675 100644 --- a/firmware/target/arm/s5l8702/ipod6g/serial-ipod6g.c +++ b/firmware/target/arm/s5l8702/ipod6g/serial-ipod6g.c | |||
@@ -41,6 +41,9 @@ | |||
41 | #define IPOD6G_UART_CLK_HZ 12000000 /* external OSC0 ??? */ | 41 | #define IPOD6G_UART_CLK_HZ 12000000 /* external OSC0 ??? */ |
42 | 42 | ||
43 | extern struct uartc s5l8702_uart; | 43 | extern struct uartc s5l8702_uart; |
44 | #ifdef IPOD_ACCESSORY_PROTOCOL | ||
45 | void iap_rx_isr(int, char*, char*, uint32_t); | ||
46 | #endif | ||
44 | 47 | ||
45 | struct uartc_port ser_port IDATA_ATTR = { | 48 | struct uartc_port ser_port IDATA_ATTR = { |
46 | /* location */ | 49 | /* location */ |
@@ -54,7 +57,11 @@ struct uartc_port ser_port IDATA_ATTR = { | |||
54 | .clkhz = IPOD6G_UART_CLK_HZ, | 57 | .clkhz = IPOD6G_UART_CLK_HZ, |
55 | 58 | ||
56 | /* interrupt callbacks */ | 59 | /* interrupt callbacks */ |
60 | #ifdef IPOD_ACCESSORY_PROTOCOL | ||
61 | .rx_cb = iap_rx_isr, | ||
62 | #else | ||
57 | .rx_cb = NULL, | 63 | .rx_cb = NULL, |
64 | #endif | ||
58 | .tx_cb = NULL, /* polling */ | 65 | .tx_cb = NULL, /* polling */ |
59 | }; | 66 | }; |
60 | 67 | ||
@@ -85,3 +92,104 @@ void tx_writec(unsigned char c) | |||
85 | { | 92 | { |
86 | uartc_port_tx_byte(&ser_port, c); | 93 | uartc_port_tx_byte(&ser_port, c); |
87 | } | 94 | } |
95 | |||
96 | #ifdef IPOD_ACCESSORY_PROTOCOL | ||
97 | #include "iap.h" | ||
98 | |||
99 | enum { | ||
100 | ABR_STATUS_LAUNCHED, /* ST_SYNC */ | ||
101 | ABR_STATUS_SYNCING, /* ST_SOF */ | ||
102 | ABR_STATUS_DONE | ||
103 | }; | ||
104 | |||
105 | int abr_status; | ||
106 | |||
107 | void serial_bitrate(int rate) | ||
108 | { | ||
109 | logf("[%lu] serial_bitrate(%d)", USEC_TIMER, rate); | ||
110 | |||
111 | if (rate == 0) { | ||
112 | /* Using auto-bitrate (ABR) to detect accessory Tx speed: | ||
113 | * | ||
114 | * + Here: | ||
115 | * - Disable Rx logic to clean the FIFO and the shift | ||
116 | * register, thus no Rx data interrupts are generated. | ||
117 | * - Launch ABR and wait for a low pulse in Rx line. | ||
118 | * | ||
119 | * + In ISR, when a low pulse is detected (ideally it is the | ||
120 | * start bit of 0xff): | ||
121 | * - Calculate and configure detected speed. | ||
122 | * - Enable Rx to verify that the next received data frame | ||
123 | * is 0x55 or 0xff: | ||
124 | * - If so, it's assumed bit rate is correctly detected, | ||
125 | * it will not be modified until speed is changed using | ||
126 | * RB options menu. | ||
127 | * - If not, reset iAP state machine and launch a new ABR. | ||
128 | */ | ||
129 | uartc_port_set_rx_mode(&ser_port, UCON_MODE_DISABLED); | ||
130 | uartc_port_abr_start(&ser_port); | ||
131 | abr_status = ABR_STATUS_LAUNCHED; | ||
132 | } | ||
133 | else { | ||
134 | uartc_port_abr_stop(&ser_port); /* abort ABR if already launched */ | ||
135 | uartc_port_set_bitrate(&ser_port, rate); | ||
136 | uartc_port_set_rx_mode(&ser_port, UCON_MODE_INTREQ); | ||
137 | abr_status = ABR_STATUS_DONE; | ||
138 | } | ||
139 | } | ||
140 | |||
141 | void iap_rx_isr(int len, char *data, char *err, uint32_t abr_cnt) | ||
142 | { | ||
143 | /* ignore Rx errors, upper layer will discard bad packets */ | ||
144 | (void) err; | ||
145 | |||
146 | static int sync_retry; | ||
147 | |||
148 | if (abr_status == ABR_STATUS_LAUNCHED) { | ||
149 | /* autobauding */ | ||
150 | if (abr_cnt) { | ||
151 | #define BR2CNT(s) (IPOD6G_UART_CLK_HZ / (unsigned)(s)) | ||
152 | unsigned speed; | ||
153 | |||
154 | if (abr_cnt < BR2CNT(57600*1.1) || abr_cnt > BR2CNT(9600*0.9)) { | ||
155 | /* detected speed out of range, relaunch ABR */ | ||
156 | uartc_port_abr_start(&ser_port); | ||
157 | return; | ||
158 | } | ||
159 | /* valid speed detected, select it */ | ||
160 | else if (abr_cnt < BR2CNT(48000)) speed = 57600; | ||
161 | else if (abr_cnt < BR2CNT(33600)) speed = 38400; | ||
162 | else if (abr_cnt < BR2CNT(24000)) speed = 28800; | ||
163 | else if (abr_cnt < BR2CNT(14400)) speed = 19200; | ||
164 | else speed = 9600; | ||
165 | |||
166 | /* set detected speed */ | ||
167 | uartc_port_set_bitrate(&ser_port, speed); | ||
168 | uartc_port_set_rx_mode(&ser_port, UCON_MODE_INTREQ); | ||
169 | |||
170 | /* enter SOF state */ | ||
171 | iap_getc(0xff); | ||
172 | |||
173 | abr_status = ABR_STATUS_SYNCING; | ||
174 | sync_retry = 2; /* we are expecting [0xff] 0x55 */ | ||
175 | } | ||
176 | } | ||
177 | |||
178 | /* process received data */ | ||
179 | while (len--) { | ||
180 | bool sync_done = !iap_getc(*data++); | ||
181 | |||
182 | if (abr_status == ABR_STATUS_SYNCING) { | ||
183 | if (sync_done) { | ||
184 | abr_status = ABR_STATUS_DONE; | ||
185 | } | ||
186 | else if (--sync_retry == 0) { | ||
187 | /* invalid speed detected, relaunch ABR | ||
188 | discarding remaining data (if any) */ | ||
189 | serial_bitrate(0); | ||
190 | break; | ||
191 | } | ||
192 | } | ||
193 | } | ||
194 | } | ||
195 | #endif /* IPOD_ACCESSORY_PROTOCOL */ | ||