Add support to IRQ
authorTracy Yi <tracy-yi@ti.com>
Wed, 25 Jul 2018 07:22:02 +0000 (15:22 +0800)
committerTracy Yi <tracy-yi@ti.com>
Wed, 25 Jul 2018 07:22:02 +0000 (15:22 +0800)
Signed-off-by: Tracy Yi <tracy-yi@ti.com>
tas2770-codec.c
tas2770-codec.h
tas2770-regmap.c
tas2770.h

index 3f64c20ff9f21501f01e9fb354eb0d248e454501..5e34d07ac7c76924f2753d9509db972e2ef78872 100644 (file)
@@ -137,27 +137,58 @@ static SOC_ENUM_SINGLE_DECL(
 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)
+static int tas2770_set_power_state(struct tas2770_priv *pTAS2770, int state)
 {
-       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+       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);
+               break;
+
+       case TAS2770_POWER_MUTE:
                snd_soc_update_bits(codec, TAS2770_PowerControl,
                        TAS2770_PowerControl_OperationalMode10_Mask,
                        TAS2770_PowerControl_OperationalMode10_Mute);
                break;
-       case SND_SOC_DAPM_PRE_PMD:
+
+       case TAS2770_POWER_SHUTDOWN:
                snd_soc_update_bits(codec, TAS2770_PowerControl,
                        TAS2770_PowerControl_OperationalMode10_Mask,
                        TAS2770_PowerControl_OperationalMode10_Shutdown);
                break;
 
+       default:
+               dev_err(pTAS2770->dev, "wrong power state setting %d\n", state);
+
        }
+
+       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 =
@@ -200,57 +231,41 @@ static int tas2770_mute(struct snd_soc_dai *dai, int mute)
 
        mutex_lock(&pTAS2770->codec_lock);
        if (mute) {
-               snd_soc_update_bits(codec, TAS2770_PowerControl,
-                       TAS2770_PowerControl_OperationalMode10_Mask,
-                       TAS2770_PowerControl_OperationalMode10_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);
        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 ret = 0;
-       int slot_width_tmp = 16;
-
-       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_RXWLEN32_16Bits);
-                       pTAS2770->mnCh_size = 16;
+                       /* If machine driver did not call set slot width */
                        if (pTAS2770->mnSlot_width == 0)
-                               slot_width_tmp = 16;
+                               tas2770_set_slot(pTAS2770->codec, 16);
                break;
        case SNDRV_PCM_FORMAT_S24_LE:
