/* * Tfa9890_DspSystemStable will compensate for the wrong behavior of CLKS * to determine if the DSP subsystem is ready for patch and config loading. * * A MTP calibration register is checked for non-zero. * * Note: This only works after i2c reset as this will clear the MTP contents. * When we are configured then the DSP communication will synchronize access. * */ enum Tfa98xx_Error Tfa9890_DspSystemStable(Tfa98xx_handle_t handle, int *ready) { enum Tfa98xx_Error error; unsigned short status, mtp0; int tries; /* check the contents of the STATUS register */ error = Tfa98xx_ReadRegister16(handle, TFA98XX_STATUSREG, &status); if (error) goto errorExit; /* if AMPS is set then we were already configured and running * no need to check further */ *ready = (status & TFA98XX_STATUSREG_AMPS_MSK) == (TFA98XX_STATUSREG_AMPS_MSK); if (*ready) /* if ready go back */ return error; /* will be Tfa98xx_Error_Ok */ /* check AREFS and CLKS: not ready if either is clear */ *ready = (status & (TFA98XX_STATUSREG_AREFS_MSK | TFA98XX_STATUSREG_CLKS_MSK)) == (TFA98XX_STATUSREG_AREFS_MSK | TFA98XX_STATUSREG_CLKS_MSK); if (!*ready) /* if not ready go back */ return error; /* will be Tfa98xx_Error_Ok */ /* check MTPB * mtpbusy will be active when the subsys copies MTP to I2C * 2 times retry avoids catching this short mtpbusy active period */ for (tries = 2; tries > 0; tries--) { error = Tfa98xx_ReadRegister16(handle, TFA98XX_STATUSREG, &status); if (error) goto errorExit; /* check the contents of the STATUS register */ *ready = (status & TFA98XX_STATUSREG_MTPB_MSK) == 0; if (*ready) /* if ready go on */ break; } if (tries == 0) /* ready will be 0 if retries exausted */ return Tfa98xx_Error_Ok; /* check the contents of MTP register for non-zero, * this indicates that the subsys is ready */ error = Tfa98xx_ReadRegister16(handle, 0x84, &mtp0); if (error) goto errorExit; *ready = (mtp0 != 0); /* The MTP register written? */ return error; errorExit: *ready = 0; _ASSERT(error); /* an error here can be considered to be fatal */ return error; }
Tfa98xx_Error_t Tfa9890_DspReset(Tfa98xx_handle_t handle, int state) { Tfa98xx_Error_t error; unsigned short value49, value; /* for TFA9890 temporarily disable clock gating when dsp reset is used */ error = Tfa98xx_ReadRegister16(handle, TFA98XX_CURRENTSENSE4, &value49); if (error) return error; if (Tfa98xx_Error_Ok == error) { /* clock gating off */ value = value49 | TFA98XX_CURRENTSENSE4_CTRL_CLKGATECFOFF; // set the bit error = Tfa98xx_WriteRegister16(handle, TFA98XX_CURRENTSENSE4, value); if (error) return error; } error = Tfa98xx_ReadRegister16(handle, TFA98XX_CF_CONTROLS, &value); if (error) return error; /* set requested the DSP reset signal state */ value = state ? (value | TFA98XX_CF_CONTROLS_RST_MSK) : (value & ~TFA98XX_CF_CONTROLS_RST_MSK); error = Tfa98xx_WriteRegister16(handle, TFA98XX_CF_CONTROLS, value); /* clock gating restore */ error = Tfa98xx_WriteRegister16(handle, 0x49, value49);/* clock gating restore */ return error; }
/* * write/read test of a register that has no risk of causing damage * return code: * 2 : write value wrong * */ int tfa98xxDiagI2cRw(int slave) { Tfa98xx_handle_t handle; int testregoffset, result = 0; // 1 is failure unsigned short testreg; TRACEIN; lastApiError = Tfa98xx_Open(slave << 1, &handle); if (lastApiError != Tfa98xx_Error_Ok) return 1; // get the index of the testreg for ( testregoffset = 0; testregoffset < MAXREGS; testregoffset++) { if (regdefs[ testregoffset].offset == RWTEST_REG) break; } // powerdown to avoid side effects lastApiError = Tfa98xx_Powerdown(handle, 1); assert(lastApiError == Tfa98xx_Error_Ok); // check pwron default first lastApiError = Tfa98xx_ReadRegister16(handle, RWTEST_REG, &testreg); // assert(lastApiError == Tfa98xx_Error_Ok); if (regdefs[ testregoffset].pwronDefault != (testreg & regdefs[ testregoffset].pwronTestmask)) { sprintf(lastErrorString, "poweron default wrong: %s (0x%02x), exp:0x%04x rcv:0x%04x\n", regdefs[ testregoffset].name, regdefs[ testregoffset].offset, regdefs[ testregoffset].pwronDefault, testreg); result = 2; goto stop; } // write 0x1234 lastApiError = Tfa98xx_WriteRegister16(handle, RWTEST_REG, 0x1234); // assert(lastApiError == Tfa98xx_Error_Ok); lastApiError = Tfa98xx_ReadRegister16(handle, RWTEST_REG, &testreg); // assert(lastApiError == Tfa98xx_Error_Ok); // restore default, else pwrdefault may fail lastApiError = Tfa98xx_WriteRegister16(handle, RWTEST_REG, regdefs[RWTEST_REG].pwronDefault); // assert(lastApiError == Tfa98xx_Error_Ok); if (0x1234 != testreg) { sprintf(lastErrorString, "read back value mismatch: (testreg=0x%02x), exp:0x%04x rcv:0x%04x\n", RWTEST_REG, 0x1234, testreg); result = 1; } stop: Tfa98xx_Close(handle); lastError = result; TRACEOUT; return result; }
static void waitCalibration(Tfa98xx_handle_t handle, int *calibrateDone) { enum Tfa98xx_Error err; int tries = 0; unsigned short mtp; unsigned short spkrCalibration; #define WAIT_TRIES 1000 err = Tfa98xx_ReadRegister16(handle, TFA98XX_MTP, &mtp); /* in case of calibrate once wait for MTPEX */ if (mtp & TFA98XX_MTP_MTPOTC) { while ((*calibrateDone == 0) && (tries < WAIT_TRIES)) { err = Tfa98xx_ReadRegister16(handle, TFA98XX_MTP, &mtp); /* check MTP bit1 (MTPEX) */ *calibrateDone = (mtp & TFA98XX_MTP_MTPEX); tries++; } } else { /* poll xmem for calibrate always */ while ((*calibrateDone == 0) && (tries < WAIT_TRIES)) { /* TODO optimise with wait estimation */ err = Tfa98xx_DspReadMem(handle, 231, 1, calibrateDone); tries++; } if (tries == WAIT_TRIES) pr_err("%s: calibrateDone 231 timedout\n", __func__); } err = Tfa98xx_ReadRegister16(handle, TFA98XX_SPKR_CALIBRATION, &spkrCalibration); if (err != Tfa98xx_Error_Ok) { pr_err("%s: Tfa98xx_ReadRegister16 failed %d\n", __func__, err); return; } spkrCalibration &= ~(TFA98XX_SPKR_CALIBRATION_TROS_MSK); err = Tfa98xx_WriteRegister16(handle, TFA98XX_SPKR_CALIBRATION, spkrCalibration); if (err != Tfa98xx_Error_Ok) { pr_err("%s: Tfa98xx_WriteRegister16 failed %d\n", __func__, err); return; } }
/* * dump all known registers * returns: * 0 if slave can't be opened * nr of registers displayed */ int tfa98xxDiagRegisterDump(int slave) { Tfa98xx_handle_t handle; int i; unsigned short regval; unsigned char reg; TRACEIN; lastApiError = Tfa98xx_Open(slave << 1, &handle); if (lastApiError != Tfa98xx_Error_Ok) return 0; for (i = 0; i < MAXREGS; i++) { lastApiError = Tfa98xx_ReadRegister16(handle, regdefs[i].offset, ®val); assert(lastApiError == Tfa98xx_Error_Ok); printf("0x%02x: 0x%04x (%s)\n", regdefs[i].offset, regval, regdefs[i].name); } Tfa98xx_Close(handle); TRACEOUT; return i; }
static void change_stereo_speaker_lr(int speaker_lr) { enum Tfa98xx_Error err; unsigned int h; unsigned short status = 0; int timeout; pr_info("%s\n", __func__); for (h = 0; h < 2; h++) { err = Tfa98xx_SetMute(handles[h], Tfa98xx_Mute_Amplifier); if (err != Tfa98xx_Error_Ok) pr_err("%s: Tfa98xx_SetMute failed, h=%d\n", __func__, h); msleep(33); err = Tfa98xx_ReadRegister16( handles[h], TFA98XX_STATUSREG, &status); if (err != Tfa98xx_Error_Ok) pr_err("%s: Tfa98xx_ReadRegister16 failed, h=%d\n", __func__, h); timeout = 0; while ((status & TFA98XX_STATUSREG_SWS_MSK) == TFA98XX_STATUSREG_SWS_MSK) { err = Tfa98xx_ReadRegister16(handles[h], TFA98XX_STATUSREG, &status); if (err != Tfa98xx_Error_Ok) pr_err("%s: Tfa98xx_ReadRegister16 failed,"\ " h=%d\n", __func__, h); timeout++; if (timeout > 50) { pr_info("%s timeout SWS checking:%d\n", __func__, status); break; } } } set_speaker_lr(handles, speaker_lr); for (h = 0; h < 2; h++) { err = Tfa98xx_SetMute(handles[h], Tfa98xx_Mute_Off); if (err != Tfa98xx_Error_Ok) pr_err("%s: Tfa98xx_SetMute failed, h=%d\n", __func__, h); } speaker_lr_now = speaker_lr; }
static void stereo_speaker_off(void) { enum Tfa98xx_Error err; unsigned int h; unsigned short status = 0; int timeout; pr_info("%s\n", __func__); for (h = 0; h < 2; h++) { err = Tfa98xx_SetMute(handles[h], Tfa98xx_Mute_Amplifier); if (err != Tfa98xx_Error_Ok) pr_err("%s: Tfa98xx_SetMute failed, h=%d\n", __func__, h); msleep(33); /* NXP SL: Added checking if amplifier is still switching or not to avoid pop sound */ /* now wait for the amplifier to turn off */ err = Tfa98xx_ReadRegister16( handles[h], TFA98XX_STATUSREG, &status); if (err != Tfa98xx_Error_Ok) pr_err("%s: Tfa98xx_ReadRegister16 failed, h=%d\n", __func__, h); timeout = 0; while ((status & TFA98XX_STATUSREG_SWS_MSK) == TFA98XX_STATUSREG_SWS_MSK) { err = Tfa98xx_ReadRegister16(handles[h], TFA98XX_STATUSREG, &status); if (err != Tfa98xx_Error_Ok) pr_err("%s: Tfa98xx_ReadRegister16 failed,"\ " h=%d\n", __func__, h); timeout++; if (timeout > 50) { pr_info("%s timeout SWS checking:%d\n", __func__, status); break; } } err = Tfa98xx_Powerdown(handles[h], 1); if (err != Tfa98xx_Error_Ok) pr_err("%s: Tfa98xx_Powerdown failed, h=%d\n", __func__, h); } }
/* * check battery level to be above 2Volts * * */ int tfa98xxDiagBattery(int slave) { Tfa98xx_handle_t handle; int result = 0; // 1 is failure unsigned short reg; TRACEIN; lastApiError = Tfa98xx_Open(slave << 1, &handle); if (lastApiError != Tfa98xx_Error_Ok) return 4; // enable the clock in bypass mode // 48 kHz left channel I2S with coolflux in Bypass lastApiError = Tfa98xx_WriteRegister16(handle, TFA98XX_I2SREG, 0x880b); // assert(lastApiError == Tfa98xx_Error_Ok); // PLL=BCK, input 1, power off lastApiError = Tfa98xx_WriteRegister16(handle, TFA98XX_SYS_CTRL, 0x0219); // assert(lastApiError == Tfa98xx_Error_Ok); // 1.0 uF coil, PLL=BCK, input 1, power on lastApiError = Tfa98xx_WriteRegister16(handle, TFA98XX_SYS_CTRL, 0x0618); // assert(lastApiError == Tfa98xx_Error_Ok); // check if clocks are stable and running // give it some time usleep(14000); // 14ms good for all rates // expect: 0x00 : 0xd85f if (tfa98xxDiagStatus (handle, 0, TFA98XX_STATUS_PLLS | TFA98XX_STATUS_CLKS)) { sprintf(lastErrorString, "clock not running"); result = 2; // fail if any of these is clear goto stop; } // check battery level lastApiError = Tfa98xx_ReadRegister16(handle, TFA98XX_BATTERYVOLTAGE, ®); assert(lastApiError == Tfa98xx_Error_Ok); // 2V: 2/(5.5/1024)=372 if (reg < 372) { sprintf(lastErrorString, "battery level too low: exp > 2.0V, rcv=%2.2f", reg * (5.5 / 1024)); result = 1; goto stop; } // any other errors if (tfa98xxDiagStatus (handle, TFA98XX_STATUS_ERRORS_SET_MSK, TFA98XX_STATUS_ERRORS_CLR_MSK)) { sprintf(lastErrorString, "status errorbit active"); result = 3; } stop: Tfa98xx_Close(handle); lastError = result; TRACEOUT; return result; }
Tfa98xx_Error_t Tfa9890_specific(Tfa98xx_handle_t handle) { Tfa98xx_Error_t error = Tfa98xx_Error_Ok; unsigned short value; ALOGD("[%s][%s] 2", __FILE__, __func__); if (!handle_is_open(handle)) return Tfa98xx_Error_NotOpen; /* reset all i2C registers to default */ error = Tfa98xx_WriteRegister16(handle, 0x09, 0x0002); if (Tfa98xx_Error_Ok == error) { error = Tfa98xx_ReadRegister16(handle, 0x09, &value); } if (Tfa98xx_Error_Ok == error) { /* DSP must be in control of the amplifier to avoid plops */ value |= TFA98XX_SYS_CTRL_AMPE_POS; error = Tfa98xx_WriteRegister16(handle, 0x09, value); } /* some other registers must be set for optimal amplifier behaviour */ if (Tfa98xx_Error_Ok == error) { error = Tfa98xx_WriteRegister16(handle, 0x06, 0x000F); // not for n1c } if (Tfa98xx_Error_Ok == error) { error = Tfa98xx_WriteRegister16(handle, 0x07, 0x8FFF); // not for n1c } if (Tfa98xx_Error_Ok == error) { error = Tfa98xx_WriteRegister16(handle, 0x08, 0x7832); // change for n1c } if (Tfa98xx_Error_Ok == error) { error = Tfa98xx_WriteRegister16(handle, 0x09, 0x824D); } if (Tfa98xx_Error_Ok == error) { error = Tfa98xx_WriteRegister16(handle, 0x0A, 0x38E5); // not for n1c } if (Tfa98xx_Error_Ok == error) { error = Tfa98xx_WriteRegister16(handle, 0x0E, 0x0F01);// not for n1c } if (Tfa98xx_Error_Ok == error) { error = Tfa98xx_WriteRegister16(handle, 0x46, 0x4000);// not for n1c } if (Tfa98xx_Error_Ok == error) { error = Tfa98xx_WriteRegister16(handle, 0x47, 0x5901); } if (Tfa98xx_Error_Ok == error) { error = Tfa98xx_WriteRegister16(handle, 0x48, 0x06C0); } if (Tfa98xx_Error_Ok == error) { error = Tfa98xx_WriteRegister16(handle, 0x49, 0xAD93); } return error; }
/* * assume I2S input and verify signal activity */ int tfa98xxDiagI2sInput(int slave) { { Tfa98xx_handle_t handle; int result; Tfa98xx_StateInfo_t stateInfo; unsigned short sysctrlReg; TRACEIN; lastApiError = Tfa98xx_Open(slave << 1, &handle); if (lastApiError != Tfa98xx_Error_Ok) return 3; gHandle = handle; // global prevents reopen result = tfa98xxDiagLoadSpeaker(slave); if (result) { result = 2; goto stop; } lastApiError = Tfa98xx_SetConfigured(handle); assert(lastApiError == Tfa98xx_Error_Ok); //select channel lastApiError = Tfa98xx_ReadRegister16(handle, 0x09, &sysctrlReg); assert(lastApiError == Tfa98xx_Error_Ok); lastApiError = Tfa98xx_WriteRegister16(handle, 0x09, sysctrlReg & ~(0x1 << 13)); // input 1 // lastApiError = Tfa98xx_WriteRegister16(handle, 0x09, sysctrlReg | (0x1<<13)); // input 2 assert(lastApiError == Tfa98xx_Error_Ok); lastApiError = Tfa98xx_DspGetStateInfo(handle, &stateInfo); assert(lastApiError == Tfa98xx_Error_Ok); // check for activity if ((stateInfo.statusFlag & (1 << Tfa98xx_SpeakerBoost_Activity)) == 0) { sprintf(lastErrorString, "no audio active on input"); result = 1; } else result = 0; stop: Tfa98xx_Close(handle); lastError = result; gHandle = -1; TRACEOUT; return result; } }
/* * Unbypassed the DSP */ static int tfa98xx_unbypass_dsp(Tfa98xx_handle_t handleIn) { enum Tfa98xx_Error err = Tfa98xx_Error_Other; unsigned short i2SRead = 0; unsigned short sysRead = 0; unsigned short sysCtrlRead = 0; unsigned short batProtRead = 0; if (handleIn == -1) return err; /* basic settings for quickset */ err = Tfa98xx_ReadRegister16(handleIn, TFA98XX_I2SREG, &i2SRead); err = Tfa98xx_ReadRegister16(handleIn, TFA98XX_I2S_SEL_REG, &sysRead); err = Tfa98xx_ReadRegister16(handleIn, TFA98XX_SYS_CTRL, &sysCtrlRead); err = Tfa98xx_ReadRegister16(handleIn, TFA98XX_BAT_PROT, &batProtRead); i2SRead |= TFA98XX_I2SREG_CHSA; /* Set CHSA to Unbypass DSP */ sysRead |= TFA9890_I2S_SEL_REG_POR;/* Set I2S SEL REG to set DCDC compensation to default 100%*/ sysRead &= ~(TFA98XX_I2S_SEL_REG_SPKR_MSK);/*Set impedance to be defined by DSP */ sysCtrlRead |= TFA98XX_SYS_CTRL_DCA_MSK;/* Set DCDC to active mode*/ sysCtrlRead |= TFA98XX_SYS_CTRL_CFE_MSK;/* Enable Coolflux */ batProtRead &= ~(TFA989X_BAT_PROT_BSSBY_MSK);/*Set clipper active */ /* Set CHSA to Unbypass DSP */ err = Tfa98xx_WriteRegister16(handleIn, TFA98XX_I2SREG, i2SRead); /* Set I2S SEL REG to set DCDC compensation to default 100% and Set impedance to be defined by DSP */ err = Tfa98xx_WriteRegister16(handleIn, TFA98XX_I2S_SEL_REG, sysRead); /* Set DCDC to active mode and enable Coolflux */ err = Tfa98xx_WriteRegister16(handleIn, TFA98XX_SYS_CTRL, sysCtrlRead); /* Set bypass clipper battery protection */ err = Tfa98xx_WriteRegister16(handleIn, TFA98XX_BAT_PROT, batProtRead); return err; }
void read_tfa98xx_id(int *id) { Tfa98xx_handle_t handle; int err; /* create handle */ err = Tfa98xx_Open(I2C_ADDRESS, &handle); if(err != Tfa98xx_Error_Ok) { ALOGE("[%s] Tfa98xx_Open failed! err = %d, I2C_ADDRESS = %#x", __func__, err,I2C_ADDRESS); } err = Tfa98xx_ReadRegister16(handle, TFA98XX_REVISIONNUMBER, id); ALOGD("TFA98xx ID=%#x",*id); err = Tfa98xx_Close(handle); }
/* * Bypass DSP handling */ static int tfa98xx_bypass_dsp(Tfa98xx_handle_t handleIn) { enum Tfa98xx_Error err = Tfa98xx_Error_Other; unsigned short i2SRead = 0; unsigned short sysRead = 0; unsigned short sysCtrlRead = 0; unsigned short batProtRead = 0; if (handleIn == -1) return err; err = Tfa98xx_ReadRegister16(handleIn, TFA98XX_I2SREG, &i2SRead); err = Tfa98xx_ReadRegister16(handleIn, TFA98XX_I2S_SEL_REG, &sysRead); err = Tfa98xx_ReadRegister16(handleIn, TFA98XX_SYS_CTRL, &sysCtrlRead); err = Tfa98xx_ReadRegister16(handleIn, TFA98XX_BAT_PROT, &batProtRead); i2SRead &= ~(TFA98XX_I2SREG_CHSA_MSK); /* Set CHSA to bypass DSP */ sysRead &= ~(TFA98XX_I2S_SEL_REG_DCFG_MSK);/* Set DCDC compensation to off */ sysRead |= TFA98XX_I2S_SEL_REG_SPKR_MSK; /* Set impedance as 8ohm */ sysCtrlRead &= ~(TFA98XX_SYS_CTRL_DCA_MSK);/* Set DCDC to follower mode */ sysCtrlRead &= ~(TFA98XX_SYS_CTRL_CFE_MSK);/* Disable coolflux */ batProtRead |= TFA989X_BAT_PROT_BSSBY_MSK;/* Set clipper bypassed */ /* Set CHSA to bypass DSP */ err = Tfa98xx_WriteRegister16(handleIn, TFA98XX_I2SREG, i2SRead); /* Set DCDC compensation to off and set impedance as 8ohm */ err = Tfa98xx_WriteRegister16(handleIn, TFA98XX_I2S_SEL_REG, sysRead); /* Set DCDC to follower mode and disable coolflux */ err = Tfa98xx_WriteRegister16(handleIn, TFA98XX_SYS_CTRL, sysCtrlRead); /* Set bypass clipper battery protection */ err = Tfa98xx_WriteRegister16(handleIn, TFA98XX_BAT_PROT, batProtRead); return err; }
static int checkMTPEX(Tfa98xx_handle_t handle) { unsigned short mtp; enum Tfa98xx_Error err; err = Tfa98xx_ReadRegister16(handle, TFA98XX_MTP, &mtp); if (err != Tfa98xx_Error_Ok) { pr_err("%s: Tfa98xx_ReadRegister16 failed %d\n", __func__, err); } if (mtp & (1<<1)) /* check MTP bit1 (MTPEX) */ return 1; /* MTPEX is 1, calibration is done */ else return 0; /* MTPEX is 0, calibration is not done yet */ }
/* * check status register flags for any of the error bits set * return 0 if ok * 1 if not ok * other internal errors */ int tfa98xxDiagStatus(Tfa98xx_handle_t handle, unsigned short setmask, unsigned short clearmask) { int result = 0; // 1 is failure unsigned short statusreg; TRACEIN; lastApiError = Tfa98xx_ReadRegister16(handle, TFA98XX_STATUSREG, &statusreg); assert(lastApiError == Tfa98xx_Error_Ok); if ((statusreg & setmask)) /* check for any of these bits set */ return 1; if ((~statusreg & clearmask)) /* check for any of these bits clear */ return 1; lastError = result; TRACEOUT; return result; }
/* * verify default state of relevant registers */ int tfa98xxDiagRegisterDefaults(int slave) { Tfa98xx_handle_t handle; int i, result = 0; // 1 is failure unsigned short regval; unsigned char reg; TRACEIN; lastApiError = Tfa98xx_Open(slave << 1, &handle); if (lastApiError != Tfa98xx_Error_Ok) return 2; for (i = 0; i < MAXREGS; i++) { if (regdefs[i].pwronTestmask == 0) continue; lastApiError = Tfa98xx_ReadRegister16(handle, regdefs[i].offset, ®val); assert(lastApiError == Tfa98xx_Error_Ok); if (regdefs[i].pwronDefault != (regval & regdefs[i].pwronTestmask)) { sprintf(lastErrorString, "poweron default wrong: %s (0x%02x), exp:0x%04x rcv:0x%04x\n", regdefs[i].name, regdefs[i].offset, regdefs[i].pwronDefault, regval); result++; } } // set DC-DC peak protection bit lastApiError = Tfa98xx_WriteRegister16(handle, TFA98XX_SPKR_CALIBRATION, 0x0c00); // assert(lastApiError == Tfa98xx_Error_Ok); stop: Tfa98xx_Close(handle); lastError = result; TRACEOUT; return result; }
/* * check status register flags and assume coldstart (or fail) * return code: * 1 : error bit * 2 : not cold powered on * other internal errors */ int tfa98xxDiagStatusCold(int slave) { Tfa98xx_handle_t handle; int result = 0; // 1 is failure unsigned short statusreg; TRACEIN; lastApiError = Tfa98xx_Open(slave << 1, &handle); if (lastApiError != Tfa98xx_Error_Ok) { return 3; } lastApiError = Tfa98xx_ReadRegister16(handle, TFA98XX_STATUSREG, &statusreg); assert(lastApiError == Tfa98xx_Error_Ok); if (!(statusreg & TFA98XX_STATUS_ACS)) { /* ensure cold booted */ sprintf(lastErrorString, "not a cold start"); result = 2; goto stop; } if (tfa98xxDiagStatus (handle, TFA98XX_STATUS_ERRORS_SET_MSK, TFA98XX_STATUS_ERRORS_CLR_MSK)) { sprintf(lastErrorString, "status errorbit active"); result = 1; } stop: Tfa98xx_Close(handle); lastError = result; TRACEOUT; return result; }
static int tfa98xx_enable(void) { int ret = 0; enum Tfa98xx_Error err; unsigned short status1 = 0; unsigned short status2 = 0; bool cold_start = false; struct tfa98xx_param_data *preset_ptr[2] = {NULL, NULL}; struct tfa98xx_param_data *config_ptr[2] = {NULL, NULL}; struct tfa98xx_param_data *speaker_ptr[2] = {NULL, NULL}; struct tfa98xx_param_data *eq_ptr[2] = {NULL, NULL}; if (speaker_type >= 0 && speaker_type <= SPEAKER_TYPE_VOICECALL && speaker_channel >= 0 && speaker_channel <= SPEAKER_CHANNEL_BOTH && speaker_lr >= 0 && speaker_lr <= SPEAKER_LR_SWAP) pr_info("%s type:%s channel:%s lr:%s\n", __func__, speaker_type_text[speaker_type], speaker_channel_text[speaker_channel], speaker_lr_text[speaker_lr]); else pr_info("%s type:%d channel:%d lr:%d\n", __func__, speaker_type, speaker_channel, speaker_lr); if (speaker_type_now != speaker_type || speaker_channel_now != speaker_channel) { tfa98xx_disable(); cold_start = true; } speaker_ptr[TOP] = &speaker_data[AMP_TOP]; speaker_ptr[BOTTOM] = &speaker_data[AMP_BOTTOM]; config_ptr[TOP] = &config_data[AMP_TOP]; config_ptr[BOTTOM] = &config_data[AMP_BOTTOM]; if (speaker_type >= 0 && speaker_type < SPEAKER_TYPE_MAX) { preset_ptr[TOP] = preset_data_table[speaker_type][TOP]; preset_ptr[BOTTOM] = preset_data_table[speaker_type][BOTTOM]; eq_ptr[TOP] = eql_data_table[speaker_type][TOP]; eq_ptr[BOTTOM] = eql_data_table[speaker_type][BOTTOM]; } else { pr_err("%s: Invalid speaker type:%x", __func__, speaker_type); return -EINVAL; } if (speaker_bypass_dsp == SPEAKER_BYPASS_DSP_ON) { if (speaker_channel == SPEAKER_CHANNEL_TOP || speaker_channel == SPEAKER_CHANNEL_BOTH) { err = bypass_dsp_speaker_on(TOP); if (err != Tfa98xx_Error_Ok) { pr_err("%s: bypass_speaker_on failed %d\n", __func__, err); } } if (speaker_channel == SPEAKER_CHANNEL_BOTTOM || speaker_channel == SPEAKER_CHANNEL_BOTH) { err = bypass_dsp_speaker_on(BOTTOM); if (err != Tfa98xx_Error_Ok) { pr_err("%s: bypass_speaker_on failed %d\n", __func__, err); } } } else if (speaker_channel == SPEAKER_CHANNEL_TOP) { if (preset_ptr[TOP] == NULL) { pr_err("%s: Invalid speaker type:%x channel:%d", __func__, speaker_type, speaker_channel); return -EINVAL; } err = Tfa98xx_ReadRegister16( handles[TOP], TFA98XX_STATUSREG, &status1); if (err != Tfa98xx_Error_Ok) { pr_err("%s: Tfa98xx_ReadRegister16 failed %d\n", __func__, err); } if (cold_start || (status1 & TFA98XX_STATUSREG_ACS_MSK) != 0) { pr_info("cold start %04x\n", status1); ret = mono_speaker_on( TOP, speaker_ptr[TOP], config_ptr[TOP], preset_ptr[TOP], eq_ptr[TOP]); } else { pr_info("warm start %04x\n", status1); ret = mono_speaker_warm_on(TOP); } } else if (speaker_channel == SPEAKER_CHANNEL_BOTTOM) { if (preset_ptr[BOTTOM] == NULL) { pr_err("%s: Invalid speaker type:%x channel:%d", __func__, speaker_type, speaker_channel); return -EINVAL; } err = Tfa98xx_ReadRegister16( handles[BOTTOM], TFA98XX_STATUSREG, &status1); if (err != Tfa98xx_Error_Ok) { pr_err("%s: Tfa98xx_ReadRegister16 failed %d\n", __func__, err); } if (cold_start || (status1 & TFA98XX_STATUSREG_ACS_MSK) != 0) { pr_info("cold start %04x\n", status1); ret = mono_speaker_on( BOTTOM, speaker_ptr[BOTTOM], config_ptr[BOTTOM], preset_ptr[BOTTOM], eq_ptr[BOTTOM]); } else { pr_info("warm start %04x\n", status1); ret = mono_speaker_warm_on(BOTTOM); } } else if (speaker_channel == SPEAKER_CHANNEL_BOTH) { if (preset_ptr[TOP] == NULL || preset_ptr[BOTTOM] == NULL) { pr_err("%s: Invalid speaker type:%x channel:%d", __func__, speaker_type, speaker_channel); return -EINVAL; } err = Tfa98xx_ReadRegister16( handles[TOP], TFA98XX_STATUSREG, &status1); if (err != Tfa98xx_Error_Ok) { pr_err("%s: Tfa98xx_ReadRegister16 failed %d\n", __func__, err); } err = Tfa98xx_ReadRegister16( handles[BOTTOM], TFA98XX_STATUSREG, &status2); if (err != Tfa98xx_Error_Ok) { pr_err("%s: Tfa98xx_ReadRegister16 failed %d\n", __func__, err); } if (cold_start || (status1 & TFA98XX_STATUSREG_ACS_MSK) != 0 || (status2 & TFA98XX_STATUSREG_ACS_MSK) != 0) { pr_info("cold start %04x %04x\n", status1, status2); ret = stereo_speaker_on( speaker_ptr, config_ptr, preset_ptr, eq_ptr); } else if (speaker_lr != speaker_lr_now) { pr_info("speaker LR change %d\n", speaker_lr); ret = set_speaker_lr(handles, speaker_lr); ret = stereo_speaker_warm_on(); } else { pr_info("warm start %04x %04x\n", status1, status2); ret = stereo_speaker_warm_on(); } } speaker_type_now = speaker_type; speaker_channel_now = speaker_channel; speaker_lr_now = speaker_lr; speaker_bypass_dsp_now = speaker_bypass_dsp; speaker_synced_now = speaker_synced; return ret; }
static void coldStartup(Tfa98xx_handle_t handle) { enum Tfa98xx_Error err; unsigned short status; int ready = 0; int timeout; unsigned short dcdcRead = 0; unsigned short dcdcBoost = 0; /* load the optimal TFA98xx in HW settings */ err = Tfa98xx_Init(handle); if (err != Tfa98xx_Error_Ok) { pr_err("%s: Tfa98xx_Init failed %d\n", __func__, err); return; } /* NXP SL: Sample rate should be set before power up */ /* Set sample rate to example 48000*/ err = Tfa98xx_SetSampleRate(handle, SAMPLE_RATE); if (err != Tfa98xx_Error_Ok) pr_err("%s: Tfa98xx_SetSampleRate failed %d\n", __func__, err); /* Power On the device by setting bit 0 to 0 of register 9*/ err = Tfa98xx_Powerdown(handle, 0); if (err != Tfa98xx_Error_Ok) { pr_err("%s: Tfa98xx_Powerdown failed %d\n", __func__, err); return; } /* set Max boost coil current 1.92 A */ err = Tfa98xx_ReadRegister16(handle, TFA98XX_DCDCBOOST, &dcdcRead); dcdcRead &= ~(TFA98XX_DCDCBOOST_DCMCC_MSK); dcdcRead |= (3 << TFA98XX_DCDCBOOST_DCMCC_POS); err = Tfa98xx_WriteRegister16(handle, TFA98XX_DCDCBOOST, dcdcRead); /* set Max boost voltage 7.5 V */ err = Tfa98xx_ReadRegister16(handle, TFA98XX_DCDCBOOST, &dcdcBoost); dcdcBoost &= ~(TFA98XX_DCDCBOOST_DCVO_MSK); dcdcBoost |= 3; err = Tfa98xx_WriteRegister16(handle, TFA98XX_DCDCBOOST, dcdcBoost); /* Check the PLL is powered up from status register 0*/ err = Tfa98xx_ReadRegister16(handle, TFA98XX_STATUSREG, &status); if (err != Tfa98xx_Error_Ok) { pr_err("%s: Tfa98xx_ReadRegister16 failed %d\n", __func__, err); return; } timeout = 0; while ((status & TFA98XX_STATUSREG_AREFS_MSK) == 0) { /* not ok yet */ err = Tfa98xx_ReadRegister16(handle, TFA98XX_STATUSREG, &status); if (err != Tfa98xx_Error_Ok) { pr_err("%s: Tfa98xx_ReadRegister16 failed %d\n", __func__, err); return; } msleep(20); timeout++; if (timeout > 50) { pr_info("%s timeout status:%x\n", __func__, status); break; } } /* powered on * - now it is allowed to access DSP specifics * - stall DSP by setting reset * */ err = Tfa98xx_DspReset(handle, 1); if (err != Tfa98xx_Error_Ok) { pr_err("%s: Tfa98xx_DspReset failed %d\n", __func__, err); return; } /* wait until the DSP subsystem hardware is ready * note that the DSP CPU is not running yet (RST=1) * */ timeout = 0; while (ready == 0) { /* are we ready? */ err = Tfa98xx_DspSystemStable(handle, &ready); if (err != Tfa98xx_Error_Ok) { pr_err("%s: Tfa98xx_DspSystemStable failed %d\n", __func__, err); return; } msleep(20); timeout++; if (timeout > 50) { pr_info("%s timeout ready:%d\n", __func__, ready); break; } } /* Load cold-boot patch for the first time to force cold start-up. * use the patchload only to write the internal register * */ dspPatch(handle, &patch_data[PATCH_COLDBOOT]); err = Tfa98xx_ReadRegister16(handle, TFA98XX_STATUSREG, &status); if (err != Tfa98xx_Error_Ok) { pr_err("%s: Tfa98xx_ReadRegister16 failed %d\n", __func__, err); return; } if ((status & TFA98XX_STATUSREG_ACS_MSK) == 0) { pr_err("%s: status & TFA98XX_STATUSREG_ACS_MSK == 0\n", __func__); return; } /* cold boot, need to load all parameters and patches */ /* patch the ROM code */ dspPatch(handle, &patch_data[PATCH_DSP]); }
static void setOtc(Tfa98xx_handle_t handle, int otcOn) { enum Tfa98xx_Error err; unsigned short mtp; unsigned short status; unsigned short spkrCalibration; int mtpChanged = 0; int timeout; err = Tfa98xx_ReadRegister16(handle, TFA98XX_SPKR_CALIBRATION, &spkrCalibration); if (err != Tfa98xx_Error_Ok) { pr_err("%s: Tfa98xx_ReadRegister16 failed %d\n", __func__, err); return; } spkrCalibration |= TFA98XX_SPKR_CALIBRATION_TROS_MSK; spkrCalibration &= ~(TFA98XX_SPKR_CALIBRATION_EXTTS_MSK); spkrCalibration |= (SPKR_CALIBRATION_EXTTS_VALUE << TFA98XX_SPKR_CALIBRATION_EXTTS_POS); err = Tfa98xx_WriteRegister16(handle, TFA98XX_SPKR_CALIBRATION, spkrCalibration); if (err != Tfa98xx_Error_Ok) { pr_err("%s: Tfa98xx_WriteRegister16 failed %d\n", __func__, err); return; } err = Tfa98xx_ReadRegister16(handle, TFA98XX_MTP, &mtp); if (err != Tfa98xx_Error_Ok) { pr_err("%s: Tfa98xx_DspReset failed %d\n", __func__, err); return; } if ((otcOn != 0) && (otcOn != 1)) { pr_err("%s: Tfa98xx_ReadRegister16 failed %d\n", __func__, err); return; } /* set reset MTPEX bit if needed */ if ((mtp & TFA98XX_MTP_MTPOTC) != otcOn) { /* need to change the OTC bit, set MTPEX=0 in any case */ /* unlock key2 */ err = Tfa98xx_WriteRegister16(handle, 0x0B, 0x5A); if (err != Tfa98xx_Error_Ok) { pr_err("%s: Tfa98xx_DspReset failed %d\n", __func__, err); return; } /* MTPOTC=otcOn, MTPEX=0 */ err = Tfa98xx_WriteRegister16(handle, TFA98XX_MTP, (unsigned short)otcOn); if (err != Tfa98xx_Error_Ok) { pr_err("%s: Tfa98xx_DspReset failed %d\n", __func__, err); return; } /* CIMTP=1 */ err = Tfa98xx_WriteRegister16(handle, 0x62, 1<<11); if (err != Tfa98xx_Error_Ok) { pr_err("%s: Tfa98xx_DspReset failed %d\n", __func__, err); return; } mtpChanged = 1; } timeout = 0; do { msleep(20); err = Tfa98xx_ReadRegister16(handle, TFA98XX_STATUSREG, &status); pr_info("%s %04x\n", __func__, status); if (err != Tfa98xx_Error_Ok) { pr_err("%s: Tfa98xx_DspReset failed %d\n", __func__, err); return; } timeout++; if (timeout > 50) { pr_info("%s timeout\n", __func__); break; } } while ((status & TFA98XX_STATUSREG_MTPB_MSK) == TFA98XX_STATUSREG_MTPB_MSK); }