blob: 907aed48d7c608234f884fe694a0dc8a57cb91f4 [file] [log] [blame]
/*
* Copyright (C) 2012-2013 Motorola Mobility, LLC.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* 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.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* 02111-1307, USA
*/
#include <linux/cdev.h>
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/firmware.h>
#include <linux/init.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/i2c.h>
#include <linux/gpio.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/pm.h>
#include <linux/slab.h>
#include <linux/regulator/consumer.h>
#include <sound/tfa9890.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
#include <sound/soc-dapm.h>
#include <sound/initval.h>
#include <sound/tlv.h>
#include "tfa9890-core.h"
#define DSP_ENABLE 1 /* DSP is enabled or bypassed */
#define I2C_RETRY_DELAY 5 /* ms */
#define I2C_RETRIES 5
#define PLL_SYNC_RETRIES 10
#define MTPB_RETRIES 5
#define DSP_TRANSFER_RETRIES 50
#define TFA9890_RATES SNDRV_PCM_RATE_KNOT
#define TFA9890_FORMATS (SNDRV_PCM_FMTBIT_S16_LE)
#define FIRMWARE_NAME_SIZE 128
#define TFA9890_STATUS_UP_MASK (TFA9890_STATUS_PLLS | \
TFA9890_STATUS_CLKS | \
TFA9890_STATUS_VDDS | \
TFA9890_STATUS_ARFS)
struct tfa9890_priv {
struct i2c_client *control_data;
struct regulator *vdd;
struct snd_soc_codec *codec;
struct workqueue_struct *tfa9890_wq;
struct work_struct init_work;
struct work_struct calib_work;
struct work_struct mode_work;
struct work_struct load_preset;
struct delayed_work delay_work;
struct mutex dsp_init_lock;
struct mutex i2c_rw_lock;
int dsp_init;
int speaker_imp;
int sysclk;
int rst_gpio;
int max_vol_steps;
int mode;
int mode_switched;
int curr_mode;
int vol_idx;
int curr_vol_idx;
int ic_version;
};
static const struct tfa9890_regs tfa9890_reg_defaults[] = {
{
.reg = TFA9890_BATT_CTL_REG,
.value = 0x9392,
},
{
.reg = TFA9890_I2S_CTL_REG,
#if DSP_ENABLE
.value = 0x888b, /* sampling rate = 48000Hz, dsp output */
#else
.value = 0x880b, /* sampling rate = 48000Hz, output is I2S input left channel, dsp bypassed */
#endif
},
{
.reg = TFA9890_VOL_CTL_REG,
.value = 0x182f, /* Volume level can be changed only in DSP */
},
{
.reg = TFA9890_SPK_CTL_REG,
.value = 0x3800,
},
{
.reg = TFA9890_DC2DC_CTL_REG,
.value = 0x8FE6,
},
{
.reg = TFA9890_SYS_CTL1_REG,
#if DSP_ENABLE
.value = 0x826d, /* I2S1 is selected, dsp on*/
#else
.value = 0x8269, /* I2S1 is selected, dsp off*/
#endif
},
{
.reg = TFA9890_SYS_CTL2_REG,
.value = 0x38D2,
},
{
.reg = TFA9890_PWM_CTL_REG,
.value = 0x0308,
},
{
.reg = TFA9890_CURRT_SNS1_REG,
.value = 0x7be1,
},
{
.reg = TFA9890_CURRC_SNS_REG,
.value = 0xAD93,
},
{
.reg = TFA9890_CURRT_CTL_REG,
.value = 0x4000,
},
{
.reg = TFA9890_DEM_CTL_REG,
.value = 0x00,
},
{
.reg = TFA9890_CURRT_SNS2_REG,
.value = 0x340,
},
};
/* presets tables per volume step for different modes */
static char const *fw_path;
static char const *tfa9890_preset_tables[] = {
"tfa9890_music_table.preset",
"tfa9890_voice_table.preset",
"tfa9890_ringtone_table.preset",
};
static char const *tfa9890_mode[] = {
"tfa9890_music",
"tfa9890_voice",
"tfa9890_ringtone",
};
static const struct firmware *fw_pst_table[ARRAY_SIZE(tfa9890_mode)];
/* table used by ALSA core while creating codec register
* access debug fs.
*/
static u8 tfa9890_reg_readable[TFA9890_REG_CACHE_SIZE] = {
[TFA9890_SYS_STATUS_REG] = 1,
[TFA9890_BATT_STATUS_REG] = 1,
[TFA9890_TEMP_STATUS_REG] = 1,
[TFA9890_REV_ID] = 1,
[TFA9890_I2S_CTL_REG] = 1,
[TFA9890_BATT_CTL_REG] = 1,
[TFA9890_VOL_CTL_REG] = 1,
[TFA9890_DC2DC_CTL_REG] = 1,
[TFA9890_SPK_CTL_REG] = 1,
[TFA9890_SYS_CTL1_REG] = 1,
[TFA9890_SYS_CTL2_REG] = 1,
[TFA9890_MTP_KEY_REG] = 1,
[TFA9890_LDO_REG] = 1,
[TFA9890_PWM_CTL_REG] = 1,
[TFA9890_CURRT_SNS1_REG] = 1,
[TFA9890_CURRT_SNS2_REG] = 1,
[TFA9890_CURRC_SNS_REG] = 1,
[TFA9890_CURRT_CTL_REG] = 1,
[TFA9890_DEM_CTL_REG] = 1,
[TFA9890_MTP_COPY_REG] = 1,
[TFA9890_CF_CONTROLS] = 1,
[TFA9890_CF_MAD] = 1,
[TFA9890_CF_MEM] = 0,
[TFA9890_CF_STATUS] = 1,
[TFA9890_MTP_REG] = 1,
};
static u32 tfa9890_asrc_rates[] = {
8000, 11025, 16000, 22050,
24000, 32000, 44100, 48000
};
static struct snd_pcm_hw_constraint_list tfa9890_rate_constraints = {
.count = ARRAY_SIZE(tfa9890_asrc_rates),
.list = tfa9890_asrc_rates,
};
/*
* I2C Read/Write Functions
*/
static int tfa9890_i2c_read(struct i2c_client *tfa9890_client,
u8 reg, u8 *value, int len)
{
int err;
int tries = 0;
struct i2c_msg msgs[] = {
{
.addr = tfa9890_client->addr,
.flags = 0,
.len = 1,
.buf = &reg,
},
{
.addr = tfa9890_client->addr,
.flags = I2C_M_RD,
.len = len,
.buf = value,
},
};
do {
err = i2c_transfer(tfa9890_client->adapter, msgs,
ARRAY_SIZE(msgs));
if (err != ARRAY_SIZE(msgs))
msleep_interruptible(I2C_RETRY_DELAY);
} while ((err != ARRAY_SIZE(msgs)) && (++tries < I2C_RETRIES));
if (err != ARRAY_SIZE(msgs)) {
dev_err(&tfa9890_client->dev, "read transfer error %d\n"
, err);
err = -EIO;
} else {
err = 0;
}
return err;
}
static int tfa9890_i2c_write(struct i2c_client *tfa9890_client,
u8 *value, u8 len)
{
int err;
int tries = 0;
struct i2c_msg msgs[] = {
{
.addr = tfa9890_client->addr,
.flags = 0,
.len = len,
.buf = value,
},
};
do {
err = i2c_transfer(tfa9890_client->adapter, msgs,
ARRAY_SIZE(msgs));
if (err != ARRAY_SIZE(msgs))
msleep_interruptible(I2C_RETRY_DELAY);
} while ((err != ARRAY_SIZE(msgs)) && (++tries < I2C_RETRIES));
if (err != ARRAY_SIZE(msgs)) {
dev_err(&tfa9890_client->dev, "write transfer error\n");
err = -EIO;
} else {
err = 0;
}
return err;
}
static int tfa9890_bulk_write(struct snd_soc_codec *codec, unsigned int reg,
const void *data, size_t len)
{
struct tfa9890_priv *tfa9890 = snd_soc_codec_get_drvdata(codec);
u8 chunk_buf[TFA9890_MAX_I2C_SIZE + 1];
int offset = 0;
int ret = 0;
/* first byte is mem address */
int remaining_bytes = len ;
int chunk_size = TFA9890_MAX_I2C_SIZE;
chunk_buf[0] = reg & 0xff;
mutex_lock(&tfa9890->i2c_rw_lock);
while ((remaining_bytes > 0)) {
if (remaining_bytes < chunk_size)
chunk_size = remaining_bytes;
memcpy(chunk_buf + 1, data + offset, chunk_size);
ret = tfa9890_i2c_write(codec->control_data, chunk_buf,
chunk_size + 1);
offset = offset + chunk_size;
remaining_bytes = remaining_bytes - chunk_size;
}
mutex_unlock(&tfa9890->i2c_rw_lock);
return ret;
}
static int tfa9890_write(struct snd_soc_codec *codec, unsigned int reg,
unsigned int val)
{
struct tfa9890_priv *tfa9890 = snd_soc_codec_get_drvdata(codec);
u8 buf[3] = {0, 0, 0};
int ret;
buf[0] = (reg & 0xff);
buf[1] = (val >> 8) & 0xff;
buf[2] = (val & 0xff);
mutex_lock(&tfa9890->i2c_rw_lock);
/* Temporary hack to prevent speaker blow-up */
if (reg == TFA9890_VOL_CTL_REG && buf[1] < 0x18) {
pr_info("Saturating volume at -12dB\n");
buf[1] = 0x18;
}
ret = tfa9890_i2c_write(codec->control_data, buf, ARRAY_SIZE(buf));
mutex_unlock(&tfa9890->i2c_rw_lock);
return ret;
}
static unsigned int tfa9890_read(struct snd_soc_codec *codec, unsigned int reg)
{
struct tfa9890_priv *tfa9890 = snd_soc_codec_get_drvdata(codec);
u8 buf[3];
int len;
int val = -EIO;
mutex_lock(&tfa9890->i2c_rw_lock);
/* check if we are reading from Device memory whose word size is
* 2 bytes or DSP memory whose word size is 3 bytes.
*/
if (reg == TFA9890_CF_MEM)
len = 3;
else
len = 2;
if (tfa9890_i2c_read(codec->control_data, reg & 0xff, buf, len) == 0) {
if (len == 3)
val = (buf[0] << 16 | buf[1] << 8 | buf[2]);
else if (len == 2)
val = (buf[0] << 8 | buf[1]);
}
mutex_unlock(&tfa9890->i2c_rw_lock);
return val;
}
static int tfa9890_bulk_read(struct snd_soc_codec *codec, u8 reg,
u8 *data, int len)
{
struct tfa9890_priv *tfa9890 = snd_soc_codec_get_drvdata(codec);
int ret = 0;
int offset = 0;
int remaining_bytes = len;
int chunk_size = TFA9890_MAX_I2C_SIZE;
mutex_lock(&tfa9890->i2c_rw_lock);
while ((remaining_bytes > 0)) {
if (remaining_bytes < chunk_size)
chunk_size = remaining_bytes;
ret = tfa9890_i2c_read(codec->control_data, reg, data + offset,
chunk_size);
offset = offset + chunk_size;
remaining_bytes = remaining_bytes - chunk_size;
}
mutex_unlock(&tfa9890->i2c_rw_lock);
return ret;
}
/* RPC Protocol to Access DSP Memory is implemented in tfa9890_dsp_transfer func
*- The host writes into a certain DSP memory location the data for the RPC
*- Module and Id of the function
*- Parameters for the function (in case of SetParam), maximum 145 parameters
*- The host triggers the DSP that there is valid RPC data
* - The DSP executes the RPC and stores the result
* -An error code
* -Return parameters (in case of GetParam)
* - The host reads the result
*/
static int tfa9890_dsp_transfer(struct snd_soc_codec *codec,
int module_id, int param_id, const u8 *bytes,
int len, int type, u8 *read)
{
u8 buffer[8];
/* DSP mem access control */
u16 cf_ctrl = TFA9890_CF_CTL_MEM_REQ;
/* memory address to be accessed (0 : Status, 1 : ID, 2 : parameters) */
u16 cf_mad = TFA9890_CF_MAD_ID;
int err;
int rpc_status;
int cf_status;
int tries = 0;
/* first the data for CF_CONTROLS */
buffer[0] = TFA9890_CF_CONTROLS;
buffer[1] = ((cf_ctrl >> 8) & 0xFF);
buffer[2] = (cf_ctrl & 0xFF);
/* write the contents of CF_MAD which is the subaddress
* following CF_CONTROLS.
*/
buffer[3] = ((cf_mad >> 8) & 0xFF);
buffer[4] = (cf_mad & 0xFF);
/* write the module and RPC id into CF_MEM, which follows CF_MAD */
buffer[5] = 0;
buffer[6] = module_id + 128;
buffer[7] = param_id;
err = codec->bulk_write_raw(codec, TFA9890_CF_CONTROLS, buffer,
ARRAY_SIZE(buffer));
if (err < 0) {
pr_err("tfa9890: Failed to Write DSP controls req %d:", err);
return err;
}
/* check transfer type */
if (type == TFA9890_DSP_WRITE) {
/* write data to DSP memory*/
err = codec->bulk_write_raw(codec, TFA9890_CF_MEM, bytes, len);
if (err < 0)
return err;
}
/* wake up the DSP to process the data */
cf_ctrl |= TFA9890_CF_ACK_REQ | TFA9890_CF_INT_REQ;
snd_soc_write(codec, TFA9890_CF_CONTROLS, cf_ctrl);
do {
/* wait for ~1 msec (max per spec) and check for DSP status */
msleep_interruptible(1);
cf_status = snd_soc_read(codec, TFA9890_CF_STATUS);
tries++;
} while ( (tries < DSP_TRANSFER_RETRIES) && ((cf_status & TFA9890_STATUS_CF) == 0) );
if ((cf_status & TFA9890_STATUS_CF) == 0) {
pr_err("tfa9890: Failed to ack DSP CTL req %d:", err);
return -EIO;
}
/* read the RPC Status */
cf_ctrl = TFA9890_CF_CTL_MEM_REQ;
buffer[0] = TFA9890_CF_CONTROLS;
buffer[1] = (unsigned char)((cf_ctrl >> 8) & 0xFF);
buffer[2] = (unsigned char)(cf_ctrl & 0xFF);
cf_mad = TFA9890_CF_MAD_STATUS;
buffer[3] = (unsigned char)((cf_mad >> 8) & 0xFF);
buffer[4] = (unsigned char)(cf_mad & 0xFF);
err = codec->bulk_write_raw(codec, TFA9890_CF_CONTROLS, buffer, 5);
if (err < 0) {
pr_err("tfa9890: Failed to Write NXP DSP CTL reg for rpc check%d",
err);
return err;
}
rpc_status = snd_soc_read(codec, TFA9890_CF_MEM);
if (rpc_status != TFA9890_STATUS_OK) {
pr_err("tfa9890: RPC status check failed %d",
err);
return -EIO;
}
if (type == TFA9890_DSP_READ) {
cf_mad = TFA9890_CF_MAD_PARAM;
snd_soc_write(codec, TFA9890_CF_MAD, cf_mad);
tfa9890_bulk_read(codec, TFA9890_CF_MEM,
read, len);
}
return 0;
}
/*
* ASOC controls
*/
/* 0dB min, 0.5dB steps */
static DECLARE_TLV_DB_SCALE(tlv_step_0_5, 0, 50, 0);
static int tfa9890_get_mode(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
struct tfa9890_priv *tfa9890 = snd_soc_codec_get_drvdata(codec);
ucontrol->value.integer.value[0] = tfa9890->curr_mode;
return 0;
}
static int tfa9890_set_mode(struct tfa9890_priv *tfa9890)
{
int ret;
if ((fw_pst_table[tfa9890->mode])->size !=
tfa9890->max_vol_steps*TFA9890_PST_FW_SIZE) {
pr_err("tfa9890: Data size check failed preset file");
return -EIO;
}
pr_debug("tfa9890: switching to mode: %s vol idx: %d",
tfa9890_mode[tfa9890->mode], tfa9890->vol_idx);
ret = tfa9890_dsp_transfer(tfa9890->codec, TFA9890_DSP_MOD_SPEAKERBOOST,
TFA9890_PARAM_SET_PRESET,
(fw_pst_table[tfa9890->mode])->data +
((TFA9890_PST_FW_SIZE)*
(tfa9890->max_vol_steps - tfa9890->vol_idx)),
TFA9890_PST_FW_SIZE, TFA9890_DSP_WRITE, 0);
if (ret < 0)
return ret;
tfa9890->mode_switched = 0;
tfa9890->curr_mode = tfa9890->mode;
tfa9890->curr_vol_idx = tfa9890->vol_idx;
return ret;
}
static int tfa9890_put_mode(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
struct tfa9890_priv *tfa9890 = snd_soc_codec_get_drvdata(codec);
u16 val;
int mode_value = ucontrol->value.integer.value[0];
int vol_value = ucontrol->value.integer.value[1];
mutex_lock(&tfa9890->dsp_init_lock);
/* check for boundary conditions */
if ((vol_value > tfa9890->max_vol_steps || vol_value < 0) ||
(mode_value > (ARRAY_SIZE(tfa9890_mode) - 1) ||
mode_value < 0)) {
pr_err("%s: invalid mode or vol index set", __func__);
mutex_unlock(&tfa9890->dsp_init_lock);
return -EINVAL;
}
if (vol_value == 0)
/* increment vol value to 1 for index 0, vol index 0 is not
* treated as mute for all streams in android, use
* nxp preset 1 for vol index 0.
*/
vol_value++;
if (tfa9890->curr_mode != mode_value ||
tfa9890->curr_vol_idx != vol_value) {
tfa9890->mode_switched = 1;
tfa9890->mode = mode_value;
tfa9890->vol_idx = vol_value;
val = snd_soc_read(codec, TFA9890_SYS_STATUS_REG);
/* audio session active switch the preset realtime */
if ((val & TFA9890_STATUS_UP_MASK) == TFA9890_STATUS_UP_MASK)
tfa9890_set_mode(tfa9890);
}
mutex_unlock(&tfa9890->dsp_init_lock);
return 1;
}
static const struct soc_enum tfa9890_mode_enum[] = {
SOC_ENUM_SINGLE_EXT(2, tfa9890_mode),
};
static const struct snd_kcontrol_new tfa9890_snd_controls[] = {
SOC_SINGLE_TLV("NXP Volume", TFA9890_VOL_CTL_REG,
8, 0xff, 0, tlv_step_0_5),
SOC_SINGLE_MULTI_EXT("NXP Mode", SND_SOC_NOPM, 0, 255,
0, 2, tfa9890_get_mode,
tfa9890_put_mode),
};
/* bit 6,7 : 01 - DSP bypassed, 10 - DSP used */
static const struct snd_kcontrol_new tfa9890_mixer_controls[] = {
SOC_DAPM_SINGLE("DSP Switch", TFA9890_I2S_CTL_REG, 6, 3, 0),
};
static const struct snd_soc_dapm_widget tfa9890_dapm_widgets[] = {
SND_SOC_DAPM_INPUT("I2S1"),
SND_SOC_DAPM_MIXER("NXP Output Mixer", SND_SOC_NOPM, 0, 0,
&tfa9890_mixer_controls[0],
ARRAY_SIZE(tfa9890_mixer_controls)),
};
static const struct snd_soc_dapm_route tfa9890_dapm_routes[] = {
{"NXP Output Mixer", "DSP Switch", "I2S1"},
};
/*
* DSP Read/Write/Setup Functions
*/
static int tfa9890_coldboot(struct snd_soc_codec *codec)
{
u8 coldpatch[7] = {0x00, 0x07, 0x81, 0x00,
0x00, 0x00, 0x01};
int ret;
u16 val;
/* This will cold boot the DSP */
ret = codec->bulk_write_raw(codec, TFA9890_CF_CONTROLS, coldpatch,
ARRAY_SIZE(coldpatch));
if (ret < 0)
return ret;
val = snd_soc_read(codec, TFA9890_SYS_STATUS_REG);
/* Check if cold started sucessfully */
if (TFA9890_STATUS_ACS & val)
ret = 0;
else
ret = -EINVAL;
return ret;
}
static void tfa9890_power(struct snd_soc_codec *codec, int on)
{
u16 val;
val = snd_soc_read(codec, TFA9890_SYS_CTL1_REG);
if (on)
val = val & ~(TFA9890_POWER_DOWN);
else
val = val | (TFA9890_POWER_DOWN);
snd_soc_write(codec, TFA9890_SYS_CTL1_REG, val);
}
static void tfa9890_set_mute(struct snd_soc_codec *codec, int mute_state)
{
u16 mute_val;
u16 amp_en;
/* read volume ctrl register */
mute_val = snd_soc_read(codec, TFA9890_VOL_CTL_REG);
/* read sys ctrl register */
amp_en = snd_soc_read(codec, TFA9890_SYS_CTL1_REG);
switch (mute_state) {
case TFA9890_MUTE_OFF:
/* unmute and enable amp */
mute_val = mute_val & ~(TFA9890_STATUS_MUTE);
amp_en = amp_en | (TFA9890_STATUS_AMPE);
amp_en = amp_en | (TFA9890_STATUS_DC2DC);
break;
case TFA9890_DIGITAL_MUTE:
/* mute amp and enable amp */
mute_val = mute_val | (TFA9890_STATUS_MUTE);
amp_en = amp_en | (TFA9890_STATUS_AMPE);
amp_en = amp_en & ~(TFA9890_STATUS_DC2DC);
break;
case TFA9890_AMP_MUTE:
/* turn off amp */
mute_val = mute_val & ~(TFA9890_STATUS_MUTE);
amp_en = amp_en & ~(TFA9890_STATUS_AMPE);
amp_en = amp_en & ~(TFA9890_STATUS_DC2DC);
break;
default:
break;
}
/* update register settings */
snd_soc_write(codec, TFA9890_VOL_CTL_REG, mute_val);
snd_soc_write(codec, TFA9890_SYS_CTL1_REG, amp_en);
}
static int tfa9890_read_spkr_imp(struct tfa9890_priv *tfa9890)
{
int imp;
u8 buf[3];
int ret;
ret = tfa9890_dsp_transfer(tfa9890->codec,
TFA9890_DSP_MOD_SPEAKERBOOST,
TFA9890_PARAM_GET_RE0, 0, ARRAY_SIZE(buf),
TFA9890_DSP_READ, buf);
if (ret == 0) {
imp = (buf[0] << 16 | buf[1] << 8 | buf[2]);
imp = imp/(1 << (23 - TFA9890_SPKR_IMP_EXP));
} else
imp = 0;
return imp;
}
#if 0
static int tfa9890_get_ic_ver(struct snd_soc_codec *codec)
{
u16 ver1;
u16 ver2;
u16 ver3;
int ret = TFA9890_N1C2;
/* read all the three IC version registers to determine tfa9890 type */
ver1 = snd_soc_read(codec, 0x8b) & TFA9890_N1B12_VER1_MASK;
ver2 = snd_soc_read(codec, 0x8c);
ver3 = snd_soc_read(codec, 0x8d) & TFA9890_N1B12_VER3_MASK;
if ((ver1 == TFA9890_N1B12_VER1_VAL) &&
(ver2 == TFA9890_N1B12_VER2_VAL) &&
(ver3 == TFA9890_N1B12_VER3_VAL)) {
pr_debug("tfa9890: n1b12 version detected\n");
ret = TFA9890_N1B12;
} else if (!ver1 && !ver2 && !ver3) {
pr_debug("tfa9890: n1b4 version detected\n");
ret = TFA9890_N1B4;
} else
/* if it not above types then it must be N1C2 ver type */
pr_debug("tfa9890: n1c2 version detected\n");
return ret;
}
#endif
static int tfa9890_wait_pll_sync(struct tfa9890_priv *tfa9890)
{
int ret = 0;
int tries = 0;
u16 val;
struct snd_soc_codec *codec = tfa9890->codec;
/* check if DSP pll is synced */
do {
val = snd_soc_read(codec, TFA9890_SYS_STATUS_REG);
if ((val & TFA9890_STATUS_UP_MASK) == TFA9890_STATUS_UP_MASK)
break;
msleep_interruptible(1);
} while ((++tries < PLL_SYNC_RETRIES));
if (tries == PLL_SYNC_RETRIES) {
pr_err("tfa9890:DSP pll sync failed!!");
ret = -EIO;
}
return ret;
}
static int tfa9887_load_dsp_patch(struct snd_soc_codec *codec, const u8 *fw,
int fw_len)
{
int index = 0;
int length;
int size = 0;
const u8 *fw_data;
int err = -EINVAL;
length = fw_len - TFA9890_PATCH_HEADER;
fw_data = fw + TFA9890_PATCH_HEADER;
/* process the firmware */
while (index < length) {
/* extract length from first two bytes*/
size = *(fw_data + index) + (*(fw_data + index + 1)) * 256;
index += 2;
if ((index + size) > length) {
/* outside the buffer, error in the input data */
pr_err("tfa9890: invalid length");
goto out;
}
if ((size) > TFA9890_MAX_I2C_SIZE) {
/* too big */
pr_err("tfa9890: ivalid dsp patch");
goto out;
}
err = codec->bulk_write_raw(codec, *(fw_data + index),
(fw_data + index), size);
if (err < 0) {
pr_err("tfa9890: writing dsp patch failed");
goto out;
}
index += size;
}
err = 0;
out:
return err;
}
static int tfa9890_load_config(struct tfa9890_priv *tfa9890)
{
struct snd_soc_codec *codec = tfa9890->codec;
int ret = -EIO;
const struct firmware *fw_speaker = NULL;
const struct firmware *fw_config = NULL;
const struct firmware *fw_coeff = NULL;
const struct firmware *fw_patch = NULL;
u16 val;
char *fw_name;
fw_name = kzalloc(FIRMWARE_NAME_SIZE, GFP_KERNEL);
if (!fw_name) {
pr_err("tfa9890: Failed to allocate fw_name\n");
goto out;
}
/* Load DSP config and firmware files */
/* check IC version to get correct firmware */
scnprintf(fw_name, FIRMWARE_NAME_SIZE, "%s/tfa9890_n1c3_2_1_1.patch",
fw_path);
ret = request_firmware(&fw_patch, fw_name, codec->dev);
if (ret) {
pr_err("tfa9890: Failed to locate tfa9890_n1c3_2_1_1.patch");
goto out;
}
if (fw_patch) {
ret = tfa9887_load_dsp_patch(codec, fw_patch->data,
fw_patch->size);
if (ret) {
pr_err("tfa9890: Failed to load dsp patch!!");
goto out;
}
}
scnprintf(fw_name, FIRMWARE_NAME_SIZE, "%s/tfa9890.speaker", fw_path);
ret = request_firmware(&fw_speaker, fw_name, codec->dev);
if (ret) {
pr_err("tfa9890: Failed to locate speaker model!!");
goto out;
}
if (fw_speaker->size != TFA9890_SPK_FW_SIZE) {
pr_err("tfa9890: Data size check failed for spkr model");
goto out;
}
ret = tfa9890_dsp_transfer(codec, TFA9890_DSP_MOD_SPEAKERBOOST,
TFA9890_PARAM_SET_LSMODEL, fw_speaker->data,
fw_speaker->size, TFA9890_DSP_WRITE, 0);
if (ret < 0)
goto out;
scnprintf(fw_name, FIRMWARE_NAME_SIZE, "%s/tfa9890.config", fw_path);
ret = request_firmware(&fw_config, fw_name, codec->dev);
if (ret) {
pr_err("tfa9890: Failed to locate dsp config!!");
goto out;
}
if (fw_config->size != TFA9890_CFG_FW_SIZE) {
pr_err("%s: Data size check failed for config file", __func__);
goto out;
}
ret = tfa9890_dsp_transfer(codec, TFA9890_DSP_MOD_SPEAKERBOOST,
TFA9890_PARAM_SET_CONFIG, fw_config->data,
fw_config->size, TFA9890_DSP_WRITE, 0);
if (ret < 0)
goto out;
ret = tfa9890_set_mode(tfa9890);
if (ret < 0)
goto out;
scnprintf(fw_name, FIRMWARE_NAME_SIZE, "%s/tfa9890.eq", fw_path);
ret = request_firmware(&fw_coeff, fw_name, codec->dev);
if (ret) {
pr_err("tfa9890: Failed to locate DSP coefficients");
goto out;
}
if (fw_coeff->size != TFA9890_COEFF_FW_SIZE) {
pr_err("tfa9890: Data size check failed coefficients");
goto out;
}
ret = tfa9890_dsp_transfer(codec, TFA9890_DSP_MOD_BIQUADFILTERBANK,
0, fw_coeff->data, fw_coeff->size,
TFA9890_DSP_WRITE, 0);
if (ret < 0)
goto out;
/* set all dsp config loaded */
val = (u16)snd_soc_read(codec, TFA9890_SYS_CTL1_REG);
val = val | TFA9890_SYSCTRL_CONFIGURED;
snd_soc_write(codec, TFA9890_SYS_CTL1_REG, val);
ret = 0;
out:
kfree(fw_name);
/* release firmware */
release_firmware(fw_speaker);
release_firmware(fw_coeff);
release_firmware(fw_config);
release_firmware(fw_patch);
return ret;
}
static void tfa9890_calibaration(struct tfa9890_priv *tfa9890)
{
u16 val;
struct snd_soc_codec *codec = tfa9890->codec;
/* Ensure no audio playback while calibarating but leave
* amp enabled*/
tfa9890_set_mute(codec, TFA9890_DIGITAL_MUTE);
/* unlock write access MTP memory*/
snd_soc_write(codec, TFA9890_MTP_KEY_REG, TFA9890_MTK_KEY);
val = snd_soc_read(codec, TFA9890_MTP_REG);
/* set MTPOTC = 1 & MTPEX = 0*/
val = val | TFA9890_MTPOTC;
val = val & (~(TFA9890_STATUS_MTPEX));
snd_soc_write(codec, TFA9890_MTP_REG, val);
/* set CIMTB to initiate copy of calib values */
val = snd_soc_read(codec, TFA9890_MTP_COPY_REG);
val = val | TFA9890_STATUS_CIMTP;
snd_soc_write(codec, TFA9890_MTP_COPY_REG, val);
}
static void tfa9890_work_read_imp(struct work_struct *work)
{
struct tfa9890_priv *tfa9890 =
container_of(work, struct tfa9890_priv, calib_work);
u16 val;
val = snd_soc_read(tfa9890->codec, TFA9890_SYS_STATUS_REG);
if ((val & TFA9890_STATUS_PLLS) && (val & TFA9890_STATUS_CLKS))
tfa9890->speaker_imp = tfa9890_read_spkr_imp(tfa9890);
}
static void tfa9890_work_mode(struct work_struct *work)
{
struct tfa9890_priv *tfa9890 =
container_of(work, struct tfa9890_priv, mode_work);
int ret;
mutex_lock(&tfa9890->dsp_init_lock);
/* check if DSP pll is synced, It should be sync'ed at this point */
ret = tfa9890_wait_pll_sync(tfa9890);
if (ret < 0)
goto out;
tfa9890_set_mode(tfa9890);
out:
mutex_unlock(&tfa9890->dsp_init_lock);
}
static void tfa9890_load_preset(struct work_struct *work)
{
struct tfa9890_priv *tfa9890 =
container_of(work, struct tfa9890_priv, load_preset);
struct snd_soc_codec *codec = tfa9890->codec;
int ret;
int i;
char *preset_name;
preset_name = kzalloc(FIRMWARE_NAME_SIZE, GFP_KERNEL);
if (!preset_name) {
tfa9890->dsp_init = TFA9890_DSP_INIT_FAIL;
pr_err("tfa9890 : Load preset allocation failure\n");
return;
}
for (i = 0; i < ARRAY_SIZE(fw_pst_table); i++) {
scnprintf(preset_name, FIRMWARE_NAME_SIZE, "%s/%s",
fw_path, tfa9890_preset_tables[i]);
ret = request_firmware(&fw_pst_table[i],
preset_name,
codec->dev);
if (ret || (fw_pst_table[i]->size !=
tfa9890->max_vol_steps*TFA9890_PST_FW_SIZE)) {
pr_err("tfa9890: Failed to locate DSP preset table %s",
preset_name);
tfa9890->dsp_init = TFA9890_DSP_INIT_FAIL;
break;
}
}
kfree(preset_name);
}
static void tfa9890_monitor(struct work_struct *work)
{
struct tfa9890_priv *tfa9890 =
container_of(work, struct tfa9890_priv,
delay_work.work);
u16 val;
mutex_lock(&tfa9890->dsp_init_lock);
val = snd_soc_read(tfa9890->codec, TFA9890_SYS_STATUS_REG);
pr_debug("%s: status:0x%x", __func__, val);
/* check IC status bits: cold start, amp switching, speaker error
* and DSP watch dog bit to re init */
if ((TFA9890_STATUS_ACS & val) || (TFA9890_STATUS_WDS & val) ||
(TFA9890_STATUS_SPKS & val) ||
!(TFA9890_STATUS_AMP_SWS & val)) {
tfa9890->dsp_init = TFA9890_DSP_INIT_PENDING;
/* schedule init now if the clocks are up and stable */
if ((val & TFA9890_STATUS_UP_MASK) == TFA9890_STATUS_UP_MASK)
queue_work(tfa9890->tfa9890_wq, &tfa9890->init_work);
} /* else just reschedule */
queue_delayed_work(tfa9890->tfa9890_wq, &tfa9890->delay_work,
5*HZ);
mutex_unlock(&tfa9890->dsp_init_lock);
}
static void tfa9890_dsp_init(struct work_struct *work)
{
struct tfa9890_priv *tfa9890 =
container_of(work, struct tfa9890_priv, init_work);
struct snd_soc_codec *codec = tfa9890->codec;
u16 val;
int ret;
mutex_lock(&tfa9890->dsp_init_lock);
#if DSP_ENABLE
/* check if DSP pll is synced, It should be sync'ed at this point */
ret = tfa9890_wait_pll_sync(tfa9890);
if (ret < 0)
goto out;
val = snd_soc_read(codec, TFA9890_SYS_STATUS_REG);
pr_info("tfa9890: Initializing DSP, status:0x%x", val);
/* cold boot device before loading firmware and parameters */
ret = tfa9890_coldboot(codec);
if (ret < 0) {
pr_err("tfa9890: cold boot failed!!");
goto out;
}
ret = tfa9890_load_config(tfa9890);
if (ret < 0) {
pr_err("tfa9890: load dsp config failed!!");
goto out;
}
val = snd_soc_read(codec, TFA9890_MTP_REG);
/* check if calibaration completed, Calibaration is one time event.
* Will be done only once when device boots up for the first time.Once
* calibarated info is stored in non-volatile memory of the device.
* It will be part of the factory test to validate spkr imp.
* The MTPEX will be set to 1 always after calibration, on subsequent
* power down/up as well.
*/
if (!(val & TFA9890_STATUS_MTPEX)) {
pr_info("tfa9890:Calib not completed initiating ..");
tfa9890_calibaration(tfa9890);
} else
/* speaker impedence available to read */
tfa9890->speaker_imp = tfa9890_read_spkr_imp(tfa9890);
#endif
tfa9890->dsp_init = TFA9890_DSP_INIT_DONE;
mutex_unlock(&tfa9890->dsp_init_lock);
return;
out:
/* retry firmware load failure, according to NXP
* due to PLL instability firmware loading could corrupt
* DSP memory, putting the dsp in reset and adding additional
* delay should avoid this situation, but its safe retry loading
* all fimrware file again if we detect failure here.
*/
tfa9890->dsp_init = TFA9890_DSP_INIT_PENDING;
mutex_unlock(&tfa9890->dsp_init_lock);
}
/*
* ASOC OPS
*/
static int tfa9890_set_dai_sysclk(struct snd_soc_dai *codec_dai,
int clk_id, unsigned int freq, int dir)
{
struct tfa9890_priv *tfa9890 =
snd_soc_codec_get_drvdata(codec_dai->codec);
tfa9890->sysclk = freq;
return 0;
}
static int tfa9890_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
{
struct snd_soc_codec *codec = codec_dai->codec;
u16 val;
/* set master/slave audio interface */
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
case SND_SOC_DAIFMT_CBS_CFS:
/* default value */
break;
case SND_SOC_DAIFMT_CBM_CFM:
default:
/* only supports Slave mode */
pr_err("tfa9890: invalid DAI master/slave interface\n");
return -EINVAL;
}
val = snd_soc_read(codec, TFA9890_I2S_CTL_REG);
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
case SND_SOC_DAIFMT_I2S:
/* default value */
break;
case SND_SOC_DAIFMT_RIGHT_J:
val = val & ~(TFA9890_FORMAT_MASK);
val = val | TFA9890_FORMAT_LSB;
snd_soc_write(codec, TFA9890_I2S_CTL_REG, val);
break;
case SND_SOC_DAIFMT_LEFT_J:
val = val & ~(TFA9890_FORMAT_MASK);
val = val | TFA9890_FORMAT_MSB;
snd_soc_write(codec, TFA9890_I2S_CTL_REG, val);
break;
default:
pr_err("tfa9890: invalid DAI interface format\n");
return -EINVAL;
}
return 0;
}
static int tfa9890_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
struct snd_soc_codec *codec = dai->codec;
struct tfa9890_priv *tfa9890 = snd_soc_codec_get_drvdata(codec);
u16 val;
int bclk;
int bclk_ws_ratio;
int bclk_div;
/* validate and set params */
if (params_format(params) != SNDRV_PCM_FORMAT_S16_LE) {
pr_err("tfa9890: invalid pcm bit lenght\n");
return -EINVAL;
}
val = snd_soc_read(codec, TFA9890_I2S_CTL_REG);
/* clear Sample rate bits */
val = val & ~(TFA887_SAMPLE_RATE);
switch (params_rate(params)) {
case 8000:
snd_soc_write(codec, TFA9890_I2S_CTL_REG, val);
break;
case 11025:
val = val | TFA9890_SAMPLE_RATE_11k;
snd_soc_write(codec, TFA9890_I2S_CTL_REG, val);
break;
case 12000:
val = val | TFA9890_SAMPLE_RATE_12k;
snd_soc_write(codec, TFA9890_I2S_CTL_REG, val);
break;
case 16000:
val = val | TFA9890_SAMPLE_RATE_16k;
snd_soc_write(codec, TFA9890_I2S_CTL_REG, val);
break;
case 22050:
val = val | TFA9890_SAMPLE_RATE_22k;
snd_soc_write(codec, TFA9890_I2S_CTL_REG, val);
break;
case 24000:
val = val | TFA9890_SAMPLE_RATE_24k;
snd_soc_write(codec, TFA9890_I2S_CTL_REG, val);
break;
case 32000:
val = val | TFA9890_SAMPLE_RATE_32k;
snd_soc_write(codec, TFA9890_I2S_CTL_REG, val);
break;
case 44100:
val = val | TFA9890_SAMPLE_RATE_44k;
break;
case 48000:
val = val | TFA9890_SAMPLE_RATE_48k;
break;
default:
pr_err("tfa9890: invalid sample rate\n");
return -EINVAL;
}
snd_soc_write(codec, TFA9890_I2S_CTL_REG, val);
/* calc bclk to ws freq ratio, tfa9890 supports only 32, 48, 64 */
bclk_div = tfa9890->sysclk/(params_rate(params) * 16 * 2);
bclk = tfa9890->sysclk/bclk_div;
bclk_ws_ratio = bclk/params_rate(params);
if (bclk_ws_ratio != 32 && bclk_ws_ratio != 48
&& bclk_ws_ratio != 64) {
pr_err("tfa9890: invalid bit clk to ws freq ratio %d:",
bclk_ws_ratio);
return -EINVAL;
}
return 0;
}
static int tfa9890_mute(struct snd_soc_dai *dai, int mute)
{
struct snd_soc_codec *codec = dai->codec;
struct tfa9890_priv *tfa9890 = snd_soc_codec_get_drvdata(codec);
u16 val;
u16 tries = 0;
if (mute) {
#if DSP_ENABLE
cancel_delayed_work_sync(&tfa9890->delay_work);
#endif
tfa9890_set_mute(codec, TFA9890_AMP_MUTE);
do {
/* need to wait for amp to stop switching, to minimize
* pop, else I2S clk is going away too soon interrupting
* the dsp from smothering the amp pop while turning it
* off, It shouldn't take more than 50 ms for the amp
* switching to stop.
*/
usleep_range(50000, 50000);
val = snd_soc_read(codec, TFA9890_SYS_STATUS_REG);
if (!(val & TFA9890_STATUS_AMP_SWS))
break;
} while ((++tries < 20));
} else {
mutex_lock(&tfa9890->dsp_init_lock);
if (tfa9890->dsp_init == TFA9890_DSP_INIT_PENDING) {
/* if the initialzation is pending treat it as cold
* startcase, need to put the dsp in reset and and
* power it up after additional delay to make sure
* the pll is stable. once the init is done this step
* is not needed for warm start as the dsp firmware
* patch configures the PLL for stable startup.
*/
snd_soc_write(codec, TFA9890_CF_CONTROLS, 0x1);
/* power up IC */
tfa9890_power(codec, 1);
#if DSP_ENABLE
tfa9890_wait_pll_sync(tfa9890);
/* wait additional 3msec for PLL to be stable */
usleep_range(3000, 3000);
/* take DSP out of reset */
snd_soc_write(codec, TFA9890_CF_CONTROLS, 0x0);
#endif
}
tfa9890_set_mute(codec, TFA9890_MUTE_OFF);
/* start monitor thread to check IC status bit 5secs, and
* re-init IC to recover.
*/
#if DSP_ENABLE
queue_delayed_work(tfa9890->tfa9890_wq, &tfa9890->delay_work,
HZ);
#endif
mutex_unlock(&tfa9890->dsp_init_lock);
}
return 0;
}
static int tfa9890_startup(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct snd_soc_codec *codec = dai->codec;
struct tfa9890_priv *tfa9890 = snd_soc_codec_get_drvdata(dai->codec);
pr_debug("%s: enter\n", __func__);
/* power up IC here only on warm start, if the initialization
* is still pending the DSP will be put in reset and powered
* up ater firmware load in the mute function where clock is up.
*/
if (tfa9890->dsp_init == TFA9890_DSP_INIT_DONE)
tfa9890_power(codec, 1);
return snd_pcm_hw_constraint_list(substream->runtime, 0,
SNDRV_PCM_HW_PARAM_RATE,
&tfa9890_rate_constraints);
}
static void tfa9890_shutdown(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
pr_debug("%s: enter\n", __func__);
tfa9890_power(dai->codec, 0);
}
/* Trigger callback is atomic function, It gets called when pcm is started */
static int tfa9890_trigger(struct snd_pcm_substream *substream, int cmd,
struct snd_soc_dai *dai)
{
struct tfa9890_priv *tfa9890 = snd_soc_codec_get_drvdata(dai->codec);
int ret = 0;
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
/* To initialize dsp all the I2S signals should be bought up,
* so that the DSP's internal PLL can sync up and memory becomes
* accessible. Trigger callback is called when pcm write starts,
* so this should be the place where DSP is initialized
*/
if (tfa9890->dsp_init == TFA9890_DSP_INIT_PENDING)
queue_work(tfa9890->tfa9890_wq, &tfa9890->init_work);
/* will need to read speaker impedence here if its not read yet
* to complete the calibartion process. This step will enable
* device to calibrate if its not calibrated/validated in the
* factory. When the factory process is in place speaker imp
* will be read from sysfs and validated.
*/
else if (tfa9890->dsp_init == TFA9890_DSP_INIT_DONE) {
#if DSP_ENABLE
if (tfa9890->mode_switched == 1)
queue_work(tfa9890->tfa9890_wq,
&tfa9890->mode_work);
if (tfa9890->speaker_imp == 0)
queue_work(tfa9890->tfa9890_wq,
&tfa9890->calib_work);
#endif
}
/* else nothing to do */
break;
case SNDRV_PCM_TRIGGER_RESUME:
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
case SNDRV_PCM_TRIGGER_STOP:
case SNDRV_PCM_TRIGGER_SUSPEND:
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
break;
default:
ret = -EINVAL;
}
return ret;
}
/*
* SysFS support
*/
static ssize_t tfa9890_show_spkr_imp(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct tfa9890_priv *tfa9890 =
i2c_get_clientdata(to_i2c_client(dev));
u16 val;
if (tfa9890->codec) {
val = snd_soc_read(tfa9890->codec, TFA9890_SYS_STATUS_REG);
if ((val & TFA9890_STATUS_PLLS) &&
(val & TFA9890_STATUS_CLKS))
/* if I2S CLKS are ON read from DSP mem, otherwise print
* stored value as DSP mem cannot be accessed.
*/
tfa9890->speaker_imp =
tfa9890_read_spkr_imp(tfa9890);
}
return scnprintf(buf, PAGE_SIZE, "%u\n", tfa9890->speaker_imp);
}
static ssize_t tfa9890_show_dev_state_info(struct file *filp,
struct kobject *kobj,
struct bin_attribute *attr,
char *buf, loff_t off, size_t count)
{
struct tfa9890_priv *tfa9890 =
i2c_get_clientdata(kobj_to_i2c_client(kobj));
u16 val;
if (off >= attr->size)
return 0;
if (off + count > attr->size)
count = attr->size - off;
if (tfa9890->codec) {
val = snd_soc_read(tfa9890->codec, TFA9890_SYS_STATUS_REG);
if ((val & TFA9890_STATUS_PLLS) &&
(val & TFA9890_STATUS_CLKS)) {
tfa9890_dsp_transfer(tfa9890->codec,
TFA9890_DSP_MOD_SPEAKERBOOST,
TFA9890_PARAM_GET_STATE,
0, attr->size, TFA9890_DSP_READ, buf);
return count;
}
}
return 0;
}
static ssize_t tfa9890_show_spkr_imp_model(struct file *filp,
struct kobject *kobj,
struct bin_attribute *attr,
char *buf, loff_t off, size_t count)
{
struct tfa9890_priv *tfa9890 =
i2c_get_clientdata(kobj_to_i2c_client(kobj));
u16 val;
if (off >= attr->size)
return 0;
if (off + count > attr->size)
count = attr->size - off;
if (tfa9890->codec) {
val = snd_soc_read(tfa9890->codec, TFA9890_SYS_STATUS_REG);
if ((val & TFA9890_STATUS_PLLS) &&
(val & TFA9890_STATUS_CLKS)) {
tfa9890_dsp_transfer(tfa9890->codec,
TFA9890_DSP_MOD_SPEAKERBOOST,
TFA9890_PARAM_GET_LSMODEL,
0, attr->size, TFA9890_DSP_READ, buf);
return count;
}
}
return 0;
}
static ssize_t tfa9890_show_spkr_exc_model(struct file *filp,
struct kobject *kobj,
struct bin_attribute *attr,
char *buf, loff_t off, size_t count)
{
struct tfa9890_priv *tfa9890 =
i2c_get_clientdata(kobj_to_i2c_client(kobj));
u16 val;
if (off >= attr->size)
return 0;
if (off + count > attr->size)
count = attr->size - off;
if (tfa9890->codec) {
val = snd_soc_read(tfa9890->codec, TFA9890_SYS_STATUS_REG);
if ((val & TFA9890_STATUS_PLLS) &&
(val & TFA9890_STATUS_CLKS)) {
tfa9890_dsp_transfer(tfa9890->codec,
TFA9890_DSP_MOD_SPEAKERBOOST,
TFA9890_PARAM_GET_LSMODELW,
0, attr->size, TFA9890_DSP_READ, buf);
return count;
}
}
return 0;
}
static ssize_t tfa9890_show_config_preset(struct file *filp,
struct kobject *kobj,
struct bin_attribute *attr,
char *buf, loff_t off, size_t count)
{
struct tfa9890_priv *tfa9890 =
i2c_get_clientdata(kobj_to_i2c_client(kobj));
u16 val;
if (off >= attr->size)
return 0;
if (off + count > (attr->size))
count = (attr->size) - off;
if (tfa9890->codec) {
val = snd_soc_read(tfa9890->codec, TFA9890_SYS_STATUS_REG);
if ((val & TFA9890_STATUS_PLLS) &&
(val & TFA9890_STATUS_CLKS)) {
tfa9890_dsp_transfer(tfa9890->codec,
TFA9890_DSP_MOD_SPEAKERBOOST,
TFA9890_PARAM_GET_CFGPST,
0, (attr->size), TFA9890_DSP_READ, buf);
return count;
}
}
return 0;
}
static ssize_t tfa9890_show_ic_temp(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct tfa9890_priv *tfa9890 = i2c_get_clientdata(to_i2c_client(dev));
u16 val;
int temp = 0;
if (tfa9890->codec) {
val = snd_soc_read(tfa9890->codec, TFA9890_SYS_STATUS_REG);
if ((val & TFA9890_STATUS_PLLS) &&
(val & TFA9890_STATUS_CLKS)) {
/* calibaration should take place when the IC temp is
* between 0 and 50C, factory test command will verify
* factory test command will verify the temp along
* with impdedence to pass the test.
*/
val = snd_soc_read(tfa9890->codec,
TFA9890_TEMP_STATUS_REG);
temp = val & TFA9890_STATUS_TEMP;
}
}
return scnprintf(buf, PAGE_SIZE, "%u\n", temp);
}
static ssize_t tfa9890_force_calibaration(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
struct i2c_client *client = to_i2c_client(dev);
struct tfa9890_priv *tfa9890 = i2c_get_clientdata(client);
unsigned long val;
if (kstrtoul(buf, 10, &val))
return -EINVAL;
if (val < 0 || val > 1)
return -EINVAL;
tfa9890_calibaration(tfa9890);
return count;
}
static const struct bin_attribute tf9890_raw_bin_attr[] = {
{
.attr = {.name = "device_state", .mode = S_IRUGO},
.read = tfa9890_show_dev_state_info,
.size = TFA9890_DEV_STATE_SIZE,
},
{
.attr = {.name = "spkr_imp_model", .mode = S_IRUGO},
.read = tfa9890_show_spkr_imp_model,
.size = TFA9890_SPK_FW_SIZE - 1,
},
{
.attr = {.name = "config_preset", .mode = S_IRUGO},
.read = tfa9890_show_config_preset,
.size = TFA9890_CFG_FW_SIZE + TFA9890_PST_FW_SIZE - 2,
},
{
.attr = {.name = "spkr_exc_model", .mode = S_IRUGO},
.read = tfa9890_show_spkr_exc_model,
.size = TFA9890_SPK_EX_FW_SIZE - 1,
},
};
static DEVICE_ATTR(ic_temp, S_IRUGO,
tfa9890_show_ic_temp, NULL);
static DEVICE_ATTR(spkr_imp, S_IRUGO,
tfa9890_show_spkr_imp, NULL);
static DEVICE_ATTR(force_calib, S_IWUSR,
NULL, tfa9890_force_calibaration);
static struct attribute *tfa9890_attributes[] = {
&dev_attr_spkr_imp.attr,
&dev_attr_force_calib.attr,
&dev_attr_ic_temp.attr,
NULL
};
static const struct attribute_group tfa9890_attr_group = {
.attrs = tfa9890_attributes,
};
static const struct snd_soc_dai_ops tfa9890_ops = {
.hw_params = tfa9890_hw_params,
.digital_mute = tfa9890_mute,
.set_fmt = tfa9890_set_dai_fmt,
.set_sysclk = tfa9890_set_dai_sysclk,
.startup = tfa9890_startup,
.shutdown = tfa9890_shutdown,
.trigger = tfa9890_trigger,
};
static struct snd_soc_dai_driver tfa9890_dai = {
.name = "tfa9890_codec",
.playback = {
.stream_name = "Playback",
.channels_min = 1,
.channels_max = 2,
.rate_min = 8000,
.rate_max = 48000,
.rates = TFA9890_RATES,
.formats = TFA9890_FORMATS,},
.ops = &tfa9890_ops,
.symmetric_rates = 1,
};
static int tfa9890_probe(struct snd_soc_codec *codec)
{
struct tfa9890_priv *tfa9890 = snd_soc_codec_get_drvdata(codec);
int i;
/* set codec Bulk write method, will be used for
* loading DSP firmware and config files.
*/
codec->bulk_write_raw = tfa9890_bulk_write;
codec->control_data = tfa9890->control_data;
tfa9890->codec = codec;
/* reset registers to Default values */
snd_soc_write(codec, TFA9890_SYS_CTL1_REG, 0x0002);
/* initialize I2C registers */
for (i = 0; i < ARRAY_SIZE(tfa9890_reg_defaults); i++) {
snd_soc_write(codec, tfa9890_reg_defaults[i].reg,
tfa9890_reg_defaults[i].value);
}
/* add controls and didgets */
snd_soc_add_codec_controls(codec, tfa9890_snd_controls,
ARRAY_SIZE(tfa9890_snd_controls));
snd_soc_dapm_new_controls(&codec->dapm, tfa9890_dapm_widgets,
ARRAY_SIZE(tfa9890_dapm_widgets));
snd_soc_dapm_add_routes(&codec->dapm, tfa9890_dapm_routes,
ARRAY_SIZE(tfa9890_dapm_routes));
snd_soc_dapm_new_widgets(&codec->dapm);
snd_soc_dapm_sync(&codec->dapm);
/* load preset tables */
queue_work(tfa9890->tfa9890_wq, &tfa9890->load_preset);
pr_info("tfa9890 codec registered");
return 0;
}
static int tfa9890_remove(struct snd_soc_codec *codec)
{
tfa9890_power(codec, 0);
return 0;
}
static int tfa9890_readable(struct snd_soc_codec *codec, unsigned int reg)
{
return tfa9890_reg_readable[reg];
}
static struct snd_soc_codec_driver soc_codec_dev_tfa9890 = {
.read = tfa9890_read,
.write = tfa9890_write,
.probe = tfa9890_probe,
.remove = tfa9890_remove,
.readable_register = tfa9890_readable,
.reg_cache_size = TFA9890_REG_CACHE_SIZE,
.reg_cache_default = tfa9890_reg_defaults,
.reg_word_size = 2,
};
#ifdef CONFIG_OF
static struct tfa9890_pdata *
tfa9890_of_init(struct i2c_client *client)
{
struct tfa9890_pdata *pdata;
struct device_node *np = client->dev.of_node;
if (of_property_read_string(np, "tfa9890_bin_path", &fw_path))
fw_path = ".";
pdata = devm_kzalloc(&client->dev, sizeof(*pdata), GFP_KERNEL);
if (!pdata) {
pr_err("%s : pdata allocation failure\n", __func__);
return NULL;
}
of_property_read_u32(np, "nxp,tfa_max-vol-steps",
&pdata->max_vol_steps);
pdata->reset_gpio = of_get_gpio(np, 0);
return pdata;
}
#else
static inline struct tfa9890_pdata *
tfa9890_of_init(struct i2c_client *client)
{
return NULL;
}
#endif
static int tfa9890_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
struct tfa9890_pdata *pdata;
struct tfa9890_priv *tfa9890;
int ret;
int i;
if (!i2c_check_functionality(i2c->adapter, I2C_FUNC_I2C)) {
dev_err(&i2c->dev, "check_functionality failed\n");
return -EIO;
}
if (i2c->dev.of_node)
pdata = tfa9890_of_init(i2c);
else
pdata = i2c->dev.platform_data;
/* check platform data */
if (pdata == NULL) {
dev_err(&i2c->dev,
"platform data is NULL\n");
return -EINVAL;
}
tfa9890 = devm_kzalloc(&i2c->dev, sizeof(struct tfa9890_priv),
GFP_KERNEL);
if (tfa9890 == NULL)
return -ENOMEM;
tfa9890->rst_gpio = pdata->reset_gpio;
tfa9890->max_vol_steps = pdata->max_vol_steps;
tfa9890->control_data = i2c;
tfa9890->dsp_init = TFA9890_DSP_INIT_PENDING;
tfa9890->vol_idx = pdata->max_vol_steps;
tfa9890->curr_vol_idx = pdata->max_vol_steps;
i2c_set_clientdata(i2c, tfa9890);
mutex_init(&tfa9890->dsp_init_lock);
mutex_init(&tfa9890->i2c_rw_lock);
/* enable regulator */
tfa9890->vdd = regulator_get(&i2c->dev, "tfa_vdd");
if (IS_ERR(tfa9890->vdd)) {
pr_err("%s: Error getting vdd regulator.\n", __func__);
ret = PTR_ERR(tfa9890->vdd);
goto reg_get_fail;
}
/* Doesnt work on 3.10 kernel
regulator_set_voltage(tfa9890->vdd, 1800000, 1800000);
*/
ret = regulator_enable(tfa9890->vdd);
if (ret < 0) {
pr_err("%s: Error enabling vdd regulator %d:", __func__, ret);
goto reg_enable_fail;
}
/* register sysfs hooks */
ret = sysfs_create_group(&i2c->dev.kobj, &tfa9890_attr_group);
if (ret)
pr_err("%s: Error registering tfa9890 sysfs\n", __func__);
for (i = 0; i < ARRAY_SIZE(tf9890_raw_bin_attr); i++) {
ret = sysfs_create_bin_file(&i2c->dev.kobj,
&tf9890_raw_bin_attr[i]);
if (ret)
pr_warn("%s: Error creating tfa9890 sysfs bin attr\n",
__func__);
}
/* setup work queue, will be used to initial DSP on first boot up */
tfa9890->tfa9890_wq =
create_singlethread_workqueue("tfa9890");
if (tfa9890->tfa9890_wq == NULL) {
ret = -ENOMEM;
goto wq_fail;
}
INIT_WORK(&tfa9890->init_work, tfa9890_dsp_init);
INIT_WORK(&tfa9890->calib_work, tfa9890_work_read_imp);
INIT_WORK(&tfa9890->mode_work, tfa9890_work_mode);
INIT_WORK(&tfa9890->load_preset, tfa9890_load_preset);
INIT_DELAYED_WORK(&tfa9890->delay_work, tfa9890_monitor);
ret = gpio_request(tfa9890->rst_gpio, "tfa reset gpio");
if (ret < 0) {
pr_err("%s: tfa reset gpio_request failed: %d\n",
__func__, ret);
goto gpio_fail;
}
/* take IC out of reset, device registers are reset in codec probe
* through register write.
*/
gpio_direction_output(tfa9890->rst_gpio, 0);
/* register codec */
ret = snd_soc_register_codec(&i2c->dev,
&soc_codec_dev_tfa9890, &tfa9890_dai, 1);
if (ret < 0) {
pr_err("%s: Error registering tfa9890 codec", __func__);
goto codec_fail;
}
pr_info("tfa9890 probed successfully!");
return ret;
codec_fail:
gpio_free(tfa9890->rst_gpio);
gpio_fail:
destroy_workqueue(tfa9890->tfa9890_wq);
wq_fail:
snd_soc_unregister_codec(&i2c->dev);
reg_enable_fail:
regulator_disable(tfa9890->vdd);
regulator_put(tfa9890->vdd);
reg_get_fail:
return ret;
}
static int tfa9890_i2c_remove(struct i2c_client *client)
{
struct tfa9890_priv *tfa9890 = i2c_get_clientdata(client);
snd_soc_unregister_codec(&client->dev);
regulator_disable(tfa9890->vdd);
gpio_free(tfa9890->rst_gpio);
regulator_put(tfa9890->vdd);
destroy_workqueue(tfa9890->tfa9890_wq);
return 0;
}
static const struct i2c_device_id tfa9890_i2c_id[] = {
{ "tfa9890", 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, tfa9890_i2c_id);
#ifdef CONFIG_OF
static struct of_device_id tfa9890_match_tbl[] = {
{ .compatible = "nxp,tfa9890" },
{ },
};
MODULE_DEVICE_TABLE(of, tfa9890_match_tbl);
#endif
static struct i2c_driver tfa9890_i2c_driver = {
.driver = {
.name = "tfa9890",
.owner = THIS_MODULE,
.of_match_table = of_match_ptr(tfa9890_match_tbl),
},
.probe = tfa9890_i2c_probe,
.remove = tfa9890_i2c_remove,
.id_table = tfa9890_i2c_id,
};
static int __init tfa9890_modinit(void)
{
int ret;
ret = i2c_add_driver(&tfa9890_i2c_driver);
if (ret != 0) {
pr_err("Failed to register tfa9890 I2C driver: %d\n",
ret);
}
return ret;
}
module_init(tfa9890_modinit);
static void __exit tfa9890_exit(void)
{
i2c_del_driver(&tfa9890_i2c_driver);
}
module_exit(tfa9890_exit);
MODULE_DESCRIPTION("ASoC tfa9890 codec driver");
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Motorola Mobility");