lineage_kernel_xcoverpro/sound/soc/codecs/tfa9872/tfa_init.c

874 lines
26 KiB
C
Raw Permalink Normal View History

2023-06-18 22:53:49 +00:00
/*
* Copyright 2014,215 NXP Semiconductors
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 or later
* as published by the Free Software Foundation.
*/
#include "tfa_dsp_fw.h"
#include "tfa_service.h"
#include "tfa_internal.h"
#include "tfa98xx_tfafieldnames.h"
static enum tfa98xx_error tfa9895_specific(tfa98xx_handle_t handle)
{
enum tfa98xx_error error = TFA98XX_ERROR_OK;
int result;
if (!tfa98xx_handle_is_open(handle))
return TFA98XX_ERROR_NOT_OPEN;
/* all i2C registers are already set to default */
result = TFA_SET_BF(handle, AMPE, 1);
if (result < 0)
return -result;
/* some other registers must be set for optimal amplifier behaviour */
reg_write(handle, 0x05, 0x13AB);
reg_write(handle, 0x06, 0x001F);
/* peak voltage protection is always on, but may be written */
reg_write(handle, 0x08, 0x3C4E);
/*TFA98XX_SYSCTRL_DCA=0*/
reg_write(handle, 0x09, 0x024D);
reg_write(handle, 0x41, 0x0308);
error = reg_write(handle, 0x49, 0x0E82);
return error;
}
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_NOT_OPEN;
/* all i2C registers are already set to default for N1C2 */
/* some PLL registers must be set optimal for amplifier behaviour
*/
error = reg_write(handle, 0x40, 0x5a6b);
if (error)
return error;
reg_read(handle, 0x59, &regRead);
regRead |= 0x3;
reg_write(handle, 0x59, regRead);
error = reg_write(handle, 0x40, 0x0000);
error = reg_write(handle, 0x47, 0x7BE1);
return error;
}
static enum tfa98xx_error tfa9891_specific(tfa98xx_handle_t handle)
{
enum tfa98xx_error error = TFA98XX_ERROR_OK;
if (!tfa98xx_handle_is_open(handle))
return TFA98XX_ERROR_NOT_OPEN;
/* ----- generated code start ----- */
/* ----- version 18.0 ----- */
reg_write(handle, 0x09, 0x025d); /* POR=0x024d */
reg_write(handle, 0x10, 0x0018); /* POR=0x0024 */
reg_write(handle, 0x22, 0x0003); /* POR=0x0023 */
reg_write(handle, 0x25, 0x0001); /* POR=0x0000 */
reg_write(handle, 0x46, 0x0000); /* POR=0x4000 */
reg_write(handle, 0x55, 0x3ffb); /* POR=0x7fff */
/* ----- generated code end ----- */
return error;
}
static enum tfa98xx_error tfa9896_specific(tfa98xx_handle_t handle)
{
enum tfa98xx_error error = TFA98XX_ERROR_OK;
unsigned short check_value;
if (!tfa98xx_handle_is_open(handle))
return TFA98XX_ERROR_NOT_OPEN;
/* all i2C registers must already set to default POR value */
/* $48:[3] - 1 ==> 0; iddqtestbst - default value changed.
* When Iddqtestbst is set to "0", the slewrate is reduced.
* This will lower overshoot on IN-B to avoid NMOS damage of booster.
*/
/* ----- generated code start ----- */
/*v17*/
reg_write(handle, 0x06, 0x000b); /* POR=0x0001 */
reg_write(handle, 0x07, 0x3e7f); /* POR=0x1e7f */
reg_write(handle, 0x0a, 0x0d8a); /* POR=0x0592 */
reg_write(handle, 0x48, 0x0300); /* POR=0x0308 */
reg_write(handle, 0x88, 0x0100); /* POR=0x0000 */
/* ----- generated code end ----- */
/* $49:[0] - 1 ==> 0; CLIP - default value changed. 0 means CLIPPER on
*/
error = reg_read(handle, 0x49, &check_value);
check_value &= ~0x1;
error = reg_write(handle, 0x49, check_value);
return error;
}
static enum tfa98xx_error tfa9897_specific(tfa98xx_handle_t handle)
{
enum tfa98xx_error error = TFA98XX_ERROR_OK;
unsigned short check_value;
if (!tfa98xx_handle_is_open(handle))
return TFA98XX_ERROR_NOT_OPEN;
/* all i2C registers must already set to default POR value */
/* $48:[3] - 1 ==> 0; iddqtestbst - default value changed.
* When Iddqtestbst is set to "0", the slewrate is reduced.
* This will lower overshoot on IN-B to avoid NMOS damage of booster.
*/
error = reg_write(handle, 0x48, 0x0300); /* POR value = 0x308 */
/* $49:[0] - 1 ==> 0; CLIP - default value changed. 0 means CLIPPER on
*/
error = reg_read(handle, 0x49, &check_value);
check_value &= ~0x1;
error = reg_write(handle, 0x49, check_value);
return error;
}
static enum tfa98xx_error tfa9888_specific(tfa98xx_handle_t handle)
{
enum tfa98xx_error error = TFA98XX_ERROR_OK;
unsigned short value, xor;
if (!tfa98xx_handle_is_open(handle))
return TFA98XX_ERROR_NOT_OPEN;
if ((handles_local[handle].rev & 0xff) != 0x88) {
pr_err("This code is not for this device type: %x\n",
handles_local[handle].rev);
return TFA98XX_ERROR_BAD_PARAMETER;
}
/* Unlock keys to write settings */
error = reg_write(handle, 0x0F, 0x5A6B);
error = reg_read(handle, 0xFB, &value);
xor = value ^ 0x005A;
error = reg_write(handle, 0xA0, xor);
/* The optimal settings are different for 1c, 2c, 3b and 2b/1b */
if (handles_local[handle].rev == 0x2c88) {
/* ----- generated code start ----- */
/* --------- Version v1 ---------- */
reg_write(handle, 0x00, 0x164d); /* POR=0x064d */
reg_write(handle, 0x01, 0x828b); /* POR=0x92cb */
reg_write(handle, 0x02, 0x1dc8); /* POR=0x1828 */
reg_write(handle, 0x0e, 0x0080); /* POR=0x0000 */
reg_write(handle, 0x20, 0x089e); /* POR=0x0890 */
reg_write(handle, 0x22, 0x543c); /* POR=0x545c */
reg_write(handle, 0x23, 0x0006); /* POR=0x0000 */
reg_write(handle, 0x24, 0x0014); /* POR=0x0000 */
reg_write(handle, 0x25, 0x000a); /* POR=0x0000 */
reg_write(handle, 0x26, 0x0100); /* POR=0x0000 */
reg_write(handle, 0x28, 0x1000); /* POR=0x0000 */
reg_write(handle, 0x51, 0x0000); /* POR=0x00c0 */
reg_write(handle, 0x52, 0xfafe); /* POR=0xbaf6 */
reg_write(handle, 0x70, 0x3ee4); /* POR=0x3ee6 */
reg_write(handle, 0x71, 0x1074); /* POR=0x3074 */
reg_write(handle, 0x83, 0x0014); /* POR=0x0013 */
/* ----- generated code end ----- */
} else if (handles_local[handle].rev == 0x1c88) {
/* ----- generated code start ----- */
/* --------- Version v6 ---------- */
reg_write(handle, 0x00, 0x164d); /* POR=0x064d */
reg_write(handle, 0x01, 0x828b); /* POR=0x92cb */
reg_write(handle, 0x02, 0x1dc8); /* POR=0x1828 */
reg_write(handle, 0x0e, 0x0080); /* POR=0x0000 */
reg_write(handle, 0x20, 0x089e); /* POR=0x0890 */
reg_write(handle, 0x22, 0x543c); /* POR=0x545c */
reg_write(handle, 0x23, 0x0006); /* POR=0x0000 */
reg_write(handle, 0x24, 0x0014); /* POR=0x0000 */
reg_write(handle, 0x25, 0x000a); /* POR=0x0000 */
reg_write(handle, 0x26, 0x0100); /* POR=0x0000 */
reg_write(handle, 0x28, 0x1000); /* POR=0x0000 */
reg_write(handle, 0x51, 0x0000); /* POR=0x00c0 */
reg_write(handle, 0x52, 0xfafe); /* POR=0xbaf6 */
reg_write(handle, 0x70, 0x3ee4); /* POR=0x3ee6 */
reg_write(handle, 0x71, 0x1074); /* POR=0x3074 */
reg_write(handle, 0x83, 0x0014); /* POR=0x0013 */
/* ----- generated code end ----- */
} else if (handles_local[handle].rev == 0x3b88) {
/* ----- generated code start ----- */
/* --------- Version v20 ---------- */
reg_write(handle, 0x01, 0x828b); /* POR=0x92cb */
reg_write(handle, 0x02, 0x1dc8); /* POR=0x1828 */
reg_write(handle, 0x20, 0x089e); /* POR=0x0890 */
reg_write(handle, 0x22, 0x543c); /* POR=0x545c */
reg_write(handle, 0x23, 0x0c06); /* POR=0x0000 */
reg_write(handle, 0x24, 0x0014); /* POR=0x0000 */
reg_write(handle, 0x25, 0x000a); /* POR=0x0000 */
reg_write(handle, 0x26, 0x0100); /* POR=0x0000 */
reg_write(handle, 0x28, 0x1000); /* POR=0x0000 */
reg_write(handle, 0x51, 0x0000); /* POR=0x00c0 */
reg_write(handle, 0x52, 0xfafe); /* POR=0xbaf6 */
reg_write(handle, 0x58, 0x1e1c); /* POR=0x161c */
reg_write(handle, 0x70, 0x3ee4); /* POR=0x3ee6 */
reg_write(handle, 0x71, 0x1074); /* POR=0x3074 */
reg_write(handle, 0x83, 0x0014); /* POR=0x0013 */
/* ----- generated code end ----- */
} else {
/* If not 1c or 3b assume older version */
/* ----- generated code start ----- */
/* --------- Version v19 ---------- */
reg_write(handle, 0x00, 0x1e5d); /* POR=0x064d */
reg_write(handle, 0x01, 0x828b); /* POR=0x92cb */
reg_write(handle, 0x20, 0x089e); /* POR=0x0890 */
reg_write(handle, 0x23, 0x0c06); /* POR=0x0000 */
reg_write(handle, 0x24, 0x0014); /* POR=0x0000 */
reg_write(handle, 0x25, 0x000a); /* POR=0x0000 */
reg_write(handle, 0x26, 0x0100); /* POR=0x0000 */
reg_write(handle, 0x28, 0x1000); /* POR=0x0000 */
reg_write(handle, 0x51, 0x0000); /* POR=0x00c0 */
reg_write(handle, 0x52, 0x9ae2); /* POR=0xbaf6 */
reg_write(handle, 0x58, 0x1e1c); /* POR=0x161c */
reg_write(handle, 0x70, 0x3ce6); /* POR=0x3ee6 */
reg_write(handle, 0x71, 0x1074); /* POR=0x3074 */
reg_write(handle, 0x83, 0x0014); /* POR=0x0013 */
/* ----- generated code end ----- */
}
return error;
}
static enum tfa98xx_error tfa9872_specific(tfa98xx_handle_t handle)
{
enum tfa98xx_error error = TFA98XX_ERROR_OK;
uint16_t MANAOOSC = 0x0140; /* version 17 */
unsigned short value, xor;
if (!tfa98xx_handle_is_open(handle))
return TFA98XX_ERROR_NOT_OPEN;
/* Unlock key 1 and 2 */
error = reg_write(handle, 0x0F, 0x5A6B);
error = reg_read(handle, 0xFB, &value);
xor = value ^ 0x005A;
error = reg_write(handle, 0xA0, xor);
tfa98xx_key2(handle, 0);
switch (handles_local[handle].rev) {
case 0x1a72:
case 0x2a72:
/* ----- generated code start ----- */
/* ----- version 26 ----- */
reg_write(handle, 0x00, 0x1801); /* POR=0x0001 */
reg_write(handle, 0x02, 0x2dc8); /* POR=0x2028 */
reg_write(handle, 0x20, 0x0890); /* POR=0x2890 */
reg_write(handle, 0x22, 0x043c); /* POR=0x045c */
reg_write(handle, 0x51, 0x0000); /* POR=0x0080 */
reg_write(handle, 0x52, 0x1a1c); /* POR=0x7ae8 */
reg_write(handle, 0x58, 0x161c); /* POR=0x101c */
reg_write(handle, 0x61, 0x0198); /* POR=0x0000 */
reg_write(handle, 0x65, 0x0a8b); /* POR=0x0a9a */
reg_write(handle, 0x70, 0x07f5); /* POR=0x06e6 */
reg_write(handle, 0x74, 0xcc84); /* POR=0xd823 */
reg_write(handle, 0x82, 0x01ed); /* POR=0x000d */
reg_write(handle, 0x83, 0x0014); /* POR=0x0013 */
reg_write(handle, 0x84, 0x0021); /* POR=0x0020 */
reg_write(handle, 0x85, 0x0001); /* POR=0x0003 */
/* ----- generated code end ----- */
break;
case 0x1b72:
case 0x2b72:
case 0x3b72:
/* ----- generated code start ----- */
/* ----- TFA9872 Probus Registers map N1B2
* - Version 21 (10/19/2016) -----
*/
reg_write(handle, 0x02, 0x2dc8); /* POR=0x2828 */
reg_write(handle, 0x20, 0x0890); /* POR=0x2890 */
reg_write(handle, 0x22, 0x043c); /* POR=0x045c */
reg_write(handle, 0x23, 0x0001); /* POR=0x0003 */
reg_write(handle, 0x51, 0x0000); /* POR=0x0080 */
reg_write(handle, 0x52, 0x5a1c); /* POR=0x7a08 */
reg_write(handle, 0x61, 0x0198); /* POR=0x0000 */
reg_write(handle, 0x63, 0x0a9a); /* POR=0x0a93 */
reg_write(handle, 0x65, 0x0a82); /* POR=0x0a8d */
reg_write(handle, 0x6f, 0x01e3); /* POR=0x02e4 */
reg_write(handle, 0x70, 0x06fd); /* POR=0x06e6 */
reg_write(handle, 0x71, 0x307e); /* POR=0x207e */
reg_write(handle, 0x74, 0xcc84); /* POR=0xd913 */
reg_write(handle, 0x75, 0x1132); /* POR=0x118a */
reg_write(handle, 0x82, 0x01ed); /* POR=0x000d */
reg_write(handle, 0x83, 0x001a); /* POR=0x0013 */
/* ----- generated code end ----- */
break;
default:
pr_info("\nWarning: Optimal settings not found for device with revid = 0x%x\n",
handles_local[handle].rev);
break;
}
/* Turn off the osc1m to save power: PLMA4928 */
error = tfa_set_bf(handle, MANAOOSC, 1);
/* Bypass OVP by setting bit 3 from register 0xB0 (bypass_ovp=1): */
/* PLMA5258 */
error = reg_read(handle, 0xB0, &value);
value |= 1 << 3;
error = reg_write(handle, 0xB0, value);
return error;
}
static enum tfa98xx_error tfa9912_specific(tfa98xx_handle_t handle)
{
enum tfa98xx_error error = TFA98XX_ERROR_OK;
unsigned short value, xor;
if (!tfa98xx_handle_is_open(handle))
return TFA98XX_ERROR_NOT_OPEN;
if ((handles_local[handle].rev & 0xff) != 0x13) {
pr_err("This code is not for this device type: %x\n",
handles_local[handle].rev);
return TFA98XX_ERROR_BAD_PARAMETER;
}
/* Unlock keys to write settings */
error = reg_write(handle, 0x0F, 0x5A6B);
error = reg_read(handle, 0xFB, &value);
xor = value ^ 0x005A;
error = reg_write(handle, 0xA0, xor);
/* The optimal settings */
if (handles_local[handle].rev == 0x1a13) {
/* ----- generated code start ----- */
/* ----- version 1.34 ----- */
reg_write(handle, 0x00, 0x0255); /* POR=0x0245 */
reg_write(handle, 0x01, 0x838a); /* POR=0x83ca */
reg_write(handle, 0x02, 0x2dc8); /* POR=0x2828 */
reg_write(handle, 0x05, 0x762a); /* POR=0x766a */
reg_write(handle, 0x22, 0x543c); /* POR=0x545c */
reg_write(handle, 0x26, 0x0100); /* POR=0x0010 */
reg_write(handle, 0x51, 0x0000); /* POR=0x0080 */
reg_write(handle, 0x52, 0x551c); /* POR=0x1afc */
reg_write(handle, 0x61, 0x000c); /* POR=0x0018 */
reg_write(handle, 0x63, 0x0a96); /* POR=0x0a9a */
reg_write(handle, 0x65, 0x0a82); /* POR=0x0a8b */
reg_write(handle, 0x6c, 0x01d5); /* POR=0x02d5 */
reg_write(handle, 0x70, 0x26f8); /* POR=0x06e0 */
reg_write(handle, 0x71, 0x3074); /* POR=0x2074 */
reg_write(handle, 0x75, 0x4484); /* POR=0x4585 */
reg_write(handle, 0x76, 0x72ea); /* POR=0x54a2 */
reg_write(handle, 0x82, 0x024d); /* POR=0x000d */
reg_write(handle, 0x89, 0x0013); /* POR=0x0014 */
/* ----- generated code end ----- */
}
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 = reg_read(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;
/* TFA9890 temporarily disable clock gating when dsp reset is used */
error = reg_read(handle, TFA98XX_CURRENTSENSE4, &value);
if (error)
return error;
if (error == TFA98XX_ERROR_OK) {
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 = reg_write(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;
}
/*
* the int24 values for the vsfw delay table
*/
static unsigned char vsfwdelay_table[] = {
0, 0, 2, /*Index 0 - Current/Volt Fractional Delay for 8KHz */
0, 0, 0, /*Index 1 - Current/Volt Fractional Delay for 11KHz */
0, 0, 0, /*Index 2 - Current/Volt Fractional Delay for 12KHz */
0, 0, 2, /*Index 3 - Current/Volt Fractional Delay for 16KHz */
0, 0, 2, /*Index 4 - Current/Volt Fractional Delay for 22KHz */
0, 0, 2, /*Index 5 - Current/Volt Fractional Delay for 24KHz */
0, 0, 2, /*Index 6 - Current/Volt Fractional Delay for 32KHz */
0, 0, 2, /*Index 7 - Current/Volt Fractional Delay for 44KHz */
0, 0, 3 /*Index 8 - Current/Volt Fractional Delay for 48KHz */
};
/*
* TODO make this tfa98xx
* Note that the former products write this table via the patch
* so moving this to the tfa98xx API requires also updating all patches
*/
static enum tfa98xx_error
tfa9896_dsp_write_vsfwdelay_table(tfa98xx_handle_t handle)
{
enum tfa98xx_error error;
error = tfa_dsp_cmd_id_write(handle, MODULE_FRAMEWORK,
TFA1_FW_PAR_ID_SET_CURRENT_DELAY, sizeof(vsfwdelay_table),
vsfwdelay_table);
return error;
}
/*
* The int24 values for the fracdelay table
* For now applicable only for 8 and 48 kHz
*/
static unsigned char cvfracdelay_table[] = {
0, 0, 51, /*Index 0 - Current/Volt Fractional Delay for 8KHz */
0, 0, 0, /*Index 1 - Current/Volt Fractional Delay for 11KHz */
0, 0, 0, /*Index 2 - Current/Volt Fractional Delay for 12KHz */
0, 0, 38, /*Index 3 - Current/Volt Fractional Delay for 16KHz */
0, 0, 34, /*Index 4 - Current/Volt Fractional Delay for 22KHz */
0, 0, 33, /*Index 5 - Current/Volt Fractional Delay for 24KHz */
0, 0, 11, /*Index 6 - Current/Volt Fractional Delay for 32KHz */
0, 0, 2, /*Index 7 - Current/Volt Fractional Delay for 44KHz */
0, 0, 62 /*Index 8 - Current/Volt Fractional Delay for 48KHz */
};
enum tfa98xx_error tfa9896_dsp_write_cvfracdelay_table(tfa98xx_handle_t handle)
{
enum tfa98xx_error error;
error = tfa_dsp_cmd_id_write(handle, MODULE_FRAMEWORK,
TFA1_FW_PAR_ID_SET_CURFRAC_DELAY, sizeof(cvfracdelay_table),
cvfracdelay_table);
return error;
}
static enum tfa98xx_error
tfa9896_tfa_dsp_write_tables(tfa98xx_handle_t dev_idx, int sample_rate)
{
enum tfa98xx_error error;
/* Not used for max1! */
//sample_rate = sample_rate;
error = tfa9896_dsp_write_vsfwdelay_table(dev_idx);
if (error == TFA98XX_ERROR_OK)
error = tfa9896_dsp_write_cvfracdelay_table(dev_idx);
tfa98xx_dsp_reset(dev_idx, 1);
tfa98xx_dsp_reset(dev_idx, 0);
return error;
}
#if defined(TFA9896_SET_TRIP_LEVEL) /* TODO: remove or use me */
static enum tfa98xx_error
tfa9896_tfa_set_boost_trip_level(tfa98xx_handle_t handle, int Re25C)
{
enum tfa98xx_error error = TFA98XX_ERROR_OK;
int trip_value;
if (Re25C == 0) {
pr_debug("\nWarning: No calibration values found: Boost trip level not adjusted!\n");
return error;
}
/* Read trip level: The trip level is already set
* (if defined in cnt file) so we can just read the bitfield
*/
trip_value = tfa_get_bf(handle, TFA9896_BF_DCTRIP);
pr_debug("\nCurrent calibration value is %d mOhm and the boost_trip_lvl is %d\n",
Re25C, trip_value);
if (Re25C > 0 && Re25C < 4000)
trip_value = 0xa;
else if (Re25C >= 4000 && Re25C < 6000)
trip_value = 0x9;
else if (Re25C >= 6000 && Re25C < 8000)
trip_value = 0x8;
else if (Re25C >= 8000)
trip_value = 0x7;
/* Set the boost trip level according to the new value */
error = tfa_set_bf(handle, TFA9896_BF_DCTRIP, (uint16_t)trip_value);
pr_debug("New boost_trip_lvl is set to %d\n", trip_value);
return error;
}
#endif
/*
* the int24 values for the vsfw delay table
*/
static unsigned char tfa9897_vsfwdelay_table[] = {
0, 0, 2, /*Index 0 - Current/Volt Fractional Delay for 8KHz */
0, 0, 0, /*Index 1 - Current/Volt Fractional Delay for 11KHz */
0, 0, 0, /*Index 2 - Current/Volt Fractional Delay for 12KHz */
0, 0, 2, /*Index 3 - Current/Volt Fractional Delay for 16KHz */
0, 0, 2, /*Index 4 - Current/Volt Fractional Delay for 22KHz */
0, 0, 2, /*Index 5 - Current/Volt Fractional Delay for 24KHz */
0, 0, 2, /*Index 6 - Current/Volt Fractional Delay for 32KHz */
0, 0, 2, /*Index 7 - Current/Volt Fractional Delay for 44KHz */
0, 0, 3 /*Index 8 - Current/Volt Fractional Delay for 48KHz */
};
/*
* TODO make this tfa98xx
* Note that the former products write this table via the patch
* so moving this to tfa98xx API requires also updating all patches
*/
static enum tfa98xx_error
tfa9897_dsp_write_vsfwdelay_table(tfa98xx_handle_t handle)
{
enum tfa98xx_error error;
error = tfa_dsp_cmd_id_write(handle, MODULE_FRAMEWORK,
TFA1_FW_PAR_ID_SET_CURRENT_DELAY,
sizeof(tfa9897_vsfwdelay_table),
tfa9897_vsfwdelay_table);
return error;
}
/*
* The int24 values for the fracdelay table
* For now applicable only for 8 and 48 kHz
*/
static unsigned char tfa9897_cvfracdelay_table[] = {
0, 0, 51, /*Index 0 - Current/Volt Fractional Delay for 8KHz */
0, 0, 0, /*Index 1 - Current/Volt Fractional Delay for 11KHz */
0, 0, 0, /*Index 2 - Current/Volt Fractional Delay for 12KHz */
0, 0, 38, /*Index 3 - Current/Volt Fractional Delay for 16KHz */
0, 0, 34, /*Index 4 - Current/Volt Fractional Delay for 22KHz */
0, 0, 33, /*Index 5 - Current/Volt Fractional Delay for 24KHz */
0, 0, 11, /*Index 6 - Current/Volt Fractional Delay for 32KHz */
0, 0, 2, /*Index 7 - Current/Volt Fractional Delay for 44KHz */
0, 0, 62 /*Index 8 - Current/Volt Fractional Delay for 48KHz */
};
enum tfa98xx_error
tfa9897_dsp_write_cvfracdelay_table(tfa98xx_handle_t handle)
{
enum tfa98xx_error error;
error = tfa_dsp_cmd_id_write(handle, MODULE_FRAMEWORK,
TFA1_FW_PAR_ID_SET_CURFRAC_DELAY,
sizeof(tfa9897_cvfracdelay_table),
tfa9897_cvfracdelay_table);
return error;
}
static enum tfa98xx_error
tfa9897_tfa_dsp_write_tables(tfa98xx_handle_t dev_idx, int sample_rate)
{
enum tfa98xx_error error;
/* Not used for max1! */
//sample_rate = sample_rate;
error = tfa9897_dsp_write_vsfwdelay_table(dev_idx);
if (error == TFA98XX_ERROR_OK)
error = tfa9897_dsp_write_cvfracdelay_table(dev_idx);
tfa98xx_dsp_reset(dev_idx, 1);
tfa98xx_dsp_reset(dev_idx, 0);
return error;
}
static enum tfa98xx_error
tfa9888_tfa_dsp_write_tables(tfa98xx_handle_t handle, int sample_rate)
{
unsigned char buffer[15] = {0};
int size = 15 * sizeof(char);
/* Write the fractional delay in hardware register 'cs_frac_delay' */
switch (sample_rate) {
case 0: /* 8kHz */
TFA_SET_BF(handle, FRACTDEL, 40);
break;
case 1: /* 11.025KHz */
TFA_SET_BF(handle, FRACTDEL, 38);
break;
case 2: /* 12kHz */
TFA_SET_BF(handle, FRACTDEL, 37);
break;
case 3: /* 16kHz */
TFA_SET_BF(handle, FRACTDEL, 59);
break;
case 4: /* 22.05KHz */
TFA_SET_BF(handle, FRACTDEL, 56);
break;
case 5: /* 24kHz */
TFA_SET_BF(handle, FRACTDEL, 56);
break;
case 6: /* 32kHz */
TFA_SET_BF(handle, FRACTDEL, 52);
break;
case 7: /* 44.1kHz */
TFA_SET_BF(handle, FRACTDEL, 48);
break;
case 8:
default:/* 48kHz */
TFA_SET_BF(handle, FRACTDEL, 46);
break;
}
/* First copy the msg_id to the buffer */
buffer[0] = (uint8_t) 0;
buffer[1] = (uint8_t) MODULE_FRAMEWORK + 128;
buffer[2] = (uint8_t) FW_PAR_ID_SET_SENSES_DELAY;
/* Required for all FS exept 8kHz (8kHz is all zero) */
if (sample_rate != 0) {
buffer[5] = 1; /* Vdelay_P */
buffer[8] = 0; /* Idelay_P */
buffer[11] = 1; /* Vdelay_S */
buffer[14] = 0; /* Idelay_S */
}
/* send SetSensesDelay msg */
return dsp_msg(handle, size, (char *)buffer);
}
static enum tfa98xx_error
tfa9912_tfa_dsp_write_tables(tfa98xx_handle_t handle, int sample_rate)
{
unsigned char buffer[15] = {0};
int size = 15 * sizeof(char);
/* Write the fractional delay in hardware register 'cs_frac_delay' */
switch (sample_rate) {
case 0: /* 8kHz */
TFA_SET_BF(handle, FRACTDEL, 40);
break;
case 1: /* 11.025KHz */
TFA_SET_BF(handle, FRACTDEL, 38);
break;
case 2: /* 12kHz */
TFA_SET_BF(handle, FRACTDEL, 37);
break;
case 3: /* 16kHz */
TFA_SET_BF(handle, FRACTDEL, 59);
break;
case 4: /* 22.05KHz */
TFA_SET_BF(handle, FRACTDEL, 56);
break;
case 5: /* 24kHz */
TFA_SET_BF(handle, FRACTDEL, 56);
break;
case 6: /* 32kHz */
TFA_SET_BF(handle, FRACTDEL, 52);
break;
case 7: /* 44.1kHz */
TFA_SET_BF(handle, FRACTDEL, 48);
break;
case 8:
default:/* 48kHz */
TFA_SET_BF(handle, FRACTDEL, 46);
break;
}
/* First copy the msg_id to the buffer */
buffer[0] = (uint8_t) 0;
buffer[1] = (uint8_t) MODULE_FRAMEWORK + 128;
buffer[2] = (uint8_t) FW_PAR_ID_SET_SENSES_DELAY;
/* Required for all FS exept 8kHz (8kHz is all zero) */
if (sample_rate != 0) {
buffer[5] = 1; /* Vdelay_P */
buffer[8] = 0; /* Idelay_P */
buffer[11] = 1; /* Vdelay_S */
buffer[14] = 0; /* Idelay_S */
}
/* send SetSensesDelay msg */
return dsp_msg(handle, size, (char *)buffer);
}
/*
* register device specifics functions
*/
void tfa9895_ops(struct tfa_device_ops *ops)
{
ops->tfa_init = tfa9895_specific;
}
/*
* 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;
}
/*
* register device specifics functions
*/
void tfa9891_ops(struct tfa_device_ops *ops)
{
ops->tfa_init = tfa9891_specific;
}
/*
* register device specifics functions
*/
void tfa9896_ops(struct tfa_device_ops *ops)
{
ops->tfa_init = tfa9896_specific;
ops->tfa_dsp_write_tables = tfa9896_tfa_dsp_write_tables;
}
/*
* register device specifics functions
*/
void tfa9897_ops(struct tfa_device_ops *ops)
{
ops->tfa_init = tfa9897_specific;
ops->tfa_dsp_write_tables = tfa9897_tfa_dsp_write_tables;
}
/*
* register device specifics functions
*/
void tfa9888_ops(struct tfa_device_ops *ops)
{
ops->tfa_init = tfa9888_specific;
ops->tfa_dsp_write_tables = tfa9888_tfa_dsp_write_tables;
}
/*
* register device specifics functions
*/
void tfa9872_ops(struct tfa_device_ops *ops)
{
ops->tfa_init = tfa9872_specific;
}
/*
* register device specifics functions
*/
void tfa9912_ops(struct tfa_device_ops *ops)
{
ops->tfa_init = tfa9912_specific;
ops->tfa_dsp_write_tables = tfa9912_tfa_dsp_write_tables;
}