diff options
3 files changed, 234 insertions, 103 deletions
diff --git a/firmware/target/arm/tms320dm320/sansa-connect/avr-sansaconnect.c b/firmware/target/arm/tms320dm320/sansa-connect/avr-sansaconnect.c index 9d91093a02..2a71563c0b 100644 --- a/firmware/target/arm/tms320dm320/sansa-connect/avr-sansaconnect.c +++ b/firmware/target/arm/tms320dm320/sansa-connect/avr-sansaconnect.c @@ -24,6 +24,8 @@ #include "system.h" #include "power.h" #include "kernel.h" +#include "panic.h" +/*#define LOGF_ENABLE*/ #include "logf.h" #include "avr-sansaconnect.h" #include "uart-target.h" @@ -48,25 +50,56 @@ #define dbgprintf(...) #endif -#define CMD_SYNC 0xAA -#define CMD_CLOSE 0xCC -#define CMD_LCM_POWER 0xC9 -#define LCM_POWER_OFF 0x00 -#define LCM_POWER_ON 0x01 -#define LCM_POWER_SLEEP 0x02 -#define LCM_POWER_WAKE 0x03 -#define LCM_REPOWER_ON 0x04 - -#define CMD_STATE 0xBB -#define CMD_VER 0xBC -#define CMD_WHEEL_EN 0xD0 -#define CMD_SET_INTCHRG 0xD1 -#define CMD_CODEC_RESET 0xD7 -#define CMD_AMP_ENABLE 0xCA -#define CMD_FILL 0xFF - -#define CMD_SYS_CTRL 0xDA -#define SYS_CTRL_POWEROFF 0x00 +#define AVR_DELAY_US 100 + +#define CMD_SYNC 0xAA +#define CMD_CLOSE 0xCC +#define CMD_FILL 0xFF + +/* Actual command opcodes handled by AVR */ +#define CMD_STATE 0xBB +#define CMD_VER 0xBC +#define CMD_MONOTIME 0xBD +#define CMD_PGMWAKE 0xBF +#define CMD_HDQ_READ 0xC0 +#define CMD_HDQ_WRITE 0xC1 +#define CMD_HDQ_STATUS 0xC2 +#define CMD_GET_LAST_RESET_TYPE 0xC4 +#define CMD_UNKNOWN_C5 0xC5 +#define CMD_GET_BATTERY_TEMP 0xC8 +#define CMD_LCM_POWER 0xC9 +#define CMD_AMP_ENABLE 0xCA +#define CMD_WHEEL_EN 0xD0 +#define CMD_SET_INTCHRG 0xD1 +#define CMD_GET_INTCHRG 0xD2 +#define CMD_UNKNOWN_D3 0xD3 +#define CMD_UNKNOWN_D4 0xD4 +#define CMD_UNKNOWN_D5 0xD5 +#define CMD_UNKNOWN_D6 0xD6 +#define CMD_CODEC_RESET 0xD7 +#define CMD_ADC_START 0xD8 +#define CMD_ADC_RESULT 0xD9 +#define CMD_SYS_CTRL 0xDA +#define CMD_SET_USBCHRG 0xE2 +#define CMD_GET_USBCHRG 0xE3 +#define CMD_MONORSTCNT 0xE4 + +/* CMD_LCM_POWER parameters */ +#define LCM_POWER_OFF 0x00 +#define LCM_POWER_ON 0x01 +#define LCM_POWER_SLEEP 0x02 +#define LCM_POWER_WAKE 0x03 +#define LCM_REPOWER_ON 0x04 + +/* CMD_SYS_CTRL parameters */ +#define SYS_CTRL_POWEROFF 0x00 +#define SYS_CTRL_RESET 0x01 +#define SYS_CTRL_SLEEP 0x02 +#define SYS_CTRL_DISABLE_WD 0x03 +#define SYS_CTRL_KICK_WD 0x04 +#define SYS_CTRL_EN_HDQ_THERM 0x05 +#define SYS_CTRL_EN_TS_THERM 0x06 +#define SYS_CTRL_FRESET 0x80 /* protects spi avr commands from concurrent access */ static struct mutex avr_mtx; @@ -93,21 +126,21 @@ static uint8_t avr_battery_status; #define BATTERY_LEVEL_PERCENTAGE_MASK 0x7F static uint8_t avr_battery_level = 100; -static inline unsigned short be2short(unsigned char* buf) +static inline uint16_t be2short(uint8_t *buf) { - return (unsigned short)((buf[0] << 8) | buf[1]); + return (uint16_t)((buf[0] << 8) | buf[1]); } #define BUTTON_DIRECT_MASK (BUTTON_LEFT | BUTTON_UP | BUTTON_RIGHT | BUTTON_DOWN | BUTTON_SELECT | BUTTON_VOL_UP | BUTTON_VOL_DOWN | BUTTON_NEXT | BUTTON_PREV) #ifndef BOOTLOADER -static void handle_wheel(unsigned char wheel) +static void handle_wheel(uint8_t wheel) { static int key = 0; - static unsigned char velocity = 0; - static unsigned long wheel_delta = 1ul << 24; - static unsigned char wheel_prev = 0; - static long nextbacklight_hw_on = 0; + static uint8_t velocity = 0; + static uint32_t wheel_delta = 1ul << 24; + static uint8_t wheel_prev = 0; + static unsigned long nextbacklight_hw_on = 0; static int prev_key = -1; static int prev_key_post = 0; @@ -168,18 +201,18 @@ static void handle_wheel(unsigned char wheel) } #endif -/* buf must be 11-byte array of byte (reply from avr_hid_get_state() */ -static void parse_button_state(unsigned char *buf) +/* buf must be 8-byte state array (reply from avr_hid_get_state() */ +static void parse_button_state(uint8_t *state) { - unsigned short main_btns_state = be2short(&buf[4]); + uint16_t main_btns_state = be2short(&state[2]); #ifdef BUTTON_DEBUG - unsigned short main_btns_changed = be2short(&buf[6]); + uint16_t main_btns_changed = be2short(&state[4]); #endif /* make sure other bits doesn't conflict with our "free bits" buttons */ main_btns_state &= BUTTON_DIRECT_MASK; - if (buf[3] & 0x01) /* is power button pressed? */ + if (state[1] & 0x01) /* is power button pressed? */ { main_btns_state |= BUTTON_POWER; } @@ -188,11 +221,11 @@ static void parse_button_state(unsigned char *buf) #ifndef BOOTLOADER /* check if stored hold_switch state changed (prevents lost changes) */ - if ((buf[3] & 0x20) /* hold change notification */ || - (hold_switch != ((buf[3] & 0x02) >> 1))) + if ((state[1] & 0x20) /* hold change notification */ || + (hold_switch != ((state[1] & 0x02) >> 1))) { #endif - hold_switch = (buf[3] & 0x02) >> 1; + hold_switch = (state[1] & 0x02) >> 1; #ifdef BUTTON_DEBUG dbgprintf("HOLD changed (%d)", hold_switch); #endif @@ -201,14 +234,14 @@ static void parse_button_state(unsigned char *buf) } #endif #ifndef BOOTLOADER - if ((hold_switch == false) && (buf[3] & 0x80)) /* scrollwheel change */ + if ((hold_switch == false) && (state[1] & 0x80)) /* scrollwheel change */ { - handle_wheel(buf[2]); + handle_wheel(state[0]); } #endif #ifdef BUTTON_DEBUG - if (buf[3] & 0x10) /* power button change */ + if (state[1] & 0x10) /* power button change */ { /* power button state has changed */ main_btns_changed |= BUTTON_POWER; @@ -230,50 +263,164 @@ static void parse_button_state(unsigned char *buf) #endif } -static void spi_txrx(unsigned char *buf_tx, unsigned char *buf_rx, int n) +static bool avr_command_reads_data(uint8_t opcode) { - int i; - unsigned short rxdata; + switch (opcode) + { + case CMD_STATE: + case CMD_VER: + case CMD_GET_LAST_RESET_TYPE: + case CMD_GET_INTCHRG: + case CMD_MONOTIME: + case CMD_UNKNOWN_C5: + case CMD_MONORSTCNT: + case CMD_HDQ_STATUS: + case CMD_GET_BATTERY_TEMP: + case CMD_GET_USBCHRG: + case CMD_ADC_RESULT: + return true; + default: + return false; + } +} + +static size_t avr_command_data_size(uint8_t opcode) +{ + switch (opcode) + { + case CMD_STATE: return 8; + case CMD_VER: return 1; + case CMD_MONOTIME: return 4; + case CMD_PGMWAKE: return 4; + case CMD_HDQ_READ: return 1; + case CMD_HDQ_WRITE: return 2; + case CMD_HDQ_STATUS: return 2; + case CMD_GET_LAST_RESET_TYPE: return 1; + case CMD_UNKNOWN_C5: return 1; + case CMD_GET_BATTERY_TEMP: return 2; + case CMD_LCM_POWER: return 1; + case CMD_AMP_ENABLE: return 1; + case CMD_WHEEL_EN: return 1; + case CMD_SET_INTCHRG: return 1; + case CMD_GET_INTCHRG: return 1; + case CMD_UNKNOWN_D3: return 1; + case CMD_UNKNOWN_D4: return 1; + case CMD_UNKNOWN_D5: return 2; + case CMD_UNKNOWN_D6: return 2; + case CMD_CODEC_RESET: return 0; + case CMD_ADC_START: return 1; + case CMD_ADC_RESULT: return 2; + case CMD_SYS_CTRL: return 1; + case CMD_SET_USBCHRG: return 1; + case CMD_GET_USBCHRG: return 1; + case CMD_MONORSTCNT: return 2; + default: + panicf("Invalid AVR opcode %02X", opcode); + return 0; + } +} + +static uint8_t spi_read_byte(void) +{ + uint16_t rxdata; + + do + { + rxdata = IO_SERIAL1_RX_DATA; + } + while (rxdata & (1<<8)); + + return rxdata & 0xFF; +} + +static bool avr_run_command(uint8_t opcode, uint8_t *data, size_t data_length) +{ + bool success = true; + const bool is_read = avr_command_reads_data(opcode); + size_t i; + uint8_t rx; + + /* Verify command data size and also make sure command is valid */ + if (avr_command_data_size(opcode) != data_length) + { + panicf("AVR %02x invalid data length", opcode); + } mutex_lock(&avr_mtx); bitset16(&IO_CLK_MOD2, CLK_MOD2_SIF1); IO_SERIAL1_TX_ENABLE = 0x0001; - for (i = 0; i<n; i++) - { - IO_SERIAL1_TX_DATA = buf_tx[i]; + IO_SERIAL1_TX_DATA = CMD_SYNC; + spi_read_byte(); + /* Allow AVR to process CMD_SYNC */ + udelay(AVR_DELAY_US); - /* 100 us wait for AVR */ - udelay(100); + IO_SERIAL1_TX_DATA = opcode; + rx = spi_read_byte(); + if (rx != CMD_SYNC) + { + /* AVR failed to register CMD_SYNC */ + success = false; + } + /* Allow AVR to process opcode */ + udelay(AVR_DELAY_US); - do + if (is_read) + { + for (i = 0; i < data_length; i++) { - rxdata = IO_SERIAL1_RX_DATA; - } while (rxdata & (1<<8)); - - if (buf_rx != NULL) - buf_rx[i] = rxdata & 0xFF; + IO_SERIAL1_TX_DATA = CMD_FILL; + data[i] = spi_read_byte(); + udelay(AVR_DELAY_US); + } + } + else + { + for (i = 0; i < data_length; i++) + { + IO_SERIAL1_TX_DATA = data[i]; + spi_read_byte(); + udelay(AVR_DELAY_US); + } + } - /* 100 us wait to give AVR time to process data */ - udelay(100); + IO_SERIAL1_TX_DATA = CMD_CLOSE; + rx = spi_read_byte(); + udelay(AVR_DELAY_US); + if (is_read) + { + success = success && (rx == CMD_CLOSE); } IO_SERIAL1_TX_ENABLE = 0; bitclr16(&IO_CLK_MOD2, CLK_MOD2_SIF1); mutex_unlock(&avr_mtx); + + return success; } -void avr_hid_sync(void) + +static void avr_hid_sync(void) { - int i; - unsigned char prg[4] = {CMD_SYNC, CMD_VER, CMD_FILL, CMD_CLOSE}; + uint8_t data; + while (!avr_run_command(CMD_VER, &data, sizeof(data))) + { + /* TODO: Program HID if failing for long time. + * To do so, unfortunately, AVR firmware would have to be written + * from scratch as OF blob cannot be used due to licensing. + */ + } - /* Send SYNC three times */ - for (i = 0; i<3; i++) +} + +static void avr_execute_command(uint8_t opcode, uint8_t *data, size_t data_length) +{ + while (!avr_run_command(opcode, data, data_length)) { - spi_txrx(prg, NULL, sizeof(prg)); + /* Resync and try again */ + avr_hid_sync(); } } @@ -324,87 +471,70 @@ bool charging_state(void) static void avr_hid_get_state(void) { - static unsigned char cmd[11] = {CMD_SYNC, CMD_STATE, - CMD_FILL, CMD_FILL, CMD_FILL, CMD_FILL, CMD_FILL, CMD_FILL, CMD_FILL, CMD_FILL, - CMD_CLOSE}; - - static unsigned char buf[11]; + uint8_t state[8]; + avr_execute_command(CMD_STATE, state, sizeof(state)); - /* In very unlikely case the command has to be repeated */ - do - { - spi_txrx(cmd, buf, sizeof(cmd)); - } - while ((buf[1] != CMD_SYNC) || (buf[10] != CMD_CLOSE)); - - avr_battery_status = buf[8]; - avr_battery_level = buf[9]; - parse_button_state(buf); + avr_battery_status = state[6]; + avr_battery_level = state[7]; + parse_button_state(state); } static void avr_hid_enable_wheel(void) { - unsigned char wheel_en[4] = {CMD_SYNC, CMD_WHEEL_EN, 0x01, CMD_CLOSE}; - - spi_txrx(wheel_en, NULL, sizeof(wheel_en)); + uint8_t enable = 0x01; + avr_execute_command(CMD_WHEEL_EN, &enable, sizeof(enable)); } /* command that is sent by "hidtool -J 1" issued on every OF boot */ void avr_hid_enable_charger(void) { - unsigned char charger_en[4] = {CMD_SYNC, CMD_SET_INTCHRG, 0x01, CMD_CLOSE}; + uint8_t enable = 0x01; + avr_execute_command(CMD_SET_INTCHRG, &enable, sizeof(enable)); +} - spi_txrx(charger_en, NULL, sizeof(charger_en)); +static void avr_hid_lcm_power(uint8_t parameter) +{ + avr_execute_command(CMD_LCM_POWER, ¶meter, sizeof(parameter)); } void avr_hid_lcm_sleep(void) { - unsigned char lcm_sleep[4] = {CMD_SYNC, CMD_LCM_POWER, LCM_POWER_SLEEP, CMD_CLOSE}; - - spi_txrx(lcm_sleep, NULL, sizeof(lcm_sleep)); + avr_hid_lcm_power(LCM_POWER_SLEEP); } - void avr_hid_lcm_wake(void) { - unsigned char lcm_wake[4] = {CMD_SYNC, CMD_LCM_POWER, LCM_POWER_WAKE, CMD_CLOSE}; - - spi_txrx(lcm_wake, NULL, sizeof(lcm_wake)); + avr_hid_lcm_power(LCM_POWER_WAKE); } void avr_hid_lcm_power_on(void) { - unsigned char lcm_power_on[4] = {CMD_SYNC, CMD_LCM_POWER, LCM_POWER_ON, CMD_CLOSE}; - - spi_txrx(lcm_power_on, NULL, sizeof(lcm_power_on)); + avr_hid_lcm_power(LCM_POWER_ON); } void avr_hid_lcm_power_off(void) { - unsigned char lcm_power_off[4] = {CMD_SYNC, CMD_LCM_POWER, LCM_POWER_OFF, CMD_CLOSE}; - - spi_txrx(lcm_power_off, NULL, sizeof(lcm_power_off)); + avr_hid_lcm_power(LCM_POWER_OFF); } void avr_hid_reset_codec(void) { - unsigned char codec_reset[4] = {CMD_SYNC, CMD_CODEC_RESET, CMD_CLOSE, CMD_FILL}; - - spi_txrx(codec_reset, NULL, sizeof(codec_reset)); + avr_execute_command(CMD_CODEC_RESET, NULL, 0); } -void avr_hid_set_amp_enable(unsigned char enable) +void avr_hid_set_amp_enable(uint8_t enable) { - unsigned char amp_enable[4] = {CMD_SYNC, CMD_AMP_ENABLE, enable, CMD_CLOSE}; + avr_execute_command(CMD_AMP_ENABLE, &enable, sizeof(enable)); +} - spi_txrx(amp_enable, NULL, sizeof(amp_enable)); +static void avr_hid_sys_ctrl(uint8_t parameter) +{ + avr_execute_command(CMD_SYS_CTRL, ¶meter, sizeof(parameter)); } void avr_hid_power_off(void) { - unsigned char prg[4] = {CMD_SYNC, CMD_SYS_CTRL, SYS_CTRL_POWEROFF, CMD_CLOSE}; - - spi_txrx(prg, NULL, sizeof(prg)); + avr_hid_sys_ctrl(SYS_CTRL_POWEROFF); } #ifndef BOOTLOADER @@ -491,6 +621,9 @@ void button_init_device(void) #endif IO_GIO_DIR0 |= 0x01; /* Set GIO0 as input */ + /* Get in sync with AVR */ + avr_hid_sync(); + /* Enable wheel */ avr_hid_enable_wheel(); /* Read button status and tell avr we want interrupt on next change */ diff --git a/firmware/target/arm/tms320dm320/sansa-connect/avr-sansaconnect.h b/firmware/target/arm/tms320dm320/sansa-connect/avr-sansaconnect.h index 06fd2b2d72..64b44675f7 100644 --- a/firmware/target/arm/tms320dm320/sansa-connect/avr-sansaconnect.h +++ b/firmware/target/arm/tms320dm320/sansa-connect/avr-sansaconnect.h @@ -24,7 +24,6 @@ #include "config.h" -void avr_hid_sync(void); void avr_hid_init(void); void avr_hid_enable_charger(void); diff --git a/firmware/target/arm/tms320dm320/sansa-connect/lcd-sansaconnect.c b/firmware/target/arm/tms320dm320/sansa-connect/lcd-sansaconnect.c index 27eb0b407a..07be11e849 100644 --- a/firmware/target/arm/tms320dm320/sansa-connect/lcd-sansaconnect.c +++ b/firmware/target/arm/tms320dm320/sansa-connect/lcd-sansaconnect.c @@ -123,7 +123,6 @@ void lcd_init_device(void) /* Copy Rockbox frame buffer to the second framebuffer */ lcd_update(); - avr_hid_sync(); avr_hid_lcm_power_on(); /* set framebuffer address - OF sets RAM start address to 0x1000000 */ |