blob: cd260afc0cd747a7a667b2a55297ec6c4060f6c4 [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-regmap.c
**
** Description:
** I2C driver with regmap for Texas Instruments TAS2557 High Performance 4W Smart Amplifier
**
** =============================================================================
*/
#ifdef CONFIG_TAS2557_REGMAP
#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>
//[FairPhone][Audio][jinjia]=2020.05.19=Fix the build error with TI sample code. -s
#include <linux/interrupt.h>
//[FairPhone][Audio][jinjia]=2020.05.19=Fix the build error with TI sample code. -e
#include "tas2557.h"
#include "tas2557-core.h"
#ifdef CONFIG_TAS2557_CODEC
#include "tas2557-codec.h"
#endif
#ifdef CONFIG_TAS2557_MISC
#include "tas2557-misc.h"
#endif
#define ENABLE_TILOAD
#ifdef ENABLE_TILOAD
#include "tiload.h"
#endif
#define LOW_TEMPERATURE_GAIN 6
#define LOW_TEMPERATURE_COUNTER 12
static int tas2557_change_book_page(
struct tas2557_priv *pTAS2557,
unsigned char nBook,
unsigned char nPage)
{
int nResult = 0;
if ((pTAS2557->mnCurrentBook == nBook)
&& pTAS2557->mnCurrentPage == nPage)
goto end;
if (pTAS2557->mnCurrentBook != nBook) {
nResult = regmap_write(pTAS2557->mpRegmap, TAS2557_BOOKCTL_PAGE, 0);
if (nResult < 0) {
dev_err(pTAS2557->dev, "%s, %d, I2C error %d\n",
__func__, __LINE__, nResult);
goto end;
}
pTAS2557->mnCurrentPage = 0;
nResult = regmap_write(pTAS2557->mpRegmap, TAS2557_BOOKCTL_REG, nBook);
if (nResult < 0) {
dev_err(pTAS2557->dev, "%s, %d, I2C error %d\n",
__func__, __LINE__, nResult);
goto end;
}
pTAS2557->mnCurrentBook = nBook;
if (nPage != 0) {
nResult = regmap_write(pTAS2557->mpRegmap, TAS2557_BOOKCTL_PAGE, nPage);
if (nResult < 0) {
dev_err(pTAS2557->dev, "%s, %d, I2C error %d\n",
__func__, __LINE__, nResult);
goto end;
}
pTAS2557->mnCurrentPage = nPage;
}
} else if (pTAS2557->mnCurrentPage != nPage) {
nResult = regmap_write(pTAS2557->mpRegmap, TAS2557_BOOKCTL_PAGE, nPage);
if (nResult < 0) {
dev_err(pTAS2557->dev, "%s, %d, I2C error %d\n",
__func__, __LINE__, nResult);
goto end;
}
pTAS2557->mnCurrentPage = nPage;
}
end:
if (nResult < 0)
pTAS2557->mnErrCode |= ERROR_DEVA_I2C_COMM;
else
pTAS2557->mnErrCode &= ~ERROR_DEVA_I2C_COMM;
return nResult;
}
static int tas2557_dev_read(
struct tas2557_priv *pTAS2557,
unsigned int nRegister,
unsigned int *pValue)
{
int nResult = 0;
unsigned int Value = 0;
mutex_lock(&pTAS2557->dev_lock);
printk("[tas2557] tas2557_dev_read +++++\n"); //[jinjia]Trace
if (pTAS2557->mbTILoadActive) {
if (!(nRegister & 0x80000000))
goto end; /* let only reads from TILoad pass. */
nRegister &= ~0x80000000;
printk("[tas2557] [tas2557_dev_read] mbTILoadActive \n"); //[jinjia]Trace
dev_dbg(pTAS2557->dev, "TiLoad R REG B[%d]P[%d]R[%d]\n",
TAS2557_BOOK_ID(nRegister),
TAS2557_PAGE_ID(nRegister),
TAS2557_PAGE_REG(nRegister));
}
nResult = tas2557_change_book_page(pTAS2557,
TAS2557_BOOK_ID(nRegister),
TAS2557_PAGE_ID(nRegister));
if (nResult >= 0) {
nResult = regmap_read(pTAS2557->mpRegmap, TAS2557_PAGE_REG(nRegister), &Value);
if (nResult < 0) {
dev_err(pTAS2557->dev, "%s, %d, I2C error %d\n",
__func__, __LINE__, nResult);
pTAS2557->mnErrCode |= ERROR_DEVA_I2C_COMM;
goto end;
} else
pTAS2557->mnErrCode &= ~ERROR_DEVA_I2C_COMM;
*pValue = Value;
}
printk("[tas2557] tas2557_dev_read -----\n"); //[jinjia]Trace
end:
mutex_unlock(&pTAS2557->dev_lock);
return nResult;
}
static int tas2557_dev_write(
struct tas2557_priv *pTAS2557,
unsigned int nRegister,
unsigned int nValue)
{
int nResult = 0;
mutex_lock(&pTAS2557->dev_lock);
if ((nRegister == 0xAFFEAFFE) && (nValue == 0xBABEBABE)) {
pTAS2557->mbTILoadActive = true;
goto end;
}
if ((nRegister == 0xBABEBABE) && (nValue == 0xAFFEAFFE)) {
pTAS2557->mbTILoadActive = false;
goto end;
}
if (pTAS2557->mbTILoadActive) {
if (!(nRegister & 0x80000000))
goto end;/* let only writes from TILoad pass. */
nRegister &= ~0x80000000;
dev_dbg(pTAS2557->dev, "TiLoad W REG B[%d]P[%d]R[%d] =0x%x\n",
TAS2557_BOOK_ID(nRegister),
TAS2557_PAGE_ID(nRegister),
TAS2557_PAGE_REG(nRegister),
nValue);
}
nResult = tas2557_change_book_page(pTAS2557,
TAS2557_BOOK_ID(nRegister),
TAS2557_PAGE_ID(nRegister));
if (nResult >= 0) {
nResult = regmap_write(pTAS2557->mpRegmap, TAS2557_PAGE_REG(nRegister), nValue);
if (nResult < 0) {
dev_err(pTAS2557->dev, "%s, %d, I2C error %d\n",
__func__, __LINE__, nResult);
pTAS2557->mnErrCode |= ERROR_DEVA_I2C_COMM;
} else
pTAS2557->mnErrCode &= ~ERROR_DEVA_I2C_COMM;
}
end:
mutex_unlock(&pTAS2557->dev_lock);
return nResult;
}
static int tas2557_dev_bulk_read(
struct tas2557_priv *pTAS2557,
unsigned int nRegister,
u8 *pData,
unsigned int nLength)
{
int nResult = 0;
mutex_lock(&pTAS2557->dev_lock);
if (pTAS2557->mbTILoadActive) {
if (!(nRegister & 0x80000000))
goto end; /* let only writes from TILoad pass. */
nRegister &= ~0x80000000;
dev_dbg(pTAS2557->dev, "TiLoad BR REG B[%d]P[%d]R[%d], count=%d\n",
TAS2557_BOOK_ID(nRegister),
TAS2557_PAGE_ID(nRegister),
TAS2557_PAGE_REG(nRegister),
nLength);
}
nResult = tas2557_change_book_page(pTAS2557,
TAS2557_BOOK_ID(nRegister),
TAS2557_PAGE_ID(nRegister));
if (nResult >= 0) {
nResult = regmap_bulk_read(pTAS2557->mpRegmap, TAS2557_PAGE_REG(nRegister), pData, nLength);
if (nResult < 0) {
dev_err(pTAS2557->dev, "%s, %d, I2C error %d\n",
__func__, __LINE__, nResult);
pTAS2557->mnErrCode |= ERROR_DEVA_I2C_COMM;
} else
pTAS2557->mnErrCode &= ~ERROR_DEVA_I2C_COMM;
}
end:
mutex_unlock(&pTAS2557->dev_lock);
return nResult;
}
static int tas2557_dev_bulk_write(
struct tas2557_priv *pTAS2557,
unsigned int nRegister,
u8 *pData,
unsigned int nLength)
{
int nResult = 0;
mutex_lock(&pTAS2557->dev_lock);
if (pTAS2557->mbTILoadActive) {
if (!(nRegister & 0x80000000))
goto end; /* let only writes from TILoad pass. */
nRegister &= ~0x80000000;
dev_dbg(pTAS2557->dev, "TiLoad BW REG B[%d]P[%d]R[%d], count=%d\n",
TAS2557_BOOK_ID(nRegister),
TAS2557_PAGE_ID(nRegister),
TAS2557_PAGE_REG(nRegister),
nLength);
}
nResult = tas2557_change_book_page( pTAS2557,
TAS2557_BOOK_ID(nRegister),
TAS2557_PAGE_ID(nRegister));
if (nResult >= 0) {
nResult = regmap_bulk_write(pTAS2557->mpRegmap, TAS2557_PAGE_REG(nRegister), pData, nLength);
if (nResult < 0) {
dev_err(pTAS2557->dev, "%s, %d, I2C error %d\n",
__func__, __LINE__, nResult);
pTAS2557->mnErrCode |= ERROR_DEVA_I2C_COMM;
} else
pTAS2557->mnErrCode &= ~ERROR_DEVA_I2C_COMM;
}
end:
mutex_unlock(&pTAS2557->dev_lock);
return nResult;
}
static int tas2557_dev_update_bits(
struct tas2557_priv *pTAS2557,
unsigned int nRegister,
unsigned int nMask,
unsigned int nValue)
{
int nResult = 0;
mutex_lock(&pTAS2557->dev_lock);
if (pTAS2557->mbTILoadActive) {
if (!(nRegister & 0x80000000))
goto end; /* let only writes from TILoad pass. */
nRegister &= ~0x80000000;
dev_dbg(pTAS2557->dev, "TiLoad SB REG B[%d]P[%d]R[%d], mask=0x%x, value=0x%x\n",
TAS2557_BOOK_ID(nRegister),
TAS2557_PAGE_ID(nRegister),
TAS2557_PAGE_REG(nRegister),
nMask, nValue);
}
nResult = tas2557_change_book_page( pTAS2557,
TAS2557_BOOK_ID(nRegister),
TAS2557_PAGE_ID(nRegister));
if (nResult >= 0) {
nResult = regmap_update_bits(pTAS2557->mpRegmap, TAS2557_PAGE_REG(nRegister), nMask, nValue);
if (nResult < 0) {
dev_err(pTAS2557->dev, "%s, %d, I2C error %d\n",
__func__, __LINE__, nResult);
pTAS2557->mnErrCode |= ERROR_DEVA_I2C_COMM;
} else
pTAS2557->mnErrCode &= ~ERROR_DEVA_I2C_COMM;
}
end:
mutex_unlock(&pTAS2557->dev_lock);
return nResult;
}
void tas2557_clearIRQ(struct tas2557_priv *pTAS2557)
{
unsigned int nValue;
int nResult = 0;
nResult = pTAS2557->read(pTAS2557, TAS2557_FLAGS_1, &nValue);
if (nResult >= 0)
pTAS2557->read(pTAS2557, TAS2557_FLAGS_2, &nValue);
}
void tas2557_enableIRQ(struct tas2557_priv *pTAS2557, bool enable, bool startup_chk)
{
if (enable) {
if (!pTAS2557->mbIRQEnable) {
if (gpio_is_valid(pTAS2557->mnGpioINT)) {
enable_irq(pTAS2557->mnIRQ);
if (startup_chk) {
/* check after 10 ms */
schedule_delayed_work(&pTAS2557->irq_work, msecs_to_jiffies(10));
}
pTAS2557->mbIRQEnable = true;
}
}
} else {
if (gpio_is_valid(pTAS2557->mnGpioINT))
disable_irq_nosync(pTAS2557->mnIRQ);
pTAS2557->mbIRQEnable = false;
}
}
static void tas2557_hw_reset(struct tas2557_priv *pTAS2557)
{
printk("[tas2557] tas2557_hw_reset ++++++\n"); //[jinjia]Trace
if (gpio_is_valid(pTAS2557->mnResetGPIO)) {
printk("[tas2557][tas2557_hw_reset] gpio_is_valid(mnResetGPIO) \n"); //[jinjia]Trace
gpio_direction_output(pTAS2557->mnResetGPIO, 0);
msleep(5);
gpio_direction_output(pTAS2557->mnResetGPIO, 1);
msleep(2);
}
pTAS2557->mnCurrentBook = -1;
pTAS2557->mnCurrentPage = -1;
if (pTAS2557->mnErrCode)
dev_info(pTAS2557->dev, "before reset, ErrCode=0x%x\n", pTAS2557->mnErrCode);
pTAS2557->mnErrCode = 0;
printk("[tas2557] tas2557_hw_reset ------\n"); //[jinjia]Trace
}
static void irq_work_routine(struct work_struct *work)
{
int nResult = 0;
unsigned int nDevInt1Status = 0, nDevInt2Status = 0;
unsigned int nDevPowerUpFlag = 0;
int nCounter = 2;
struct tas2557_priv *pTAS2557 =
container_of(work, struct tas2557_priv, irq_work.work);
#ifdef CONFIG_TAS2557_CODEC
mutex_lock(&pTAS2557->codec_lock);
#endif
#ifdef CONFIG_TAS2557_MISC
mutex_lock(&pTAS2557->file_lock);
#endif
if(pTAS2557->mnErrCode & ERROR_FAILSAFE)
goto program;
if (pTAS2557->mbRuntimeSuspend) {
dev_info(pTAS2557->dev, "%s, Runtime Suspended\n", __func__);
goto end;
}
if (!pTAS2557->mbPowerUp) {
dev_info(pTAS2557->dev, "%s, device not powered\n", __func__);
goto end;
}
if ((!pTAS2557->mpFirmware->mnConfigurations)
|| (!pTAS2557->mpFirmware->mnPrograms)) {
dev_info(pTAS2557->dev, "%s, firmware not loaded\n", __func__);
goto end;
}
nResult = tas2557_dev_write(pTAS2557, TAS2557_GPIO4_PIN_REG, 0x00);
if (nResult < 0)
goto program;
nResult = tas2557_dev_read(pTAS2557, TAS2557_FLAGS_1, &nDevInt1Status);
if (nResult >= 0)
nResult = tas2557_dev_read(pTAS2557, TAS2557_FLAGS_2, &nDevInt2Status);
if (nResult < 0)
goto program;
if (((nDevInt1Status & 0xfc) != 0) || ((nDevInt2Status & 0x0c) != 0)) {
/* in case of INT_OC, INT_UV, INT_OT, INT_BO, INT_CL, INT_CLK1, INT_CLK2 */
dev_err(pTAS2557->dev, "critical error: 0x%x, 0x%x\n", nDevInt1Status, nDevInt2Status);
if (nDevInt1Status & 0x80) {
pTAS2557->mnErrCode |= ERROR_OVER_CURRENT;
dev_err(pTAS2557->dev, "DEVA SPK over current!\n");
} else
pTAS2557->mnErrCode &= ~ERROR_OVER_CURRENT;
if (nDevInt1Status & 0x40) {
pTAS2557->mnErrCode |= ERROR_UNDER_VOLTAGE;
dev_err(pTAS2557->dev, "DEVA SPK under voltage!\n");
} else
pTAS2557->mnErrCode &= ~ERROR_UNDER_VOLTAGE;
if (nDevInt1Status & 0x20) {
pTAS2557->mnErrCode |= ERROR_CLK_HALT;
dev_err(pTAS2557->dev, "DEVA clk halted!\n");
} else
pTAS2557->mnErrCode &= ~ERROR_CLK_HALT;
if (nDevInt1Status & 0x10) {
pTAS2557->mnErrCode |= ERROR_DIE_OVERTEMP;
dev_err(pTAS2557->dev, "DEVA die over temperature!\n");
} else
pTAS2557->mnErrCode &= ~ERROR_DIE_OVERTEMP;
if (nDevInt1Status & 0x08) {
pTAS2557->mnErrCode |= ERROR_BROWNOUT;
dev_err(pTAS2557->dev, "DEVA brownout!\n");
} else
pTAS2557->mnErrCode &= ~ERROR_BROWNOUT;
if (nDevInt1Status & 0x04) {
pTAS2557->mnErrCode |= ERROR_CLK_LOST;
dev_err(pTAS2557->dev, "DEVA clock lost!\n");
} else
pTAS2557->mnErrCode &= ~ERROR_CLK_LOST;
if (nDevInt2Status & 0x08) {
pTAS2557->mnErrCode |= ERROR_CLK_DET1;
dev_err(pTAS2557->dev, "DEVA clk detection 1!\n");
} else
pTAS2557->mnErrCode &= ~ERROR_CLK_DET1;
if (nDevInt2Status & 0x04) {
pTAS2557->mnErrCode |= ERROR_CLK_DET2;
dev_err(pTAS2557->dev, "DEVA clk detection 2!\n");
} else
pTAS2557->mnErrCode &= ~ERROR_CLK_DET2;
goto program;
} else {
dev_dbg(pTAS2557->dev, "IRQ Status: 0x%x, 0x%x\n", nDevInt1Status, nDevInt2Status);
nCounter = 2;
while (nCounter > 0) {
nResult = tas2557_dev_read(pTAS2557, TAS2557_POWER_UP_FLAG_REG, &nDevPowerUpFlag);
if (nResult < 0)
goto program;
if ((nDevPowerUpFlag & 0xc0) == 0xc0)
break;
nCounter--;
if (nCounter > 0) {
/* in case check pow status just after power on TAS2557 */
dev_dbg(pTAS2557->dev, "PowSts: 0x%x, check again after 10ms\n",
nDevPowerUpFlag);
msleep(10);
}
}
if ((nDevPowerUpFlag & 0xc0) != 0xc0) {
dev_err(pTAS2557->dev, "%s, Critical ERROR B[%d]_P[%d]_R[%d]= 0x%x\n",
__func__,
TAS2557_BOOK_ID(TAS2557_POWER_UP_FLAG_REG),
TAS2557_PAGE_ID(TAS2557_POWER_UP_FLAG_REG),
TAS2557_PAGE_REG(TAS2557_POWER_UP_FLAG_REG),
nDevPowerUpFlag);
pTAS2557->mnErrCode |= ERROR_CLASSD_PWR;
goto program;
}
pTAS2557->mnErrCode &= ~ERROR_CLASSD_PWR;
dev_dbg(pTAS2557->dev, "%s: INT1=0x%x, INT2=0x%x; PowerUpFlag=0x%x\n",
__func__, nDevInt1Status, nDevInt2Status, nDevPowerUpFlag);
goto end;
}
program:
/* hardware reset and reload */
nResult = -1;
tas2557_set_program(pTAS2557, pTAS2557->mnCurrentProgram, pTAS2557->mnCurrentConfiguration);
end:
if (nResult >= 0) {
tas2557_dev_write(pTAS2557, TAS2557_GPIO4_PIN_REG, 0x07);
tas2557_enableIRQ(pTAS2557, true, false);
}
#ifdef CONFIG_TAS2557_MISC
mutex_unlock(&pTAS2557->file_lock);
#endif
#ifdef CONFIG_TAS2557_CODEC
mutex_unlock(&pTAS2557->codec_lock);
#endif
}
static irqreturn_t tas2557_irq_handler(int irq, void *dev_id)
{
struct tas2557_priv *pTAS2557 = (struct tas2557_priv *)dev_id;
tas2557_enableIRQ(pTAS2557, false, false);
/* get IRQ status after 100 ms */
schedule_delayed_work(&pTAS2557->irq_work, msecs_to_jiffies(100));
return IRQ_HANDLED;
}
static enum hrtimer_restart temperature_timer_func(struct hrtimer *timer)
{
struct tas2557_priv *pTAS2557 = container_of(timer, struct tas2557_priv, mtimer);
if (pTAS2557->mbPowerUp) {
schedule_work(&pTAS2557->mtimerwork);
if (gpio_is_valid(pTAS2557->mnGpioINT)) {
tas2557_enableIRQ(pTAS2557, false, false);
schedule_delayed_work(&pTAS2557->irq_work, msecs_to_jiffies(1));
}
}
return HRTIMER_NORESTART;
}
static void timer_work_routine(struct work_struct *work)
{
struct tas2557_priv *pTAS2557 = container_of(work, struct tas2557_priv, mtimerwork);
int nResult, nActTemp;
int nTemp = 0;
struct TProgram *pProgram;
static int nAvg;
#ifdef CONFIG_TAS2557_CODEC
mutex_lock(&pTAS2557->codec_lock);
#endif
#ifdef CONFIG_TAS2557_MISC
mutex_lock(&pTAS2557->file_lock);
#endif
if (pTAS2557->mbRuntimeSuspend) {
dev_info(pTAS2557->dev, "%s, Runtime Suspended\n", __func__);
goto end;
}
if (!pTAS2557->mpFirmware->mnConfigurations) {
dev_info(pTAS2557->dev, "%s, firmware not loaded\n", __func__);
goto end;
}
pProgram = &(pTAS2557->mpFirmware->mpPrograms[pTAS2557->mnCurrentProgram]);
if (!pTAS2557->mbPowerUp
|| (pProgram->mnAppMode != TAS2557_APP_TUNINGMODE)) {
dev_info(pTAS2557->dev, "%s, pass, Pow=%d, program=%s\n",
__func__, pTAS2557->mbPowerUp, pProgram->mpName);
goto end;
}
nResult = tas2557_get_die_temperature(pTAS2557, &nTemp);
if (nResult >= 0) {
nActTemp = (int)(nTemp >> 23);
dev_dbg(pTAS2557->dev, "Die=0x%x, degree=%d\n", nTemp, nActTemp);
if (!pTAS2557->mnDieTvReadCounter)
nAvg = 0;
pTAS2557->mnDieTvReadCounter++;
nAvg += nActTemp;
if (!(pTAS2557->mnDieTvReadCounter % LOW_TEMPERATURE_COUNTER)) {
nAvg /= LOW_TEMPERATURE_COUNTER;
dev_dbg(pTAS2557->dev, "check : avg=%d\n", nAvg);
if (nAvg < -6) {
/* if Die temperature is below -6 degree C */
if (pTAS2557->mnDevCurrentGain != LOW_TEMPERATURE_GAIN) {
nResult = tas2557_set_DAC_gain(pTAS2557, LOW_TEMPERATURE_GAIN);
if (nResult < 0)
goto end;
pTAS2557->mnDevCurrentGain = LOW_TEMPERATURE_GAIN;
dev_dbg(pTAS2557->dev, "LOW Temp: set gain to %d\n", LOW_TEMPERATURE_GAIN);
}
} else if (nAvg > 5) {
/* if Die temperature is above 5 degree C */
if (pTAS2557->mnDevCurrentGain != pTAS2557->mnDevGain) {
nResult = tas2557_set_DAC_gain(pTAS2557, pTAS2557->mnDevGain);
if (nResult < 0)
goto end;
pTAS2557->mnDevCurrentGain = pTAS2557->mnDevGain;
dev_dbg(pTAS2557->dev, "LOW Temp: set gain to original\n");
}
}
nAvg = 0;
}
if (pTAS2557->mbPowerUp)
hrtimer_start(&pTAS2557->mtimer,
ns_to_ktime((u64)LOW_TEMPERATURE_CHECK_PERIOD * NSEC_PER_MSEC), HRTIMER_MODE_REL);
}
end:
#ifdef CONFIG_TAS2557_MISC
mutex_unlock(&pTAS2557->file_lock);
#endif
#ifdef CONFIG_TAS2557_CODEC
mutex_unlock(&pTAS2557->codec_lock);
#endif
}
static int tas2557_runtime_suspend(struct tas2557_priv *pTAS2557)
{
dev_dbg(pTAS2557->dev, "%s\n", __func__);
pTAS2557->mbRuntimeSuspend = true;
if (hrtimer_active(&pTAS2557->mtimer)) {
dev_dbg(pTAS2557->dev, "cancel die temp timer\n");
hrtimer_cancel(&pTAS2557->mtimer);
}
if (work_pending(&pTAS2557->mtimerwork)) {
dev_dbg(pTAS2557->dev, "cancel timer work\n");
cancel_work_sync(&pTAS2557->mtimerwork);
}
if (gpio_is_valid(pTAS2557->mnGpioINT)) {
if (delayed_work_pending(&pTAS2557->irq_work)) {
dev_dbg(pTAS2557->dev, "cancel IRQ work\n");
cancel_delayed_work_sync(&pTAS2557->irq_work);
}
}
return 0;
}
static int tas2557_runtime_resume(struct tas2557_priv *pTAS2557)
{
struct TProgram *pProgram;
dev_dbg(pTAS2557->dev, "%s\n", __func__);
if (!pTAS2557->mpFirmware->mpPrograms) {
dev_dbg(pTAS2557->dev, "%s, firmware not loaded\n", __func__);
goto end;
}
if (pTAS2557->mnCurrentProgram >= pTAS2557->mpFirmware->mnPrograms) {
dev_err(pTAS2557->dev, "%s, firmware corrupted\n", __func__);
goto end;
}
pProgram = &(pTAS2557->mpFirmware->mpPrograms[pTAS2557->mnCurrentProgram]);
if (pTAS2557->mbPowerUp && (pProgram->mnAppMode == TAS2557_APP_TUNINGMODE)) {
if (!hrtimer_active(&pTAS2557->mtimer)) {
dev_dbg(pTAS2557->dev, "%s, start Die Temp check timer\n", __func__);
pTAS2557->mnDieTvReadCounter = 0;
hrtimer_start(&pTAS2557->mtimer,
ns_to_ktime((u64)LOW_TEMPERATURE_CHECK_PERIOD * NSEC_PER_MSEC), HRTIMER_MODE_REL);
}
}
pTAS2557->mbRuntimeSuspend = false;
end:
return 0;
}
static bool tas2557_volatile(struct device *pDev, unsigned int nRegister)
{
return true;
}
static bool tas2557_writeable(struct device *pDev, unsigned int nRegister)
{
return true;
}
static const struct regmap_config tas2557_i2c_regmap = {
.reg_bits = 8,
.val_bits = 8,
.writeable_reg = tas2557_writeable,
.volatile_reg = tas2557_volatile,
.cache_type = REGCACHE_NONE,
.max_register = 128,
};
/* tas2557_i2c_probe :
* platform dependent
* should implement hardware reset functionality
*/
static int tas2557_i2c_probe(struct i2c_client *pClient,
const struct i2c_device_id *pID)
{
struct tas2557_priv *pTAS2557;
int nResult = 0;
unsigned int nValue = 0;
const char *pFWName;
printk("[tas2557] tas2557_i2c_probe +++++\n"); //[jinjia]Trace
dev_info(&pClient->dev, "%s enter\n", __func__);
pTAS2557 = devm_kzalloc(&pClient->dev, sizeof(struct tas2557_priv), GFP_KERNEL);
if (!pTAS2557) {
nResult = -ENOMEM;
goto err;
}
pTAS2557->dev = &pClient->dev;
i2c_set_clientdata(pClient, pTAS2557);
dev_set_drvdata(&pClient->dev, pTAS2557);
pTAS2557->mpRegmap = devm_regmap_init_i2c(pClient, &tas2557_i2c_regmap);
if (IS_ERR(pTAS2557->mpRegmap)) {
nResult = PTR_ERR(pTAS2557->mpRegmap);
dev_err(&pClient->dev, "Failed to allocate register map: %d\n",
nResult);
goto err;
}
if (pClient->dev.of_node)
tas2557_parse_dt(&pClient->dev, pTAS2557);
if (gpio_is_valid(pTAS2557->mnResetGPIO)) {
printk("[tas2557] gpio_is_valid (mnResetGPIO) +++++ \n "); //[jinjia]Trace
nResult = gpio_request(pTAS2557->mnResetGPIO, "TAS2557-RESET");
if (nResult < 0) {
dev_err(pTAS2557->dev, "%s: GPIO %d request error\n",
__func__, pTAS2557->mnResetGPIO);
goto err;
}
tas2557_hw_reset(pTAS2557);
}
pTAS2557->read = tas2557_dev_read;
pTAS2557->write = tas2557_dev_write;
pTAS2557->bulk_read = tas2557_dev_bulk_read;
pTAS2557->bulk_write = tas2557_dev_bulk_write;
pTAS2557->update_bits = tas2557_dev_update_bits;
pTAS2557->enableIRQ = tas2557_enableIRQ;
pTAS2557->clearIRQ = tas2557_clearIRQ;
pTAS2557->set_config = tas2557_set_config;
pTAS2557->set_calibration = tas2557_set_calibration;
pTAS2557->hw_reset = tas2557_hw_reset;
pTAS2557->runtime_suspend = tas2557_runtime_suspend;
pTAS2557->runtime_resume = tas2557_runtime_resume;
pTAS2557->mnRestart = 0;
pTAS2557->mnEdge = 4;
mutex_init(&pTAS2557->dev_lock);
/* Reset the chip */
nResult = tas2557_dev_write(pTAS2557, TAS2557_SW_RESET_REG, 0x01);
if (nResult < 0) {
dev_err(&pClient->dev, "I2c fail, %d\n", nResult);
goto err;
}
msleep(1);
tas2557_dev_read(pTAS2557, TAS2557_REV_PGID_REG, &nValue);
pTAS2557->mnPGID = nValue;
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 err;
}
printk("[tas2557] gpio_is_valid(mnGpioINT) +\n"); //[jinjia]Trace
if (gpio_is_valid(pTAS2557->mnGpioINT)) {
printk("[tas2557] gpio_is_valid(mnGpioINT) ++\n"); //[jinjia]Trace
nResult = gpio_request(pTAS2557->mnGpioINT, "TAS2557-IRQ");
if (nResult < 0) {
dev_err(pTAS2557->dev,
"%s: GPIO %d request INT error\n",
__func__, pTAS2557->mnGpioINT);
goto err;
}
gpio_direction_input(pTAS2557->mnGpioINT);
pTAS2557->mnIRQ = gpio_to_irq(pTAS2557->mnGpioINT);
dev_dbg(pTAS2557->dev, "irq = %d\n", pTAS2557->mnIRQ);
INIT_DELAYED_WORK(&pTAS2557->irq_work, irq_work_routine);
nResult = request_threaded_irq(pTAS2557->mnIRQ, tas2557_irq_handler,
NULL, IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
pClient->name, pTAS2557);
if (nResult < 0) {
dev_err(pTAS2557->dev,
"request_irq failed, %d\n", nResult);
goto err;
}
disable_irq_nosync(pTAS2557->mnIRQ);
}
pTAS2557->mpFirmware = devm_kzalloc(&pClient->dev, sizeof(struct TFirmware), GFP_KERNEL);
if (!pTAS2557->mpFirmware) {
nResult = -ENOMEM;
goto err;
}
pTAS2557->mpCalFirmware = devm_kzalloc(&pClient->dev, sizeof(struct TFirmware), GFP_KERNEL);
if (!pTAS2557->mpCalFirmware) {
nResult = -ENOMEM;
goto err;
}
#ifdef CONFIG_TAS2557_CODEC
mutex_init(&pTAS2557->codec_lock);
tas2557_register_codec(pTAS2557);
#endif
#ifdef CONFIG_TAS2557_MISC
mutex_init(&pTAS2557->file_lock);
tas2557_register_misc(pTAS2557);
#endif
#ifdef ENABLE_TILOAD
tiload_driver_init(pTAS2557);
#endif
hrtimer_init(&pTAS2557->mtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
pTAS2557->mtimer.function = temperature_timer_func;
INIT_WORK(&pTAS2557->mtimerwork, timer_work_routine);
nResult = request_firmware_nowait(THIS_MODULE, 1, pFWName,
pTAS2557->dev, GFP_KERNEL, pTAS2557, tas2557_fw_ready);
printk("[tas2557] tas2557_i2c_probe -----\n"); //[jinjia]Trace
err:
return nResult;
}
static int tas2557_i2c_remove(struct i2c_client *pClient)
{
struct tas2557_priv *pTAS2557 = i2c_get_clientdata(pClient);
dev_info(pTAS2557->dev, "%s\n", __func__);
#ifdef CONFIG_TAS2557_CODEC
tas2557_deregister_codec(pTAS2557);
mutex_destroy(&pTAS2557->codec_lock);
#endif
#ifdef CONFIG_TAS2557_MISC
tas2557_deregister_misc(pTAS2557);
mutex_destroy(&pTAS2557->file_lock);
#endif
mutex_destroy(&pTAS2557->dev_lock);
return 0;
}
static const struct i2c_device_id tas2557_i2c_id[] = {
{"tas2557", 0},
{}
};
MODULE_DEVICE_TABLE(i2c, tas2557_i2c_id);
#if defined(CONFIG_OF)
static const struct of_device_id tas2557_of_match[] = {
{.compatible = "ti,tas2557"},
{},
};
MODULE_DEVICE_TABLE(of, tas2557_of_match);
#endif
static struct i2c_driver tas2557_i2c_driver = {
.driver = {
.name = "tas2557",
.owner = THIS_MODULE,
#if defined(CONFIG_OF)
.of_match_table = of_match_ptr(tas2557_of_match),
#endif
},
.probe = tas2557_i2c_probe,
.remove = tas2557_i2c_remove,
.id_table = tas2557_i2c_id,
};
module_i2c_driver(tas2557_i2c_driver);
MODULE_AUTHOR("Texas Instruments Inc.");
MODULE_DESCRIPTION("TAS2557 I2C Smart Amplifier driver");
MODULE_LICENSE("GPL v2");
#endif