blob: 9109f8d94c7fd2c9fac771de920ee845f8d557e1 [file] [log] [blame]
/*
** =============================================================================
** Copyright (c) 2016 Texas Instruments Inc.
**
** This program is free software; you can redistribute it and/or modify it under
** the terms of the GNU General Public License as published by the Free Software
** Foundation; version 2.
**
** This program is distributed in the hope that it will be useful, but WITHOUT
** ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
** FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
**
** File:
** tas2557-core.c
**
** Description:
** TAS2557 common functions for Android Linux
**
** =============================================================================
*/
#define DEBUG
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/pm.h>
#include <linux/i2c.h>
#include <linux/gpio.h>
#include <linux/regulator/consumer.h>
#include <linux/firmware.h>
#include <linux/regmap.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/slab.h>
#include <linux/syscalls.h>
#include <linux/fcntl.h>
#include <linux/uaccess.h>
#include <linux/crc8.h>
#include "tas2557.h"
#include "tas2557-core.h"
#define PPC_DRIVER_CRCCHK 0x00000200
#define PPC_DRIVER_CONFDEV 0x00000300
#define PPC_DRIVER_MTPLLSRC 0x00000400
#define PPC_DRIVER_CFGDEV_NONCRC 0x00000101
#define TAS2557_CAL_NAME "/data/tas2557_cal.bin"
#define RESTART_MAX 3
static int tas2557_load_calibration(struct tas2557_priv *pTAS2557,
char *pFileName);
static int tas2557_load_data(struct tas2557_priv *pTAS2557, struct TData *pData,
unsigned int nType);
static void tas2557_clear_firmware(struct TFirmware *pFirmware);
static int tas2557_load_block(struct tas2557_priv *pTAS2557, struct TBlock *pBlock);
static int tas2557_load_configuration(struct tas2557_priv *pTAS2557,
unsigned int nConfiguration, bool bLoadSame);
#define TAS2557_UDELAY 0xFFFFFFFE
#define TAS2557_MDELAY 0xFFFFFFFD
#define TAS2557_BLOCK_PLL 0x00
#define TAS2557_BLOCK_PGM_ALL 0x0d
#define TAS2557_BLOCK_PGM_DEV_A 0x01
#define TAS2557_BLOCK_PGM_DEV_B 0x08
#define TAS2557_BLOCK_CFG_COEFF_DEV_A 0x03
#define TAS2557_BLOCK_CFG_COEFF_DEV_B 0x0a
#define TAS2557_BLOCK_CFG_PRE_DEV_A 0x04
#define TAS2557_BLOCK_CFG_PRE_DEV_B 0x0b
#define TAS2557_BLOCK_CFG_POST 0x05
#define TAS2557_BLOCK_CFG_POST_POWER 0x06
static unsigned int p_tas2557_default_data[] = {
TAS2557_SAR_ADC2_REG, 0x05, /* enable SAR ADC */
TAS2557_CLK_ERR_CTRL2, 0x21, /*clk1:clock hysteresis, 0.34ms; clock halt, 22ms*/
TAS2557_CLK_ERR_CTRL3, 0x21, /*clk2: rampDown 15dB/us, clock hysteresis, 10.66us; clock halt, 22ms */
TAS2557_SAFE_GUARD_REG, TAS2557_SAFE_GUARD_PATTERN, /* safe guard */
0xFFFFFFFF, 0xFFFFFFFF
};
static unsigned int p_tas2557_irq_config[] = {
TAS2557_CLK_HALT_REG, 0x71, /* enable clk halt detect2 interrupt */
TAS2557_INT_GEN1_REG, 0x11, /* enable spk OC and OV */
TAS2557_INT_GEN2_REG, 0x11, /* enable clk err1 and die OT */
TAS2557_INT_GEN3_REG, 0x11, /* enable clk err2 and brownout */
TAS2557_INT_GEN4_REG, 0x01, /* disable SAR, enable clk halt */
TAS2557_GPIO4_PIN_REG, 0x07, /* set GPIO4 as int1, default */
TAS2557_INT_MODE_REG, 0x80, /* active high until INT_STICKY_1 and INT_STICKY_2 are read to be cleared. */
0xFFFFFFFF, 0xFFFFFFFF
};
static unsigned int p_tas2557_startup_data[] = {
TAS2557_GPI_PIN_REG, 0x15, /* enable DIN, MCLK, CCI */
TAS2557_GPIO1_PIN_REG, 0x01, /* enable BCLK */
TAS2557_GPIO2_PIN_REG, 0x01, /* enable WCLK */
TAS2557_POWER_CTRL2_REG, 0xA0, /* Class-D, Boost power up */
TAS2557_POWER_CTRL2_REG, 0xA3, /* Class-D, Boost, IV sense power up */
TAS2557_POWER_CTRL1_REG, 0xF8, /* PLL, DSP, clock dividers power up */
TAS2557_UDELAY, 2000, /* delay */
TAS2557_CLK_ERR_CTRL, 0x2b, /* enable clock error detection */
0xFFFFFFFF, 0xFFFFFFFF
};
static unsigned int p_tas2557_unmute_data[] = {
TAS2557_MUTE_REG, 0x00, /* unmute */
TAS2557_SOFT_MUTE_REG, 0x00, /* soft unmute */
0xFFFFFFFF, 0xFFFFFFFF
};
static unsigned int p_tas2557_shutdown_data[] = {
TAS2557_CLK_ERR_CTRL, 0x00, /* disable clock error detection */
TAS2557_SOFT_MUTE_REG, 0x01, /* soft mute */
TAS2557_UDELAY, 10000, /* delay 10ms */
TAS2557_MUTE_REG, 0x03, /* mute */
TAS2557_POWER_CTRL1_REG, 0x60, /* DSP power down */
TAS2557_UDELAY, 2000, /* delay 2ms */
TAS2557_POWER_CTRL2_REG, 0x00, /* Class-D, Boost power down */
TAS2557_POWER_CTRL1_REG, 0x00, /* all power down */
TAS2557_GPIO1_PIN_REG, 0x00, /* disable BCLK */
TAS2557_GPIO2_PIN_REG, 0x00, /* disable WCLK */
TAS2557_GPI_PIN_REG, 0x00, /* disable DIN, MCLK, CCI */
0xFFFFFFFF, 0xFFFFFFFF
};
static int tas2557_dev_load_data(struct tas2557_priv *pTAS2557,
unsigned int *pData)
{
int ret = 0;
unsigned int n = 0;
unsigned int nRegister;
unsigned int nData;
do {
nRegister = pData[n * 2];
nData = pData[n * 2 + 1];
if (nRegister == TAS2557_UDELAY)
udelay(nData);
else if (nRegister != 0xFFFFFFFF) {
ret = pTAS2557->write(pTAS2557, nRegister, nData);
if (ret < 0)
break;
}
n++;
} while (nRegister != 0xFFFFFFFF);
return ret;
}
int tas2557_configIRQ(struct tas2557_priv *pTAS2557)
{
return tas2557_dev_load_data(pTAS2557, p_tas2557_irq_config);
}
int tas2557_set_bit_rate(struct tas2557_priv *pTAS2557, unsigned int nBitRate)
{
int ret = 0, n = -1;
dev_dbg(pTAS2557->dev, "tas2557_set_bit_rate: nBitRate = %d\n", nBitRate);
switch (nBitRate) {
case 16:
n = 0;
break;
case 20:
n = 1;
break;
case 24:
n = 2;
break;
case 32:
n = 3;
break;
}
if (n >= 0)
ret = pTAS2557->update_bits(pTAS2557, TAS2557_ASI1_DAC_FORMAT_REG, 0x18, n<<3);
return ret;
}
int tas2557_get_bit_rate(struct tas2557_priv *pTAS2557, unsigned char *pBitRate)
{
int ret = 0;
unsigned int nValue = 0;
unsigned char bitRate;
ret = pTAS2557->read(pTAS2557, TAS2557_ASI1_DAC_FORMAT_REG, &nValue);
if (ret >= 0) {
bitRate = (nValue&0x18)>>3;
if (bitRate == 0)
bitRate = 16;
else if (bitRate == 1)
bitRate = 20;
else if (bitRate == 2)
bitRate = 24;
else if (bitRate == 3)
bitRate = 32;
*pBitRate = bitRate;
}
return ret;
}
int tas2557_get_DAC_gain(struct tas2557_priv *pTAS2557, unsigned char *pnGain)
{
int ret = 0;
unsigned int nValue = 0;
ret = pTAS2557->read(pTAS2557, TAS2557_SPK_CTRL_REG, &nValue);
if (ret >= 0)
*pnGain = ((nValue&TAS2557_DAC_GAIN_MASK)>>TAS2557_DAC_GAIN_SHIFT);
return ret;
}
int tas2557_set_DAC_gain(struct tas2557_priv *pTAS2557, unsigned int nGain)
{
int ret = 0;
ret = pTAS2557->update_bits(pTAS2557, TAS2557_SPK_CTRL_REG, TAS2557_DAC_GAIN_MASK,
(nGain<<TAS2557_DAC_GAIN_SHIFT));
return ret;
}
/*
* die temperature calculation:
* DieTemp = readout / 2^23
*/
int tas2557_get_die_temperature(struct tas2557_priv *pTAS2557, int *pTemperature)
{
int nResult = 0;
unsigned char nBuf[4];
int temp;
if (!pTAS2557->mpFirmware->mnConfigurations) {
dev_err(pTAS2557->dev, "%s, firmware not loaded\n", __func__);
goto end;
}
if (!pTAS2557->mbPowerUp) {
dev_err(pTAS2557->dev, "%s, device not powered on\n", __func__);
goto end;
}
nResult = pTAS2557->bulk_read(pTAS2557, TAS2557_DIE_TEMP_REG, nBuf, 4);
if (nResult >= 0) {
temp = ((int)nBuf[0] << 24) | ((int)nBuf[1] << 16) | ((int)nBuf[2] << 8) | nBuf[3];
*pTemperature = temp;
}
end:
return nResult;
}
int tas2557_load_platdata(struct tas2557_priv *pTAS2557)
{
int nResult = 0;
if (gpio_is_valid(pTAS2557->mnGpioINT)) {
nResult = tas2557_configIRQ(pTAS2557);
if (nResult < 0)
goto end;
}
nResult = tas2557_set_bit_rate(pTAS2557, pTAS2557->mnI2SBits);
end:
return nResult;
}
int tas2557_load_default(struct tas2557_priv *pTAS2557)
{
int nResult = 0;
nResult = tas2557_dev_load_data(pTAS2557, p_tas2557_default_data);
if (nResult < 0)
goto end;
nResult = tas2557_load_platdata(pTAS2557);
if (nResult < 0)
goto end;
/* enable DOUT tri-state for extra BCLKs */
nResult = pTAS2557->update_bits(pTAS2557, TAS2557_ASI1_DAC_FORMAT_REG, 0x01, 0x01);
end:
return nResult;
}
static void failsafe(struct tas2557_priv *pTAS2557)
{
int ret;
dev_err(pTAS2557->dev, "%s\n", __func__);
pTAS2557->mnErrCode |= ERROR_FAILSAFE;
if (hrtimer_active(&pTAS2557->mtimer))
hrtimer_cancel(&pTAS2557->mtimer);
if(pTAS2557->mnRestart < RESTART_MAX)
{
pTAS2557->mnRestart ++;
msleep(100);
dev_err(pTAS2557->dev, "I2C COMM error, restart SmartAmp.\n");
schedule_delayed_work(&pTAS2557->irq_work, msecs_to_jiffies(100));
return;
}
pTAS2557->enableIRQ(pTAS2557, false, false);
ret = tas2557_dev_load_data(pTAS2557, p_tas2557_shutdown_data);
if (ret < 0)
dev_dbg(pTAS2557->dev, "failed load shutdown\n");
pTAS2557->mbPowerUp = false;
pTAS2557->hw_reset(pTAS2557);
ret = pTAS2557->write(pTAS2557, TAS2557_SW_RESET_REG, 0x01);
if (ret < 0)
dev_dbg(pTAS2557->dev, "failed sw reset\n");
udelay(1000);
ret = pTAS2557->write(pTAS2557, TAS2557_SPK_CTRL_REG, 0x04);
if (ret < 0)
dev_dbg(pTAS2557->dev, "failed in spk ctrl\n");
if (pTAS2557->mpFirmware != NULL)
tas2557_clear_firmware(pTAS2557->mpFirmware);
pTAS2557->mpFirmware->mnPrograms = 0;
}
int tas2557_checkPLL(struct tas2557_priv *pTAS2557)
{
int nResult = 0;
/*
* TO DO
*/
return nResult;
}
/*
* tas2557_load_coefficient
*/
static int tas2557_load_coefficient(struct tas2557_priv *pTAS2557,
int nPrevConfig, int nNewConfig, bool bPowerOn)
{
int nResult = 0;
struct TPLL *pPLL;
struct TProgram *pProgram;
struct TConfiguration *pPrevConfiguration;
struct TConfiguration *pNewConfiguration;
bool bRestorePower = false;
if (!pTAS2557->mpFirmware->mnConfigurations) {
dev_err(pTAS2557->dev, "%s, firmware not loaded\n", __func__);
goto end;
}
if (nNewConfig >= pTAS2557->mpFirmware->mnConfigurations) {
dev_err(pTAS2557->dev, "%s, invalid configuration New=%d, total=%d\n",
__func__, nNewConfig, pTAS2557->mpFirmware->mnConfigurations);
goto end;
}
if (nPrevConfig < 0)
pPrevConfiguration = NULL;
else if (nPrevConfig == nNewConfig) {
dev_dbg(pTAS2557->dev, "%s, config [%d] already loaded\n",
__func__, nNewConfig);
goto end;
} else
pPrevConfiguration = &(pTAS2557->mpFirmware->mpConfigurations[nPrevConfig]);
pNewConfiguration = &(pTAS2557->mpFirmware->mpConfigurations[nNewConfig]);
pTAS2557->mnCurrentConfiguration = nNewConfig;
if (pPrevConfiguration) {
if (pPrevConfiguration->mnPLL == pNewConfiguration->mnPLL) {
dev_dbg(pTAS2557->dev, "%s, PLL same\n", __func__);
goto prog_coefficient;
}
}
pProgram = &(pTAS2557->mpFirmware->mpPrograms[pTAS2557->mnCurrentProgram]);
if (bPowerOn) {
dev_dbg(pTAS2557->dev, "%s, power down to load new PLL\n", __func__);
if (hrtimer_active(&pTAS2557->mtimer))
hrtimer_cancel(&pTAS2557->mtimer);
if (pProgram->mnAppMode == TAS2557_APP_TUNINGMODE)
pTAS2557->enableIRQ(pTAS2557, false, false);
nResult = tas2557_dev_load_data(pTAS2557, p_tas2557_shutdown_data);
if (nResult < 0)
goto end;
bRestorePower = true;
}
/* load PLL */
pPLL = &(pTAS2557->mpFirmware->mpPLLs[pNewConfiguration->mnPLL]);
dev_dbg(pTAS2557->dev, "load PLL: %s block for Configuration %s\n",
pPLL->mpName, pNewConfiguration->mpName);
nResult = tas2557_load_block(pTAS2557, &(pPLL->mBlock));
if (nResult < 0)
goto end;
pTAS2557->mnCurrentSampleRate = pNewConfiguration->mnSamplingRate;
dev_dbg(pTAS2557->dev, "load configuration %s conefficient pre block\n",
pNewConfiguration->mpName);
nResult = tas2557_load_data(pTAS2557, &(pNewConfiguration->mData), TAS2557_BLOCK_CFG_PRE_DEV_A);
if (nResult < 0)
goto end;
prog_coefficient:
dev_dbg(pTAS2557->dev, "load new configuration: %s, coeff block data\n",
pNewConfiguration->mpName);
nResult = tas2557_load_data(pTAS2557, &(pNewConfiguration->mData),
TAS2557_BLOCK_CFG_COEFF_DEV_A);
if (nResult < 0)
goto end;
if (pTAS2557->mpCalFirmware->mnCalibrations) {
nResult = tas2557_set_calibration(pTAS2557, pTAS2557->mnCurrentCalibration);
if (nResult < 0)
goto end;
}
if (bRestorePower) {
pTAS2557->clearIRQ(pTAS2557);
dev_dbg(pTAS2557->dev, "device powered up, load startup\n");
nResult = tas2557_dev_load_data(pTAS2557, p_tas2557_startup_data);
if (nResult < 0)
goto end;
if (pProgram->mnAppMode == TAS2557_APP_TUNINGMODE) {
nResult = tas2557_checkPLL(pTAS2557);
if (nResult < 0) {
nResult = tas2557_dev_load_data(pTAS2557, p_tas2557_shutdown_data);
pTAS2557->mbPowerUp = false;
goto end;
}
}
dev_dbg(pTAS2557->dev,
"device powered up, load unmute\n");
nResult = tas2557_dev_load_data(pTAS2557, p_tas2557_unmute_data);
if (nResult < 0)
goto end;
if (pProgram->mnAppMode == TAS2557_APP_TUNINGMODE) {
pTAS2557->enableIRQ(pTAS2557, true, true);
if (!hrtimer_active(&pTAS2557->mtimer)) {
pTAS2557->mnDieTvReadCounter = 0;
hrtimer_start(&pTAS2557->mtimer,
ns_to_ktime((u64)LOW_TEMPERATURE_CHECK_PERIOD * NSEC_PER_MSEC), HRTIMER_MODE_REL);
}
}
}
end:
pTAS2557->mnNewConfiguration = pTAS2557->mnCurrentConfiguration;
return nResult;
}
int tas2557_update_edge(struct tas2557_priv *pTAS2557)
{
int nResult = 0;
dev_dbg(pTAS2557->dev,
"%s, edge: %d\n",
__func__, pTAS2557->mnEdge);
nResult = pTAS2557->update_bits(pTAS2557, TAS2557_SPK_CTRL_REG, 0x7, pTAS2557->mnEdge);
return nResult;
}
int tas2557_enable(struct tas2557_priv *pTAS2557, bool bEnable)
{
int nResult = 0;
unsigned int nValue;
const char *pFWName;
struct TProgram *pProgram;
dev_dbg(pTAS2557->dev, "Enable: %d\n", bEnable);
if ((pTAS2557->mpFirmware->mnPrograms == 0)
|| (pTAS2557->mpFirmware->mnConfigurations == 0)) {
dev_err(pTAS2557->dev, "%s, firmware not loaded\n", __func__);
/*Load firmware*/
if (pTAS2557->mnPGID == TAS2557_PG_VERSION_2P1) {
dev_info(pTAS2557->dev, "PG2.1 Silicon found\n");
pFWName = TAS2557_FW_NAME;
} else if (pTAS2557->mnPGID == TAS2557_PG_VERSION_1P0) {
dev_info(pTAS2557->dev, "PG1.0 Silicon found\n");
pFWName = TAS2557_PG1P0_FW_NAME;
} else {
nResult = -ENOTSUPP;
dev_info(pTAS2557->dev, "unsupport Silicon 0x%x\n", pTAS2557->mnPGID);
goto end;
}
nResult = request_firmware_nowait(THIS_MODULE, 1, pFWName,
pTAS2557->dev, GFP_KERNEL, pTAS2557, tas2557_fw_ready);
if(nResult < 0)
goto end;
dev_err(pTAS2557->dev, "%s, firmware is loaded\n", __func__);
}
/* check safe guard*/
nResult = pTAS2557->read(pTAS2557, TAS2557_SAFE_GUARD_REG, &nValue);
if (nResult < 0)
goto end;
if ((nValue&0xff) != TAS2557_SAFE_GUARD_PATTERN) {
dev_err(pTAS2557->dev, "ERROR safe guard failure!\n");
nResult = -EPIPE;
pTAS2557->mnErrCode = ERROR_SAFE_GUARD;
pTAS2557->mbPowerUp = true;
goto end;
}
pProgram = &(pTAS2557->mpFirmware->mpPrograms[pTAS2557->mnCurrentProgram]);
if (bEnable) {
if (!pTAS2557->mbPowerUp) {
if (!pTAS2557->mbCalibrationLoaded) {
tas2557_set_calibration(pTAS2557, 0xFF);
pTAS2557->mbCalibrationLoaded = true;
}
if (pTAS2557->mbLoadConfigurationPrePowerUp) {
dev_dbg(pTAS2557->dev, "load coefficient before power\n");
pTAS2557->mbLoadConfigurationPrePowerUp = false;
nResult = tas2557_load_coefficient(pTAS2557,
pTAS2557->mnCurrentConfiguration, pTAS2557->mnNewConfiguration, false);
if (nResult < 0)
goto end;
}
pTAS2557->clearIRQ(pTAS2557);
/* power on device */
dev_dbg(pTAS2557->dev, "Enable: load startup sequence\n");
nResult = tas2557_dev_load_data(pTAS2557, p_tas2557_startup_data);
if (nResult < 0)
goto end;
if (pProgram->mnAppMode == TAS2557_APP_TUNINGMODE) {
nResult = tas2557_checkPLL(pTAS2557);
if (nResult < 0) {
nResult = tas2557_dev_load_data(pTAS2557, p_tas2557_shutdown_data);
goto end;
}
}
dev_dbg(pTAS2557->dev, "Enable: load unmute sequence\n");
nResult = tas2557_dev_load_data(pTAS2557, p_tas2557_unmute_data);
if (nResult < 0)
goto end;
pTAS2557->mbPowerUp = true;
tas2557_get_die_temperature(pTAS2557, &nValue);
if(nValue == 0x80000000)
{
dev_err(pTAS2557->dev, "%s, thermal sensor is wrong, mute output\n", __func__);
nResult = tas2557_dev_load_data(pTAS2557, p_tas2557_shutdown_data);
pTAS2557->mbPowerUp = false;
goto end;
}
if (pProgram->mnAppMode == TAS2557_APP_TUNINGMODE) {
/* turn on IRQ */
pTAS2557->enableIRQ(pTAS2557, true, true);
if (!hrtimer_active(&pTAS2557->mtimer)) {
pTAS2557->mnDieTvReadCounter = 0;
hrtimer_start(&pTAS2557->mtimer,
ns_to_ktime((u64)LOW_TEMPERATURE_CHECK_PERIOD * NSEC_PER_MSEC), HRTIMER_MODE_REL);
}
}
pTAS2557->mnRestart = 0;
}
} else {
if (pTAS2557->mbPowerUp) {
if (hrtimer_active(&pTAS2557->mtimer))
hrtimer_cancel(&pTAS2557->mtimer);
dev_dbg(pTAS2557->dev, "Enable: load shutdown sequence\n");
if (pProgram->mnAppMode == TAS2557_APP_TUNINGMODE) {
/* turn off IRQ */
pTAS2557->enableIRQ(pTAS2557, false, false);
}
nResult = tas2557_dev_load_data(pTAS2557, p_tas2557_shutdown_data);
if (nResult < 0)
goto end;
pTAS2557->mbPowerUp = false;
pTAS2557->mnRestart = 0;
}
}
nResult = 0;
end:
if (nResult < 0) {
if (pTAS2557->mnErrCode & (ERROR_DEVA_I2C_COMM | ERROR_PRAM_CRCCHK | ERROR_YRAM_CRCCHK | ERROR_SAFE_GUARD))
failsafe(pTAS2557);
}
return nResult;
}
int tas2557_set_sampling_rate(struct tas2557_priv *pTAS2557, unsigned int nSamplingRate)
{
int nResult = 0;
struct TConfiguration *pConfiguration;
unsigned int nConfiguration;
dev_dbg(pTAS2557->dev, "tas2557_setup_clocks: nSamplingRate = %d [Hz]\n",
nSamplingRate);
if ((!pTAS2557->mpFirmware->mpPrograms) ||
(!pTAS2557->mpFirmware->mpConfigurations)) {
dev_err(pTAS2557->dev, "Firmware not loaded\n");
nResult = -EINVAL;
goto end;
}
pConfiguration = &(pTAS2557->mpFirmware->mpConfigurations[pTAS2557->mnCurrentConfiguration]);
if (pConfiguration->mnSamplingRate == nSamplingRate) {
dev_info(pTAS2557->dev, "Sampling rate for current configuration matches: %d\n",
nSamplingRate);
nResult = 0;
goto end;
}
for (nConfiguration = 0;
nConfiguration < pTAS2557->mpFirmware->mnConfigurations;
nConfiguration++) {
pConfiguration =
&(pTAS2557->mpFirmware->mpConfigurations[nConfiguration]);
if ((pConfiguration->mnSamplingRate == nSamplingRate)
&& (pConfiguration->mnProgram == pTAS2557->mnCurrentProgram)) {
dev_info(pTAS2557->dev,
"Found configuration: %s, with compatible sampling rate %d\n",
pConfiguration->mpName, nSamplingRate);
nResult = tas2557_load_configuration(pTAS2557, nConfiguration, false);
goto end;
}
}
dev_err(pTAS2557->dev, "Cannot find a configuration that supports sampling rate: %d\n",
nSamplingRate);
end:
return nResult;
}
static void fw_print_header(struct tas2557_priv *pTAS2557, struct TFirmware *pFirmware)
{
dev_info(pTAS2557->dev, "FW Size = %d", pFirmware->mnFWSize);
dev_info(pTAS2557->dev, "Checksum = 0x%04X", pFirmware->mnChecksum);
dev_info(pTAS2557->dev, "PPC Version = 0x%04X", pFirmware->mnPPCVersion);
dev_info(pTAS2557->dev, "FW Version = 0x%04X", pFirmware->mnFWVersion);
dev_info(pTAS2557->dev, "Driver Version= 0x%04X", pFirmware->mnDriverVersion);
dev_info(pTAS2557->dev, "Timestamp = %d", pFirmware->mnTimeStamp);
dev_info(pTAS2557->dev, "DDC Name = %s", pFirmware->mpDDCName);
dev_info(pTAS2557->dev, "Description = %s", pFirmware->mpDescription);
}
inline unsigned int fw_convert_number(unsigned char *pData)
{
return pData[3] + (pData[2] << 8) + (pData[1] << 16) + (pData[0] << 24);
}
static int fw_parse_header(struct tas2557_priv *pTAS2557,
struct TFirmware *pFirmware, unsigned char *pData, unsigned int nSize)
{
unsigned char *pDataStart = pData;
unsigned int n;
unsigned char pMagicNumber[] = { 0x35, 0x35, 0x35, 0x32 };
if (nSize < 104) {
dev_err(pTAS2557->dev, "Firmware: Header too short");
return -EINVAL;
}
if (memcmp(pData, pMagicNumber, 4)) {
dev_err(pTAS2557->dev, "Firmware: Magic number doesn't match");
return -EINVAL;
}
pData += 4;
pFirmware->mnFWSize = fw_convert_number(pData);
pData += 4;
pFirmware->mnChecksum = fw_convert_number(pData);
pData += 4;
pFirmware->mnPPCVersion = fw_convert_number(pData);
pData += 4;
pFirmware->mnFWVersion = fw_convert_number(pData);
pData += 4;
pFirmware->mnDriverVersion = fw_convert_number(pData);
pData += 4;
pFirmware->mnTimeStamp = fw_convert_number(pData);
pData += 4;
memcpy(pFirmware->mpDDCName, pData, 64);
pData += 64;
n = strlen(pData);
pFirmware->mpDescription = kmemdup(pData, n + 1, GFP_KERNEL);
pData += n + 1;
if ((pData - pDataStart) >= nSize) {
dev_err(pTAS2557->dev, "Firmware: Header too short after DDC description");
return -EINVAL;
}
pFirmware->mnDeviceFamily = fw_convert_number(pData);
pData += 4;
if (pFirmware->mnDeviceFamily != 0) {
dev_err(pTAS2557->dev,
"deviceFamily %d, not TAS device", pFirmware->mnDeviceFamily);
return -EINVAL;
}
pFirmware->mnDevice = fw_convert_number(pData);
pData += 4;
if (pFirmware->mnDevice != 2) {
dev_err(pTAS2557->dev,
"device %d, not TAS2557 Dual Mono", pFirmware->mnDevice);
return -EINVAL;
}
fw_print_header(pTAS2557, pFirmware);
return pData - pDataStart;
}
static int fw_parse_block_data(struct tas2557_priv *pTAS2557, struct TFirmware *pFirmware,
struct TBlock *pBlock, unsigned char *pData)
{
unsigned char *pDataStart = pData;
unsigned int n;
pBlock->mnType = fw_convert_number(pData);
pData += 4;
if (pFirmware->mnDriverVersion >= PPC_DRIVER_CRCCHK) {
pBlock->mbPChkSumPresent = pData[0];
pData++;
pBlock->mnPChkSum = pData[0];
pData++;
pBlock->mbYChkSumPresent = pData[0];
pData++;
pBlock->mnYChkSum = pData[0];
pData++;
} else {
pBlock->mbPChkSumPresent = 0;
pBlock->mbYChkSumPresent = 0;
}
pBlock->mnCommands = fw_convert_number(pData);
pData += 4;
n = pBlock->mnCommands * 4;
pBlock->mpData = kmemdup(pData, n, GFP_KERNEL);
pData += n;
return pData - pDataStart;
}
static int fw_parse_data(struct tas2557_priv *pTAS2557, struct TFirmware *pFirmware,
struct TData *pImageData, unsigned char *pData)
{
unsigned char *pDataStart = pData;
unsigned int nBlock;
unsigned int n;
memcpy(pImageData->mpName, pData, 64);
pData += 64;
n = strlen(pData);
pImageData->mpDescription = kmemdup(pData, n + 1, GFP_KERNEL);
pData += n + 1;
pImageData->mnBlocks = (pData[0] << 8) + pData[1];
pData += 2;
pImageData->mpBlocks =
kmalloc(sizeof(struct TBlock) * pImageData->mnBlocks, GFP_KERNEL);
if(pImageData->mpBlocks == NULL)
{
dev_dbg(pTAS2557->dev, "failed malloc blocks mem\n");
goto end;
}
for (nBlock = 0; nBlock < pImageData->mnBlocks; nBlock++) {
n = fw_parse_block_data(pTAS2557, pFirmware,
&(pImageData->mpBlocks[nBlock]), pData);
pData += n;
}
end: //[FairPhone][Audio][jinjia]=2020.05.19=Fix the build error with TI sample code.
return pData - pDataStart;
}
static int fw_parse_pll_data(struct tas2557_priv *pTAS2557,
struct TFirmware *pFirmware, unsigned char *pData)
{
unsigned char *pDataStart = pData;
unsigned int n;
unsigned int nPLL;
struct TPLL *pPLL;
pFirmware->mnPLLs = (pData[0] << 8) + pData[1];
pData += 2;
if (pFirmware->mnPLLs == 0)
goto end;
pFirmware->mpPLLs = kmalloc_array(pFirmware->mnPLLs, sizeof(struct TPLL), GFP_KERNEL);
for (nPLL = 0; nPLL < pFirmware->mnPLLs; nPLL++) {
pPLL = &(pFirmware->mpPLLs[nPLL]);
memcpy(pPLL->mpName, pData, 64);
pData += 64;
n = strlen(pData);
pPLL->mpDescription = kmemdup(pData, n + 1, GFP_KERNEL);
pData += n + 1;
n = fw_parse_block_data(pTAS2557, pFirmware, &(pPLL->mBlock), pData);
pData += n;
}
end:
return pData - pDataStart;
}
static int fw_parse_program_data(struct tas2557_priv *pTAS2557,
struct TFirmware *pFirmware, unsigned char *pData)
{
unsigned char *pDataStart = pData;
unsigned int n;
unsigned int nProgram;
struct TProgram *pProgram;
pFirmware->mnPrograms = (pData[0] << 8) + pData[1];
pData += 2;
if (pFirmware->mnPrograms == 0)
goto end;
pFirmware->mpPrograms =
kmalloc(sizeof(struct TProgram) * pFirmware->mnPrograms, GFP_KERNEL);
if(pFirmware->mpPrograms == NULL)
{
dev_dbg(pTAS2557->dev, "failed malloc program mem\n");
goto end;
}
for (nProgram = 0; nProgram < pFirmware->mnPrograms; nProgram++) {
pProgram = &(pFirmware->mpPrograms[nProgram]);
memcpy(pProgram->mpName, pData, 64);
pData += 64;
n = strlen(pData);
pProgram->mpDescription = kmemdup(pData, n + 1, GFP_KERNEL);
pData += n + 1;
pProgram->mnAppMode = pData[0];
pData++;
pProgram->mnBoost = (pData[0] << 8) + pData[1];
pData += 2;
n = fw_parse_data(pTAS2557, pFirmware, &(pProgram->mData), pData);
pData += n;
}
end:
return pData - pDataStart;
}
static int fw_parse_configuration_data(struct tas2557_priv *pTAS2557,
struct TFirmware *pFirmware, unsigned char *pData)
{
unsigned char *pDataStart = pData;
unsigned int n;
unsigned int nConfiguration;
struct TConfiguration *pConfiguration;
pFirmware->mnConfigurations = (pData[0] << 8) + pData[1];
pData += 2;
if (pFirmware->mnConfigurations == 0)
goto end;
pFirmware->mpConfigurations =
kmalloc(sizeof(struct TConfiguration) * pFirmware->mnConfigurations,
GFP_KERNEL);
if(pFirmware->mpConfigurations == NULL)
{
dev_dbg(pTAS2557->dev, "failed malloc configuration mem\n");
goto end;
}
for (nConfiguration = 0; nConfiguration < pFirmware->mnConfigurations;
nConfiguration++) {
pConfiguration = &(pFirmware->mpConfigurations[nConfiguration]);
memcpy(pConfiguration->mpName, pData, 64);
pData += 64;
n = strlen(pData);
pConfiguration->mpDescription = kmemdup(pData, n + 1, GFP_KERNEL);
pData += n + 1;
if ((pFirmware->mnDriverVersion >= PPC_DRIVER_CONFDEV)
|| ((pFirmware->mnDriverVersion >= PPC_DRIVER_CFGDEV_NONCRC)
&& (pFirmware->mnDriverVersion < PPC_DRIVER_CRCCHK))) {
pConfiguration->mnDevices = (pData[0] << 8) + pData[1];
pData += 2;
} else
pConfiguration->mnDevices = 1;
pConfiguration->mnProgram = pData[0];
pData++;
pConfiguration->mnPLL = pData[0];
pData++;
pConfiguration->mnSamplingRate = fw_convert_number(pData);
pData += 4;
if (pFirmware->mnDriverVersion >= PPC_DRIVER_MTPLLSRC) {
pConfiguration->mnPLLSrc = pData[0];
pData++;
pConfiguration->mnPLLSrcRate = fw_convert_number(pData);
pData += 4;
}
n = fw_parse_data(pTAS2557, pFirmware, &(pConfiguration->mData), pData);
pData += n;
}
end:
return pData - pDataStart;
}
int fw_parse_calibration_data(struct tas2557_priv *pTAS2557,
struct TFirmware *pFirmware, unsigned char *pData)
{
unsigned char *pDataStart = pData;
unsigned int n;
unsigned int nCalibration;
struct TCalibration *pCalibration;
pFirmware->mnCalibrations = (pData[0] << 8) + pData[1];
pData += 2;
if (pFirmware->mnCalibrations == 0)
goto end;
pFirmware->mpCalibrations =
kmalloc(sizeof(struct TCalibration) * pFirmware->mnCalibrations, GFP_KERNEL);
if(pFirmware->mpCalibrations == NULL)
{
dev_err(pTAS2557->dev, "failed to malloc calibration mem\n");
goto end;
}
for (nCalibration = 0;
nCalibration < pFirmware->mnCalibrations;
nCalibration++) {
pCalibration = &(pFirmware->mpCalibrations[nCalibration]);
memcpy(pCalibration->mpName, pData, 64);
pData += 64;
n = strlen(pData);
pCalibration->mpDescription = kmemdup(pData, n + 1, GFP_KERNEL);
pData += n + 1;
pCalibration->mnProgram = pData[0];
pData++;
pCalibration->mnConfiguration = pData[0];
pData++;
n = fw_parse_data(pTAS2557, pFirmware, &(pCalibration->mData), pData);
pData += n;
}
end:
return pData - pDataStart;
}
static int fw_parse(struct tas2557_priv *pTAS2557,
struct TFirmware *pFirmware, unsigned char *pData, unsigned int nSize)
{
int nPosition = 0;
nPosition = fw_parse_header(pTAS2557, pFirmware, pData, nSize);
if (nPosition < 0) {
dev_err(pTAS2557->dev, "Firmware: Wrong Header");
return -EINVAL;
}
if (nPosition >= nSize) {
dev_err(pTAS2557->dev, "Firmware: Too short");
return -EINVAL;
}
pData += nPosition;
nSize -= nPosition;
nPosition = 0;
nPosition = fw_parse_pll_data(pTAS2557, pFirmware, pData);
pData += nPosition;
nSize -= nPosition;
nPosition = 0;
nPosition = fw_parse_program_data(pTAS2557, pFirmware, pData);
pData += nPosition;
nSize -= nPosition;
nPosition = 0;
nPosition = fw_parse_configuration_data(pTAS2557, pFirmware, pData);
pData += nPosition;
nSize -= nPosition;
nPosition = 0;
if (nSize > 64)
nPosition = fw_parse_calibration_data(pTAS2557, pFirmware, pData);
return 0;
}
static const unsigned char crc8_lookup_table[CRC8_TABLE_SIZE] = {
0x00, 0x4D, 0x9A, 0xD7, 0x79, 0x34, 0xE3, 0xAE, 0xF2, 0xBF, 0x68, 0x25, 0x8B, 0xC6, 0x11, 0x5C,
0xA9, 0xE4, 0x33, 0x7E, 0xD0, 0x9D, 0x4A, 0x07, 0x5B, 0x16, 0xC1, 0x8C, 0x22, 0x6F, 0xB8, 0xF5,
0x1F, 0x52, 0x85, 0xC8, 0x66, 0x2B, 0xFC, 0xB1, 0xED, 0xA0, 0x77, 0x3A, 0x94, 0xD9, 0x0E, 0x43,
0xB6, 0xFB, 0x2C, 0x61, 0xCF, 0x82, 0x55, 0x18, 0x44, 0x09, 0xDE, 0x93, 0x3D, 0x70, 0xA7, 0xEA,
0x3E, 0x73, 0xA4, 0xE9, 0x47, 0x0A, 0xDD, 0x90, 0xCC, 0x81, 0x56, 0x1B, 0xB5, 0xF8, 0x2F, 0x62,
0x97, 0xDA, 0x0D, 0x40, 0xEE, 0xA3, 0x74, 0x39, 0x65, 0x28, 0xFF, 0xB2, 0x1C, 0x51, 0x86, 0xCB,
0x21, 0x6C, 0xBB, 0xF6, 0x58, 0x15, 0xC2, 0x8F, 0xD3, 0x9E, 0x49, 0x04, 0xAA, 0xE7, 0x30, 0x7D,
0x88, 0xC5, 0x12, 0x5F, 0xF1, 0xBC, 0x6B, 0x26, 0x7A, 0x37, 0xE0, 0xAD, 0x03, 0x4E, 0x99, 0xD4,
0x7C, 0x31, 0xE6, 0xAB, 0x05, 0x48, 0x9F, 0xD2, 0x8E, 0xC3, 0x14, 0x59, 0xF7, 0xBA, 0x6D, 0x20,
0xD5, 0x98, 0x4F, 0x02, 0xAC, 0xE1, 0x36, 0x7B, 0x27, 0x6A, 0xBD, 0xF0, 0x5E, 0x13, 0xC4, 0x89,
0x63, 0x2E, 0xF9, 0xB4, 0x1A, 0x57, 0x80, 0xCD, 0x91, 0xDC, 0x0B, 0x46, 0xE8, 0xA5, 0x72, 0x3F,
0xCA, 0x87, 0x50, 0x1D, 0xB3, 0xFE, 0x29, 0x64, 0x38, 0x75, 0xA2, 0xEF, 0x41, 0x0C, 0xDB, 0x96,
0x42, 0x0F, 0xD8, 0x95, 0x3B, 0x76, 0xA1, 0xEC, 0xB0, 0xFD, 0x2A, 0x67, 0xC9, 0x84, 0x53, 0x1E,
0xEB, 0xA6, 0x71, 0x3C, 0x92, 0xDF, 0x08, 0x45, 0x19, 0x54, 0x83, 0xCE, 0x60, 0x2D, 0xFA, 0xB7,
0x5D, 0x10, 0xC7, 0x8A, 0x24, 0x69, 0xBE, 0xF3, 0xAF, 0xE2, 0x35, 0x78, 0xD6, 0x9B, 0x4C, 0x01,
0xF4, 0xB9, 0x6E, 0x23, 0x8D, 0xC0, 0x17, 0x5A, 0x06, 0x4B, 0x9C, 0xD1, 0x7F, 0x32, 0xE5, 0xA8
};
static int isInPageYRAM(struct tas2557_priv *pTAS2557, struct TYCRC *pCRCData,
unsigned char nBook, unsigned char nPage, unsigned char nReg, unsigned char len)
{
int nResult = 0;
if (nBook == TAS2557_YRAM_BOOK1) {
if (nPage == TAS2557_YRAM1_PAGE) {
if (nReg >= TAS2557_YRAM1_START_REG) {
pCRCData->mnOffset = nReg;
pCRCData->mnLen = len;
nResult = 1;
} else if ((nReg + len) > TAS2557_YRAM1_START_REG) {
pCRCData->mnOffset = TAS2557_YRAM1_START_REG;
pCRCData->mnLen = len - (TAS2557_YRAM1_START_REG - nReg);
nResult = 1;
} else
nResult = 0;
} else if (nPage == TAS2557_YRAM3_PAGE) {
if (nReg > TAS2557_YRAM3_END_REG) {
nResult = 0;
} else if (nReg >= TAS2557_YRAM3_START_REG) {
if ((nReg + len) > TAS2557_YRAM3_END_REG) {
pCRCData->mnOffset = nReg;
pCRCData->mnLen = TAS2557_YRAM3_END_REG - nReg + 1;
nResult = 1;
} else {
pCRCData->mnOffset = nReg;
pCRCData->mnLen = len;
nResult = 1;
}
} else {
if ((nReg + (len - 1)) < TAS2557_YRAM3_START_REG)
nResult = 0;
else {
pCRCData->mnOffset = TAS2557_YRAM3_START_REG;
pCRCData->mnLen = len - (TAS2557_YRAM3_START_REG - nReg);
nResult = 1;
}
}
}
} else if (nBook == TAS2557_YRAM_BOOK2) {
if (nPage == TAS2557_YRAM5_PAGE) {
if (nReg > TAS2557_YRAM5_END_REG) {
nResult = 0;
} else if (nReg >= TAS2557_YRAM5_START_REG) {
if ((nReg + len) > TAS2557_YRAM5_END_REG) {
pCRCData->mnOffset = nReg;
pCRCData->mnLen = TAS2557_YRAM5_END_REG - nReg + 1;
nResult = 1;
} else {
pCRCData->mnOffset = nReg;
pCRCData->mnLen = len;
nResult = 1;
}
} else {
if ((nReg + (len - 1)) < TAS2557_YRAM5_START_REG)
nResult = 0;
else {
pCRCData->mnOffset = TAS2557_YRAM5_START_REG;
pCRCData->mnLen = len - (TAS2557_YRAM5_START_REG - nReg);
nResult = 1;
}
}
}
} else
nResult = 0;
return nResult;
}
static int isInBlockYRAM(struct tas2557_priv *pTAS2557, struct TYCRC *pCRCData,
unsigned char nBook, unsigned char nPage, unsigned char nReg, unsigned char len)
{
int nResult;
if (nBook == TAS2557_YRAM_BOOK1) {
if (nPage < TAS2557_YRAM2_START_PAGE)
nResult = 0;
else if (nPage <= TAS2557_YRAM2_END_PAGE) {
if (nReg > TAS2557_YRAM2_END_REG)
nResult = 0;
else if (nReg >= TAS2557_YRAM2_START_REG) {
pCRCData->mnOffset = nReg;
pCRCData->mnLen = len;
nResult = 1;
} else {
if ((nReg + (len - 1)) < TAS2557_YRAM2_START_REG)
nResult = 0;
else {
pCRCData->mnOffset = TAS2557_YRAM2_START_REG;
pCRCData->mnLen = nReg + len - TAS2557_YRAM2_START_REG;
nResult = 1;
}
}
} else
nResult = 0;
} else if (nBook == TAS2557_YRAM_BOOK2) {
if (nPage < TAS2557_YRAM4_START_PAGE)
nResult = 0;
else if (nPage <= TAS2557_YRAM4_END_PAGE) {
if (nReg > TAS2557_YRAM2_END_REG)
nResult = 0;
else if (nReg >= TAS2557_YRAM2_START_REG) {
pCRCData->mnOffset = nReg;
pCRCData->mnLen = len;
nResult = 1;
} else {
if ((nReg + (len - 1)) < TAS2557_YRAM2_START_REG)
nResult = 0;
else {
pCRCData->mnOffset = TAS2557_YRAM2_START_REG;
pCRCData->mnLen = nReg + len - TAS2557_YRAM2_START_REG;
nResult = 1;
}
}
} else
nResult = 0;
} else
nResult = 0;
return nResult;
}
static int isYRAM(struct tas2557_priv *pTAS2557, struct TYCRC *pCRCData,
unsigned char nBook, unsigned char nPage, unsigned char nReg, unsigned char len)
{
int nResult;
nResult = isInPageYRAM(pTAS2557, pCRCData, nBook, nPage, nReg, len);
if (nResult == 0)
nResult = isInBlockYRAM(pTAS2557, pCRCData, nBook, nPage, nReg, len);
return nResult;
}
/*
* crc8 - calculate a crc8 over the given input data.
*
* table: crc table used for calculation.
* pdata: pointer to data buffer.
* nbytes: number of bytes in data buffer.
* crc: previous returned crc8 value.
*/
static u8 ti_crc8(const u8 table[CRC8_TABLE_SIZE], u8 *pdata, size_t nbytes, u8 crc)
{
/* loop over the buffer data */
while (nbytes-- > 0)
crc = table[(crc ^ *pdata++) & 0xff];
return crc;
}
static int doSingleRegCheckSum(struct tas2557_priv *pTAS2557,
unsigned char nBook, unsigned char nPage, unsigned char nReg, unsigned char nValue)
{
int nResult = 0;
struct TYCRC sCRCData;
unsigned int nData1 = 0;
if ((nBook == TAS2557_BOOK_ID(TAS2557_SA_COEFF_SWAP_REG))
&& (nPage == TAS2557_PAGE_ID(TAS2557_SA_COEFF_SWAP_REG))
&& (nReg >= TAS2557_PAGE_REG(TAS2557_SA_COEFF_SWAP_REG))
&& (nReg <= (TAS2557_PAGE_REG(TAS2557_SA_COEFF_SWAP_REG) + 4))) {
/* DSP swap command, pass */
nResult = 0;
goto end;
}
nResult = isYRAM(pTAS2557, &sCRCData, nBook, nPage, nReg, 1);
if (nResult == 1) {
nResult = pTAS2557->read(pTAS2557, TAS2557_REG(nBook, nPage, nReg), &nData1);
if (nResult < 0)
goto end;
if (nData1 != nValue) {
dev_err(pTAS2557->dev, "error2 (line %d),B[0x%x]P[0x%x]R[0x%x] W[0x%x], R[0x%x]\n",
__LINE__, nBook, nPage, nReg, nValue, nData1);
nResult = -EAGAIN;
goto end;
}
nResult = ti_crc8(crc8_lookup_table, &nValue, 1, 0);
}
end:
return nResult;
}
static int doMultiRegCheckSum(struct tas2557_priv *pTAS2557,
unsigned char nBook, unsigned char nPage, unsigned char nReg, unsigned int len)
{
int nResult = 0, i;
unsigned char nCRCChkSum = 0;
unsigned char nBuf1[128];
struct TYCRC TCRCData;
if ((nReg + len-1) > 127) {
nResult = -EINVAL;
dev_err(pTAS2557->dev, "firmware error\n");
goto end;
}
if ((nBook == TAS2557_BOOK_ID(TAS2557_SA_COEFF_SWAP_REG))
&& (nPage == TAS2557_PAGE_ID(TAS2557_SA_COEFF_SWAP_REG))
&& (nReg == TAS2557_PAGE_REG(TAS2557_SA_COEFF_SWAP_REG))
&& (len == 4)) {
/* DSP swap command, pass */
nResult = 0;
goto end;
}
nResult = isYRAM(pTAS2557, &TCRCData, nBook, nPage, nReg, len);
if (nResult == 1) {
if (len == 1) {
dev_err(pTAS2557->dev, "firmware error\n");
nResult = -EINVAL;
goto end;
} else {
nResult = pTAS2557->bulk_read(pTAS2557, TAS2557_REG(nBook, nPage, TCRCData.mnOffset), nBuf1, TCRCData.mnLen);
if (nResult < 0)
goto end;
for (i = 0; i < TCRCData.mnLen; i++) {
if ((nBook == TAS2557_BOOK_ID(TAS2557_SA_COEFF_SWAP_REG))
&& (nPage == TAS2557_PAGE_ID(TAS2557_SA_COEFF_SWAP_REG))
&& ((i + TCRCData.mnOffset)
>= TAS2557_PAGE_REG(TAS2557_SA_COEFF_SWAP_REG))
&& ((i + TCRCData.mnOffset)
<= (TAS2557_PAGE_REG(TAS2557_SA_COEFF_SWAP_REG) + 4))) {
/* DSP swap command, bypass */
continue;
} else
nCRCChkSum += ti_crc8(crc8_lookup_table, &nBuf1[i], 1, 0);
}
nResult = nCRCChkSum;
}
}
end:
return nResult;
}
static int tas2557_load_block(struct tas2557_priv *pTAS2557, struct TBlock *pBlock)
{
int nResult = 0;
unsigned int nCommand = 0;
unsigned char nBook;
unsigned char nPage;
unsigned char nOffset;
unsigned char nData;
unsigned int nLength;
unsigned int nSleep;
unsigned char nCRCChkSum = 0;
unsigned int nValue1;
int nRetry = 6;
unsigned char *pData = pBlock->mpData;
dev_dbg(pTAS2557->dev, "TAS2557 load block: Type = %d, commands = %d\n",
pBlock->mnType, pBlock->mnCommands);
start:
if (pBlock->mbPChkSumPresent) {
nResult = pTAS2557->write(pTAS2557, TAS2557_CRC_RESET_REG, 1);
if (nResult < 0)
goto end;
}
if (pBlock->mbYChkSumPresent)
nCRCChkSum = 0;
nCommand = 0;
while (nCommand < pBlock->mnCommands) {
pData = pBlock->mpData + nCommand * 4;
nBook = pData[0];
nPage = pData[1];
nOffset = pData[2];
nData = pData[3];
nCommand++;
if (nOffset <= 0x7F) {
nResult = pTAS2557->write(pTAS2557, TAS2557_REG(nBook, nPage, nOffset), nData);
if (nResult < 0)
goto end;
if (pBlock->mbYChkSumPresent) {
nResult = doSingleRegCheckSum(pTAS2557, nBook, nPage, nOffset, nData);
if (nResult < 0)
goto check;
nCRCChkSum += (unsigned char)nResult;
}
} else if (nOffset == 0x81) {
nSleep = (nBook << 8) + nPage;
msleep(nSleep);
} else if (nOffset == 0x85) {
pData += 4;
nLength = (nBook << 8) + nPage;
nBook = pData[0];
nPage = pData[1];
nOffset = pData[2];
if (nLength > 1) {
nResult = pTAS2557->bulk_write(pTAS2557, TAS2557_REG(nBook, nPage, nOffset), pData + 3, nLength);
if (nResult < 0)
goto end;
if (pBlock->mbYChkSumPresent) {
nResult = doMultiRegCheckSum(pTAS2557, nBook, nPage, nOffset, nLength);
if (nResult < 0)
goto check;
nCRCChkSum += (unsigned char)nResult;
}
} else {
nResult = pTAS2557->write(pTAS2557, TAS2557_REG(nBook, nPage, nOffset), pData[3]);
if (nResult < 0)
goto end;
if (pBlock->mbYChkSumPresent) {
nResult = doSingleRegCheckSum(pTAS2557, nBook, nPage, nOffset, pData[3]);
if (nResult < 0)
goto check;
nCRCChkSum += (unsigned char)nResult;
}
}
nCommand++;
if (nLength >= 2)
nCommand += ((nLength - 2) / 4) + 1;
}
}
if (pBlock->mbPChkSumPresent) {
nResult = pTAS2557->read(pTAS2557, TAS2557_CRC_CHECKSUM_REG, &nValue1);
if (nResult < 0)
goto end;
if ((nValue1&0xff) != pBlock->mnPChkSum) {
dev_err(pTAS2557->dev, "Block PChkSum Error: FW = 0x%x, Reg = 0x%x\n",
pBlock->mnPChkSum, (nValue1&0xff));
nResult = -EAGAIN;
pTAS2557->mnErrCode |= ERROR_PRAM_CRCCHK;
goto check;
}
nResult = 0;
pTAS2557->mnErrCode &= ~ERROR_PRAM_CRCCHK;
dev_dbg(pTAS2557->dev, "Block[0x%x] PChkSum match\n", pBlock->mnType);
}
if (pBlock->mbYChkSumPresent) {
if (nCRCChkSum != pBlock->mnYChkSum) {
dev_err(pTAS2557->dev, "Block YChkSum Error: FW = 0x%x, YCRC = 0x%x\n",
pBlock->mnYChkSum, nCRCChkSum);
nResult = -EAGAIN;
pTAS2557->mnErrCode |= ERROR_YRAM_CRCCHK;
goto check;
}
pTAS2557->mnErrCode &= ~ERROR_YRAM_CRCCHK;
nResult = 0;
dev_dbg(pTAS2557->dev, "Block[0x%x] YChkSum match\n", pBlock->mnType);
}
check:
if (nResult == -EAGAIN) {
nRetry--;
if (nRetry > 0)
goto start;
}
end:
if (nResult < 0) {
dev_err(pTAS2557->dev, "Block (%d) load error\n",
pBlock->mnType);
}
return nResult;
}
static int tas2557_load_data(struct tas2557_priv *pTAS2557, struct TData *pData, unsigned int nType)
{
int nResult = 0;
unsigned int nBlock;
struct TBlock *pBlock;
dev_dbg(pTAS2557->dev,
"TAS2557 load data: %s, Blocks = %d, Block Type = %d\n", pData->mpName, pData->mnBlocks, nType);
for (nBlock = 0; nBlock < pData->mnBlocks; nBlock++) {
pBlock = &(pData->mpBlocks[nBlock]);
if (pBlock->mnType == nType) {
nResult = tas2557_load_block(pTAS2557, pBlock);
if (nResult < 0)
break;
}
}
return nResult;
}
static int tas2557_load_configuration(struct tas2557_priv *pTAS2557,
unsigned int nConfiguration, bool bLoadSame)
{
int nResult = 0;
struct TConfiguration *pCurrentConfiguration = NULL;
struct TConfiguration *pNewConfiguration = NULL;
dev_dbg(pTAS2557->dev, "%s: %d\n", __func__, nConfiguration);
if ((!pTAS2557->mpFirmware->mpPrograms) ||
(!pTAS2557->mpFirmware->mpConfigurations)) {
dev_err(pTAS2557->dev, "Firmware not loaded\n");
nResult = 0;
goto end;
}
if (nConfiguration >= pTAS2557->mpFirmware->mnConfigurations) {
dev_err(pTAS2557->dev, "Configuration %d doesn't exist\n",
nConfiguration);
nResult = 0;
goto end;
}
if ((!pTAS2557->mbLoadConfigurationPrePowerUp)
&& (nConfiguration == pTAS2557->mnCurrentConfiguration)
&& (!bLoadSame)) {
dev_info(pTAS2557->dev, "Configuration %d is already loaded\n",
nConfiguration);
nResult = 0;
goto end;
}
pCurrentConfiguration =
&(pTAS2557->mpFirmware->mpConfigurations[pTAS2557->mnCurrentConfiguration]);
pNewConfiguration =
&(pTAS2557->mpFirmware->mpConfigurations[nConfiguration]);
if (pNewConfiguration->mnProgram != pCurrentConfiguration->mnProgram) {
dev_err(pTAS2557->dev, "Configuration %d, %s doesn't share the same program as current %d\n",
nConfiguration, pNewConfiguration->mpName, pCurrentConfiguration->mnProgram);
nResult = 0;
goto end;
}
if (pNewConfiguration->mnPLL >= pTAS2557->mpFirmware->mnPLLs) {
dev_err(pTAS2557->dev, "Configuration %d, %s doesn't have a valid PLL index %d\n",
nConfiguration, pNewConfiguration->mpName, pNewConfiguration->mnPLL);
nResult = 0;
goto end;
}
if (pTAS2557->mbPowerUp) {
pTAS2557->mbLoadConfigurationPrePowerUp = false;
nResult = tas2557_load_coefficient(pTAS2557, pTAS2557->mnCurrentConfiguration, nConfiguration, true);
} else {
dev_dbg(pTAS2557->dev,
"TAS2557 was powered down, will load coefficient when power up\n");
pTAS2557->mbLoadConfigurationPrePowerUp = true;
pTAS2557->mnNewConfiguration = nConfiguration;
}
end:
if (nResult < 0) {
if (pTAS2557->mnErrCode & (ERROR_DEVA_I2C_COMM | ERROR_PRAM_CRCCHK | ERROR_YRAM_CRCCHK))
failsafe(pTAS2557);
}
return nResult;
}
int tas2557_set_config(struct tas2557_priv *pTAS2557, int config)
{
struct TConfiguration *pConfiguration;
struct TProgram *pProgram;
unsigned int nProgram = pTAS2557->mnCurrentProgram;
unsigned int nConfiguration = config;
int nResult = 0;
if ((!pTAS2557->mpFirmware->mpPrograms) ||
(!pTAS2557->mpFirmware->mpConfigurations)) {
dev_err(pTAS2557->dev, "Firmware not loaded\n");
nResult = -EINVAL;
goto end;
}
if (nConfiguration >= pTAS2557->mpFirmware->mnConfigurations) {
dev_err(pTAS2557->dev, "Configuration %d doesn't exist\n",
nConfiguration);
nResult = -EINVAL;
goto end;
}
pConfiguration = &(pTAS2557->mpFirmware->mpConfigurations[nConfiguration]);
pProgram = &(pTAS2557->mpFirmware->mpPrograms[nProgram]);
if (nProgram != pConfiguration->mnProgram) {
dev_err(pTAS2557->dev,
"Configuration %d, %s with Program %d isn't compatible with existing Program %d, %s\n",
nConfiguration, pConfiguration->mpName, pConfiguration->mnProgram,
nProgram, pProgram->mpName);
nResult = -EINVAL;
goto end;
}
nResult = tas2557_load_configuration(pTAS2557, nConfiguration, false);
end:
return nResult;
}
void tas2557_clear_firmware(struct TFirmware *pFirmware)
{
unsigned int n, nn;
if (!pFirmware)
return;
kfree(pFirmware->mpDescription);
if (pFirmware->mpPLLs != NULL) {
for (n = 0; n < pFirmware->mnPLLs; n++) {
kfree(pFirmware->mpPLLs[n].mpDescription);
kfree(pFirmware->mpPLLs[n].mBlock.mpData);
}
kfree(pFirmware->mpPLLs);
}
if (pFirmware->mpPrograms != NULL) {
for (n = 0; n < pFirmware->mnPrograms; n++) {
kfree(pFirmware->mpPrograms[n].mpDescription);
kfree(pFirmware->mpPrograms[n].mData.mpDescription);
for (nn = 0; nn < pFirmware->mpPrograms[n].mData.mnBlocks; nn++)
kfree(pFirmware->mpPrograms[n].mData.mpBlocks[nn].mpData);
kfree(pFirmware->mpPrograms[n].mData.mpBlocks);
}
kfree(pFirmware->mpPrograms);
}
if (pFirmware->mpConfigurations != NULL) {
for (n = 0; n < pFirmware->mnConfigurations; n++) {
kfree(pFirmware->mpConfigurations[n].mpDescription);
kfree(pFirmware->mpConfigurations[n].mData.mpDescription);
for (nn = 0; nn < pFirmware->mpConfigurations[n].mData.mnBlocks; nn++)
kfree(pFirmware->mpConfigurations[n].mData.mpBlocks[nn].mpData);
kfree(pFirmware->mpConfigurations[n].mData.mpBlocks);
}
kfree(pFirmware->mpConfigurations);
}
if (pFirmware->mpCalibrations != NULL) {
for (n = 0; n < pFirmware->mnCalibrations; n++) {
kfree(pFirmware->mpCalibrations[n].mpDescription);
kfree(pFirmware->mpCalibrations[n].mData.mpDescription);
for (nn = 0; nn < pFirmware->mpCalibrations[n].mData.mnBlocks; nn++)
kfree(pFirmware->mpCalibrations[n].mData.mpBlocks[nn].mpData);
kfree(pFirmware->mpCalibrations[n].mData.mpBlocks);
}
kfree(pFirmware->mpCalibrations);
}
memset(pFirmware, 0x00, sizeof(struct TFirmware));
}
static int tas2557_load_calibration(struct tas2557_priv *pTAS2557, char *pFileName)
{
int nResult = 0;
int nFile;
mm_segment_t fs;
unsigned char pBuffer[1000];
int nSize = 0;
dev_dbg(pTAS2557->dev, "%s:\n", __func__);
fs = get_fs();
set_fs(KERNEL_DS);
nFile = sys_open(pFileName, O_RDONLY, 0);
dev_info(pTAS2557->dev, "TAS2557 calibration file = %s, handle = %d\n",
pFileName, nFile);
if (nFile >= 0) {
nSize = sys_read(nFile, pBuffer, 1000);
sys_close(nFile);
} else {
dev_err(pTAS2557->dev, "TAS2557 cannot open calibration file: %s\n",
pFileName);
}
set_fs(fs);
if (!nSize)
goto end;
tas2557_clear_firmware(pTAS2557->mpCalFirmware);
dev_info(pTAS2557->dev, "TAS2557 calibration file size = %d\n", nSize);
nResult = fw_parse(pTAS2557, pTAS2557->mpCalFirmware, pBuffer, nSize);
if (nResult)
dev_err(pTAS2557->dev, "TAS2557 calibration file is corrupt\n");
else
dev_info(pTAS2557->dev, "TAS2557 calibration: %d calibrations\n",
pTAS2557->mpCalFirmware->mnCalibrations);
end:
return nResult;
}
static bool tas2557_get_coefficient_in_block(struct tas2557_priv *pTAS2557,
struct TBlock *pBlock, int nReg, int *pnValue)
{
int nCoefficient = 0;
bool bFound = false;
unsigned char *pCommands;
int nBook, nPage, nOffset, len;
int i, n;
pCommands = pBlock->mpData;
for (i = 0 ; i < pBlock->mnCommands;) {
nBook = pCommands[4 * i + 0];
nPage = pCommands[4 * i + 1];
nOffset = pCommands[4 * i + 2];
if ((nOffset < 0x7f) || (nOffset == 0x81))
i++;
else if (nOffset == 0x85) {
len = ((int)nBook << 8) | nPage;
nBook = pCommands[4 * i + 4];
nPage = pCommands[4 * i + 5];
nOffset = pCommands[4 * i + 6];
n = 4 * i + 7;
i += 2;
i += ((len - 1) / 4);
if ((len - 1) % 4)
i++;
if ((nBook != TAS2557_BOOK_ID(nReg))
|| (nPage != TAS2557_PAGE_ID(nReg)))
continue;
if (nOffset > TAS2557_PAGE_REG(nReg))
continue;
if ((len + nOffset) >= (TAS2557_PAGE_REG(nReg) + 4)) {
n += (TAS2557_PAGE_REG(nReg) - nOffset);
nCoefficient = ((int)pCommands[n] << 24)
| ((int)pCommands[n + 1] << 16)
| ((int)pCommands[n + 2] << 8)
| (int)pCommands[n + 3];
bFound = true;
break;
}
} else {
dev_err(pTAS2557->dev, "%s, format error %d\n", __func__, nOffset);
break;
}
}
if (bFound) {
*pnValue = nCoefficient;
dev_dbg(pTAS2557->dev, "%s, B[0x%x]P[0x%x]R[0x%x]=0x%x\n", __func__,
TAS2557_BOOK_ID(nReg), TAS2557_PAGE_ID(nReg), TAS2557_PAGE_REG(nReg),
nCoefficient);
}
return bFound;
}
static bool tas2557_get_coefficient_in_data(struct tas2557_priv *pTAS2557,
struct TData *pData, int blockType, int nReg, int *pnValue)
{
bool bFound = false;
struct TBlock *pBlock;
int i;
for (i = 0; i < pData->mnBlocks; i++) {
pBlock = &(pData->mpBlocks[i]);
if (pBlock->mnType == blockType) {
bFound = tas2557_get_coefficient_in_block(pTAS2557,
pBlock, nReg, pnValue);
if (bFound)
break;
}
}
return bFound;
}
static bool tas2557_find_Tmax_in_configuration(struct tas2557_priv *pTAS2557,
struct TConfiguration *pConfiguration, int *pnTMax)
{
struct TData *pData;
bool bFound = false;
int nBlockType, nReg, nCoefficient;
if (pTAS2557->mnPGID == TAS2557_PG_VERSION_2P1)
nReg = TAS2557_PG2P1_CALI_T_REG;
else
nReg = TAS2557_PG1P0_CALI_T_REG;
nBlockType = TAS2557_BLOCK_CFG_COEFF_DEV_A;
pData = &(pConfiguration->mData);
bFound = tas2557_get_coefficient_in_data(pTAS2557, pData, nBlockType, nReg, &nCoefficient);
if (bFound)
*pnTMax = nCoefficient;
return bFound;
}
void tas2557_fw_ready(const struct firmware *pFW, void *pContext)
{
struct tas2557_priv *pTAS2557 = (struct tas2557_priv *) pContext;
int nResult;
unsigned int nProgram = 0;
unsigned int nSampleRate = 0;
#ifdef CONFIG_TAS2557_CODEC
mutex_lock(&pTAS2557->codec_lock);
#endif
#ifdef CONFIG_TAS2557_MISC
mutex_lock(&pTAS2557->file_lock);
#endif
printk("[tas2557] tas2557_fw_ready +++++ \n"); //[jinjia]Trace
dev_info(pTAS2557->dev, "%s:\n", __func__);
if (unlikely(!pFW) || unlikely(!pFW->data)) {
dev_err(pTAS2557->dev, "%s firmware is not loaded.\n",
TAS2557_FW_NAME);
goto end;
}
if (pTAS2557->mpFirmware->mpConfigurations) {
nProgram = pTAS2557->mnCurrentProgram;
nSampleRate = pTAS2557->mnCurrentSampleRate;
dev_dbg(pTAS2557->dev, "clear current firmware\n");
tas2557_clear_firmware(pTAS2557->mpFirmware);
}
nResult = fw_parse(pTAS2557, pTAS2557->mpFirmware, (unsigned char *)(pFW->data), pFW->size);
release_firmware(pFW);
if (nResult < 0) {
dev_err(pTAS2557->dev, "firmware is corrupt\n");
goto end;
}
if (!pTAS2557->mpFirmware->mnPrograms) {
dev_err(pTAS2557->dev, "firmware contains no programs\n");
nResult = -EINVAL;
goto end;
}
if (!pTAS2557->mpFirmware->mnConfigurations) {
dev_err(pTAS2557->dev, "firmware contains no configurations\n");
nResult = -EINVAL;
goto end;
}
if (nProgram >= pTAS2557->mpFirmware->mnPrograms) {
dev_info(pTAS2557->dev,
"no previous program, set to default\n");
nProgram = 0;
}
pTAS2557->mnCurrentSampleRate = nSampleRate;
nResult = tas2557_set_program(pTAS2557, nProgram, -1);
printk("[tas2557] tas2557_fw_ready ----- \n"); //[jinjia]Trace
end:
#ifdef CONFIG_TAS2557_CODEC
mutex_unlock(&pTAS2557->codec_lock);
#endif
#ifdef CONFIG_TAS2557_MISC
mutex_unlock(&pTAS2557->file_lock);
#endif
}
int tas2557_set_program(struct tas2557_priv *pTAS2557,
unsigned int nProgram, int nConfig)
{
struct TProgram *pProgram;
unsigned int nConfiguration = 0;
unsigned int nSampleRate = 0;
unsigned char nGain;
bool bFound = false;
int nResult = 0;
if ((!pTAS2557->mpFirmware->mpPrograms) ||
(!pTAS2557->mpFirmware->mpConfigurations)) {
dev_err(pTAS2557->dev, "Firmware not loaded\n");
nResult = 0;
goto end;
}
if (nProgram >= pTAS2557->mpFirmware->mnPrograms) {
dev_err(pTAS2557->dev, "TAS2557: Program %d doesn't exist\n",
nProgram);
nResult = 0;
goto end;
}
if (nConfig < 0) {
nConfiguration = 0;
nSampleRate = pTAS2557->mnCurrentSampleRate;
while (!bFound && (nConfiguration < pTAS2557->mpFirmware->mnConfigurations)) {
if (pTAS2557->mpFirmware->mpConfigurations[nConfiguration].mnProgram == nProgram) {
if (nSampleRate == 0) {
bFound = true;
dev_info(pTAS2557->dev, "find default configuration %d\n", nConfiguration);
} else if (nSampleRate == pTAS2557->mpFirmware->mpConfigurations[nConfiguration].mnSamplingRate) {
bFound = true;
dev_info(pTAS2557->dev, "find matching configuration %d\n", nConfiguration);
} else {
nConfiguration++;
}
} else {
nConfiguration++;
}
}
if (!bFound) {
dev_err(pTAS2557->dev,
"Program %d, no valid configuration found for sample rate %d, ignore\n",
nProgram, nSampleRate);
nResult = 0;
goto end;
}
} else {
if (pTAS2557->mpFirmware->mpConfigurations[nConfig].mnProgram != nProgram) {
dev_err(pTAS2557->dev, "%s, configuration program doesn't match\n", __func__);
nResult = 0;
goto end;
}
nConfiguration = nConfig;
}
pProgram = &(pTAS2557->mpFirmware->mpPrograms[nProgram]);
if (pTAS2557->mbPowerUp) {
dev_info(pTAS2557->dev,
"device powered up, power down to load program %d (%s)\n",
nProgram, pProgram->mpName);
if (hrtimer_active(&pTAS2557->mtimer))
hrtimer_cancel(&pTAS2557->mtimer);
if (pProgram->mnAppMode == TAS2557_APP_TUNINGMODE)
pTAS2557->enableIRQ(pTAS2557, false, false);
nResult = tas2557_dev_load_data(pTAS2557, p_tas2557_shutdown_data);
if (nResult < 0)
goto end;
}
pTAS2557->hw_reset(pTAS2557);
nResult = pTAS2557->write(pTAS2557, TAS2557_SW_RESET_REG, 0x01);
if (nResult < 0)
goto end;
msleep(1);
nResult = tas2557_load_default(pTAS2557);
if (nResult < 0)
goto end;
dev_info(pTAS2557->dev, "load program %d (%s)\n", nProgram, pProgram->mpName);
nResult = tas2557_load_data(pTAS2557, &(pProgram->mData), TAS2557_BLOCK_PGM_DEV_A);
if (nResult < 0)
goto end;
pTAS2557->mnCurrentProgram = nProgram;
nResult = tas2557_get_DAC_gain(pTAS2557, &nGain);
if (nResult < 0)
goto end;
pTAS2557->mnDevGain = nGain;
pTAS2557->mnDevCurrentGain = nGain;
nResult = tas2557_load_coefficient(pTAS2557, -1, nConfiguration, false);
if (nResult < 0)
goto end;
tas2557_update_edge(pTAS2557);
if (pTAS2557->mbPowerUp) {
pTAS2557->clearIRQ(pTAS2557);
dev_dbg(pTAS2557->dev, "device powered up, load startup\n");
nResult = tas2557_dev_load_data(pTAS2557, p_tas2557_startup_data);
if (nResult < 0)
goto end;
if (pProgram->mnAppMode == TAS2557_APP_TUNINGMODE) {
nResult = tas2557_checkPLL(pTAS2557);
if (nResult < 0) {
nResult = tas2557_dev_load_data(pTAS2557, p_tas2557_shutdown_data);
pTAS2557->mbPowerUp = false;
goto end;
}
}
dev_dbg(pTAS2557->dev, "device powered up, load unmute\n");
nResult = tas2557_dev_load_data(pTAS2557, p_tas2557_unmute_data);
if (nResult < 0)
goto end;
if (pProgram->mnAppMode == TAS2557_APP_TUNINGMODE) {
pTAS2557->enableIRQ(pTAS2557, true, true);
if (!hrtimer_active(&pTAS2557->mtimer)) {
pTAS2557->mnDieTvReadCounter = 0;
hrtimer_start(&pTAS2557->mtimer,
ns_to_ktime((u64)LOW_TEMPERATURE_CHECK_PERIOD * NSEC_PER_MSEC), HRTIMER_MODE_REL);
}
}
}
end:
if (nResult < 0) {
if (pTAS2557->mnErrCode & (ERROR_DEVA_I2C_COMM | ERROR_PRAM_CRCCHK | ERROR_YRAM_CRCCHK))
failsafe(pTAS2557);
}
return nResult;
}
int tas2557_set_calibration(struct tas2557_priv *pTAS2557, int nCalibration)
{
struct TCalibration *pCalibration = NULL;
struct TConfiguration *pConfiguration;
struct TProgram *pProgram;
int nTmax = 0;
bool bFound = false;
int nResult = 0;
if ((!pTAS2557->mpFirmware->mpPrograms)
|| (!pTAS2557->mpFirmware->mpConfigurations)) {
dev_err(pTAS2557->dev, "Firmware not loaded\n\r");
nResult = 0;
goto end;
}
if (nCalibration == 0x00FF) {
nResult = tas2557_load_calibration(pTAS2557, TAS2557_CAL_NAME);
if (nResult < 0) {
dev_info(pTAS2557->dev, "load new calibration file %s fail %d\n",
TAS2557_CAL_NAME, nResult);
goto end;
}
nCalibration = 0;
}
if (nCalibration >= pTAS2557->mpCalFirmware->mnCalibrations) {
dev_err(pTAS2557->dev,
"Calibration %d doesn't exist\n", nCalibration);
nResult = 0;
goto end;
}
pTAS2557->mnCurrentCalibration = nCalibration;
if (pTAS2557->mbLoadConfigurationPrePowerUp)
goto end;
pCalibration = &(pTAS2557->mpCalFirmware->mpCalibrations[nCalibration]);
pProgram = &(pTAS2557->mpFirmware->mpPrograms[pTAS2557->mnCurrentProgram]);
pConfiguration = &(pTAS2557->mpFirmware->mpConfigurations[pTAS2557->mnCurrentConfiguration]);
if (pProgram->mnAppMode == TAS2557_APP_TUNINGMODE) {
if (pTAS2557->mbBypassTMax) {
bFound = tas2557_find_Tmax_in_configuration(pTAS2557, pConfiguration, &nTmax);
if (bFound && (nTmax == TAS2557_COEFFICIENT_TMAX)) {
dev_dbg(pTAS2557->dev, "%s, config[%s] bypass load calibration\n",
__func__, pConfiguration->mpName);
goto end;
}
}
dev_dbg(pTAS2557->dev, "%s, load calibration\n", __func__);
nResult = tas2557_load_data(pTAS2557, &(pCalibration->mData), TAS2557_BLOCK_CFG_COEFF_DEV_A);
if (nResult < 0)
goto end;
}
end:
if (nResult < 0) {
tas2557_clear_firmware(pTAS2557->mpCalFirmware);
nResult = tas2557_set_program(pTAS2557, pTAS2557->mnCurrentProgram, pTAS2557->mnCurrentConfiguration);
}
return nResult;
}
bool tas2557_get_Cali_prm_r0(struct tas2557_priv *pTAS2557, int *prm_r0)
{
struct TCalibration *pCalibration;
struct TData *pData;
int nReg;
int nCali_Re;
bool bFound = false;
int nBlockType;
if (!pTAS2557->mpCalFirmware->mnCalibrations) {
dev_err(pTAS2557->dev, "%s, no calibration data\n", __func__);
goto end;
}
if (pTAS2557->mnPGID == TAS2557_PG_VERSION_2P1)
nReg = TAS2557_PG2P1_CALI_R0_REG;
else
nReg = TAS2557_PG1P0_CALI_R0_REG;
nBlockType = TAS2557_BLOCK_CFG_COEFF_DEV_A;
pCalibration = &(pTAS2557->mpCalFirmware->mpCalibrations[pTAS2557->mnCurrentCalibration]);
pData = &(pCalibration->mData);
bFound = tas2557_get_coefficient_in_data(pTAS2557, pData, nBlockType, nReg, &nCali_Re);
end:
if (bFound)
*prm_r0 = nCali_Re;
return bFound;
}
int tas2557_parse_dt(struct device *dev, struct tas2557_priv *pTAS2557)
{
struct device_node *np = dev->of_node;
int rc = 0, ret = 0;
unsigned int value;
pTAS2557->mnResetGPIO = of_get_named_gpio(np, "ti,cdc-reset-gpio", 0);
if (!gpio_is_valid(pTAS2557->mnResetGPIO)) {
dev_err(pTAS2557->dev, "Looking up %s property in node %s failed %d\n",
"ti,cdc-reset-gpio", np->full_name,
pTAS2557->mnResetGPIO);
ret = -EINVAL;
goto end;
} else
dev_dbg(pTAS2557->dev, "ti,cdc-reset-gpio=%d\n", pTAS2557->mnResetGPIO);
pTAS2557->mnGpioINT = of_get_named_gpio(np, "ti,irq-gpio", 0);
if (!gpio_is_valid(pTAS2557->mnGpioINT))
dev_err(pTAS2557->dev, "Looking up %s property in node %s failed %d\n",
"ti,irq-gpio", np->full_name,
pTAS2557->mnGpioINT);
rc = of_property_read_u32(np, "ti,i2s-bits", &value);
if (rc)
dev_err(pTAS2557->dev, "Looking up %s property in node %s failed %d\n",
"ti,i2s-bits", np->full_name, rc);
else
pTAS2557->mnI2SBits = value;
rc = of_property_read_u32(np, "ti,bypass-tmax", &value);
if (rc)
dev_err(pTAS2557->dev, "Looking up %s property in node %s failed %d\n",
"ti,bypass-tmax", np->full_name, rc);
else
pTAS2557->mbBypassTMax = (value > 0);
end:
return ret;
}
MODULE_AUTHOR("Texas Instruments Inc.");
MODULE_DESCRIPTION("TAS2557 common functions for Android Linux");
MODULE_LICENSE("GPL v2");