blob: 595779ae2a69359b88bf7d257f8e62a84877ca08 [file] [log] [blame]
/*
*Copyright 2014,2015 NXP Semiconductors
*
*Licensed under the Apache License, Version 2.0 (the "License");
*you may not use this file except in compliance with the License.
*You may obtain a copy of the License at
*
*http://www.apache.org/licenses/LICENSE-2.0
*
*Unless required by applicable law or agreed to in writing, software
*distributed under the License is distributed on an "AS IS" BASIS,
*WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*See the License for the specific language governing permissions and
*limitations under the License.
*/
#include "tfa_dsp_fw.h"
#include "tfa_service.h"
#include "tfa_internal.h"
#include "tfa98xx_tfafieldnames.h"
static enum Tfa98xx_Error tfa9890_specific(Tfa98xx_handle_t handle)
{
enum Tfa98xx_Error error = Tfa98xx_Error_Ok;
unsigned short regRead = 0;
if (!tfa98xx_handle_is_open(handle))
return Tfa98xx_Error_NotOpen;
/* all i2C registers are already set to default for N1C2 */
/* some PLL registers must be set optimal for amplifier behaviour
*/
error = tfa98xx_write_register16(handle, 0x40, 0x5a6b);
if (error)
return error;
tfa98xx_read_register16(handle, 0x59, &regRead);
regRead |= 0x3;
tfa98xx_write_register16(handle, 0x59, regRead);
error = tfa98xx_write_register16(handle, 0x40, 0x0000);
error = tfa98xx_write_register16(handle, 0x47, 0x7BE1);
return error;
}
/*
* 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.
*
*/
static enum Tfa98xx_Error tfa9890_dsp_system_stable(Tfa98xx_handle_t handle, int *ready)
{
enum Tfa98xx_Error error = Tfa98xx_Error_Ok;
unsigned short status, mtp0;
int result, tries;
/* check the contents of the STATUS register */
result = TFA_READ_REG(handle, AREFS);
if (result < 0) {
error = -result;
goto errorExit;
}
status = (unsigned short)result;
/* if AMPS is set then we were already configured and running
* no need to check further
*/
*ready = (TFA_GET_BF_VALUE(handle, AMPS, status) == 1);
if (*ready) /* if ready go back */
return error; /* will be Tfa98xx_Error_Ok */
/* check AREFS and CLKS: not ready if either is clear */
*ready = !((TFA_GET_BF_VALUE(handle, AREFS, status) == 0)
|| (TFA_GET_BF_VALUE(handle, CLKS, status) == 0));
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--) {
result = TFA_GET_BF(handle, MTPB);
if (result < 0) {
error = -result;
goto errorExit;
}
status = (unsigned short)result;
/* check the contents of the STATUS register */
*ready = (result == 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_read_register16(handle, 0x84, &mtp0);
if (error)
goto errorExit;
*ready = (mtp0 != 0); /* The MTP register written? */
return error;
errorExit:
*ready = 0;
return error;
}
/*
* The CurrentSense4 register is not in the datasheet, define local
*/
#define TFA98XX_CURRENTSENSE4_CTRL_CLKGATECFOFF (1<<2)
#define TFA98XX_CURRENTSENSE4 0x49
/*
* Disable clock gating
*/
static enum Tfa98xx_Error tfa9890_clockgating(Tfa98xx_handle_t handle, int on)
{
enum Tfa98xx_Error error;
unsigned short value;
/* for TFA9890 temporarily disable clock gating when dsp reset is used */
error = tfa98xx_read_register16(handle, TFA98XX_CURRENTSENSE4, &value);
if (error) return error;
if (Tfa98xx_Error_Ok == error) {
if (on) /* clock gating on - clear the bit */
value &= ~TFA98XX_CURRENTSENSE4_CTRL_CLKGATECFOFF;
else /* clock gating off - set the bit */
value |= TFA98XX_CURRENTSENSE4_CTRL_CLKGATECFOFF;
error = tfa98xx_write_register16(handle, TFA98XX_CURRENTSENSE4, value);
}
return error;
}
/*
* Tfa9890_DspReset will deal with clock gating control in order
* to reset the DSP for warm state restart
*/
static enum Tfa98xx_Error tfa9890_dsp_reset(Tfa98xx_handle_t handle, int state)
{
enum Tfa98xx_Error error;
/* for TFA9890 temporarily disable clock gating
when dsp reset is used */
tfa9890_clockgating(handle, 0);
TFA_SET_BF(handle, RST, (uint16_t)state);
/* clock gating restore */
error = tfa9890_clockgating(handle, 1);
return error;
}
/*
* register device specifics functions
*/
void tfa9890_ops(struct tfa_device_ops *ops) {
ops->tfa_init = tfa9890_specific;
ops->tfa_dsp_reset = tfa9890_dsp_reset;
ops->tfa_dsp_system_stable = tfa9890_dsp_system_stable;
}