]> Gitweb @ Texas Instruments - Open Source Git Repositories - git.TI.com/gitweb - tas2770sw-android/tas2770sw-android.git/blobdiff - tas2770-codec.c
Add regmap init and support of DAC volume
[tas2770sw-android/tas2770sw-android.git] / tas2770-codec.c
index 6efab7a14d7f67c411510bc1afe67c99fc57be96..ce05bc2172cb77d994b2350ed5e6cb115ea8b954 100644 (file)
@@ -47,6 +47,8 @@
 
 #define TAS2770_MDELAY 0xFFFFFFFE
 
+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)
 {
@@ -124,15 +126,17 @@ static int tas2770_codec_resume(struct snd_soc_codec *codec)
        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 const struct snd_kcontrol_new tas2770_asi1_mux =
+       SOC_DAPM_ENUM("ASI1 Source", tas2770_ASI1_src_enum);
+
 
 static int tas2770_dac_event(struct snd_soc_dapm_widget *w,
                        struct snd_kcontrol *kcontrol, int event)
@@ -143,7 +147,7 @@ static int tas2770_dac_event(struct snd_soc_dapm_widget *w,
        case SND_SOC_DAPM_POST_PMU:
                snd_soc_update_bits(codec, TAS2770_PowerControl,
                        TAS2770_PowerControl_OperationalMode10_Mask,
-                       TAS2770_PowerControl_OperationalMode10_Active);
+                       TAS2770_PowerControl_OperationalMode10_Mute);
                break;
        case SND_SOC_DAPM_PRE_PMD:
                snd_soc_update_bits(codec, TAS2770_PowerControl,
@@ -163,10 +167,8 @@ static const struct snd_kcontrol_new vsense_switch =
 
 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_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,
@@ -179,6 +181,7 @@ static const struct snd_soc_dapm_widget tas2770_dapm_widgets[] = {
 };
 
 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"},
@@ -216,6 +219,7 @@ static int tas2770_hw_params(struct snd_pcm_substream *substream,
        struct snd_soc_codec *codec = dai->codec;
        struct tas2770_priv *pTAS2770 = snd_soc_codec_get_drvdata(codec);
        int ret = 0;
+       int slot_width_tmp = 16;
 
        dev_dbg(pTAS2770->dev, "%s, format: %d\n", __func__,
                params_format(params));
@@ -224,45 +228,53 @@ static int tas2770_hw_params(struct snd_pcm_substream *substream,
        case SNDRV_PCM_FORMAT_S16_LE:
                snd_soc_update_bits(codec,
                        TAS2770_TDMConfigurationReg2,
-                       TAS2770_TDMConfigurationReg2_RXWLEN32_Mask |
-                       TAS2770_TDMConfigurationReg2_RXSLEN10_Mask,
-                       TAS2770_TDMConfigurationReg2_RXWLEN32_16Bits |
-                       TAS2770_TDMConfigurationReg2_RXSLEN10_16Bits);
-                       pTAS2770->ch_size = 16;
+                       TAS2770_TDMConfigurationReg2_RXWLEN32_Mask,
+                       TAS2770_TDMConfigurationReg2_RXWLEN32_16Bits);
+                       pTAS2770->mnCh_size = 16;
+                       if (pTAS2770->mnSlot_width == 0)
+                               slot_width_tmp = 16;
                break;
        case SNDRV_PCM_FORMAT_S24_LE:
                        snd_soc_update_bits(codec,
                        TAS2770_TDMConfigurationReg2,
-                       TAS2770_TDMConfigurationReg2_RXWLEN32_Mask |
-                       TAS2770_TDMConfigurationReg2_RXSLEN10_Mask,
-                       TAS2770_TDMConfigurationReg2_RXWLEN32_24Bits  |
-                       TAS2770_TDMConfigurationReg2_RXSLEN10_32Bits);
-                       pTAS2770->ch_size = 32;
+                       TAS2770_TDMConfigurationReg2_RXWLEN32_Mask,
+                       TAS2770_TDMConfigurationReg2_RXWLEN32_24Bits);
+                       pTAS2770->mnCh_size = 24;
+                       if (pTAS2770->mnSlot_width == 0)
+                               slot_width_tmp = 32;
                break;
        case SNDRV_PCM_FORMAT_S32_LE:
                        snd_soc_update_bits(codec,
                        TAS2770_TDMConfigurationReg2,
-                       TAS2770_TDMConfigurationReg2_RXWLEN32_Mask |
-                       TAS2770_TDMConfigurationReg2_RXSLEN10_Mask,
-                       TAS2770_TDMConfigurationReg2_RXWLEN32_32Bits |
-                       TAS2770_TDMConfigurationReg2_RXSLEN10_32Bits);
-                       pTAS2770->ch_size = 32;
+                       TAS2770_TDMConfigurationReg2_RXWLEN32_Mask,
+                       TAS2770_TDMConfigurationReg2_RXWLEN32_32Bits);
+                       pTAS2770->mnCh_size = 32;
+                       if (pTAS2770->mnSlot_width == 0)
+                               slot_width_tmp = 32;
                break;
 
+       default:
+               dev_dbg(pTAS2770->dev, "Not supported params format\n");
+               return -EINVAL;
        }
 
