diff --git a/sound/soc/codecs/Kbuild b/sound/soc/codecs/Kbuild index 25ac220ebf57..d27a5ecfaa9c 100644 --- a/sound/soc/codecs/Kbuild +++ b/sound/soc/codecs/Kbuild @@ -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 diff --git a/sound/soc/codecs/tas2562-codec.c b/sound/soc/codecs/tas2562-codec.c index 9e42a1593bce..bdf1bf4c5b06 100644 --- a/sound/soc/codecs/tas2562-codec.c +++ b/sound/soc/codecs/tas2562-codec.c @@ -44,6 +44,11 @@ #include "tas2562.h" +#ifdef CONFIG_TAS25XX_ALGO +#include +#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), diff --git a/sound/soc/codecs/tas2562-regmap.c b/sound/soc/codecs/tas2562-regmap.c index 44addbedfc0b..286fa7874026 100644 --- a/sound/soc/codecs/tas2562-regmap.c +++ b/sound/soc/codecs/tas2562-regmap.c @@ -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, diff --git a/sound/soc/codecs/tas25xx-algo.c b/sound/soc/codecs/tas25xx-algo.c new file mode 100644 index 000000000000..9f368425e75f --- /dev/null +++ b/sound/soc/codecs/tas25xx-algo.c @@ -0,0 +1,822 @@ +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#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"); diff --git a/sound/soc/codecs/tas25xx-calib.c b/sound/soc/codecs/tas25xx-calib.c new file mode 100644 index 000000000000..1b50494d6bf1 --- /dev/null +++ b/sound/soc/codecs/tas25xx-calib.c @@ -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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* 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"); diff --git a/sound/soc/codecs/tas25xx-calib.h b/sound/soc/codecs/tas25xx-calib.h new file mode 100644 index 000000000000..ad6484d6c973 --- /dev/null +++ b/sound/soc/codecs/tas25xx-calib.h @@ -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 */