merge updates from TAS2557 dual mono
authorPeter Li <peter-li@ti.com>
Wed, 8 Mar 2017 15:18:21 +0000 (23:18 +0800)
committerPeter Li <peter-li@ti.com>
Wed, 8 Mar 2017 15:18:21 +0000 (23:18 +0800)
dts.readme
tas2557-codec.c
tas2557-codec.h
tas2557-core.c
tas2557-core.h
tas2557-misc.c
tas2557-misc.h
tas2557-regmap.c
tas2557.h
tiload.c
tiload.h

index b936a9971b5ed087ed11c890dacc3d28c48695f3..641ebdb1bfa9e6365afe54ecc78114d3c9ec6052 100755 (executable)
@@ -1,10 +1,11 @@
 example for dts:
-               
+
                tas2557@4c {
+                       #sound-dai-cells = <1>;
                        compatible = "ti,tas2557";
-                       reg = <0x4c>;                   
+                       reg = <0x4c>;
                        ti,cdc-reset-gpio = <&msmgpio 73 0>;
-                       ti,channel = <0>;   /* 0, left channel; 1, right channel */
-                       ti,load = <0>;   /* 0, 8Ohm; 1, 6Ohm; 2, 4Ohm */
+                       ti,irq-gpio = <&msmgpio 59 0>;
+                       ti,i2s-bits = <16>;   /* support 16, 24, 32 */
                        status = "ok";
                };
\ No newline at end of file
index 885d2f687177e8d1b04aa12210db33ef3f83fdeb..a22a8e0d9da9a968a76a04205039f038b9b0ac89 100755 (executable)
@@ -3,17 +3,13 @@
 ** 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 
+** 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.
 **
-** You should have received a copy of the GNU General Public License along with
-** this program; if not, write to the Free Software Foundation, Inc., 51 Franklin
-** Street, Fifth Floor, Boston, MA 02110-1301, USA.
-**
 ** File:
 **     tas2557-codec.c
 **
