audio:add ti2558 speaker protection

add ti2558 speaker protection related code.
add ko in kbuild for sofiar

Change-Id: I6c7aa5c53bff4724a4fc3d2a6df07433c7ee71a6
Signed-off-by: liaohj <liaohj@lenovo.com>
Reviewed-on: https://gerrit.mot.com/1405309
SLTApproved: Slta Waiver
SME-Granted: SME Approvals Granted
Tested-by: Jira Key
Reviewed-by: Wanlong Zhou <zhouwl@motorola.com>
Reviewed-by: Hujun Liao <liaohj@motorola.com>
Submit-Approved: Jira Key
This commit is contained in:
liaohj 2019-08-20 16:22:02 +08:00 • committed by Hujun Liao
commit 636b9f2ed8
6 changed files with 1159 additions and 42 deletions

View file

@ -20,7 +20,7 @@ EXTRA_CFLAGS += -DCONFIG_TAS2560_REGMAP -DCONFIG_TAS2560_CODEC -DCONFIG_TAS2560_
endif
ifneq (,$(filter sofiar%, $(TARGET_PRODUCT)))
EXTRA_CFLAGS += -DCONFIG_TAS2562_REGMAP -DCONFIG_TAS2562_CODEC -DCONFIG_SND_SOC_TAS2562 -DTAS2558_CODEC
EXTRA_CFLAGS += -DCONFIG_TAS2562_REGMAP -DCONFIG_TAS2562_CODEC -DCONFIG_SND_SOC_TAS2562 -DTAS2558_CODEC -DCONFIG_TAS25XX_ALGO -DCONFIG_TAS25XX_ALGO_STEREO
endif
ifneq (,$(filter rav%, $(TARGET_PRODUCT)))
@ -58,5 +58,5 @@ obj-m += tas2560_algo.o
tas2560_calib-objs = tas2560-calib.o
obj-m += tas2560_calib.o
tas2562-objs = tas2562-codec.o tas2562-regmap.o
tas2562-objs = tas2562-codec.o tas2562-regmap.o tas25xx-algo.o tas25xx-calib.o
obj-m += tas2562.o

View file

