#include #include #include "encoding.h" #include "platform.h" #include "board.h" #include "eos.h" #include "event.h" #include "soc/interrupt.h" #include "soc/timer.h" #include "soc/pwr.h" #include "soc/i2s.h" #include "eve/eve.h" #include "batt.h" #include "sdcard.h" #include "ctp.h" #include "eve.h" #include "app.h" #include "drv/fxl6408.h" #include "egpio.h" /* FXL chip only */ static const uint8_t egpio_switch[2] = { EGPIO_BIT_SDCARD_DET | EGPIO_BIT_BTN_WAKE, EGPIO_BIT_MIC_MUTE | EGPIO_BIT_HP_NDET, }; static uint8_t egpio_pinval[EGPIO_MAX_CHIP]; static uint8_t egpio_alt_pin; static uint32_t wake_start; static eos_egpio_intr_handler_t egpio_intr_handler; static eos_egpio_ext_handler_t egpio_ext_handler; #define EGPIO_ALT_EVEAUDIO_DIS 0x01 #define EGPIO_ALT_LSGAIN_SEL 0x02 #define EGPIO_ALT_AUDIO_SEL 0x04 #define BITSET(var, bit, val) { var = (val) ? (var | (bit)) : (var & ~(bit)); } #define PINSWITCH(STPIN, SETPIN) { \ int rv; \ BITSET(egpio_alt_pin, pin2alt_bit(STPIN), _eos_egpio_get_val(STPIN)); \ rv = _eos_egpio_set_val(SETPIN, !!(egpio_alt_pin & pin2alt_bit(SETPIN))); \ if (rv) return rv; \ } static uint8_t pin2alt_bit(uint8_t pin) { switch (pin) { case EGPIO_PIN_EVEAUDIO_DIS: return EGPIO_ALT_EVEAUDIO_DIS; case EGPIO_PIN_LSGAIN_SEL: return EGPIO_ALT_LSGAIN_SEL; case EGPIO_PIN_AUDIO_SEL: return EGPIO_ALT_AUDIO_SEL; } return 0x00; } static int handle_egpio_intr(uint8_t chip_id, uint8_t intr) { int rv; switch (chip_id) { case 0: { if (intr & EGPIO_BIT_BAT_INT) { uint8_t fault0, fault1; rv = eos_batt_read_fault(&fault0, &fault1); if (rv) return rv; if (egpio_intr_handler) egpio_intr_handler(EGPIO_INT_TYPE_BAT, fault1, fault0); } if (intr & EGPIO_BIT_CTP_INT) { eos_ctp_handle_intr(); } if (intr & EGPIO_BIT_EVE_INT) { eos_eve_handle_intr(); } if (intr & EGPIO_BIT_BTN_WAKE) { int btn_wake, tdelta; btn_wake = eos_egpio_get_val(EGPIO_PIN_BTN_WAKE); if (btn_wake == 0) { wake_start = eos_get_tick(); } else { tdelta = eos_tdelta_ms(wake_start); } if (egpio_intr_handler) egpio_intr_handler(EGPIO_INT_TYPE_WAKE, btn_wake, btn_wake ? tdelta : 0); } if (intr & EGPIO_BIT_SDCARD_DET) { int sdc_det = eos_egpio_get_val(EGPIO_PIN_SDCARD_DET); eos_sdc_insert(sdc_det); if (egpio_intr_handler) egpio_intr_handler(EGPIO_INT_TYPE_SDCARD, sdc_det, 0); } break; } case 1: { if (intr & EGPIO_BIT_MIC_MUTE) { if (egpio_intr_handler) egpio_intr_handler(EGPIO_INT_TYPE_MUTE, eos_egpio_get_val(EGPIO_PIN_MIC_MUTE), 0); } if (intr & EGPIO_BIT_HP_NDET) { int hp_det, i2s_running, app_audio; hp_det = !eos_egpio_get_val(EGPIO_PIN_HP_NDET); i2s_running = eos_i2s_running(); app_audio = !_eos_egpio_get_val(EGPIO_PIN_AUDIO_SEL); if (i2s_running || app_audio) { if (i2s_running) { eos_i2s_hp_change(hp_det); } else { eos_app_hp_change(hp_det); } if (hp_det) { /* store LSGAIN_SEL pin and set EVEAUDIO_DIS pin */ PINSWITCH(EGPIO_PIN_LSGAIN_SEL, EGPIO_PIN_EVEAUDIO_DIS); } else { /* store EVEAUDIO_DIS pin and set LSGAIN_SEL pin */ PINSWITCH(EGPIO_PIN_EVEAUDIO_DIS, EGPIO_PIN_LSGAIN_SEL); } } if (egpio_intr_handler) egpio_intr_handler(EGPIO_INT_TYPE_HP, hp_det, 0); } break; } } return EOS_OK; } static int handle_egpio_evt(uint8_t chip_id) { uint8_t intr_reg, def_reg; int rv; rv = fxl6408_reg_read(chip_id, FXL6408_REG_INT_STATE, &intr_reg); if (rv) return rv;; if (!intr_reg) return 0; if (intr_reg & egpio_switch[chip_id]) { rv = fxl6408_reg_read(chip_id, FXL6408_REG_I_DEFAULT, &def_reg); if (rv) return rv; def_reg ^= (intr_reg & egpio_switch[chip_id]); rv = fxl6408_reg_write(chip_id, FXL6408_REG_I_DEFAULT, def_reg); if (rv) return rv; egpio_pinval[chip_id] ^= (intr_reg & egpio_switch[chip_id]); } rv = handle_egpio_intr(chip_id, intr_reg); if (rv) return rv; return 1; } static void handle_evt(unsigned char type, unsigned char *buffer, uint16_t len) { type &= ~EOS_EVT_MASK; switch (type) { case EGPIO_ETYPE_INT: { int rv; rv = handle_egpio_evt(0); if (rv < 0) goto handle_evt_fin; if (GPIO_REG(GPIO_INPUT_VAL) & (1 << EGPIO_PIN_INT)) goto handle_evt_fin; rv = handle_egpio_evt(1); if (rv < 0) goto handle_evt_fin; if (GPIO_REG(GPIO_INPUT_VAL) & (1 << EGPIO_PIN_INT)) goto handle_evt_fin; if (egpio_ext_handler) rv = egpio_ext_handler(); handle_evt_fin: clear_csr(mstatus, MSTATUS_MIE); GPIO_REG(GPIO_LOW_IP) = (1 << EGPIO_PIN_INT); GPIO_REG(GPIO_LOW_IE) |= (1 << EGPIO_PIN_INT); set_csr(mstatus, MSTATUS_MIE); break; } case EGPIO_ETYPE_INT_CTP: case EGPIO_ETYPE_INT_EVE: { if (eos_egpio_get_val(EGPIO_PIN_CTP_SEL)) { eos_ctp_handle_intr(); } else { eos_eve_handle_intr(); } handle_evt_eve_fin: clear_csr(mstatus, MSTATUS_MIE); GPIO_REG(GPIO_LOW_IP) = (1 << EVE_PIN_INT); GPIO_REG(GPIO_LOW_IE) |= (1 << EVE_PIN_INT); set_csr(mstatus, MSTATUS_MIE); break; } } } static void handle_intr(void) { GPIO_REG(GPIO_LOW_IE) &= ~(1 << EGPIO_PIN_INT); eos_evtq_push_isr(EOS_EVT_EGPIO | EGPIO_ETYPE_INT, NULL, 0); } static void handle_intr_eve(void) { GPIO_REG(GPIO_LOW_IE) &= ~(1 << EVE_PIN_INT); if (egpio_pinval[EGPIO_CHIP_FXL0] & EGPIO_PIN2BIT(EGPIO0_PIN_CTP_SEL)) { eos_evtq_push_isr(EOS_EVT_EGPIO | EGPIO_ETYPE_INT_CTP, NULL, 0); } else { eos_evtq_push_isr(EOS_EVT_EGPIO | EGPIO_ETYPE_INT_EVE, NULL, 0); } } int eos_egpio_init(void) { uint8_t wakeup_cause, data, data_dir; int rst, rv; wakeup_cause = eos_pwr_wakeup_cause(); rst = (wakeup_cause == EOS_PWR_WAKE_RST); if (rst) { rv = fxl6408_reg_read(0, FXL6408_REG_ID_CTRL, &data); if (rv) return rv; rv = fxl6408_reg_read(1, FXL6408_REG_ID_CTRL, &data); if (rv) return rv; rv = fxl6408_reg_write(0, FXL6408_REG_INT_MASK, 0xff); if (rv) return rv; rv = fxl6408_reg_write(1, FXL6408_REG_INT_MASK, 0xff); if (rv) return rv; /* 1st chip */ data = EGPIO_BIT_CTP_SEL | EGPIO_BIT_EXP_IO0 | EGPIO_BIT_EXP_IO1; rv = fxl6408_reg_write(0, FXL6408_REG_IO_DIR, data); if (rv) return rv; data = EGPIO_BIT_CTP_SEL; rv = fxl6408_reg_write(0, FXL6408_REG_O_STATE, data); if (rv) return rv; data = EGPIO_BIT_EXP_IO0 | EGPIO_BIT_EXP_IO1; rv = fxl6408_reg_write(0, FXL6408_REG_O_HIZ, data); if (rv) return rv; data = EGPIO_BIT_EVE_INT | EGPIO_BIT_SDCARD_DET | EGPIO_BIT_BTN_WAKE | EGPIO_BIT_BAT_INT | EGPIO_BIT_CTP_INT; rv = fxl6408_reg_write(0, FXL6408_REG_PULL_ENA, data); if (rv) return rv; data = EGPIO_BIT_EVE_INT | EGPIO_BIT_SDCARD_DET | EGPIO_BIT_BTN_WAKE | EGPIO_BIT_BAT_INT | EGPIO_BIT_CTP_INT; rv = fxl6408_reg_write(0, FXL6408_REG_PULL_DIR, data); if (rv) return rv; /* 2nd chip */ data = EGPIO_BIT_HPAMP_CS | EGPIO_BIT_AUDIO_SEL | EGPIO_BIT_USR0 | EGPIO_BIT_USR1 | EGPIO_BIT_USR2 | EGPIO_BIT_USR3; rv = fxl6408_reg_write(1, FXL6408_REG_IO_DIR, data); if (rv) return rv; data = EGPIO_BIT_HPAMP_CS | EGPIO_BIT_AUDIO_SEL; rv = fxl6408_reg_write(1, FXL6408_REG_O_STATE, data); if (rv) return rv; data = EGPIO_BIT_USR0 | EGPIO_BIT_USR1 | EGPIO_BIT_USR2 | EGPIO_BIT_USR3; rv = fxl6408_reg_write(1, FXL6408_REG_O_HIZ, data); if (rv) return rv; data = 0; rv = fxl6408_reg_write(1, FXL6408_REG_PULL_ENA, data); if (rv) return rv; data = 0; rv = fxl6408_reg_write(1, FXL6408_REG_PULL_DIR, data); if (rv) return rv; } rv = fxl6408_reg_read(0, FXL6408_REG_I_STATE, &data); if (rv) return rv; data &= egpio_switch[0]; egpio_pinval[EGPIO_CHIP_FXL0] = data; data |= EGPIO_BIT_EVE_INT | EGPIO_BIT_BAT_INT | EGPIO_BIT_CTP_INT; rv = fxl6408_reg_write(0, FXL6408_REG_I_DEFAULT, data); if (rv) return rv; rv = fxl6408_reg_read(0, FXL6408_REG_IO_DIR, &data_dir); if (rv) return rv; rv = fxl6408_reg_read(0, FXL6408_REG_O_STATE, &data); if (rv) return rv; egpio_pinval[EGPIO_CHIP_FXL0] |= (data & data_dir); rv = fxl6408_reg_read(1, FXL6408_REG_I_STATE, &data); if (rv) return rv; data &= egpio_switch[1]; egpio_pinval[EGPIO_CHIP_FXL1] = data; rv = fxl6408_reg_write(1, FXL6408_REG_I_DEFAULT, data); if (rv) return rv; rv = fxl6408_reg_read(1, FXL6408_REG_IO_DIR, &data_dir); if (rv) return rv; rv = fxl6408_reg_read(1, FXL6408_REG_O_STATE, &data); if (rv) return rv; egpio_pinval[EGPIO_CHIP_FXL1] |= (data & data_dir); return EOS_OK; } int eos_egpio_run(void) { uint8_t wakeup_cause, data; int rst, rv; eos_evtq_set_handler(EOS_EVT_EGPIO, handle_evt); GPIO_REG(GPIO_INPUT_EN) |= (1 << EGPIO_PIN_INT); clear_csr(mstatus, MSTATUS_MIE); GPIO_REG(GPIO_LOW_IE) |= (1 << EGPIO_PIN_INT); set_csr(mstatus, MSTATUS_MIE); eos_intr_set(INT_GPIO_BASE + EGPIO_PIN_INT, IRQ_PRIORITY_EGPIO, handle_intr); /* EVE_PIN_INT will be set in intr_set() below */ eos_intr_set(INT_GPIO_BASE + EVE_PIN_INT, IRQ_PRIORITY_EVE, handle_intr_eve); wakeup_cause = eos_pwr_wakeup_cause(); rst = (wakeup_cause == EOS_PWR_WAKE_RST); if (rst) { /* turn on interrupts when all is configured */ data = ~(EGPIO_BIT_SDCARD_DET | EGPIO_BIT_BTN_WAKE | EGPIO_BIT_BAT_INT); rv = fxl6408_reg_write(0, FXL6408_REG_INT_MASK, data); if (rv) return rv; data = ~(EGPIO_BIT_MIC_MUTE | EGPIO_BIT_HP_NDET); rv = fxl6408_reg_write(1, FXL6408_REG_INT_MASK, data); if (rv) return rv; } rv = eos_egpio_intr_set(); if (rv) return rv; return EOS_OK; } void eos_egpio_eve_set(uint16_t gpio_reg) { egpio_pinval[EGPIO_CHIP_EVE] = gpio_reg & 0xff; if (gpio_reg & (1 << EVE_GPIO_DISP)) egpio_pinval[EGPIO_CHIP_EVE] |= EGPIO_PIN2BIT(EGPIO_PIN_DISP_SEL); } int _eos_egpio_intr_set(int i2s_running, int app_disp) { uint8_t data; int rv; rv = fxl6408_reg_read(0, FXL6408_REG_INT_MASK, &data); if (rv) return rv; data &= ~(EGPIO_BIT_EVE_INT | EGPIO_BIT_CTP_INT); if (app_disp) { data |= (EGPIO_BIT_EVE_INT | EGPIO_BIT_CTP_INT); } else if (!i2s_running) { if (eos_egpio_get_val(EGPIO_PIN_CTP_SEL)) { data |= EGPIO_BIT_CTP_INT; } else { data |= EGPIO_BIT_EVE_INT; } } rv = fxl6408_reg_write(0, FXL6408_REG_INT_MASK, data); if (rv) return rv; GPIO_REG(GPIO_INPUT_EN) |= (1 << EVE_PIN_INT); clear_csr(mstatus, MSTATUS_MIE); if (app_disp || i2s_running) { GPIO_REG(GPIO_LOW_IE) &= ~(1 << EVE_PIN_INT); } else { GPIO_REG(GPIO_LOW_IE) |= (1 << EVE_PIN_INT); } set_csr(mstatus, MSTATUS_MIE); return EOS_OK; } int eos_egpio_intr_set(void) { return _eos_egpio_intr_set(eos_i2s_running(), !eos_egpio_get_val(EGPIO_PIN_DISP_SEL)); } int eos_egpio_intr_disable(void) { uint8_t data; int rv; rv = fxl6408_reg_read(0, FXL6408_REG_INT_MASK, &data); if (rv) return rv; data |= (EGPIO_BIT_EVE_INT | EGPIO_BIT_CTP_INT); rv = fxl6408_reg_write(0, FXL6408_REG_INT_MASK, data); if (rv) return rv; clear_csr(mstatus, MSTATUS_MIE); GPIO_REG(GPIO_LOW_IE) &= ~(1 << EVE_PIN_INT); set_csr(mstatus, MSTATUS_MIE); GPIO_REG(GPIO_INPUT_EN) &= ~(1 << EVE_PIN_INT); return EOS_OK; } void eos_egpio_set_intr_handler(eos_egpio_intr_handler_t handler) { egpio_intr_handler = handler; } void eos_egpio_set_ext_handler(eos_egpio_ext_handler_t handler) { egpio_ext_handler = handler; } int eos_egpio_fxl_get_pin(uint8_t reg, uint8_t pin, uint8_t *val) { uint8_t chip_id; int rv; chip_id = EGPIO_PIN2CHIP(pin); pin &= EGPIO_PIN_MASK; rv = fxl6408_get_pin(chip_id, reg, pin, val); return rv; } int eos_egpio_fxl_set_pin(uint8_t reg, uint8_t pin, uint8_t val) { uint8_t chip_id; int rv; chip_id = EGPIO_PIN2CHIP(pin); pin &= EGPIO_PIN_MASK; rv = fxl6408_set_pin(chip_id, reg, pin, val); if (rv) return rv; return EOS_OK; } int _eos_egpio_get_val(uint8_t pin) { uint8_t chip_id; chip_id = EGPIO_PIN2CHIP(pin); return !!(egpio_pinval[chip_id] & EGPIO_PIN2BIT(pin)); } int _eos_egpio_set_val(uint8_t pin, int val) { uint8_t chip_id; int rv; val = !!val; chip_id = EGPIO_PIN2CHIP(pin); pin &= EGPIO_PIN_MASK; if (chip_id == EGPIO_CHIP_EVE) { rv = eve_select(); if (rv) return rv; /* activate if needed */ eve_activate(); if (pin == EGPIOE_PIN_DISP) pin = EVE_GPIO_DISP; eve_gpio_set(pin, val); /* restore previous power state */ eve_deactivate(); eve_deselect(); } else { rv = fxl6408_set_pin(chip_id, FXL6408_REG_O_STATE, pin, val); if (rv) return rv; } BITSET(egpio_pinval[chip_id], EGPIO_PIN2BIT(pin), val); return EOS_OK; } int eos_egpio_get_val(uint8_t pin) { switch (pin) { case EGPIO_PIN_AUDIO_SEL: { if (eos_i2s_running()) { return !!(egpio_alt_pin & pin2alt_bit(pin)); } break; } case EGPIO_PIN_EVEAUDIO_DIS: case EGPIO_PIN_LSGAIN_SEL: { int lspk_on = (eos_i2s_running() || !_eos_egpio_get_val(EGPIO_PIN_AUDIO_SEL)) && eos_egpio_get_val(EGPIO_PIN_HP_NDET); if ((pin == EGPIO_PIN_EVEAUDIO_DIS) && lspk_on) { return !!(egpio_alt_pin & pin2alt_bit(pin)); } if ((pin == EGPIO_PIN_LSGAIN_SEL) && !lspk_on) { return !!(egpio_alt_pin & pin2alt_bit(pin)); } break; } } return _eos_egpio_get_val(pin); } int eos_egpio_set_val(uint8_t pin, int val) { uint8_t chip_id; int rv; val = !!val; switch (pin) { case EGPIO_PIN_CTP_SEL: { if (!eos_egpio_get_val(EGPIO_PIN_DISP_SEL)) { return EOS_ERR_BUSY; } break; } case EGPIO_PIN_AUDIO_SEL: { if (eos_i2s_running()) { BITSET(egpio_alt_pin, pin2alt_bit(pin), val); return EOS_OK; } if ((val != _eos_egpio_get_val(EGPIO_PIN_AUDIO_SEL)) && eos_egpio_get_val(EGPIO_PIN_HP_NDET)) { if (val) { /* store LSGAIN_SEL pin and set EVEAUDIO_DIS pin */ PINSWITCH(EGPIO_PIN_LSGAIN_SEL, EGPIO_PIN_EVEAUDIO_DIS); } else { /* store EVEAUDIO_DIS pin and set LSGAIN_SEL pin */ PINSWITCH(EGPIO_PIN_EVEAUDIO_DIS, EGPIO_PIN_LSGAIN_SEL); } } break; } case EGPIO_PIN_EVEAUDIO_DIS: case EGPIO_PIN_LSGAIN_SEL: { int lspk_on = (eos_i2s_running() || !_eos_egpio_get_val(EGPIO_PIN_AUDIO_SEL)) && eos_egpio_get_val(EGPIO_PIN_HP_NDET); if ((pin == EGPIO_PIN_EVEAUDIO_DIS) && lspk_on) { BITSET(egpio_alt_pin, pin2alt_bit(pin), val); return EOS_OK; } if ((pin == EGPIO_PIN_LSGAIN_SEL) && !lspk_on) { BITSET(egpio_alt_pin, pin2alt_bit(pin), val); return EOS_OK; } break; } } rv = _eos_egpio_set_val(pin, val); if (rv) return rv; return EOS_OK; } int eos_egpio_i2s_start(void) { uint8_t data; int rv, audio_sel; rv = _eos_egpio_intr_set(1, !eos_egpio_get_val(EGPIO_PIN_DISP_SEL)); if (rv) return rv; audio_sel = _eos_egpio_get_val(EGPIO_PIN_AUDIO_SEL); BITSET(egpio_alt_pin, pin2alt_bit(EGPIO_PIN_AUDIO_SEL), audio_sel); rv = _eos_egpio_set_val(EGPIO_PIN_AUDIO_SEL, 1); if (rv) return rv; if (!audio_sel && eos_egpio_get_val(EGPIO_PIN_HP_NDET)) { /* store EVEAUDIO_DIS pin and set LSGAIN_SEL pin */ PINSWITCH(EGPIO_PIN_EVEAUDIO_DIS, EGPIO_PIN_LSGAIN_SEL); } return EOS_OK; } int eos_egpio_i2s_stop(void) { int rv, audio_sel; rv = _eos_egpio_intr_set(0, !eos_egpio_get_val(EGPIO_PIN_DISP_SEL)); if (rv) return rv; audio_sel = (egpio_alt_pin & pin2alt_bit(EGPIO_PIN_AUDIO_SEL)); if (!audio_sel && eos_egpio_get_val(EGPIO_PIN_HP_NDET)) { /* store LSGAIN_SEL pin and set EVEAUDIO_DIS pin */ PINSWITCH(EGPIO_PIN_LSGAIN_SEL, EGPIO_PIN_EVEAUDIO_DIS); } rv = _eos_egpio_set_val(EGPIO_PIN_AUDIO_SEL, audio_sel); if (rv) return rv; return EOS_OK; }