diff options
author | Cástor Muñoz <cmvidal@gmail.com> | 2016-05-14 14:24:49 +0200 |
---|---|---|
committer | Cástor Muñoz <cmvidal@gmail.com> | 2016-05-14 19:39:09 +0200 |
commit | 9a4cd2eaee7d389f2fa6e0d79f0f6ea526f7ef85 (patch) | |
tree | 2cf04d46c512cf48d05c1804e03aee952885bf47 /firmware/target/arm/s5l8700/ipodnano2g/serial-nano2g.c | |
parent | 60fb707203c5b0ce2c32776890611846f0c22566 (diff) | |
download | rockbox-9a4cd2eaee7d389f2fa6e0d79f0f6ea526f7ef85.tar.gz rockbox-9a4cd2eaee7d389f2fa6e0d79f0f6ea526f7ef85.zip |
iPod Nano2G: add IPOD_ACCESSORY_PROTOCOL
Change-Id: I78a19972624504bc802d96b9b8e9cec132164c2c
Diffstat (limited to 'firmware/target/arm/s5l8700/ipodnano2g/serial-nano2g.c')
-rw-r--r-- | firmware/target/arm/s5l8700/ipodnano2g/serial-nano2g.c | 113 |
1 files changed, 113 insertions, 0 deletions
diff --git a/firmware/target/arm/s5l8700/ipodnano2g/serial-nano2g.c b/firmware/target/arm/s5l8700/ipodnano2g/serial-nano2g.c index 487984fbe3..5ff0b0ca25 100644 --- a/firmware/target/arm/s5l8700/ipodnano2g/serial-nano2g.c +++ b/firmware/target/arm/s5l8700/ipodnano2g/serial-nano2g.c | |||
@@ -47,6 +47,9 @@ | |||
47 | 47 | ||
48 | 48 | ||
49 | extern const struct uartc s5l8701_uartc0; | 49 | extern const struct uartc s5l8701_uartc0; |
50 | #ifdef IPOD_ACCESSORY_PROTOCOL | ||
51 | void iap_rx_isr(int, char*, char*, uint32_t); | ||
52 | #endif | ||
50 | 53 | ||
51 | struct uartc_port ser_port IDATA_ATTR = | 54 | struct uartc_port ser_port IDATA_ATTR = |
52 | { | 55 | { |
@@ -61,7 +64,11 @@ struct uartc_port ser_port IDATA_ATTR = | |||
61 | .clkhz = NANO2G_UART_CLK_HZ, | 64 | .clkhz = NANO2G_UART_CLK_HZ, |
62 | 65 | ||
63 | /* interrupt callbacks */ | 66 | /* interrupt callbacks */ |
67 | #ifdef IPOD_ACCESSORY_PROTOCOL | ||
68 | .rx_cb = iap_rx_isr, | ||
69 | #else | ||
64 | .rx_cb = NULL, | 70 | .rx_cb = NULL, |
71 | #endif | ||
65 | .tx_cb = NULL, /* polling */ | 72 | .tx_cb = NULL, /* polling */ |
66 | }; | 73 | }; |
67 | 74 | ||
@@ -94,3 +101,109 @@ void tx_writec(unsigned char c) | |||
94 | { | 101 | { |
95 | uartc_port_tx_byte(&ser_port, c); | 102 | uartc_port_tx_byte(&ser_port, c); |
96 | } | 103 | } |
104 | |||
105 | |||
106 | #ifdef IPOD_ACCESSORY_PROTOCOL | ||
107 | #include "iap.h" | ||
108 | |||
109 | static enum { | ||
110 | ABR_STATUS_LAUNCHED, /* ST_SYNC */ | ||
111 | ABR_STATUS_SYNCING, /* ST_SOF */ | ||
112 | ABR_STATUS_DONE | ||
113 | } abr_status; | ||
114 | |||
115 | void serial_bitrate(int rate) | ||
116 | { | ||
117 | logf("[%lu] serial_bitrate(%d)", (uint32_t)USEC_TIMER, rate); | ||
118 | |||
119 | if (rate == 0) { | ||
120 | /* Using auto-bitrate (ABR) to detect accessory Tx speed: | ||
121 | * | ||
122 | * + Here: | ||
123 | * - Disable Rx logic to clean the FIFO and the shift | ||
124 | * register, thus no Rx data interrupts are generated. | ||
125 | * - Launch ABR and wait for a low pulse in Rx line. | ||
126 | * | ||
127 | * + In ISR, when a low pulse is detected (ideally it is the | ||
128 | * start bit of 0xff): | ||
129 | * - Calculate and configure detected speed. | ||
130 | * - Enable Rx to verify that the next received data frame | ||
131 | * is 0x55 or 0xff: | ||
132 | * - If so, it's assumed bit rate is correctly detected, | ||
133 | * it will not be modified until speed is changed using | ||
134 | * RB options menu. | ||
135 | * - If not, reset iAP state machine and launch a new ABR. | ||
136 | */ | ||
137 | uartc_port_set_rx_mode(&ser_port, UCON_MODE_DISABLED); | ||
138 | uartc_port_abr_start(&ser_port); | ||
139 | abr_status = ABR_STATUS_LAUNCHED; | ||
140 | } | ||
141 | else { | ||
142 | uint32_t brdata; | ||
143 | if (rate == 57600) brdata = BRDATA_57600; | ||
144 | else if (rate == 38400) brdata = BRDATA_38400; | ||
145 | else if (rate == 19200) brdata = BRDATA_19200; | ||
146 | else brdata = BRDATA_9600; | ||
147 | uartc_port_abr_stop(&ser_port); /* abort ABR if already launched */ | ||
148 | uartc_port_set_bitrate_raw(&ser_port, brdata); | ||
149 | uartc_port_set_rx_mode(&ser_port, UCON_MODE_INTREQ); | ||
150 | abr_status = ABR_STATUS_DONE; | ||
151 | } | ||
152 | } | ||
153 | |||
154 | void iap_rx_isr(int len, char *data, char *err, uint32_t abr_cnt) | ||
155 | { | ||
156 | /* ignore Rx errors, upper layer will discard bad packets */ | ||
157 | (void) err; | ||
158 | |||
159 | static int sync_retry; | ||
160 | |||
161 | if (abr_status == ABR_STATUS_LAUNCHED) { | ||
162 | /* autobauding */ | ||
163 | if (abr_cnt) { | ||
164 | #define BR2CNT(s) (NANO2G_UART_CLK_HZ / (unsigned)(s)) | ||
165 | if (abr_cnt < BR2CNT(57600*1.1) || abr_cnt > BR2CNT(9600*0.9)) { | ||
166 | /* detected speed out of range, relaunch ABR */ | ||
167 | uartc_port_abr_start(&ser_port); | ||
168 | return; | ||
169 | } | ||
170 | /* valid speed detected, select it */ | ||
171 | uint32_t brdata; | ||
172 | if (abr_cnt < BR2CNT(48000)) brdata = BRDATA_57600; | ||
173 | else if (abr_cnt < BR2CNT(33600)) brdata = BRDATA_38400; | ||
174 | else if (abr_cnt < BR2CNT(24000)) brdata = BRDATA_28800; | ||
175 | else if (abr_cnt < BR2CNT(14400)) brdata = BRDATA_19200; | ||
176 | else brdata = BRDATA_9600; | ||
177 | |||
178 | /* set detected speed */ | ||
179 | uartc_port_set_bitrate_raw(&ser_port, brdata); | ||
180 | uartc_port_set_rx_mode(&ser_port, UCON_MODE_INTREQ); | ||
181 | |||
182 | /* enter SOF state */ | ||
183 | iap_getc(0xff); | ||
184 | |||
185 | abr_status = ABR_STATUS_SYNCING; | ||
186 | sync_retry = 2; /* we are expecting [0xff] 0x55 */ | ||
187 | } | ||
188 | } | ||
189 | |||
190 | /* process received data */ | ||
191 | while (len--) | ||
192 | { | ||
193 | bool sync_done = !iap_getc(*data++); | ||
194 | |||
195 | if (abr_status == ABR_STATUS_SYNCING) | ||
196 | { | ||
197 | if (sync_done) { | ||
198 | abr_status = ABR_STATUS_DONE; | ||
199 | } | ||
200 | else if (--sync_retry == 0) { | ||
201 | /* invalid speed detected, relaunch ABR | ||
202 | discarding remaining data (if any) */ | ||
203 | serial_bitrate(0); | ||
204 | break; | ||
205 | } | ||
206 | } | ||
207 | } | ||
208 | } | ||
209 | #endif /* IPOD_ACCESSORY_PROTOCOL */ | ||