-       dev_dbg(pTAS2770->dev, "ch_size: %d\n", pTAS2770->ch_size);
+       /* If machine driver did not call set slot width */
+       if (pTAS2770->mnSlot_width == 0)
+               tas2770_set_slot(codec, slot_width_tmp);
+
+       dev_dbg(pTAS2770->dev, "mnCh_size: %d\n", pTAS2770->mnCh_size);
        snd_soc_update_bits(codec,
                TAS2770_TDMConfigurationReg5,
                TAS2770_TDMConfigurationReg5_VSNSTX_Mask |
                TAS2770_TDMConfigurationReg5_VSNSSLOT50_Mask,
                TAS2770_TDMConfigurationReg5_VSNSTX_Enable |
-               (pTAS2770->ch_size >> 3));
+               pTAS2770->mnVmon_slot_no);
        snd_soc_update_bits(codec,
                TAS2770_TDMConfigurationReg6,
                TAS2770_TDMConfigurationReg6_ISNSTX_Mask |
                TAS2770_TDMConfigurationReg6_ISNSSLOT50_Mask,
-               TAS2770_TDMConfigurationReg6_ISNSTX_Enable);
+               TAS2770_TDMConfigurationReg6_ISNSTX_Enable |
+               pTAS2770->mnImon_slot_no);
 
        dev_dbg(pTAS2770->dev, "%s, sample rate: %d\n", __func__,
                params_rate(params));
@@ -320,6 +332,7 @@ 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;
+       int value = 0;
 
        dev_dbg(pTAS2770->dev, "%s, format=0x%x\n", __func__, fmt);
 
@@ -370,6 +383,75 @@ static int tas2770_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
        snd_soc_update_bits(codec, TAS2770_TDMConfigurationReg1,
                TAS2770_TDMConfigurationReg1_RXOFFSET51_Mask,
        (tdm_rx_start_slot << TAS2770_TDMConfigurationReg1_RXOFFSET51_Shift));
+
+       snd_soc_update_bits(codec, TAS2770_TDMConfigurationReg3,
+               TAS2770_TDMConfigurationReg3_RXSLOTLeft30_Mask,
+               (pTAS2770->mnLeftSlot << TAS2770_TDMConfigurationReg3_RXSLOTLeft30_Shift));
+       snd_soc_update_bits(codec, TAS2770_TDMConfigurationReg3,
+               TAS2770_TDMConfigurationReg3_RXSLOTRight74_Mask,
+       (pTAS2770->mnRightSlot << TAS2770_TDMConfigurationReg3_RXSLOTRight74_Shift));
+
+       value = snd_soc_read(codec, TAS2770_TDMConfigurationReg3);
+       dev_dbg(pTAS2770->dev, "slot value: 0x%x", value);
+
+       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);
+
+       ret = tas2770_set_slot(codec, slot_width);
+
        return ret;
 }
 
@@ -377,6 +459,7 @@ static struct snd_soc_dai_ops tas2770_dai_ops = {
        .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 |\
@@ -415,6 +498,7 @@ static int tas2770_codec_probe(struct snd_soc_codec *codec)
        struct tas2770_priv *pTAS2770 = snd_soc_codec_get_drvdata(codec);
 
        dev_err(pTAS2770->dev, "%s\n", __func__);
+       snd_soc_codec_init_regmap(codec, pTAS2770->regmap);
 
        return 0;
 }
@@ -425,11 +509,15 @@ static int tas2770_codec_remove(struct snd_soc_codec *codec)
 }
 
 static DECLARE_TLV_DB_SCALE(tas2770_digital_tlv, 1100, 50, 0);
+static DECLARE_TLV_DB_SCALE(tas2770_playback_volume, -10000, 50, 0);
 
 static const struct snd_kcontrol_new tas2770_snd_controls[] = {
        SOC_SINGLE_TLV("Amp Output Level", TAS2770_PlaybackConfigurationReg0,
                0, TAS2770_PlaybackConfigurationReg0_AmplifierLevel40_Mask, 0,
                tas2770_digital_tlv),
+       SOC_SINGLE_TLV("Playback Volume", TAS2770_PlaybackConfigurationReg2,
+               0, TAS2770_PlaybackConfigurationReg2_DVCPCM70_Mask, 1,
+               tas2770_playback_volume),
 };
 
 static struct snd_soc_codec_driver soc_codec_driver_tas2770 = {