-                       snd_soc_update_bits(codec,
+                       snd_soc_update_bits(pTAS2770->codec,
                        TAS2770_TDMConfigurationReg2,
                        TAS2770_TDMConfigurationReg2_RXWLEN32_Mask,
                        TAS2770_TDMConfigurationReg2_RXWLEN32_24Bits);
-                       pTAS2770->mnCh_size = 24;
                        if (pTAS2770->mnSlot_width == 0)
-                               slot_width_tmp = 32;
+                               tas2770_set_slot(pTAS2770->codec, 32);
                break;
        case SNDRV_PCM_FORMAT_S32_LE:
-                       snd_soc_update_bits(codec,
+                       snd_soc_update_bits(pTAS2770->codec,
                        TAS2770_TDMConfigurationReg2,
                        TAS2770_TDMConfigurationReg2_RXWLEN32_Mask,
                        TAS2770_TDMConfigurationReg2_RXWLEN32_32Bits);
-                       pTAS2770->mnCh_size = 32;
                        if (pTAS2770->mnSlot_width == 0)
-                               slot_width_tmp = 32;
+                               tas2770_set_slot(pTAS2770->codec, 32);
                break;
 
        default:
@@ -258,63 +273,84 @@ static int tas2770_hw_params(struct snd_pcm_substream *substream,
                return -EINVAL;
        }
 
-       /* If machine driver did not call set slot width */
-       if (pTAS2770->mnSlot_width == 0)
-               tas2770_set_slot(codec, slot_width_tmp);
-
+       pTAS2770->mnCh_size = bitwidth;
        dev_dbg(pTAS2770->dev, "mnCh_size: %d\n", pTAS2770->mnCh_size);
-       snd_soc_update_bits(codec,
+
+       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(codec,
+       snd_soc_update_bits(pTAS2770->codec,
                TAS2770_TDMConfigurationReg6,
                TAS2770_TDMConfigurationReg6_ISNSTX_Mask |
                TAS2770_TDMConfigurationReg6_ISNSSLOT50_Mask,
                TAS2770_TDMConfigurationReg6_ISNSTX_Enable |
                pTAS2770->mnImon_slot_no);
 
-       dev_dbg(pTAS2770->dev, "%s, sample rate: %d\n", __func__,
-               params_rate(params));
-       switch (params_rate(params)) {
+       return 0;
+}
+
+static int tas2770_set_samplerate(struct tas2770_priv *pTAS2770, int samplerate)
+{
+       switch (samplerate) {
        case 48000:
-                       snd_soc_update_bits(codec,
+                       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,
+                       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,
+                       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(pTAS2770->codec,
+                               TAS2770_TDMConfigurationReg0,
+                               TAS2770_TDMConfigurationReg0_SAMPRATERAMP_Mask,
+                               TAS2770_TDMConfigurationReg0_SAMPRATERAMP_44_1KHz);
+                       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,
+                       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(pTAS2770->codec,
+                               TAS2770_TDMConfigurationReg0,
+                               TAS2770_TDMConfigurationReg0_SAMPRATERAMP_Mask,
+                               TAS2770_TDMConfigurationReg0_SAMPRATERAMP_44_1KHz);
+                       snd_soc_update_bits(pTAS2770->codec,
                                TAS2770_TDMConfigurationReg0,
                                TAS2770_TDMConfigurationReg0_SAMPRATE31_Mask,
                                TAS2770_TDMConfigurationReg0_SAMPRATE31_176_4_192kHz);
@@ -323,18 +359,42 @@ static int tas2770_hw_params(struct snd_pcm_substream *substream,
                        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;
-       int value = 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;
 
        switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
        case SND_SOC_DAIFMT_CBS_CFS:
@@ -359,7 +419,7 @@ static int tas2770_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
                ret = -EINVAL;
        }
 
-       snd_soc_update_bits(codec, TAS2770_TDMConfigurationReg1,
+       snd_soc_update_bits(pTAS2770->codec, TAS2770_TDMConfigurationReg1,
                TAS2770_TDMConfigurationReg1_RXEDGE_Mask,
                asi_cfg_1);
 
@@ -380,20 +440,37 @@ static int tas2770_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
                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));
 
-       snd_soc_update_bits(codec, TAS2770_TDMConfigurationReg3,
+       snd_soc_update_bits(pTAS2770->codec, TAS2770_TDMConfigurationReg3,
                TAS2770_TDMConfigurationReg3_RXSLOTLeft30_Mask,
                (pTAS2770->mnLeftSlot << TAS2770_TDMConfigurationReg3_RXSLOTLeft30_Shift));
-       snd_soc_update_bits(codec, TAS2770_TDMConfigurationReg3,
+       snd_soc_update_bits(pTAS2770->codec, TAS2770_TDMConfigurationReg3,
                TAS2770_TDMConfigurationReg3_RXSLOTRight74_Mask,
        (pTAS2770->mnRightSlot << TAS2770_TDMConfigurationReg3_RXSLOTRight74_Shift));
 
-       value = snd_soc_read(codec, TAS2770_TDMConfigurationReg3);
+       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;
 }
 
@@ -450,7 +527,9 @@ static int tas2770_set_dai_tdm_slot(struct snd_soc_dai *dai,
        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;
 }
@@ -498,7 +577,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);
+       pTAS2770->codec = codec;
 
        return 0;
 }
@@ -516,7 +595,7 @@ static const struct snd_kcontrol_new tas2770_snd_controls[] = {
                0, 0x14, 0,
                tas2770_digital_tlv),
        SOC_SINGLE_TLV("Playback Volume", TAS2770_PlaybackConfigurationReg2,
-               0, TAS2770_PlaybackConfigurationReg2_DVCPCM70_Mask, 1,
+               0, TAS2770_PlaybackConfigurationReg2_VOLMAX, 1,
                tas2770_playback_volume),
 };
 
@@ -556,6 +635,39 @@ int tas2770_deregister_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");
index 5cb70797f3bc13262c3fe4ac4040bf05105f3119..3c7bccd3bb740a5225c32e8e52ae8562d0b65803 100644 (file)
@@ -26,6 +26,6 @@
 
 int tas2770_register_codec(struct tas2770_priv *pTAS2770);
 int tas2770_deregister_codec(struct tas2770_priv *pTAS2770);
-int tas2770_LoadConfig(struct tas2770_priv *pTAS2770, bool bPowerOn);
+void tas2770_LoadConfig(struct tas2770_priv *pTAS2770);
 
 #endif /* _TAS2770_CODEC_H */
index 402d97320e2a5e09e98818143b26b0fdab7b61d4..e2b65b94bddbf97440a2d6d652fbbbe78442d99d 100644 (file)
@@ -129,9 +129,6 @@ void tas2770_enableIRQ(struct tas2770_priv *pTAS2770, bool enable)
                schedule_delayed_work(&pTAS2770->irq_work, msecs_to_jiffies(10));
                pTAS2770->mbIRQEnable = true;
        } else {
-               if (!pTAS2770->mbIRQEnable)
-                       return;
-
                if (gpio_is_valid(pTAS2770->mnIRQGPIO))
                        disable_irq_nosync(pTAS2770->mnIRQ);
                pTAS2770->mbIRQEnable = false;
@@ -142,7 +139,11 @@ static void irq_work_routine(struct work_struct *work)
 {
        struct tas2770_priv *pTAS2770 =
                container_of(work, struct tas2770_priv, irq_work.work);
+       unsigned int nDevInt1Status = 0, nDevInt2Status = 0;
+       int nCounter = 2;
+       int nResult = 0;
 
+       dev_info(pTAS2770->dev, "%s\n", __func__);
 #ifdef CONFIG_TAS2770_CODEC
        mutex_lock(&pTAS2770->codec_lock);
 #endif
@@ -152,11 +153,109 @@ static void irq_work_routine(struct work_struct *work)
                goto end;
        }
 
-       if (!pTAS2770->mbPowerUp) {
+       if (pTAS2770->mnPowerState == TAS2770_POWER_SHUTDOWN) {
                dev_info(pTAS2770->dev, "%s, device not powered\n", __func__);
                goto end;
        }
 
+       nResult = regmap_write(pTAS2770->regmap, TAS2770_InterruptMaskReg0,
+                               TAS2770_InterruptMaskReg0_Disable);
+       nResult = regmap_write(pTAS2770->regmap, TAS2770_InterruptMaskReg1,
+                               TAS2770_InterruptMaskReg1_Disable);
+
+       if (nResult < 0)
+               goto reload;
+
+       nResult = regmap_read(pTAS2770->regmap, TAS2770_LatchedInterruptReg0, &nDevInt1Status);
+       if (nResult >= 0)
+               nResult = regmap_read(pTAS2770->regmap, TAS2770_LatchedInterruptReg1, &nDevInt2Status);
+       else
+               goto reload;
+
+       dev_dbg(pTAS2770->dev, "IRQ status : 0x%x, 0x%x\n",
+                       nDevInt1Status, nDevInt2Status);
+
+       if (((nDevInt1Status & 0x3) != 0) || ((nDevInt2Status & 0x0f) != 0)) {
+               /* in case of INT_OC, INT_OT, INT_OVLT, INT_UVLT, INT_BO */
+
+               if (nDevInt1Status & TAS2770_LatchedInterruptReg0_OCEFlagSticky_Interrupt) {
+                       pTAS2770->mnErrCode |= ERROR_OVER_CURRENT;
+                       dev_err(pTAS2770->dev, "SPK over current!\n");
+               } else
+                       pTAS2770->mnErrCode &= ~ERROR_OVER_CURRENT;
+
+               if (nDevInt1Status & TAS2770_LatchedInterruptReg0_OTEFlagSticky_Interrupt) {
+                       pTAS2770->mnErrCode |= ERROR_DIE_OVERTEMP;
+                       dev_err(pTAS2770->dev, "die over temperature!\n");
+               } else
+                       pTAS2770->mnErrCode &= ~ERROR_DIE_OVERTEMP;
+
+               if (nDevInt2Status & TAS2770_LatchedInterruptReg1_VBATOVLOSticky_Interrupt) {
+                       pTAS2770->mnErrCode |= ERROR_OVER_VOLTAGE;
+                       dev_err(pTAS2770->dev, "SPK over voltage!\n");
+               } else
+                       pTAS2770->mnErrCode &= ~ERROR_UNDER_VOLTAGE;
+
+               if (nDevInt2Status & TAS2770_LatchedInterruptReg1_VBATUVLOSticky_Interrupt) {
+                       pTAS2770->mnErrCode |= ERROR_UNDER_VOLTAGE;
+                       dev_err(pTAS2770->dev, "SPK under voltage!\n");
+               } else
+                       pTAS2770->mnErrCode &= ~ERROR_UNDER_VOLTAGE;
+
+               if (nDevInt2Status & TAS2770_LatchedInterruptReg1_BrownOutFlagSticky_Interrupt) {
+                       pTAS2770->mnErrCode |= ERROR_BROWNOUT;
+                       dev_err(pTAS2770->dev, "brownout!\n");
+               } else
+                       pTAS2770->mnErrCode &= ~ERROR_BROWNOUT;
+
+               goto reload;
+       } else {
+               nCounter = 2;
+
+               while (nCounter > 0) {
+                       nResult = regmap_read(pTAS2770->regmap, TAS2770_PowerControl, &nDevInt1Status);
+                       if (nResult < 0)
+                               goto reload;
+
+                       if ((nDevInt1Status & TAS2770_PowerControl_OperationalMode10_Mask)
+                               != TAS2770_PowerControl_OperationalMode10_Shutdown)
+                               break;
+
+                       nCounter--;
+                       if (nCounter > 0) {
+                               /* in case check pow status just after power on TAS2770 */
+                               dev_dbg(pTAS2770->dev, "PowSts B: 0x%x, check again after 10ms\n",
+                                       nDevInt1Status);
+                               msleep(10);
+                       }
+               }
+
+               if ((nDevInt1Status & TAS2770_PowerControl_OperationalMode10_Mask)
+                       == TAS2770_PowerControl_OperationalMode10_Shutdown) {
+                       dev_err(pTAS2770->dev, "%s, Critical ERROR REG[0x%x] = 0x%x\n",
+                               __func__,
+                               TAS2770_PowerControl,
+                               nDevInt1Status);
+                       pTAS2770->mnErrCode |= ERROR_CLASSD_PWR;
+                       goto reload;
+               }
+               pTAS2770->mnErrCode &= ~ERROR_CLASSD_PWR;
+       }
+
+       nResult = regmap_write(pTAS2770->regmap, TAS2770_InterruptMaskReg0, 0xfc);
+       if (nResult < 0)
+               goto reload;
+
+       nResult = regmap_write(pTAS2770->regmap, TAS2770_InterruptMaskReg1, 0xb1);
+       if (nResult < 0)
+               goto reload;
+
+       goto end;
+
+reload:
+       /* hardware reset and reload */
+       tas2770_LoadConfig(pTAS2770);
+
 end:
 #ifdef CONFIG_TAS2770_CODEC
        mutex_unlock(&pTAS2770->codec_lock);
@@ -168,7 +267,7 @@ static enum hrtimer_restart timer_func(struct hrtimer *timer)
        struct tas2770_priv *pTAS2770 = container_of(timer,
                struct tas2770_priv, mtimer);
 
-       if (pTAS2770->mbPowerUp) {
+       if (pTAS2770->mnPowerState != TAS2770_POWER_SHUTDOWN) {
                if (!delayed_work_pending(&pTAS2770->irq_work))
                        schedule_delayed_work(&pTAS2770->irq_work,
                                msecs_to_jiffies(20));
@@ -215,13 +314,12 @@ static int tas2770_runtime_resume(struct tas2770_priv *pTAS2770)
 {
        dev_dbg(pTAS2770->dev, "%s\n", __func__);
 
-       if (pTAS2770->mbPowerUp) {
+       if (pTAS2770->mnPowerState != TAS2770_POWER_SHUTDOWN) {
                if (!hrtimer_active(&pTAS2770->mtimer)) {
                        hrtimer_start(&pTAS2770->mtimer,
                                ns_to_ktime((u64)CHECK_PERIOD * NSEC_PER_MSEC),
                                HRTIMER_MODE_REL);
                }
-
        }
 
        pTAS2770->mbRuntimeSuspend = false;
@@ -351,7 +449,7 @@ static int tas2770_i2c_probe(struct i2c_client *client,
                dev_dbg(pTAS2770->dev, "irq = %d\n", pTAS2770->mnIRQ);
                nResult = request_threaded_irq(pTAS2770->mnIRQ,
                                        tas2770_irq_handler, NULL,
-                                       IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
+                                       IRQF_TRIGGER_LOW | IRQF_ONESHOT,
                                        client->name, pTAS2770);
                if (nResult < 0) {
                        dev_err(pTAS2770->dev,
index 6545830a426a5d386f88e8ff48da2fc1f8af8673..8aaa6cff2b72e84707a8455a5edaf32d2d52ff89 100644 (file)
--- a/tas2770.h
+++ b/tas2770.h
@@ -67,6 +67,7 @@
     /* Playback Configuration Reg2 */
 #define TAS2770_PlaybackConfigurationReg2  TAS2770_REG(0X0, 0x05)
 #define TAS2770_PlaybackConfigurationReg2_DVCPCM70_Mask  (0xff << 0)
+#define TAS2770_PlaybackConfigurationReg2_VOLMAX (0xc9 << 0)
 
     /* Playback Configuration Reg3 */
 #define TAS2770_PlaybackConfigurationReg3  TAS2770_REG(0X0, 0x06)
 #define TAS2770_InterruptMaskReg0_OTEINTMASK_Mask  (0x1 << 0)
 #define TAS2770_InterruptMaskReg0_OTEINTMASK_Unmask  (0x0 << 0)
 #define TAS2770_InterruptMaskReg0_OTEINTMASK_Disable  (0x1 << 0)
+#define TAS2770_InterruptMaskReg0_Disable 0xff
 
     /* Interrupt Mask Reg1 */
 #define TAS2770_InterruptMaskReg1  TAS2770_REG(0X0, 0x21)
 #define TAS2770_InterruptMaskReg1_PDMClockErrorINTMASK_Mask  (0x1 << 0)
 #define TAS2770_InterruptMaskReg1_PDMClockErrorINTMASK_Unmask  (0x0 << 0)
 #define TAS2770_InterruptMaskReg1_PDMClockErrorINTMASK_Disable  (0x1 << 0)
+#define TAS2770_InterruptMaskReg1_Disable 0xff
 
     /* Live-Interrupt Reg0 */
 #define TAS2770_LiveInterruptReg0  TAS2770_REG(0X0, 0x22)
@@ -675,6 +678,9 @@ TAS2770_InterruptConfiguration_PININTConfig10_Assert2msOnLatchedInterrupts \
 #define TAS2770_Book  TAS2770_REG(0X0, 0x7F)
 #define TAS2770_Book_Book70_Mask  (0xff << 0)
 
+#define TAS2770_POWER_ACTIVE 0
+#define TAS2770_POWER_MUTE 1
+#define TAS2770_POWER_SHUTDOWN 2
 
 #define TAS2770_RegisterCount  55
 
@@ -683,17 +689,12 @@ TAS2770_InterruptConfiguration_PININTConfig10_Assert2msOnLatchedInterrupts \
 #define ERROR_DEVA_I2C_COMM 0x0000000
 #define ERROR_DEVB_I2C_COMM 0x0000000
 #define ERROR_PRAM_CRCCHK   0x0000000
-#define ERROR_YRAM_CRCCHK   0x0000001
-#define ERROR_CLK_DET2      0x0000002
-#define ERROR_CLK_DET1      0x0000004
-#define ERROR_CLK_LOST      0x0000008
+#define ERROR_OVER_CURRENT  0x0000001
+#define ERROR_DIE_OVERTEMP  0x0000002
+#define ERROR_OVER_VOLTAGE  0x0000004
+#define ERROR_UNDER_VOLTAGE 0x0000008
 #define ERROR_BROWNOUT      0x0000010
-#define ERROR_DIE_OVERTEMP  0x0000020
-#define ERROR_CLK_HALT      0x0000040
-#define ERROR_UNDER_VOLTAGE 0x0000080
-#define ERROR_OVER_CURRENT  0x0000100
-#define ERROR_CLASSD_PWR    0x0000200
-#define ERROR_FAILSAFE      0x4000000
+#define ERROR_CLASSD_PWR    0x0000020
 
 struct tas2770_register {
        int book;
@@ -709,12 +710,13 @@ struct tas2770_dai_cfg {
 struct tas2770_priv {
        struct device *dev;
        struct regmap *regmap;
+       struct snd_soc_codec *codec;
        struct mutex dev_lock;
        struct delayed_work irq_work;
        struct hrtimer mtimer;
        int mnClkin;
        int mnClkid;
-       bool mbPowerUp;
+       int mnPowerState;
        int mnCurrentBook;
        int mnCurrentPage;
        int mnLoad;
@@ -726,7 +728,6 @@ struct tas2770_priv {
        int mnSamplingRate;
        int mnFrameSize;
        int mnPLL;
-       int mnPPG;
        int mnLeftSlot;
        int mnRightSlot;
        int mnCh_size;