/* * ============================================================================= * 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: * tas2562-codec.c * * Description: * ALSA SoC driver for Texas Instruments TAS2562 High Performance 4W Smart * Amplifier * * ============================================================================= */ #ifdef CONFIG_TAS2562_CODEC #define DEBUG 5 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #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 #define TAS2562_IVSENSER_DISABLE 0 /* #define TAS2558_CODEC */ static char const *iv_enable_text[] = {"Off", "On"}; static int tas2562iv_enable; static int mb_mute; /* Register Table to cache and reload after reset */ /* ?? Can use [ 0 ... MAX_REGISTERS-1 ] = -1 instead */ static int tas2562_reg_cache[MAX_REGISTERS][2] = {{0,0}}; static int tas2562_reg_count[MAX_REGISTERS] = {0}; static int reg_count = 0; static const struct soc_enum tas2562_enum[] = { SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(iv_enable_text), iv_enable_text), }; static int tas2562_set_fmt(struct tas2562_priv *p_tas2562, unsigned int fmt); static int tas2562_i2c_load_data(struct tas2562_priv *p_tas2562, enum channel chn, unsigned int *p_data); static int tas2562_system_mute_ctrl_get(struct snd_kcontrol *pKcontrol, struct snd_ctl_elem_value *pValue); static int tas2562_system_mute_ctrl_put(struct snd_kcontrol *pKcontrol, struct snd_ctl_elem_value *pValue); static int tas2562_mute_ctrl_get(struct snd_kcontrol *pKcontrol, struct snd_ctl_elem_value *pValue); static int tas2562_mute_ctrl_put(struct snd_kcontrol *pKcontrol, struct snd_ctl_elem_value *pValue); static unsigned int p_tas2562_classh_d_data[] = { /* reg address size values */ TAS2562_CLASSHHEADROOM, 0x4, 0x09, 0x99, 0x99, 0x9a, TAS2562_CLASSHHYSTERESIS, 0x4, 0x0, 0x0, 0x0, 0x0, TAS2562_CLASSHMTCT, 0x4, 0xb, 0x0, 0x0, 0x0, TAS2562_VBATFILTER, 0x1, 0x38, TAS2562_CLASSHRELEASETIMER, 0x1, 0x3c, TAS2562_BOOSTSLOPE, 0x1, 0x78, TAS2562_TESTPAGECONFIGURATION, 0x1, 0xd, TAS2562_CLASSDCONFIGURATION3, 0x1, 0x8e, TAS2562_CLASSDCONFIGURATION2, 0x1, 0x49, TAS2562_CLASSDCONFIGURATION4, 0x1, 0x21, TAS2562_CLASSDCONFIGURATION1, 0x1, 0x80, TAS2562_EFFICIENCYCONFIGURATION, 0x1, 0xc1, 0xFFFFFFFF, 0xFFFFFFFF }; static unsigned int tas2562_codec_read(struct snd_soc_codec *codec, unsigned int reg) { unsigned int value = 0; struct tas2562_priv *p_tas2562 = snd_soc_codec_get_drvdata(codec); p_tas2562->read (p_tas2562, channel_left, reg, &value); dev_dbg(p_tas2562->dev, "%s, reg=%d, value=%d", __func__, reg, value); return value; } static int tas2562_iv_enable(struct tas2562_priv *p_tas2562, int enable) { int n_result; if (enable) { pr_debug("%s:tas2562iv_enable\n", __func__); n_result = p_tas2562->update_bits(p_tas2562, channel_both, TAS2562_POWERCONTROL, TAS2562_POWERCONTROL_ISNSPOWER_MASK | TAS2562_POWERCONTROL_VSNSPOWER_MASK, TAS2562_POWERCONTROL_VSNSPOWER_ACTIVE | TAS2562_POWERCONTROL_ISNSPOWER_ACTIVE); } else { pr_debug("%s:tas2562iv_disable\n", __func__); n_result = p_tas2562->update_bits(p_tas2562, channel_both, TAS2562_POWERCONTROL, TAS2562_POWERCONTROL_ISNSPOWER_MASK | TAS2562_POWERCONTROL_VSNSPOWER_MASK, TAS2562_POWERCONTROL_VSNSPOWER_POWEREDDOWN | TAS2562_POWERCONTROL_ISNSPOWER_POWEREDDOWN); } tas2562iv_enable = enable; return n_result; } 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 = NULL; int iv_enable = 0, n_result = 0; 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; } iv_enable = ucontrol->value.integer.value[0]; n_result = tas2562_iv_enable(p_tas2562, iv_enable); pr_debug("%s: tas2562iv_enable = %d\n", __func__, tas2562iv_enable); return n_result; } 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 = 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) dev_err(p_tas2562->dev, "can't get ivsensor state %s, L=%d\n", __func__, __LINE__); else if (((value & TAS2562_POWERCONTROL_ISNSPOWER_MASK) == TAS2562_POWERCONTROL_ISNSPOWER_ACTIVE) && ((value & TAS2562_POWERCONTROL_VSNSPOWER_MASK) == TAS2562_POWERCONTROL_VSNSPOWER_ACTIVE)) { ucontrol->value.integer.value[0] = TAS2562_IVSENSER_ENABLE; } else { ucontrol->value.integer.value[0] = TAS2562_IVSENSER_DISABLE; } tas2562iv_enable = ucontrol->value.integer.value[0]; dev_info(p_tas2562->dev, "value: 0x%x, tas2562iv_enable %d\n", value, tas2562iv_enable); return 0; } static const struct snd_kcontrol_new tas2562_controls[] = { SOC_ENUM_EXT("TAS2562 IVSENSE ENABLE", tas2562_enum[0], tas2562iv_get, tas2562iv_put), }; static int tas2562_codec_write(struct snd_soc_codec *codec, unsigned int reg, unsigned int value) { struct tas2562_priv *p_tas2562 = snd_soc_codec_get_drvdata(codec); dev_dbg(p_tas2562->dev, "%s: %d, %d", __func__, reg, value); /* This Reg Cache Table only support Book-0, Page-0 * So range is 0-0x7f */ if (reg <= 0x7f) { if (tas2562_reg_cache[reg][0] == 0) { tas2562_reg_count[reg_count] = reg; tas2562_reg_cache[reg][0] = 1; reg_count++; } tas2562_reg_cache[reg][1] = value; } p_tas2562->write (p_tas2562, channel_both, reg, value); return 0; } static int tas2562_i2c_load_data(struct tas2562_priv *p_tas2562, enum channel chn, unsigned int *p_data) { unsigned int n_register; unsigned int *n_data; unsigned char buf[128]; unsigned int n_length = 0; unsigned int i = 0; unsigned int n_size = 0; int n_result = 0; do { n_register = p_data[n_length]; n_size = p_data[n_length + 1]; n_data = &p_data[n_length + 2]; if (n_register == TAS2562_MSLEEP) { msleep(n_data[0]); dev_dbg(p_tas2562->dev, "%s, msleep = %d\n", __func__, n_data[0]); } else if (n_register == TAS2562_MDELAY) { msleep(n_data[0]); dev_dbg(p_tas2562->dev, "%s, mdelay = %d\n", __func__, n_data[0]); } else { if (n_register != 0xFFFFFFFF) { if (n_size > 128) { dev_err(p_tas2562->dev, "%s, Line=%d, invalid size, maximum is 128 bytes!\n", __func__, __LINE__); break; } if (n_size > 1) { for (i = 0; i < n_size; i++) buf[i] = (unsigned char)n_data[i]; n_result = p_tas2562->bulk_write(p_tas2562, chn, n_register, buf, n_size); if (n_result < 0) break; } else if (n_size == 1) { n_result = p_tas2562->write(p_tas2562, chn, n_register, n_data[0]); if (n_result < 0) break; } else { dev_err(p_tas2562->dev, "%s, Line=%d,invalid size, minimum is 1 bytes!\n", __func__, __LINE__); } } } n_length = n_length + 2 + p_data[n_length + 1]; } while (n_register != 0xFFFFFFFF); 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); int ret = 0; mutex_lock(&p_tas2562->codec_lock); dev_dbg(p_tas2562->dev, "%s\n", __func__); p_tas2562->runtime_suspend(p_tas2562); mutex_unlock(&p_tas2562->codec_lock); return ret; } static int tas2562_codec_resume(struct snd_soc_codec *codec) { struct tas2562_priv *p_tas2562 = snd_soc_codec_get_drvdata(codec); int ret = 0; mutex_lock(&p_tas2562->codec_lock); dev_dbg(p_tas2562->dev, "%s\n", __func__); p_tas2562->runtime_resume(p_tas2562); 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) { int n_result = 0; int irqreg; /*unsigned int n_value;*/ if ((p_tas2562->mb_mute) && (state == TAS2562_POWER_ACTIVE)) state = TAS2562_POWER_MUTE; dev_info(p_tas2562->dev, "set power state: %d\n", state); switch (state) { case TAS2562_POWER_ACTIVE: /* if set format was not called by asoc, then set it default */ if (p_tas2562->mn_asi_format == 0) p_tas2562->mn_asi_format = SND_SOC_DAIFMT_CBS_CFS | SND_SOC_DAIFMT_IB_NF | SND_SOC_DAIFMT_I2S; n_result = tas2562_set_fmt(p_tas2562, p_tas2562->mn_asi_format); if (n_result < 0) return n_result; #ifdef CONFIG_TAS25XX_ALGO tas25xx_send_algo_calibration(); #endif /* Clear latched IRQ before power on */ p_tas2562->update_bits(p_tas2562, chn, TAS2562_INTERRUPTCONFIGURATION, TAS2562_INTERRUPTCONFIGURATION_LTCHINTCLEAR_MASK, TAS2562_INTERRUPTCONFIGURATION_LTCHINTCLEAR); p_tas2562->read(p_tas2562, channel_left, TAS2562_LATCHEDINTERRUPTREG0, &irqreg); dev_info(p_tas2562->dev, "IRQ reg is: %s %d, %d\n", __func__, irqreg, __LINE__); p_tas2562->read(p_tas2562, channel_right, TAS2562_LATCHEDINTERRUPTREG0, &irqreg); dev_info(p_tas2562->dev, "IRQ reg is: %s %d, %d\n", __func__, irqreg, __LINE__); p_tas2562->mb_power_up = true; p_tas2562->mn_power_state = TAS2562_POWER_ACTIVE; schedule_delayed_work(&p_tas2562->irq_work, msecs_to_jiffies(40)); break; case TAS2562_POWER_MUTE: n_result = p_tas2562->update_bits(p_tas2562, chn, TAS2562_POWERCONTROL, TAS2562_POWERCONTROL_OPERATIONALMODE10_MASK | TAS2562_POWERCONTROL_ISNSPOWER_MASK | TAS2562_POWERCONTROL_VSNSPOWER_MASK, TAS2562_POWERCONTROL_OPERATIONALMODE10_MUTE | TAS2562_POWERCONTROL_VSNSPOWER_ACTIVE | TAS2562_POWERCONTROL_ISNSPOWER_ACTIVE); p_tas2562->mb_power_up = true; p_tas2562->mn_power_state = TAS2562_POWER_MUTE; break; case TAS2562_POWER_SHUTDOWN: if (p_tas2562->mn_status_check) { if (hrtimer_active(&p_tas2562->mtimer)) { dev_info(p_tas2562->dev, "cancel timer\n"); hrtimer_cancel(&p_tas2562->mtimer); } } n_result = p_tas2562->update_bits(p_tas2562, chn, TAS2562_POWERCONTROL, TAS2562_POWERCONTROL_OPERATIONALMODE10_MASK, TAS2562_POWERCONTROL_OPERATIONALMODE10_SHUTDOWN); p_tas2562->mb_power_up = false; p_tas2562->mn_power_state = TAS2562_POWER_SHUTDOWN; msleep(20); p_tas2562->enable_irq(p_tas2562, false); #ifdef CONFIG_TAS25XX_ALGO tas25xx_update_big_data(); #endif break; default: dev_err(p_tas2562->dev, "wrong power state setting %d\n", state); } return n_result; } static int tas2562_dac_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); struct tas2562_priv *p_tas2562 = snd_soc_codec_get_drvdata(codec); switch (event) { case SND_SOC_DAPM_POST_PMU: dev_info(p_tas2562->dev, "SND_SOC_DAPM_POST_PMU\n"); break; case SND_SOC_DAPM_PRE_PMD: dev_info(p_tas2562->dev, "SND_SOC_DAPM_PRE_PMD\n"); break; } return 0; } 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") }; static const struct snd_soc_dapm_route tas2562_audio_map[] = { {"DAC", NULL, "ASI1"}, {"OUT", NULL, "DAC"} }; static int tas2562_get_left_speaker_switch(struct snd_kcontrol *pKcontrol, struct snd_ctl_elem_value *p_u_control) { struct snd_soc_codec *codec = snd_soc_kcontrol_codec(pKcontrol); struct tas2562_priv *p_tas2562 = snd_soc_codec_get_drvdata(codec); dev_info(p_tas2562->dev, "%s, p_u_control = %ld\n", __func__, p_u_control->value.integer.value[0]); p_u_control->value.integer.value[0] = p_tas2562->spk_l_control; return 0; } static int tas2562_set_left_speaker_switch(struct snd_kcontrol *pKcontrol, struct snd_ctl_elem_value *p_u_control) { struct snd_soc_codec *codec = snd_soc_kcontrol_codec(pKcontrol); struct tas2562_priv *p_tas2562 = snd_soc_codec_get_drvdata(codec); dev_info(p_tas2562->dev, "%s, spk_l_control = %d\n", __func__, p_tas2562->spk_l_control); p_tas2562->spk_l_control = p_u_control->value.integer.value[0]; return 0; } static int tas2562_get_right_speaker_switch(struct snd_kcontrol *pKcontrol, struct snd_ctl_elem_value *p_u_control) { struct snd_soc_codec *codec = snd_soc_kcontrol_codec(pKcontrol); struct tas2562_priv *p_tas2562 = snd_soc_codec_get_drvdata(codec); dev_info(p_tas2562->dev, "%s, p_u_control = %ld\n", __func__, p_u_control->value.integer.value[0]); p_u_control->value.integer.value[0] = p_tas2562->spk_r_control; return 0; } static int tas2562_set_right_speaker_switch(struct snd_kcontrol *pKcontrol, struct snd_ctl_elem_value *p_u_control) { struct snd_soc_codec *codec = snd_soc_kcontrol_codec(pKcontrol); struct tas2562_priv *p_tas2562 = snd_soc_codec_get_drvdata(codec); dev_info(p_tas2562->dev, "%s, spk_r_control = %d\n", __func__, p_tas2562->spk_r_control); p_tas2562->spk_r_control = p_u_control->value.integer.value[0]; return 0; } static int tas2562_mute(struct snd_soc_dai *dai, int mute) { struct snd_soc_codec *codec = dai->codec; struct tas2562_priv *p_tas2562 = snd_soc_codec_get_drvdata(codec); enum channel chn; dev_dbg(p_tas2562->dev, "%s,%d\n", __func__, mute); mutex_lock(&p_tas2562->codec_lock); if ((p_tas2562->spk_l_control == 1) && (p_tas2562->spk_r_control == 1) && (p_tas2562->mn_channels == 2)) chn = channel_both; else if (p_tas2562->spk_l_control == 1) chn = channel_left; else if ((p_tas2562->spk_r_control == 1) && (p_tas2562->mn_channels == 2)) chn = channel_right; else chn = channel_left; if (mute) { tas2562_set_power_state(p_tas2562, channel_both, TAS2562_POWER_SHUTDOWN); } else { tas2562_set_power_state(p_tas2562, chn, TAS2562_POWER_ACTIVE); } mutex_unlock(&p_tas2562->codec_lock); return 0; } static int tas2562_iv_slot_config(struct tas2562_priv *p_tas2562) { int ret = 0; dev_info(p_tas2562->dev, "%s, %d\n", __func__, p_tas2562->mn_slot_width); if (p_tas2562->mn_channels == 2) { if (p_tas2562->mn_slot_width == 16) { p_tas2562->update_bits(p_tas2562, channel_left, TAS2562_TDMCONFIGURATIONREG5, 0xff, 0x41); p_tas2562->update_bits(p_tas2562, channel_left, TAS2562_TDMCONFIGURATIONREG6, 0xff, 0x40); p_tas2562->update_bits(p_tas2562, channel_right, TAS2562_TDMCONFIGURATIONREG5, 0xff, 0x43); p_tas2562->update_bits(p_tas2562, channel_right, TAS2562_TDMCONFIGURATIONREG6, 0xff, 0x42); } else { p_tas2562->update_bits(p_tas2562, channel_left, TAS2562_TDMCONFIGURATIONREG5, 0xff, 0x42); p_tas2562->update_bits(p_tas2562, channel_left, TAS2562_TDMCONFIGURATIONREG6, 0xff, 0x40); p_tas2562->update_bits(p_tas2562, channel_right, TAS2562_TDMCONFIGURATIONREG5, 0xff, 0x46); p_tas2562->update_bits(p_tas2562, channel_right, TAS2562_TDMCONFIGURATIONREG6, 0xff, 0x44); } } else if ((p_tas2562->mn_channels == 1) && (p_tas2562->mn_slot_width == 32)) { p_tas2562->update_bits(p_tas2562, channel_left, TAS2562_TDMCONFIGURATIONREG5, 0xff, 0x44); p_tas2562->update_bits(p_tas2562, channel_left, TAS2562_TDMCONFIGURATIONREG6, 0xff, 0x40); } else if ((p_tas2562->mn_channels == 1) && (p_tas2562->mn_slot_width == 16)) { p_tas2562->update_bits(p_tas2562, channel_left, TAS2562_TDMCONFIGURATIONREG5, 0xff, 0x42); p_tas2562->update_bits(p_tas2562, channel_left, TAS2562_TDMCONFIGURATIONREG6, 0xff, 0x40); } else { dev_err(p_tas2562->dev, "%s, wrong params, %d\n", __func__, p_tas2562->mn_slot_width); } return ret; } static int tas2562_iv_bitwidth_config(struct tas2562_priv *p_tas2562) { int ret = 0; if ((p_tas2562->mn_channels == 2) && (p_tas2562->mn_slot_width == 16)){ ret = p_tas2562->update_bits(p_tas2562, channel_both, TAS2562_TDMCONFIGURATIONREG2, TAS2562_TDMCONFIGURATIONREG2_IVMONLEN76_MASK, TAS2562_TDMCONFIGURATIONREG2_IVMONLEN76_8BITS); } else { ret = p_tas2562->update_bits(p_tas2562, channel_both, TAS2562_TDMCONFIGURATIONREG2, TAS2562_TDMCONFIGURATIONREG2_IVMONLEN76_MASK, TAS2562_TDMCONFIGURATIONREG2_IVMONLEN76_16BITS); } return ret; } static int tas2562_set_slot(struct tas2562_priv *p_tas2562, int slot_width) { int ret = 0; switch (slot_width) { case 16: ret = p_tas2562->update_bits(p_tas2562, channel_both, TAS2562_TDMCONFIGURATIONREG2, TAS2562_TDMCONFIGURATIONREG2_RXSLEN10_MASK, TAS2562_TDMCONFIGURATIONREG2_RXSLEN10_16BITS); break; case 24: ret = p_tas2562->update_bits(p_tas2562, channel_both, TAS2562_TDMCONFIGURATIONREG2, TAS2562_TDMCONFIGURATIONREG2_RXSLEN10_MASK, TAS2562_TDMCONFIGURATIONREG2_RXSLEN10_24BITS); break; case 32: ret = p_tas2562->update_bits(p_tas2562, channel_both, TAS2562_TDMCONFIGURATIONREG2, TAS2562_TDMCONFIGURATIONREG2_RXSLEN10_MASK, TAS2562_TDMCONFIGURATIONREG2_RXSLEN10_32BITS); break; case 0: /* Do not change slot width */ break; default: dev_err(p_tas2562->dev, "slot width not supported"); ret = -EINVAL; } if (ret >= 0) p_tas2562->mn_slot_width = slot_width; return ret; } static int tas2562_set_bitwidth(struct tas2562_priv *p_tas2562, int bitwidth) { int slot_width_tmp = 16; dev_info(p_tas2562->dev, "%s %d\n", __func__, bitwidth); switch (bitwidth) { case SNDRV_PCM_FORMAT_S16_LE: p_tas2562->update_bits(p_tas2562, channel_both, TAS2562_TDMCONFIGURATIONREG2, TAS2562_TDMCONFIGURATIONREG2_RXWLEN32_MASK, TAS2562_TDMCONFIGURATIONREG2_RXWLEN32_16BITS); p_tas2562->mn_ch_size = 16; slot_width_tmp = 16; break; case SNDRV_PCM_FORMAT_S24_LE: p_tas2562->update_bits(p_tas2562, channel_both, TAS2562_TDMCONFIGURATIONREG2, TAS2562_TDMCONFIGURATIONREG2_RXWLEN32_MASK, TAS2562_TDMCONFIGURATIONREG2_RXWLEN32_24BITS); p_tas2562->mn_ch_size = 24; slot_width_tmp = 24; break; case SNDRV_PCM_FORMAT_S32_LE: p_tas2562->update_bits(p_tas2562, channel_both, TAS2562_TDMCONFIGURATIONREG2, TAS2562_TDMCONFIGURATIONREG2_RXWLEN32_MASK, TAS2562_TDMCONFIGURATIONREG2_RXWLEN32_32BITS); p_tas2562->mn_ch_size = 32; slot_width_tmp = 32; break; default: dev_info(p_tas2562->dev, "Not supported params format\n"); } tas2562_set_slot(p_tas2562, slot_width_tmp); p_tas2562->update_bits(p_tas2562, channel_left, TAS2562_TDMCONFIGURATIONREG2, TAS2562_TDMCONFIGURATIONREG2_RXSCFG54_MASK, TAS2562_TDMCONFIGURATIONREG2_RXSCFG54_MONO_LEFT); p_tas2562->update_bits(p_tas2562, channel_right, TAS2562_TDMCONFIGURATIONREG2, TAS2562_TDMCONFIGURATIONREG2_RXSCFG54_MASK, TAS2562_TDMCONFIGURATIONREG2_RXSCFG54_MONO_RIGHT); tas2562_iv_slot_config(p_tas2562); tas2562_iv_bitwidth_config(p_tas2562); dev_info(p_tas2562->dev, "mn_ch_size: %d\n", p_tas2562->mn_ch_size); p_tas2562->mn_pcm_format = bitwidth; return 0; } static int tas2562_set_samplerate(struct tas2562_priv *p_tas2562, int samplerate) { switch (samplerate) { case 48000: p_tas2562->update_bits(p_tas2562, channel_both, TAS2562_TDMCONFIGURATIONREG0, TAS2562_TDMCONFIGURATIONREG0_SAMPRATERAMP_MASK, TAS2562_TDMCONFIGURATIONREG0_SAMPRATERAMP_48KHZ); p_tas2562->update_bits(p_tas2562, channel_both, TAS2562_TDMCONFIGURATIONREG0, TAS2562_TDMCONFIGURATIONREG0_SAMPRATE31_MASK, TAS2562_TDMCONFIGURATIONREG0_SAMPRATE31_44_1_48KHZ); break; case 44100: p_tas2562->update_bits(p_tas2562, channel_both, TAS2562_TDMCONFIGURATIONREG0, TAS2562_TDMCONFIGURATIONREG0_SAMPRATERAMP_MASK, TAS2562_TDMCONFIGURATIONREG0_SAMPRATERAMP_44_1KHZ); p_tas2562->update_bits(p_tas2562, channel_both, TAS2562_TDMCONFIGURATIONREG0, TAS2562_TDMCONFIGURATIONREG0_SAMPRATE31_MASK, TAS2562_TDMCONFIGURATIONREG0_SAMPRATE31_44_1_48KHZ); break; case 96000: p_tas2562->update_bits(p_tas2562, channel_both, TAS2562_TDMCONFIGURATIONREG0, TAS2562_TDMCONFIGURATIONREG0_SAMPRATERAMP_MASK, TAS2562_TDMCONFIGURATIONREG0_SAMPRATERAMP_48KHZ); p_tas2562->update_bits(p_tas2562, channel_both, TAS2562_TDMCONFIGURATIONREG0, TAS2562_TDMCONFIGURATIONREG0_SAMPRATE31_MASK, TAS2562_TDMCONFIGURATIONREG0_SAMPRATE31_88_2_96KHZ); break; case 88200: p_tas2562->update_bits(p_tas2562, channel_both, TAS2562_TDMCONFIGURATIONREG0, TAS2562_TDMCONFIGURATIONREG0_SAMPRATERAMP_MASK, TAS2562_TDMCONFIGURATIONREG0_SAMPRATERAMP_44_1KHZ); p_tas2562->update_bits(p_tas2562, channel_both, TAS2562_TDMCONFIGURATIONREG0, TAS2562_TDMCONFIGURATIONREG0_SAMPRATE31_MASK, TAS2562_TDMCONFIGURATIONREG0_SAMPRATE31_88_2_96KHZ); break; case 19200: p_tas2562->update_bits(p_tas2562, channel_both, TAS2562_TDMCONFIGURATIONREG0, TAS2562_TDMCONFIGURATIONREG0_SAMPRATERAMP_MASK, TAS2562_TDMCONFIGURATIONREG0_SAMPRATERAMP_48KHZ); p_tas2562->update_bits(p_tas2562, channel_both, TAS2562_TDMCONFIGURATIONREG0, TAS2562_TDMCONFIGURATIONREG0_SAMPRATE31_MASK, TAS2562_TDMCONFIGURATIONREG0_SAMPRATE31_176_4_192KHZ); break; case 17640: p_tas2562->update_bits(p_tas2562, channel_both, TAS2562_TDMCONFIGURATIONREG0, TAS2562_TDMCONFIGURATIONREG0_SAMPRATERAMP_MASK, TAS2562_TDMCONFIGURATIONREG0_SAMPRATERAMP_44_1KHZ); p_tas2562->update_bits(p_tas2562, channel_both, TAS2562_TDMCONFIGURATIONREG0, TAS2562_TDMCONFIGURATIONREG0_SAMPRATE31_MASK, TAS2562_TDMCONFIGURATIONREG0_SAMPRATE31_176_4_192KHZ); break; default: dev_info(p_tas2562->dev, "%s, unsupported sample rate, %d\n", __func__, samplerate); } p_tas2562->mn_sampling_rate = samplerate; return 0; } static int tas2562_system_mute_ctrl_get(struct snd_kcontrol *pKcontrol, struct snd_ctl_elem_value *pValue) { struct snd_soc_codec *codec = snd_soc_kcontrol_codec(pKcontrol); struct tas2562_priv *p_tas2562 = snd_soc_codec_get_drvdata(codec); pValue->value.integer.value[0] = p_tas2562->mb_mute; dev_dbg(p_tas2562->dev, "%s = %d\n", __func__, p_tas2562->mb_mute); return 0; } static int tas2562_system_mute_ctrl_put(struct snd_kcontrol *pKcontrol, struct snd_ctl_elem_value *pValue) { struct snd_soc_codec *codec = snd_soc_kcontrol_codec(pKcontrol); struct tas2562_priv *p_tas2562 = snd_soc_codec_get_drvdata(codec); mb_mute = pValue->value.integer.value[0]; dev_dbg(p_tas2562->dev, "%s = %d\n", __func__, mb_mute); p_tas2562->mb_mute = !!mb_mute; return 0; } static int tas2562_mute_ctrl_get(struct snd_kcontrol *pKcontrol, struct snd_ctl_elem_value *pValue) { struct snd_soc_codec *codec = snd_soc_kcontrol_codec(pKcontrol); struct tas2562_priv *p_tas2562 = snd_soc_codec_get_drvdata(codec); pValue->value.integer.value[0] = p_tas2562->mb_mute; if((p_tas2562->mb_power_up == true)&& (p_tas2562->mn_power_state == TAS2562_POWER_ACTIVE)) pValue->value.integer.value[0] = 0; else pValue->value.integer.value[0] = 1; dev_dbg(p_tas2562->dev, "%s = %ld\n", __func__, pValue->value.integer.value[0]); return 0; } static int tas2562_mute_ctrl_put(struct snd_kcontrol *pKcontrol, struct snd_ctl_elem_value *pValue) { struct snd_soc_codec *codec = snd_soc_kcontrol_codec(pKcontrol); struct tas2562_priv *p_tas2562 = snd_soc_codec_get_drvdata(codec); enum channel chn; int mute = pValue->value.integer.value[0]; dev_dbg(p_tas2562->dev, "%s, %d\n", __func__, mute); mutex_lock(&p_tas2562->codec_lock); if ((p_tas2562->spk_l_control == 1) && (p_tas2562->spk_r_control == 1) && (p_tas2562->mn_channels == 2)) chn = channel_both; else if (p_tas2562->spk_l_control == 1) chn = channel_left; else if ((p_tas2562->spk_r_control == 1) && (p_tas2562->mn_channels == 2)) chn = channel_right; else chn = channel_left; if (mute) { tas2562_set_power_state(p_tas2562, chn, TAS2562_POWER_MUTE); } else { tas2562_set_power_state(p_tas2562, chn, TAS2562_POWER_ACTIVE); } mutex_unlock(&p_tas2562->codec_lock); return 0; } static int tas2562_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 tas2562_priv *p_tas2562 = snd_soc_codec_get_drvdata(codec); /* int blr_clk_ratio; */ int n_result = 0; dev_dbg(p_tas2562->dev, "%s, format: %d\n", __func__, params_format(params)); mutex_lock(&p_tas2562->codec_lock); n_result = tas2562_set_bitwidth(p_tas2562, params_format(params)); if (n_result < 0) { dev_info(p_tas2562->dev, "set bitwidth failed, %d\n", n_result); goto ret; } dev_info(p_tas2562->dev, "%s, sample rate: %d\n", __func__, params_rate(params)); n_result = tas2562_set_samplerate(p_tas2562, params_rate(params)); ret: mutex_unlock(&p_tas2562->codec_lock); return n_result; } static int tas2562_set_fmt(struct tas2562_priv *p_tas2562, unsigned int fmt) { u8 tdm_rx_start_slot = 0, asi_cfg_1 = 0; int ret = 0; switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { case SND_SOC_DAIFMT_CBS_CFS: asi_cfg_1 = 0x00; break; default: dev_err(p_tas2562->dev, "ASI format master is not found\n"); ret = -EINVAL; } switch (fmt & SND_SOC_DAIFMT_INV_MASK) { case SND_SOC_DAIFMT_NB_NF: dev_info(p_tas2562->dev, "INV format: NBNF\n"); asi_cfg_1 |= TAS2562_TDMCONFIGURATIONREG1_RXEDGE_RISING; break; case SND_SOC_DAIFMT_IB_NF: dev_info(p_tas2562->dev, "INV format: IBNF\n"); asi_cfg_1 |= TAS2562_TDMCONFIGURATIONREG1_RXEDGE_FALLING; break; default: dev_err(p_tas2562->dev, "ASI format Inverse is not found\n"); ret = -EINVAL; } p_tas2562->update_bits(p_tas2562, channel_both, TAS2562_TDMCONFIGURATIONREG1, TAS2562_TDMCONFIGURATIONREG1_RXEDGE_MASK, asi_cfg_1); switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { case (SND_SOC_DAIFMT_I2S): tdm_rx_start_slot = 1; break; case (SND_SOC_DAIFMT_DSP_A): case (SND_SOC_DAIFMT_DSP_B): tdm_rx_start_slot = 1; break; case (SND_SOC_DAIFMT_LEFT_J): tdm_rx_start_slot = 0; break; default: dev_err(p_tas2562->dev, "DAI Format is not found, fmt=0x%x\n", fmt); ret = -EINVAL; break; } p_tas2562->update_bits(p_tas2562, channel_left, TAS2562_TDMCONFIGURATIONREG1, TAS2562_TDMCONFIGURATIONREG1_RXOFFSET51_MASK, (tdm_rx_start_slot << TAS2562_TDMCONFIGURATIONREG1_RXOFFSET51_SHIFT)); if (p_tas2562->mn_channels == 2) { p_tas2562->update_bits(p_tas2562, channel_right, TAS2562_TDMCONFIGURATIONREG1, TAS2562_TDMCONFIGURATIONREG1_RXOFFSET51_MASK, (tdm_rx_start_slot << TAS2562_TDMCONFIGURATIONREG1_RXOFFSET51_SHIFT)); } p_tas2562->mn_asi_format = fmt; return 0; } static int tas2562_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) { struct snd_soc_codec *codec = dai->codec; struct tas2562_priv *p_tas2562 = snd_soc_codec_get_drvdata(codec); int ret = 0; dev_dbg(p_tas2562->dev, "%s, format=0x%x\n", __func__, fmt); ret = tas2562_set_fmt(p_tas2562, fmt); return ret; } static int tas2562_set_dai_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask, unsigned int rx_mask, int slots, int slot_width) { int ret = 0; struct snd_soc_codec *codec = dai->codec; struct tas2562_priv *p_tas2562 = snd_soc_codec_get_drvdata(codec); dev_dbg(p_tas2562->dev, "%s, tx_mask:%d, rx_mask:%d, slots:%d, slot_width:%d", __func__, tx_mask, rx_mask, slots, slot_width); ret = tas2562_set_slot(p_tas2562, slot_width); return ret; } static struct snd_soc_dai_ops tas2562_dai_ops = { .digital_mute = tas2562_mute, .hw_params = tas2562_hw_params, .set_fmt = tas2562_set_dai_fmt, .set_tdm_slot = tas2562_set_dai_tdm_slot, }; #define TAS2562_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE) #define TAS2562_RATES (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 \ SNDRV_PCM_RATE_88200 |\ SNDRV_PCM_RATE_96000 |\ SNDRV_PCM_RATE_176400 |\ SNDRV_PCM_RATE_192000\ ) static struct snd_soc_dai_driver tas2562_dai_driver[] = { { .name = "tas2562 ASI1", .id = 0, .playback = { .stream_name = "ASI1 Playback", .channels_min = 2, .channels_max = 2, .rates = SNDRV_PCM_RATE_8000_192000, .formats = TAS2562_FORMATS, }, .capture = { .stream_name = "ASI1 Capture", .channels_min = 0, .channels_max = 2, .rates = SNDRV_PCM_RATE_8000_192000, .formats = TAS2562_FORMATS, }, .ops = &tas2562_dai_ops, .symmetric_rates = 1, }, }; static int tas2562_load_init(struct tas2562_priv *p_tas2562) { int ret; #ifdef TAS2558_CODEC /* Max voltage to 9V */ ret = p_tas2562->update_bits(p_tas2562, channel_both, TAS2562_BOOSTCONFIGURATION2, TAS2562_BOOSTCONFIGURATION2_BOOSTMAXVOLTAGE_MASK, 0x7); ret = p_tas2562->update_bits(p_tas2562, channel_both, TAS2562_PLAYBACKCONFIGURATIONREG0, TAS2562_PLAYBACKCONFIGURATIONREG0_AMPLIFIERLEVEL51_MASK, 0xd << 1); if (ret < 0) return ret; #endif ret = p_tas2562->write(p_tas2562, channel_both, TAS2562_MISCCONFIGURATIONREG0, 0xcf); if (ret < 0) return ret; #ifdef CONFIG_PLATFORM_EXYNOS if(p_tas2562->mn_channels == 2) { ret = p_tas2562->write(p_tas2562, channel_both, TAS2562_TDMConfigurationReg4, 0x13); if (ret < 0) return ret; } else { ret = p_tas2562->write(p_tas2562, channel_both, TAS2562_TDMConfigurationReg4, 0x03); if (ret < 0) return ret; } #else 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; } #endif ret = p_tas2562->write(p_tas2562, channel_both, TAS2562_CLOCKCONFIGURATION, 0x0c); if (ret < 0) return ret; ret = tas2562_i2c_load_data(p_tas2562, channel_both, p_tas2562_classh_d_data); /* Use Oscillator for Boost Clock instead of PLL */ if (p_tas2562->mn_bst_clk_src) { ret = p_tas2562->write(p_tas2562, channel_both, TAS2562_TESTPAGECONFIGURATION, 0x0d); if (ret < 0) return ret; p_tas2562->update_bits(p_tas2562, channel_both, TAS2562_EFFICIENCYCONFIGURATION, TAS2562_OSC_BOOST_CLK_MASK, TAS2562_OSC_BOOST_CLK); } return ret; } static int tas2562_codec_probe(struct snd_soc_codec *codec) { int ret; struct tas2562_priv *p_tas2562 = snd_soc_codec_get_drvdata(codec); ret = snd_soc_add_codec_controls(codec, tas2562_controls, ARRAY_SIZE(tas2562_controls)); if (ret < 0) { pr_err("%s: add_codec_controls failed, err %d\n", __func__, ret); return ret; } tas2562_load_init(p_tas2562); tas2562_iv_enable(p_tas2562, 1); dev_dbg(p_tas2562->dev, "%s\n", __func__); return 0; } static int tas2562_codec_remove(struct snd_soc_codec *codec) { return 0; } static DECLARE_TLV_DB_SCALE(tas2562_digital_tlv, 1100, 50, 0); static const char * const speaker_switch_text[] = {"Off", "On"}; static const struct soc_enum spk_enum[] = { SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(speaker_switch_text), speaker_switch_text), }; static const char * const icn_sw_text[] = {"Enable", "Disable"}; static const struct soc_enum icn_sw_enum[] = { SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(icn_sw_text), icn_sw_text), }; static int tas2562_get_icn_switch(struct snd_kcontrol *pKcontrol, struct snd_ctl_elem_value *p_u_control) { struct snd_soc_codec *codec = snd_soc_kcontrol_codec(pKcontrol); struct tas2562_priv *p_tas2562 = snd_soc_codec_get_drvdata(codec); dev_info(p_tas2562->dev, "%s, icn_sw = %ld\n", __func__, p_u_control->value.integer.value[0]); p_u_control->value.integer.value[0] = p_tas2562->icn_sw; return 0; } static int tas2562_set_icn_switch(struct snd_kcontrol *pKcontrol, struct snd_ctl_elem_value *p_u_control) { struct snd_soc_codec *codec = snd_soc_kcontrol_codec(pKcontrol); struct tas2562_priv *p_tas2562 = snd_soc_codec_get_drvdata(codec); p_tas2562->icn_sw = p_u_control->value.integer.value[0]; if (p_tas2562->icn_sw == 0) { p_tas2562->update_bits(p_tas2562, channel_both, TAS2562_ICN_SW_REG, TAS2562_ICN_SW_MASK, TAS2562_ICN_SW_ENABLE); dev_info(p_tas2562->dev, "%s: ICN Enable!\n", __func__); } else { p_tas2562->update_bits(p_tas2562, channel_both, TAS2562_ICN_SW_REG, TAS2562_ICN_SW_MASK, TAS2562_ICN_SW_DISABLE); dev_info(p_tas2562->dev, "%s: ICN Disable!\n", __func__); } return 0; } static int tas2562_dac_mute_ctrl_get(struct snd_kcontrol *pKcontrol, struct snd_ctl_elem_value *pValue) { struct snd_soc_codec *codec = snd_soc_kcontrol_codec(pKcontrol); struct tas2562_priv *p_tas2562 = snd_soc_codec_get_drvdata(codec); pValue->value.integer.value[0] = p_tas2562->dac_mute; dev_dbg(p_tas2562->dev, "%s = %ld\n", __func__, pValue->value.integer.value[0]); return 0; } static int tas2562_dac_mute_ctrl_put(struct snd_kcontrol *pKcontrol, struct snd_ctl_elem_value *pValue) { int n_result = 0; enum channel chn; int mute = pValue->value.integer.value[0]; struct snd_soc_codec *codec = snd_soc_kcontrol_codec(pKcontrol); struct tas2562_priv *p_tas2562 = snd_soc_codec_get_drvdata(codec); dev_dbg(p_tas2562->dev, "%s, %d\n", __func__, mute); mutex_lock(&p_tas2562->codec_lock); if ((p_tas2562->spk_l_control == 1) && (p_tas2562->spk_r_control == 1) && (p_tas2562->mn_channels == 2)) chn = channel_both; else if (p_tas2562->spk_l_control == 1) chn = channel_left; else if ((p_tas2562->spk_r_control == 1) && (p_tas2562->mn_channels == 2)) chn = channel_right; else chn = channel_left; if (p_tas2562->mn_power_state == TAS2562_POWER_ACTIVE) { if (mute) { n_result = p_tas2562->update_bits(p_tas2562, chn, TAS2562_POWERCONTROL, TAS2562_POWERCONTROL_OPERATIONALMODE10_MASK, TAS2562_POWERCONTROL_OPERATIONALMODE10_MUTE); } else { n_result = p_tas2562->update_bits(p_tas2562, chn, TAS2562_POWERCONTROL, TAS2562_POWERCONTROL_OPERATIONALMODE10_MASK, TAS2562_POWERCONTROL_OPERATIONALMODE10_ACTIVE); } } p_tas2562->dac_mute = mute; mutex_unlock(&p_tas2562->codec_lock); return n_result; } static const struct snd_kcontrol_new tas2562_snd_controls[] = { SOC_SINGLE_TLV("Amp Output Level", TAS2562_PLAYBACKCONFIGURATIONREG0, 1, 0x16, 0, tas2562_digital_tlv), SOC_SINGLE_EXT("SmartPA System Mute", SND_SOC_NOPM, 0, 0x0001, 0, tas2562_system_mute_ctrl_get, tas2562_system_mute_ctrl_put), SOC_SINGLE_EXT("SmartPA Mute", SND_SOC_NOPM, 0, 0x0001, 0, tas2562_mute_ctrl_get, tas2562_mute_ctrl_put), SOC_SINGLE_EXT("TAS2562 DAC Mute", SND_SOC_NOPM, 0, 0x0001, 0, tas2562_dac_mute_ctrl_get, tas2562_dac_mute_ctrl_put), SOC_ENUM_EXT("TAS2562 Left Speaker Switch", spk_enum[0], tas2562_get_left_speaker_switch, tas2562_set_left_speaker_switch), SOC_ENUM_EXT("TAS2562 Right Speaker Switch", spk_enum[0], tas2562_get_right_speaker_switch, tas2562_set_right_speaker_switch), SOC_ENUM_EXT("TAS2562 ICN Switch", icn_sw_enum[0], tas2562_get_icn_switch, tas2562_set_icn_switch), }; static struct snd_soc_codec_driver soc_codec_driver_tas2562 = { .probe = tas2562_codec_probe, .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), .dapm_widgets = tas2562_dapm_widgets, .num_dapm_widgets = ARRAY_SIZE(tas2562_dapm_widgets), .dapm_routes = tas2562_audio_map, .num_dapm_routes = ARRAY_SIZE(tas2562_audio_map), }, }; int tas2562_register_codec(struct tas2562_priv *p_tas2562) { int n_result = 0; dev_info(p_tas2562->dev, "%s, enter\n", __func__); n_result = snd_soc_register_codec(p_tas2562->dev, &soc_codec_driver_tas2562, tas2562_dai_driver, ARRAY_SIZE(tas2562_dai_driver)); #ifdef CONFIG_TAS25XX_ALGO smartamp_add_algo(p_tas2562->mn_channels); tas_calib_init(); #endif /*CONFIG_TAS25XX_ALGO*/ return n_result; } int tas2562_deregister_codec(struct tas2562_priv *p_tas2562) { #ifdef CONFIG_TAS25XX_ALGO smartamp_remove_algo(); #endif /*CONFIG_TAS25XX_ALGO*/ snd_soc_unregister_codec(p_tas2562->dev); return 0; } void tas2562_load_config(struct tas2562_priv *p_tas2562) { int ret = 0; p_tas2562->hw_reset(p_tas2562); msleep(20); p_tas2562->write(p_tas2562, channel_both, TAS2562_SOFTWARERESET, TAS2562_SOFTWARERESET_SOFTWARERESET_RESET); msleep(20); ret = tas2562_iv_slot_config(p_tas2562); if(ret < 0) { goto end; } tas2562_load_init(p_tas2562); tas2562_iv_enable(p_tas2562, tas2562iv_enable); ret = tas2562_set_slot(p_tas2562, p_tas2562->mn_slot_width); if (ret < 0) goto end; ret = tas2562_set_fmt(p_tas2562, p_tas2562->mn_asi_format); if (ret < 0) goto end; ret = tas2562_set_bitwidth(p_tas2562, p_tas2562->mn_pcm_format); if (ret < 0) goto end; ret = tas2562_set_samplerate(p_tas2562, p_tas2562->mn_sampling_rate); if (ret < 0) goto end; ret = tas2562_set_power_state(p_tas2562, channel_both, p_tas2562->mn_power_state); if (ret < 0) goto end; end: /* power up failed, restart later */ if (ret < 0) schedule_delayed_work(&p_tas2562->irq_work, msecs_to_jiffies(1000)); } /* Added for Mute Issue: Device Reset and Reload */ void tas2562_reset_reload(struct tas2562_priv *p_tas2562) { int ret = 0; int i = 0; unsigned int reg = -1; dev_info(p_tas2562->dev, "%s\n", __func__); /*Software Reset*/ p_tas2562->write(p_tas2562, channel_both, TAS2562_SOFTWARERESET, TAS2562_SOFTWARERESET_SOFTWARERESET_RESET); msleep(2); /*Reload all configuration*/ ret = tas2562_iv_slot_config(p_tas2562); if (ret < 0) goto end; ret = tas2562_load_init(p_tas2562); if (ret < 0) goto end; ret = tas2562_iv_enable(p_tas2562, tas2562iv_enable); if (ret < 0) goto end; ret = tas2562_set_slot(p_tas2562, p_tas2562->mn_slot_width); if (ret < 0) goto end; ret = tas2562_set_fmt(p_tas2562, p_tas2562->mn_asi_format); if (ret < 0) goto end; ret = tas2562_set_bitwidth(p_tas2562, p_tas2562->mn_pcm_format); if (ret < 0) goto end; ret = tas2562_set_samplerate(p_tas2562, p_tas2562->mn_sampling_rate); if (ret < 0) goto end; /* Update mixer control changes */ /* Update Amplifier Gain(Amp Output Level)*/ for (i = 0; i < reg_count; i++) { reg = tas2562_reg_count[i]; ret |= p_tas2562->write (p_tas2562, channel_both, reg, tas2562_reg_cache[reg][1]); } if (ret < 0) goto end; /* Update ICN */ if (p_tas2562->icn_sw == 0) { ret = p_tas2562->update_bits(p_tas2562, channel_both, TAS2562_ICN_SW_REG, TAS2562_ICN_SW_MASK, TAS2562_ICN_SW_ENABLE); dev_info(p_tas2562->dev, "%s: ICN Enable!\n", __func__); } else { ret = p_tas2562->update_bits(p_tas2562, channel_both, TAS2562_ICN_SW_REG, TAS2562_ICN_SW_MASK, TAS2562_ICN_SW_DISABLE); dev_info(p_tas2562->dev, "%s: ICN Disable!\n", __func__); } if (ret < 0) goto end; ret = tas2562_set_power_state(p_tas2562, channel_both, p_tas2562->mn_power_state); end: /* power up failed, restart later */ if (ret < 0) schedule_delayed_work(&p_tas2562->irq_work, msecs_to_jiffies(1000)); } MODULE_AUTHOR("Texas Instruments Inc."); MODULE_DESCRIPTION("TAS2562 ALSA SOC Smart Amplifier driver"); MODULE_LICENSE("GPL v2"); #endif /* CONFIG_TAS2562_CODEC */