@@ -41,7 +37,7 @@
 #include <linux/slab.h>
 #include <linux/syscalls.h>
 #include <linux/fcntl.h>
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
@@ -68,12 +64,9 @@ static unsigned int tas2557_codec_read(struct snd_soc_codec *pCodec,
        int ret = 0;
        unsigned int Value = 0;
 
-       mutex_lock(&pTAS2557->codec_lock);
        ret = pTAS2557->read(pTAS2557, nRegister, &Value);
-       mutex_unlock(&pTAS2557->codec_lock);
-       
        if (ret < 0) {
-               dev_err(pTAS2557->dev, "%s, %d, ERROR happen=%d\n", __FUNCTION__,
+               dev_err(pTAS2557->dev, "%s, %d, ERROR happen=%d\n", __func__,
                        __LINE__, ret);
                return 0;
        } else
@@ -85,9 +78,8 @@ static int tas2557_codec_write(struct snd_soc_codec *pCodec, unsigned int nRegis
 {
        struct tas2557_priv *pTAS2557 = snd_soc_codec_get_drvdata(pCodec);
        int ret = 0;
-       mutex_lock(&pTAS2557->codec_lock);
+
        ret = pTAS2557->write(pTAS2557, nRegister, nValue);
-       mutex_unlock(&pTAS2557->codec_lock);
        
        return ret;
 }
@@ -121,9 +113,8 @@ static int tas2557_startup(struct snd_pcm_substream *substream,
 {
        struct snd_soc_codec *codec = dai->codec;
        struct tas2557_priv *pTAS2557 = snd_soc_codec_get_drvdata(codec);
-       
-       dev_dbg(pTAS2557->dev, "%s\n", __func__);
 
+       dev_dbg(pTAS2557->dev, "%s\n", __func__);
        return 0;
 }
 
@@ -140,12 +131,9 @@ static int tas2557_mute(struct snd_soc_dai *dai, int mute)
 {
        struct snd_soc_codec *codec = dai->codec;
        struct tas2557_priv *pTAS2557 = snd_soc_codec_get_drvdata(codec);
-       
+
        dev_dbg(pTAS2557->dev, "%s\n", __func__);
-       mutex_lock(&pTAS2557->codec_lock);
        tas2557_enable(pTAS2557, !mute);
-       mutex_unlock(&pTAS2557->codec_lock);
-       
        return 0;
 }
 
@@ -166,12 +154,10 @@ static int tas2557_hw_params(struct snd_pcm_substream *pSubstream,
        struct snd_soc_codec *pCodec = pDAI->codec;
        struct tas2557_priv *pTAS2557 = snd_soc_codec_get_drvdata(pCodec);
 
-       dev_dbg(pCodec->dev, "%s\n", __func__);
-       
-       mutex_lock(&pTAS2557->codec_lock);
+       dev_dbg(pTAS2557->dev, "%s\n", __func__);
+/* do bit rate setting during platform data */
+/* tas2557_set_bit_rate(pTAS2557, channel_both, snd_pcm_format_width(params_format(pParams))); */
        tas2557_set_sampling_rate(pTAS2557, params_rate(pParams));
-       mutex_unlock(&pTAS2557->codec_lock);
-
        return 0;
 }
 
@@ -179,9 +165,8 @@ static int tas2557_set_dai_fmt(struct snd_soc_dai *pDAI, unsigned int nFormat)
 {
        struct snd_soc_codec *codec = pDAI->codec;
        struct tas2557_priv *pTAS2557 = snd_soc_codec_get_drvdata(codec);
-       
+
        dev_dbg(pTAS2557->dev, "%s\n", __func__);
-       
        return 0;
 }
 
@@ -190,9 +175,8 @@ static int tas2557_prepare(struct snd_pcm_substream *pSubstream,
 {
        struct snd_soc_codec *codec = pDAI->codec;
        struct tas2557_priv *pTAS2557 = snd_soc_codec_get_drvdata(codec);
-       
+
        dev_dbg(pTAS2557->dev, "%s\n", __func__);
-       
        return 0;
 }
 
@@ -200,9 +184,8 @@ static int tas2557_set_bias_level(struct snd_soc_codec *pCodec,
        enum snd_soc_bias_level eLevel)
 {
        struct tas2557_priv *pTAS2557 = snd_soc_codec_get_drvdata(pCodec);
-       
-       dev_dbg(pTAS2557->dev, "%s: %d\n", __func__, eLevel);
 
+       dev_dbg(pTAS2557->dev, "%s: %d\n", __func__, eLevel);
        return 0;
 }
 
@@ -210,8 +193,7 @@ static int tas2557_codec_probe(struct snd_soc_codec *pCodec)
 {
        struct tas2557_priv *pTAS2557 = snd_soc_codec_get_drvdata(pCodec);
 
-       dev_info(pTAS2557->dev, "%s\n", __func__);
-
+       dev_dbg(pTAS2557->dev, "%s\n", __func__);
        return 0;
 }
 
@@ -272,8 +254,6 @@ static int tas2557_get_reg_value(struct snd_kcontrol *pKcontrol,
        unsigned int reg;
        unsigned int nValue;
 
-       mutex_lock(&pTAS2557->codec_lock);      
-       
        if (TAS2557_REG_IS_VALID(register_addr.book,
                        register_addr.page, register_addr.reg)) {
                reg = TAS2557_REG((unsigned int) register_addr.book,
@@ -289,8 +269,7 @@ static int tas2557_get_reg_value(struct snd_kcontrol *pKcontrol,
        dev_dbg(pTAS2557->dev, "%s: Read [%d, %d, %d] = %ld\n", __func__,
                register_addr.book, register_addr.page, register_addr.reg,
                pUcontrol->value.integer.value[0]);
-               
-       mutex_unlock(&pTAS2557->codec_lock);
+
        return 0;
 }
 
@@ -305,8 +284,6 @@ static int tas2557_put_reg_value(struct snd_kcontrol *pKcontrol,
        struct tas2557_priv *pTAS2557 = snd_soc_codec_get_drvdata(codec);
        unsigned int reg;
 
-       mutex_lock(&pTAS2557->codec_lock);
-       
        if (TAS2557_REG_IS_VALID(register_addr.book,
                        register_addr.page, register_addr.reg)) {
                reg = TAS2557_REG((unsigned int) register_addr.book,
@@ -321,7 +298,6 @@ static int tas2557_put_reg_value(struct snd_kcontrol *pKcontrol,
                register_addr.book, register_addr.page, register_addr.reg,
                pUcontrol->value.integer.value[0]);
 
-       mutex_unlock(&pTAS2557->codec_lock);                    
        return 0;
 }
 
@@ -335,13 +311,9 @@ static int tas2557_power_ctrl_get(struct snd_kcontrol *pKcontrol,
 #endif
        struct tas2557_priv *pTAS2557 = snd_soc_codec_get_drvdata(codec);
 
-       mutex_lock(&pTAS2557->codec_lock);      
-       
-       pValue->value.integer.value[0] = pTAS2557->mnPowerCtrl;
+       pValue->value.integer.value[0] = pTAS2557->mbPowerUp;
        dev_dbg(pTAS2557->dev, "tas2557_power_ctrl_get = %d\n",
-               pTAS2557->mnPowerCtrl);
-               
-       mutex_unlock(&pTAS2557->codec_lock);                    
+               pTAS2557->mbPowerUp);
        return 0;
 }
 
@@ -355,18 +327,11 @@ static int tas2557_power_ctrl_put(struct snd_kcontrol *pKcontrol,
 #endif
        struct tas2557_priv *pTAS2557 = snd_soc_codec_get_drvdata(codec);
 
-       mutex_lock(&pTAS2557->codec_lock);      
-       pTAS2557->mnPowerCtrl = pValue->value.integer.value[0];
+       int nPowerOn = pValue->value.integer.value[0];
 
-       dev_dbg(pTAS2557->dev, "tas2557_power_ctrl_put = %d\n",
-               pTAS2557->mnPowerCtrl);
+       dev_dbg(pTAS2557->dev, "tas2557_power_ctrl_put = %d\n", nPowerOn);
 
-       if (pTAS2557->mnPowerCtrl == 1)
-               tas2557_enable(pTAS2557, true);
-       if (pTAS2557->mnPowerCtrl == 0)
-               tas2557_enable(pTAS2557, false);
-               
-       mutex_unlock(&pTAS2557->codec_lock);
+       tas2557_enable(pTAS2557, (nPowerOn != 0));
        return 0;
 }
 
@@ -379,19 +344,12 @@ static int tas2557_fs_get(struct snd_kcontrol *pKcontrol,
        struct snd_soc_codec *codec = snd_kcontrol_chip(pKcontrol);
 #endif
        struct tas2557_priv *pTAS2557 = snd_soc_codec_get_drvdata(codec);
-
        int nFS = 48000;
 
-       mutex_lock(&pTAS2557->codec_lock);
-       
        if (pTAS2557->mpFirmware->mnConfigurations)
                nFS = pTAS2557->mpFirmware->mpConfigurations[pTAS2557->mnCurrentConfiguration].mnSamplingRate;
-       
        pValue->value.integer.value[0] = nFS;
-       
-       mutex_unlock(&pTAS2557->codec_lock);    
-       
-       dev_info(pTAS2557->dev, "tas2557_fs_get = %d\n", nFS);
+       dev_dbg(pTAS2557->dev, "tas2557_fs_get = %d\n", nFS);
        return 0;
 }
 
@@ -406,13 +364,9 @@ static int tas2557_fs_put(struct snd_kcontrol *pKcontrol,
        struct tas2557_priv *pTAS2557 = snd_soc_codec_get_drvdata(codec);
        int ret = 0;
        int nFS = pValue->value.integer.value[0];
-       
+
        dev_info(pTAS2557->dev, "tas2557_fs_put = %d\n", nFS);
-       
-       mutex_lock(&pTAS2557->codec_lock);      
        ret = tas2557_set_sampling_rate(pTAS2557, nFS);
-       
-       mutex_unlock(&pTAS2557->codec_lock);    
        return ret;
 }
 
@@ -425,11 +379,10 @@ static int tas2557_program_get(struct snd_kcontrol *pKcontrol,
        struct snd_soc_codec *codec = snd_kcontrol_chip(pKcontrol);
 #endif
        struct tas2557_priv *pTAS2557 = snd_soc_codec_get_drvdata(codec);
-       mutex_lock(&pTAS2557->codec_lock);      
+
        pValue->value.integer.value[0] = pTAS2557->mnCurrentProgram;
        dev_dbg(pTAS2557->dev, "tas2557_program_get = %d\n",
                pTAS2557->mnCurrentProgram);
-       mutex_unlock(&pTAS2557->codec_lock);                    
        return 0;
 }
 
@@ -444,9 +397,8 @@ static int tas2557_program_put(struct snd_kcontrol *pKcontrol,
        struct tas2557_priv *pTAS2557 = snd_soc_codec_get_drvdata(codec);
        unsigned int nProgram = pValue->value.integer.value[0];
        int ret = 0;
-       mutex_lock(&pTAS2557->codec_lock);      
-       ret = tas2557_set_program(pTAS2557, nProgram);
-       mutex_unlock(&pTAS2557->codec_lock);    
+
+       ret = tas2557_set_program(pTAS2557, nProgram, -1);
        return ret;
 }
 
@@ -460,11 +412,9 @@ static int tas2557_configuration_get(struct snd_kcontrol *pKcontrol,
 #endif
        struct tas2557_priv *pTAS2557 = snd_soc_codec_get_drvdata(codec);
 
-       mutex_lock(&pTAS2557->codec_lock);      
        pValue->value.integer.value[0] = pTAS2557->mnCurrentConfiguration;
        dev_dbg(pTAS2557->dev, "tas2557_configuration_get = %d\n",
                pTAS2557->mnCurrentConfiguration);
-       mutex_unlock(&pTAS2557->codec_lock);                    
        return 0;
 }
 
@@ -480,9 +430,7 @@ static int tas2557_configuration_put(struct snd_kcontrol *pKcontrol,
        unsigned int nConfiguration = pValue->value.integer.value[0];
        int ret = 0;
 
-       mutex_lock(&pTAS2557->codec_lock);      
        ret = tas2557_set_config(pTAS2557, nConfiguration);
-       mutex_unlock(&pTAS2557->codec_lock);    
        return ret;
 }
 
@@ -496,12 +444,10 @@ static int tas2557_calibration_get(struct snd_kcontrol *pKcontrol,
 #endif
        struct tas2557_priv *pTAS2557 = snd_soc_codec_get_drvdata(codec);
 
-       mutex_lock(&pTAS2557->codec_lock);      
        pValue->value.integer.value[0] = pTAS2557->mnCurrentCalibration;
        dev_info(pTAS2557->dev,
                "tas2557_calibration_get = %d\n",
                pTAS2557->mnCurrentCalibration);
-       mutex_unlock(&pTAS2557->codec_lock);                    
        return 0;
 }
 
@@ -517,56 +463,20 @@ static int tas2557_calibration_put(struct snd_kcontrol *pKcontrol,
        unsigned int nCalibration = pValue->value.integer.value[0];
        int ret = 0;
 
-       mutex_lock(&pTAS2557->codec_lock);              
        ret = tas2557_set_calibration(pTAS2557, nCalibration);
-       mutex_unlock(&pTAS2557->codec_lock);    
        
        return ret;
 }
 
+
 /*
  * DAC digital volumes. From 0 to 15 dB in 1 dB steps
  */
 static DECLARE_TLV_DB_SCALE(dac_tlv, 0, 100, 0);
 
-static const char *channel_text[] = {"Left Channel","Right Channel"};
 
-static const struct soc_enum channel_enum[] = {
-       SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(channel_text),channel_text),
-};
-
-static int tas2557_get_channel(struct snd_kcontrol *pKcontrol,
-                       struct snd_ctl_elem_value *pUcontrol)
-{
-#ifdef KCONTROL_CODEC
-       struct snd_soc_codec *pCodec = snd_soc_kcontrol_codec(pKcontrol);
-#else
-       struct snd_soc_codec *pCodec = snd_kcontrol_chip(pKcontrol);
-#endif
-       struct tas2557_priv *pTAS2557 = snd_soc_codec_get_drvdata(pCodec);
 
-       pUcontrol->value.integer.value[0] = pTAS2557->mnDevChl;
        
-       return 0;
-}
-
-static int tas2557_set_channel(struct snd_kcontrol *pKcontrol,
-                       struct snd_ctl_elem_value *pUcontrol)
-{
-#ifdef KCONTROL_CODEC
-       struct snd_soc_codec *pCodec = snd_soc_kcontrol_codec(pKcontrol);
-#else
-       struct snd_soc_codec *pCodec = snd_kcontrol_chip(pKcontrol);
-#endif 
-       struct tas2557_priv *pTAS2557 = snd_soc_codec_get_drvdata(pCodec);
-
-       pTAS2557->mnDevChl = pUcontrol->value.integer.value[0];
-       dev_dbg(pTAS2557->dev,"%s:channel = 0x%x\n",__func__,
-                       pTAS2557->mnDevChl);
-
-       tas2557_setChannel(pTAS2557, pTAS2557->mnDevChl);
-       return 0;
-}
 
 static const struct snd_kcontrol_new tas2557_snd_controls[] = {
        SOC_SINGLE_TLV("DAC Playback Volume", TAS2557_SPK_CTRL_REG, 3, 0x0f, 0,
@@ -585,8 +495,6 @@ static const struct snd_kcontrol_new tas2557_snd_controls[] = {
                tas2557_fs_get, tas2557_fs_put),
        SOC_SINGLE_EXT("Calibration", SND_SOC_NOPM, 0, 0x00FF, 0,
                tas2557_calibration_get, tas2557_calibration_put),
-       SOC_ENUM_EXT("TAS2557 Channel",channel_enum[0],
-                     tas2557_get_channel,tas2557_set_channel),         
 };
 
 static struct snd_soc_codec_driver soc_codec_driver_tas2557 = {
@@ -596,7 +504,6 @@ static struct snd_soc_codec_driver soc_codec_driver_tas2557 = {
        .write = tas2557_codec_write,
        .set_bias_level = tas2557_set_bias_level,
        .idle_bias_off = true,
-       //.ignore_pmdown_time = true,
        .controls = tas2557_snd_controls,
        .num_controls = ARRAY_SIZE(tas2557_snd_controls),
        .dapm_widgets = tas2557_dapm_widgets,
@@ -616,7 +523,7 @@ static struct snd_soc_dai_ops tas2557_dai_ops = {
 };
 
 #define TAS2557_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
-             SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
+       SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
 static struct snd_soc_dai_driver tas2557_dai_driver[] = {
        {
                .name = "tas2557 ASI1",
@@ -663,23 +570,20 @@ int tas2557_register_codec(struct tas2557_priv *pTAS2557)
 {
        int nResult = 0;
 
-       dev_info(pTAS2557->dev, "%s, enter\n", __FUNCTION__);
-         
-       nResult = snd_soc_register_codec(pTAS2557->dev, 
+       dev_info(pTAS2557->dev, "%s, enter\n", __func__);
+       nResult = snd_soc_register_codec(pTAS2557->dev,
                &soc_codec_driver_tas2557,
                tas2557_dai_driver, ARRAY_SIZE(tas2557_dai_driver));
-               
        return nResult;
 }
 
 int tas2557_deregister_codec(struct tas2557_priv *pTAS2557)
 {
        snd_soc_unregister_codec(pTAS2557->dev);
-               
        return 0;
 }
 
 MODULE_AUTHOR("Texas Instruments Inc.");
 MODULE_DESCRIPTION("TAS2557 ALSA SOC Smart Amplifier driver");
-MODULE_LICENSE("GPLv2");
+MODULE_LICENSE("GPL v2");
 #endif
index aa65bb9c5da64db0ec0db4ad7c6ca3656fa7f9e7..8e20270c6b92cc684b748a33d38940b3c880a41b 100755 (executable)
@@ -3,17 +3,13 @@
 ** 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 
+** 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.
 **
-** You should have received a copy of the GNU General Public License along with
-** this program; if not, write to the Free Software Foundation, Inc., 51 Franklin
-** Street, Fifth Floor, Boston, MA 02110-1301, USA.
-**
 ** File:
 **     tas2557-codec.h
 **
@@ -28,7 +24,7 @@
 
 #include "tas2557.h"
 
-extern int tas2557_register_codec(struct tas2557_priv *pTAS2557);
-extern int tas2557_deregister_codec(struct tas2557_priv *pTAS2557);    
+int tas2557_register_codec(struct tas2557_priv *pTAS2557);
+int tas2557_deregister_codec(struct tas2557_priv *pTAS2557);
 
 #endif /* _TAS2557_CODEC_H */
index 2f025b84ee40df9004027577d15658ca5ace9429..23817333cfb27eca3c6a8db781f8af9aa73555f6 100755 (executable)
@@ -3,17 +3,13 @@
 ** 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 
+** 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.
 **
-** You should have received a copy of the GNU General Public License along with
-** this program; if not, write to the Free Software Foundation, Inc., 51 Franklin
-** Street, Fifth Floor, Boston, MA 02110-1301, USA.
-**
 ** File:
 **     tas2557-core.c
 **
 #include <linux/slab.h>
 #include <linux/syscalls.h>
 #include <linux/fcntl.h>
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
+#include <linux/crc8.h>
 
 #include "tas2557.h"
 #include "tas2557-core.h"
 
-#define TAS2557_CAL_NAME    "/data/tas2557_cal.bin"
+#define PPC_DRIVER_VERSION 0x00000200
+#define TAS2557_CAL_NAME "/data/tas2557_cal.bin"
 
-//set default PLL CLKIN to GPI2 (MCLK) = 0x00
-#define TAS2557_DEFAULT_PLL_CLKIN 0x00
+static int tas2557_load_calibration(struct tas2557_priv *pTAS2557, char *pFileName);
+static int tas2557_load_data(struct tas2557_priv *pTAS2557, struct TData *pData, unsigned int nType);
+static void tas2557_clear_firmware(struct TFirmware *pFirmware);
+static int tas2557_load_block(struct tas2557_priv *pTAS2557, struct TBlock *pBlock);
+static int tas2557_load_configuration(struct tas2557_priv *pTAS2557, unsigned int nConfiguration, bool bLoadSame);
 
-static void tas2557_load_calibration(struct tas2557_priv *pTAS2557,
-       char *pFileName);
-static void tas2557_load_data(struct tas2557_priv *pTAS2557, struct TData * pData,
-       unsigned int nType);
-static void tas2557_load_block(struct tas2557_priv *pTAS2557, struct TBlock * pBlock);
-static void tas2557_load_configuration(struct tas2557_priv *pTAS2557,
-       unsigned int nConfiguration, bool bLoadSame);
-       
 #define TAS2557_UDELAY 0xFFFFFFFE
 #define TAS2557_MDELAY 0xFFFFFFFD
 
-#define FW_ERR_HEADER -1
-#define FW_ERR_SIZE -2
-
 #define TAS2557_BLOCK_PLL                              0x00
 #define TAS2557_BLOCK_PGM_ALL                  0x0d
 #define TAS2557_BLOCK_PGM_DEV_A                        0x01
@@ -73,71 +63,68 @@ static void tas2557_load_configuration(struct tas2557_priv *pTAS2557,
 #define TAS2557_BLOCK_CFG_PRE_DEV_B            0x0b
 #define TAS2557_BLOCK_CFG_POST                 0x05
 #define TAS2557_BLOCK_CFG_POST_POWER   0x06
-#define TAS2557_BLOCK_CFG_CAL_A                        0x10
-#define TAS2557_BLOCK_CFG_CAL_B                        0x20
-
-static unsigned int p_tas2557_SA_chl_left_data[] =
-{
-       TAS2557_SA_CHL_CTRL_REG, 0x08, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0xFFFFFFFF, 0xFFFFFFFF
-};
 
-static unsigned int p_tas2557_SA_chl_right_data[] =
-{
-       TAS2557_SA_CHL_CTRL_REG, 0x08, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00,
+static unsigned int p_tas2557_default_data[] = {
+       TAS2557_SAR_ADC2_REG, 0x05,     /* enable SAR ADC */
+/*TODO TAS2555_CLK_ERR_CTRL2, 0x39,    enable clock error detection on PLL */
+/*TODO TAS2555_CLK_ERR_CTRL3, 0x11,    enable clock error detection on PLL */
+       TAS2557_SAFE_GUARD_REG, TAS2557_SAFE_GUARD_PATTERN,     /* safe guard */
        0xFFFFFFFF, 0xFFFFFFFF
 };
 
-static unsigned int p_tas2557_SA_swap_data[] =
-{
-       TAS2557_SA_COEFF_SWAP_REG, 0x04, 0x00, 0x00, 0x00, 0x01, // when DSP powered on, swap needed to update coefficient memory
+static unsigned int p_tas2557_irq_config[] = {
+/*     TAS2555_CLK_HALT_REG, 0x71,      TODO */
+       TAS2557_INT_GEN1_REG, 0x11,     /* enable spk OC and OV */
+       TAS2557_INT_GEN2_REG, 0x11,     /* enable clk err1 and die OT */
+       TAS2557_INT_GEN3_REG, 0x11,     /* enable clk err2 and brownout */
+       TAS2557_INT_GEN4_REG, 0x01,     /* disable SAR, enable clk halt */
+       TAS2557_INT_MODE_REG, 0x80,     /* active high until INT_STICKY_1 and INT_STICKY_2 are read to be cleared. */
+       TAS2557_GPIO4_PIN_REG, 0x07,    /* set GPIO4 as int1, default */
        0xFFFFFFFF, 0xFFFFFFFF
 };
 
-#define TAS2557_STARTUP_DATA_PLL_CLKIN_INDEX 3
 static unsigned int p_tas2557_startup_data[] = {
-       TAS2557_CLK_ERR_CTRL, 0x03,     //enable clock error detection
-       TAS2557_PLL_CLKIN_REG, TAS2557_DEFAULT_PLL_CLKIN,
-       TAS2557_POWER_CTRL2_REG, 0xA0,  //Class-D, Boost power up
-       TAS2557_POWER_CTRL2_REG, 0xA3,  //Class-D, Boost, IV sense power up
-       TAS2557_POWER_CTRL1_REG, 0xF8,  //PLL, DSP, clock dividers power up
-       TAS2557_UDELAY, 2000,           //delay
+       TAS2557_GPI_PIN_REG, 0x15,      /* enable DIN, MCLK, CCI */
+       TAS2557_GPIO1_PIN_REG, 0x01,    /* enable BCLK */
+       TAS2557_GPIO2_PIN_REG, 0x01,    /* enable WCLK */
+       TAS2557_CLK_ERR_CTRL, 0x00,      /* enable clock error detection */
+       TAS2557_POWER_CTRL2_REG, 0xA0,   /* Class-D, Boost power up */
+       TAS2557_POWER_CTRL2_REG, 0xA3,   /* Class-D, Boost, IV sense power up */
+       TAS2557_POWER_CTRL1_REG, 0xF8,   /* PLL, DSP, clock dividers power up */
+       TAS2557_UDELAY, 2000,            /* delay */
+/*     TAS2557_CLK_ERR_CTRL, 0x03,      TODO  enable clock error detection */
        0xFFFFFFFF, 0xFFFFFFFF
 };
 
 static unsigned int p_tas2557_unmute_data[] = {
-       TAS2557_MUTE_REG, 0x00,         //unmute
-       TAS2557_SOFT_MUTE_REG, 0x00,    //soft unmute
+       TAS2557_MUTE_REG, 0x00,          /* unmute */
+       TAS2557_SOFT_MUTE_REG, 0x00,     /* soft unmute */
        0xFFFFFFFF, 0xFFFFFFFF
 };
 
 static unsigned int p_tas2557_shutdown_data[] = {
-       TAS2557_SOFT_MUTE_REG, 0x01,    //soft mute
-       TAS2557_UDELAY, 10000,          //delay 10ms
-       TAS2557_MUTE_REG, 0x03,         //mute
-       TAS2557_POWER_CTRL1_REG, 0x60,  //DSP power down
-       TAS2557_UDELAY, 2000,           //delay 2ms
-       TAS2557_POWER_CTRL2_REG, 0x00,  //Class-D, Boost power down
-       TAS2557_POWER_CTRL1_REG, 0x00,  //all power down
-       0xFFFFFFFF, 0xFFFFFFFF
-};
-
-#if 0
-static unsigned int p_tas2557_shutdown_clk_err[] = {
-       TAS2557_CLK_ERR_CTRL, 0x09,     //enable clock error detection on PLL
+       TAS2557_CLK_ERR_CTRL, 0x00,      /* disable clock error detection */
+       TAS2557_SOFT_MUTE_REG, 0x01,     /* soft mute */
+       TAS2557_UDELAY, 10000,           /* delay 10ms */
+       TAS2557_MUTE_REG, 0x03,          /* mute */
+       TAS2557_POWER_CTRL1_REG, 0x60,   /* DSP power down */
+       TAS2557_UDELAY, 2000,            /* delay 2ms */
+       TAS2557_POWER_CTRL2_REG, 0x00,   /* Class-D, Boost power down */
+       TAS2557_POWER_CTRL1_REG, 0x00,   /* all power down */
+       TAS2557_GPIO1_PIN_REG, 0x00,    /* disable BCLK */
+       TAS2557_GPIO2_PIN_REG, 0x00,    /* disable WCLK */
+       TAS2557_GPI_PIN_REG, 0x00,      /* disable DIN, MCLK, CCI */
        0xFFFFFFFF, 0xFFFFFFFF
 };
-#endif
 
 static unsigned int p_tas2557_mute_DSP_down_data[] = {
-       TAS2557_MUTE_REG, 0x03,         //mute
-       TAS2557_POWER_CTRL1_REG, 0x60,  //DSP power down
-       TAS2557_UDELAY, 0xFF,           //delay
+       TAS2557_MUTE_REG, 0x03,          /* mute */
+       TAS2557_POWER_CTRL1_REG, 0x60,   /* DSP power down */
+       TAS2557_UDELAY, 0xFF,            /* delay */
        0xFFFFFFFF, 0xFFFFFFFF
 };
 
-static int tas2557_dev_load_data(struct tas2557_priv *pTAS2557,
-       unsigned int *pData)
+static int tas2557_dev_load_data(struct tas2557_priv *pTAS2557, unsigned int *pData)
 {
        int ret = 0;
        unsigned int n = 0;
@@ -149,125 +136,290 @@ static int tas2557_dev_load_data(struct tas2557_priv *pTAS2557,
                nData = pData[n * 2 + 1];
                if (nRegister == TAS2557_UDELAY)
                        udelay(nData);
-               else if (nRegister != 0xFFFFFFFF){
+               else if (nRegister != 0xFFFFFFFF) {
                        ret = pTAS2557->write(pTAS2557, nRegister, nData);
-                       if(ret < 0) {
-                               dev_err(pTAS2557->dev, "Reg Write err %d\n", ret);
+                       if (ret < 0)
                                break;
-                       }
                }
                n++;
        } while (nRegister != 0xFFFFFFFF);
-       
        return ret;
 }
 
-static int tas2557_dev_load_blk_data(struct tas2557_priv *pTAS2557,
-                                 unsigned int *pData) {
-       unsigned int nRegister;
-       unsigned int *nData;
-       unsigned char Buf[128];
-       unsigned int nLength = 0;
-       unsigned int i =0;
-       unsigned int nSize = 0;
-       int ret = 0;
+int tas2557_configIRQ(struct tas2557_priv *pTAS2557)
+{
+       return tas2557_dev_load_data(pTAS2557, p_tas2557_irq_config);
+}
 
-       do{
-               nRegister = pData[nLength];
-               nSize = pData[nLength + 1];
-               nData = &pData[nLength + 2];
-               if (nRegister == TAS2557_MDELAY){
-                       mdelay(nData[0]);
-               }
-               else{
-                       if (nRegister != 0xFFFFFFFF){
-                               if(nSize > 128){ 
-                                       dev_err(pTAS2557->dev, 
-                                               "%s, Line=%d, invalid size, maximum is 128 bytes!\n", 
-                                               __FUNCTION__, __LINE__);
-                                       break;
-                               }
-                               
-                               if(nSize > 1){
-                                       for(i = 0; i < nSize; i++) Buf[i] = (unsigned char)nData[i];
-                                       ret = pTAS2557->bulk_write(pTAS2557, nRegister, Buf, nSize);
-                               }else if(nSize == 1){
-                                       ret = pTAS2557->write(pTAS2557,nRegister, nData[0]);
-                               }else{
-                                       dev_err(pTAS2557->dev, 
-                                               "%s, Line=%d,invalid size, minimum is 1 bytes!\n", 
-                                               __FUNCTION__, __LINE__);
-                               }
-                               
-                               if(ret < 0) break;
-                       }
-               }
-               nLength = nLength + 2 + pData[nLength+1] ;
-       } while (nRegister != 0xFFFFFFFF);
-       
+int tas2557_set_bit_rate(struct tas2557_priv *pTAS2557, unsigned int nBitRate)
+{
+       int ret = 0, n = -1;
+
+       dev_dbg(pTAS2557->dev, "tas2557_set_bit_rate: nBitRate = %d\n", nBitRate);
+
+       switch (nBitRate) {
+       case 16:
+               n = 0;
+               break;
+       case 20:
+               n = 1;
+               break;
+       case 24:
+               n = 2;
+               break;
+       case 32:
+               n = 3;
+               break;
+       }
+
+       if (n >= 0)
+               ret = pTAS2557->update_bits(pTAS2557, TAS2557_ASI1_DAC_FORMAT_REG, 0x18, n<<3);
        return ret;
 }
 
-int tas2557_setChannel(struct tas2557_priv *pTAS2557, int channel)
+int tas2557_get_bit_rate(struct tas2557_priv *pTAS2557, unsigned char *pBitRate)
 {
-       int ret = -1;
-       
-       if(channel == LEFT_CHANNEL){
-               ret = pTAS2557->update_bits(pTAS2557, TAS2557_ASI_CTRL_REG, 0x06, 0x00);        //ROM mode
-               ret = tas2557_dev_load_blk_data(pTAS2557, p_tas2557_SA_chl_left_data);
-       }else if(channel == RIGHT_CHANNEL){
-               ret = pTAS2557->update_bits(pTAS2557, TAS2557_ASI_CTRL_REG, 0x06, 0x02);        //ROM mode
-               ret = tas2557_dev_load_blk_data(pTAS2557, p_tas2557_SA_chl_right_data);
-       }
-               
-       ret = tas2557_dev_load_blk_data(pTAS2557, p_tas2557_SA_swap_data);
-       
+       int ret = 0;
+       unsigned int nValue = 0;
+       unsigned char bitRate;
+
+       ret = pTAS2557->read(pTAS2557, TAS2557_ASI1_DAC_FORMAT_REG, &nValue);
+       if (ret >= 0) {
+               bitRate = (nValue&0x18)>>3;
+               if (bitRate == 0)
+                       bitRate = 16;
+               else if (bitRate == 1)
+                       bitRate = 20;
+               else if (bitRate == 2)
+                       bitRate = 24;
+               else if (bitRate == 3)
+                       bitRate = 32;
+               *pBitRate = bitRate;
+       }
+
        return ret;
 }
 
-int tas2557_load_platdata(struct tas2557_priv *pTAS2557)
+int tas2557_get_DAC_gain(struct tas2557_priv *pTAS2557, unsigned char *pnGain)
 {
        int ret = 0;
-       
-       ret = tas2557_setChannel(pTAS2557, pTAS2557->mnDevChl);
-               
+       unsigned int nValue = 0;
+
+       ret = pTAS2557->read(pTAS2557, TAS2557_SPK_CTRL_REG, &nValue);
+       if (ret >= 0)
+               *pnGain = ((nValue&TAS2557_DAC_GAIN_MASK)>>TAS2557_DAC_GAIN_SHIFT);
+
        return ret;
 }
 
-int tas2557_load_default(struct tas2557_priv *pTAS2557)
+int tas2557_set_DAC_gain(struct tas2557_priv *pTAS2557, unsigned int nGain)
 {
        int ret = 0;
-       
-       ret = tas2557_load_platdata(pTAS2557);
-               
+
+       ret = pTAS2557->update_bits(pTAS2557, TAS2557_SPK_CTRL_REG, TAS2557_DAC_GAIN_MASK,
+               (nGain<<TAS2557_DAC_GAIN_SHIFT));
        return ret;
 }
 
-void tas2557_enable(struct tas2557_priv *pTAS2557, bool bEnable)
+/*
+* die temperature calculation:
+* DieTemp = readout / 2^23
+*/
+int tas2557_get_die_temperature(struct tas2557_priv *pTAS2557, int *pTemperature)
+{
+       unsigned char nBuf[4];
+       int temp;
+       int nResult = 0;
+
+       if (pTAS2557->mbPowerUp) {
+               nResult = pTAS2557->bulk_read(pTAS2557, TAS2557_DIE_TEMP_REG, nBuf, 4);
+               if (nResult >= 0) {
+                       temp = ((int)nBuf[0] << 24) | ((int)nBuf[1] << 16) | ((int)nBuf[2] << 8) | nBuf[3];
+                       *pTemperature = temp;
+               }
+       } else
+               dev_err(pTAS2557->dev, "Get Die Temperature when music is playing\n");
+
+       return nResult;
+}
+
+int tas2557_load_platdata(struct tas2557_priv *pTAS2557)
+{
+       int nResult = 0;
+       unsigned char nGain;
+
+       if (gpio_is_valid(pTAS2557->mnGpioINT)) {
+               nResult = tas2557_configIRQ(pTAS2557);
+               if (nResult < 0)
+                       goto end;
+               pTAS2557->enableIRQ(pTAS2557, false, true);
+       }
+
+       nResult = tas2557_set_bit_rate(pTAS2557, pTAS2557->mnI2SBits);
+       if (nResult < 0)
+               goto end;
+
+       nResult = tas2557_get_DAC_gain(pTAS2557, &nGain);
+       if (nResult >= 0) {
+               pTAS2557->mnDevGain = nGain;
+               pTAS2557->mnDevCurrentGain = nGain;
+       }
+
+end:
+
+       return nResult;
+}
+
+int tas2557_load_default(struct tas2557_priv *pTAS2557)
 {
+       int nResult = 0;
+
+       nResult = tas2557_dev_load_data(pTAS2557, p_tas2557_default_data);
+       if (nResult < 0)
+               goto end;
+
+       nResult = tas2557_load_platdata(pTAS2557);
+       if (nResult < 0)
+               goto end;
+
+       /* enable DOUT tri-state for extra BCLKs */
+       nResult = pTAS2557->update_bits(pTAS2557, TAS2557_ASI1_DAC_FORMAT_REG, 0x01, 0x01);
+end:
+
+       return nResult;
+}
+
+static void failsafe(struct tas2557_priv *pTAS2557)
+{
+       dev_err(pTAS2557->dev, "%s\n", __func__);
+       tas2557_dev_load_data(pTAS2557, p_tas2557_shutdown_data);
+       pTAS2557->mbPowerUp = false;
+       pTAS2557->hw_reset(pTAS2557);
+       pTAS2557->write(pTAS2557, TAS2557_SW_RESET_REG, 0x01);
+       udelay(1000);
+       pTAS2557->write(pTAS2557, TAS2557_SPK_CTRL_REG, 0x04);
+       if (pTAS2557->mpFirmware != NULL)
+               tas2557_clear_firmware(pTAS2557->mpFirmware);
+}
+
+int tas2557_enable(struct tas2557_priv *pTAS2557, bool bEnable)
+{
+       int nResult = 0, nRetry = 10;
+       unsigned char nBuf[4];
+       unsigned int nValue;
+       struct TProgram *pProgram;
+
        dev_dbg(pTAS2557->dev, "Enable: %d\n", bEnable);
+
+       if ((pTAS2557->mpFirmware->mnPrograms == 0)
+               || (pTAS2557->mpFirmware->mnConfigurations == 0)) {
+               dev_err(pTAS2557->dev, "%s, firmware not loaded\n", __func__);
+               goto end;
+       }
+       /* check safe guard*/
+       nResult = pTAS2557->read(pTAS2557, TAS2557_SAFE_GUARD_REG, &nValue);
+       if (nResult < 0)
+               goto end;
+       if ((nValue&0xff) != TAS2557_SAFE_GUARD_PATTERN) {
+               dev_err(pTAS2557->dev, "ERROR safe guard failure!\n");
+               nResult = -EPIPE;
+               goto end;
+       }
+
+       pProgram = &(pTAS2557->mpFirmware->mpPrograms[pTAS2557->mnCurrentProgram]);
        if (bEnable) {
                if (!pTAS2557->mbPowerUp) {
+                       if (pProgram->mnAppMode == TAS2557_APP_TUNINGMODE) {
+pllcheck:              /* check PLL */
+                               nResult = pTAS2557->write(pTAS2557, TAS2557_POWER_CTRL1_REG, 0xf8);
+                               if (nResult < 0)
+                                       goto end;
+                               msleep(2);
+                               /* check TAS2557 */
+                               memset(nBuf, 0, 4);
+                               nResult = pTAS2557->bulk_read(pTAS2557, TAS2557_XMEM_44_REG, nBuf, 4);
+                               if (nResult < 0)
+                                       goto end;
+                               nValue = ((unsigned int)nBuf[0] << 24) | ((unsigned int)nBuf[1] << 16) | ((unsigned int)nBuf[2] << 8) | nBuf[3];
+                               if (nValue == 0) {
+                                       nResult = pTAS2557->write(pTAS2557, TAS2557_POWER_CTRL1_REG, 0x60);
+                                       if (nResult < 0)
+                                               goto end;
+                                       msleep(2);
+                                       nResult = pTAS2557->write(pTAS2557, TAS2557_POWER_CTRL1_REG, 0x00);
+                                       if (nResult < 0)
+                                               goto end;
+                                       msleep(2);
+                                       nRetry--;
+                                       nResult = -EAGAIN;
+                                       if (nRetry == 0)
+                                               goto end;
+
+                                       dev_info(pTAS2557->dev, "PLL is absent, check again %d\n", nRetry);
+                                       goto pllcheck;
+                               }
+                       }
+
+                       /* power on device */
                        dev_dbg(pTAS2557->dev, "Enable: load startup sequence\n");
-                       tas2557_dev_load_data(pTAS2557, p_tas2557_startup_data);
+                       nResult = tas2557_dev_load_data(pTAS2557, p_tas2557_startup_data);
+                       if (nResult < 0)
+                               goto end;
                        dev_dbg(pTAS2557->dev, "Enable: load unmute sequence\n");
-                       tas2557_dev_load_data(pTAS2557, p_tas2557_unmute_data);
+                       nResult = tas2557_dev_load_data(pTAS2557, p_tas2557_unmute_data);
+                       if (nResult < 0)
+                               goto end;
                        pTAS2557->mbPowerUp = true;
+
+                       if (pProgram->mnAppMode == TAS2557_APP_TUNINGMODE) {
+                               /* turn on IRQ */
+                               nResult = pTAS2557->enableIRQ(pTAS2557, true, true);
+                               if (nResult < 0)
+                                       goto end;
+                               hrtimer_start(&pTAS2557->mtimer,
+                                       ns_to_ktime((u64)LOW_TEMPERATURE_CHECK_PERIOD * NSEC_PER_MSEC), HRTIMER_MODE_REL);
+                       }
                }
        } else {
                if (pTAS2557->mbPowerUp) {
-                       dev_dbg(pTAS2557->dev, "Enable: load shutdown sequence\n");
-                       tas2557_dev_load_data(pTAS2557, p_tas2557_shutdown_data);
-                       //tas2557_dev_load_data(pTAS2557, p_tas2557_shutdown_clk_err);
+                       if (pProgram->mnAppMode == TAS2557_APP_TUNINGMODE) {
+                               if (hrtimer_active(&pTAS2557->mtimer))
+                                       hrtimer_cancel(&pTAS2557->mtimer);
+
+                               dev_dbg(pTAS2557->dev, "Enable: load shutdown sequence\n");
+                               /* turn off IRQ */
+                               nResult = pTAS2557->enableIRQ(pTAS2557, false, true);
+                               if (nResult < 0)
+                                       goto end;
+                       }
+
+                       nResult = tas2557_dev_load_data(pTAS2557, p_tas2557_shutdown_data);
+                       if (nResult < 0)
+                               goto end;
+
                        pTAS2557->mbPowerUp = false;
                }
        }
+
+       nResult = 0;
+
+end:
+       if (nResult < 0) {
+               if (nRetry == 0)
+                       dev_err(pTAS2557->dev, "PLL is absent and enable timeout\n");
+               else
+                       dev_err(pTAS2557->dev, "enable failure %d\n", nResult);
+               failsafe(pTAS2557);
+       }
+
+       return nResult;
 }
 
 int tas2557_set_sampling_rate(struct tas2557_priv *pTAS2557, unsigned int nSamplingRate)
 {
        struct TConfiguration *pConfiguration;
        unsigned int nConfiguration;
+       int nResult = 0;
 
        dev_dbg(pTAS2557->dev, "tas2557_setup_clocks: nSamplingRate = %d [Hz]\n",
                nSamplingRate);
@@ -275,14 +427,16 @@ int tas2557_set_sampling_rate(struct tas2557_priv *pTAS2557, unsigned int nSampl
        if ((!pTAS2557->mpFirmware->mpPrograms) ||
                (!pTAS2557->mpFirmware->mpConfigurations)) {
                dev_err(pTAS2557->dev, "Firmware not loaded\n");
-               return -EINVAL;
+               nResult = -EINVAL;
+               goto end;
        }
 
        pConfiguration = &(pTAS2557->mpFirmware->mpConfigurations[pTAS2557->mnCurrentConfiguration]);
        if (pConfiguration->mnSamplingRate == nSamplingRate) {
                dev_info(pTAS2557->dev, "Sampling rate for current configuration matches: %d\n",
                        nSamplingRate);
-               return 0;
+               nResult = 0;
+               goto end;
        }
 
        for (nConfiguration = 0;
@@ -291,31 +445,33 @@ int tas2557_set_sampling_rate(struct tas2557_priv *pTAS2557, unsigned int nSampl
                pConfiguration =
                        &(pTAS2557->mpFirmware->mpConfigurations[nConfiguration]);
                if ((pConfiguration->mnSamplingRate == nSamplingRate)
-                       &&(pConfiguration->mnProgram == pTAS2557->mnCurrentProgram)){
+                       && (pConfiguration->mnProgram == pTAS2557->mnCurrentProgram)) {
                        dev_info(pTAS2557->dev,
                                "Found configuration: %s, with compatible sampling rate %d\n",
                                pConfiguration->mpName, nSamplingRate);
-                       tas2557_load_configuration(pTAS2557, nConfiguration, false);
-                       return 0;
+                       nResult = tas2557_load_configuration(pTAS2557, nConfiguration, false);
+                       goto end;
                }
        }
 
        dev_err(pTAS2557->dev, "Cannot find a configuration that supports sampling rate: %d\n",
                nSamplingRate);
 
-       return -EINVAL;
+end:
+
+       return nResult;
 }
 
-static void fw_print_header(struct tas2557_priv *pTAS2557, struct TFirmware * pFirmware)
+static void fw_print_header(struct tas2557_priv *pTAS2557, struct TFirmware *pFirmware)
 {
-       dev_info(pTAS2557->dev, "FW Size        = %d", pFirmware->mnFWSize);
-       dev_info(pTAS2557->dev, "Checksum       = 0x%04X", pFirmware->mnChecksum);
-       dev_info(pTAS2557->dev, "PPC Version    = 0x%04X", pFirmware->mnPPCVersion);
+       dev_info(pTAS2557->dev, "FW Size       = %d", pFirmware->mnFWSize);
+       dev_info(pTAS2557->dev, "Checksum      = 0x%04X", pFirmware->mnChecksum);
+       dev_info(pTAS2557->dev, "PPC Version   = 0x%04X", pFirmware->mnPPCVersion);
        dev_info(pTAS2557->dev, "FW  Version    = 0x%04X", pFirmware->mnFWVersion);
-       dev_info(pTAS2557->dev, "Driver Version = 0x%04X", pFirmware->mnDriverVersion);
-       dev_info(pTAS2557->dev, "Timestamp      = %d", pFirmware->mnTimeStamp);
-       dev_info(pTAS2557->dev, "DDC Name       = %s", pFirmware->mpDDCName);
-       dev_info(pTAS2557->dev, "Description    = %s", pFirmware->mpDescription);
+       dev_info(pTAS2557->dev, "Driver Version= 0x%04X", pFirmware->mnDriverVersion);
+       dev_info(pTAS2557->dev, "Timestamp     = %d", pFirmware->mnTimeStamp);
+       dev_info(pTAS2557->dev, "DDC Name      = %s", pFirmware->mpDDCName);
+       dev_info(pTAS2557->dev, "Description   = %s", pFirmware->mpDescription);
 }
 
 inline unsigned int fw_convert_number(unsigned char *pData)
@@ -323,23 +479,22 @@ inline unsigned int fw_convert_number(unsigned char *pData)
        return pData[3] + (pData[2] << 8) + (pData[1] << 16) + (pData[0] << 24);
 }
 
-static int fw_parse_header(struct tas2557_priv *pTAS2557, 
-       struct TFirmware * pFirmware, unsigned char *pData,
-       unsigned int nSize)
+static int fw_parse_header(struct tas2557_priv *pTAS2557,
+       struct TFirmware *pFirmware, unsigned char *pData, unsigned int nSize)
 {
        unsigned char *pDataStart = pData;
        unsigned int n;
        unsigned char pMagicNumber[] = { 0x35, 0x35, 0x35, 0x32 };
-       if (nSize < 102) {
+
+       if (nSize < 104) {
                dev_err(pTAS2557->dev, "Firmware: Header too short");
-               return -1;
+               return -EINVAL;
        }
 
        if (memcmp(pData, pMagicNumber, 4)) {
                dev_err(pTAS2557->dev, "Firmware: Magic number doesn't match");
-               return -1;
+               return -EINVAL;
        }
-
        pData += 4;
 
        pFirmware->mnFWSize = fw_convert_number(pData);
@@ -355,8 +510,8 @@ static int fw_parse_header(struct tas2557_priv *pTAS2557,
        pData += 4;
 
        pFirmware->mnDriverVersion = fw_convert_number(pData);
-       pData += 4;             
-                       
+       pData += 4;
+
        pFirmware->mnTimeStamp = fw_convert_number(pData);
        pData += 4;
 
@@ -366,36 +521,32 @@ static int fw_parse_header(struct tas2557_priv *pTAS2557,
        n = strlen(pData);
        pFirmware->mpDescription = kmemdup(pData, n + 1, GFP_KERNEL);
        pData += n + 1;
-
        if ((pData - pDataStart) >= nSize) {
                dev_err(pTAS2557->dev, "Firmware: Header too short after DDC description");
-               return -1;
+               return -EINVAL;
        }
 
        pFirmware->mnDeviceFamily = fw_convert_number(pData);
        pData += 4;
-
-       if(pFirmware->mnDeviceFamily != 0){
-               dev_err(pTAS2557->dev, 
-                       "deviceFamily %d, not TAS device", pFirmware->mnDeviceFamily);
-               return -1;
+       if (pFirmware->mnDeviceFamily != 0) {
+               dev_err(pTAS2557->dev, "deviceFamily %d, not TAS device", pFirmware->mnDeviceFamily);
+               return -EINVAL;
        }
-       
+
        pFirmware->mnDevice = fw_convert_number(pData);
        pData += 4;
 
-       if(pFirmware->mnDevice != 2){
-               dev_err(pTAS2557->dev, 
-                       "device %d, not TAS2557", pFirmware->mnDevice);
-               return -1;
+       if (pFirmware->mnDevice != 2) {
+               dev_err(pTAS2557->dev, "device %d, not TAS2557", pFirmware->mnDevice);
+               return -EINVAL;
        }
-       
-       fw_print_header(pTAS2557, pFirmware);
 
+       fw_print_header(pTAS2557, pFirmware);
        return pData - pDataStart;
 }
 
-static int fw_parse_block_data(struct TBlock * pBlock, unsigned char *pData)
+static int fw_parse_block_data(struct tas2557_priv *pTAS2557, struct TFirmware *pFirmware,
+       struct TBlock *pBlock, unsigned char *pData)
 {
        unsigned char *pDataStart = pData;
        unsigned int n;
@@ -403,6 +554,23 @@ static int fw_parse_block_data(struct TBlock * pBlock, unsigned char *pData)
        pBlock->mnType = fw_convert_number(pData);
        pData += 4;
 
+       if (pFirmware->mnDriverVersion >= PPC_DRIVER_VERSION) {
+               pBlock->mbPChkSumPresent = pData[0];
+               pData++;
+
+               pBlock->mnPChkSum = pData[0];
+               pData++;
+
+               pBlock->mbYChkSumPresent = pData[0];
+               pData++;
+
+               pBlock->mnYChkSum = pData[0];
+               pData++;
+       } else {
+               pBlock->mbPChkSumPresent = 0;
+               pBlock->mbYChkSumPresent = 0;
+       }
+
        pBlock->mnCommands = fw_convert_number(pData);
        pData += 4;
 
@@ -413,7 +581,8 @@ static int fw_parse_block_data(struct TBlock * pBlock, unsigned char *pData)
        return pData - pDataStart;
 }
 
-static int fw_parse_data(struct TData * pImageData, unsigned char *pData)
+static int fw_parse_data(struct tas2557_priv *pTAS2557, struct TFirmware *pFirmware,
+       struct TData *pImageData, unsigned char *pData)
 {
        unsigned char *pDataStart = pData;
        unsigned int nBlock;
@@ -431,16 +600,17 @@ static int fw_parse_data(struct TData * pImageData, unsigned char *pData)
 
        pImageData->mpBlocks =
                kmalloc(sizeof(struct TBlock) * pImageData->mnBlocks, GFP_KERNEL);
-
        for (nBlock = 0; nBlock < pImageData->mnBlocks; nBlock++) {
-               n = fw_parse_block_data(&(pImageData->mpBlocks[nBlock]), pData);
+               n = fw_parse_block_data(pTAS2557, pFirmware,
+                       &(pImageData->mpBlocks[nBlock]), pData);
                pData += n;
        }
 
        return pData - pDataStart;
 }
 
-static int fw_parse_pll_data(struct TFirmware * pFirmware, unsigned char *pData)
+static int fw_parse_pll_data(struct tas2557_priv *pTAS2557,
+       struct TFirmware *pFirmware, unsigned char *pData)
 {
        unsigned char *pDataStart = pData;
        unsigned int n;
@@ -450,7 +620,10 @@ static int fw_parse_pll_data(struct TFirmware * pFirmware, unsigned char *pData)
        pFirmware->mnPLLs = (pData[0] << 8) + pData[1];
        pData += 2;
 
-       pFirmware->mpPLLs = kmalloc(sizeof(struct TPLL) * pFirmware->mnPLLs, GFP_KERNEL);
+       if (pFirmware->mnPLLs == 0)
+               goto end;
+
+       pFirmware->mpPLLs = kmalloc_array(pFirmware->mnPLLs, sizeof(struct TPLL), GFP_KERNEL);
        for (nPLL = 0; nPLL < pFirmware->mnPLLs; nPLL++) {
                pPLL = &(pFirmware->mpPLLs[nPLL]);
 
@@ -461,14 +634,16 @@ static int fw_parse_pll_data(struct TFirmware * pFirmware, unsigned char *pData)
                pPLL->mpDescription = kmemdup(pData, n + 1, GFP_KERNEL);
                pData += n + 1;
 
-               n = fw_parse_block_data(&(pPLL->mBlock), pData);
+               n = fw_parse_block_data(pTAS2557, pFirmware, &(pPLL->mBlock), pData);
                pData += n;
        }
 
+end:
        return pData - pDataStart;
 }
 
-static int fw_parse_program_data(struct TFirmware * pFirmware, unsigned char *pData)
+static int fw_parse_program_data(struct tas2557_priv *pTAS2557,
+       struct TFirmware *pFirmware, unsigned char *pData)
 {
        unsigned char *pDataStart = pData;
        unsigned int n;
@@ -478,6 +653,9 @@ static int fw_parse_program_data(struct TFirmware * pFirmware, unsigned char *pD
        pFirmware->mnPrograms = (pData[0] << 8) + pData[1];
        pData += 2;
 
+       if (pFirmware->mnPrograms == 0)
+               goto end;
+
        pFirmware->mpPrograms =
                kmalloc(sizeof(struct TProgram) * pFirmware->mnPrograms, GFP_KERNEL);
        for (nProgram = 0; nProgram < pFirmware->mnPrograms; nProgram++) {
@@ -491,19 +669,21 @@ static int fw_parse_program_data(struct TFirmware * pFirmware, unsigned char *pD
 
                pProgram->mnAppMode = pData[0];
                pData++;
-               
+
                pProgram->mnBoost = (pData[0] << 8) + pData[1];
                pData += 2;
-               
-               n = fw_parse_data(&(pProgram->mData), pData);
+
+               n = fw_parse_data(pTAS2557, pFirmware, &(pProgram->mData), pData);
                pData += n;
        }
 
+end:
+
        return pData - pDataStart;
 }
 
-static int fw_parse_configuration_data(struct TFirmware * pFirmware,
-       unsigned char *pData)
+static int fw_parse_configuration_data(struct tas2557_priv *pTAS2557,
+       struct TFirmware *pFirmware, unsigned char *pData)
 {
        unsigned char *pDataStart = pData;
        unsigned int n;
@@ -513,11 +693,13 @@ static int fw_parse_configuration_data(struct TFirmware * pFirmware,
        pFirmware->mnConfigurations = (pData[0] << 8) + pData[1];
        pData += 2;
 
+       if (pFirmware->mnConfigurations == 0)
+               goto end;
+
        pFirmware->mpConfigurations =
                kmalloc(sizeof(struct TConfiguration) * pFirmware->mnConfigurations,
                GFP_KERNEL);
-       for (nConfiguration = 0; nConfiguration < pFirmware->mnConfigurations;
-               nConfiguration++) {
+       for (nConfiguration = 0; nConfiguration < pFirmware->mnConfigurations; nConfiguration++) {
                pConfiguration = &(pFirmware->mpConfigurations[nConfiguration]);
                memcpy(pConfiguration->mpName, pData, 64);
                pData += 64;
@@ -535,14 +717,17 @@ static int fw_parse_configuration_data(struct TFirmware * pFirmware,
                pConfiguration->mnSamplingRate = fw_convert_number(pData);
                pData += 4;
 
-               n = fw_parse_data(&(pConfiguration->mData), pData);
+               n = fw_parse_data(pTAS2557, pFirmware, &(pConfiguration->mData), pData);
                pData += n;
        }
 
+end:
+
        return pData - pDataStart;
 }
 
-int fw_parse_calibration_data(struct TFirmware * pFirmware, unsigned char *pData)
+int fw_parse_calibration_data(struct tas2557_priv *pTAS2557,
+       struct TFirmware *pFirmware, unsigned char *pData)
 {
        unsigned char *pDataStart = pData;
        unsigned int n;
@@ -552,11 +737,12 @@ int fw_parse_calibration_data(struct TFirmware * pFirmware, unsigned char *pData
        pFirmware->mnCalibrations = (pData[0] << 8) + pData[1];
        pData += 2;
 
+       if (pFirmware->mnCalibrations == 0)
+               goto end;
+
        pFirmware->mpCalibrations =
                kmalloc(sizeof(struct TCalibration) * pFirmware->mnCalibrations, GFP_KERNEL);
-       for (nCalibration = 0;
-               nCalibration < pFirmware->mnCalibrations;
-               nCalibration++) {
+       for (nCalibration = 0; nCalibration < pFirmware->mnCalibrations; nCalibration++) {
                pCalibration = &(pFirmware->mpCalibrations[nCalibration]);
                memcpy(pCalibration->mpName, pData, 64);
                pData += 64;
@@ -571,71 +757,354 @@ int fw_parse_calibration_data(struct TFirmware * pFirmware, unsigned char *pData
                pCalibration->mnConfiguration = pData[0];
                pData++;
 
-               n = fw_parse_data(&(pCalibration->mData), pData);
+               n = fw_parse_data(pTAS2557, pFirmware, &(pCalibration->mData), pData);
                pData += n;
        }
 
+end:
+
        return pData - pDataStart;
 }
 
 static int fw_parse(struct tas2557_priv *pTAS2557,
-       struct TFirmware * pFirmware,
-       unsigned char *pData,
-       unsigned int nSize)
+       struct TFirmware *pFirmware, unsigned char *pData, unsigned int nSize)
 {
        int nPosition = 0;
 
        nPosition = fw_parse_header(pTAS2557, pFirmware, pData, nSize);
        if (nPosition < 0) {
                dev_err(pTAS2557->dev, "Firmware: Wrong Header");
-               return FW_ERR_HEADER;
+               return -EINVAL;
        }
 
        if (nPosition >= nSize) {
                dev_err(pTAS2557->dev, "Firmware: Too short");
-               return FW_ERR_SIZE;
+               return -EINVAL;
        }
 
        pData += nPosition;
        nSize -= nPosition;
        nPosition = 0;
 
-       nPosition = fw_parse_pll_data(pFirmware, pData);
+       nPosition = fw_parse_pll_data(pTAS2557, pFirmware, pData);
 
        pData += nPosition;
        nSize -= nPosition;
        nPosition = 0;
 
-       nPosition = fw_parse_program_data(pFirmware, pData);
+       nPosition = fw_parse_program_data(pTAS2557, pFirmware, pData);
 
        pData += nPosition;
        nSize -= nPosition;
        nPosition = 0;
 
-       nPosition = fw_parse_configuration_data(pFirmware, pData);
+       nPosition = fw_parse_configuration_data(pTAS2557, pFirmware, pData);
 
        pData += nPosition;
        nSize -= nPosition;
        nPosition = 0;
 
        if (nSize > 64)
-               nPosition = fw_parse_calibration_data(pFirmware, pData);
-
+               nPosition = fw_parse_calibration_data(pTAS2557, pFirmware, pData);
        return 0;
 }
 
-static void tas2557_load_block(struct tas2557_priv *pTAS2557, struct TBlock * pBlock)
+
+static const unsigned char crc8_lookup_table[CRC8_TABLE_SIZE] = {
+0x00, 0x4D, 0x9A, 0xD7, 0x79, 0x34, 0xE3, 0xAE, 0xF2, 0xBF, 0x68, 0x25, 0x8B, 0xC6, 0x11, 0x5C,
+0xA9, 0xE4, 0x33, 0x7E, 0xD0, 0x9D, 0x4A, 0x07, 0x5B, 0x16, 0xC1, 0x8C, 0x22, 0x6F, 0xB8, 0xF5,
+0x1F, 0x52, 0x85, 0xC8, 0x66, 0x2B, 0xFC, 0xB1, 0xED, 0xA0, 0x77, 0x3A, 0x94, 0xD9, 0x0E, 0x43,
+0xB6, 0xFB, 0x2C, 0x61, 0xCF, 0x82, 0x55, 0x18, 0x44, 0x09, 0xDE, 0x93, 0x3D, 0x70, 0xA7, 0xEA,
+0x3E, 0x73, 0xA4, 0xE9, 0x47, 0x0A, 0xDD, 0x90, 0xCC, 0x81, 0x56, 0x1B, 0xB5, 0xF8, 0x2F, 0x62,
+0x97, 0xDA, 0x0D, 0x40, 0xEE, 0xA3, 0x74, 0x39, 0x65, 0x28, 0xFF, 0xB2, 0x1C, 0x51, 0x86, 0xCB,
+0x21, 0x6C, 0xBB, 0xF6, 0x58, 0x15, 0xC2, 0x8F, 0xD3, 0x9E, 0x49, 0x04, 0xAA, 0xE7, 0x30, 0x7D,
+0x88, 0xC5, 0x12, 0x5F, 0xF1, 0xBC, 0x6B, 0x26, 0x7A, 0x37, 0xE0, 0xAD, 0x03, 0x4E, 0x99, 0xD4,
+0x7C, 0x31, 0xE6, 0xAB, 0x05, 0x48, 0x9F, 0xD2, 0x8E, 0xC3, 0x14, 0x59, 0xF7, 0xBA, 0x6D, 0x20,
+0xD5, 0x98, 0x4F, 0x02, 0xAC, 0xE1, 0x36, 0x7B, 0x27, 0x6A, 0xBD, 0xF0, 0x5E, 0x13, 0xC4, 0x89,
+0x63, 0x2E, 0xF9, 0xB4, 0x1A, 0x57, 0x80, 0xCD, 0x91, 0xDC, 0x0B, 0x46, 0xE8, 0xA5, 0x72, 0x3F,
+0xCA, 0x87, 0x50, 0x1D, 0xB3, 0xFE, 0x29, 0x64, 0x38, 0x75, 0xA2, 0xEF, 0x41, 0x0C, 0xDB, 0x96,
+0x42, 0x0F, 0xD8, 0x95, 0x3B, 0x76, 0xA1, 0xEC, 0xB0, 0xFD, 0x2A, 0x67, 0xC9, 0x84, 0x53, 0x1E,
+0xEB, 0xA6, 0x71, 0x3C, 0x92, 0xDF, 0x08, 0x45, 0x19, 0x54, 0x83, 0xCE, 0x60, 0x2D, 0xFA, 0xB7,
+0x5D, 0x10, 0xC7, 0x8A, 0x24, 0x69, 0xBE, 0xF3, 0xAF, 0xE2, 0x35, 0x78, 0xD6, 0x9B, 0x4C, 0x01,
+0xF4, 0xB9, 0x6E, 0x23, 0x8D, 0xC0, 0x17, 0x5A, 0x06, 0x4B, 0x9C, 0xD1, 0x7F, 0x32, 0xE5, 0xA8
+};
+
+static int isInPageYRAM(struct tas2557_priv *pTAS2557, struct TYCRC *pCRCData,
+       unsigned char nBook, unsigned char nPage, unsigned char nReg, unsigned char len)
 {
+       int nResult = 0;
+
+       if (nBook == TAS2557_YRAM_BOOK1) {
+               if (nPage == TAS2557_YRAM1_PAGE) {
+                       if (nReg >= TAS2557_YRAM1_START_REG) {
+                               pCRCData->mnOffset = nReg;
+                               pCRCData->mnLen = len;
+                               nResult = 1;
+                       } else if ((nReg + len) > TAS2557_YRAM1_START_REG) {
+                               pCRCData->mnOffset = TAS2557_YRAM1_START_REG;
+                               pCRCData->mnLen = len - (TAS2557_YRAM1_START_REG - nReg);
+                               nResult = 1;
+                       } else
+                               nResult = 0;
+               } else if (nPage == TAS2557_YRAM3_PAGE) {
+                       if (nReg > TAS2557_YRAM3_END_REG) {
+                               nResult = 0;
+                       } else if (nReg >= TAS2557_YRAM3_START_REG) {
+                               if ((nReg + len) > TAS2557_YRAM3_END_REG) {
+                                       pCRCData->mnOffset = nReg;
+                                       pCRCData->mnLen = TAS2557_YRAM3_END_REG - nReg + 1;
+                                       nResult = 1;
+                               } else {
+                                       pCRCData->mnOffset = nReg;
+                                       pCRCData->mnLen = len;
+                                       nResult = 1;
+                               }
+                       } else {
+                               if ((nReg + len) < TAS2557_YRAM3_START_REG)
+                                       nResult = 0;
+                               else {
+                                       pCRCData->mnOffset = TAS2557_YRAM3_START_REG;
+                                       pCRCData->mnLen = len - (TAS2557_YRAM3_START_REG - nReg);
+                                       nResult = 1;
+                               }
+                       }
+               }
+       } else if (nBook == TAS2557_YRAM_BOOK2) {
+               if (nPage == TAS2557_YRAM5_PAGE) {
+                       if (nReg > TAS2557_YRAM5_END_REG) {
+                               nResult = 0;
+                       } else if (nReg >= TAS2557_YRAM5_START_REG) {
+                               if ((nReg + len) > TAS2557_YRAM5_END_REG) {
+                                       pCRCData->mnOffset = nReg;
+                                       pCRCData->mnLen = TAS2557_YRAM5_END_REG - nReg + 1;
+                                       nResult = 1;
+                               } else {
+                                       pCRCData->mnOffset = nReg;
+                                       pCRCData->mnLen = len;
+                                       nResult = 1;
+                               }
+                       } else {
+                               if ((nReg + len) < TAS2557_YRAM5_START_REG)
+                                       nResult = 0;
+                               else {
+                                       pCRCData->mnOffset = TAS2557_YRAM5_START_REG;
+                                       pCRCData->mnLen = len - (TAS2557_YRAM5_START_REG - nReg);
+                                       nResult = 1;
+                               }
+                       }
+               }
+       } else
+               nResult = 0;
+
+       return nResult;
+}
+
+static int isInBlockYRAM(struct tas2557_priv *pTAS2557, struct TYCRC *pCRCData,
+       unsigned char nBook, unsigned char nPage, unsigned char nReg, unsigned char len)
+{
+       int nResult;
+
+       if (nBook == TAS2557_YRAM_BOOK1) {
+               if (nPage < TAS2557_YRAM2_START_PAGE)
+                       nResult = 0;
+               else if (nPage <= TAS2557_YRAM2_END_PAGE) {
+                       if (nReg > TAS2557_YRAM2_END_REG)
+                               nResult = 0;
+                       else if (nReg >= TAS2557_YRAM2_START_REG) {
+                               pCRCData->mnOffset = nReg;
+                               pCRCData->mnLen = len;
+                               nResult = 1;
+                       } else {
+                               if ((nReg + len) < TAS2557_YRAM2_START_REG)
+                                       nResult = 0;
+                               else {
+                                       pCRCData->mnOffset = TAS2557_YRAM2_START_REG;
+                                       pCRCData->mnLen = nReg + len - TAS2557_YRAM2_START_REG;
+                                       nResult = 1;
+                               }
+                       }
+               } else
+                       nResult = 0;
+       } else if (nBook == TAS2557_YRAM_BOOK2) {
+               if (nPage < TAS2557_YRAM4_START_PAGE)
+                       nResult = 0;
+               else if (nPage <= TAS2557_YRAM4_END_PAGE) {
+                       if (nReg > TAS2557_YRAM2_END_REG)
+                               nResult = 0;
+                       else if (nReg >= TAS2557_YRAM2_START_REG) {
+                               pCRCData->mnOffset = nReg;
+                               pCRCData->mnLen = len;
+                               nResult = 1;
+                       } else {
+                               if ((nReg + len) < TAS2557_YRAM2_START_REG)
+                                       nResult = 0;
+                               else {
+                                       pCRCData->mnOffset = TAS2557_YRAM2_START_REG;
+                                       pCRCData->mnLen = nReg + len - TAS2557_YRAM2_START_REG;
+                                       nResult = 1;
+                               }
+                       }
+               } else
+                       nResult = 0;
+       } else
+               nResult = 0;
+
+       return nResult;
+}
+
+
+static int isYRAM(struct tas2557_priv *pTAS2557, struct TYCRC *pCRCData,
+       unsigned char nBook, unsigned char nPage, unsigned char nReg, unsigned char len)
+{
+       int nResult;
+
+       nResult = isInPageYRAM(pTAS2557, pCRCData, nBook, nPage, nReg, len);
+
+       if (nResult == 0)
+               nResult = isInBlockYRAM(pTAS2557, pCRCData, nBook, nPage, nReg, len);
+
+       return nResult;
+}
+
+/*
+ * crc8 - calculate a crc8 over the given input data.
+ *
+ * table: crc table used for calculation.
+ * pdata: pointer to data buffer.
+ * nbytes: number of bytes in data buffer.
+ * crc:        previous returned crc8 value.
+ */
+static u8 ti_crc8(const u8 table[CRC8_TABLE_SIZE], u8 *pdata, size_t nbytes, u8 crc)
+{
+       /* loop over the buffer data */
+       while (nbytes-- > 0)
+               crc = table[(crc ^ *pdata++) & 0xff];
+
+       return crc;
+}
+
+static int doSingleRegCheckSum(struct tas2557_priv *pTAS2557, 
+       unsigned char nBook, unsigned char nPage, unsigned char nReg, unsigned char nValue)
+{
+       int nResult = 0;
+       struct TYCRC sCRCData;
+       unsigned int nData1 = 0;
+
+       if ((nBook == TAS2557_BOOK_ID(TAS2557_SA_COEFF_SWAP_REG))
+               && (nPage == TAS2557_PAGE_ID(TAS2557_SA_COEFF_SWAP_REG))
+               && (nReg >= TAS2557_PAGE_REG(TAS2557_SA_COEFF_SWAP_REG))
+               && (nReg <= (TAS2557_PAGE_REG(TAS2557_SA_COEFF_SWAP_REG) + 4))) {
+               /* DSP swap command, pass */
+               nResult = 0;
+               goto end;
+       }
+
+       nResult = isYRAM(pTAS2557, &sCRCData, nBook, nPage, nReg, 1);
+       if (nResult == 1) {
+               nResult = pTAS2557->read(pTAS2557, TAS2557_REG(nBook, nPage, nReg), &nData1);
+               if (nResult < 0)
+                       goto end;
+
+               if (nData1 != nValue) {
+                       dev_err(pTAS2557->dev, "error2 (line %d),B[0x%x]P[0x%x]R[0x%x] W[0x%x], R[0x%x]\n",
+                               __LINE__, nBook, nPage, nReg, nValue, nData1);
+                       nResult = -EAGAIN;
+                       goto end;
+               }
+
+               nResult = ti_crc8(crc8_lookup_table, &nValue, 1, 0);
+       }
+
+end:
+
+       return nResult;
+}
+
+static int doMultiRegCheckSum(struct tas2557_priv *pTAS2557, 
+       unsigned char nBook, unsigned char nPage, unsigned char nReg, unsigned int len)
+{
+       int nResult = 0, i;
+       unsigned char nCRCChkSum = 0;
+       unsigned char nBuf1[128];
+       struct TYCRC TCRCData;
+
+       if ((nReg + len-1) > 127) {
+               nResult = -EINVAL;
+               dev_err(pTAS2557->dev, "firmware error\n");
+               goto end;
+       }
+
+       if ((nBook == TAS2557_BOOK_ID(TAS2557_SA_COEFF_SWAP_REG))
+               && (nPage == TAS2557_PAGE_ID(TAS2557_SA_COEFF_SWAP_REG))
+               && (nReg == TAS2557_PAGE_REG(TAS2557_SA_COEFF_SWAP_REG))
+               && (len == 4)) {
+               /* DSP swap command, pass */
+               nResult = 0;
+               goto end;
+       }
+
+       nResult = isYRAM(pTAS2557, &TCRCData, nBook, nPage, nReg, len);
+       if (nResult == 1) {
+               if (len == 1) {
+                       dev_err(pTAS2557->dev, "firmware error\n");
+                       nResult = -EINVAL;
+                       goto end;
+               } else {
+                       nResult = pTAS2557->bulk_read(pTAS2557, TAS2557_REG(nBook, nPage, TCRCData.mnOffset), nBuf1, TCRCData.mnLen);
+                       if (nResult < 0)
+                               goto end;
+
+                       for (i = 0; i < TCRCData.mnLen; i++) {
+                               if ((nBook == TAS2557_BOOK_ID(TAS2557_SA_COEFF_SWAP_REG))
+                                       && (nPage == TAS2557_PAGE_ID(TAS2557_SA_COEFF_SWAP_REG))
+                                       && ((i + TCRCData.mnOffset)
+                                               >= TAS2557_PAGE_REG(TAS2557_SA_COEFF_SWAP_REG))
+                                       && ((i + TCRCData.mnOffset)
+                                               <= (TAS2557_PAGE_REG(TAS2557_SA_COEFF_SWAP_REG) + 4))) {
+                                       /* DSP swap command, bypass */
+                                       continue;
+                               } else
+                                       nCRCChkSum += ti_crc8(crc8_lookup_table, &nBuf1[i], 1, 0);
+                       }
+
+                       nResult = nCRCChkSum;
+               }
+       }
+
+end:
+
+       return nResult;
+}
+
+static int tas2557_load_block(struct tas2557_priv *pTAS2557, struct TBlock *pBlock)
+{
+       int nResult = 0;
        unsigned int nCommand = 0;
        unsigned char nBook;
        unsigned char nPage;
        unsigned char nOffset;
        unsigned char nData;
        unsigned int nLength;
+       unsigned int nSleep;
+       unsigned char nCRCChkSum = 0;
+       unsigned int nValue1;
+       int nRetry = 6;
        unsigned char *pData = pBlock->mpData;
 
        dev_dbg(pTAS2557->dev, "TAS2557 load block: Type = %d, commands = %d\n",
                pBlock->mnType, pBlock->mnCommands);
+start:
+       if (pBlock->mbPChkSumPresent) {
+               nResult = pTAS2557->write(pTAS2557, TAS2557_CRC_RESET_REG, 1);
+               if (nResult < 0)
+                       goto end;
+       }
+
+       if (pBlock->mbYChkSumPresent)
+               nCRCChkSum = 0;
+
+       nCommand = 0;
+
        while (nCommand < pBlock->mnCommands) {
                pData = pBlock->mpData + nCommand * 4;
 
@@ -646,151 +1115,239 @@ static void tas2557_load_block(struct tas2557_priv *pTAS2557, struct TBlock * pB
 
                nCommand++;
 
-               if (nOffset <= 0x7F){
-                       pTAS2557->write(pTAS2557, TAS2557_REG(nBook, nPage, nOffset),
-                               nData);
-               }else if (nOffset == 0x81) {
-                       unsigned int nSleep = (nBook << 8) + nPage;
+               if (nOffset <= 0x7F) {
+                       nResult = pTAS2557->write(pTAS2557, TAS2557_REG(nBook, nPage, nOffset), nData);
+                       if (nResult < 0)
+                               goto end;
+                       if (pBlock->mbYChkSumPresent) {
+                               nResult = doSingleRegCheckSum(pTAS2557, nBook, nPage, nOffset, nData);
+                               if (nResult < 0)
+                                       goto check;
+                               nCRCChkSum += (unsigned char)nResult;
+                       }
+               } else if (nOffset == 0x81) {
+                       nSleep = (nBook << 8) + nPage;
                        msleep(nSleep);
-               }else if (nOffset == 0x85) {
+               } else if (nOffset == 0x85) {
                        pData += 4;
                        nLength = (nBook << 8) + nPage;
                        nBook = pData[0];
                        nPage = pData[1];
                        nOffset = pData[2];
-                       if (nLength > 1)
-                               pTAS2557->bulk_write(pTAS2557, TAS2557_REG(nBook, nPage,
-                                               nOffset), pData + 3, nLength);
-                       else
-                               pTAS2557->write(pTAS2557, TAS2557_REG(nBook, nPage, nOffset),
-                                       pData[3]);
+                       if (nLength > 1) {
+                               nResult = pTAS2557->bulk_write(pTAS2557, TAS2557_REG(nBook, nPage, nOffset), pData + 3, nLength);
+                               if (nResult < 0)
+                                       goto end;
+                               if (pBlock->mbYChkSumPresent) {
+                                       nResult = doMultiRegCheckSum(pTAS2557, nBook, nPage, nOffset, nLength);
+                                       if (nResult < 0)
+                                               goto check;
+                                       nCRCChkSum += (unsigned char)nResult;
+                               }
+                       } else {
+                               nResult = pTAS2557->write(pTAS2557, TAS2557_REG(nBook, nPage, nOffset), pData[3]);
+                               if (nResult < 0)
+                                       goto end;
+                               if (pBlock->mbYChkSumPresent) {
+                                       nResult = doSingleRegCheckSum(pTAS2557, nBook, nPage, nOffset, pData[3]);
+                                       if (nResult < 0)
+                                               goto check;
+                                       nCRCChkSum += (unsigned char)nResult;
+                               }
+                       }
 
                        nCommand++;
+
                        if (nLength >= 2)
                                nCommand += ((nLength - 2) / 4) + 1;
                }
        }
+       if (pBlock->mbPChkSumPresent) {
+               nResult = pTAS2557->read(pTAS2557, TAS2557_CRC_CHECKSUM_REG, &nValue1);
+               if (nResult < 0)
+                       goto end;
+               if ((nValue1&0xff) != pBlock->mnPChkSum) {
+                       dev_err(pTAS2557->dev, "Block PChkSum Error: FW = 0x%x, Reg = 0x%x\n",
+                               pBlock->mnPChkSum, (nValue1&0xff));
+                       nResult = -EAGAIN;
+                       goto check;
+               }
+
+               nResult = 0;
+               dev_dbg(pTAS2557->dev, "Block[0x%x] PChkSum match\n", pBlock->mnType);
+       }
+
+       if (pBlock->mbYChkSumPresent) {
+               if (nCRCChkSum != pBlock->mnYChkSum) {
+                       dev_err(pTAS2557->dev, "Block YChkSum Error: FW = 0x%x, YCRC = 0x%x\n",
+                               pBlock->mnYChkSum, nCRCChkSum);
+                       nResult = -EAGAIN;
+                       goto check;
+               }
+               nResult = 0;
+               dev_dbg(pTAS2557->dev, "Block[0x%x] YChkSum match\n", pBlock->mnType);
+       }
+
+check:
+       if (nResult == -EAGAIN) {
+               nRetry--;
+               if (nRetry > 0)
+                       goto start;
+       }
+
+end:
+       if (nResult < 0) {
+               dev_err(pTAS2557->dev, "Block (%d) load error\n",
+                               pBlock->mnType);
+       }
+       return nResult;
 }
 
-static void tas2557_load_data(struct tas2557_priv *pTAS2557, struct TData * pData,
-       unsigned int nType)
+static int tas2557_load_data(struct tas2557_priv *pTAS2557, struct TData *pData, unsigned int nType)
 {
+       int nResult = 0;
        unsigned int nBlock;
        struct TBlock *pBlock;
 
        dev_dbg(pTAS2557->dev,
-               "TAS2557 load data: %s, Blocks = %d, Block Type = %d\n", pData->mpName,
-               pData->mnBlocks, nType);
+               "TAS2557 load data: %s, Blocks = %d, Block Type = %d\n", pData->mpName, pData->mnBlocks, nType);
 
        for (nBlock = 0; nBlock < pData->mnBlocks; nBlock++) {
                pBlock = &(pData->mpBlocks[nBlock]);
-               if (pBlock->mnType == nType)
-                       tas2557_load_block(pTAS2557, pBlock);
+               if (pBlock->mnType == nType) {
+                       nResult = tas2557_load_block(pTAS2557, pBlock);
+                       if (nResult < 0)
+                               break;
+               }
        }
+
+       return nResult;
 }
 
-static void tas2557_load_configuration(struct tas2557_priv *pTAS2557,
+static int tas2557_load_configuration(struct tas2557_priv *pTAS2557,
        unsigned int nConfiguration, bool bLoadSame)
 {
-       struct TConfiguration *pCurrentConfiguration;
-       struct TConfiguration *pNewConfiguration;
-       struct TPLL *pNewPLL;
+       int nResult = 0;
+       struct TProgram *pCurrentProgram = NULL;
+       struct TConfiguration *pCurrentConfiguration = NULL;
+       struct TConfiguration *pNewConfiguration = NULL;
+       struct TCalibration *pCalibration = NULL;
+       struct TPLL *pNewPLL = NULL;
 
        dev_dbg(pTAS2557->dev, "tas2557_load_configuration: %d\n", nConfiguration);
 
        if ((!pTAS2557->mpFirmware->mpPrograms) ||
                (!pTAS2557->mpFirmware->mpConfigurations)) {
                dev_err(pTAS2557->dev, "Firmware not loaded\n");
-               return;
+               nResult = 0;
+               goto end;
        }
 
        if (nConfiguration >= pTAS2557->mpFirmware->mnConfigurations) {
                dev_err(pTAS2557->dev, "Configuration %d doesn't exist\n",
                        nConfiguration);
-               return;
+               nResult = 0;
+               goto end;
        }
 
        if ((nConfiguration == pTAS2557->mnCurrentConfiguration) && (!bLoadSame)) {
                dev_info(pTAS2557->dev, "Configuration %d is already loaded\n",
                        nConfiguration);
-               return;
+               nResult = 0;
+               goto end;
        }
 
        pCurrentConfiguration =
                &(pTAS2557->mpFirmware->mpConfigurations[pTAS2557->mnCurrentConfiguration]);
        pNewConfiguration =
                &(pTAS2557->mpFirmware->mpConfigurations[nConfiguration]);
-
        if (pNewConfiguration->mnProgram != pCurrentConfiguration->mnProgram) {
-               dev_err(pTAS2557->dev,
-                       "Configuration %d, %s doesn't share the same program as current %d\n",
+               dev_err(pTAS2557->dev, "Configuration %d, %s doesn't share the same program as current %d\n",
                        nConfiguration, pNewConfiguration->mpName, pCurrentConfiguration->mnProgram);
-               return;
+               nResult = 0;
+               goto end;
        }
 
        if (pNewConfiguration->mnPLL >= pTAS2557->mpFirmware->mnPLLs) {
-               dev_err(pTAS2557->dev,
-                       "Configuration %d, %s doesn't have a valid PLL index %d\n",
+               dev_err(pTAS2557->dev, "Configuration %d, %s doesn't have a valid PLL index %d\n",
                        nConfiguration, pNewConfiguration->mpName, pNewConfiguration->mnPLL);
-               return;
+               nResult = 0;
+               goto end;
        }
-       
+
+       pCurrentProgram = &(pTAS2557->mpFirmware->mpPrograms[pTAS2557->mnCurrentProgram]);
        pNewPLL = &(pTAS2557->mpFirmware->mpPLLs[pNewConfiguration->mnPLL]);
 
+       if (pTAS2557->mpCalFirmware->mnCalibrations)
+               pCalibration = &(pTAS2557->mpCalFirmware->mpCalibrations[pTAS2557->mnCurrentCalibration]);
+
        if (pTAS2557->mbPowerUp) {
                if (pNewConfiguration->mnPLL != pCurrentConfiguration->mnPLL) {
+                       if (hrtimer_active(&pTAS2557->mtimer))
+                               hrtimer_cancel(&pTAS2557->mtimer);
+                       nResult = pTAS2557->enableIRQ(pTAS2557, false, true);
+                       if (nResult < 0)
+                               goto end;
                        dev_dbg(pTAS2557->dev,
-                               "TAS2557 is powered up -> mute and power down DSP before loading new configuration\n");
-                       //tas2557_dev_load_data(pTAS2557, p_tas2557_mute_DSP_down_data);
-                       tas2557_dev_load_data(pTAS2557, p_tas2557_shutdown_data);
-                       dev_dbg(pTAS2557->dev, "TAS2557: load new PLL: %s, block data\n",
-                               pNewPLL->mpName);
-                       tas2557_load_block(pTAS2557, &(pNewPLL->mBlock));
+                               "TAS2557 is powered up, power down DSP before loading new configuration\n");
+                       nResult = tas2557_dev_load_data(pTAS2557, p_tas2557_shutdown_data);
+                       if (nResult < 0)
+                               goto end;
+                       dev_dbg(pTAS2557->dev, "TAS2557: load new PLL: %s, block data\n", pNewPLL->mpName);
+                       nResult = tas2557_load_block(pTAS2557, &(pNewPLL->mBlock));
+                       if (nResult < 0)
+                               goto end;
                        pTAS2557->mnCurrentSampleRate = pNewConfiguration->mnSamplingRate;
-                       dev_dbg(pTAS2557->dev,
-                               "load new configuration: %s, pre block data\n",
+                       dev_dbg(pTAS2557->dev, "load new configuration: %s, pre block data\n",
                                pNewConfiguration->mpName);
-                       tas2557_load_data(pTAS2557, &(pNewConfiguration->mData),
+                       nResult = tas2557_load_data(pTAS2557, &(pNewConfiguration->mData),
                                TAS2557_BLOCK_CFG_PRE_DEV_A);
-                       dev_dbg(pTAS2557->dev,
-                               "TAS2557: load new configuration: %s, coeff block data\n",
+                       if (nResult < 0)
+                               goto end;
+                       dev_dbg(pTAS2557->dev, "TAS2557: load new configuration: %s, coeff block data\n",
                                pNewConfiguration->mpName);
-                       tas2557_load_data(pTAS2557, &(pNewConfiguration->mData),
+                       nResult = tas2557_load_data(pTAS2557, &(pNewConfiguration->mData),
                                TAS2557_BLOCK_CFG_COEFF_DEV_A);
-                       if(pTAS2557->mpCalFirmware->mnCalibrations){
-                               struct TCalibration *pCalibration = &(pTAS2557->mpCalFirmware->mpCalibrations[pTAS2557->mnCurrentCalibration]);
-                               tas2557_load_data(pTAS2557, &(pCalibration->mData),
+                       if (nResult < 0)
+                               goto end;
+                       if ((pTAS2557->mpCalFirmware->mnCalibrations)
+                               && (pCurrentProgram->mnAppMode == TAS2557_APP_TUNINGMODE)) {
+                               dev_dbg(pTAS2557->dev, "Enable: load calibration\n");
+                               nResult = tas2557_load_data(pTAS2557, &(pCalibration->mData),
                                        TAS2557_BLOCK_CFG_COEFF_DEV_A);
-                       }
-
-                       if(pTAS2557->mnDevChl == LEFT_CHANNEL){
-                               tas2557_dev_load_blk_data(pTAS2557, p_tas2557_SA_chl_left_data);
-                       }else if(pTAS2557->mnDevChl == RIGHT_CHANNEL){
-                               tas2557_dev_load_blk_data(pTAS2557, p_tas2557_SA_chl_right_data);
+                               if (nResult < 0)
+                                       goto end;
                        }
                        dev_dbg(pTAS2557->dev, "TAS2557: power up TAS2557\n");
-                       tas2557_dev_load_data(pTAS2557, p_tas2557_startup_data);
+                       nResult = tas2557_dev_load_data(pTAS2557, p_tas2557_startup_data);
+                       if (nResult < 0)
+                               goto end;
                        dev_dbg(pTAS2557->dev, "TAS2557: unmute TAS2557\n");
-                       tas2557_dev_load_data(pTAS2557, p_tas2557_unmute_data);
+                       nResult = tas2557_dev_load_data(pTAS2557, p_tas2557_unmute_data);
+                       if (nResult < 0)
+                               goto end;
+
+                       if (pCurrentProgram->mnAppMode == TAS2557_APP_TUNINGMODE) {
+                               nResult = pTAS2557->enableIRQ(pTAS2557, true, false);
+                               hrtimer_start(&pTAS2557->mtimer,
+                                       ns_to_ktime((u64)LOW_TEMPERATURE_CHECK_PERIOD * NSEC_PER_MSEC), HRTIMER_MODE_REL);
+                       }
                } else {
                        dev_dbg(pTAS2557->dev,
                                "TAS2557 is powered up, no change in PLL: load new configuration: %s, coeff block data\n",
                                pNewConfiguration->mpName);
-                       tas2557_load_data(pTAS2557, &(pNewConfiguration->mData),
+                       nResult = tas2557_load_data(pTAS2557, &(pNewConfiguration->mData),
                                TAS2557_BLOCK_CFG_COEFF_DEV_A);
-                       if (pTAS2557->mpCalFirmware->mnCalibrations) {
-                               struct TCalibration *pCalibration = &(pTAS2557->mpCalFirmware->mpCalibrations[pTAS2557->mnCurrentCalibration]);
-                               tas2557_load_data(pTAS2557, &(pCalibration->mData),
-                                       TAS2557_BLOCK_CFG_COEFF_DEV_A);
+                       if (nResult < 0)
+                               goto end;
+                       if ((pTAS2557->mpCalFirmware->mnCalibrations)
+                               && (pCurrentProgram->mnAppMode == TAS2557_APP_TUNINGMODE)) {
+                               dev_dbg(pTAS2557->dev, "Enable: load calibration\n");
+                               nResult = tas2557_load_data(pTAS2557, &(pCalibration->mData), TAS2557_BLOCK_CFG_COEFF_DEV_A);
+                               if (nResult < 0)
+                                       goto end;
                        }
-
-                       if(pTAS2557->mnDevChl == LEFT_CHANNEL){
-                               tas2557_dev_load_blk_data(pTAS2557, p_tas2557_SA_chl_left_data);
-                       }else if(pTAS2557->mnDevChl == RIGHT_CHANNEL){
-                               tas2557_dev_load_blk_data(pTAS2557, p_tas2557_SA_chl_right_data);
-                       }       
                }
-                               
                pTAS2557->mbLoadConfigurationPostPowerUp = false;
        } else {
                dev_dbg(pTAS2557->dev,
@@ -798,34 +1355,37 @@ static void tas2557_load_configuration(struct tas2557_priv *pTAS2557,
                if (pNewConfiguration->mnPLL != pCurrentConfiguration->mnPLL) {
                        dev_dbg(pTAS2557->dev, "TAS2557: load new PLL: %s, block data\n",
                                pNewPLL->mpName);
-                       tas2557_load_block(pTAS2557, &(pNewPLL->mBlock));
+                       nResult = tas2557_load_block(pTAS2557, &(pNewPLL->mBlock));
+                       if (nResult < 0)
+                               goto end;
                        pTAS2557->mnCurrentSampleRate = pNewConfiguration->mnSamplingRate;
-                       dev_dbg(pTAS2557->dev,
-                               "load new configuration: %s, pre block data\n",
-                               pNewConfiguration->mpName);
-                       tas2557_load_data(pTAS2557, &(pNewConfiguration->mData),
-                               TAS2557_BLOCK_CFG_PRE_DEV_A);
+                       dev_dbg(pTAS2557->dev, "load new configuration: %s, pre block data\n", pNewConfiguration->mpName);
+                       nResult = tas2557_load_data(pTAS2557, &(pNewConfiguration->mData), TAS2557_BLOCK_CFG_PRE_DEV_A);
+                       if (nResult < 0)
+                               goto end;
                }
-
-               dev_dbg(pTAS2557->dev,
-                               "TAS2557: load new configuration: %s, coeff block data\n",
-                               pNewConfiguration->mpName);
-               tas2557_load_data(pTAS2557, &(pNewConfiguration->mData),
-                               TAS2557_BLOCK_CFG_COEFF_DEV_A);
-               if (pTAS2557->mpFirmware->mnCalibrations) {
-                       struct TCalibration *pCalibration = &(pTAS2557->mpCalFirmware->mpCalibrations[pTAS2557->mnCurrentCalibration]);
-                       tas2557_load_data(pTAS2557, &(pCalibration->mData),
-                               TAS2557_BLOCK_CFG_COEFF_DEV_A);
+               dev_dbg(pTAS2557->dev, "TAS2557: load new configuration: %s, coeff block data\n", pNewConfiguration->mpName);
+               nResult = tas2557_load_data(pTAS2557, &(pNewConfiguration->mData), TAS2557_BLOCK_CFG_COEFF_DEV_A);
+               if (nResult < 0)
+                       goto end;
+
+               if ((pTAS2557->mpCalFirmware->mnCalibrations)
+                       && (pCurrentProgram->mnAppMode == TAS2557_APP_TUNINGMODE)) {
+                       dev_dbg(pTAS2557->dev, "Enable: load calibration\n");
+                       nResult = tas2557_load_data(pTAS2557, &(pCalibration->mData), TAS2557_BLOCK_CFG_COEFF_DEV_A);
+                       if (nResult < 0)
+                               goto end;
                }
-               if (pTAS2557->mnDevChl == LEFT_CHANNEL)
-                       tas2557_dev_load_blk_data(pTAS2557, p_tas2557_SA_chl_left_data);
-               else if(pTAS2557->mnDevChl == RIGHT_CHANNEL)
-                       tas2557_dev_load_blk_data(pTAS2557, p_tas2557_SA_chl_right_data);
-
                pTAS2557->mbLoadConfigurationPostPowerUp = true;
        }
-
        pTAS2557->mnCurrentConfiguration = nConfiguration;
+
+end:
+
+       if (nResult < 0)
+               failsafe(pTAS2557);
+
+       return nResult;
 }
 
 int tas2557_set_config(struct tas2557_priv *pTAS2557, int config)
@@ -834,17 +1394,20 @@ int tas2557_set_config(struct tas2557_priv *pTAS2557, int config)
        struct TProgram *pProgram;
        unsigned int nProgram = pTAS2557->mnCurrentProgram;
        unsigned int nConfiguration = config;
+       int nResult = 0;
 
        if ((!pTAS2557->mpFirmware->mpPrograms) ||
                (!pTAS2557->mpFirmware->mpConfigurations)) {
                dev_err(pTAS2557->dev, "Firmware not loaded\n");
-               return -1;
+               nResult = -EINVAL;
+               goto end;
        }
 
        if (nConfiguration >= pTAS2557->mpFirmware->mnConfigurations) {
                dev_err(pTAS2557->dev, "Configuration %d doesn't exist\n",
                        nConfiguration);
-               return -1;
+               nResult = -EINVAL;
+               goto end;
        }
 
        pConfiguration = &(pTAS2557->mpFirmware->mpConfigurations[nConfiguration]);
@@ -855,21 +1418,27 @@ int tas2557_set_config(struct tas2557_priv *pTAS2557, int config)
                        "Configuration %d, %s with Program %d isn't compatible with existing Program %d, %s\n",
                        nConfiguration, pConfiguration->mpName, pConfiguration->mnProgram,
                        nProgram, pProgram->mpName);
-               return -1;
+               nResult = -EINVAL;
+               goto end;
        }
 
-       tas2557_load_configuration(pTAS2557, nConfiguration, false);
+       nResult = tas2557_load_configuration(pTAS2557, nConfiguration, false);
 
-       return 0;
+end:
+
+       return nResult;
 }
 
 void tas2557_clear_firmware(struct TFirmware *pFirmware)
 {
        unsigned int n, nn;
-       if (!pFirmware) return;
-       if (pFirmware->mpDescription) kfree(pFirmware->mpDescription);  
 
-       if (pFirmware->mpPLLs) {
+       if (!pFirmware)
+               return;
+
+       kfree(pFirmware->mpDescription);
+
+       if (pFirmware->mpPLLs != NULL) {
                for (n = 0; n < pFirmware->mnPLLs; n++) {
                        kfree(pFirmware->mpPLLs[n].mpDescription);
                        kfree(pFirmware->mpPLLs[n].mBlock.mpData);
@@ -877,7 +1446,7 @@ void tas2557_clear_firmware(struct TFirmware *pFirmware)
                kfree(pFirmware->mpPLLs);
        }
 
-       if (pFirmware->mpPrograms) {
+       if (pFirmware->mpPrograms != NULL) {
                for (n = 0; n < pFirmware->mnPrograms; n++) {
                        kfree(pFirmware->mpPrograms[n].mpDescription);
                        kfree(pFirmware->mpPrograms[n].mData.mpDescription);
@@ -888,7 +1457,7 @@ void tas2557_clear_firmware(struct TFirmware *pFirmware)
                kfree(pFirmware->mpPrograms);
        }
 
-       if (pFirmware->mpConfigurations) {
+       if (pFirmware->mpConfigurations != NULL) {
                for (n = 0; n < pFirmware->mnConfigurations; n++) {
                        kfree(pFirmware->mpConfigurations[n].mpDescription);
                        kfree(pFirmware->mpConfigurations[n].mData.mpDescription);
@@ -899,9 +1468,10 @@ void tas2557_clear_firmware(struct TFirmware *pFirmware)
                kfree(pFirmware->mpConfigurations);
        }
 
-       if (pFirmware->mpCalibrations) {
+       if (pFirmware->mpCalibrations != NULL) {
                for (n = 0; n < pFirmware->mnCalibrations; n++) {
                        kfree(pFirmware->mpCalibrations[n].mpDescription);
+                       kfree(pFirmware->mpCalibrations[n].mData.mpDescription);
                        for (nn = 0; nn < pFirmware->mpCalibrations[n].mData.mnBlocks; nn++)
                                kfree(pFirmware->mpCalibrations[n].mData.mpBlocks[nn].mpData);
                        kfree(pFirmware->mpCalibrations[n].mData.mpBlocks);
@@ -912,49 +1482,50 @@ void tas2557_clear_firmware(struct TFirmware *pFirmware)
        memset(pFirmware, 0x00, sizeof(struct TFirmware));
 }
 
-static void tas2557_load_calibration(struct tas2557_priv *pTAS2557,
-       char *pFileName)
+static int tas2557_load_calibration(struct tas2557_priv *pTAS2557,     char *pFileName)
 {
-       int nResult;
-       int nFile;
-       mm_segment_t fs;
-       unsigned char pBuffer[512];
-       int nSize = 0;
-
-       dev_dbg(pTAS2557->dev, "%s:\n", __func__);
-
-       fs = get_fs();
-       set_fs(KERNEL_DS);
-       nFile = sys_open(pFileName, O_RDONLY, 0);
-
-       dev_info(pTAS2557->dev, "TAS2557 calibration file = %s, handle = %d\n",
-               pFileName, nFile);
-
-       if (nFile >= 0) {
-               nSize = sys_read(nFile, pBuffer, 512);
-               sys_close(nFile);
-       } else {
-               dev_err(pTAS2557->dev, "TAS2557 cannot open calibration file: %s\n",
-                       pFileName);
-       }
-
-       set_fs(fs);
-
-       if (!nSize)
-               return;
-
-       tas2557_clear_firmware(pTAS2557->mpCalFirmware);
-               
-       dev_info(pTAS2557->dev, "TAS2557 calibration file size = %d\n", nSize);
-       nResult = fw_parse(pTAS2557, pTAS2557->mpCalFirmware, pBuffer, nSize);
-
-       if (nResult) {
-               dev_err(pTAS2557->dev, "TAS2557 calibration file is corrupt\n");
-               return;
-       }
-
-       dev_info(pTAS2557->dev, "TAS2557 calibration: %d calibrations\n",
-               pTAS2557->mpCalFirmware->mnCalibrations);
+       int nResult = 0;
+/*
+*      int nFile;
+*      mm_segment_t fs;
+*      unsigned char pBuffer[1000];
+*      int nSize = 0;
+*
+*      dev_dbg(pTAS2557->dev, "%s:\n", __func__);
+*
+*      fs = get_fs();
+*      set_fs(KERNEL_DS);
+*      nFile = sys_open(pFileName, O_RDONLY, 0);
+*
+*      dev_info(pTAS2557->dev, "TAS2557 calibration file = %s, handle = %d\n",
+*              pFileName, nFile);
+*
+*      if (nFile >= 0) {
+*              nSize = sys_read(nFile, pBuffer, 1000);
+*              sys_close(nFile);
+*      } else {
+*              dev_err(pTAS2557->dev, "TAS2557 cannot open calibration file: %s\n",
+*                      pFileName);
+*      }
+*
+*      set_fs(fs);
+*
+*      if (!nSize)
+*              goto end;
+*
+*      tas2557_clear_firmware(pTAS2557->mpCalFirmware);
+*      dev_info(pTAS2557->dev, "TAS2557 calibration file size = %d\n", nSize);
+*      nResult = fw_parse(pTAS2557, pTAS2557->mpCalFirmware, pBuffer, nSize);
+*
+*      if (nResult)
+*              dev_err(pTAS2557->dev, "TAS2557 calibration file is corrupt\n");
+*      else
+*              dev_info(pTAS2557->dev, "TAS2557 calibration: %d calibrations\n",
+*                      pTAS2557->mpCalFirmware->mnCalibrations);
+*
+*end:
+**/
+       return nResult;
 }
 
 void tas2557_fw_ready(const struct firmware *pFW, void *pContext)
@@ -969,226 +1540,258 @@ void tas2557_fw_ready(const struct firmware *pFW, void *pContext)
        if (unlikely(!pFW) || unlikely(!pFW->data)) {
                dev_err(pTAS2557->dev, "%s firmware is not loaded.\n",
                        TAS2557_FW_NAME);
-               
-               nResult = tas2557_load_default(pTAS2557);
-               return;
+               goto end;
        }
 
-       if (pTAS2557->mpFirmware->mpConfigurations){
+       if (pTAS2557->mpFirmware->mpConfigurations) {
                nProgram = pTAS2557->mnCurrentProgram;
                nSampleRate = pTAS2557->mnCurrentSampleRate;
                dev_dbg(pTAS2557->dev, "clear current firmware\n");
                tas2557_clear_firmware(pTAS2557->mpFirmware);
-       }       
-               
-       nResult = fw_parse(pTAS2557, pTAS2557->mpFirmware, 
-               (unsigned char *) (pFW->data),  pFW->size);
+       }
 
+       nResult = fw_parse(pTAS2557, pTAS2557->mpFirmware, (unsigned char *)(pFW->data), pFW->size);
        release_firmware(pFW);
-       
-       if (nResult) {
+       if (nResult < 0) {
                dev_err(pTAS2557->dev, "firmware is corrupt\n");
-               return;
+               goto end;
        }
 
        if (!pTAS2557->mpFirmware->mnPrograms) {
                dev_err(pTAS2557->dev, "firmware contains no programs\n");
-               return;
+               nResult = -EINVAL;
+               goto end;
        }
-       
+
        if (!pTAS2557->mpFirmware->mnConfigurations) {
-               dev_err(pTAS2557->dev, 
-                       "firmware contains no configurations\n");
-               return;
+               dev_err(pTAS2557->dev, "firmware contains no configurations\n");
+               nResult = -EINVAL;
+               goto end;
        }
-       
-       if(nProgram >= pTAS2557->mpFirmware->mnPrograms){
-               dev_info(pTAS2557->dev, 
+
+       if (nProgram >= pTAS2557->mpFirmware->mnPrograms) {
+               dev_info(pTAS2557->dev,
                        "no previous program, set to default\n");
                nProgram = 0;
        }
-               
+
        pTAS2557->mnCurrentSampleRate = nSampleRate;
 
-       tas2557_set_program(pTAS2557, nProgram);
-}      
+       nResult = tas2557_set_program(pTAS2557, nProgram, -1);
+
+end:
+       return;
+}
 
-int tas2557_set_program(struct tas2557_priv *pTAS2557,
-       unsigned int nProgram)
+int tas2557_set_program(struct tas2557_priv *pTAS2557, unsigned int nProgram, int nConfig)
 {
        struct TPLL *pPLL;
        struct TConfiguration *pConfiguration;
+       struct TProgram *pProgram;
        unsigned int nConfiguration = 0;
        unsigned int nSampleRate = 0;
-       unsigned int Value = 0;
        bool bFound = false;
-       int nResult = -1;
+       int nResult = 0;
 
        if ((!pTAS2557->mpFirmware->mpPrograms) ||
                (!pTAS2557->mpFirmware->mpConfigurations)) {
                dev_err(pTAS2557->dev, "Firmware not loaded\n");
-               return -1;
+               nResult = 0;
+               goto end;
        }
-       
+
        if (nProgram >= pTAS2557->mpFirmware->mnPrograms) {
                dev_err(pTAS2557->dev, "TAS2557: Program %d doesn't exist\n",
-                       nConfiguration);
-               return -1;
-       }
-       
-       nConfiguration = 0;
-       nSampleRate = pTAS2557->mnCurrentSampleRate;
-       
-       while (!bFound 
-               && (nConfiguration < pTAS2557->mpFirmware->mnConfigurations)) {
-               if (pTAS2557->mpFirmware->mpConfigurations[nConfiguration].mnProgram 
-                       == nProgram){
-                       if(nSampleRate == 0){
-                               bFound = true;
-                               dev_info(pTAS2557->dev, "find default configuration %d\n", nConfiguration);
-                       }else if(nSampleRate 
-                               == pTAS2557->mpFirmware->mpConfigurations[nConfiguration].mnSamplingRate){
-                               bFound = true;
-                               dev_info(pTAS2557->dev, "find matching configuration %d\n", nConfiguration);
-                       }else{
+                       nProgram);
+               nResult = 0;
+               goto end;
+       }
+
+       if (nConfig < 0) {
+               nConfiguration = 0;
+               nSampleRate = pTAS2557->mnCurrentSampleRate;
+               while (!bFound && (nConfiguration < pTAS2557->mpFirmware->mnConfigurations)) {
+                       if (pTAS2557->mpFirmware->mpConfigurations[nConfiguration].mnProgram == nProgram) {
+                               if (nSampleRate == 0) {
+                                       bFound = true;
+                                       dev_info(pTAS2557->dev, "find default configuration %d\n", nConfiguration);
+                               } else if (nSampleRate == pTAS2557->mpFirmware->mpConfigurations[nConfiguration].mnSamplingRate) {
+                                       bFound = true;
+                                       dev_info(pTAS2557->dev, "find matching configuration %d\n", nConfiguration);
+                               } else {
+                                       nConfiguration++;
+                               }
+                       } else {
                                nConfiguration++;
                        }
-               }else{
-                       nConfiguration++;
                }
-       }
-       
-       if (!bFound) {
-               dev_err(pTAS2557->dev, 
-                       "Program %d, no valid configuration found for sample rate %d, ignore\n",
-                       nProgram, nSampleRate);
-               return -1;
-       }
-       
+               if (!bFound) {
+                       dev_err(pTAS2557->dev,
+                               "Program %d, no valid configuration found for sample rate %d, ignore\n",
+                               nProgram, nSampleRate);
+                       nResult = 0;
+                       goto end;
+               }
+       } else
+               nConfiguration = nConfig;
+
        pTAS2557->mnCurrentProgram = nProgram;
-       
-       nResult = tas2557_dev_load_data(pTAS2557, p_tas2557_mute_DSP_down_data);
-       if(nResult < 0){
-               dev_err(pTAS2557->dev, 
-                       "device register access error\n");
-               return -1;
-       } 
-               
-       pTAS2557->write(pTAS2557, TAS2557_SW_RESET_REG, 0x01);
+       if (pTAS2557->mbPowerUp) {
+               if (hrtimer_active(&pTAS2557->mtimer))
+                       hrtimer_cancel(&pTAS2557->mtimer);
+               nResult = pTAS2557->enableIRQ(pTAS2557, false, true);
+               if (nResult < 0)
+                       goto end;
+               nResult = tas2557_dev_load_data(pTAS2557, p_tas2557_mute_DSP_down_data);
+               if (nResult < 0)
+                       goto end;
+       }
 
-       udelay(1000);
-       pTAS2557->mnCurrentBook = 0;
-       pTAS2557->mnCurrentPage = 0;
-       
-       nResult = tas2557_load_default(pTAS2557);       
-       
+       nResult = pTAS2557->write(pTAS2557, TAS2557_SW_RESET_REG, 0x01);
+       if (nResult < 0)
+               goto end;
+       msleep(1);
+       nResult = tas2557_load_default(pTAS2557);
+       if (nResult < 0)
+               goto end;
        dev_info(pTAS2557->dev, "load program %d\n", nProgram);
-       tas2557_load_data(pTAS2557,
-               &(pTAS2557->mpFirmware->mpPrograms[nProgram].mData),
-               TAS2557_BLOCK_PGM_DEV_A);
-
-       nResult = pTAS2557->read(pTAS2557, TAS2557_CRC_CHECKSUM_REG, &Value);
-       dev_info(pTAS2557->dev, "uCDSP Checksum: 0x%02x\n", Value);
-       
+       pProgram = &(pTAS2557->mpFirmware->mpPrograms[nProgram]);
+       nResult = tas2557_load_data(pTAS2557, &(pProgram->mData), TAS2557_BLOCK_PGM_ALL);
+       if (nResult < 0)
+               goto end;
+       nResult = tas2557_load_data(pTAS2557, &(pProgram->mData), TAS2557_BLOCK_PGM_DEV_A);
+       if (nResult < 0)
+               goto end;
        pTAS2557->mnCurrentConfiguration = nConfiguration;
-       pConfiguration =
-               &(pTAS2557->mpFirmware->mpConfigurations[nConfiguration]);
+       pConfiguration = &(pTAS2557->mpFirmware->mpConfigurations[nConfiguration]);
        pPLL = &(pTAS2557->mpFirmware->mpPLLs[pConfiguration->mnPLL]);
-       dev_dbg(pTAS2557->dev,
-               "TAS2557 load PLL: %s block for Configuration %s\n",
-               pPLL->mpName, pConfiguration->mpName);
-       
-       tas2557_load_block(pTAS2557, &(pPLL->mBlock));
+       dev_dbg(pTAS2557->dev, "TAS2557 load PLL: %s block for Configuration %s\n", pPLL->mpName, pConfiguration->mpName);
+       nResult = tas2557_load_block(pTAS2557, &(pPLL->mBlock));
+       if (nResult < 0)
+               goto end;
        pTAS2557->mnCurrentSampleRate = pConfiguration->mnSamplingRate;
-       dev_dbg(pTAS2557->dev,
-               "load configuration %s conefficient pre block\n",
-               pConfiguration->mpName);                
-       tas2557_load_data(pTAS2557, &(pConfiguration->mData), TAS2557_BLOCK_CFG_PRE_DEV_A);
+       dev_dbg(pTAS2557->dev, "load configuration %s conefficient pre block\n", pConfiguration->mpName);
+       nResult = tas2557_load_data(pTAS2557, &(pConfiguration->mData), TAS2557_BLOCK_CFG_PRE_DEV_A);
+       if (nResult < 0)
+               goto end;
 
-       nResult = pTAS2557->read(pTAS2557, TAS2557_PLL_CLKIN_REG, &Value);
-       dev_info(pTAS2557->dev, "TAS2557 PLL_CLKIN = 0x%02X\n", Value);
-       p_tas2557_startup_data[TAS2557_STARTUP_DATA_PLL_CLKIN_INDEX] = Value;
+       nResult = tas2557_load_configuration(pTAS2557, nConfiguration, true);
+       if (nResult < 0)
+               goto end;
 
-       tas2557_load_configuration(pTAS2557, nConfiguration, true);
-       if (pTAS2557->mbPowerUp){
+       if (pTAS2557->mbPowerUp) {
                dev_dbg(pTAS2557->dev, "device powered up, load startup\n");
-               tas2557_dev_load_data(pTAS2557, p_tas2557_startup_data);
+               nResult = tas2557_dev_load_data(pTAS2557, p_tas2557_startup_data);
+               if (nResult < 0)
+                       goto end;
                dev_dbg(pTAS2557->dev,
                        "device powered up, load unmute\n");
-               tas2557_dev_load_data(pTAS2557, p_tas2557_unmute_data);
+               nResult = tas2557_dev_load_data(pTAS2557, p_tas2557_unmute_data);
+               if (nResult < 0)
+                       goto end;
+               if (pProgram->mnAppMode == TAS2557_APP_TUNINGMODE) {
+                       nResult = pTAS2557->enableIRQ(pTAS2557, true, false);
+                       hrtimer_start(&pTAS2557->mtimer, 
+                               ns_to_ktime((u64)LOW_TEMPERATURE_CHECK_PERIOD * NSEC_PER_MSEC), HRTIMER_MODE_REL);
+               }
        }
 
-       return 0;
+end:
+
+       if (nResult < 0)
+               failsafe(pTAS2557);
+
+       return nResult;
 }
 
 int tas2557_set_calibration(struct tas2557_priv *pTAS2557, int nCalibration)
 {
-       struct TCalibration *pCalibration;
+       struct TCalibration *pCalibration = NULL;
+       struct TProgram *pProgram;
+       int nResult = 0;
 
-       if ((!pTAS2557->mpFirmware->mpPrograms) || (!pTAS2557->mpFirmware->mpConfigurations)) 
-       {
+       if ((!pTAS2557->mpFirmware->mpPrograms)
+               || (!pTAS2557->mpFirmware->mpConfigurations)) {
                dev_err(pTAS2557->dev, "Firmware not loaded\n\r");
-               return -1;
+               nResult = 0;
+               goto end;
        }
 
-       if (nCalibration == 0x00FF)
-       {
-               dev_info(pTAS2557->dev, "load new calibration file %s\n", TAS2557_CAL_NAME);    
-               tas2557_load_calibration(pTAS2557, TAS2557_CAL_NAME);
+       if (nCalibration == 0x00FF) {
+               dev_info(pTAS2557->dev, "load new calibration file %s\n", TAS2557_CAL_NAME);
+               nResult = tas2557_load_calibration(pTAS2557, TAS2557_CAL_NAME);
+               if (nResult < 0)
+                       goto end;
                nCalibration = 0;
        }
 
        if (nCalibration >= pTAS2557->mpCalFirmware->mnCalibrations) {
                dev_err(pTAS2557->dev,
                        "Calibration %d doesn't exist\n", nCalibration);
-               return -1;
+               nResult = 0;
+               goto end;
        }
 
        pTAS2557->mnCurrentCalibration = nCalibration;
-       pCalibration = &(pTAS2557->mpCalFirmware->mpCalibrations[pTAS2557->mnCurrentCalibration]);
-       tas2557_load_data(pTAS2557, &(pCalibration->mData), TAS2557_BLOCK_CFG_COEFF_DEV_A);
+       pCalibration = &(pTAS2557->mpCalFirmware->mpCalibrations[nCalibration]);
+       pProgram = &(pTAS2557->mpFirmware->mpPrograms[pTAS2557->mnCurrentProgram]);
+
+       if (pProgram->mnAppMode == TAS2557_APP_TUNINGMODE) {
+               dev_dbg(pTAS2557->dev, "Enable: load calibration\n");
+               nResult = tas2557_load_data(pTAS2557, &(pCalibration->mData), TAS2557_BLOCK_CFG_COEFF_DEV_A);
+               if (nResult < 0)
+                       goto end;
+       }
 
-       return 0;
+end:
+       if (nResult < 0) {
+               tas2557_clear_firmware(pTAS2557->mpCalFirmware);
+               nResult = tas2557_set_program(pTAS2557, pTAS2557->mnCurrentProgram, pTAS2557->mnCurrentConfiguration);
+       }
+
+       return nResult;
 }
 
-int tas2557_parse_dt(struct device *dev,
-                       struct tas2557_priv *pTAS2557)
+int tas2557_parse_dt(struct device *dev, struct tas2557_priv *pTAS2557)
 {
        struct device_node *np = dev->of_node;
-       int rc= 0, ret = 0;
-
-       rc = of_property_read_u32(np, "ti,load", &pTAS2557->mnLoad);
-       if (rc) {
-               dev_err(pTAS2557->dev, "Looking up %s property in node %s failed %d\n",
-                       "ti,load", np->full_name, rc);
-               ret = -1;
-       }else{
-               dev_dbg(pTAS2557->dev, "ti,load=%d", pTAS2557->mnLoad);
-       }
+       int rc = 0, ret = 0;
+       unsigned int value;
 
-       rc = of_property_read_u32(np, "ti,channel", &pTAS2557->mnDevChl);
-       if (rc) {
-               dev_err(pTAS2557->dev, "Looking up %s property in node %s failed %d\n",
-                       "ti,channel", np->full_name, rc);
-               ret = -1;
-       }else{
-               dev_dbg(pTAS2557->dev, "ti,channel=%d", pTAS2557->mnDevChl);
-       }
-       
-       pTAS2557->mnResetGPIO = of_get_named_gpio(np,
-                               "ti,cdc-reset-gpio", 0);
+       pTAS2557->mnResetGPIO = of_get_named_gpio(np, "ti,cdc-reset-gpio", 0);
        if (pTAS2557->mnResetGPIO < 0) {
                dev_err(pTAS2557->dev, "Looking up %s property in node %s failed %d\n",
                        "ti,cdc-reset-gpio", np->full_name,
                        pTAS2557->mnResetGPIO);
-               ret = -1;
-       }else{
-               dev_dbg(pTAS2557->dev, "ti,cdc-reset-gpio=%d", pTAS2557->mnResetGPIO);
+               ret = -EINVAL;
+       } else
+                       dev_dbg(pTAS2557->dev, "ti,cdc-reset-gpio=%d\n", pTAS2557->mnResetGPIO);
+
+       if (ret >= 0) {
+               rc = of_property_read_u32(np, "ti,i2s-bits", &value);
+               if (rc) {
+                       dev_err(pTAS2557->dev, "Looking up %s property in node %s failed %d\n",
+                               "ti,i2s-bits", np->full_name, rc);
+                       ret = -EINVAL;
+               } else {
+                       pTAS2557->mnI2SBits = value;
+                       dev_dbg(pTAS2557->dev, "ti,i2s-bits=%d\n", pTAS2557->mnI2SBits);
+               }
        }
 
+       if (ret >= 0) {
+               pTAS2557->mnGpioINT = of_get_named_gpio(np, "ti,irq-gpio", 0);
+               if (pTAS2557->mnGpioINT < 0) {
+                       dev_err(pTAS2557->dev, "Looking up %s property in node %s failed %d\n",
+                               "ti,irq-gpio", np->full_name,
+                               pTAS2557->mnGpioINT);
+                       ret = -EINVAL;
+               } else
+                       dev_dbg(pTAS2557->dev, "ti,irq-gpio=%d\n", pTAS2557->mnGpioINT);
+       }
        return ret;
 }
 
 MODULE_AUTHOR("Texas Instruments Inc.");
 MODULE_DESCRIPTION("TAS2557 common functions for Android Linux");
-MODULE_LICENSE("GPLv2");
\ No newline at end of file
+MODULE_LICENSE("GPL v2");
\ No newline at end of file
index 7aa9eaca1683d2c4e3ae0dc70ee45afc3875df3e..1252ae485886cbaa090693fa67e5ae340705a346 100755 (executable)
@@ -3,17 +3,13 @@
 ** 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 
+** 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.
 **
-** You should have received a copy of the GNU General Public License along with
-** this program; if not, write to the Free Software Foundation, Inc., 51 Franklin
-** Street, Fifth Floor, Boston, MA 02110-1301, USA.
-**
 ** File:
 **     tas2557-core.h
 **
 
 #include "tas2557.h"
 
-int tas2557_parse_dt(struct device *dev,
-                       struct tas2557_priv *pTAS2557);
-void tas2557_enable(struct tas2557_priv *pTAS2557, bool bEnable);
-int tas2557_set_sampling_rate(struct tas2557_priv *pTAS2557, 
-       unsigned int nSamplingRate);
+#define TAS2557_YRAM_BOOK1                             140
+
+#define TAS2557_YRAM1_PAGE                             42
+#define TAS2557_YRAM1_START_REG                        88
+#define TAS2557_YRAM1_END_REG                  127
+
+#define TAS2557_YRAM2_START_PAGE               43
+#define TAS2557_YRAM2_END_PAGE                 49
+#define TAS2557_YRAM2_START_REG                        8
+#define TAS2557_YRAM2_END_REG                  127
+
+#define TAS2557_YRAM3_PAGE                             50
+#define TAS2557_YRAM3_START_REG                        8
+#define TAS2557_YRAM3_END_REG                  23
+
+/* should not include B0_P53_R44-R47 */
+#define TAS2557_YRAM_BOOK2                             0
+#define TAS2557_YRAM4_START_PAGE               50
+#define TAS2557_YRAM4_END_PAGE                 60
+#define TAS2557_YRAM4_START_REG                        8
+#define TAS2557_YRAM4_END_REG                  127
+
+#define TAS2557_YRAM5_PAGE                             61
+#define TAS2557_YRAM5_START_REG                        8
+#define TAS2557_YRAM5_END_REG                  27
+
+#define TAS2557_SAFE_GUARD_PATTERN             0x5a
+#define LOW_TEMPERATURE_CHECK_PERIOD 5000      /* 5 second */
+
+struct TYCRC {
+       unsigned char mnOffset;
+       unsigned char mnLen;
+};
+
+int tas2557_enable(struct tas2557_priv *pTAS2557, bool bEnable);
+int tas2557_get_die_temperature(struct tas2557_priv *pTAS2557, int *pTemperature);
+int tas2557_set_sampling_rate(struct tas2557_priv *pTAS2557, unsigned int nSamplingRate);
+int tas2557_set_bit_rate(struct tas2557_priv *pTAS2557, unsigned int nBitRate);
+int tas2557_get_bit_rate(struct tas2557_priv *pTAS2557, unsigned char *pBitRate);
 int tas2557_set_config(struct tas2557_priv *pTAS2557, int config);
-void tas2557_load_fs_firmware(struct tas2557_priv *pTAS2557,
-       char *pFileName);
 void tas2557_fw_ready(const struct firmware *pFW, void *pContext);
-int tas2557_set_program(struct tas2557_priv *pTAS2557,
-       unsigned int nProgram);
-int tas2557_set_calibration(struct tas2557_priv *pTAS2557,
-       int nCalibration);
+int tas2557_set_program(struct tas2557_priv *pTAS2557, unsigned int nProgram, int nConfig);
+int tas2557_set_calibration(struct tas2557_priv *pTAS2557, int nCalibration);
 int tas2557_load_default(struct tas2557_priv *pTAS2557);
-int tas2557_setChannel(struct tas2557_priv *pTAS2557, int channel);
-       
+int tas2557_parse_dt(struct device *dev, struct tas2557_priv *pTAS2557);
+int tas2557_get_DAC_gain(struct tas2557_priv *pTAS2557, unsigned char *pnGain);
+int tas2557_set_DAC_gain(struct tas2557_priv *pTAS2557, unsigned int nGain);
+int tas2557_configIRQ(struct tas2557_priv *pTAS2557);
 #endif /* _TAS2557_CORE_H */
index 26cb388e16bbdbc832061519a0be3649f3297af9..db4bb3d2ba4bcd9e66b2b69de92843457c87f6d2 100755 (executable)
@@ -3,17 +3,13 @@
 ** 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 
+** 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.
 **
-** You should have received a copy of the GNU General Public License along with
-** this program; if not, write to the Free Software Foundation, Inc., 51 Franklin
-** Street, Fifth Floor, Boston, MA 02110-1301, USA.
-**
 ** File:
 **     tas2557-misc.c
 **
 #include <linux/syscalls.h>
 #include <linux/fcntl.h>
 #include <linux/miscdevice.h>
-#include <asm/uaccess.h>
-//#include <dt-bindings/sound/tas2557.h>
+#include <linux/uaccess.h>
 
 #include "tas2557.h"
 #include "tas2557-core.h"
 #include "tas2557-misc.h"
 #include <linux/dma-mapping.h>
 
-#define TAS2557_FW_FULL_NAME     "/etc/firmware/tas2557_uCDSP.bin"
-     
 static int g_logEnable = 1;
-static struct tas2557_priv *g_tas2557 = NULL;
+static struct tas2557_priv *g_tas2557;
 
-static int tas2557_set_bit_rate(struct tas2557_priv *pTAS2557, unsigned int nBitRate)
-{
-       int ret = 0, n = -1;
-       
-       dev_dbg(pTAS2557->dev, "tas2557_set_bit_rate: nBitRate = %d \n",
-               nBitRate);
-       switch(nBitRate){
-               case 16:
-                       n = 0;
-               break;
-               case 20:
-                       n = 1;
-               break;
-               case 24:
-                       n = 2;
-               break;
-               case 32:
-                       n = 3;
-               break;
-       }
-       
-       if(n >= 0)
-               ret = pTAS2557->update_bits(pTAS2557, 
-                       TAS2557_ASI1_DAC_FORMAT_REG, 0x18, n<<3);       
-               
-       return ret;     
-}
-                                 
 static int tas2557_file_open(struct inode *inode, struct file *file)
 {
        struct tas2557_priv *pTAS2557 = g_tas2557;
-       
-       if (!try_module_get(THIS_MODULE)) return -ENODEV;
 
-       file->private_data = (void*)pTAS2557;
-       
-       if(g_logEnable) dev_info(pTAS2557->dev,
-                               "%s\n", __FUNCTION__);
+       if (!try_module_get(THIS_MODULE))
+               return -ENODEV;
+
+       file->private_data = (void *)pTAS2557;
+       if (g_logEnable)
+               dev_info(pTAS2557->dev, "%s\n", __func__);
        return 0;
 }
 
@@ -100,10 +65,9 @@ static int tas2557_file_release(struct inode *inode, struct file *file)
 {
        struct tas2557_priv *pTAS2557 = (struct tas2557_priv *)file->private_data;
 
-       if(g_logEnable) dev_info(pTAS2557->dev,
-                               "%s\n", __FUNCTION__);
-                               
-       file->private_data = (void*)NULL;
+       if (g_logEnable)
+               dev_info(pTAS2557->dev, "%s\n", __func__);
+       file->private_data = (void *)NULL;
        module_put(THIS_MODULE);
 
        return 0;
@@ -118,251 +82,211 @@ static ssize_t tas2557_file_read(struct file *file, char *buf, size_t count, lof
        unsigned char *p_kBuf = NULL;
 
        mutex_lock(&pTAS2557->file_lock);
-       
-       switch(pTAS2557->mnDBGCmd)
-       {
-               case TIAUDIO_CMD_REG_READ:
-               {
-                       if(g_logEnable) dev_info(pTAS2557->dev,
-                               "TIAUDIO_CMD_REG_READ: current_reg = 0x%x, count=%d\n", pTAS2557->mnCurrentReg, (int)count);
-                       if(count == 1){
-                               ret = pTAS2557->read(pTAS2557, pTAS2557->mnCurrentReg, &nValue);
-                               if( 0 > ret) {
-                                       dev_err(pTAS2557->dev, "dev read fail %d\n", ret);
+
+       switch (pTAS2557->mnDBGCmd) {
+       case TIAUDIO_CMD_REG_READ: {
+               if (g_logEnable)
+                       dev_info(pTAS2557->dev, "TIAUDIO_CMD_REG_READ: current_reg = 0x%x, count=%d\n",
+                               pTAS2557->mnCurrentReg, (int)count);
+               if (count == 1) {
+                       ret = pTAS2557->read(pTAS2557, pTAS2557->mnCurrentReg, &nValue);
+                       if (ret < 0)
+                               break;
+
+                       value = (u8)nValue;
+                       if (g_logEnable)
+                               dev_info(pTAS2557->dev, "TIAUDIO_CMD_REG_READ: nValue=0x%x, value=0x%x\n", nValue, value);
+                       ret = copy_to_user(buf, &value, 1);
+                       if (ret != 0) {
+                               /* Failed to copy all the data, exit */
+                               dev_err(pTAS2557->dev, "copy to user fail %d\n", ret);
+                       }
+               } else if (count > 1) {
+                       p_kBuf = kzalloc(count, GFP_KERNEL);
+                       if (p_kBuf != NULL) {
+                               ret = pTAS2557->bulk_read(pTAS2557, pTAS2557->mnCurrentReg, p_kBuf, count);
+                               if (ret < 0)
                                        break;
-                               }                       
-                               
-                               value = (u8)nValue;
-                               if(g_logEnable) dev_info(pTAS2557->dev,
-                                       "TIAUDIO_CMD_REG_READ: nValue=0x%x, value=0x%x\n", 
-                                       nValue, value);
-                               ret = copy_to_user(buf, &value, 1);
-                               if (0 != ret) {
+                               ret = copy_to_user(buf, p_kBuf, count);
+                               if (ret != 0) {
                                        /* Failed to copy all the data, exit */
                                        dev_err(pTAS2557->dev, "copy to user fail %d\n", ret);
-                               }       
-                       }else if(count > 1){
-                               p_kBuf = (unsigned char *)kzalloc(count, GFP_KERNEL);
-                               if(p_kBuf != NULL){
-                                       ret = pTAS2557->bulk_read(pTAS2557, pTAS2557->mnCurrentReg, p_kBuf, count);
-                                       if( 0 > ret) {
-                                               dev_err(pTAS2557->dev, "dev bulk read fail %d\n", ret);
-                                       }else{                                          
-                                               ret = copy_to_user(buf, p_kBuf, count);
-                                               if (0 != ret) {
-                                                       /* Failed to copy all the data, exit */
-                                                       dev_err(pTAS2557->dev, "copy to user fail %d\n", ret);
-                                               }
-                                       }
-                                       
-                                       kfree(p_kBuf);
-                               }else{
-                                       dev_err(pTAS2557->dev, "read no mem\n");
                                }
-                       }
-               }
-               break;
-               
-               case TIAUDIO_CMD_PROGRAM:
-               {
-                       if (g_logEnable) dev_info(pTAS2557->dev,
-                                               "TIAUDIO_CMD_PROGRAM: count = %d\n", 
-                                               (int)count);
-
-                       if (count == PROGRAM_BUF_SIZE) {
-                               p_kBuf = (unsigned char *)kzalloc(count, GFP_KERNEL);
-                               if (p_kBuf != NULL) {
-                                       struct TProgram * pProgram = 
-                                               &(pTAS2557->mpFirmware->mpPrograms[pTAS2557->mnCurrentProgram]);
-                                       
-                                       p_kBuf[0] = pTAS2557->mpFirmware->mnPrograms;                                                   
-                                       p_kBuf[1] = pTAS2557->mnCurrentProgram;         
-                                       p_kBuf[2] = pProgram->mnAppMode;        
-                                       p_kBuf[3] = (pProgram->mnBoost&0xff00)>>8;      
-                                       p_kBuf[4] = (pProgram->mnBoost&0x00ff); 
-                                       memcpy(&p_kBuf[5], pProgram->mpName, FW_NAME_SIZE);
-                                       strcpy(&p_kBuf[5+FW_NAME_SIZE], pProgram->mpDescription);
-                                       
-                                       ret = copy_to_user(buf, p_kBuf, count);
-                                       if (0 != ret) {
-                                               /* Failed to copy all the data, exit */
-                                               dev_err(pTAS2557->dev, "copy to user fail %d\n", ret);
-                                       }
-                                       kfree(p_kBuf);
-                               } else
-                                       dev_err(pTAS2557->dev, "read no mem\n");
-                       }else
-                               dev_err(pTAS2557->dev, "read buffer not sufficient\n");
+                               kfree(p_kBuf);
+                       } else
+                               dev_err(pTAS2557->dev, "read no mem\n");
                }
-               break;
-               
-               case TIAUDIO_CMD_CONFIGURATION:
-               {
-                       if (g_logEnable) dev_info(pTAS2557->dev,
-                                               "TIAUDIO_CMD_CONFIGURATION: count = %d\n", 
-                                               (int)count);
-
-                       if(count == CONFIGURATION_BUF_SIZE){
-                               p_kBuf = (unsigned char *)kzalloc(count, GFP_KERNEL);
-                               if(p_kBuf != NULL){
-                                       struct TConfiguration * pConfiguration = 
-                                               &(pTAS2557->mpFirmware->mpConfigurations[pTAS2557->mnCurrentConfiguration]);
-
-                                       p_kBuf[0] = pTAS2557->mpFirmware->mnConfigurations;                                                                                     
-                                       p_kBuf[1] = pTAS2557->mnCurrentConfiguration;                                   
-                                       memcpy(&p_kBuf[2], pConfiguration->mpName, FW_NAME_SIZE);
-                                       p_kBuf[2+FW_NAME_SIZE] = pConfiguration->mnProgram;
-                                       p_kBuf[3+FW_NAME_SIZE] = pConfiguration->mnPLL;
-                                       p_kBuf[4+FW_NAME_SIZE] = (pConfiguration->mnSamplingRate&0x000000ff);
-                                       p_kBuf[5+FW_NAME_SIZE] = ((pConfiguration->mnSamplingRate&0x0000ff00)>>8);
-                                       p_kBuf[6+FW_NAME_SIZE] = ((pConfiguration->mnSamplingRate&0x00ff0000)>>16);
-                                       p_kBuf[7+FW_NAME_SIZE] = ((pConfiguration->mnSamplingRate&0xff000000)>>24);
-                                       strcpy(&p_kBuf[8+FW_NAME_SIZE], pConfiguration->mpDescription);
-                                       
-                                       ret = copy_to_user(buf, p_kBuf, count);
-                                       if (0 != ret) {
-                                               /* Failed to copy all the data, exit */
-                                               dev_err(pTAS2557->dev, "copy to user fail %d\n", ret);
-                                       }
-                                       
-                                       kfree(p_kBuf);
-                               }else{
-                                       dev_err(pTAS2557->dev, "read no mem\n");
-                               }                               
-                       }else{
-                               dev_err(pTAS2557->dev, "read buffer not sufficient\n");
-                       }
+       }
+       break;
+
+       case TIAUDIO_CMD_PROGRAM: {
+               if (g_logEnable)
+                       dev_info(pTAS2557->dev, "TIAUDIO_CMD_PROGRAM: count = %d\n", (int)count);
+
+               if (count == PROGRAM_BUF_SIZE) {
+                       p_kBuf = kzalloc(count, GFP_KERNEL);
+                       if (p_kBuf != NULL) {
+                               struct TProgram *pProgram =
+                                       &(pTAS2557->mpFirmware->mpPrograms[pTAS2557->mnCurrentProgram]);
+                               p_kBuf[0] = pTAS2557->mpFirmware->mnPrograms;
+                               p_kBuf[1] = pTAS2557->mnCurrentProgram;
+                               p_kBuf[2] = pProgram->mnAppMode;
+                               p_kBuf[3] = (pProgram->mnBoost&0xff00)>>8;
+                               p_kBuf[4] = (pProgram->mnBoost&0x00ff);
+                               memcpy(&p_kBuf[5], pProgram->mpName, FW_NAME_SIZE);
+                               strlcpy(&p_kBuf[5+FW_NAME_SIZE], pProgram->mpDescription, strlen(pProgram->mpDescription) + 1);
+                               ret = copy_to_user(buf, p_kBuf, count);
+                               if (ret != 0) {
+                                       /* Failed to copy all the data, exit */
+                                       dev_err(pTAS2557->dev, "copy to user fail %d\n", ret);
+                               }
+                               kfree(p_kBuf);
+                       } else
+                               dev_err(pTAS2557->dev, "read no mem\n");
+               } else
+                       dev_err(pTAS2557->dev, "read buffer not sufficient\n");
+       }
+       break;
+
+       case TIAUDIO_CMD_CONFIGURATION: {
+               if (g_logEnable)
+                       dev_info(pTAS2557->dev, "TIAUDIO_CMD_CONFIGURATION: count = %d\n", (int)count);
+               if (count == CONFIGURATION_BUF_SIZE) {
+                       p_kBuf = kzalloc(count, GFP_KERNEL);
+                       if (p_kBuf != NULL) {
+                               struct TConfiguration *pConfiguration =
+                                       &(pTAS2557->mpFirmware->mpConfigurations[pTAS2557->mnCurrentConfiguration]);
+
+                               p_kBuf[0] = pTAS2557->mpFirmware->mnConfigurations;
+                               p_kBuf[1] = pTAS2557->mnCurrentConfiguration;
+                               memcpy(&p_kBuf[2], pConfiguration->mpName, FW_NAME_SIZE);
+                               p_kBuf[2+FW_NAME_SIZE] = pConfiguration->mnProgram;
+                               p_kBuf[3+FW_NAME_SIZE] = pConfiguration->mnPLL;
+                               p_kBuf[4+FW_NAME_SIZE] = (pConfiguration->mnSamplingRate&0x000000ff);
+                               p_kBuf[5+FW_NAME_SIZE] = ((pConfiguration->mnSamplingRate&0x0000ff00)>>8);
+                               p_kBuf[6+FW_NAME_SIZE] = ((pConfiguration->mnSamplingRate&0x00ff0000)>>16);
+                               p_kBuf[7+FW_NAME_SIZE] = ((pConfiguration->mnSamplingRate&0xff000000)>>24);
+                               strlcpy(&p_kBuf[8+FW_NAME_SIZE], pConfiguration->mpDescription, strlen(pConfiguration->mpDescription)+1);
+                               ret = copy_to_user(buf, p_kBuf, count);
+                               if (ret != 0) {
+                                       /* Failed to copy all the data, exit */
+                                       dev_err(pTAS2557->dev, "copy to user fail %d\n", ret);
+                               }
+                               kfree(p_kBuf);
+                       } else
+                               dev_err(pTAS2557->dev, "read no mem\n");
+               } else
+                       dev_err(pTAS2557->dev, "read buffer not sufficient\n");
+       }
+       break;
+
+       case TIAUDIO_CMD_FW_TIMESTAMP: {
+               if (g_logEnable)
+                       dev_info(pTAS2557->dev, "TIAUDIO_CMD_FW_TIMESTAMP: count = %d\n", (int)count);
+
+               if (count == 4) {
+                       p_kBuf = kzalloc(count, GFP_KERNEL);
+                       if (p_kBuf != NULL) {
+                               p_kBuf[0] = (pTAS2557->mpFirmware->mnTimeStamp&0x000000ff);
+                               p_kBuf[1] = ((pTAS2557->mpFirmware->mnTimeStamp&0x0000ff00)>>8);
+                               p_kBuf[2] = ((pTAS2557->mpFirmware->mnTimeStamp&0x00ff0000)>>16);
+                               p_kBuf[3] = ((pTAS2557->mpFirmware->mnTimeStamp&0xff000000)>>24);
+                               ret = copy_to_user(buf, p_kBuf, count);
+                               if (ret != 0) {
+                                       /* Failed to copy all the data, exit */
+                                       dev_err(pTAS2557->dev, "copy to user fail %d\n", ret);
+                               }
+                               kfree(p_kBuf);
+                       } else
+                               dev_err(pTAS2557->dev, "read no mem\n");
                }
-               break;
-               
-               case TIAUDIO_CMD_FW_TIMESTAMP:
-               {
-                       if(g_logEnable) dev_info(pTAS2557->dev,
-                                               "TIAUDIO_CMD_FW_TIMESTAMP: count = %d\n", 
-                                               (int)count);
-
-                       if(count == 4){
-                               p_kBuf = (unsigned char *)kzalloc(count, GFP_KERNEL);
-                               if(p_kBuf != NULL){
-                                       p_kBuf[0] = (pTAS2557->mpFirmware->mnTimeStamp&0x000000ff);
-                                       p_kBuf[1] = ((pTAS2557->mpFirmware->mnTimeStamp&0x0000ff00)>>8);
-                                       p_kBuf[2] = ((pTAS2557->mpFirmware->mnTimeStamp&0x00ff0000)>>16);
-                                       p_kBuf[3] = ((pTAS2557->mpFirmware->mnTimeStamp&0xff000000)>>24);
-                                       
-                                       ret = copy_to_user(buf, p_kBuf, count);
-                                       if (0 != ret) {
-                                               /* Failed to copy all the data, exit */
-                                               dev_err(pTAS2557->dev, "copy to user fail %d\n", ret);
-                                       }
-                                       
-                                       kfree(p_kBuf);
-                               }else{
-                                       dev_err(pTAS2557->dev, "read no mem\n");
-                               }       
+       }
+       break;
+
+       case TIAUDIO_CMD_CALIBRATION: {
+               if (g_logEnable)
+                       dev_info(pTAS2557->dev, "TIAUDIO_CMD_CALIBRATION: count = %d\n", (int)count);
+
+               if (count == 1) {
+                       unsigned char curCal = pTAS2557->mnCurrentCalibration;
+
+                       ret = copy_to_user(buf, &curCal, 1);
+                       if (ret != 0) {
+                               /* Failed to copy all the data, exit */
+                               dev_err(pTAS2557->dev, "copy to user fail %d\n", ret);
                        }
                }
-               break;
-               
-               case TIAUDIO_CMD_CALIBRATION:
-               {
-                       if(g_logEnable) dev_info(pTAS2557->dev,
-                                               "TIAUDIO_CMD_CALIBRATION: count = %d\n", 
-                                               (int)count);
-
-                       if(count == 1){
-                               unsigned char curCal = pTAS2557->mnCurrentCalibration;
-                               ret = copy_to_user(buf, &curCal, 1);
-                               if (0 != ret) {
+       }
+       break;
+
+       case TIAUDIO_CMD_SAMPLERATE: {
+               if (g_logEnable)
+                       dev_info(pTAS2557->dev, "TIAUDIO_CMD_SAMPLERATE: count = %d\n", (int)count);
+               if (count == 4) {
+                       p_kBuf = kzalloc(count, GFP_KERNEL);
+                       if (p_kBuf != NULL) {
+                               struct TConfiguration *pConfiguration =
+                                       &(pTAS2557->mpFirmware->mpConfigurations[pTAS2557->mnCurrentConfiguration]);
+
+                               p_kBuf[0] = (pConfiguration->mnSamplingRate&0x000000ff);
+                               p_kBuf[1] = ((pConfiguration->mnSamplingRate&0x0000ff00)>>8);
+                               p_kBuf[2] = ((pConfiguration->mnSamplingRate&0x00ff0000)>>16);
+                               p_kBuf[3] = ((pConfiguration->mnSamplingRate&0xff000000)>>24);
+
+                               ret = copy_to_user(buf, p_kBuf, count);
+                               if (ret != 0) {
                                        /* Failed to copy all the data, exit */
                                        dev_err(pTAS2557->dev, "copy to user fail %d\n", ret);
-                               }       
-                       }
-               }
-               break;
-               
-               case TIAUDIO_CMD_SAMPLERATE:
-               {
-                       if(g_logEnable) dev_info(pTAS2557->dev,
-                                               "TIAUDIO_CMD_SAMPLERATE: count = %d\n", 
-                                               (int)count);
-                       if(count == 4){
-                               p_kBuf = (unsigned char *)kzalloc(count, GFP_KERNEL);
-                               if(p_kBuf != NULL){                             
-                                       struct TConfiguration *pConfiguration = 
-                                               &(pTAS2557->mpFirmware->mpConfigurations[pTAS2557->mnCurrentConfiguration]);
-
-                                       p_kBuf[0] = (pConfiguration->mnSamplingRate&0x000000ff);
-                                       p_kBuf[1] = ((pConfiguration->mnSamplingRate&0x0000ff00)>>8);
-                                       p_kBuf[2] = ((pConfiguration->mnSamplingRate&0x00ff0000)>>16);
-                                       p_kBuf[3] = ((pConfiguration->mnSamplingRate&0xff000000)>>24);
-                                       
-                                       ret = copy_to_user(buf, p_kBuf, count);
-                                       if (0 != ret) {
-                                               /* Failed to copy all the data, exit */
-                                               dev_err(pTAS2557->dev, "copy to user fail %d\n", ret);
-                                       }
-                                       
-                                       kfree(p_kBuf);
-                               }else{
-                                       dev_err(pTAS2557->dev, "read no mem\n");
-                               }       
-                       }
+                               }
+
+                               kfree(p_kBuf);
+                       } else
+                               dev_err(pTAS2557->dev, "read no mem\n");
                }
-               break;
-               
-               case TIAUDIO_CMD_BITRATE:
-               {
-                       if(g_logEnable) dev_info(pTAS2557->dev,
-                                               "TIAUDIO_CMD_BITRATE: count = %d\n", 
-                                               (int)count);
-
-                       if(count == 1){
-                               unsigned int dac_format = 0;
-                               unsigned char bitRate = 0;
-                               ret = pTAS2557->read(pTAS2557, 
-                                       TAS2557_ASI1_DAC_FORMAT_REG, &dac_format);
-                               if(ret >=0){    
-                                       bitRate = (dac_format&0x18)>>3;
-                                       if(bitRate == 0) bitRate = 16;
-                                       else if(bitRate == 1) bitRate = 20;
-                                       else if(bitRate == 2) bitRate = 24;
-                                       else if(bitRate == 3) bitRate = 32;
-                                       ret = copy_to_user(buf, &bitRate, 1);
-                                       if (0 != ret) {
+       }
+       break;
+
+       case TIAUDIO_CMD_BITRATE: {
+               if (g_logEnable)
+                       dev_info(pTAS2557->dev,
+                                       "TIAUDIO_CMD_BITRATE: count = %d\n", (int)count);
+
+               if (count == 1) {
+                       unsigned char bitRate = 0;
+                       ret = tas2557_get_bit_rate(pTAS2557, &bitRate);
+                       if (ret >= 0) {
+                               ret = copy_to_user(buf, &bitRate, 1);
+                               if (ret != 0) {
                                        /* Failed to copy all the data, exit */
-                                               dev_err(pTAS2557->dev, "copy to user fail %d\n", ret);
-                                       }
-                               }                                       
+                                       dev_err(pTAS2557->dev, "copy to user fail %d\n", ret);
+                               }
                        }
                }
-               break;
-               
-               case TIAUDIO_CMD_DACVOLUME:
-               {
-                       if(g_logEnable) dev_info(pTAS2557->dev,
-                                               "TIAUDIO_CMD_DACVOLUME: count = %d\n", 
-                                               (int)count);
-
-                       if(count == 1){
-                               unsigned int value = 0;
-                               unsigned char volume = 0;
-                               ret = pTAS2557->read(pTAS2557, 
-                                       TAS2557_SPK_CTRL_REG, &value);
-                               if(ret >=0){    
-                                       volume = (value&0x78)>>3;                                       
-                                       ret = copy_to_user(buf, &volume, 1);
-                                       if (0 != ret) {
-                                       /* Failed to copy all the data, exit */
-                                               dev_err(pTAS2557->dev, "copy to user fail %d\n", ret);
-                                       }
-                               }                                       
+       }
+       break;
+
+       case TIAUDIO_CMD_DACVOLUME: {
+               if (g_logEnable)
+                       dev_info(pTAS2557->dev, "TIAUDIO_CMD_DACVOLUME: count = %d\n", (int)count);
+
+               if (count == 1) {
+                       unsigned char volume = 0;
+
+                       ret = tas2557_get_DAC_gain(pTAS2557, &volume);
+                       if (ret >= 0) {
+                               ret = copy_to_user(buf, &volume, 1);
+                               if (ret != 0) {
+                               /* Failed to copy all the data, exit */
+                                       dev_err(pTAS2557->dev, "copy to user fail %d\n", ret);
+                               }
                        }
                }
-               break;
        }
-        pTAS2557->mnDBGCmd = 0;
+       break;
+       }
+       pTAS2557->mnDBGCmd = 0;
 
-       mutex_unlock(&pTAS2557->file_lock); 
+       mutex_unlock(&pTAS2557->file_lock);
        return count;
 }
 
@@ -370,202 +294,165 @@ static ssize_t tas2557_file_write(struct file *file, const char *buf, size_t cou
 {
        struct tas2557_priv *pTAS2557 = (struct tas2557_priv *)file->private_data;
        int ret = 0;
-//     unsigned int value = 0;
        unsigned char *p_kBuf = NULL;
        unsigned int reg = 0;
        unsigned int len = 0;
 
        mutex_lock(&pTAS2557->file_lock);
-               
-       p_kBuf = (unsigned char *)kzalloc(count, GFP_KERNEL);
-       if(p_kBuf == NULL) {
+
+       p_kBuf = kzalloc(count, GFP_KERNEL);
+       if (p_kBuf == NULL) {
                dev_err(pTAS2557->dev, "write no mem\n");
                goto err;
        }
-       
+
        ret = copy_from_user(p_kBuf, buf, count);
-       if (0 != ret) {
-               dev_err(pTAS2557->dev,"copy_from_user failed.\n");
+       if (ret != 0) {
+               dev_err(pTAS2557->dev, "copy_from_user failed.\n");
                goto err;
        }
 
        pTAS2557->mnDBGCmd = p_kBuf[0];
-       switch(pTAS2557->mnDBGCmd)
-       {
-               case TIAUDIO_CMD_REG_WITE:
-               if(count > 5){
-                       reg = ((unsigned int)p_kBuf[1] << 24) + 
-                               ((unsigned int)p_kBuf[2] << 16) + 
-                               ((unsigned int)p_kBuf[3] << 8) + 
-                               (unsigned int)p_kBuf[4];
+       switch (pTAS2557->mnDBGCmd) {
+       case TIAUDIO_CMD_REG_WITE:
+               if (count > 5) {
+                       reg = ((unsigned int)p_kBuf[1] << 24)
+                               + ((unsigned int)p_kBuf[2] << 16)
+                               + ((unsigned int)p_kBuf[3] << 8)
+                               + (unsigned int)p_kBuf[4];
                        len = count - 5;
-                       if(len == 1){
+                       if (len == 1) {
                                ret = pTAS2557->write(pTAS2557, reg, p_kBuf[5]);
-                               if(g_logEnable)
-                                       dev_info(pTAS2557->dev, 
-                                       "TIAUDIO_CMD_REG_WITE, Reg=0x%x, Val=0x%x\n", 
-                                       reg, p_kBuf[5]);
-                       }else{
+                               if (g_logEnable)
+                                       dev_info(pTAS2557->dev, "TIAUDIO_CMD_REG_WITE, Reg=0x%x, Val=0x%x\n", reg, p_kBuf[5]);
+                       } else
                                ret = pTAS2557->bulk_write(pTAS2557, reg, &p_kBuf[5], len);
-                       }
-               }else{
-                       dev_err(pTAS2557->dev,"%s, write len fail, count=%d.\n", 
-                               __FUNCTION__, (int)count);
-               }
+               } else
+                       dev_err(pTAS2557->dev, "%s, write len fail, count=%d.\n", __func__, (int)count);
                pTAS2557->mnDBGCmd = 0;
-               break;
-               
-               case TIAUDIO_CMD_REG_READ:
-               if(count == 5){
-                       pTAS2557->mnCurrentReg = ((unsigned int)p_kBuf[1] << 24) + 
-                               ((unsigned int)p_kBuf[2] << 16) + 
-                               ((unsigned int)p_kBuf[3] << 8)  + 
-                               (unsigned int)p_kBuf[4];                
-                       if(g_logEnable){
-                               dev_info(pTAS2557->dev,
-                                       "TIAUDIO_CMD_REG_READ, whole=0x%x\n", 
-                                       pTAS2557->mnCurrentReg);
-                       }       
-               }else{
-                       dev_err(pTAS2557->dev,"read len fail.\n");
-               }                       
-               break;
-               
-               case TIAUDIO_CMD_DEBUG_ON:
-               {
-                       if(count == 2){
-                               g_logEnable = p_kBuf[1];
-                       }
+       break;
+
+       case TIAUDIO_CMD_REG_READ:
+               if (count == 5) {
+                       pTAS2557->mnCurrentReg = ((unsigned int)p_kBuf[1] << 24)
+                               + ((unsigned int)p_kBuf[2] << 16)
+                               + ((unsigned int)p_kBuf[3] << 8)
+                               + (unsigned int)p_kBuf[4];
+                       if (g_logEnable)
+                               dev_info(pTAS2557->dev, "TIAUDIO_CMD_REG_READ whole=0x%x\n", pTAS2557->mnCurrentReg);
+               } else
+                       dev_err(pTAS2557->dev, "read len fail.\n");
+       break;
+
+       case TIAUDIO_CMD_DEBUG_ON:
+               if (count == 2)
+                       g_logEnable = p_kBuf[1];
+
+               pTAS2557->mnDBGCmd = 0;
+       break;
+
+       case TIAUDIO_CMD_PROGRAM:
+               if (count == 2) {
+                       if (g_logEnable)
+                               dev_info(pTAS2557->dev, "TIAUDIO_CMD_PROGRAM, set to %d\n", p_kBuf[1]);
+                       tas2557_set_program(pTAS2557, p_kBuf[1], -1);
                        pTAS2557->mnDBGCmd = 0;
                }
-               break;
-                       
-               case TIAUDIO_CMD_PROGRAM:
-               {
-                       if(count == 2){
-                               if(g_logEnable)
-                                       dev_info(pTAS2557->dev, 
-                                       "TIAUDIO_CMD_PROGRAM, set to %d\n", 
-                                       p_kBuf[1]);
-                               tas2557_set_program(pTAS2557, p_kBuf[1]);
-                               pTAS2557->mnDBGCmd = 0;
-                       }
-               }
-               break;
-               
-               case TIAUDIO_CMD_CONFIGURATION:
-               {
-                       if(count == 2){
-                               if(g_logEnable)
-                                       dev_info(pTAS2557->dev, 
-                                       "TIAUDIO_CMD_CONFIGURATION, set to %d\n", 
-                                       p_kBuf[1]);
-                               tas2557_set_config(pTAS2557, p_kBuf[1]);
-                               pTAS2557->mnDBGCmd = 0;
-                       }
+       break;
+
+       case TIAUDIO_CMD_CONFIGURATION:
+               if (count == 2) {
+                       if (g_logEnable)
+                               dev_info(pTAS2557->dev, "TIAUDIO_CMD_CONFIGURATION, set to %d\n", p_kBuf[1]);
+                       tas2557_set_config(pTAS2557, p_kBuf[1]);
+                       pTAS2557->mnDBGCmd = 0;
                }
-               break;  
-               
-               case TIAUDIO_CMD_FW_TIMESTAMP:
-               /*let go*/
-               break;
-               
-               case TIAUDIO_CMD_CALIBRATION:
-               {
-                       if(count == 2){
-                               if(g_logEnable)
-                                       dev_info(pTAS2557->dev, 
-                                       "TIAUDIO_CMD_CALIBRATION, set to %d\n", 
-                                       p_kBuf[1]);
-                               tas2557_set_calibration(pTAS2557, p_kBuf[1]);
-                               pTAS2557->mnDBGCmd = 0;
-                       }
+       break;
+
+       case TIAUDIO_CMD_FW_TIMESTAMP:
+       /*let go*/
+       break;
+
+       case TIAUDIO_CMD_CALIBRATION:
+               if (count == 2) {
+                       if (g_logEnable)
+                               dev_info(pTAS2557->dev, "TIAUDIO_CMD_CALIBRATION, set to %d\n", p_kBuf[1]);
+                       tas2557_set_calibration(pTAS2557, p_kBuf[1]);
+                       pTAS2557->mnDBGCmd = 0;
                }
-               break;
-               
-               case TIAUDIO_CMD_SAMPLERATE:
-               {
-                       if(count == 5){
-                               unsigned int nSampleRate = ((unsigned int)p_kBuf[1] << 24) + 
-                                       ((unsigned int)p_kBuf[2] << 16) + 
-                                       ((unsigned int)p_kBuf[3] << 8)  + 
-                                       (unsigned int)p_kBuf[4];        
-                               if(g_logEnable)
-                                       dev_info(pTAS2557->dev, 
-                                       "TIAUDIO_CMD_SAMPLERATE, set to %d\n", 
-                                       nSampleRate);
-
-                               tas2557_set_sampling_rate(pTAS2557, nSampleRate);
-                       }
+       break;
+
+       case TIAUDIO_CMD_SAMPLERATE:
+               if (count == 5) {
+                       unsigned int nSampleRate = ((unsigned int)p_kBuf[1] << 24) +
+                               ((unsigned int)p_kBuf[2] << 16) +
+                               ((unsigned int)p_kBuf[3] << 8) +
+                               (unsigned int)p_kBuf[4];
+                       if (g_logEnable)
+                               dev_info(pTAS2557->dev, "TIAUDIO_CMD_SAMPLERATE, set to %d\n", nSampleRate);
+
+                       tas2557_set_sampling_rate(pTAS2557, nSampleRate);
                }
-               break;
-               
-               case TIAUDIO_CMD_BITRATE:
-               {
-                       if(count == 2){
-                               if(g_logEnable)
-                                       dev_info(pTAS2557->dev, 
-                                       "TIAUDIO_CMD_BITRATE, set to %d\n", 
-                                       p_kBuf[1]);
-
-                               tas2557_set_bit_rate(pTAS2557, p_kBuf[1]);
-                       }
+       break;
+
+       case TIAUDIO_CMD_BITRATE:
+               if (count == 2) {
+                       if (g_logEnable)
+                               dev_info(pTAS2557->dev, "TIAUDIO_CMD_BITRATE, set to %d\n", p_kBuf[1]);
+
+                       tas2557_set_bit_rate(pTAS2557, p_kBuf[1]);
                }
-               break;
-               
-               case TIAUDIO_CMD_DACVOLUME:
-               {
-                       if(count == 2){
-                               unsigned char volume = (p_kBuf[1] & 0x0f);
-                               if(g_logEnable)
-                                       dev_info(pTAS2557->dev, 
-                                       "TIAUDIO_CMD_DACVOLUME, set to %d\n", 
-                                       volume);
-
-                               pTAS2557->update_bits(pTAS2557, 
-                                       TAS2557_SPK_CTRL_REG, 0x78, volume<<3);
-                       }
+       break;
+
+       case TIAUDIO_CMD_DACVOLUME:
+               if (count == 2) {
+                       unsigned char volume;
+
+                       volume = (p_kBuf[1] & 0x0f);
+                       if (g_logEnable)
+                               dev_info(pTAS2557->dev, "TIAUDIO_CMD_DACVOLUME, set to %d\n", volume);
+
+                       tas2557_set_DAC_gain(pTAS2557, volume);
                }
-               break;
-               
-               case TIAUDIO_CMD_SPEAKER:
-               {
-                       if(count == 2){
-                               if(g_logEnable)
-                                       dev_info(pTAS2557->dev, 
-                                       "TIAUDIO_CMD_SPEAKER, set to %d\n", 
-                                       p_kBuf[1]);
-                               tas2557_enable(pTAS2557, (p_kBuf[1]>0));
-                       }
+       break;
+
+       case TIAUDIO_CMD_SPEAKER:
+               if (count == 2) {
+                       if (g_logEnable)
+                               dev_info(pTAS2557->dev, "TIAUDIO_CMD_SPEAKER, set to %d\n", p_kBuf[1]);
+                       tas2557_enable(pTAS2557, (p_kBuf[1] > 0));
                }
-               break;
-
-               case TIAUDIO_CMD_FW_RELOAD:
-               {
-                       if(count == 1){
-                               ret = request_firmware_nowait(THIS_MODULE, 1, TAS2557_FW_NAME,
-                                       pTAS2557->dev, GFP_KERNEL, pTAS2557, tas2557_fw_ready);
-                                       
-                               if(g_logEnable) 
-                                       dev_info(pTAS2557->dev,
-                                               "TIAUDIO_CMD_FW_RELOAD: ret = %d\n", 
-                                               ret);                                   
-                       }
-                               
+       break;
+
+       case TIAUDIO_CMD_FW_RELOAD:
+               if (count == 1) {
+                       const char *pFWName;
+                       if (pTAS2557->mnPGID == TAS2557_PG_VERSION_2P1)
+                               pFWName = TAS2557_FW_NAME;
+                       else if (pTAS2557->mnPGID == TAS2557_PG_VERSION_1P0)
+                               pFWName = TAS2557_PG1P0_FW_NAME;
+                       else
+                               break;
+
+                       ret = request_firmware_nowait(THIS_MODULE, 1, pFWName,
+                               pTAS2557->dev, GFP_KERNEL, pTAS2557, tas2557_fw_ready);
+
+                       if (g_logEnable)
+                               dev_info(pTAS2557->dev, "TIAUDIO_CMD_FW_RELOAD: ret = %d\n", ret);
                }
-               break;
-               
-               default:
-                       pTAS2557->mnDBGCmd = 0;
-               break;
+       break;
+
+       default:
+               pTAS2557->mnDBGCmd = 0;
+       break;
        }
 
 err:
-       if(p_kBuf != NULL)
+       if (p_kBuf != NULL)
                kfree(p_kBuf);
-       
+
        mutex_unlock(&pTAS2557->file_lock);
-       
+
        return count;
 }
 
@@ -573,67 +460,63 @@ static long tas2557_file_unlocked_ioctl(struct file *file, unsigned int cmd, uns
 {
        struct tas2557_priv *pTAS2557 = file->private_data;
        int ret = 0;
-       
+
        mutex_lock(&pTAS2557->file_lock);
-               
+
        switch (cmd) {
-               case SMARTPA_SPK_DAC_VOLUME:
-               {
-                       u8 volume = (arg & 0x0f);
-                       pTAS2557->update_bits(pTAS2557, 
-                               TAS2557_SPK_CTRL_REG, 0x78, volume<<3);
-               }               
-               break;
-       
-               case SMARTPA_SPK_POWER_ON:
-               {
-                       tas2557_enable(pTAS2557, true);
-               }
-               break;
-               
-               case SMARTPA_SPK_POWER_OFF:
-               {
-                       tas2557_enable(pTAS2557, false);
-               }               
-               break;
-               
-               case SMARTPA_SPK_SWITCH_PROGRAM:
-               {
-                       tas2557_set_program(pTAS2557, arg);
-               }
-               break;
-               
-               case SMARTPA_SPK_SWITCH_CONFIGURATION:
-               {
-                       tas2557_set_config(pTAS2557, arg);
-               }
-               break;
-               
-               case SMARTPA_SPK_SWITCH_CALIBRATION:
-               {
-                       tas2557_set_calibration(pTAS2557, arg);
-               }
-               break;
-               
-               case SMARTPA_SPK_SET_SAMPLERATE:
-               {
-                       tas2557_set_sampling_rate(pTAS2557, arg);
-               }
-               break;          
+       case SMARTPA_SPK_DAC_VOLUME:
+       {
+       }
+       break;
 
-               case SMARTPA_SPK_SET_BITRATE:
-               {
-                       tas2557_set_bit_rate(pTAS2557, arg);
-               }
-               break;  
+       case SMARTPA_SPK_POWER_ON:
+       {
+               tas2557_enable(pTAS2557, true);
+       }
+       break;
+
+       case SMARTPA_SPK_POWER_OFF:
+       {
+               tas2557_enable(pTAS2557, false);
+       }
+       break;
+
+       case SMARTPA_SPK_SWITCH_PROGRAM:
+       {
+               tas2557_set_program(pTAS2557, arg, -1);
+       }
+       break;
+
+       case SMARTPA_SPK_SWITCH_CONFIGURATION:
+       {
+               tas2557_set_config(pTAS2557, arg);
+       }
+       break;
+
+       case SMARTPA_SPK_SWITCH_CALIBRATION:
+       {
+               tas2557_set_calibration(pTAS2557, arg);
+       }
+       break;
+
+       case SMARTPA_SPK_SET_SAMPLERATE:
+       {
+               tas2557_set_sampling_rate(pTAS2557, arg);
+       }
+       break;
+
+       case SMARTPA_SPK_SET_BITRATE:
+       {
+               tas2557_set_bit_rate(pTAS2557, arg);
+       }
+       break;
        }
-       
+
        mutex_unlock(&pTAS2557->file_lock);
        return ret;
 }
 
-static struct file_operations fops =
-{
+static const struct file_operations fops = {
        .owner = THIS_MODULE,
        .read = tas2557_file_read,
        .write = tas2557_file_write,
@@ -643,30 +526,28 @@ static struct file_operations fops =
 };
 
 #define MODULE_NAME    "tas2557"
-static struct miscdevice tas2557_misc =
-{
+static struct miscdevice tas2557_misc = {
        .minor = MISC_DYNAMIC_MINOR,
        .name = MODULE_NAME,
        .fops = &fops,
 };
 
-int tas2557_register_misc(struct tas2557_priv * pTAS2557)
+int tas2557_register_misc(struct tas2557_priv *pTAS2557)
 {
        int ret = 0;
-       
+
        g_tas2557 = pTAS2557;
-       
+
        ret = misc_register(&tas2557_misc);
-       if (ret) {
+       if (ret)
                dev_err(pTAS2557->dev, "TAS2557 misc fail: %d\n", ret);
-       }
 
-    dev_info(pTAS2557->dev, "%s, leave\n", __FUNCTION__);
-       
+       dev_info(pTAS2557->dev, "%s, leave\n", __func__);
+
        return ret;
 }
 
-int tas2557_deregister_misc(struct tas2557_priv * pTAS2557)
+int tas2557_deregister_misc(struct tas2557_priv *pTAS2557)
 {
        misc_deregister(&tas2557_misc);
        return 0;
@@ -674,5 +555,5 @@ int tas2557_deregister_misc(struct tas2557_priv * pTAS2557)
 
 MODULE_AUTHOR("Texas Instruments Inc.");
 MODULE_DESCRIPTION("TAS2557 Misc Smart Amplifier driver");
-MODULE_LICENSE("GPLv2");
+MODULE_LICENSE("GPL v2");
 #endif
index a1d95e01c21dcd6391ca3481dfb8d04547dc7f2d..f9994b156a9e327761c03c5113c79ae3c2fadf2f 100755 (executable)
@@ -3,17 +3,13 @@
 ** 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 
+** 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.
 **
-** You should have received a copy of the GNU General Public License along with
-** this program; if not, write to the Free Software Foundation, Inc., 51 Franklin
-** Street, Fifth Floor, Boston, MA 02110-1301, USA.
-**
 ** File:
 **     tas2557-misc.h
 **
@@ -28,8 +24,8 @@
 
 #define        FW_NAME_SIZE                    64
 #define        FW_DESCRIPTION_SIZE             256
-#define        PROGRAM_BUF_SIZE                (5 + FW_NAME_SIZE + FW_DESCRIPTION_SIZE)
-#define        CONFIGURATION_BUF_SIZE  (8 + FW_NAME_SIZE + FW_DESCRIPTION_SIZE)
+#define        PROGRAM_BUF_SIZE                (5 + FW_NAME_SIZE + FW_DESCRIPTION_SIZE)
+#define        CONFIGURATION_BUF_SIZE  (8 + FW_NAME_SIZE + FW_DESCRIPTION_SIZE)
 
 #define        TIAUDIO_CMD_REG_WITE                    1
 #define        TIAUDIO_CMD_REG_READ                    2
 #define        TIAUDIO_CMD_SPEAKER                             11
 #define        TIAUDIO_CMD_FW_RELOAD                   12
 
-#define        TAS2557_MAGIC_NUMBER    0x32353535      /* '2557' */
+#define        TAS2557_MAGIC_NUMBER    0x32353537      /* '2557' */
 
-#define        SMARTPA_SPK_DAC_VOLUME                          _IOWR(TAS2557_MAGIC_NUMBER, 1, unsigned long)
-#define        SMARTPA_SPK_POWER_ON                            _IOWR(TAS2557_MAGIC_NUMBER, 2, unsigned long)
-#define        SMARTPA_SPK_POWER_OFF                           _IOWR(TAS2557_MAGIC_NUMBER, 3, unsigned long)
-#define        SMARTPA_SPK_SWITCH_PROGRAM                      _IOWR(TAS2557_MAGIC_NUMBER, 4, unsigned long)
-#define        SMARTPA_SPK_SWITCH_CONFIGURATION        _IOWR(TAS2557_MAGIC_NUMBER, 5, unsigned long)
-#define        SMARTPA_SPK_SWITCH_CALIBRATION          _IOWR(TAS2557_MAGIC_NUMBER, 6, unsigned long)
-#define        SMARTPA_SPK_SET_SAMPLERATE                      _IOWR(TAS2557_MAGIC_NUMBER, 7, unsigned long)
-#define        SMARTPA_SPK_SET_BITRATE                         _IOWR(TAS2557_MAGIC_NUMBER, 8, unsigned long)
+#define        SMARTPA_SPK_DAC_VOLUME                          _IOWR(TAS2557_MAGIC_NUMBER, 1, unsigned long)
+#define        SMARTPA_SPK_POWER_ON                            _IOWR(TAS2557_MAGIC_NUMBER, 2, unsigned long)
+#define        SMARTPA_SPK_POWER_OFF                           _IOWR(TAS2557_MAGIC_NUMBER, 3, unsigned long)
+#define        SMARTPA_SPK_SWITCH_PROGRAM                      _IOWR(TAS2557_MAGIC_NUMBER, 4, unsigned long)
+#define        SMARTPA_SPK_SWITCH_CONFIGURATION        _IOWR(TAS2557_MAGIC_NUMBER, 5, unsigned long)
+#define        SMARTPA_SPK_SWITCH_CALIBRATION          _IOWR(TAS2557_MAGIC_NUMBER, 6, unsigned long)
+#define        SMARTPA_SPK_SET_SAMPLERATE                      _IOWR(TAS2557_MAGIC_NUMBER, 7, unsigned long)
+#define        SMARTPA_SPK_SET_BITRATE                         _IOWR(TAS2557_MAGIC_NUMBER, 8, unsigned long)
 
-extern int tas2557_register_misc(struct tas2557_priv *pTAS2557);
-extern int tas2557_deregister_misc(struct tas2557_priv *pTAS2557);     
+int tas2557_register_misc(struct tas2557_priv *pTAS2557);
+int tas2557_deregister_misc(struct tas2557_priv *pTAS2557);
 
 #endif /* _TAS2557_MISC_H */
index ed72cb879ee18ef7f1a02e02235a1fa2edbe7cc4..47478cb868dfa49c5e913f26d73d8410c5872bba 100755 (executable)
@@ -3,17 +3,13 @@
 ** 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 
+** 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.
 **
-** You should have received a copy of the GNU General Public License along with
-** this program; if not, write to the Free Software Foundation, Inc., 51 Franklin
-** Street, Fifth Floor, Boston, MA 02110-1301, USA.
-**
 ** File:
 **     tas2557-regmap.c
 **
@@ -41,7 +37,7 @@
 #include <linux/slab.h>
 #include <linux/syscalls.h>
 #include <linux/fcntl.h>
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
 #include "tas2557.h"
 #include "tas2557-core.h"
 
 #include "tas2557-misc.h"
 #endif
 
-#define ENABLE_TILOAD                  //only enable this for in-system tuning or debug, not for production systems
+#define ENABLE_TILOAD
 #ifdef ENABLE_TILOAD
 #include "tiload.h"
 #endif
 
-static void tas2557_change_book_page(struct tas2557_priv *pTAS2557, unsigned char nBook,
+#define LOW_TEMPERATURE_GAIN 6
+
+static int tas2557_change_book_page(
+       struct tas2557_priv *pTAS2557,
+       unsigned char nBook,
        unsigned char nPage)
 {
+       int nResult = 0;
+
        if ((pTAS2557->mnCurrentBook == nBook) 
-               && pTAS2557->mnCurrentPage == nPage){
-               return;
-       }
+               && pTAS2557->mnCurrentPage == nPage)
+               goto end;
 
        if (pTAS2557->mnCurrentBook != nBook) {
-               regmap_write(pTAS2557->mpRegmap, TAS2557_BOOKCTL_PAGE, 0);
+               nResult = regmap_write(pTAS2557->mpRegmap, TAS2557_BOOKCTL_PAGE, 0);
+               if (nResult < 0) {
+                       dev_err(pTAS2557->dev, "%s, %d, I2C error %d\n",
+                               __func__, __LINE__, nResult);
+                       goto end;
+               }
                pTAS2557->mnCurrentPage = 0;
-               regmap_write(pTAS2557->mpRegmap, TAS2557_BOOKCTL_REG, nBook);
+               nResult = regmap_write(pTAS2557->mpRegmap, TAS2557_BOOKCTL_REG, nBook);
+               if (nResult < 0) {
+                       dev_err(pTAS2557->dev, "%s, %d, I2C error %d\n",
+                               __func__, __LINE__, nResult);
+                       goto end;
+               }
                pTAS2557->mnCurrentBook = nBook;
                if (nPage != 0) {
-                       regmap_write(pTAS2557->mpRegmap, TAS2557_BOOKCTL_PAGE, nPage);
+                       nResult = regmap_write(pTAS2557->mpRegmap, TAS2557_BOOKCTL_PAGE, nPage);
+                       if (nResult < 0) {
+                               dev_err(pTAS2557->dev, "%s, %d, I2C error %d\n",
+                                       __func__, __LINE__, nResult);
+                               goto end;
+                       }
                        pTAS2557->mnCurrentPage = nPage;
                }
        } else if (pTAS2557->mnCurrentPage != nPage) {
-               regmap_write(pTAS2557->mpRegmap, TAS2557_BOOKCTL_PAGE, nPage);
+               nResult = regmap_write(pTAS2557->mpRegmap, TAS2557_BOOKCTL_PAGE, nPage);
+               if (nResult < 0) {
+                       dev_err(pTAS2557->dev, "%s, %d, I2C error %d\n",
+                               __func__, __LINE__, nResult);
+                       goto end;
+               }
                pTAS2557->mnCurrentPage = nPage;
        }
+
+end:
+
+       return nResult;
 }
 
-static int tas2557_dev_read(struct tas2557_priv *pTAS2557,
-       unsigned int nRegister, unsigned int *pValue)
+static int tas2557_dev_read(
+       struct tas2557_priv *pTAS2557,
+       unsigned int nRegister,
+       unsigned int *pValue)
 {
-       int ret = 0;
+       int nResult = 0;
+       unsigned int Value = 0;
+
+       mutex_lock(&pTAS2557->dev_lock);
 
-       mutex_lock(&pTAS2557->dev_lock);        
-       
        if (pTAS2557->mbTILoadActive) {
-               if (!(nRegister & 0x80000000)){
-                       mutex_unlock(&pTAS2557->dev_lock);
-                       return 0;                       // let only reads from TILoad pass.
-               }
+               if (!(nRegister & 0x80000000))
+                       goto end; /* let only reads from TILoad pass. */
                nRegister &= ~0x80000000;
+
+               dev_dbg(pTAS2557->dev, "TiLoad R REG B[%d]P[%d]R[%d]\n",
+                               TAS2557_BOOK_ID(nRegister),
+                               TAS2557_PAGE_ID(nRegister),
+                               TAS2557_PAGE_REG(nRegister));
        }
 
-/*     
-       dev_dbg(pTAS2557->dev, "%s: BOOK:PAGE:REG %u:%u:%u\n", __func__,
-               TAS2557_BOOK_ID(nRegister), TAS2557_PAGE_ID(nRegister),
-               TAS2557_PAGE_REG(nRegister));
-*/
-       tas2557_change_book_page(pTAS2557, TAS2557_BOOK_ID(nRegister),
-               TAS2557_PAGE_ID(nRegister));
-       ret = regmap_read(pTAS2557->mpRegmap, TAS2557_PAGE_REG(nRegister), pValue);
+       nResult = tas2557_change_book_page(pTAS2557, 
+                               TAS2557_BOOK_ID(nRegister),
+                               TAS2557_PAGE_ID(nRegister));
+       if (nResult >= 0) {
+               nResult = regmap_read(pTAS2557->mpRegmap, TAS2557_PAGE_REG(nRegister), &Value);
+               if (nResult < 0) {
+                       dev_err(pTAS2557->dev, "%s, %d, I2C error %d\n",
+                               __func__, __LINE__, nResult);
+                       goto end;
+               }
+               *pValue = Value;
+       }
+
+end:
 
        mutex_unlock(&pTAS2557->dev_lock);
-       return ret;
+       return nResult;
 }
 
-static int tas2557_dev_write(struct tas2557_priv *pTAS2557,
-       unsigned int nRegister, unsigned int nValue)
+static int tas2557_dev_write(
+       struct tas2557_priv *pTAS2557,
+       unsigned int nRegister,
+       unsigned int nValue)
 {
-       int ret = 0;
-       
+       int nResult = 0;
+
        mutex_lock(&pTAS2557->dev_lock);
        if ((nRegister == 0xAFFEAFFE) && (nValue == 0xBABEBABE)) {
                pTAS2557->mbTILoadActive = true;
-               mutex_unlock(&pTAS2557->dev_lock);
-               return 0;
+               goto end;
        }
 
        if ((nRegister == 0xBABEBABE) && (nValue == 0xAFFEAFFE)) {
                pTAS2557->mbTILoadActive = false;
-               mutex_unlock(&pTAS2557->dev_lock);
-               return 0;
+               goto end;
        }
 
        if (pTAS2557->mbTILoadActive) {
-               if (!(nRegister & 0x80000000)){
-                       mutex_unlock(&pTAS2557->dev_lock);
-                       return 0;                       // let only writes from TILoad pass.
-               }
+               if (!(nRegister & 0x80000000))
+                       goto end;/* let only writes from TILoad pass. */
                nRegister &= ~0x80000000;
+
+               dev_dbg(pTAS2557->dev, "TiLoad W REG B[%d]P[%d]R[%d] =0x%x\n",
+                                               TAS2557_BOOK_ID(nRegister),
+                                               TAS2557_PAGE_ID(nRegister),
+                                               TAS2557_PAGE_REG(nRegister),
+                                               nValue);
+       }
+
+       nResult = tas2557_change_book_page(pTAS2557,
+                               TAS2557_BOOK_ID(nRegister),
+                               TAS2557_PAGE_ID(nRegister));
+       if (nResult >= 0) {
+               nResult = regmap_write(pTAS2557->mpRegmap, TAS2557_PAGE_REG(nRegister), nValue);
+               if (nResult < 0)
+                       dev_err(pTAS2557->dev, "%s, %d, I2C error %d\n",
+                               __func__, __LINE__, nResult);
        }
 
-       tas2557_change_book_page(pTAS2557, TAS2557_BOOK_ID(nRegister),
-               TAS2557_PAGE_ID(nRegister));
-//  dev_err(codec->dev, "%s: BOOK:PAGE:REG %u:%u:%u, VAL: 0x%02x\n",
-//      __func__, TAS2557_BOOK_ID(nRegister), TAS2557_PAGE_ID(nRegister),
-//      TAS2557_PAGE_REG(nRegister), value);
-       ret = regmap_write(pTAS2557->mpRegmap, TAS2557_PAGE_REG(nRegister),
-               nValue);
-       mutex_unlock(&pTAS2557->dev_lock);              
-       
-       return ret;
+end:
+
+       mutex_unlock(&pTAS2557->dev_lock);
+
+       return nResult;
 }
 
-static int tas2557_dev_bulk_read(struct tas2557_priv *pTAS2557,
-       unsigned int nRegister, u8 * pData, unsigned int nLength)
+static int tas2557_dev_bulk_read(
+       struct tas2557_priv *pTAS2557,
+       unsigned int nRegister,
+       u8 *pData,
+       unsigned int nLength)
 {
-       int ret = 0;
-       
+       int nResult = 0;
+
        mutex_lock(&pTAS2557->dev_lock);
        if (pTAS2557->mbTILoadActive) {
-               if (!(nRegister & 0x80000000)){
-                       mutex_unlock(&pTAS2557->dev_lock);
-                       return 0;                       // let only writes from TILoad pass.
-               }
+               if (!(nRegister & 0x80000000))
+                       goto end; /* let only writes from TILoad pass. */
+
                nRegister &= ~0x80000000;
+               dev_dbg(pTAS2557->dev, "TiLoad BR REG B[%d]P[%d]R[%d], count=%d\n",
+                               TAS2557_BOOK_ID(nRegister),
+                               TAS2557_PAGE_ID(nRegister),
+                               TAS2557_PAGE_REG(nRegister),
+                               nLength);
+       }
+
+       nResult = tas2557_change_book_page(pTAS2557,
+                               TAS2557_BOOK_ID(nRegister),
+                               TAS2557_PAGE_ID(nRegister));
+       if (nResult >= 0) {
+               nResult = regmap_bulk_read(pTAS2557->mpRegmap, TAS2557_PAGE_REG(nRegister), pData, nLength);
+               if (nResult < 0)
+                       dev_err(pTAS2557->dev, "%s, %d, I2C error %d\n",
+                               __func__, __LINE__, nResult);
        }
 
-       tas2557_change_book_page(pTAS2557, TAS2557_BOOK_ID(nRegister),
-               TAS2557_PAGE_ID(nRegister));
-       ret = regmap_bulk_read(pTAS2557->mpRegmap, TAS2557_PAGE_REG(nRegister),
-               pData, nLength);
-       mutex_unlock(&pTAS2557->dev_lock);      
+end:
 
-       return ret;
+       mutex_unlock(&pTAS2557->dev_lock);
+       return nResult;
 }
 
-static int tas2557_dev_bulk_write(struct tas2557_priv *pTAS2557,
-       unsigned int nRegister, u8 * pData, unsigned int nLength)
+static int tas2557_dev_bulk_write(
+       struct tas2557_priv *pTAS2557,
+       unsigned int nRegister,
+       u8 *pData,
+       unsigned int nLength)
 {
-       int ret = 0;
+       int nResult = 0;
+
        mutex_lock(&pTAS2557->dev_lock);
        if (pTAS2557->mbTILoadActive) {
-               if (!(nRegister & 0x80000000)){
-                       mutex_unlock(&pTAS2557->dev_lock);
-                       return 0;                       // let only writes from TILoad pass.
-               }
+               if (!(nRegister & 0x80000000))
+                       goto end; /* let only writes from TILoad pass. */
+
                nRegister &= ~0x80000000;
+
+               dev_dbg(pTAS2557->dev, "TiLoad BW REG B[%d]P[%d]R[%d], count=%d\n",
+                               TAS2557_BOOK_ID(nRegister),
+                               TAS2557_PAGE_ID(nRegister),
+                               TAS2557_PAGE_REG(nRegister),
+                               nLength);
        }
 
-       tas2557_change_book_page(pTAS2557, TAS2557_BOOK_ID(nRegister),
-               TAS2557_PAGE_ID(nRegister));
-       ret = regmap_bulk_write(pTAS2557->mpRegmap, TAS2557_PAGE_REG(nRegister),
-               pData, nLength);
-       mutex_unlock(&pTAS2557->dev_lock);              
-       
-       return ret;
+       nResult = tas2557_change_book_page( pTAS2557,
+                               TAS2557_BOOK_ID(nRegister),
+                               TAS2557_PAGE_ID(nRegister));
+       if (nResult >= 0) {
+               nResult = regmap_bulk_write(pTAS2557->mpRegmap, TAS2557_PAGE_REG(nRegister), pData, nLength);
+               if (nResult < 0)
+                       dev_err(pTAS2557->dev, "%s, %d, I2C error %d\n",
+                               __func__, __LINE__, nResult);
+       }
+
+end:
+
+       mutex_unlock(&pTAS2557->dev_lock);
+       return nResult;
 }
 
-static int tas2557_dev_update_bits(struct tas2557_priv *pTAS2557,
-       unsigned int nRegister, unsigned int nMask, unsigned int nValue)
+static int tas2557_dev_update_bits(
+       struct tas2557_priv *pTAS2557,
+       unsigned int nRegister,
+       unsigned int nMask,
+       unsigned int nValue)
 {
-       int ret = 0;
-       
+       int nResult = 0;
+
        mutex_lock(&pTAS2557->dev_lock);
-       
+
        if (pTAS2557->mbTILoadActive) {
-               if (!(nRegister & 0x80000000)){
-                       mutex_unlock(&pTAS2557->dev_lock);
-                       return 0;                       // let only writes from TILoad pass.
-               }
+               if (!(nRegister & 0x80000000))
+                       goto end; /* let only writes from TILoad pass. */
+
                nRegister &= ~0x80000000;
+               dev_dbg(pTAS2557->dev, "TiLoad SB REG B[%d]P[%d]R[%d], mask=0x%x, value=0x%x\n",
+                               TAS2557_BOOK_ID(nRegister),
+                               TAS2557_PAGE_ID(nRegister),
+                               TAS2557_PAGE_REG(nRegister),
+                               nMask, nValue);
+       }
+
+       nResult = tas2557_change_book_page( pTAS2557,
+                               TAS2557_BOOK_ID(nRegister),
+                               TAS2557_PAGE_ID(nRegister));
+       if (nResult >= 0) {
+               nResult = regmap_update_bits(pTAS2557->mpRegmap, TAS2557_PAGE_REG(nRegister), nMask, nValue);
+               if (nResult < 0)
+                       dev_err(pTAS2557->dev, "%s, %d, I2C error %d\n",
+                               __func__, __LINE__, nResult);
+       }
+
+end:
+       mutex_unlock(&pTAS2557->dev_lock);
+       return nResult;
+}
+
+int tas2557_enableIRQ(struct tas2557_priv *pTAS2557, bool enable, bool clear)
+{
+       unsigned int nValue;
+       int nResult = 0;
+
+       if (enable) {
+               if (clear) {
+                       nResult = pTAS2557->read(pTAS2557, TAS2557_FLAGS_1, &nValue);
+                       if (nResult >= 0)
+                               nResult = pTAS2557->read(pTAS2557, TAS2557_FLAGS_2, &nValue);
+               }
+
+               if (!pTAS2557->mbIRQEnable) {
+                       if (pTAS2557->mnIRQ != 0)
+                               enable_irq(pTAS2557->mnIRQ);
+                       pTAS2557->mbIRQEnable = true;
+               }
+       } else {
+               if (pTAS2557->mbIRQEnable) {
+                       if (pTAS2557->mnIRQ != 0)
+                               disable_irq_nosync(pTAS2557->mnIRQ);
+                       pTAS2557->mbIRQEnable = false;
+               }
+
+               if (clear) {
+                       nResult = pTAS2557->read(pTAS2557, TAS2557_FLAGS_1, &nValue);
+                       if (nResult >= 0)
+                               nResult = pTAS2557->read(pTAS2557, TAS2557_FLAGS_2, &nValue);
+               }
+       }
+
+       return nResult;
+}
+
+static void tas2557_hw_reset(struct tas2557_priv *pTAS2557)
+{
+#ifdef ENABLE_GPIO_RESET
+       if (gpio_is_valid(pTAS2557->mnResetGPIO)) {
+               devm_gpio_request_one(pTAS2557->dev, pTAS2557->mnResetGPIO,
+                       GPIOF_OUT_INIT_LOW, "TAS2557_RST");
+               msleep(10);
+               gpio_set_value_cansleep(pTAS2557->mnResetGPIO, 1);
+               udelay(1000);
+       }
+#endif
+       pTAS2557->mnCurrentBook = -1;
+       pTAS2557->mnCurrentPage = -1;
+}
+
+static void irq_work_routine(struct work_struct *work)
+{
+       int nResult = 0;
+       unsigned int nDevInt1Status = 0, nDevInt2Status = 0;
+       unsigned int nDevPowerUpFlag = 0, nDevPowerStatus = 0;
+       struct tas2557_priv *pTAS2557 =
+               container_of(work, struct tas2557_priv, irq_work.work);
+
+       if (!pTAS2557->mbPowerUp)
+               return;
+
+       nResult = tas2557_dev_read(pTAS2557, TAS2557_FLAGS_1, &nDevInt1Status);
+       if (nResult >= 0)
+               nResult = tas2557_dev_read(pTAS2557, TAS2557_FLAGS_2, &nDevInt2Status);
+
+       if (nResult < 0)
+               goto program;
+
+       if (((nDevInt1Status & 0xdc) != 0) || ((nDevInt2Status & 0x0c) != 0)) {
+               /* in case of INT_OC, INT_UV, INT_OT, INT_BO, INT_CL, INT_CLK1, INT_CLK2 */
+               dev_err(pTAS2557->dev, "critical error: 0x%x, 0x%x\n", nDevInt1Status, nDevInt2Status);
+               goto program;
+       } else {
+               nResult = tas2557_dev_read(pTAS2557, TAS2557_POWER_UP_FLAG_REG, &nDevPowerUpFlag);
+               if (nResult < 0)
+                       goto program;
+               if ((nDevPowerUpFlag & 0x40) == 0) {
+                       /* Class-D doesn't power on */
+                       nResult = tas2557_dev_read(pTAS2557, TAS2557_POWER_CTRL2_REG, &nDevPowerStatus);
+                       if (nResult < 0)
+                               goto program;
+                       if (nDevPowerStatus & 0x80)
+                               goto program; /* failed to power on the Class-D */
+               }
+
+               dev_dbg(pTAS2557->dev, "%s: INT1=0x%x, INT2=0x%x; PowerUpFlag=0x%x, PwrStatus=0x%x\n",
+                       __func__, nDevInt1Status, nDevInt2Status, nDevPowerUpFlag, nDevPowerStatus);
+       }
+       return;
+
+program:
+       /* hardware reset and reload */
+       tas2557_hw_reset(pTAS2557);
+       tas2557_set_program(pTAS2557, pTAS2557->mnCurrentProgram, pTAS2557->mnCurrentConfiguration);
+}
+
+static irqreturn_t tas2557_irq_handler(int irq, void *dev_id)
+{
+       struct tas2557_priv *pTAS2557 = (struct tas2557_priv *)dev_id;
+
+       tas2557_enableIRQ(pTAS2557, false, false);
+       /* get IRQ status after 100 ms */
+       schedule_delayed_work(&pTAS2557->irq_work, msecs_to_jiffies(100));
+       return IRQ_HANDLED;
+}
+
+static enum hrtimer_restart temperature_timer_func(struct hrtimer *timer)
+{
+       struct tas2557_priv *pTAS2557 = container_of(timer, struct tas2557_priv, mtimer);
+
+       if (pTAS2557->mbPowerUp)
+               schedule_work(&pTAS2557->mtimerwork);
+       return HRTIMER_NORESTART;
+}
+
+static void timer_work_routine(struct work_struct *work)
+{
+       struct tas2557_priv *pTAS2557 = container_of(work, struct tas2557_priv, mtimerwork);
+       int nResult, nTemp;
+
+       if (!pTAS2557->mbPowerUp)
+               goto end;
+
+       nResult = tas2557_get_die_temperature(pTAS2557, &nTemp);
+       if (nResult >= 0) {
+               dev_dbg(pTAS2557->dev, "Die=0x%x, degree=%d\n", nTemp, (nTemp>>23));
+               if ((nTemp & 0x80000000) != 0) {
+                       /* if Die temperature is below ZERO */
+                       if (pTAS2557->mnDevCurrentGain != LOW_TEMPERATURE_GAIN) {
+                               nResult = tas2557_set_DAC_gain(pTAS2557, LOW_TEMPERATURE_GAIN);
+                               if (nResult < 0)
+                                       goto end;
+                               pTAS2557->mnDevCurrentGain = LOW_TEMPERATURE_GAIN;
+                               dev_dbg(pTAS2557->dev, "LOW Temp: set gain to %d\n", LOW_TEMPERATURE_GAIN);
+                       }
+               } else {
+                       /* if Die temperature is above ZERO */
+                       if (pTAS2557->mnDevCurrentGain != pTAS2557->mnDevGain) {
+                               nResult = tas2557_set_DAC_gain(pTAS2557, pTAS2557->mnDevGain);
+                               if (nResult < 0)
+                                       goto end;
+                               pTAS2557->mnDevCurrentGain = pTAS2557->mnDevGain;
+                               dev_dbg(pTAS2557->dev, "LOW Temp: set gain to original\n");
+                       }
+               }
+
+               if (pTAS2557->mbPowerUp)
+                       hrtimer_start(&pTAS2557->mtimer,
+                               ns_to_ktime((u64)LOW_TEMPERATURE_CHECK_PERIOD * NSEC_PER_MSEC), HRTIMER_MODE_REL);
+       }
+
+end:
+       return;
+}
+
+int tas2557_suspend(struct i2c_client *pClient, pm_message_t mesg)
+{
+       struct tas2557_priv *pTAS2557 = i2c_get_clientdata(pClient);
+
+       dev_dbg(pTAS2557->dev, "%s, power status = %d\n", __func__, mesg.event);
+       if (hrtimer_active(&pTAS2557->mtimer)) {
+               dev_dbg(pTAS2557->dev, "cancel die temp timer\n");
+               hrtimer_cancel(&pTAS2557->mtimer);
+       }
+
+       return 0;
+}
+
+int tas2557_resume(struct i2c_client *pClient)
+{
+       struct tas2557_priv *pTAS2557 = i2c_get_clientdata(pClient);
+       struct TProgram *pProgram;
+
+       if (!pTAS2557->mpFirmware->mpPrograms) {
+               dev_dbg(pTAS2557->dev, "%s, firmware not loaded\n", __func__);
+               goto end;
+       }
+
+       if (pTAS2557->mnCurrentProgram >= pTAS2557->mpCalFirmware->mnPrograms) {
+               dev_err(pTAS2557->dev, "%s, firmware corrupted\n", __func__);
+               goto end;
+       }
+
+       pProgram = &(pTAS2557->mpFirmware->mpPrograms[pTAS2557->mnCurrentProgram]);
+       if (pTAS2557->mbPowerUp && (pProgram->mnAppMode == TAS2557_APP_TUNINGMODE)) {
+               dev_dbg(pTAS2557->dev, "%s, start Die Temp check timer\n", __func__);
+               hrtimer_start(&pTAS2557->mtimer,
+                       ns_to_ktime((u64)LOW_TEMPERATURE_CHECK_PERIOD * NSEC_PER_MSEC), HRTIMER_MODE_REL);
        }
-       
-       tas2557_change_book_page(pTAS2557, TAS2557_BOOK_ID(nRegister),
-               TAS2557_PAGE_ID(nRegister));
-       
-       ret = regmap_update_bits(pTAS2557->mpRegmap, TAS2557_PAGE_REG(nRegister), nMask, nValue);
-               
-       mutex_unlock(&pTAS2557->dev_lock);              
-       return ret;
+
+end:
+
+       return 0; 
 }
 
 static bool tas2557_volatile(struct device *pDev, unsigned int nRegister)
@@ -235,90 +518,118 @@ static const struct regmap_config tas2557_i2c_regmap = {
        .max_register = 128,
 };
 
+/* tas2557_i2c_probe :
+* platform dependent
+* should implement hardware reset functionality
+*/
 static int tas2557_i2c_probe(struct i2c_client *pClient,
        const struct i2c_device_id *pID)
 {
        struct tas2557_priv *pTAS2557;
-       int nResult;
+       int nResult = 0;
+       unsigned int nValue = 0;
+       const char *pFWName;
+
+       dev_info(&pClient->dev, "%s enter\n", __func__);
 
-       dev_info(&pClient->dev, "%s enter\n", __FUNCTION__);
-       
        pTAS2557 = devm_kzalloc(&pClient->dev, sizeof(struct tas2557_priv), GFP_KERNEL);
-       if (!pTAS2557)
-               return -ENOMEM;
+       if (!pTAS2557) {
+               nResult = -ENOMEM;
+               goto err;
+       }
 
        pTAS2557->dev = &pClient->dev;
        i2c_set_clientdata(pClient, pTAS2557);
        dev_set_drvdata(&pClient->dev, pTAS2557);
 
-       if (pClient->dev.of_node){
-               tas2557_parse_dt(&pClient->dev, pTAS2557);
-       }
-
-       if (gpio_is_valid(pTAS2557->mnResetGPIO)) {
-#ifdef HW_RESET        //mandatory             
-               devm_gpio_request_one(&pClient->dev, pTAS2557->mnResetGPIO,
-                       GPIOF_OUT_INIT_LOW, "TAS2557_RST");
-               msleep(5);
-               gpio_set_value_cansleep(pTAS2557->mnResetGPIO, 1);
-               mdelay(1);
-#endif         
-       }
-
        pTAS2557->mpRegmap = devm_regmap_init_i2c(pClient, &tas2557_i2c_regmap);
        if (IS_ERR(pTAS2557->mpRegmap)) {
                nResult = PTR_ERR(pTAS2557->mpRegmap);
                dev_err(&pClient->dev, "Failed to allocate register map: %d\n",
                        nResult);
-               return nResult;
+               goto err;
        }
 
+       if (pClient->dev.of_node)
+               tas2557_parse_dt(&pClient->dev, pTAS2557);
+
+       tas2557_hw_reset(pTAS2557);
+
        pTAS2557->read = tas2557_dev_read;
        pTAS2557->write = tas2557_dev_write;
        pTAS2557->bulk_read = tas2557_dev_bulk_read;
        pTAS2557->bulk_write = tas2557_dev_bulk_write;
        pTAS2557->update_bits = tas2557_dev_update_bits;
+       pTAS2557->enableIRQ = tas2557_enableIRQ;
        pTAS2557->set_config = tas2557_set_config;
        pTAS2557->set_calibration = tas2557_set_calibration;
-               
+       pTAS2557->hw_reset = tas2557_hw_reset;
+
        mutex_init(&pTAS2557->dev_lock);
-       
+
        /* Reset the chip */
        nResult = tas2557_dev_write(pTAS2557, TAS2557_SW_RESET_REG, 0x01);
-       if(nResult < 0){
-               dev_err(&pClient->dev, "I2C communication ERROR: %d\n",
-                       nResult);
-               return nResult;
+       if (nResult < 0) {
+               dev_err(&pClient->dev, "I2c fail, %d\n", nResult);
+               goto err;
        }
-       
-       udelay(1000);
 
-       pTAS2557->mpFirmware =
-               devm_kzalloc(&pClient->dev, sizeof(struct TFirmware),
-               GFP_KERNEL);
-       if (!pTAS2557->mpFirmware)
-               return -ENOMEM;
+       msleep(1);
+       tas2557_dev_read(pTAS2557, TAS2557_REV_PGID_REG, &nValue);
+       pTAS2557->mnPGID = nValue;
+       if (pTAS2557->mnPGID == TAS2557_PG_VERSION_2P1) {
+               dev_info(pTAS2557->dev, "PG2.1 Silicon found\n");
+               pFWName = TAS2557_FW_NAME;
+       } else if (pTAS2557->mnPGID == TAS2557_PG_VERSION_1P0) {
+               dev_info(pTAS2557->dev, "PG1.0 Silicon found\n");
+               pFWName = TAS2557_PG1P0_FW_NAME;
+       } else {
+               nResult = -ENOTSUPP;
+               dev_info(pTAS2557->dev, "unsupport Silicon 0x%x\n", pTAS2557->mnPGID);
+               goto err;
+       }
 
-       pTAS2557->mpCalFirmware =
-               devm_kzalloc(&pClient->dev, sizeof(struct TFirmware),
-               GFP_KERNEL);
-       if (!pTAS2557->mpCalFirmware)
-               return -ENOMEM;
+       if (gpio_is_valid(pTAS2557->mnGpioINT)) {
+               nResult = gpio_request(pTAS2557->mnGpioINT, "TAS2557-IRQ");
+               if (nResult < 0) {
+                       dev_err(pTAS2557->dev,
+                               "%s: GPIO %d request INT error\n",
+                               __func__, pTAS2557->mnGpioINT);
+                       goto err;
+               }
 
-       pTAS2557->mnCurrentPage = 0;
-       pTAS2557->mnCurrentBook = 0;
+               gpio_direction_input(pTAS2557->mnGpioINT);
+               pTAS2557->mnIRQ = gpio_to_irq(pTAS2557->mnGpioINT);
+               dev_dbg(pTAS2557->dev, "irq = %d\n", pTAS2557->mnIRQ);
+               INIT_DELAYED_WORK(&pTAS2557->irq_work, irq_work_routine);
+               nResult = request_threaded_irq(pTAS2557->mnIRQ, tas2557_irq_handler,
+                               NULL, IRQF_TRIGGER_RISING | IRQF_ONESHOT,
+                               pClient->name, pTAS2557);
+               if (nResult < 0) {
+                       dev_err(pTAS2557->dev,
+                               "request_irq failed, %d\n", nResult);
+                       goto err;
+               }
+               disable_irq_nosync(pTAS2557->mnIRQ);
+       }
 
-       nResult = tas2557_dev_read(pTAS2557, TAS2557_REV_PGID_REG, &pTAS2557->mnPGID);
-       dev_info(&pClient->dev, "TAS2557 PGID: 0x%02x\n", pTAS2557->mnPGID);
+       pTAS2557->mpFirmware = devm_kzalloc(&pClient->dev, sizeof(struct TFirmware), GFP_KERNEL);
+       if (!pTAS2557->mpFirmware) {
+               nResult = -ENOMEM;
+               goto err;
+       }
 
-       pTAS2557->mbTILoadActive = false;
+       pTAS2557->mpCalFirmware = devm_kzalloc(&pClient->dev, sizeof(struct TFirmware), GFP_KERNEL);
+       if (!pTAS2557->mpCalFirmware) {
+               nResult = -ENOMEM;
+               goto err;
+       }
 
-#ifdef CONFIG_TAS2557_CODEC    
-       mutex_init(&pTAS2557->codec_lock);
+#ifdef CONFIG_TAS2557_CODEC
        tas2557_register_codec(pTAS2557);
 #endif
 
-#ifdef CONFIG_TAS2557_MISC     
+#ifdef CONFIG_TAS2557_MISC
        mutex_init(&pTAS2557->file_lock);
        tas2557_register_misc(pTAS2557);
 #endif
@@ -327,28 +638,34 @@ static int tas2557_i2c_probe(struct i2c_client *pClient,
        tiload_driver_init(pTAS2557);
 #endif
 
-       nResult = request_firmware_nowait(THIS_MODULE, 1, TAS2557_FW_NAME,
-               pTAS2557->dev, GFP_KERNEL, pTAS2557, tas2557_fw_ready);
-               
+       hrtimer_init(&pTAS2557->mtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+       pTAS2557->mtimer.function = temperature_timer_func;
+       INIT_WORK(&pTAS2557->mtimerwork, timer_work_routine);
+
+       nResult = request_firmware_nowait(THIS_MODULE, 1, pFWName,
+                               pTAS2557->dev, GFP_KERNEL, pTAS2557, tas2557_fw_ready);
+
+err:
+
        return nResult;
 }
 
 static int tas2557_i2c_remove(struct i2c_client *pClient)
 {
        struct tas2557_priv *pTAS2557 = i2c_get_clientdata(pClient);
-       
-       dev_info(pTAS2557->dev, "%s\n", __FUNCTION__);
-       
-#ifdef CONFIG_TAS2557_CODEC            
+
+       dev_info(pTAS2557->dev, "%s\n", __func__);
+
+#ifdef CONFIG_TAS2557_CODEC
        tas2557_deregister_codec(pTAS2557);
-       mutex_destroy(&pTAS2557->codec_lock);
 #endif
 
-#ifdef CONFIG_TAS2557_MISC             
+#ifdef CONFIG_TAS2557_MISC
        tas2557_deregister_misc(pTAS2557);
        mutex_destroy(&pTAS2557->file_lock);
 #endif
-       
+
+       mutex_destroy(&pTAS2557->dev_lock);
        return 0;
 }
 
@@ -379,11 +696,13 @@ static struct i2c_driver tas2557_i2c_driver = {
        .probe = tas2557_i2c_probe,
        .remove = tas2557_i2c_remove,
        .id_table = tas2557_i2c_id,
+       .suspend = tas2557_suspend,
+       .resume = tas2557_resume,
 };
 
 module_i2c_driver(tas2557_i2c_driver);
 
 MODULE_AUTHOR("Texas Instruments Inc.");
 MODULE_DESCRIPTION("TAS2557 I2C Smart Amplifier driver");
-MODULE_LICENSE("GPLv2");
+MODULE_LICENSE("GPL v2");
 #endif
\ No newline at end of file
index 609f62822947305f3cfd0bc62df2e7d7b2e70be5..31490c96e46925e169fbc42ecaed05b4a31c2e93 100755 (executable)
--- a/tas2557.h
+++ b/tas2557.h
@@ -3,17 +3,13 @@
 ** 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 
+** 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.
 **
-** You should have received a copy of the GNU General Public License along with
-** this program; if not, write to the Free Software Foundation, Inc., 51 Franklin
-** Street, Fifth Floor, Boston, MA 02110-1301, USA.
-**
 ** File:
 **     tas2557.h
 **
 #ifndef _TAS2557_H
 #define _TAS2557_H
 
+#include <linux/regmap.h>
+#include <linux/workqueue.h>
+#include <linux/timer.h>
+
 /* Page Control Register */
 #define TAS2557_PAGECTL_REG                    0
 
 
 #define TAS2557_POWER_CTRL1_REG                        TAS2557_REG(0, 0, 4)
 #define TAS2557_POWER_CTRL2_REG                        TAS2557_REG(0, 0, 5)
+
 #define TAS2557_SPK_CTRL_REG                   TAS2557_REG(0, 0, 6)
-#define TAS2557_MUTE_REG                               TAS2557_REG(0, 0, 7)
+/* B0P0R6 - TAS2557_SPK_CTRL_REG */
+#define TAS2557_DAC_GAIN_MASK                  (0xf << 3)
+#define TAS2557_DAC_GAIN_SHIFT                 0x03
+
+#define TAS2557_MUTE_REG                       TAS2557_REG(0, 0, 7)
 #define TAS2557_SNS_CTRL_REG                   TAS2557_REG(0, 0, 8)
 #define TAS2557_ADC_INPUT_SEL_REG              TAS2557_REG(0, 0, 9)
 #define TAS2557_DBOOST_CTL_REG                 TAS2557_REG(0, 0, 10)
 #define TAS2557_NONAME18_REG                   TAS2557_REG(0, 0, 18)
 #define TAS2557_SAR_SAMPLING_TIME_REG          TAS2557_REG(0, 0, 19)
 #define TAS2557_SAR_ADC1_REG                   TAS2557_REG(0, 0, 20)
-#define TAS2557_SAR_ADC2_REG                   TAS2557_REG(0, 0, 21)
+#define TAS2557_SAR_ADC2_REG                   TAS2557_REG(0, 0, 21)   /* B0_P0_R0x15*/
 #define TAS2557_CRC_CHECKSUM_REG               TAS2557_REG(0, 0, 32)
 #define TAS2557_CRC_RESET_REG                  TAS2557_REG(0, 0, 33)
 #define TAS2557_DSP_MODE_SELECT_REG            TAS2557_REG(0, 0, 34)
-#define TAS2557_ASI_CTRL_REG                   TAS2557_REG(0, 0, 42)
+#define TAS2557_SAFE_GUARD_REG                 TAS2557_REG(0, 0, 37)
+#define TAS2557_ASI_CTL1_REG                   TAS2557_REG(0, 0, 42)
 #define TAS2557_CLK_ERR_CTRL                   TAS2557_REG(0, 0, 44)
 #define TAS2557_DBOOST_CFG_REG                 TAS2557_REG(0, 0, 52)
 #define TAS2557_POWER_UP_FLAG_REG              TAS2557_REG(0, 0, 100)
-#define TAS2557_FLAGS_1                                TAS2557_REG(0, 0, 104)
-#define TAS2557_FLAGS_2                                TAS2557_REG(0, 0, 108)
+#define TAS2557_FLAGS_1                                TAS2557_REG(0, 0, 104)  /* B0_P0_R0x68*/
+#define TAS2557_FLAGS_2                                TAS2557_REG(0, 0, 108)  /* B0_P0_R0x6c*/
+
 /* Book0, Page1 registers */
 #define TAS2557_ASI1_DAC_FORMAT_REG            TAS2557_REG(0, 1, 1)
 #define TAS2557_ASI1_ADC_FORMAT_REG            TAS2557_REG(0, 1, 2)
 #define TAS2557_ASI2_DAC_CLKOUT_REG            TAS2557_REG(0, 1, 36)
 #define TAS2557_ASI2_ADC_CLKOUT_REG            TAS2557_REG(0, 1, 37)
 
-#define TAS2557_GPIO1_PIN_REG                  TAS2557_REG(0, 1, 61)
-#define TAS2557_GPIO2_PIN_REG                  TAS2557_REG(0, 1, 62)
-#define TAS2557_GPIO3_PIN_REG                  TAS2557_REG(0, 1, 63)
-#define TAS2557_GPIO4_PIN_REG                  TAS2557_REG(0, 1, 64)
+#define TAS2557_GPIO1_PIN_REG                  TAS2557_REG(0, 1, 61)   /*B0_P1_R0x3d */
+#define TAS2557_GPIO2_PIN_REG                  TAS2557_REG(0, 1, 62)   /*B0_P1_R0x3e */
+#define TAS2557_GPIO3_PIN_REG                  TAS2557_REG(0, 1, 63)   /*B0_P1_R0x3f */
+#define TAS2557_GPIO4_PIN_REG                  TAS2557_REG(0, 1, 64)   /*B0_P1_R0x40 */
 #define TAS2557_GPIO5_PIN_REG                  TAS2557_REG(0, 1, 65)
 #define TAS2557_GPIO6_PIN_REG                  TAS2557_REG(0, 1, 66)
 #define TAS2557_GPIO7_PIN_REG                  TAS2557_REG(0, 1, 67)
 #define TAS2557_GPIO9_PIN_REG                  TAS2557_REG(0, 1, 69)
 #define TAS2557_GPIO10_PIN_REG                 TAS2557_REG(0, 1, 70)
 
-#define TAS2557_GPI_PIN_REG                    TAS2557_REG(0, 1, 77)
+#define TAS2557_GPI_PIN_REG                            TAS2557_REG(0, 1, 77)   /*B0_P1_R0x4d */
 #define TAS2557_GPIO_HIZ_CTRL1_REG             TAS2557_REG(0, 1, 79)
 #define TAS2557_GPIO_HIZ_CTRL2_REG             TAS2557_REG(0, 1, 80)
 #define TAS2557_GPIO_HIZ_CTRL3_REG             TAS2557_REG(0, 1, 81)
 #define TAS2557_ASIM_IFACE8_REG                        TAS2557_REG(0, 1, 105)
 #define TAS2557_ASIM_IFACE9_REG                        TAS2557_REG(0, 1, 106)
 
+#define TAS2557_INT_GEN1_REG                   TAS2557_REG(0, 1, 108)  /* B0_P1_R0x6c */
+#define TAS2557_INT_GEN2_REG                   TAS2557_REG(0, 1, 109)
+#define TAS2557_INT_GEN3_REG                   TAS2557_REG(0, 1, 110)  /* B0_P1_R0x6e */
+#define TAS2557_INT_GEN4_REG                   TAS2557_REG(0, 1, 111)  /* B0_P1_R0x6f */
+#define TAS2557_INT_MODE_REG                   TAS2557_REG(0, 1, 114)  /* B0_P1_R0x72 */
+
 #define TAS2557_MAIN_CLKIN_REG                 TAS2557_REG(0, 1, 115)
 #define TAS2557_PLL_CLKIN_REG                  TAS2557_REG(0, 1, 116)
 #define TAS2557_CLKOUT_MUX_REG                 TAS2557_REG(0, 1, 117)
 #define TAS2557_CLKOUT_CDIV_REG                        TAS2557_REG(0, 1, 118)
 
 #define TAS2557_HACK_GP01_REG                  TAS2557_REG(0, 1, 122)
+
 #define TAS2557_HACK01_REG                     TAS2557_REG(0, 2, 10)
 
 #define TAS2557_ISENSE_THRESHOLD               TAS2557_REG(0, 50, 104)
 #define TAS2557_BOOST_HEADROOM                 TAS2557_REG(0, 51, 24)
 #define TAS2557_THERMAL_FOLDBACK_REG   TAS2557_REG(0, 51, 100)
 
-#define TAS2557_VPRED_COMP_REG                 TAS2557_REG(0, 53, 24)
-#define TAS2557_SA_COEFF_SWAP_REG              TAS2557_REG(0, 53, 44)
+#define TAS2557_SA_PG2P1_CHL_CTRL_REG  TAS2557_REG(0, 53, 20)  /* B0_P0x35_R0x14 */
+#define TAS2557_SA_COEFF_SWAP_REG              TAS2557_REG(0, 53, 44)  /* B0_P0x35_R0x2c */
+
+#define TAS2557_SA_PG1P0_CHL_CTRL_REG  TAS2557_REG(0, 58, 120) /* B0_P0x3a_R0x78 */
 
-#define TAS2557_SA_CHL_CTRL_REG                TAS2557_REG(0, 58, 120)
 
 #define TAS2557_TEST_MODE_REG                  TAS2557_REG(0, 253, 13)
+#define TAS2557_BROADCAST_REG                  TAS2557_REG(0, 253, 54)
 #define TAS2557_CRYPTIC_REG                    TAS2557_REG(0, 253, 71)
 
-//#define TAS2557__REG      TAS2557_REG(0, 1, )
-//#define TAS2557__REG      TAS2557_REG(1, 0, )
 #define TAS2557_DAC_INTERPOL_REG               TAS2557_REG(100, 0, 1)
 #define TAS2557_SOFT_MUTE_REG                  TAS2557_REG(100, 0, 7)
 #define TAS2557_PLL_P_VAL_REG                  TAS2557_REG(100, 0, 27)
 #define TAS2557_ISENSE_DIV_REG                 TAS2557_REG(100, 0, 42)
 #define TAS2557_RAMP_CLK_DIV_MSB_REG           TAS2557_REG(100, 0, 43)
 #define TAS2557_RAMP_CLK_DIV_LSB_REG           TAS2557_REG(100, 0, 44)
+
+#define TAS2557_XMEM_44_REG                            TAS2557_REG(130, 2, 64) /* B0x82_P0x02_R0x40 */
+#define TAS2557_DIE_TEMP_REG                   TAS2557_REG(130, 2, 124)        /* B0x82_P0x02_R0x7C */
+
 /* Bits */
 /* B0P0R4 - TAS2557_POWER_CTRL1_REG */
 #define TAS2557_SW_SHUTDOWN                    (0x1 << 0)
 #define TAS2557_BOOST_ENABLE                   (0x1 << 5)
 #define TAS2557_CLASSD_ENABLE                  (0x1 << 7)
 
-/* B0P0R6 - TAS2557_SPK_CTRL_REG */
-#define TAS2557_DAC_GAIN_MASK                  (0xf << 3)
-
 /* B0P0R7 - TAS2557_MUTE_REG */
 #define TAS2557_CLASSD_MUTE                    (0x1 << 0)
 #define TAS2557_ISENSE_MUTE                    (0x1 << 1)
 #define TAS2557_PLL_P_VAL_MASK                 (0x3f << 0)
 
 /* B100P0R28 - TAS2557_PLL_J_VAL_REG */
-#define TAS2557_PLL_J_VAL_MASK                 ((unsigned int ) (0x7f << 0))
+#define TAS2557_PLL_J_VAL_MASK                 ((unsigned int) (0x7f << 0))
 #define TAS2557_PLL_J_VAL_MASKX        0x00
 
 /* B100P0R29-30 - TAS2557_PLL_D_VAL_MSB/LSB_REG */
 #define TAS2557_DSP_CLK_FROM_PLL               (0x1 << 5)
 
 #define TAS2557_FW_NAME     "tas2557_uCDSP.bin"
+#define TAS2557_PG1P0_FW_NAME     "tas2557_pg1p0_uCDSP.bin"
 
-#define LEFT_CHANNEL   0
-#define RIGHT_CHANNEL  1
+#define TAS2557_APP_ROM1MODE   0
+#define TAS2557_APP_ROM2MODE   1
+#define TAS2557_APP_TUNINGMODE 2
 
 struct TBlock {
        unsigned int mnType;
+       unsigned char mbPChkSumPresent;
+       unsigned char mnPChkSum;
+       unsigned char mbYChkSumPresent;
+       unsigned char mnYChkSum;
        unsigned int mnCommands;
        unsigned char *mpData;
 };
@@ -376,26 +397,49 @@ struct tas2557_priv {
        bool mbLoadCalibrationPostPowerUp;
        unsigned int mnPowerCtrl;
        bool mbCalibrationLoaded;
-       int (*read)(struct tas2557_priv * pTAS2557, unsigned int reg,
+       int (*read)(struct tas2557_priv *pTAS2557,
+               unsigned int reg,
                unsigned int *pValue);
-       int (*write)(struct tas2557_priv * pTAS2557, unsigned int reg,
+       int (*write)(struct tas2557_priv *pTAS2557,
+               unsigned int reg,
                unsigned int Value);
-       int (*bulk_read)(struct tas2557_priv * pTAS2557, unsigned int reg,
-               unsigned char *pData, unsigned int len);
-       int (*bulk_write)(struct tas2557_priv * pTAS2557, unsigned int reg,
-               unsigned char *pData, unsigned int len);
-       int (*update_bits)(struct tas2557_priv * pTAS2557, unsigned int reg,
-               unsigned int mask, unsigned int value);
-       int (*set_config)(struct tas2557_priv *pTAS2557, int config);
-       int (*set_calibration)(struct tas2557_priv *pTAS2557, int calibration);
-#ifdef CONFIG_TAS2557_CODEC
-       struct mutex codec_lock;
-#endif
+       int (*bulk_read)(struct tas2557_priv *pTAS2557,
+               unsigned int reg,
+               unsigned char *pData,
+               unsigned int len);
+       int (*bulk_write)(struct tas2557_priv *pTAS2557,
+               unsigned int reg,
+               unsigned char *pData,
+               unsigned int len);
+       int (*update_bits)(struct tas2557_priv *pTAS2557,
+               unsigned int reg,
+               unsigned int mask,
+               unsigned int value);
+       int (*set_config)(struct tas2557_priv *pTAS2557,
+               int config);
+       int (*set_calibration)(struct tas2557_priv *pTAS2557,
+               int calibration);
+       int (*enableIRQ)(struct tas2557_priv *pTAS2557, bool enable, bool clear);
+       void (*hw_reset)(struct tas2557_priv *pTAS2557);
+
+       int mnGpioINT;
+       struct delayed_work irq_work;
+       unsigned int mnIRQ;
+       bool mbIRQEnable;
+       unsigned char mnI2SBits;
+
+       /* for low temperature check */
+       unsigned int mnDevGain;
+       unsigned int mnDevCurrentGain;
+       struct hrtimer mtimer;
+       struct work_struct mtimerwork;
+
 #ifdef CONFIG_TAS2557_MISC
        int mnDBGCmd;
        int mnCurrentReg;
        struct mutex file_lock;
 #endif
+
 };
 
 #endif /* _TAS2557_H */
index 5afe6f7facb50b5f9fcd6453e8595c94f4bb89d7..add7b414be9a8a060fa747b5906242304fc4cfa5 100755 (executable)
--- a/tiload.c
+++ b/tiload.c
@@ -3,17 +3,13 @@
 ** 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 
+** 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.
 **
-** You should have received a copy of the GNU General Public License along with
-** this program; if not, write to the Free Software Foundation, Inc., 51 Franklin
-** Street, Fifth Floor, Boston, MA 02110-1301, USA.
-**
 ** File:
 **     tiload.c
 **
 #include <linux/kdev_t.h>
 #include <linux/cdev.h>
 #include <linux/device.h>
-#include <asm/io.h>
+#include <linux/io.h>
 #include <linux/delay.h>
 #include <linux/i2c.h>
 #include <linux/platform_device.h>
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
 
 #include "tiload.h"
 
 #define DEBUG
 
 static struct cdev *tiload_cdev;
-static int tiload_major = 0;   /* Dynamic allocation of Mjr No. */
-static int tiload_opened = 0;  /* Dynamic allocation of Mjr No. */
+static int tiload_major; /* Dynamic allocation of Mjr No. */
+static int tiload_opened; /* Dynamic allocation of Mjr No. */
 static struct tas2557_priv *g_TAS2557;
 struct class *tiload_class;
-static unsigned int magic_num = 0x00;
+static unsigned int magic_num;
 
-static char gPage = 0;
-static char gBook = 0;
+static char gPage;
+static char gBook;
 /******************************** Debug section *****************************/
 
 
-/*
- *----------------------------------------------------------------------------
+/*----------------------------------------------------------------------------
  * Function : tiload_open
  *
  * Purpose  : open method for tiload programming interface
@@ -65,21 +60,20 @@ static char gBook = 0;
  */
 static int tiload_open(struct inode *in, struct file *filp)
 {
-       struct tas2557_priv *pTAS2557 = g_TAS2557; 
-       
-       dev_info(pTAS2557->dev, "%s\n", __FUNCTION__);
-       
+       struct tas2557_priv *pTAS2557 = g_TAS2557;
+
+       dev_info(pTAS2557->dev, "%s\n", __func__);
+
        if (tiload_opened) {
-               dev_info(pTAS2557->dev,"%s device is already opened\n", "tiload");
-               return -1;
+               dev_info(pTAS2557->dev, "%s device is already opened\n", "tiload");
+               return -EINVAL;
        }
-       filp->private_data = (void*)pTAS2557;
+       filp->private_data = (void *)pTAS2557;
        tiload_opened++;
        return 0;
 }
 
-/*
- *----------------------------------------------------------------------------
+/*----------------------------------------------------------------------------
  * Function : tiload_release
  *
  * Purpose  : close method for tiload programming interface
@@ -88,47 +82,44 @@ static int tiload_open(struct inode *in, struct file *filp)
 static int tiload_release(struct inode *in, struct file *filp)
 {
        struct tas2557_priv *pTAS2557 = (struct tas2557_priv *)filp->private_data;
-       
-       dev_info(pTAS2557->dev, "%s\n", __FUNCTION__);
+
+       dev_info(pTAS2557->dev, "%s\n", __func__);
        filp->private_data = NULL;
        tiload_opened--;
        return 0;
 }
 
 #define MAX_LENGTH 128
-/*
- *----------------------------------------------------------------------------
+/*----------------------------------------------------------------------------
  * Function : tiload_read
  *
  * Purpose  : read from codec
  *----------------------------------------------------------------------------
  */
-static ssize_t tiload_read(struct file *filp, char __user * buf,
-       size_t count, loff_t * offset)
+static ssize_t tiload_read(struct file *filp, char __user *buf,
+       size_t count, loff_t *offset)
 {
        struct tas2557_priv *pTAS2557 = (struct tas2557_priv *)filp->private_data;
        static char rd_data[MAX_LENGTH + 1];
        unsigned int nCompositeRegister = 0, Value = 0;
-       //unsigned int n;
        char reg_addr;
        size_t size;
        int ret = 0;
 #ifdef DEBUG
-       //int i;
+       /* int i; */
 #endif
-//    struct i2c_client *i2c = g_codec->control_data;
 
-       dev_info(pTAS2557->dev, "%s\n", __FUNCTION__);
+       dev_info(pTAS2557->dev, "%s\n", __func__);
        if (count > MAX_LENGTH) {
                dev_err(pTAS2557->dev, "Max %d bytes can be read\n", MAX_LENGTH);
-               return -1;
+               return -EINVAL;
        }
 
        /* copy register address from user space  */
        size = copy_from_user(&reg_addr, buf, 1);
        if (size != 0) {
-               dev_err(pTAS2557->dev,"read: copy_from_user failure\n");
-               return -1;
+               dev_err(pTAS2557->dev, "read: copy_from_user failure\n");
+               return -EINVAL;
        }
 
        size = count;
@@ -145,23 +136,23 @@ static ssize_t tiload_read(struct file *filp, char __user * buf,
                        rd_data, size);
        }
        if (ret < 0)
-               dev_err(pTAS2557->dev,"%s, %d, ret=%d, count=%zu error happen!\n", 
-                       __FUNCTION__, __LINE__, ret, count);
-//    size = i2c_master_recv(i2c, rd_data, count);
+               dev_err(pTAS2557->dev, "%s, %d, ret=%d, count=%zu error happen!\n",
+                       __func__, __LINE__, ret, count);
+
 #ifdef DEBUG
        dev_info(pTAS2557->dev, "read size = %d, reg_addr= %x , count = %d\n",
                (int) size, reg_addr, (int) count);
-//     for (i = 0; i < (int) size; i++) {
-//             dev_dbg(pTAS2557->dev, "rd_data[%d]=%x\n", i, rd_data[i]);
-//     }
+/*     for (i = 0; i < (int) size; i++) {
+*              dev_dbg(pTAS2557->dev, "rd_data[%d]=%x\n", i, rd_data[i]);
+*      }
+*/
 #endif
-       if (size != count) {
+       if (size != count)
                dev_err(pTAS2557->dev, "read %d registers from the codec\n", (int) size);
-       }
 
        if (copy_to_user(buf, rd_data, size) != 0) {
-               dev_err(pTAS2557->dev,"copy_to_user failed\n");
-               return -1;
+               dev_err(pTAS2557->dev, "copy_to_user failed\n");
+               return -EINVAL;
        }
 
        return size;
@@ -174,39 +165,38 @@ static ssize_t tiload_read(struct file *filp, char __user * buf,
  * Purpose  : write to codec
  *----------------------------------------------------------------------------
  */
-static ssize_t tiload_write(struct file *filp, const char __user * buf,
-       size_t count, loff_t * offset)
+static ssize_t tiload_write(struct file *filp, const char __user *buf,
+       size_t count, loff_t *offset)
 {
-       struct tas2557_priv *pTAS2557 = (struct tas2557_priv *)filp->private_data;      
+       struct tas2557_priv *pTAS2557 = (struct tas2557_priv *)filp->private_data;
        static char wr_data[MAX_LENGTH + 1];
        char *pData = wr_data;
        size_t size;
        unsigned int nCompositeRegister = 0;
-//    u8 pg_no;
-//    unsigned int n;   
        unsigned int nRegister;
        int ret = 0;
 #ifdef DEBUG
-       //int i;
+       /* int i; */
 #endif
-       dev_info(pTAS2557->dev, "%s\n", __FUNCTION__);
+       dev_info(pTAS2557->dev, "%s\n", __func__);
 
        if (count > MAX_LENGTH) {
                dev_err(pTAS2557->dev, "Max %d bytes can be read\n", MAX_LENGTH);
-               return -1;
+               return -EINVAL;
        }
 
        /* copy buffer from user space  */
        size = copy_from_user(wr_data, buf, count);
        if (size != 0) {
-               dev_err(pTAS2557->dev,"copy_from_user failure %d\n", (int) size);
-               return -1;
+               dev_err(pTAS2557->dev, "copy_from_user failure %d\n", (int) size);
+               return -EINVAL;
        }
 #ifdef DEBUG
        dev_info(pTAS2557->dev, "write size = %zu\n", count);
-       //for (i = 0; i < (int) count; i++) {
-       //      dev_info(pTAS2557->dev, "wr_data[%d]=%x\n", i, wr_data[i]);
-       //}
+/* for (i = 0; i < (int) count; i++) {
+*              dev_info(pTAS2557->dev, "wr_data[%d]=%x\n", i, wr_data[i]);
+*      }
+*/
 #endif
        nRegister = wr_data[0];
        size = count;
@@ -220,7 +210,7 @@ static ssize_t tiload_write(struct file *filp, const char __user * buf,
                pData++;
                count--;
        }
-#if 1
+
        nCompositeRegister = BPR_REG(gBook, gPage, nRegister);
        if (count == 2) {
                ret =
@@ -231,27 +221,20 @@ static ssize_t tiload_write(struct file *filp, const char __user * buf,
                        pTAS2557->bulk_write(pTAS2557, 0x80000000 | nCompositeRegister,
                        &pData[1], count - 1);
        }
+
        if (ret < 0)
-               dev_err(pTAS2557->dev,"%s, %d, ret=%d, count=%zu, ERROR Happen\n", __FUNCTION__,
+               dev_err(pTAS2557->dev, "%s, %d, ret=%d, count=%zu, ERROR Happen\n", __func__,
                        __LINE__, ret, count);
-#else
-       for (n = 1; n < count; n++) {
-               nCompositeRegister = BPR_REG(gBook, gPage, nRegister + n - 1);
-               g_codec->driver->write(g_codec, 0x80000000 | nCompositeRegister,
-                       pData[n]);
-       }
-#endif
 
        return size;
 }
 
 static void tiload_route_IO(struct tas2557_priv *pTAS2557, unsigned int bLock)
 {
-       if (bLock) {
+       if (bLock)
                pTAS2557->write(pTAS2557, 0xAFFEAFFE, 0xBABEBABE);
-       } else {
+       else
                pTAS2557->write(pTAS2557, 0xBABEBABE, 0xAFFEAFFE);
-       }
 }
 
 static long tiload_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
@@ -260,12 +243,12 @@ static long tiload_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
        long num = 0;
        void __user *argp = (void __user *) arg;
        int val;
+       struct BPR bpr;
 
-       BPR bpr;
-
-       dev_info(pTAS2557->dev, "%s, cmd=0x%x\n", __FUNCTION__, cmd);
-//    if (_IOC_TYPE(cmd) != TILOAD_IOC_MAGIC)
-//        return -ENOTTY;
+       dev_info(pTAS2557->dev, "%s, cmd=0x%x\n", __func__, cmd);
+/*  if (_IOC_TYPE(cmd) != TILOAD_IOC_MAGIC)
+ *      return -ENOTTY;
+ */
 
        switch (cmd) {
        case TILOAD_IOMAGICNUM_GET:
@@ -279,8 +262,8 @@ static long tiload_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
        case TILOAD_BPR_READ:
                break;
        case TILOAD_BPR_WRITE:
-               num = copy_from_user(&bpr, argp, sizeof(BPR));
-               dev_info(pTAS2557->dev,"TILOAD_BPR_WRITE: 0x%02X, 0x%02X, 0x%02X\n\r", bpr.nBook,
+               num = copy_from_user(&bpr, argp, sizeof(struct BPR));
+               dev_info(pTAS2557->dev, "TILOAD_BPR_WRITE: 0x%02X, 0x%02X, 0x%02X\n\r", bpr.nBook,
                        bpr.nPage, bpr.nRegister);
                break;
        case TILOAD_IOCTL_SET_CHL:
@@ -300,7 +283,7 @@ static long tiload_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
 }
 
 /*********** File operations structure for tiload *************/
-static struct file_operations tiload_fops = {
+static const struct file_operations tiload_fops = {
        .owner = THIS_MODULE,
        .open = tiload_open,
        .release = tiload_release,
@@ -309,8 +292,7 @@ static struct file_operations tiload_fops = {
        .unlocked_ioctl = tiload_ioctl,
 };
 
-/*
- *----------------------------------------------------------------------------
+/*----------------------------------------------------------------------------
  * Function : tiload_driver_init
  *
  * Purpose  : Register a char driver for dynamic tiload programming
@@ -319,11 +301,11 @@ static struct file_operations tiload_fops = {
 int tiload_driver_init(struct tas2557_priv *pTAS2557)
 {
        int result;
-
        dev_t dev = MKDEV(tiload_major, 0);
+
        g_TAS2557 = pTAS2557;
 
-       dev_info(pTAS2557->dev, "%s\n", __FUNCTION__);
+       dev_info(pTAS2557->dev, "%s\n", __func__);
 
        result = alloc_chrdev_region(&dev, 0, 1, DEVICE_NAME);
        if (result < 0) {
@@ -332,7 +314,7 @@ int tiload_driver_init(struct tas2557_priv *pTAS2557)
        }
        tiload_class = class_create(THIS_MODULE, DEVICE_NAME);
        tiload_major = MAJOR(dev);
-       dev_info(pTAS2557->dev,"allocated Major Number: %d\n", tiload_major);
+       dev_info(pTAS2557->dev, "allocated Major Number: %d\n", tiload_major);
 
        tiload_cdev = cdev_alloc();
        cdev_init(tiload_cdev, &tiload_fops);
@@ -343,17 +325,16 @@ int tiload_driver_init(struct tas2557_priv *pTAS2557)
                dev_err(pTAS2557->dev, "Device creation failed\n");
 
        if (cdev_add(tiload_cdev, dev, 1) < 0) {
-               dev_err(pTAS2557->dev,"tiload_driver: cdev_add failed \n");
+               dev_err(pTAS2557->dev, "tiload_driver: cdev_add failed\n");
                unregister_chrdev_region(dev, 1);
                tiload_cdev = NULL;
                return 1;
        }
-       dev_info(pTAS2557->dev,"Registered TiLoad driver, Major number: %d \n", tiload_major);
-       //class_device_create(tiload_class, NULL, dev, NULL, DEVICE_NAME, 0);
+       dev_info(pTAS2557->dev, "Registered TiLoad driver, Major number: %d\n", tiload_major);
+       /* class_device_create(tiload_class, NULL, dev, NULL, DEVICE_NAME, 0); */
        return 0;
 }
 
 MODULE_AUTHOR("Texas Instruments Inc.");
 MODULE_DESCRIPTION("Utility for TAS2557 Android in-system tuning");
-MODULE_LICENSE("GPLv2");
-//#endif
+MODULE_LICENSE("GPL v2");
index e60914cb35fad2c1179a7209f07e202a9e9df791..8f2960b784423a97efef1b7687cdacaf1390da5d 100755 (executable)
--- a/tiload.h
+++ b/tiload.h
@@ -3,17 +3,13 @@
 ** 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 
+** 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.
 **
-** You should have received a copy of the GNU General Public License along with
-** this program; if not, write to the Free Software Foundation, Inc., 51 Franklin
-** Street, Fifth Floor, Boston, MA 02110-1301, USA.
-**
 ** File:
 **     tiload.h
 **
                                                 (page * 128)) + reg)
 
 /* typedefs required for the included header files */
-typedef char *string;
-
-typedef struct {
+struct BPR {
        unsigned char nBook;
        unsigned char nPage;
        unsigned char nRegister;
-} BPR;
+};
 
 /* defines */
 #define DEVICE_NAME     "tiload_node"
+
 #define TILOAD_IOC_MAGIC   0xE0
-#define TILOAD_IOMAGICNUM_GET                          _IOR(TILOAD_IOC_MAGIC, 1, int)
-#define TILOAD_IOMAGICNUM_SET                          _IOW(TILOAD_IOC_MAGIC, 2, int)
-#define TILOAD_BPR_READ                                _IOR(TILOAD_IOC_MAGIC, 3, BPR)
-#define TILOAD_BPR_WRITE                               _IOW(TILOAD_IOC_MAGIC, 4, BPR)
-#define TILOAD_IOCTL_SET_CHL                   _IOW(TILOAD_IOC_MAGIC, 5, int)
-#define TILOAD_IOCTL_SET_CONFIG                _IOW(TILOAD_IOC_MAGIC, 6, int)
-#define TILOAD_IOCTL_SET_CALIBRATION   _IOW(TILOAD_IOC_MAGIC, 7, int)
+#define TILOAD_IOMAGICNUM_GET                  _IOR(TILOAD_IOC_MAGIC, 1, int)
+#define TILOAD_IOMAGICNUM_SET                  _IOW(TILOAD_IOC_MAGIC, 2, int)
+#define TILOAD_BPR_READ                                        _IOR(TILOAD_IOC_MAGIC, 3, struct BPR)
+#define TILOAD_BPR_WRITE                               _IOW(TILOAD_IOC_MAGIC, 4, struct BPR)
+#define TILOAD_IOCTL_SET_CHL                   _IOW(TILOAD_IOC_MAGIC, 5, int)
+#define TILOAD_IOCTL_SET_CONFIG                        _IOW(TILOAD_IOC_MAGIC, 6, int)
+#define TILOAD_IOCTL_SET_CALIBRATION   _IOW(TILOAD_IOC_MAGIC, 7, int)
 
 int tiload_driver_init(struct tas2557_priv *pTAS2557);