diff --git a/tas2770-codec.c b/tas2770-codec.c
index 23d99c9d1489ecc98055b1993635f2ee66771ed8..295e3bcf144976a4116df739f5677a3d44afde9f 100644 (file)
--- a/tas2770-codec.c
+++ b/tas2770-codec.c
**
** 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.
+** FOR A PARTICULAR PURPOSE.See the GNU General Public License for more details.
**
** File:
** tas2770-codec.c
**
** Description:
-** ALSA SoC driver for Texas Instruments TAS2770 High Performance 4W Smart Amplifier
+** ALSA SoC driver for TAS2770 20-W Digital Input Mono Class-D Audio Amplifier
+** with Speaker I/V Sense
**
** =============================================================================
*/
#ifdef CONFIG_TAS2770_CODEC
-
#define DEBUG
#include <linux/module.h>
#include <linux/moduleparam.h>
#define TAS2770_MDELAY 0xFFFFFFFE
-//#define KCONTROL_CODEC
-static unsigned int tas2770_codec_read(struct snd_soc_codec *codec, unsigned int reg)
+static int tas2770_set_slot(struct snd_soc_codec *codec, int slot_width);
+
+static unsigned int tas2770_codec_read(struct snd_soc_codec *codec,
+ unsigned int reg)
{
struct tas2770_priv *pTAS2770 = snd_soc_codec_get_drvdata(codec);
int nResult = 0;
dev_err(pTAS2770->dev, "%s, ERROR, reg=0x%x, E=%d\n",
__func__, reg, nResult);
else
- dev_dbg(pTAS2770->dev, "%s, reg: 0x%x, value: 0x%x\n", __func__, reg, value);
+ dev_dbg(pTAS2770->dev, "%s, reg: 0x%x, value: 0x%x\n",
+ __func__, reg, value);
mutex_unlock(&pTAS2770->dev_lock);
- return nResult;
+
+ if (nResult >= 0)
+ return value;
+ else
+ return nResult;
}
mutex_lock(&pTAS2770->dev_lock);
nResult = regmap_write(pTAS2770->regmap, reg, value);
- if(nResult < 0)
+ if (nResult < 0)
dev_err(pTAS2770->dev, "%s, ERROR, reg=0x%x, E=%d\n",
__func__, reg, nResult);
else
- dev_dbg(pTAS2770->dev, "%s, reg: 0x%x, 0x%x\n", __func__, reg, value);
+ dev_dbg(pTAS2770->dev, "%s, reg: 0x%x, 0x%x\n",
+ __func__, reg, value);
mutex_unlock(&pTAS2770->dev_lock);
mutex_lock(&pTAS2770->codec_lock);
dev_dbg(pTAS2770->dev, "%s\n", __func__);
-// pTAS2770->runtime_suspend(pTAS2770);
+ pTAS2770->runtime_suspend(pTAS2770);
mutex_unlock(&pTAS2770->codec_lock);
return ret;
mutex_lock(&pTAS2770->codec_lock);
dev_dbg(pTAS2770->dev, "%s\n", __func__);
-// pTAS2770->runtime_resume(pTAS2770);
+ pTAS2770->runtime_resume(pTAS2770);
mutex_unlock(&pTAS2770->codec_lock);
return ret;
}
-static const struct snd_kcontrol_new tas2770_asi_controls[] = {
- SOC_DAPM_SINGLE("Left", TAS2770_TDMConfigurationReg2,
- 4, 1, 0),
- SOC_DAPM_SINGLE("Right", TAS2770_TDMConfigurationReg2,
- 4, 2, 0),
- SOC_DAPM_SINGLE("LeftRightDiv2", TAS2770_TDMConfigurationReg2,
- 4, 3, 0),
+static const char * const tas2770_ASI1_src[] = {
+ "I2C offset", "Left", "Right", "LeftRightDiv2",
};
+static SOC_ENUM_SINGLE_DECL(
+ tas2770_ASI1_src_enum, TAS2770_TDMConfigurationReg2,
+ 4, tas2770_ASI1_src);
-static int tas2770_dac_event(struct snd_soc_dapm_widget *w,
- struct snd_kcontrol *kcontrol, int event)
+static const struct snd_kcontrol_new tas2770_asi1_mux =
+ SOC_DAPM_ENUM("ASI1 Source", tas2770_ASI1_src_enum);
+
+static int tas2770_set_power_state(struct tas2770_priv *pTAS2770, int state)
{
-#if 1
- struct snd_soc_codec *codec = w->codec;
-// struct tas2770_priv *pTAS2770 = snd_soc_codec_get_drvdata(codec);
+ struct snd_soc_codec *codec = pTAS2770->codec;
- switch (event) {
- case SND_SOC_DAPM_POST_PMU:
+ switch (state) {
+ case TAS2770_POWER_ACTIVE:
snd_soc_update_bits(codec, TAS2770_PowerControl,
TAS2770_PowerControl_OperationalMode10_Mask,
TAS2770_PowerControl_OperationalMode10_Active);
+ pTAS2770->mnPowerState = TAS2770_POWER_ACTIVE;
+ pTAS2770->enableIRQ(pTAS2770, true);
break;
- case SND_SOC_DAPM_PRE_PMD:
+
+ case TAS2770_POWER_MUTE:
+ snd_soc_update_bits(codec, TAS2770_PowerControl,
+ TAS2770_PowerControl_OperationalMode10_Mask,
+ TAS2770_PowerControl_OperationalMode10_Mute);
+ pTAS2770->mnPowerState = TAS2770_POWER_MUTE;
+ break;
+
+ case TAS2770_POWER_SHUTDOWN:
snd_soc_update_bits(codec, TAS2770_PowerControl,
TAS2770_PowerControl_OperationalMode10_Mask,
TAS2770_PowerControl_OperationalMode10_Shutdown);
+ pTAS2770->enableIRQ(pTAS2770, false);
+ pTAS2770->mnPowerState = TAS2770_POWER_SHUTDOWN;
break;
-
+
+ default:
+ dev_err(pTAS2770->dev, "wrong power state setting %d\n", state);
+
}
-#endif
+
+ pTAS2770->mnPowerState = state;
return 0;
+}
+
+static int tas2770_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 tas2770_priv *pTAS2770 = snd_soc_codec_get_drvdata(codec);
+
+ mutex_lock(&pTAS2770->codec_lock);
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ tas2770_set_power_state(pTAS2770, TAS2770_POWER_MUTE);
+ break;
+ case SND_SOC_DAPM_PRE_PMD:
+ tas2770_set_power_state(pTAS2770, TAS2770_POWER_SHUTDOWN);
+ break;
+
+ }
+ mutex_unlock(&pTAS2770->codec_lock);
+ return 0;
}
+static const struct snd_kcontrol_new isense_switch =
+ SOC_DAPM_SINGLE("Switch", TAS2770_PowerControl, 3, 1, 1);
+static const struct snd_kcontrol_new vsense_switch =
+ SOC_DAPM_SINGLE("Switch", TAS2770_PowerControl, 2, 1, 1);
+
static const struct snd_soc_dapm_widget tas2770_dapm_widgets[] = {
SND_SOC_DAPM_AIF_IN("ASI1", "ASI1 Playback", 0, SND_SOC_NOPM, 0, 0),
- SND_SOC_DAPM_MIXER("ASI1 Sel",
- TAS2770_TDMConfigurationReg2, 4, 0,
- &tas2770_asi_controls[0],
- ARRAY_SIZE(tas2770_asi_controls)),
- SND_SOC_DAPM_DAC_E("DAC", NULL, SND_SOC_NOPM, 0, 0,
- tas2770_dac_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
- SND_SOC_DAPM_OUTPUT("OUT")
-
+ SND_SOC_DAPM_MUX("ASI1 Sel", SND_SOC_NOPM, 0, 0,
+ &tas2770_asi1_mux),
+ SND_SOC_DAPM_SWITCH("ISENSE", TAS2770_PowerControl, 3, 1,
+ &isense_switch),
+ SND_SOC_DAPM_SWITCH("VSENSE", TAS2770_PowerControl, 2, 1,
+ &vsense_switch),
+ SND_SOC_DAPM_DAC_E("DAC", NULL, SND_SOC_NOPM, 0, 0, tas2770_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")
};
static const struct snd_soc_dapm_route tas2770_audio_map[] = {
+ {"ASI1 Sel", "I2C offset", "ASI1"},
{"ASI1 Sel", "Left", "ASI1"},
{"ASI1 Sel", "Right", "ASI1"},
{"ASI1 Sel", "LeftRightDiv2", "ASI1"},
{"DAC", NULL, "ASI1 Sel"},
{"OUT", NULL, "DAC"},
+ {"ISENSE", "Switch", "IMON"},
+ {"VSENSE", "Switch", "VMON"},
};
static int tas2770_mute(struct snd_soc_dai *dai, int mute)
{
-#if 1
struct snd_soc_codec *codec = dai->codec;
struct tas2770_priv *pTAS2770 = snd_soc_codec_get_drvdata(codec);
+ dev_dbg(pTAS2770->dev, "%s\n", __func__);
mutex_lock(&pTAS2770->codec_lock);
- if(mute) {
- snd_soc_update_bits(codec, TAS2770_PowerControl,
- TAS2770_PowerControl_OperationalMode10_Mask,
- TAS2770_PowerControl_OperationalMode10_Mute);
+ if (mute) {
+ tas2770_set_power_state(pTAS2770, TAS2770_POWER_MUTE);
} else {
- snd_soc_update_bits(codec, TAS2770_PowerControl,
- TAS2770_PowerControl_OperationalMode10_Mask,
- TAS2770_PowerControl_OperationalMode10_Active);
+ tas2770_set_power_state(pTAS2770, TAS2770_POWER_ACTIVE);
}
mutex_unlock(&pTAS2770->codec_lock);
-#endif
return 0;
}
-
-
-static int tas2770_hw_params(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *params,
- struct snd_soc_dai *dai)
+static int tas2770_set_bitwidth(struct tas2770_priv *pTAS2770, int bitwidth)
{
- struct snd_soc_codec *codec = dai->codec;
- struct tas2770_priv *pTAS2770 = snd_soc_codec_get_drvdata(codec);
- int blr_clk_ratio;
- int ret = 0;
-
- dev_dbg(pTAS2770->dev, "%s, format: %d\n", __func__, params_format(params));
-
- switch(params_format(params)) {
+ switch (bitwidth) {
case SNDRV_PCM_FORMAT_S16_LE:
- snd_soc_update_bits(codec,
+ snd_soc_update_bits(pTAS2770->codec,
TAS2770_TDMConfigurationReg2,
- TAS2770_TDMConfigurationReg2_RXWLEN32_Mask |
- TAS2770_TDMConfigurationReg2_RXSLEN10_Mask,
- TAS2770_TDMConfigurationReg2_RXWLEN32_16Bits |
- TAS2770_TDMConfigurationReg2_RXWLEN32_16Bits );
- pTAS2770->ch_size = 16;
+ TAS2770_TDMConfigurationReg2_RXWLEN32_Mask,
+ TAS2770_TDMConfigurationReg2_RXWLEN32_16Bits);
+ /* If machine driver did not call set slot width */
+ if (pTAS2770->mnSlot_width == 0)
+ tas2770_set_slot(pTAS2770->codec, 16);
+ pTAS2770->mnVmon_slot_no = pTAS2770->mnImon_slot_no + 2;
break;
- case SNDRV_PCM_FMTBIT_S24_LE:
- snd_soc_update_bits(codec,
+ case SNDRV_PCM_FORMAT_S24_LE:
+ snd_soc_update_bits(pTAS2770->codec,
TAS2770_TDMConfigurationReg2,
- TAS2770_TDMConfigurationReg2_RXWLEN32_Mask |
- TAS2770_TDMConfigurationReg2_RXSLEN10_Mask,
- TAS2770_TDMConfigurationReg2_RXWLEN32_24Bits |
- TAS2770_TDMConfigurationReg2_RXWLEN32_24Bits );
- pTAS2770->ch_size = 24;
+ TAS2770_TDMConfigurationReg2_RXWLEN32_Mask,
+ TAS2770_TDMConfigurationReg2_RXWLEN32_24Bits);
+ if (pTAS2770->mnSlot_width == 0)
+ tas2770_set_slot(pTAS2770->codec, 32);
+ pTAS2770->mnVmon_slot_no = pTAS2770->mnImon_slot_no + 4;
break;
- case SNDRV_PCM_FMTBIT_S32_LE:
- snd_soc_update_bits(codec,
+ case SNDRV_PCM_FORMAT_S32_LE:
+ snd_soc_update_bits(pTAS2770->codec,
TAS2770_TDMConfigurationReg2,
- TAS2770_TDMConfigurationReg2_RXWLEN32_Mask |
- TAS2770_TDMConfigurationReg2_RXSLEN10_Mask,
- TAS2770_TDMConfigurationReg2_RXWLEN32_32Bits |
- TAS2770_TDMConfigurationReg2_RXWLEN32_32Bits );
- pTAS2770->ch_size = 32;
+ TAS2770_TDMConfigurationReg2_RXWLEN32_Mask,
+ TAS2770_TDMConfigurationReg2_RXWLEN32_32Bits);
+ if (pTAS2770->mnSlot_width == 0)
+ tas2770_set_slot(pTAS2770->codec, 32);
+ pTAS2770->mnVmon_slot_no = pTAS2770->mnImon_slot_no + 4;
break;
+ default:
+ dev_dbg(pTAS2770->dev, "Not supported params format\n");
+ return -EINVAL;
}
- blr_clk_ratio = params_channels(params) * pTAS2770->ch_size;
- dev_dbg(pTAS2770->dev, "blr_clk_ratio: %d\n", blr_clk_ratio);
+ pTAS2770->mnCh_size = bitwidth;
+ dev_dbg(pTAS2770->dev, "mnCh_size: %d\n", pTAS2770->mnCh_size);
+
+ snd_soc_update_bits(pTAS2770->codec,
+ TAS2770_TDMConfigurationReg5,
+ TAS2770_TDMConfigurationReg5_VSNSTX_Mask |
+ TAS2770_TDMConfigurationReg5_VSNSSLOT50_Mask,
+ TAS2770_TDMConfigurationReg5_VSNSTX_Enable |
+ pTAS2770->mnVmon_slot_no);
+ snd_soc_update_bits(pTAS2770->codec,
+ TAS2770_TDMConfigurationReg6,
+ TAS2770_TDMConfigurationReg6_ISNSTX_Mask |
+ TAS2770_TDMConfigurationReg6_ISNSSLOT50_Mask,
+ TAS2770_TDMConfigurationReg6_ISNSTX_Enable |
+ pTAS2770->mnImon_slot_no);
- switch(blr_clk_ratio) {
- case 16:
- snd_soc_update_bits(codec,
- TAS2770_ClockConfiguration,
- TAS2770_ClockConfiguration_SBCLKtoFS52_Mask,
- TAS2770_ClockConfiguration_SBCLKtoFS52_16);
- break;
- case 24:
- snd_soc_update_bits(codec,
- TAS2770_ClockConfiguration,
- TAS2770_ClockConfiguration_SBCLKtoFS52_Mask,
- TAS2770_ClockConfiguration_SBCLKtoFS52_24);
- break;
- case 32:
- snd_soc_update_bits(codec,
- TAS2770_ClockConfiguration,
- TAS2770_ClockConfiguration_SBCLKtoFS52_Mask,
- TAS2770_ClockConfiguration_SBCLKtoFS52_32);
- break;
- case 48:
- snd_soc_update_bits(codec,
- TAS2770_ClockConfiguration,
- TAS2770_ClockConfiguration_SBCLKtoFS52_Mask,
- TAS2770_ClockConfiguration_SBCLKtoFS52_48);
- break;
- case 64:
- snd_soc_update_bits(codec,
- TAS2770_ClockConfiguration,
- TAS2770_ClockConfiguration_SBCLKtoFS52_Mask,
- TAS2770_ClockConfiguration_SBCLKtoFS52_64);
- break;
- case 96:
- snd_soc_update_bits(codec,
- TAS2770_ClockConfiguration,
- TAS2770_ClockConfiguration_SBCLKtoFS52_Mask,
- TAS2770_ClockConfiguration_SBCLKtoFS52_96);
- break;
- case 128:
- snd_soc_update_bits(codec,
- TAS2770_ClockConfiguration,
- TAS2770_ClockConfiguration_SBCLKtoFS52_Mask,
- TAS2770_ClockConfiguration_SBCLKtoFS52_128);
- break;
- case 192:
- snd_soc_update_bits(codec,
- TAS2770_ClockConfiguration,
- TAS2770_ClockConfiguration_SBCLKtoFS52_Mask,
- TAS2770_ClockConfiguration_SBCLKtoFS52_192);
- break;
- case 256:
- snd_soc_update_bits(codec,
- TAS2770_ClockConfiguration,
- TAS2770_ClockConfiguration_SBCLKtoFS52_Mask,
- TAS2770_ClockConfiguration_SBCLKtoFS52_256);
- break;
- case 384:
- snd_soc_update_bits(codec,
- TAS2770_ClockConfiguration,
- TAS2770_ClockConfiguration_SBCLKtoFS52_Mask,
- TAS2770_ClockConfiguration_SBCLKtoFS52_384);
- break;
- case 512:
- snd_soc_update_bits(codec,
- TAS2770_ClockConfiguration,
- TAS2770_ClockConfiguration_SBCLKtoFS52_Mask,
- TAS2770_ClockConfiguration_SBCLKtoFS52_512);
- break;
- default:
- dev_err(pTAS2770->dev, "Invalid BCLK to FSYNC ratio\n");
- ret = -EINVAL;
- }
+ return 0;
+}
- dev_dbg(pTAS2770->dev, "%s, sample rate: %d\n", __func__, params_rate(params));
- switch(params_rate(params))
- {
- case 48000:
- snd_soc_update_bits(codec,
+static int tas2770_set_samplerate(struct tas2770_priv *pTAS2770, int samplerate)
+{
+ switch (samplerate) {
+ case 48000:
+ snd_soc_update_bits(pTAS2770->codec,
TAS2770_TDMConfigurationReg0,
TAS2770_TDMConfigurationReg0_SAMPRATERAMP_Mask,
TAS2770_TDMConfigurationReg0_SAMPRATERAMP_48KHz);
- snd_soc_update_bits(codec,
+ snd_soc_update_bits(pTAS2770->codec,
TAS2770_TDMConfigurationReg0,
TAS2770_TDMConfigurationReg0_SAMPRATE31_Mask,
TAS2770_TDMConfigurationReg0_SAMPRATE31_44_1_48kHz);
break;
- case 44100:
- snd_soc_update_bits(codec,
+ case 44100:
+ snd_soc_update_bits(pTAS2770->codec,
TAS2770_TDMConfigurationReg0,
TAS2770_TDMConfigurationReg0_SAMPRATERAMP_Mask,
TAS2770_TDMConfigurationReg0_SAMPRATERAMP_44_1KHz);
- snd_soc_update_bits(codec,
+ snd_soc_update_bits(pTAS2770->codec,
TAS2770_TDMConfigurationReg0,
TAS2770_TDMConfigurationReg0_SAMPRATE31_Mask,
TAS2770_TDMConfigurationReg0_SAMPRATE31_44_1_48kHz);
break;
- case 96000:
- snd_soc_update_bits(codec,
+ case 96000:
+ snd_soc_update_bits(pTAS2770->codec,
TAS2770_TDMConfigurationReg0,
TAS2770_TDMConfigurationReg0_SAMPRATERAMP_Mask,
TAS2770_TDMConfigurationReg0_SAMPRATERAMP_48KHz);
- snd_soc_update_bits(codec,
+ snd_soc_update_bits(pTAS2770->codec,
TAS2770_TDMConfigurationReg0,
TAS2770_TDMConfigurationReg0_SAMPRATE31_Mask,
TAS2770_TDMConfigurationReg0_SAMPRATE31_88_2_96kHz);
break;
- case 88200:
- snd_soc_update_bits(codec,
+ case 88200:
+ snd_soc_update_bits(pTAS2770->codec,
TAS2770_TDMConfigurationReg0,
TAS2770_TDMConfigurationReg0_SAMPRATERAMP_Mask,
TAS2770_TDMConfigurationReg0_SAMPRATERAMP_44_1KHz);
- snd_soc_update_bits(codec,
+ snd_soc_update_bits(pTAS2770->codec,
TAS2770_TDMConfigurationReg0,
TAS2770_TDMConfigurationReg0_SAMPRATE31_Mask,
TAS2770_TDMConfigurationReg0_SAMPRATE31_88_2_96kHz);
break;
- case 19200:
- snd_soc_update_bits(codec,
+ case 19200:
+ snd_soc_update_bits(pTAS2770->codec,
TAS2770_TDMConfigurationReg0,
TAS2770_TDMConfigurationReg0_SAMPRATERAMP_Mask,
TAS2770_TDMConfigurationReg0_SAMPRATERAMP_48KHz);
- snd_soc_update_bits(codec,
+ snd_soc_update_bits(pTAS2770->codec,
TAS2770_TDMConfigurationReg0,
TAS2770_TDMConfigurationReg0_SAMPRATE31_Mask,
TAS2770_TDMConfigurationReg0_SAMPRATE31_176_4_192kHz);
break;
- case 17640:
- snd_soc_update_bits(codec,
+ case 17640:
+ snd_soc_update_bits(pTAS2770->codec,
TAS2770_TDMConfigurationReg0,
TAS2770_TDMConfigurationReg0_SAMPRATERAMP_Mask,
TAS2770_TDMConfigurationReg0_SAMPRATERAMP_44_1KHz);
- snd_soc_update_bits(codec,
+ snd_soc_update_bits(pTAS2770->codec,
TAS2770_TDMConfigurationReg0,
TAS2770_TDMConfigurationReg0_SAMPRATE31_Mask,
TAS2770_TDMConfigurationReg0_SAMPRATE31_176_4_192kHz);
break;
- default:
+ default:
dev_dbg(pTAS2770->dev, "%s, unsupported sample rate\n", __func__);
-
+
}
- return ret;
+
+ pTAS2770->mnSamplingRate = samplerate;
+ return 0;
}
-static int tas2770_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+static int tas2770_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
{
- u8 tdm_rx_start_slot = 0, asi_cfg_1 = 0;
struct snd_soc_codec *codec = dai->codec;
struct tas2770_priv *pTAS2770 = snd_soc_codec_get_drvdata(codec);
int ret = 0;
- dev_dbg(pTAS2770->dev, "%s, format=0x%x\n", __func__, fmt);
+ dev_dbg(pTAS2770->dev, "%s, format: %d\n", __func__,
+ params_format(params));
+
+ mutex_lock(&pTAS2770->codec_lock);
+
+ ret = tas2770_set_bitwidth(pTAS2770, params_format(params));
+ if(ret < 0)
+ return ret;
+
+ dev_dbg(pTAS2770->dev, "%s, sample rate: %d\n", __func__,
+ params_rate(params));
+
+ ret = tas2770_set_samplerate(pTAS2770, params_rate(params));
+
+ mutex_unlock(&pTAS2770->codec_lock);
+ return ret;
+}
+
+static int tas2770_set_fmt(struct tas2770_priv *pTAS2770, unsigned int fmt)
+{
+ u8 tdm_rx_start_slot = 0, asi_cfg_1 = 0;
+ int ret = 0;
+ int value = 0;
-#if 1
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
- case SND_SOC_DAIFMT_CBS_CFS:
+ case SND_SOC_DAIFMT_CBS_CFS:
asi_cfg_1 = 0x00;
break;
default:
ret = -EINVAL;
}
- snd_soc_update_bits(codec, TAS2770_TDMConfigurationReg1,
+ snd_soc_update_bits(pTAS2770->codec, TAS2770_TDMConfigurationReg1,
TAS2770_TDMConfigurationReg1_RXEDGE_Mask,
asi_cfg_1);
tdm_rx_start_slot = 0;
break;
default:
- dev_err(pTAS2770->dev, "DAI Format is not found, fmt=0x%x\n", fmt);
- ret = -EINVAL;
+ dev_err(pTAS2770->dev, "DAI Format is not found, fmt=0x%x\n", fmt);
+ ret = -EINVAL;
break;
}
- snd_soc_update_bits(codec, TAS2770_TDMConfigurationReg1,
+ snd_soc_update_bits(pTAS2770->codec, TAS2770_TDMConfigurationReg1,
TAS2770_TDMConfigurationReg1_RXOFFSET51_Mask,
- (tdm_rx_start_slot << TAS2770_TDMConfigurationReg1_RXOFFSET51_Shift));
-#endif
+ (tdm_rx_start_slot << TAS2770_TDMConfigurationReg1_RXOFFSET51_Shift));
+
+ snd_soc_update_bits(pTAS2770->codec, TAS2770_TDMConfigurationReg3,
+ TAS2770_TDMConfigurationReg3_RXSLOTLeft30_Mask,
+ (pTAS2770->mnLeftSlot << TAS2770_TDMConfigurationReg3_RXSLOTLeft30_Shift));
+ snd_soc_update_bits(pTAS2770->codec, TAS2770_TDMConfigurationReg3,
+ TAS2770_TDMConfigurationReg3_RXSLOTRight74_Mask,
+ (pTAS2770->mnRightSlot << TAS2770_TDMConfigurationReg3_RXSLOTRight74_Shift));
+
+ value = snd_soc_read(pTAS2770->codec, TAS2770_TDMConfigurationReg3);
+ dev_dbg(pTAS2770->dev, "slot value: 0x%x", value);
+
+ pTAS2770->mnASIFormat = fmt;
+
+ return 0;
+}
+
+static int tas2770_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+ struct snd_soc_codec *codec = dai->codec;
+ struct tas2770_priv *pTAS2770 = snd_soc_codec_get_drvdata(codec);
+ int ret = 0;
+
+ dev_dbg(pTAS2770->dev, "%s, format=0x%x\n", __func__, fmt);
+ mutex_lock(&pTAS2770->codec_lock);
+
+ ret = tas2770_set_fmt(pTAS2770, fmt);
+
+ mutex_unlock(&pTAS2770->codec_lock);
+ return ret;
+}
+
+static int tas2770_set_slot(struct snd_soc_codec *codec, int slot_width)
+{
+ int ret = 0;
+ struct tas2770_priv *pTAS2770 = snd_soc_codec_get_drvdata(codec);
+
+ switch (slot_width) {
+ case 16:
+ ret = snd_soc_update_bits(codec,
+ TAS2770_TDMConfigurationReg2,
+ TAS2770_TDMConfigurationReg2_RXSLEN10_Mask,
+ TAS2770_TDMConfigurationReg2_RXSLEN10_16Bits);
+ break;
+
+ case 24:
+ ret = snd_soc_update_bits(codec,
+ TAS2770_TDMConfigurationReg2,
+ TAS2770_TDMConfigurationReg2_RXSLEN10_Mask,
+ TAS2770_TDMConfigurationReg2_RXSLEN10_24Bits);
+ break;
+
+ case 32:
+ ret = snd_soc_update_bits(codec,
+ TAS2770_TDMConfigurationReg2,
+ TAS2770_TDMConfigurationReg2_RXSLEN10_Mask,
+ TAS2770_TDMConfigurationReg2_RXSLEN10_32Bits);
+ break;
+
+ case 0:
+ /* Do not change slot width */
+ break;
+
+ default:
+ dev_dbg(pTAS2770->dev, "slot width not supported");
+ ret = -EINVAL;
+ }
+
+ if (ret >= 0)
+ pTAS2770->mnSlot_width = slot_width;
+
+ return ret;
+}
+
+static int tas2770_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 tas2770_priv *pTAS2770 = snd_soc_codec_get_drvdata(codec);
+
+ dev_dbg(pTAS2770->dev, "%s, tx_mask:%d, rx_mask:%d, slots:%d, slot_width:%d",
+ __func__, tx_mask, rx_mask, slots, slot_width);
+
+ mutex_lock(&pTAS2770->codec_lock);
+ ret = tas2770_set_slot(codec, slot_width);
+ mutex_unlock(&pTAS2770->codec_lock);
+
return ret;
}
.digital_mute = tas2770_mute,
.hw_params = tas2770_hw_params,
.set_fmt = tas2770_set_dai_fmt,
+ .set_tdm_slot = tas2770_set_dai_tdm_slot,
};
#define TAS2770_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
-#define TAS2770_RATES (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 \
- SNDRV_PCM_RATE_88200 |\
+#define TAS2770_RATES (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |\
SNDRV_PCM_RATE_96000 |\
- SNDRV_PCM_RATE_176400 |\
SNDRV_PCM_RATE_192000\
)
.stream_name = "ASI1 Playback",
.channels_min = 2,
.channels_max = 2,
- .rates = SNDRV_PCM_RATE_8000_192000,
+ .rates = TAS2770_RATES,
.formats = TAS2770_FORMATS,
},
.capture = {
.stream_name = "ASI1 Capture",
.channels_min = 0,
.channels_max = 2,
- .rates = SNDRV_PCM_RATE_8000_192000,
- .formats = TAS2770_FORMATS,
+ .rates = TAS2770_RATES,
+ .formats = TAS2770_FORMATS,
},
.ops = &tas2770_dai_ops,
.symmetric_rates = 1,
struct tas2770_priv *pTAS2770 = snd_soc_codec_get_drvdata(codec);
dev_err(pTAS2770->dev, "%s\n", __func__);
+ pTAS2770->codec = codec;
return 0;
}
return 0;
}
-#if 0
-
-/*
- * DAC digital volumes. From 0 to 31 dB in 1 dB steps
- */
-static DECLARE_TLV_DB_SCALE(dac_tlv, 0, 100, 0);
+static DECLARE_TLV_DB_SCALE(tas2770_digital_tlv, 1100, 50, 0);
+static DECLARE_TLV_DB_SCALE(tas2770_playback_volume, -12750, 50, 0);
static const struct snd_kcontrol_new tas2770_snd_controls[] = {
- SOC_SINGLE_TLV("DAC Playback Volume", TAS2770_PlaybackConfigurationReg0, 0, 0x1f, 0,
- dac_tlv),
-// SOC_SINGLE_EXT("TAS2770 PowerCtrl", SND_SOC_NOPM, 0, 0x0001, 0,
-// tas2770_power_ctrl_get, tas2770_power_ctrl_put),
+ SOC_SINGLE_TLV("Amp Output Level", TAS2770_PlaybackConfigurationReg0,
+ 0, 0x14, 0,
+ tas2770_digital_tlv),
+ SOC_SINGLE_TLV("Playback Volume", TAS2770_PlaybackConfigurationReg2,
+ 0, TAS2770_PlaybackConfigurationReg2_VOLMAX, 1,
+ tas2770_playback_volume),
};
-#endif
static struct snd_soc_codec_driver soc_codec_driver_tas2770 = {
.probe = tas2770_codec_probe,
.write = tas2770_codec_write,
.suspend = tas2770_codec_suspend,
.resume = tas2770_codec_resume,
-// .controls = tas2770_snd_controls,
-// .num_controls = ARRAY_SIZE(tas2770_snd_controls),
- .dapm_widgets = tas2770_dapm_widgets,
- .num_dapm_widgets = ARRAY_SIZE(tas2770_dapm_widgets),
- .dapm_routes = tas2770_audio_map,
- .num_dapm_routes = ARRAY_SIZE(tas2770_audio_map),
+ .component_driver = {
+ .controls = tas2770_snd_controls,
+ .num_controls = ARRAY_SIZE(tas2770_snd_controls),
+ .dapm_widgets = tas2770_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(tas2770_dapm_widgets),
+ .dapm_routes = tas2770_audio_map,
+ .num_dapm_routes = ARRAY_SIZE(tas2770_audio_map),
+ },
};
int tas2770_register_codec(struct tas2770_priv *pTAS2770)
return 0;
}
+void tas2770_LoadConfig(struct tas2770_priv *pTAS2770)
+{
+ int ret = 0;
+
+ pTAS2770->hw_reset(pTAS2770);
+ snd_soc_write(pTAS2770->codec, TAS2770_SoftwareReset,
+ TAS2770_SoftwareReset_SoftwareReset_Reset);
+
+ ret = tas2770_set_slot(pTAS2770->codec, pTAS2770->mnSlot_width);
+ if (ret < 0)
+ goto end;
+
+ ret = tas2770_set_fmt(pTAS2770, pTAS2770->mnASIFormat);
+ if (ret < 0)
+ goto end;
+
+ ret = tas2770_set_bitwidth(pTAS2770, pTAS2770->mnCh_size);
+ if (ret < 0)
+ goto end;
+
+ ret = tas2770_set_samplerate(pTAS2770, pTAS2770->mnSamplingRate);
+ if (ret < 0)
+ goto end;
+
+ ret = tas2770_set_power_state(pTAS2770, pTAS2770->mnPowerState);
+
+end:
+/* power up failed, restart later */
+ if (ret < 0)
+ schedule_delayed_work(&pTAS2770->irq_work,
+ msecs_to_jiffies(1000));
+}
+
MODULE_AUTHOR("Texas Instruments Inc.");
MODULE_DESCRIPTION("TAS2770 ALSA SOC Smart Amplifier driver");
MODULE_LICENSE("GPL v2");