iPod Classic: use PMU interrupts to detect accessories

- Speed auto detection is launched when an accessory is inserted,
  so the user doesn't need to modify settings to use accessories
  that operates at different speeds (or when the same accessory is
  unplugged and plugged again).

- UART controller is disabled when no accessory is inserted, not
  much powersave but everything counts.

Change-Id: If20c3617c2a87b6277fd7e0270031030c44fa953
This commit is contained in:
Cástor Muñoz 2016-05-25 23:18:33 +02:00
parent d8989b15b7
commit f6ed4f8306
2 changed files with 73 additions and 28 deletions

View file

@ -138,22 +138,26 @@ bool dbg_hw_info(void)
else if(state==2) else if(state==2)
{ {
extern struct uartc_port ser_port; extern struct uartc_port ser_port;
int tx_stat, rx_stat, tx_speed, rx_speed; bool opened = !!ser_port.uartc->port_l[ser_port.id];
char line_cfg[4]; _DEBUG_PRINTF("UART %d: %s", ser_port.id, opened ? "opened":"closed");
int abr_stat; if (opened)
uint32_t abr_cnt; {
char *abrstatus[] = {"Idle", "Launched", "Counting", "Abnormal"}; int tx_stat, rx_stat, tx_speed, rx_speed;
char line_cfg[4];
int abr_stat;
uint32_t abr_cnt;
char *abrstatus[] = {"Idle", "Launched", "Counting", "Abnormal"};
uartc_port_get_line_info(&ser_port, uartc_port_get_line_info(&ser_port,
&tx_stat, &rx_stat, &tx_speed, &rx_speed, line_cfg); &tx_stat, &rx_stat, &tx_speed, &rx_speed, line_cfg);
abr_stat = uartc_port_get_abr_info(&ser_port, &abr_cnt); abr_stat = uartc_port_get_abr_info(&ser_port, &abr_cnt);
_DEBUG_PRINTF("UART %d:", ser_port.id); line++;
line++; _DEBUG_PRINTF("line: %s", line_cfg);
_DEBUG_PRINTF("line: %s", line_cfg); _DEBUG_PRINTF("Tx: %s, speed: %d", tx_stat ? "On":"Off", tx_speed);
_DEBUG_PRINTF("Tx: %s, speed: %d", tx_stat ? "On":"Off", tx_speed); _DEBUG_PRINTF("Rx: %s, speed: %d", rx_stat ? "On":"Off", rx_speed);
_DEBUG_PRINTF("Rx: %s, speed: %d", rx_stat ? "On":"Off", rx_speed); _DEBUG_PRINTF("ABR: %s, cnt: %u", abrstatus[abr_stat], abr_cnt);
_DEBUG_PRINTF("ABR: %s, cnt: %u", abrstatus[abr_stat], abr_cnt); }
line++; line++;
_DEBUG_PRINTF("n_tx_bytes: %u", ser_port.n_tx_bytes); _DEBUG_PRINTF("n_tx_bytes: %u", ser_port.n_tx_bytes);
_DEBUG_PRINTF("n_rx_bytes: %u", ser_port.n_rx_bytes); _DEBUG_PRINTF("n_rx_bytes: %u", ser_port.n_rx_bytes);
@ -162,7 +166,7 @@ bool dbg_hw_info(void)
_DEBUG_PRINTF("n_frame_err: %u", ser_port.n_frame_err); _DEBUG_PRINTF("n_frame_err: %u", ser_port.n_frame_err);
_DEBUG_PRINTF("n_break_detect: %u", ser_port.n_break_detect); _DEBUG_PRINTF("n_break_detect: %u", ser_port.n_break_detect);
_DEBUG_PRINTF("ABR n_abnormal: %u %u", _DEBUG_PRINTF("ABR n_abnormal: %u %u",
ser_port.n_abnormal0, ser_port.n_abnormal1); ser_port.n_abnormal0, ser_port.n_abnormal1);
} }
#endif #endif
else else

View file

@ -48,7 +48,7 @@
extern const struct uartc s5l8702_uartc; extern const struct uartc s5l8702_uartc;
#ifdef IPOD_ACCESSORY_PROTOCOL #ifdef IPOD_ACCESSORY_PROTOCOL
void iap_rx_isr(int, char*, char*, uint32_t); static void iap_rx_isr(int, char*, char*, uint32_t);
#endif #endif
struct uartc_port ser_port IDATA_ATTR = struct uartc_port ser_port IDATA_ATTR =
@ -75,6 +75,17 @@ struct uartc_port ser_port IDATA_ATTR =
/* /*
* serial driver API * serial driver API
*/ */
int tx_rdy(void)
{
return uartc_port_tx_ready(&ser_port) ? 1 : 0;
}
void tx_writec(unsigned char c)
{
uartc_port_tx_byte(&ser_port, c);
}
#ifndef IPOD_ACCESSORY_PROTOCOL
void serial_setup(void) void serial_setup(void)
{ {
uartc_port_open(&ser_port); uartc_port_open(&ser_port);
@ -91,18 +102,10 @@ void serial_setup(void)
logf("[%lu] "MODEL_NAME" port %d ready!", USEC_TIMER, ser_port.id); logf("[%lu] "MODEL_NAME" port %d ready!", USEC_TIMER, ser_port.id);
} }
int tx_rdy(void)
{
return uartc_port_tx_ready(&ser_port) ? 1 : 0;
}
void tx_writec(unsigned char c) #else /* IPOD_ACCESSORY_PROTOCOL */
{ #include "kernel.h"
uartc_port_tx_byte(&ser_port, c); #include "pmu-target.h"
}
#ifdef IPOD_ACCESSORY_PROTOCOL
#include "iap.h" #include "iap.h"
static enum { static enum {
@ -111,8 +114,46 @@ static enum {
ABR_STATUS_DONE ABR_STATUS_DONE
} abr_status; } abr_status;
static int bitrate = 0;
static bool acc_plugged = false;
static void serial_acc_tick(void)
{
bool plugged = pmu_accessory_present();
if (acc_plugged != plugged)
{
acc_plugged = plugged;
if (acc_plugged)
{
uartc_open(ser_port.uartc);
uartc_port_open(&ser_port);
/* set a default configuration, Tx and Rx modes are
disabled when the port is initialized */
uartc_port_config(&ser_port, ULCON_DATA_BITS_8,
ULCON_PARITY_NONE, ULCON_STOP_BITS_1);
uartc_port_set_tx_mode(&ser_port, UCON_MODE_INTREQ);
serial_bitrate(bitrate);
}
else
{
uartc_port_close(&ser_port);
uartc_close(ser_port.uartc);
}
}
}
void serial_setup(void)
{
uartc_close(ser_port.uartc);
tick_add_task(serial_acc_tick);
}
void serial_bitrate(int rate) void serial_bitrate(int rate)
{ {
bitrate = rate;
if (!acc_plugged)
return;
logf("[%lu] serial_bitrate(%d)", USEC_TIMER, rate); logf("[%lu] serial_bitrate(%d)", USEC_TIMER, rate);
if (rate == 0) { if (rate == 0) {
@ -150,7 +191,7 @@ void serial_bitrate(int rate)
} }
} }
void iap_rx_isr(int len, char *data, char *err, uint32_t abr_cnt) static void iap_rx_isr(int len, char *data, char *err, uint32_t abr_cnt)
{ {
/* ignore Rx errors, upper layer will discard bad packets */ /* ignore Rx errors, upper layer will discard bad packets */
(void) err; (void) err;