summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--firmware/export/config/ipod6g.h8
-rw-r--r--firmware/target/arm/s5l8702/ipod6g/powermgmt-ipod6g.c4
-rw-r--r--firmware/target/arm/s5l8702/ipod6g/serial-ipod6g.c108
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
43extern struct uartc s5l8702_uart; 43extern struct uartc s5l8702_uart;
44#ifdef IPOD_ACCESSORY_PROTOCOL
45void iap_rx_isr(int, char*, char*, uint32_t);
46#endif
44 47
45struct uartc_port ser_port IDATA_ATTR = { 48struct 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
99enum {
100 ABR_STATUS_LAUNCHED, /* ST_SYNC */
101 ABR_STATUS_SYNCING, /* ST_SOF */
102 ABR_STATUS_DONE
103};
104
105int abr_status;
106
107void 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
141void 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 */