@ -44,6 +44,11 @@
#include "tas2562.h"
#ifdef CONFIG_TAS25XX_ALGO
#include <dsp/tas_smart_amp_v2.h>
#include "tas25xx-calib.h"
#endif /*CONFIG_TAS25XX_ALGO*/
#define TAS2562_MDELAY 0xFFFFFFFE
#define TAS2562_MSLEEP 0xFFFFFFFD
#define TAS2562_IVSENSER_ENABLE 1
@ -93,7 +98,7 @@ static unsigned int tas2562_codec_read(struct snd_soc_codec *codec,
{
struct tas2562_priv *p_tas2562 = snd_soc_codec_get_drvdata(codec);
dev_err(p_tas2562->dev, "Should not get here\n");
dev_dbg(p_tas2562->dev, "Should not get here\n");
return 0;
}
@ -128,7 +133,7 @@ static int tas2562iv_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct tas2562_priv *p_tas2562 = snd_soc_codec_get_drvdata(codec);
struct tas2562_priv *p_tas2562 = NULL;
int iv_enable = 0, n_result = 0;
if (codec == NULL) {
@ -136,6 +141,12 @@ static int tas2562iv_put(struct snd_kcontrol *kcontrol,
return 0;
}
p_tas2562 = snd_soc_codec_get_drvdata(codec);
if (p_tas2562 == NULL) {
pr_err("%s:p_tas2562 is NULL\n", __func__);
return 0;
}
iv_enable = ucontrol->value.integer.value[0];
n_result = tas2562_iv_enable(p_tas2562, iv_enable);
@ -149,9 +160,20 @@ static int tas2562iv_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct tas2562_priv *p_tas2562 = snd_soc_codec_get_drvdata(codec);
struct tas2562_priv *p_tas2562 = NULL;
int ret, value;
if (codec == NULL) {
pr_err("%s:codec is NULL\n", __func__);
return 0;
}
p_tas2562 = snd_soc_codec_get_drvdata(codec);
if (p_tas2562 == NULL) {
pr_err("%s:p_tas2562 is NULL\n", __func__);
return 0;
}
ret = p_tas2562->read(p_tas2562, channel_left,
TAS2562_POWERCONTROL, &value);
if (ret < 0)
@ -183,7 +205,7 @@ static int tas2562_codec_write(struct snd_soc_codec *codec, unsigned int reg,
{
struct tas2562_priv *p_tas2562 = snd_soc_codec_get_drvdata(codec);
dev_err(p_tas2562->dev, "Should not get here\n");
dev_dbg(p_tas2562->dev, "Should not get here\n");
return 0;
}
@ -245,6 +267,7 @@ static int tas2562_i2c_load_data(struct tas2562_priv *p_tas2562,
return n_result;
}
#ifdef CODEC_PM
static int tas2562_codec_suspend(struct snd_soc_codec *codec)
{
struct tas2562_priv *p_tas2562 = snd_soc_codec_get_drvdata(codec);
@ -272,6 +295,7 @@ static int tas2562_codec_resume(struct snd_soc_codec *codec)
mutex_unlock(&p_tas2562->codec_lock);
return ret;
}
#endif
static int tas2562_set_power_state(struct tas2562_priv *p_tas2562,
enum channel chn, int state)
@ -376,16 +400,12 @@ static const struct snd_soc_dapm_widget tas2562_dapm_widgets[] = {
SND_SOC_DAPM_AIF_IN("ASI1", "ASI1 Playback", 0, SND_SOC_NOPM, 0, 0),
SND_SOC_DAPM_DAC_E("DAC", NULL, SND_SOC_NOPM, 0, 0, tas2562_dac_event,
SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
SND_SOC_DAPM_OUTPUT("OUT"),
SND_SOC_DAPM_SIGGEN("VMON"),
SND_SOC_DAPM_SIGGEN("IMON")
SND_SOC_DAPM_OUTPUT("OUT")
};
static const struct snd_soc_dapm_route tas2562_audio_map[] = {
{"DAC", NULL, "ASI1"},
{"OUT", NULL, "DAC"},
{"Voltage Sense", NULL, "VMON"},
{"Current Sense", NULL, "IMON"},
{"OUT", NULL, "DAC"}
};
static int tas2562_get_left_speaker_switch(struct snd_kcontrol *pKcontrol,
@ -512,6 +532,7 @@ static int tas2562_set_slot(struct tas2562_priv *p_tas2562, int slot_width)
{
int ret = 0;
dev_info(p_tas2562->dev, "%s: slot_width = %d\n", __func__, slot_width);
switch (slot_width) {
case 16:
ret = p_tas2562->update_bits(p_tas2562, channel_both,
@ -955,10 +976,17 @@ static int tas2562_load_init(struct tas2562_priv *p_tas2562)
TAS2562_MISCCONFIGURATIONREG0, 0xcf);
if (ret < 0)
return ret;
ret = p_tas2562->write(p_tas2562, channel_both,
TAS2562_TDMConfigurationReg4, 0x01);
if (ret < 0)
return ret;
if(p_tas2562->mn_channels == 2) {
ret = p_tas2562->write(p_tas2562, channel_both,
TAS2562_TDMConfigurationReg4, 0x11);
if (ret < 0)
return ret;
} else {
ret = p_tas2562->write(p_tas2562, channel_both,
TAS2562_TDMConfigurationReg4, 0x01);
if (ret < 0)
return ret;
}
ret = p_tas2562->write(p_tas2562, channel_both,
TAS2562_CLOCKCONFIGURATION, 0x0c);
if (ret < 0)
@ -984,6 +1012,10 @@ static int tas2562_codec_probe(struct snd_soc_codec *codec)
tas2562_load_init(p_tas2562);
tas2562_iv_enable(p_tas2562, 1);
#ifdef CONFIG_TAS25XX_ALGO
tas_smartamp_add_algo_controls(codec);
#endif //CONFIG_TAS25XX_ALGO
dev_err(p_tas2562->dev, "%s\n", __func__);
return 0;
@ -991,6 +1023,10 @@ static int tas2562_codec_probe(struct snd_soc_codec *codec)
static int tas2562_codec_remove(struct snd_soc_codec *codec)
{
#ifdef CONFIG_TAS25XX_ALGO
tas_smartamp_remove_algo_controls(codec);
#endif //CONFIG_TAS25XX_ALGO
return 0;
}
@ -1023,8 +1059,10 @@ static struct snd_soc_codec_driver soc_codec_driver_tas2562 = {
.remove = tas2562_codec_remove,
.read = tas2562_codec_read,
.write = tas2562_codec_write,
#ifdef CODEC_PM
.suspend = tas2562_codec_suspend,
.resume = tas2562_codec_resume,
#endif
.component_driver = {
.controls = tas2562_snd_controls,
.num_controls = ARRAY_SIZE(tas2562_snd_controls),

View file

@ -830,6 +830,34 @@ static int tas2562_runtime_resume(struct tas2562_priv *p_tas2562)
return 0;
}
static int tas2562_pm_suspend(struct device *dev)
{
struct tas2562_priv *p_tas2562 = dev_get_drvdata(dev);
if(!p_tas2562){
dev_err(p_tas2562->dev, "drvdata is NULL\n");
return -EINVAL;
}
mutex_lock(&p_tas2562->codec_lock);
tas2562_runtime_suspend(p_tas2562);
mutex_unlock(&p_tas2562->codec_lock);
return 0;
}
static int tas2562_pm_resume(struct device *dev)
{
struct tas2562_priv *p_tas2562 = dev_get_drvdata(dev);
if(!p_tas2562){
dev_err(p_tas2562->dev, "drvdata is NULL\n");
return -EINVAL;
}
mutex_lock(&p_tas2562->codec_lock);
tas2562_runtime_resume(p_tas2562);
mutex_unlock(&p_tas2562->codec_lock);
return 0;
}
static int tas2562_parse_dt(struct device *dev, struct tas2562_priv *p_tas2562)
{
struct device_node *np = dev->of_node;
@ -863,16 +891,6 @@ static int tas2562_parse_dt(struct device *dev, struct tas2562_priv *p_tas2562)
p_tas2562->mn_l_addr);
}
rc = of_property_read_u32(np, "ti,right-channel",
&p_tas2562->mn_r_addr);
if (rc) {
dev_err(p_tas2562->dev, "Looking up %s property in node %s failed %d\n",
"ti,right-channel", np->full_name, rc);
} else {
dev_dbg(p_tas2562->dev, "ti,right-channel=0x%x",
p_tas2562->mn_r_addr);
}
p_tas2562->mn_reset_gpio = of_get_named_gpio(np, "ti,reset-gpio", 0);
if (!gpio_is_valid(p_tas2562->mn_reset_gpio)) {
dev_err(p_tas2562->dev, "Looking up %s property in node %s failed %d\n",
@ -883,16 +901,6 @@ static int tas2562_parse_dt(struct device *dev, struct tas2562_priv *p_tas2562)
p_tas2562->mn_reset_gpio);
}
p_tas2562->mn_reset_gpio2 = of_get_named_gpio(np, "ti,reset-gpio2", 0);
if (!gpio_is_valid(p_tas2562->mn_reset_gpio2)) {
dev_err(p_tas2562->dev, "Looking up %s property in node %s failed %d\n",
"ti,reset-gpio2", np->full_name,
p_tas2562->mn_reset_gpio2);
} else {
dev_dbg(p_tas2562->dev, "ti,reset-gpio2=%d",
p_tas2562->mn_reset_gpio2);
}
p_tas2562->mn_irq_gpio = of_get_named_gpio(np, "ti,irq-gpio", 0);
if (!gpio_is_valid(p_tas2562->mn_irq_gpio)) {
dev_err(p_tas2562->dev, "Looking up %s property in node %s failed %d\n",
@ -902,13 +910,35 @@ static int tas2562_parse_dt(struct device *dev, struct tas2562_priv *p_tas2562)
p_tas2562->mn_irq_gpio);
}
p_tas2562->mn_irq_gpio2 = of_get_named_gpio(np, "ti,irq-gpio2", 0);
if (!gpio_is_valid(p_tas2562->mn_irq_gpio2)) {
dev_err(p_tas2562->dev, "Looking up %s property in node %s failed %d\n",
if(p_tas2562->mn_channels != 1) {
rc = of_property_read_u32(np, "ti,right-channel",
&p_tas2562->mn_r_addr);
if (rc) {
dev_err(p_tas2562->dev, "Looking up %s property in node %s failed %d\n",
"ti,right-channel", np->full_name, rc);
} else {
dev_dbg(p_tas2562->dev, "ti,right-channel=0x%x",
p_tas2562->mn_r_addr);
}
p_tas2562->mn_reset_gpio2 = of_get_named_gpio(np, "ti,reset-gpio2", 0);
if (!gpio_is_valid(p_tas2562->mn_reset_gpio2)) {
dev_dbg(p_tas2562->dev, "Looking up %s property in node %s failed %d\n",
"ti,reset-gpio2", np->full_name,
p_tas2562->mn_reset_gpio2);
} else {
dev_dbg(p_tas2562->dev, "ti,reset-gpio2=%d",
p_tas2562->mn_reset_gpio2);
}
p_tas2562->mn_irq_gpio2 = of_get_named_gpio(np, "ti,irq-gpio2", 0);
if (!gpio_is_valid(p_tas2562->mn_irq_gpio2)) {
dev_dbg(p_tas2562->dev, "Looking up %s property in node %s failed %d\n",
"ti,irq-gpio2", np->full_name, p_tas2562->mn_irq_gpio2);
} else {
dev_dbg(p_tas2562->dev, "ti,irq-gpio2=%d",
p_tas2562->mn_irq_gpio2);
} else {
dev_dbg(p_tas2562->dev, "ti,irq-gpio2=%d",
p_tas2562->mn_irq_gpio2);
}
}
return ret;
@ -978,9 +1008,12 @@ static int tas2562_i2c_probe(struct i2c_client *p_client,
p_tas2562->update_bits = tas2562_dev_update_bits;
p_tas2562->hw_reset = tas2562_hw_reset;
p_tas2562->enable_irq = tas2562_enable_irq;
#ifdef CODEC_PM
p_tas2562->runtime_suspend = tas2562_runtime_suspend;
p_tas2562->runtime_resume = tas2562_runtime_resume;
p_tas2562->mn_power_state = TAS2562_POWER_SHUTDOWN;
#endif
p_tas2562->mn_power_state = TAS2562_POWER_SHUTDOWN;
p_tas2562->spk_l_control = 1;
mutex_init(&p_tas2562->dev_lock);
@ -1117,6 +1150,10 @@ static const struct of_device_id tas2562_of_match[] = {
MODULE_DEVICE_TABLE(of, tas2562_of_match);
#endif
static const struct dev_pm_ops tas2562_pm_ops = {
.suspend = tas2562_pm_suspend,
.resume = tas2562_pm_resume
};
static struct i2c_driver tas2562_i2c_driver = {
.driver = {
@ -1125,6 +1162,7 @@ static struct i2c_driver tas2562_i2c_driver = {
#if defined(CONFIG_OF)
.of_match_table = of_match_ptr(tas2562_of_match),
#endif
.pm = &tas2562_pm_ops,
},
.probe = tas2562_i2c_probe,
.remove = tas2562_i2c_remove,

View file

@ -0,0 +1,822 @@
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/version.h>
#include <linux/device.h>
#include <linux/string.h>
#include <linux/syscalls.h>
#include <linux/fs.h>
#include <dsp/q6afe-v2.h>
#include <dsp/tas_smart_amp_v2.h>
#include "tas25xx-calib.h"
#define USE_VFS 1
#define CODEC_CONTROL 1
#define CONFIG_SET_RE_IN_KERNEL
#define POISON_VAL 0xDEADDEAD
#define MAX_STRING (300)
#define SMARTAMP_SPEAKER_CALIBDATA_FILE "/mnt/vendor/persist/factory/audio/tas25xx_calib.bin"
/*Master Control to Bypass the Smartamp TI CAPIv2 module*/
static int s_tas_smartamp_bypass = 0;
static int s_tas_smartamp_enable = 0;
static struct mutex routing_lock;
#ifdef CONFIG_SET_RE_IN_KERNEL
static int get_calibrated_re_tcalib (uint32_t *rdc_fix, uint32_t *tv_fix, int channel_count)
{
struct file *file = NULL;
char calib_data[MAX_STRING] = {0};
char filepath[128] = SMARTAMP_SPEAKER_CALIBDATA_FILE;
mm_segment_t fs;
int ret = 0;
static int s_rdc_fix[2] = {POISON_VAL, POISON_VAL};
static int s_tv_fix = POISON_VAL;
#if USE_VFS
loff_t pos = 0;
#else
int size;
int fd;
#endif
if ((s_rdc_fix[0] == POISON_VAL) &&
(s_rdc_fix[1] == POISON_VAL)
)
{
fs = get_fs();
set_fs(get_ds());
#if USE_VFS
file = filp_open(filepath, O_RDONLY, 0);
if(!IS_ERR(file))
{
vfs_read(file, calib_data, MAX_STRING-1, &pos);
if (channel_count == 1) {
if(sscanf(calib_data, "%d;%d;", s_rdc_fix, &s_tv_fix) != 2) {
pr_err("[Smartamp:%s] file %s read error\n", __func__, filepath);
ret = -EIO;
}
} else if (channel_count == 2) {
if(sscanf(calib_data, "%d;%d;%d;", &s_rdc_fix[0], &s_rdc_fix[1], &s_tv_fix) != 3) {
pr_err("[Smartamp:%s] file %s read error\n", __func__, filepath);
ret = -EIO;
}
}
filp_close(file, NULL);
} else {
pr_err("[Smartamp:%s] file %s open failed %p \n ", __func__, filepath, file);
ret = -EIO;
}
#else
fd = sys_open (filepath, O_RDONLY, 0);
if (fd > 0) {
memset (calib_data, 0, sizeof(calib_data));
size = sys_read (fd, calib_data, MAX_STRING-1);
sys_close (fd);
pr_info ("TI-SmartPA: *** sys_read size = %d", size);
if (channel_count == 1) {
if(sscanf(calib_data, "%d;%d;", &rdc_fix[0], tv_fix) != 2) {
pr_err("[TI-SmartPA:%s] file %s read error\n", __func__, filepath);
ret = -EIO;
}
} else if (channel_count == 2) {
if(sscanf(calib_data, "%d;%d;%d;", &rdc_fix[0], &rdc_fix[1], tv_fix) != 3) {
pr_err("[TI-SmartPA:%s] file %s read error\n", __func__, filepath);
ret = -EIO;
}
}
} else {
pr_err("[TI-SmartPA:%s] file %s open failed %p \n ", __func__, filepath, file);
ret = -EIO;
}
#endif
set_fs(fs);
}
if (ret == 0) {
if (rdc_fix) {
rdc_fix[0] = (uint32_t)s_rdc_fix[0];
if (channel_count == 2) {
rdc_fix[1] = (uint32_t)s_rdc_fix[1];
}
}
if (tv_fix)
*tv_fix = (uint32_t)s_tv_fix;
}
return ret;
}
#endif //CONFIG_SET_RE_IN_KERNEL
static int tas25xx_smartamp_get_set(u8 *user_data, uint32_t param_id,
uint8_t get_set, uint32_t length, uint32_t module_id)
{
int ret = 0;
switch (get_set) {
case TAS_SET_PARAM:
if (s_tas_smartamp_bypass) {
pr_err("TI-SmartPA: %s: SmartAmp is bypassed no control set", __func__);
goto fail_cmd;
}
ret = afe_tas_smartamp_set_calib_data(module_id, param_id, length, user_data);
break;
case TAS_GET_PARAM:
memset(user_data, 0, length);
ret = afe_tas_smartamp_get_calib_data(module_id, param_id, length, user_data);
break;
default:
goto fail_cmd;
}
fail_cmd:
return ret;
}
/*Wrapper arround set/get parameter, all set/get commands pass through this wrapper*/
int tas25xx_smartamp_algo_ctrl(u8 *user_data, uint32_t param_id,
uint8_t get_set, uint32_t length, uint32_t module_id)
{
int ret = 0;
mutex_lock(&routing_lock);
ret = tas25xx_smartamp_get_set(user_data, param_id, get_set, length, module_id);
mutex_unlock(&routing_lock);
return ret;
}
EXPORT_SYMBOL(tas25xx_smartamp_algo_ctrl);
/*Control-1: Set Profile*/
static const char *profile_index_text[] = { "NONE", TAS_ALGO_PROFILE_LIST, "CALIB"};
static const struct soc_enum profile_index_enum[] = {
SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(profile_index_text), profile_index_text),
};
static int tas25xx_set_profile(struct snd_kcontrol *pKcontrol,
struct snd_ctl_elem_value *pUcontrol)
{
int ret;
int profile_id = pUcontrol->value.integer.value[0];
int param_id = 0;
int max_number_of_profiles = sizeof(profile_index_text)/sizeof(profile_index_text[0]);
if (profile_id >= max_number_of_profiles)
return -EINVAL;
pr_info("TI-SmartPA: %s: Setting profile %s", __func__, profile_index_text[profile_id]);
if(profile_id)
profile_id -= 1;
else
return 0;
param_id = TAS_CALC_PARAM_IDX(TAS_SA_SET_PROFILE, 1, CHANNEL0);
pr_info("TI-SmartPA: %s: Sending set profile", __func__);
ret = tas25xx_smartamp_algo_ctrl((u8 *)&profile_id, param_id,
TAS_SET_PARAM, sizeof(uint32_t), AFE_SMARTAMP_MODULE_RX);
if(ret < 0)
pr_err("TI-SmartPA: %s: Failed to set config", __func__);
return ret;
}
static int tas25xx_get_profile(struct snd_kcontrol *pKcontrol,
struct snd_ctl_elem_value *pUcontrol)
{
int ret;
int profile_id = 0;
int param_id = 0;
int max_number_of_profiles = sizeof(profile_index_text)/sizeof(profile_index_text[0]);
if(s_tas_smartamp_enable) {
param_id = TAS_CALC_PARAM_IDX(TAS_SA_SET_PROFILE, 1, CHANNEL0);
ret = tas25xx_smartamp_algo_ctrl((u8 *)&profile_id, param_id,
TAS_GET_PARAM, sizeof(uint32_t), AFE_SMARTAMP_MODULE_RX);
if(ret < 0) {
pr_err("TI-SmartPA: %s: Failed to get profile", __func__);
profile_id = 0;
} else {
profile_id += 1;
}
}
pUcontrol->value.integer.value[0] = profile_id;
if (profile_id < max_number_of_profiles) {
pr_info("TI-SmartPA: %s: getting profile %s", __func__, profile_index_text[profile_id]);
}
return 0;
}
/*Control-2: Set Calibrated Rdc*/
static int tas25xx_set_Re_common (int re_value_in, int channel)
{
int ret;
int param_id = 0;
int re_value = re_value_in;
param_id = TAS_CALC_PARAM_IDX(TAS_SA_SET_RE, 1, channel);
ret = tas25xx_smartamp_algo_ctrl((u8 *)&re_value, param_id,
TAS_SET_PARAM, sizeof(uint32_t), AFE_SMARTAMP_MODULE_RX);
return ret;
}
static int tas25xx_set_Re_left(struct snd_kcontrol *pKcontrol,
struct snd_ctl_elem_value *pUcontrol)
{
int re_value = pUcontrol->value.integer.value[0];
pr_info("TI-SmartPA: %s: Setting Re %d", __func__, re_value);
return tas25xx_set_Re_common(re_value, CHANNEL0);
}
static int tas25xx_dummy_get(struct snd_kcontrol *pKcontrol,
struct snd_ctl_elem_value *pUcontrol)
{
int ret = 0;
pUcontrol->value.integer.value[0] = 0;
return ret;
}
static int tas25xx_dummy_set(struct snd_kcontrol *pKcontrol,
struct snd_ctl_elem_value *pUcontrol)
{
return 0;
}
/*Control-3: Calibration and Test(F0,Q,Tv) Controls*/
static const char *tas25xx_calib_test_text[] = {
"NONE",
"CALIB_START",
"CALIB_STOP",
"TEST_START",
"TEST_STOP"
};
static const struct soc_enum tas25xx_calib_test_enum[] = {
SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(tas25xx_calib_test_text), tas25xx_calib_test_text),
};
static int tas25xx_calib_test_set_common (int calib_command, int channel)
{
int ret = 0;
int param_id = 0;
int data = 1;
switch(calib_command) {
case CALIB_START:
pr_info ("TI-SmartPA: %s: CALIB_START", __func__);
param_id = TAS_CALC_PARAM_IDX (TAS_SA_CALIB_INIT, 1, channel);
break;
case CALIB_STOP:
pr_info ("TI-SmartPA: %s: CALIB_STOP", __func__);
param_id = TAS_CALC_PARAM_IDX (TAS_SA_CALIB_DEINIT, 1, channel);
break;
case TEST_START:
case TEST_STOP:
default:
pr_info ("TI-SmartPA: %s: no impl", __func__);
ret = -EINVAL;
break;
}
if (param_id) {
ret = tas25xx_smartamp_algo_ctrl ((u8 *)&data, param_id,
TAS_SET_PARAM, sizeof (uint32_t), AFE_SMARTAMP_MODULE_RX);
if(ret < 0) {
pr_err("TI-SmartPA: %s: Failed to set calib/test, ret=%d", __func__, ret);
}
}
return ret;
}
static int tas25xx_calib_test_set(struct snd_kcontrol *pKcontrol,
struct snd_ctl_elem_value *pUcontrol)
{
int ret = 0;
int user_data = pUcontrol->value.integer.value[0];
if ((0 == (ret = tas25xx_calib_test_set_common (user_data, CHANNEL0)))) {
#ifdef CONFIG_TAS25XX_ALGO_STEREO
ret = tas25xx_calib_test_set_common (user_data, CHANNEL1);
#endif
}
return ret;
}
/*Control-4: Get Re*/
//returns -ve error or +ve re value, 0 if not called
static int tas25xx_get_re_common (int channel)
{
int ret = 0;
int re_value = 0;
int param_id = 0;
pr_info("TI-SmartPA: %s, channel=%d", __func__, channel);
if(s_tas_smartamp_enable) {
param_id = TAS_CALC_PARAM_IDX (TAS_SA_GET_RE, 1, channel);
ret = tas25xx_smartamp_algo_ctrl ((u8 *)&re_value, param_id,
TAS_GET_PARAM, sizeof(uint32_t), AFE_SMARTAMP_MODULE_RX);
if(ret < 0) {
pr_err("TI-SmartPA: %s: Failed to get Re", __func__);
} else {
ret = re_value;
}
}
return ret;
}
static int tas25xx_get_re_left(struct snd_kcontrol *pKcontrol,
struct snd_ctl_elem_value *pUcontrol)
{
int ret = tas25xx_get_re_common (CHANNEL0);
if (ret >= 0) {
pUcontrol->value.integer.value[0] = ret;
ret = 0;
pr_info("TI-SmartPA: %s: Getting Re %d", __func__, ret);
}
return ret;
}
/*Control-5: Get F0*/
static int tas25xx_get_f0_common(int channel)
{
int f0_value = 0;
int param_id = 0;
int ret = 0;
pr_info("TI-SmartPA: %s, channel=%d", __func__, channel);
if(s_tas_smartamp_enable) {
param_id = TAS_CALC_PARAM_IDX(TAS_SA_GET_F0, 1, channel);
ret = tas25xx_smartamp_algo_ctrl ((u8 *)&f0_value, param_id,
TAS_GET_PARAM, sizeof(uint32_t), AFE_SMARTAMP_MODULE_RX);
if (ret < 0) {
pr_err ("TI-SmartPA: %s: Failed to get F0", __func__);
} else {
ret = f0_value;
}
}
return ret;
}
static int tas25xx_get_f0_left(struct snd_kcontrol *pKcontrol,
struct snd_ctl_elem_value *pUcontrol)
{
int ret = tas25xx_get_f0_common (CHANNEL0);
if (ret >= 0) {
pUcontrol->value.integer.value[0] = ret;
pr_info("TI-SmartPA: %s: Getting F0 val=%d", __func__, ret);
ret = 0;
}
return ret;
}
/*Control-6: Get Q*/
static int tas25xx_get_q_common (int channel)
{
int ret = 0;
int q_value = 0;
int param_id = 0;
pr_info("TI-SmartPA: %s, channel=%d", __func__, channel);
if (s_tas_smartamp_enable) {
param_id = TAS_CALC_PARAM_IDX (TAS_SA_GET_Q, 1, channel);
ret = tas25xx_smartamp_algo_ctrl ((u8 *)&q_value, param_id,
TAS_GET_PARAM, sizeof(uint32_t), AFE_SMARTAMP_MODULE_RX);
if (ret < 0) {
pr_err ("TI-SmartPA: %s: Failed to get F0", __func__);
} else {
ret = q_value;
}
}
return ret;
}
static int tas25xx_get_q_left(struct snd_kcontrol *pKcontrol,
struct snd_ctl_elem_value *pUcontrol)
{
int ret = tas25xx_get_q_common (CHANNEL0);
if (ret >= 0) {
pUcontrol->value.integer.value[0] = ret;
pr_info("TI-SmartPA: %s: Getting Q %d", __func__, ret);
ret = 0;
}
return ret;
}
/*Control-7: Get Tv*/
static int tas25xx_get_tv_common(int channel)
{
int ret = 0;
int tv_value = 0;
int param_id = 0;
pr_info("TI-SmartPA: %s, channel=%d", __func__, channel);
if (s_tas_smartamp_enable) {
param_id = TAS_CALC_PARAM_IDX(TAS_SA_GET_TV, 1, channel);
ret = tas25xx_smartamp_algo_ctrl((u8 *)&tv_value, param_id,
TAS_GET_PARAM, sizeof(uint32_t), AFE_SMARTAMP_MODULE_RX);
if (ret < 0) {
pr_err ("TI-SmartPA: %s: Failed to get Tv", __func__);
} else {
ret = tv_value;
}
}
return ret;
}
static int tas25xx_get_tv_left(struct snd_kcontrol *pKcontrol,
struct snd_ctl_elem_value *pUcontrol)
{
int ret = tas25xx_get_tv_common (CHANNEL0);
if (ret >= 0) {
pUcontrol->value.integer.value[0] = ret;
pr_info("TI-SmartPA: %s: Getting Tv %d", __func__, ret);
ret = 0;
}
return ret;
}
/*Control-8: Smartamp Enable*/
static const char *tas25xx_smartamp_enable_text[] = {
"DISABLE",
"ENABLE"
};
static const struct soc_enum tas25xx_smartamp_enable_enum[] = {
SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(tas25xx_smartamp_enable_text), tas25xx_smartamp_enable_text),
};
static int tas25xx_smartamp_enable_set(struct snd_kcontrol *pKcontrol,
struct snd_ctl_elem_value *pUcontrol)
{
int ret = 0;
int param_id = 0;
int user_data = pUcontrol->value.integer.value[0];
#ifdef CONFIG_SET_RE_IN_KERNEL
uint32_t calibration_data[3];
#endif
#ifdef CONFIG_TAS25XX_ALGO_STEREO
int number_of_ch = 2;
#else
int number_of_ch = 1;
#endif
pr_info("TI-SmartPA: %s: case %d, number_of_ch=%d", __func__, user_data, number_of_ch);
s_tas_smartamp_enable = user_data;
if (s_tas_smartamp_enable == 0) {
pr_info("TI-SmartPA: %s: Disable called", __func__);
return 0;
}
pr_info ("TI-SmartPA: %s: Setting the feedback module info for TAS", __func__);
ret = afe_spk_prot_feed_back_cfg (TAS_TX_PORT,TAS_RX_PORT, 1, 0, 1);
if (ret) {
pr_err("TI-SmartPA: %s: FB Path Info failed ignoring ret = 0x%x", __func__, ret);
}
pr_info ("TI-SmartPA: %s: Sending TX Enable", __func__);
param_id = CAPI_V2_TAS_TX_ENABLE;
ret = tas25xx_smartamp_algo_ctrl ((u8 *)&user_data, param_id,
TAS_SET_PARAM, sizeof(uint32_t), AFE_SMARTAMP_MODULE_TX);
if (ret) {
pr_err("TI-SmartPA: %s: TX Enable Failed ret = 0x%x", __func__, ret);
goto fail_cmd;
}
//Special configuration indicating bin file
user_data = 0xB1B1B1B1;
pr_info("TI-SmartPA: %s: Sending TX Config", __func__);
param_id = CAPI_V2_TAS_TX_CFG;
ret = tas25xx_smartamp_algo_ctrl((u8 *)&user_data, param_id,
TAS_SET_PARAM, sizeof(uint32_t), AFE_SMARTAMP_MODULE_TX);
if(ret < 0) {
pr_err("TI-SmartPA: %s: Failed to set config", __func__);
}
user_data = 1;
pr_info ("TI-SmartPA: %s: Sending RX Enable", __func__);
param_id = CAPI_V2_TAS_RX_ENABLE;
ret = tas25xx_smartamp_algo_ctrl ((u8 *)&user_data, param_id,
TAS_SET_PARAM, sizeof(uint32_t), AFE_SMARTAMP_MODULE_RX);
if(ret) {
pr_err("TI-SmartPA: %s: RX Enable Failed ret = 0x%x", __func__, ret);
goto fail_cmd;
}
//Special configuration indicating bin file
user_data = 0xB1B1B1B1;
pr_info("TI-SmartPA: %s: Sending RX Config", __func__);
param_id = CAPI_V2_TAS_RX_CFG;
ret = tas25xx_smartamp_algo_ctrl((u8 *)&user_data, param_id,
TAS_SET_PARAM, sizeof(uint32_t), AFE_SMARTAMP_MODULE_RX);
if(ret < 0) {
pr_err("TI-SmartPA: %s: Failed to set config", __func__);
}
s_tas_smartamp_enable = true;
#ifdef CONFIG_SET_RE_IN_KERNEL
if (number_of_ch == 2) {
ret = get_calibrated_re_tcalib (calibration_data, &calibration_data[2], number_of_ch);
} else {
ret = get_calibrated_re_tcalib (calibration_data, &calibration_data[1], number_of_ch);
}
if(ret) {
pr_err("[Smartamp:%s] unable to get the calibration data = 0x%x", __func__, ret);
} else {
int32_t t_cal;
if (number_of_ch == 2) {
t_cal = calibration_data[2];
pr_info("[Smartamp:%s] setting re %d,%d and tcal %d", __func__
, calibration_data[0], calibration_data[1], calibration_data[2]);
} else {
t_cal = calibration_data[1];
pr_info("[Smartamp:%s] setting re %d and tcal %d", __func__
, calibration_data[0], calibration_data[1]);
}
param_id = TAS_CALC_PARAM_IDX(TAS_SA_SET_TCAL, 1, CHANNEL0);
ret = tas25xx_smartamp_algo_ctrl ((u8 *)&t_cal,
param_id, TAS_SET_PARAM, sizeof(uint32_t), AFE_SMARTAMP_MODULE_RX);
if(ret < 0) {
pr_err("[Smartamp:%s] Failed to set Tcal", __func__);
goto fail_cmd;
}
param_id = TAS_CALC_PARAM_IDX(TAS_SA_SET_RE, 1, CHANNEL0);
ret = tas25xx_smartamp_algo_ctrl ((u8 *)(&(calibration_data[0])),
param_id, TAS_SET_PARAM, sizeof(uint32_t), AFE_SMARTAMP_MODULE_RX);
if (ret < 0) {
pr_err("TI-SmartPA: %s: Failed to set Re", __func__);
goto fail_cmd;
}
if (number_of_ch == 2) {
param_id = TAS_CALC_PARAM_IDX(TAS_SA_SET_RE, 1, CHANNEL1);
ret = tas25xx_smartamp_algo_ctrl ((u8 *)&(calibration_data[1]),
param_id, TAS_SET_PARAM, sizeof(uint32_t), AFE_SMARTAMP_MODULE_RX);
if(ret < 0) {
pr_err("TI-SmartPA: %s: Failed to set Re", __func__);
goto fail_cmd;
}
}
}
#endif //CONFIG_SET_RE_IN_KERNEL
fail_cmd:
return ret;
}
static int tas25xx_smartamp_enable_get(struct snd_kcontrol *pKcontrol,
struct snd_ctl_elem_value *pUcontrol)
{
int ret = 0;
int user_data = s_tas_smartamp_enable;
pUcontrol->value.integer.value[0] = user_data;
pr_info("TI-SmartPA: %s: case %d(0=DISABLE, 1=ENABLE)", __func__, user_data);
return ret;
}
/*Control-9: Smartamp Bypass */
static const char *tas25xx_smartamp_bypass_text[] = {
"FALSE",
"TRUE"
};
static const struct soc_enum tas25xx_smartamp_bypass_enum[] = {
SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(tas25xx_smartamp_bypass_text), tas25xx_smartamp_bypass_text),
};
static int tas25xx_smartamp_bypass_set(struct snd_kcontrol *pKcontrol,
struct snd_ctl_elem_value *pUcontrol)
{
int ret = 0;
int user_data = pUcontrol->value.integer.value[0];
if (s_tas_smartamp_enable) {
pr_debug("TI-SmartPA: %s: cannot update while smartamp enabled", __func__);
return -EINVAL;
}
s_tas_smartamp_bypass = user_data;
pr_info("TI-SmartPA: %s: case %d(FALSE=0,TRUE=1)", __func__, user_data);
return ret;
}
static int tas25xx_smartamp_bypass_get(struct snd_kcontrol *pKcontrol,
struct snd_ctl_elem_value *pUcontrol)
{
int ret = 0;
pUcontrol->value.integer.value[0] = s_tas_smartamp_bypass;
pr_info("TI-SmartPA: %s: case %d", __func__, s_tas_smartamp_bypass);
return ret;
}
static int tas25xx_set_spk_id(struct snd_kcontrol *pKcontrol,
struct snd_ctl_elem_value *pUcontrol)
{
int ret = 0;
int speaker_id = pUcontrol->value.integer.value[0];
int param_id = 0;
pr_info("TI-SmartPA: %s: spk-id set %d", __func__, speaker_id);
param_id = TAS_CALC_PARAM_IDX(TAS_SA_SET_SPKID, 1, CHANNEL0);
ret = tas25xx_smartamp_algo_ctrl((u8 *)&speaker_id, param_id,
TAS_SET_PARAM, sizeof(uint32_t), AFE_SMARTAMP_MODULE_RX);
if (ret < 0) {
pr_err ("TI-SmartPA: %s: Failed to set spk id", __func__);
}
return ret;
}
static int tas25xx_set_t_calib(struct snd_kcontrol *pKcontrol,
struct snd_ctl_elem_value *pUcontrol)
{
int ret = 0;
int calib_temp = pUcontrol->value.integer.value[0];
int param_id = 0;
pr_info("TI-SmartPA: %s: tcalib set %d", __func__, calib_temp);
if (s_tas_smartamp_enable) {
param_id = TAS_CALC_PARAM_IDX(TAS_SA_SET_TCAL, 1, CHANNEL0);
ret = tas25xx_smartamp_algo_ctrl((u8 *)&calib_temp, param_id,
TAS_SET_PARAM, sizeof(uint32_t), AFE_SMARTAMP_MODULE_RX);
if (ret < 0) {
pr_err ("TI-SmartPA: %s: Failed to set spk id", __func__);
}
}
return ret;
}
#ifdef CONFIG_TAS25XX_ALGO_STEREO
static int tas25xx_set_Re_right(struct snd_kcontrol *pKcontrol,
struct snd_ctl_elem_value *pUcontrol)
{
int re_value = pUcontrol->value.integer.value[0];
pr_info("TI-SmartPA: %s: Setting Re %d", __func__, re_value);
return tas25xx_set_Re_common(re_value, CHANNEL1);
}
static int tas25xx_get_re_right(struct snd_kcontrol *pKcontrol,
struct snd_ctl_elem_value *pUcontrol)
{
int ret;
ret = tas25xx_get_re_common (CHANNEL1);
if (ret >= 0) {
pUcontrol->value.integer.value[0] = ret;
ret = 0;
pr_info("TI-SmartPA: %s: Getting Re value=%d", __func__, ret);
}
return ret;
}
static int tas25xx_get_f0_right(struct snd_kcontrol *pKcontrol,
struct snd_ctl_elem_value *pUcontrol)
{
int ret = tas25xx_get_f0_common (CHANNEL1);
if (ret >= 0) {
pUcontrol->value.integer.value[0] = ret;
pr_info("TI-SmartPA: %s: Getting F0 valu=%d", __func__, ret);
ret = 0;
}
return ret;
}
static int tas25xx_get_q_right(struct snd_kcontrol *pKcontrol,
struct snd_ctl_elem_value *pUcontrol)
{
int ret = tas25xx_get_q_common (CHANNEL1);
if (ret >= 0) {
pUcontrol->value.integer.value[0] = ret;
pr_info("TI-SmartPA: %s: Getting Q val=%d", __func__, ret);
ret = 0;
}
return ret;
}
static int tas25xx_get_tv_right(struct snd_kcontrol *pKcontrol,
struct snd_ctl_elem_value *pUcontrol)
{
int ret = tas25xx_get_tv_common (CHANNEL1);
if (ret >= 0) {
pUcontrol->value.integer.value[0] = ret;
pr_info("TI-SmartPA: %s: Getting Tv %d", __func__, ret);
ret = 0;
}
return ret;
}
#endif
static const struct snd_kcontrol_new smartamp_tas25xx_mixer_controls[] = {
SOC_ENUM_EXT("TAS25XX_ALGO_PROFILE", profile_index_enum[0],
tas25xx_get_profile, tas25xx_set_profile),
SOC_ENUM_EXT("TAS25XX_ALGO_CALIB_TEST", tas25xx_calib_test_enum[0],
tas25xx_dummy_get, tas25xx_calib_test_set),
SOC_SINGLE_EXT("TAS25XX_SET_SPK_ID", SND_SOC_NOPM, 0, 0x7fffffff, 0,
tas25xx_dummy_get, tas25xx_set_spk_id),
SOC_SINGLE_EXT("TAS25XX_SET_T_CALIB", SND_SOC_NOPM, 0, 100, 0,
tas25xx_dummy_get, tas25xx_set_t_calib),
//left
SOC_SINGLE_EXT("TAS25XX_SET_RE_LEFT", SND_SOC_NOPM, 0, 0x7fffffff, 0,
tas25xx_dummy_get, tas25xx_set_Re_left),
SOC_SINGLE_EXT("TAS25XX_GET_RE_LEFT", SND_SOC_NOPM, 0, 0x7fffffff, 0,
tas25xx_get_re_left, tas25xx_dummy_set),
SOC_SINGLE_EXT("TAS25XX_GET_F0_LEFT", SND_SOC_NOPM, 0, 0x7fffffff, 0,
tas25xx_get_f0_left, tas25xx_dummy_set),
SOC_SINGLE_EXT("TAS25XX_GET_Q_LEFT", SND_SOC_NOPM, 0, 0x7fffffff, 0,
tas25xx_get_q_left, tas25xx_dummy_set),
SOC_SINGLE_EXT("TAS25XX_GET_TV_LEFT", SND_SOC_NOPM, 0, 0x7fffffff, 0,
tas25xx_get_tv_left, tas25xx_dummy_set),
//Right
#ifdef CONFIG_TAS25XX_ALGO_STEREO
SOC_SINGLE_EXT("TAS25XX_SET_RE_RIGHT", SND_SOC_NOPM, 0, 0x7fffffff, 0,
tas25xx_dummy_get, tas25xx_set_Re_right),
SOC_SINGLE_EXT("TAS25XX_GET_RE_RIGHT", SND_SOC_NOPM, 0, 0x7fffffff, 0,
tas25xx_get_re_right, tas25xx_dummy_set),
SOC_SINGLE_EXT("TAS25XX_GET_F0_RIGHT", SND_SOC_NOPM, 0, 0x7fffffff, 0,
tas25xx_get_f0_right, tas25xx_dummy_set),
SOC_SINGLE_EXT("TAS25XX_GET_Q_RIGHT", SND_SOC_NOPM, 0, 0x7fffffff, 0,
tas25xx_get_q_right, tas25xx_dummy_set),
SOC_SINGLE_EXT("TAS25XX_GET_TV_RIGHT", SND_SOC_NOPM, 0, 0x7fffffff, 0,
tas25xx_get_tv_right, tas25xx_dummy_set),
#endif
SOC_ENUM_EXT("TAS25XX_SMARTPA_ENABLE", tas25xx_smartamp_enable_enum[0],
tas25xx_smartamp_enable_get, tas25xx_smartamp_enable_set),
SOC_ENUM_EXT("TAS25XX_ALGO_BYPASS", tas25xx_smartamp_bypass_enum[0],
tas25xx_smartamp_bypass_get, tas25xx_smartamp_bypass_set),
};
#if CODEC_CONTROL
void tas_smartamp_add_algo_controls(struct snd_soc_codec *codec)
{
pr_err("TI-SmartPA: %s: Adding smartamp controls", __func__);
mutex_init(&routing_lock);
snd_soc_add_codec_controls(codec, smartamp_tas25xx_mixer_controls,
ARRAY_SIZE(smartamp_tas25xx_mixer_controls));
tas_calib_init();
}
EXPORT_SYMBOL(tas_smartamp_add_algo_controls);
#else
void tas_smartamp_add_algo_controls_for_platform (struct snd_soc_platform *platform)
{
pr_err("TI-SmartPA: %s: Adding smartamp controls", __func__);
mutex_init(&routing_lock);
snd_soc_add_platform_controls (platform, smartamp_tas25xx_mixer_controls, ARRAY_SIZE(smartamp_tas25xx_mixer_controls));
tas_calib_init();
}
EXPORT_SYMBOL(tas_smartamp_add_algo_controls_for_platform);
#endif
void tas_smartamp_remove_algo_controls(struct snd_soc_codec *codec)
{
(void)codec;
tas_calib_exit();
}
EXPORT_SYMBOL(tas_smartamp_remove_algo_controls);
MODULE_AUTHOR("Texas Instrumnets Inc.");
MODULE_DESCRIPTION("TAS25xx ALSA SOC Smart Amplifier algo driver");
MODULE_LICENSE("GPL v2");

View file

@ -0,0 +1,191 @@
/*
** =============================================================================
** Copyright (c) 2017 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:
** tas25xx-calib.c
**
** Description:
** misc driver for interfacing for Texas Instruments TAS25xx algorithm
**
** =============================================================================
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/version.h>
#include <linux/device.h>
#include <linux/string.h>
#include <linux/slab.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/semaphore.h>
#include <linux/uaccess.h>
#include <linux/miscdevice.h>
#include <dsp/tas_smart_amp_v2.h>
/* Holds the Packet data required for processing */
struct tas_dsp_pkt {
u8 slave_id;
u8 book;
u8 page;
u8 offset;
u8 data[TAS_PAYLOAD_SIZE * 4];
};
static int smartamp_params_ctrl(uint8_t *input, u8 dir, u8 count)
{
u32 length = count / 4;
u32 paramid = 0;
u32 index;
int ret = 0;
int special_index = 0;
struct tas_dsp_pkt *ppacket;
ppacket = (struct tas_dsp_pkt*)kmalloc (sizeof(struct tas_dsp_pkt), GFP_KERNEL);
if (!ppacket) {
pr_err ("TI-SmartPA: %s: kmalloc failed!", __func__);
return -ENOMEM;
}
memset(ppacket, 0, sizeof(struct tas_dsp_pkt));
ret = copy_from_user (ppacket, input, sizeof(struct tas_dsp_pkt));
if (ret){
pr_err("TI-SmartPA: %s: Error copying from user\n", __func__);
kfree (ppacket);
return -EFAULT;
}
index = (ppacket->page - 1) * 30 + (ppacket->offset - 8) / 4;
special_index = TAS_SA_IS_SPL_IDX(index);
pr_info("TI-SmartPA: %s: index = %d", __func__, index);
if (special_index == 0) {
if ((index < 0 || index > MAX_DSP_PARAM_INDEX)) {
pr_err("TI-SmartPA: %s: invalid index !\n", __func__);
kfree(ppacket);
return -EINVAL;
}
}
pr_info("TI-SmartPA: %s: Valid Index. special = %s\n", __func__, special_index ? "Yes" : "No");
/* speakers are differentiated by slave ids */
if (ppacket->slave_id == SLAVE1 )
{
paramid = (paramid | (index ) | (length << 16) | (1 << 24));
pr_err("TI-SmartPA: %s: Rcvd Slave id for slave 1, %x\n", __func__, ppacket->slave_id);
}else if (ppacket->slave_id == SLAVE2 )
{
paramid = (paramid | (index ) | (length << 16) | (2 << 24));
pr_err("TI-SmartPA: %s: Rcvd Slave id for slave 2, %x\n", __func__, ppacket->slave_id);
}else{
pr_err("TI-SmartPA: %s: Wrong slaveid = %x\n", __func__, ppacket->slave_id);
}
/*
* Note: In any case calculated paramid should not match with
*/
if ((paramid == CAPI_V2_TAS_RX_ENABLE) ||
(paramid == CAPI_V2_TAS_TX_ENABLE) ||
(paramid == CAPI_V2_TAS_RX_CFG) ||
(paramid == CAPI_V2_TAS_TX_CFG))
{
pr_err("TI-SmartPA: %s: %s Slave 0x%x params failed, paramid mismatch\n", __func__,
dir == TAS_GET_PARAM ? "get" : "set", ppacket->slave_id);
kfree(ppacket);
return -EINVAL;
}
ret = tas25xx_smartamp_algo_ctrl(ppacket->data, paramid,
dir, length * 4, AFE_SMARTAMP_MODULE_RX);
if (ret)
pr_err("TI-SmartPA: %s: %s Slave 0x%x params failed from afe, ret=%x\n", __func__,
dir == TAS_GET_PARAM ? "get" : "set", ppacket->slave_id, ret);
else
pr_info("TI-SmartPA: %s: Algo control returned %d\n", __func__, ret);
if (dir == TAS_GET_PARAM) {
ret = copy_to_user(input, ppacket, sizeof(struct tas_dsp_pkt));
if (ret) {
pr_err("TI-SmartPA: %s: Error copying to user after DSP", __func__);
ret = -EFAULT;
}
}
kfree(ppacket);
return ret;
}
static int tas_calib_open(struct inode *inode, struct file *fd)
{
return 0;
}
static ssize_t tas_calib_write(struct file *file,
const char __user *buffer, size_t count, loff_t *offp)
{
int rc = 0;
rc = smartamp_params_ctrl((uint8_t *)buffer, TAS_SET_PARAM, count);
return rc;
}
static ssize_t tas_calib_read(struct file *file, char __user *buffer,
size_t count, loff_t *ptr)
{
int rc;
rc = smartamp_params_ctrl((uint8_t *)buffer, TAS_GET_PARAM, count);
if (rc < 0)
count = rc;
return count;
}
static long tas_calib_ioctl(struct file *filp, uint cmd, ulong arg)
{
return 0;
}
static int tas_calib_release(struct inode *inode, struct file *fd)
{
return 0;
}
const struct file_operations tas_calib_fops = {
.owner = THIS_MODULE,
.open = tas_calib_open,
.write = tas_calib_write,
.read = tas_calib_read,
.release = tas_calib_release,
.unlocked_ioctl = tas_calib_ioctl,
};
static struct miscdevice tas_calib_misc = {
.minor = MISC_DYNAMIC_MINOR,
.name = "tas_calib",
.fops = &tas_calib_fops,
};
int tas_calib_init(void)
{
int rc;
pr_err("TI-SmartPA: %s",__func__);
rc = misc_register(&tas_calib_misc);
if (rc)
pr_err("TI-SmartPA: %s: register calib misc failed\n", __func__);
return rc;
}
void tas_calib_exit(void)
{
misc_deregister(&tas_calib_misc);
}
MODULE_AUTHOR("Texas Instruments Inc.");
MODULE_DESCRIPTION("tas2560 Misc driver");
MODULE_LICENSE("GPL v2");

View file

@ -0,0 +1,28 @@
/*
** =============================================================================
** 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:
** tas25xx-calib.h
**
** Description:
** header file for tas25xx-calib.c
**
** =============================================================================
*/
#ifndef _TAS25XX_CALIB_H_
#define _TAS25XX_CALIB_H_
int tas_calib_init(void);
void tas_calib_exit(void);
#endif /* _TAS25XX_CALIB_H */