]> rtime.felk.cvut.cz Git - sojka/nv-tegra/linux-3.10.git/commitdiff
asoc: codec: audience: Updated driver and FW
authorSrinivas Anne <sanne@nvidia.com>
Mon, 17 Nov 2014 19:29:04 +0000 (11:29 -0800)
committerDara Ramesh <dramesh@nvidia.com>
Tue, 16 Dec 2014 04:35:51 +0000 (20:35 -0800)
FW version: M90.5.2.5_B45635_NVidia_Loki_MCFFillIn_STREAM

Features/Fixes:
1) Mono to stero copy for HS mic recording
2) LRMG headset detection and capture
3) 500 millisec capture distortion fix
4) Crash in FW after multiple HS plug-in and
Plug-out followed by HS mic recording
5) Enhanced command history logs.
6) Support for voice processing algo presets
7) fixed issue where disabling MIC0 DAPM causing issue in
simultaneous PB & Cap for Headset

Change-Id: Ifc68e810293397ef078511ec7ff28c448e6faa5f
Signed-off-by: Srinivas Anne <sanne@nvidia.com>
Reviewed-on: http://git-master/r/654917
(cherry picked from commit 34ef80324b8e7172c5a8fdd4ffa85bf93fd66bf3)
Reviewed-on: http://git-master/r/661659
Reviewed-by: Ashok Mudithanapalli <ashokm@nvidia.com>
Reviewed-by: Dara Ramesh <dramesh@nvidia.com>
firmware/audience/es755/audience-es755-fw.bin
sound/soc/codecs/audience/es-a300.c
sound/soc/codecs/audience/es-d300.c
sound/soc/codecs/audience/es755.c
sound/soc/codecs/audience/es755.h
sound/soc/codecs/audience/escore-cdev.c
sound/soc/codecs/audience/escore-list.c
sound/soc/codecs/audience/escore-pm.c
sound/soc/codecs/audience/escore-spi.c
sound/soc/codecs/audience/escore.c
sound/soc/codecs/audience/escore.h

index 4a27c47d0972d1919050b20d0568873e6df56375..c2027bfc8046d487be2921f4a1d3f7f4f4f5fd55 100644 (file)
Binary files a/firmware/audience/es755/audience-es755-fw.bin and b/firmware/audience/es755/audience-es755-fw.bin differ
index a2ebfa3b6aebe892e2bf20b2f47cc3cffdd20703..894905ceaeec67f600b74f3732198484cfdad9c1 100644 (file)
@@ -418,7 +418,7 @@ const struct snd_soc_dapm_widget es_codec_dapm_widgets[] = {
        /*SND_SOC_DAPM_SUPPLY("MICHS Bias", ES_MICBIAS_CTRL,
                ES_MBIASHS_MODE_SHIFT, 0, NULL, 0),
        SND_SOC_DAPM_SUPPLY("MIC0 Bias", ES_MICBIAS_CTRL,
-               ES_MBIAS0_MODE_SHIFT, 0, NULL, 0), */
+               ES_MBIAS0_MODE_SHIFT, 0, NULL, 0),*/
        SND_SOC_DAPM_SUPPLY("MIC1 Bias", ES_MICBIAS_CTRL,
                ES_MBIAS1_MODE_SHIFT, 0, NULL, 0),
        SND_SOC_DAPM_SUPPLY("MIC2 Bias", ES_MICBIAS_CTRL,
@@ -503,7 +503,7 @@ static const struct snd_soc_dapm_route intercon[] = {
 
        {"MICHS ON", "Switch", "MICHS"},
 
-       {"MIC0 PGA", NULL, "MIC0"},
+       /*{"MIC0 PGA", NULL, "MIC0"},*/
        {"MIC0 PGA", NULL, "MICHS ON"},
        {"MIC1 PGA", NULL, "MIC1"},
        {"MIC1 PGA", NULL, "MICHS ON"},
index 23f42df4fa1baf10f01dc5a0b2d52b2005dc4daa..a9717cf4ad8f2987ea20c8d83d44072e85dfca86 100644 (file)
@@ -232,7 +232,8 @@ static int es300_codec_stop_algo(struct escore_priv *escore)
        * diffeent route, UCM is responsible to set this algo preset
        * for every use case
        */
-       escore->algo_preset = 0;
+       escore->algo_preset_one = 0;
+       escore->algo_preset_two = 0;
        clear_chn_mgr_cache();
 exit:
        return ret;
@@ -515,32 +516,43 @@ static int convert_vp_pt_output_mux_to_cmd(u16 ch_mgr, u8 path_id,
        u8 i = 2;
        u8 update_cmds = 1;
        u16 ep_out = 0, ep_in = 0, filter_in = 0, filter_out = 0;
+       u16 filter_copyin = 0, filter_copyout = 0, copy_in = 0 , copy_out = 0;
        u16 group = 0;
 
        switch (ch_mgr) {
        case TXCHMGR0:
                filter_out = FILTER_VP;
                filter_in = FILTER_TXCHANMGR0;
+               filter_copyin = filter_copyout = FILTER_COPY0;
                ep_out = vp_o1;
                ep_in = TxChMgr_i0;
+               copy_in = copy_i0;
+               copy_out = copy_o0;
                group = 0;
                break;
        case TXCHMGR1:
-               filter_out = FILTER_VP;
                filter_in = FILTER_TXCHANMGR1;
-               ep_out = vp_o0;
+               filter_copyout = FILTER_COPY0;
+               copy_out = copy_o1;
                ep_in = TxChMgr_i0;
                group = 0;
                break;
        case TXCHMGR2:
                filter_in = FILTER_TXCHANMGR2;
                ep_in = TxChMgr_i0;
+               filter_out = FILTER_VP;
+               ep_out = vp_o0;
+               group = 0;
+               break;
+       case TXCHMGR3:
+               filter_in = FILTER_TXCHANMGR3;
+               ep_in = TxChMgr_i0;
                filter_out = FILTER_PASSTHRU;
                ep_out = pass_o0;
                group = 1;
                break;
-       case TXCHMGR3:
-               filter_in = FILTER_TXCHANMGR3;
+       case TXCHMGR4:
+               filter_in = FILTER_TXCHANMGR4;
                ep_in = TxChMgr_i0;
                filter_out = FILTER_PASSTHRU;
                ep_out = pass_o1;
@@ -554,9 +566,25 @@ static int convert_vp_pt_output_mux_to_cmd(u16 ch_mgr, u8 path_id,
        if (update_cmds) {
 
                /* Connect OUT endpoints */
-               msg[i++] = ES_API_WORD(ES_CONNECT_CMD,
-                               ES300_ENDPOINT(filter_out, OUT, ep_out));
-               msg_len += 4;
+               if (filter_out) {
+                       msg[i++] = ES_API_WORD(ES_CONNECT_CMD,
+                                ES300_ENDPOINT(filter_out, OUT, ep_out));
+                       msg_len += 4;
+               }
+
+               if (filter_copyin) {
+                       msg[i++] = ES_API_WORD(ES_CONNECT_CMD,
+                                       ES300_ENDPOINT(filter_copyin, IN,
+                                               copy_in));
+                       msg_len += 4;
+               }
+
+               if (filter_copyout) {
+                       msg[i++] = ES_API_WORD(ES_CONNECT_CMD,
+                                       ES300_ENDPOINT(filter_copyout, OUT,
+                                               copy_out));
+                       msg_len += 4;
+               }
 
                /* Connect IN endpoints */
                msg[i++] = ES_API_WORD(ES_CONNECT_CMD,
@@ -789,12 +817,20 @@ static int convert_output_mux_to_cmd(struct escore_priv *escore, int reg)
                                        path_id, msg, msg_len);
                break;
        case PASSTHRU_VP:
+               if (!strncmp(proc_block_output_texts[mux], "VP CSOUT1", 9))
+                       ch_mgr = TXCHMGR0;
+               else if (!strncmp(proc_block_output_texts[mux], "VP CSOUT2", 9))
+                       ch_mgr = TXCHMGR1;
+               else if (!strncmp(proc_block_output_texts[mux], "VP FEOUT1", 9))
+                       ch_mgr = TXCHMGR2;
+
+
                if (!strncmp(proc_block_output_texts[mux], "Pass AUDOUT1",
                                sizeof("Pass AUDOUT1")-1))
-                       ch_mgr = TXCHMGR2;
+                       ch_mgr = TXCHMGR3;
                else if (!strncmp(proc_block_output_texts[mux], "Pass AUDOUT2",
                                sizeof("Pass AUDOUT2")-1))
-                       ch_mgr = TXCHMGR3;
+                       ch_mgr = TXCHMGR4;
 
                msg_len = convert_vp_pt_output_mux_to_cmd(ch_mgr, path_id, msg,
                                msg_len);
@@ -977,13 +1013,23 @@ static int es_set_final_route(struct escore_priv *escore)
        if (!rc)
                escore_write_msg_list(escore);
 
-       if (escore->algo_preset != 0) {
+       if (escore->algo_preset_one != 0) {
                usleep_range(5000, 5005);
-               pr_debug("%s:add algo preset: %d", __func__,
-                               escore->algo_preset);
-               rc = escore_write(NULL, ES_PRESET, escore->algo_preset);
+               pr_debug("%s:add algo preset one: %d", __func__,
+                               escore->algo_preset_one);
+               rc = escore_write(NULL, ES_PRESET, escore->algo_preset_one);
                if (rc)
-                       dev_err(escore_priv.dev, "%s(): Set Preset failed:%d\n",
+                       dev_err(escore_priv.dev, "%s(): Set Algo Preset one failed:%d\n",
+                               __func__, rc);
+       }
+
+       if (escore->algo_preset_two != 0) {
+               usleep_range(5000, 5005);
+               pr_debug("%s:add algo preset two: %d", __func__,
+                               escore->algo_preset_two);
+               rc = escore_write(NULL, ES_PRESET, escore->algo_preset_two);
+               if (rc)
+                       dev_err(escore_priv.dev, "%s(): Set Algo Preset two failed:%d\n",
                                __func__, rc);
        }
        return rc;
@@ -1233,10 +1279,11 @@ static int es300_codec_enable_i2stx(struct snd_soc_dapm_widget *w,
                        }
                }
 
-        /* WAR removed the code that checks for ACK from DAI */
-               ret = es_set_final_route(escore);
-               atomic_inc(&escore->active_streams);
-
+               if (escore->i2s_dai_data[dai_id].tx_ch_act ==
+                                       escore->i2s_dai_data[dai_id].tx_ch_tot) {
+                       ret = es_set_final_route(escore);
+                       atomic_inc(&escore->active_streams);
+               }
                break;
        case SND_SOC_DAPM_POST_PMD:
                for (j = 0; j < escore->dai_nr; j++) {
@@ -1573,7 +1620,8 @@ static int put_input_route_value(struct snd_kcontrol *kcontrol,
 #endif
 
 exit:
-       pr_debug("put input reg %d val %d\n", reg, mux);
+       pr_err("put input reg %d val %d refcnt: %d\n",
+            reg, mux, cachedcmd_list[escore->algo_type][reg].refcnt);
 
        return rc;
 }
@@ -1656,7 +1704,9 @@ static int put_output_route_value(struct snd_kcontrol *kcontrol,
 #endif
 
 exit:
-       pr_debug("put output reg %d val %d\n", reg, mux);
+       pr_err("put output reg %d val %d refcnt: %d\n",
+           reg, mux, cachedcmd_list[escore->algo_type][reg].refcnt);
+
        return rc;
 }
 
@@ -1927,7 +1977,32 @@ static int put_lp_route(struct snd_kcontrol *kcontrol,
        return ret;
 }
 
-static int put_preset_value(struct snd_kcontrol *kcontrol,
+static int put_preset_value_one(struct snd_kcontrol *kcontrol,
+                                       struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = escore_priv.codec;
+       struct escore_priv *escore = snd_soc_codec_get_drvdata(codec);
+
+       unsigned int value;
+
+       value = ucontrol->value.integer.value[0];
+
+       escore->algo_preset_one = value;
+
+       return 0;
+}
+
+static int get_preset_value_one(struct snd_kcontrol *kcontrol,
+                                       struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = escore_priv.codec;
+       struct escore_priv *escore = snd_soc_codec_get_drvdata(codec);
+       ucontrol->value.integer.value[0] = escore->algo_preset_one;
+
+       return 0;
+}
+
+static int put_preset_value_two(struct snd_kcontrol *kcontrol,
                                        struct snd_ctl_elem_value *ucontrol)
 {
        struct snd_soc_codec *codec = escore_priv.codec;
@@ -1937,17 +2012,17 @@ static int put_preset_value(struct snd_kcontrol *kcontrol,
 
        value = ucontrol->value.integer.value[0];
 
-       escore->algo_preset = value;
+       escore->algo_preset_two = value;
 
        return 0;
 }
 
-static int get_preset_value(struct snd_kcontrol *kcontrol,
+static int get_preset_value_two(struct snd_kcontrol *kcontrol,
                                        struct snd_ctl_elem_value *ucontrol)
 {
        struct snd_soc_codec *codec = escore_priv.codec;
        struct escore_priv *escore = snd_soc_codec_get_drvdata(codec);
-       ucontrol->value.integer.value[0] = escore->algo_preset;
+       ucontrol->value.integer.value[0] = escore->algo_preset_two;
 
        return 0;
 }
@@ -2124,9 +2199,12 @@ static const struct snd_kcontrol_new es_d300_snd_controls[] = {
                         get_lp_route, put_lp_route),
        SOC_SINGLE_EXT("Reset", SND_SOC_NOPM, 0, 1, 0,
                         get_reset, put_reset),
-       SOC_SINGLE_EXT("Algo Preset",
-                       SND_SOC_NOPM, 0, 65535, 0, get_preset_value,
-                       put_preset_value),
+       SOC_SINGLE_EXT("Algo Preset 1",
+                       SND_SOC_NOPM, 0, 65535, 0, get_preset_value_one,
+                       put_preset_value_one),
+       SOC_SINGLE_EXT("Algo Preset 2",
+                       SND_SOC_NOPM, 0, 65535, 0, get_preset_value_two,
+                       put_preset_value_two),
 };
 
 static const struct soc_enum vp_pri_enum =
@@ -2909,6 +2987,10 @@ static const struct snd_soc_dapm_route intercon[] = {
        {"VP FEIN MUX", "ADC1", "ADC1"},
        {"VP FEIN MUX", "ADC2", "ADC2"},
        {"VP FEIN MUX", "ADC3", "ADC3"},
+       {"VP FEIN MUX", "PDMI0", "PDMI0"},
+       {"VP FEIN MUX", "PDMI1", "PDMI1"},
+       {"VP FEIN MUX", "PDMI2", "PDMI2"},
+       {"VP FEIN MUX", "PDMI3", "PDMI3"},
 
 
        {"VP UITONE1 MUX", "PCM0.0", "PCM0.0 RX"},
index 6d31edcd0c052f89259fb036761faffeafb2a61c..373bab2f53ddff774c6bcc2c4b298a6834adf2b9 100644 (file)
@@ -309,55 +309,12 @@ cmd_err:
 
 static DEVICE_ATTR(ping_status, 0444, es755_ping_status_show, NULL);
 
-/* /sys/devices/platform/msm_slim_ctrl.1/es755-codec-gen0/ping_status */
-static ssize_t es755_cmd_history_show(struct device *dev,
-               struct device_attribute *attr,
-                                  char *buf)
-{
-       int i = 0, j = 0;
-
-       for (i = cmd_hist_index; i < ES_MAX_ROUTE_MACRO_CMD; i++) {
-               if (cmd_hist[i].cmd)
-                       j += snprintf(buf+j,
-                                       PAGE_SIZE,
-                                       "cmd=0x%04x 0x%04x,tstamp=%lu\n",
-                                       cmd_hist[i].cmd>>16,
-                                       cmd_hist[i].cmd & 0xffff,
-                                       cmd_hist[i].timestamp);
-       }
-       for (i = 0; i < cmd_hist_index; i++) {
-               if (cmd_hist[i].cmd)
-                       j += snprintf(buf+j,
-                                       PAGE_SIZE,
-                                       "cmd=0x%04x 0x%04x,tstamp=%lu\n",
-                                       cmd_hist[i].cmd>>16,
-                                       cmd_hist[i].cmd & 0xffff,
-                                       cmd_hist[i].timestamp);
-       }
-       return  j;
-}
-static ssize_t es755_cmd_history_clear(struct device *dev,
-                                       struct device_attribute *attr,
-                                       const char *buf, size_t count)
-{
-       pr_info("%s(): requested - %s\n", __func__, buf);
-       if (!strncmp(buf, "clear", 5)) {
-               memset(cmd_hist, 0,  ES_MAX_ROUTE_MACRO_CMD *
-                                               sizeof(cmd_hist[0]));
-               cmd_hist_index = 0;
-       } else
-               pr_err("%s(): Invalid command: %s\n", __func__, buf);
-       return count;
-}
-static DEVICE_ATTR(cmd_history, 0666, es755_cmd_history_show,
-                                               es755_cmd_history_clear);
 static struct attribute *core_sysfs_attrs[] = {
        &dev_attr_route_status.attr,
        &dev_attr_reset_control.attr,
        &dev_attr_clock_on.attr,
        &dev_attr_fw_version.attr,
        &dev_attr_ping_status.attr,
-       &dev_attr_cmd_history.attr,
        &dev_attr_pm_enable.attr,
        NULL
 };
@@ -1682,7 +1639,6 @@ static int es755_codec_write(struct snd_soc_codec *codec, unsigned int reg,
                        goto out;
                }
        }
-
        if (reg == ES_HP_R_GAIN) {
                ret = escore_cmd(escore, sync_cmd, &sync_ack);
                if (ret < 0) {
@@ -2062,7 +2018,8 @@ static int es755_mic_config(struct escore_priv *escore)
        accdet_reg.fields.debounce_timer = accdet_cfg.debounce_timer & (0x3);
 
        /* This allows detection of both type of headsets: LRGM and LRMG */
-       accdet_reg.fields.mg_sel_force = accdet_cfg.mic_det_enabled & (0x1);
+       /*accdet_reg.fields.mg_sel_force = accdet_cfg.mic_det_enabled & (0x1);*/
+       /* No need to set mg_sel_force bit for LRGM/LRMG detection*/
 
        pr_debug("%s()\n", __func__);
 
@@ -2089,6 +2046,15 @@ static int es755_button_config(struct escore_priv *escore)
        btn_ctl4.value = 0;
 
        /* Config for Button Control 1 */
+
+       rc = escore_read(NULL, ES_BUTTON_CTRL1);
+       if (rc < 0) {
+               pr_err("%s(): Error reading button control 1\n",
+                               __func__);
+               goto btn_cfg_exit;
+       }
+       btn_ctl1.value = rc;
+
        if (btn_cfg->btn_press_settling_time != invalid) {
                btn_ctl1.fields.btn_press_settling_time =
                        (btn_cfg->btn_press_settling_time & 0x7);
@@ -2105,6 +2071,8 @@ static int es755_button_config(struct escore_priv *escore)
                update = 1;
        }
 
+       pr_debug("%s() button value: %x", __func__, btn_ctl1.value);
+
        if (update) {
                rc = escore_write(NULL, ES_BUTTON_CTRL1, btn_ctl1.value);
                if (rc < 0) {
@@ -2114,9 +2082,9 @@ static int es755_button_config(struct escore_priv *escore)
                }
                update = 0;
        }
-
+       /* Leave Button Ctrl2, 3 and 4 as default value in firwmare */
        /* Config for Button Control 2 */
-       if (btn_cfg->double_btn_timer != invalid) {
+       /*if (btn_cfg->double_btn_timer != invalid) {
                btn_ctl2.fields.double_btn_timer =
                        (btn_cfg->double_btn_timer & 0xf);
                update = 1;
@@ -2134,10 +2102,10 @@ static int es755_button_config(struct escore_priv *escore)
                        goto btn_cfg_exit;
                }
                update = 0;
-       }
+       }*/
 
        /* Config for Button Control 3 */
-       if (btn_cfg->long_btn_timer != invalid) {
+       /*if (btn_cfg->long_btn_timer != invalid) {
                btn_ctl3.fields.long_btn_timer =
                        (btn_cfg->long_btn_timer & 0xf);
                update = 1;
@@ -2155,10 +2123,10 @@ static int es755_button_config(struct escore_priv *escore)
                        goto btn_cfg_exit;
                }
                update = 0;
-       }
+       }*/
 
        /* Config for Button Control 4 */
-       if (btn_cfg->valid_levels != invalid) {
+       /*if (btn_cfg->valid_levels != invalid) {
                btn_ctl4.fields.valid_levels =
                        (btn_cfg->valid_levels & 0x3f);
                update = 1;
@@ -2176,7 +2144,7 @@ static int es755_button_config(struct escore_priv *escore)
                        goto btn_cfg_exit;
                }
                update = 0;
-       }
+       }*/
 
 btn_cfg_exit:
        return rc;
@@ -2223,10 +2191,14 @@ static int es755_codec_intr(struct notifier_block *self, unsigned long action,
                void *dev)
 {
        struct escore_priv *escore = (struct escore_priv *)dev;
-       union es755_accdet_status_reg accdet_reg;
+       union es755_accdet_status_reg accdet_status_reg;
+       union es755_accdet_reg accdet_reg;
        int value;
        int rc = 0;
        u8 impd_level;
+       u8 mg_sel_force;
+       u8 mg_select;
+       u8 is_invalid_type;
 
        pr_debug("%s(): Event: 0x%04x\n", __func__, (u32)action);
 
@@ -2239,7 +2211,7 @@ static int es755_codec_intr(struct notifier_block *self, unsigned long action,
 
                if (ES_PLUG_EVENT(value)) {
 
-                       pr_debug("%s(): Plug event\n", __func__);
+                       pr_info("%s(): Plug event\n", __func__);
                        /* Enable MIC Detection */
                        rc = es755_mic_config(escore);
                        if (rc < 0) {
@@ -2255,16 +2227,64 @@ static int es755_codec_intr(struct notifier_block *self, unsigned long action,
                                goto intr_exit;
                        }
 
-                       accdet_reg.value = value;
-                       impd_level = accdet_reg.fields.impd_level;
+                       accdet_status_reg.value = value;
+                       impd_level = accdet_status_reg.fields.impd_level;
+
+                       value = escore_read(NULL, ES_ACCDET_CONFIG);
+                       if (value < 0) {
+                               pr_err("%s(): Accessory detect config failed\n",
+                                               __func__);
+                               goto intr_exit;
+                       }
 
+                       accdet_reg.value = value;
+                       mg_sel_force = accdet_reg.fields.mg_sel_force;
+                       mg_select = accdet_reg.fields.mg_select;
+
+                       /* Headphone Type Decode Table
+                        *  ---------------------------------------------
+                        * | IMP_LEVEL | MG_SEL_FORCE | MG_SEL | HS_TYPE |
+                        * |   1-5     |       1      |   1    |  LRGM   |
+                        * |   1-5     |       1      |   0    |  LRMG   |
+                        * |   1-5     |       0      |  0/1   |  Inval  |
+                        * |    6      |       1      |   1    |  LRMG   |
+                        * |    6      |       1      |   0    |  LRGM   |
+                        * |    6      |       0      |   1    |  LRMG   |
+                        * |    6      |       0      |   0    |  LRGM   |
+                        * |  > 6      |       X      |   X    |  Inval  |
+                        * |    0      |       X      |   X    |  LRG    |
+                        *  ---------------------------------------------
+                        */
                        if (impd_level) {
-                               pr_debug("%s(): Headset detected\n", __func__);
-                               if (impd_level < MIC_IMPEDANCE_LEVEL_LRGM)
-                                       pr_debug("LRMG Headset\n");
-                               else if (impd_level == MIC_IMPEDANCE_LEVEL_LRGM)
-                                       pr_debug("LRGM Headset\n");
-                               else {
+                               pr_info("%s(): Headset detected\n", __func__);
+
+                               is_invalid_type = false;
+                               /* MIC Impedence - 1 to 5 */
+                               if (impd_level < MIC_IMPEDANCE_LEVEL) {
+                                       if ((mg_sel_force) && (mg_select))
+                                               pr_info("LRGM Headset\n");
+                                       else if ((mg_sel_force) &&
+                                                       (mg_select == false))
+                                               pr_info("LRMG Headset\n");
+                                       else
+                                               is_invalid_type = true;
+                               }
+                               /* Mic Impedence - 6 */
+                               else if (impd_level == MIC_IMPEDANCE_LEVEL) {
+                                       if ((mg_sel_force) && (mg_select))
+                                               pr_info("LRMG Headset\n");
+                                       else if ((mg_sel_force) &&
+                                                       (mg_select == false))
+                                               pr_info("LRGM Headset\n");
+                                       else if ((mg_sel_force == false) &&
+                                                       (mg_select))
+                                               pr_info("LRMG Headset\n");
+                                       else
+                                               pr_info("LRGM Headset\n");
+                               } else
+                                       is_invalid_type = true;
+
+                               if (is_invalid_type) {
                                        pr_err("Invalid type:%d\n", impd_level);
                                        rc = -EINVAL;
                                        goto intr_exit;
@@ -2279,7 +2299,7 @@ static int es755_codec_intr(struct notifier_block *self, unsigned long action,
                                        goto intr_exit;
 
                        } else {
-                               pr_debug("%s(): Headphone detected\n",
+                               pr_info("%s(): Headphone detected\n",
                                                __func__);
 
                                snd_soc_jack_report(escore->jack,
@@ -2288,12 +2308,12 @@ static int es755_codec_intr(struct notifier_block *self, unsigned long action,
                        }
 
                        pr_debug("%s(): AccDet status 0x%04x\n", __func__,
-                                       value);
+                                       accdet_status_reg.value);
                } else if (ES_BUTTON_PRESS_EVENT(value)) {
-                       pr_debug("%s(): Button event\n", __func__);
+                       pr_info("%s(): Button press event\n", __func__);
 
                } else if (ES_BUTTON_RELEASE_EVENT(value)) {
-                       pr_debug("%s(): Button released\n", __func__);
+                       pr_info("%s(): Button release event\n", __func__);
                        value = escore_read(NULL, ES_GET_ACCDET_STATUS);
                        if (value < 0) {
                                pr_err("%s(): Accessory detect status failed\n",
@@ -2301,11 +2321,12 @@ static int es755_codec_intr(struct notifier_block *self, unsigned long action,
                                goto intr_exit;
                        }
 
-                       accdet_reg.value = value;
+                       accdet_status_reg.value = value;
 
-                       pr_debug("Impd:%d\n", accdet_reg.fields.impd_level);
+                       pr_info("Impd:%d\n",
+                                       accdet_status_reg.fields.impd_level);
 
-                       switch (accdet_reg.fields.impd_level) {
+                       switch (accdet_status_reg.fields.impd_level) {
                        case 0:
                                snd_soc_jack_report(escore->jack,
                                                SND_JACK_BTN_0,
@@ -2332,11 +2353,11 @@ static int es755_codec_intr(struct notifier_block *self, unsigned long action,
                                                0, SND_JACK_BTN_2);
                                break;
                        default:
-                               pr_debug("No report of event\n");
+                               pr_info("Release event but impedance not in range\n");
                                break;
                        }
                } else if (ES_UNPLUG_EVENT(value)) {
-                       pr_debug("%s(): Unplug detected\n", __func__);
+                       pr_info("%s(): Unplug detected\n", __func__);
 
                        escore->button_config_required = 0;
                        snd_soc_jack_report(escore->jack, 0, JACK_DET_MASK);
@@ -2369,7 +2390,8 @@ irqreturn_t es755_cmd_completion_isr(int irq, void *data)
 irqreturn_t es755_irq_work(int irq, void *data)
 {
        struct escore_priv *escore = (struct escore_priv *)data;
-       int rc;
+       int retry = ES_EVENT_STATUS_RETRY_COUNT;
+       int rc, ret;
        u32 cmd = 0;
        u32 event_type = 0;
 
@@ -2397,6 +2419,27 @@ irqreturn_t es755_irq_work(int irq, void *data)
         * Interrupt will put the chip into Normal State
         */
 
+       cmd = ES_GET_EVENT << 16;
+
+       mutex_lock(&escore->api_mutex);
+       while (retry) {
+               rc = escore->bus.ops.cmd(escore, cmd, &event_type);
+               if (!rc || !--retry)
+                       break;
+               pr_info("%s(): wakeup and retry\n", __func__);
+               ret = escore_wakeup(escore);
+               if (ret) {
+                       dev_err(escore->dev, "%s() wakeup failed ret = %d\n",
+                                                               __func__, ret);
+                       break;
+               }
+       }
+       if (rc < 0) {
+               pr_err("%s(): Error reading IRQ event: %d\n", __func__, rc);
+               mutex_unlock(&escore->api_mutex);
+               goto irq_exit;
+       }
+
        if (escore->escore_power_state == escore->non_vs_sleep_state) {
                escore->escore_power_state = ES_SET_POWER_STATE_NORMAL;
        } else if (escore->escore_power_state == ES_SET_POWER_STATE_VS_LOWPWR) {
@@ -2413,15 +2456,6 @@ irqreturn_t es755_irq_work(int irq, void *data)
                escore->defer_intr_config = 1;
        }
 
-       cmd = ES_GET_EVENT << 16;
-
-       mutex_lock(&escore->api_mutex);
-       rc = escore->bus.ops.cmd(escore, cmd, &event_type);
-       if (rc < 0) {
-               pr_err("%s(): Error reading IRQ event: %d\n", __func__, rc);
-               mutex_unlock(&escore->api_mutex);
-               goto irq_exit;
-       }
        mutex_unlock(&escore->api_mutex);
 
        event_type &= ES_MASK_INTR_EVENT;
index c052c4cabc7238a13083db24f4b7de74671c2f33..c3e4103918fc431d02368359a0fd4f2595ef2e84 100644 (file)
@@ -94,6 +94,7 @@
 #define ES_ACCDET_CONFIG_CMD           0x9056
 #define ES_SMOOTH_RATE                 0x804E
 #define ES755_FW_DOWNLOAD_MAX_RETRY    5
+#define ES_EVENT_STATUS_RETRY_COUNT    2
 
 /*
  * Stereo widening presets for headphone playback and MM audio algo rate 48K
 #define ES_MAX_AZ_MODE                 2
 #define ES_MAX_AEC_MODE                        7
 /* Impedance level for MIC detection */
-#define MIC_IMPEDANCE_LEVEL_LRGM       0x6
+#define MIC_IMPEDANCE_LEVEL            0x6
 
 /* Jack detection mask */
 #define JACK_DET_MASK  (SND_JACK_HEADSET | SND_JACK_BTN_0 | SND_JACK_BTN_1 |\
index a16d499aad86c612d2e3b24b74b18fa713b0b728..7687fe760a5be4a572f263842169a1b9f52ebaa1 100644 (file)
@@ -75,6 +75,7 @@ enum {
        CDEV_STREAMING,
        CDEV_DATABLOCK,
        CDEV_DATALOGGING,
+       CDEV_CMD_HISTORY,
        CDEV_MAX_DEV,
 };
 
@@ -119,6 +120,7 @@ static atomic_t cb_pages_out = ATOMIC_INIT(0);
 #define READBUF_SIZE 128
 static struct timespec read_time;
 static char readbuf[READBUF_SIZE];
+static char *cmd_history_buf;
 
 enum parse_token {
        PT_NIL, PT_PRESET, PT_ID, PT_HEXWORD
@@ -1347,6 +1349,142 @@ static int datablock_release(struct inode *inode, struct file *filp)
        return 0;
 }
 
+static int cmd_history_open(struct inode *inode, struct file *filp)
+{
+       struct escore_priv *escore;
+       int rc = 0;
+       unsigned major;
+       unsigned minor;
+       int index, i, j = 0;
+
+       pr_debug("called: %s\n", __func__);
+
+       major = imajor(inode);
+       minor = iminor(inode);
+       if (major != cdev_major || minor < 0 || minor >= CDEV_COUNT) {
+               pr_warn("escore: no such device major=%u minor=%u\n",
+                        major, minor);
+               rc = -ENODEV;
+               goto out;
+       }
+
+       escore = container_of((inode)->i_cdev, struct escore_priv,
+                       cdev_cmd_history);
+
+       if (inode->i_cdev != &escore->cdev_cmd_history) {
+               pr_err("open: error bad cdev field\n");
+               rc = -ENODEV;
+               goto out;
+       }
+
+       filp->private_data = escore;
+
+       cmd_history_buf = kmalloc(
+               ES_MAX_ROUTE_MACRO_CMD * ES_MAX_CMD_HISTORY_LINE_SIZE,
+               GFP_KERNEL);
+       if (!cmd_history_buf) {
+               dev_err(escore->dev, "%s(): buffer alloc failed\n", __func__);
+               return -ENOMEM;
+       }
+
+       if (filp->f_flags == O_WRONLY)
+               return 0;
+
+       for (i = 0; i < ES_MAX_ROUTE_MACRO_CMD; i++) {
+               index = i + cmd_hist_index;
+               index %= ES_MAX_ROUTE_MACRO_CMD;
+               if (cmd_hist[index].cmd) {
+                       j += snprintf(cmd_history_buf + j, PAGE_SIZE,
+                                       "0x%04x 0x%04x; ",
+                                       cmd_hist[index].cmd >> 16,
+                                       cmd_hist[index].cmd & 0xffff);
+                       if (cmd_hist[index].resp)
+                               j += snprintf(cmd_history_buf + j, PAGE_SIZE,
+                                               "resp = 0x%04x 0x%04x; ",
+                                               cmd_hist[index].resp >> 16,
+                                               cmd_hist[index].resp & 0xffff);
+                       j += snprintf(cmd_history_buf + j, PAGE_SIZE,
+                                               "tstamp=%lu\n",
+                                               cmd_hist[index].timestamp);
+               }
+       }
+
+       escore->cmd_history_size = j;
+
+out:
+       return rc;
+}
+
+static ssize_t cmd_history_read(struct file *filp, char __user *buf,
+                                       size_t count, loff_t *f_pos)
+{
+       struct escore_priv * const escore
+                       = (struct escore_priv *)filp->private_data;
+       static int done, pos;
+       unsigned int size;
+       int rc;
+
+       if (done || !escore->cmd_history_size) {
+               pr_info("%s() done\n", __func__);
+               done = 0;
+               pos = 0;
+               return 0;
+       }
+
+       size = escore->cmd_history_size > count ?
+                       count : escore->cmd_history_size;
+
+       rc = copy_to_user(buf, cmd_history_buf + pos, size);
+       if (rc) {
+               pr_err("%s() error in copy_to_user() %d\n", __func__, rc);
+               return rc;
+       }
+       escore->cmd_history_size -= size;
+       pos += size;
+
+       if (!escore->cmd_history_size)
+               done = 1;
+
+       return  size;
+}
+
+static ssize_t cmd_history_write(struct file *filp, const char __user *buf,
+                               size_t count, loff_t *f_pos)
+{
+       int err;
+
+       BUG_ON(!cmd_history_buf);
+
+       err = copy_from_user(cmd_history_buf, buf, count);
+       if (err) {
+               pr_err("%s(): copy_from_user err: %d\n", __func__, err);
+               goto out;
+       }
+
+       pr_info("%s(): requested - %s\n", __func__, cmd_history_buf);
+       if (!strncmp(cmd_history_buf, "clear", 5)) {
+               memset(cmd_hist, 0,  ES_MAX_ROUTE_MACRO_CMD *
+                                               sizeof(cmd_hist[0]));
+               cmd_hist_index = 0;
+       } else
+               pr_err("%s(): Invalid command: %s\n",
+                               __func__, cmd_history_buf);
+out:
+       return (err) ? err : count;
+
+}
+
+static int cmd_history_release(struct inode *inode, struct file *filp)
+{
+       struct escore_priv * const escore
+                       = (struct escore_priv *)filp->private_data;
+
+       kfree(cmd_history_buf);
+       cmd_history_buf = NULL;
+       escore->cmd_history_size = 0;
+       return 0;
+}
+
 static const struct file_operations datablock_fops = {
        .owner = THIS_MODULE,
        .read = datablock_read,
@@ -1354,6 +1492,15 @@ static const struct file_operations datablock_fops = {
        .open = datablock_open,
        .release = datablock_release,
 };
+
+static const struct file_operations cmd_history_fops = {
+       .owner = THIS_MODULE,
+       .read = cmd_history_read,
+       .write = cmd_history_write,
+       .open = cmd_history_open,
+       .release = cmd_history_release,
+};
+
 static int create_cdev(struct escore_priv *escore, struct cdev *cdev,
                       const struct file_operations *fops, unsigned int index)
 {
@@ -1465,12 +1612,21 @@ int escore_cdev_init(struct escore_priv *escore)
                goto err_datalogging;
        dev_dbg(escore->dev, "%s(): datalogging cdev initialized.\n", __func__);
 
+       err = create_cdev(escore, &escore->cdev_cmd_history, &cmd_history_fops,
+                       CDEV_CMD_HISTORY);
+       if (err)
+               goto err_cmd_history;
+
+       dev_dbg(escore->dev, "%s(): cmd_history cdev initialized.\n", __func__);
+
        return err;
 
-err_datalogging:
+err_cmd_history:
        cdev_destroy(&escore->cdev_datalogging, CDEV_DATALOGGING);
+err_datalogging:
+       cdev_destroy(&escore->cdev_datablock, CDEV_DATABLOCK);
 err_datablock:
-       cdev_destroy(&escore->cdev_firmware, CDEV_STREAMING);
+       cdev_destroy(&escore->cdev_streaming, CDEV_STREAMING);
 err_streaming:
        cdev_destroy(&escore->cdev_firmware, CDEV_FIRMWARE);
 err_firmware:
index 4064613f2bf4284e7e0f4993fc86388a6dc003f5..78e4e67fbc981c104ffddd2da85c68530fb0aafe 100644 (file)
@@ -41,20 +41,33 @@ int escore_write_msg_list(struct escore_priv *escore)
 
        if (!escore)
                escore = &escore_priv;
+
+       rc = escore_pm_get_sync();
+       if (rc < 0) {
+               pr_err("%s(): Failed to resume :%d\n", __func__, rc);
+               return rc;
+       }
+
        mutex_lock(&escore->msg_list_mutex);
+       mutex_lock(&escore->api_mutex);
        list_for_each_entry(entry, &escore->msg_list, list) {
                memcpy((char *)api_word, entry->msg, entry->msg_len);
                for (i = 0; i < entry->msg_len / 4; i++) {
-                       rc = escore_cmd(escore, api_word[i], &resp);
+                       resp = 0;
+                       rc = escore->bus.ops.cmd(escore, api_word[i],
+                                       &resp);
                        if (rc < 0) {
                                pr_err("%s(): failed", __func__);
                                mutex_unlock(&escore->msg_list_mutex);
-                               return rc;
+                               goto exit;
                        }
                }
        }
-       mutex_unlock(&escore->msg_list_mutex);
 
+exit:
+       mutex_unlock(&escore->msg_list_mutex);
+       mutex_unlock(&escore->api_mutex);
+       escore_pm_put_autosuspend();
        return rc;
 }
 EXPORT_SYMBOL_GPL(escore_write_msg_list);
index 029dbf808a3ac5858b1521bf227cf19dc4254f02..e7e858514f09655110ff103958f18e7036552222 100644 (file)
@@ -102,6 +102,7 @@ static int escore_non_vs_suspend(struct device *dev)
                return -EBUSY;
        }
 
+       mutex_lock(&escore_priv.api_mutex);
        /* It is assumed that a channels have already been muted */
        /* Send a SetPowerState command - no respnse */
        cmd = (ES_SET_POWER_STATE << 16) |
@@ -122,6 +123,7 @@ static int escore_non_vs_suspend(struct device *dev)
        escore_priv.escore_power_state = escore_priv.non_vs_sleep_state;
 
 suspend_out:
+       mutex_unlock(&escore_priv.api_mutex);
 
        return ret;
 }
@@ -132,22 +134,25 @@ static int escore_non_vs_resume(struct device *dev)
        int ret = 0;
        dev_dbg(dev, "%s()\n", __func__);
 
+       mutex_lock(&escore->api_mutex);
        ret = escore_wakeup(escore);
        if (ret) {
                dev_err(dev, "%s() wakeup failed ret = %d\n", __func__, ret);
                goto escore_wakeup_fail_recovery;
        }
 
+       escore->escore_power_state = ES_SET_POWER_STATE_NORMAL;
+       mutex_unlock(&escore->api_mutex);
+
        dev_dbg(dev, "%s() - out rc =%d\n", __func__, ret);
 
-       escore->escore_power_state = ES_SET_POWER_STATE_NORMAL;
        return ret;
 
 escore_wakeup_fail_recovery:
        escore_gpio_reset(&escore_priv);
        ret = escore_priv.boot_ops.bootup(&escore_priv);
        escore_priv.escore_power_state = ES_SET_POWER_STATE_NORMAL;
-
+       mutex_unlock(&escore->api_mutex);
        return ret;
 }
 
@@ -194,14 +199,18 @@ static int escore_runtime_suspend(struct device *dev)
         * bring chip into normal mode to enter into desired runtime suspend
         * state.
         */
+       mutex_lock(&escore->api_mutex);
        if (escore->escore_power_state == ES_SET_POWER_STATE_MP_SLEEP) {
                ret = escore_wakeup(escore);
                if (ret) {
                        dev_err(dev, "%s() wakeup failed ret = %d\n",
                                        __func__, ret);
+                       mutex_unlock(&escore_priv.api_mutex);
                        goto out;
                }
+               escore->escore_power_state = ES_SET_POWER_STATE_NORMAL;
        }
+       mutex_unlock(&escore->api_mutex);
 #ifdef CONFIG_SND_SOC_ES_RUNTIME_SUSPEND_MODE_SLEEP
        ret = escore_non_vs_suspend(dev);
 #elif defined(CONFIG_SND_SOC_ES_RUNTIME_SUSPEND_MODE_CVQ)
@@ -311,12 +320,16 @@ int escore_system_suspend(struct device *dev)
                         * Need to bring chip into normal mode before putting
                         * into suspend state.
                         */
+                       mutex_lock(&escore_priv.api_mutex);
                        ret = escore_wakeup(escore);
                        if (ret) {
                                dev_err(dev, "%s() wakeup failed ret = %d\n",
                                                __func__, ret);
+                               mutex_unlock(&escore_priv.api_mutex);
                                goto out;
                        }
+                       escore->escore_power_state = ES_SET_POWER_STATE_NORMAL;
+                       mutex_unlock(&escore_priv.api_mutex);
                }
                ret = escore_non_vs_suspend(dev);
        }
index 66d4a8492c9ce90a83db80f0c0905c7164093f2a..91a8b180fd94d0220fc0a2710563faa6dc6877af 100644 (file)
@@ -127,10 +127,12 @@ static int escore_spi_cmd(struct escore_priv *escore,
        if ((escore->cmd_compl_mode == ES_CMD_COMP_INTR) && !sr)
                escore->wait_api_intr = 1;
 
+       *resp = 0;
+
        cmd = cpu_to_be32(cmd);
        err = escore_spi_write(escore, &cmd, sizeof(cmd));
        if (err || sr)
-               return err;
+               goto cmd_exit;
 
        if (escore->cmd_compl_mode == ES_CMD_COMP_INTR) {
                pr_debug("%s(): Waiting for API interrupt. Jiffies:%lu",
@@ -201,6 +203,7 @@ static int escore_spi_cmd(struct escore_priv *escore,
        dev_dbg(escore->dev, "%s: err=%d  *resp=0x%08x\n", __func__, err, *resp);
 
 cmd_exit:
+       update_cmd_history(be32_to_cpu(cmd), *resp);
        return err;
 }
 
index 2980f4ddc62469040de5ba57d80119fbf9fd9528..f825845c0d265d1e98ae474659427f9042429717 100644 (file)
@@ -41,16 +41,12 @@ static int _escore_cmd(struct escore_priv *escore, u32 cmd, u32 *resp)
        int sr;
        int err;
 
+       *resp = 0;
        sr = cmd & BIT(28);
-       cmd_hist[cmd_hist_index].cmd = cmd;
-       cmd_hist[cmd_hist_index].timestamp = jiffies;
-       if (cmd_hist_index == ES_MAX_ROUTE_MACRO_CMD-1)
-               cmd_hist_index = 0;
-       else
-               cmd_hist_index++;
+
        err = escore->bus.ops.cmd(escore, cmd, resp);
        if (err || sr)
-               goto cmd_err;
+               goto exit;
 
        if (resp == 0) {
                err = -ETIMEDOUT;
@@ -59,7 +55,8 @@ static int _escore_cmd(struct escore_priv *escore, u32 cmd, u32 *resp)
                escore->bus.last_response = *resp;
                get_monotonic_boottime(&escore->last_resp_time);
        }
-cmd_err:
+
+exit:
        return err;
 }
 
@@ -890,7 +887,6 @@ int escore_wakeup(struct escore_priv *escore)
        int retry = 20;
        u32 p_cmd = ES_GET_POWER_STATE << 16;
 
-       mutex_lock(&escore->api_mutex);
        /* Enable the clocks */
        if (escore_priv.pdata->esxxx_clk_cb) {
                escore_priv.pdata->esxxx_clk_cb(1);
@@ -974,7 +970,6 @@ int escore_wakeup(struct escore_priv *escore)
                                __func__, rc);
 
 escore_wakeup_exit:
-       mutex_unlock(&escore->api_mutex);
        return rc;
 }
 
index 58e513d7e56a38d77f45a77aa1dd131be443a8c3..9bccbb984855387d6554234c25dcee1c5627ed54 100644 (file)
@@ -81,6 +81,7 @@
 /* Standard commands used by all chips */
 
 #define ES_SR_BIT                      28
+#define ES_SC_BIT                      29
 #define ES_SYNC_CMD                    0x8000
 #define ES_SYNC_POLLING                        0x0000
 #define ES_SYNC_ACK                    0x80000000
 #define ES_SET_POWER_LEVEL                             0x8011
 #define ES_POWER_LEVEL_6                               0x0006
 
-#define ES_WAKEUP_TIME                         30
+#define ES_WAKEUP_TIME                         40
 #define ES_PM_CLOCK_STABILIZATION              1 /* 1ms */
 #define ES_RESP_TOUT_MSEC                      20 /* 20ms */
 #define ES_RESP_TOUT                           20000 /* 20ms */
@@ -417,6 +418,7 @@ struct escore_voicesense_ops {
 
 struct escore_macro {
        u32 cmd;
+       u32 resp;
        unsigned long timestamp;
 };
 
@@ -429,7 +431,9 @@ struct escore_pdata {
 #define ES705_PRESET_ARRAY_SIZE                10
 #endif
 
-#define        ES_MAX_ROUTE_MACRO_CMD          100
+#define        ES_MAX_ROUTE_MACRO_CMD          300
+/* Max size of cmd_history line */
+#define ES_MAX_CMD_HISTORY_LINE_SIZE   100
 extern struct escore_macro cmd_hist[ES_MAX_ROUTE_MACRO_CMD];
 extern int cmd_hist_index;
 
@@ -468,6 +472,7 @@ struct escore_priv {
        u16 es_vs_route_preset;
        u16 es_cvs_preset;
        int es_streaming_mode;
+       int cmd_history_size;
        int sleep_abort;
 
        unsigned long pm_time;
@@ -525,7 +530,8 @@ struct escore_priv {
        int fw_requested;
        u16 preset;
        u16 cvs_preset;
-       u16 algo_preset;
+       u16 algo_preset_one;
+       u16 algo_preset_two;
 /* endif 705 */
 
        struct mutex pm_mutex;
@@ -542,6 +548,7 @@ struct escore_priv {
        struct cdev cdev_firmware;
        struct cdev cdev_datablock;
        struct cdev cdev_datalogging;
+       struct cdev cdev_cmd_history;
 
        struct task_struct *stream_thread;
        wait_queue_head_t stream_in_q;
@@ -660,4 +667,13 @@ extern const struct dev_pm_ops escore_pm_ops;
 #define ESCORE_STREAM_ENABLE   1
 #define ESCORE_DATALOGGING_CMD_ENABLE    0x803f0001
 #define ESCORE_DATALOGGING_CMD_DISABLE   0x803f0000
+
+/* Take api_mutex before calling this function */
+static inline void update_cmd_history(u32 cmd, u32 resp)
+{
+       cmd_hist[cmd_hist_index].cmd = cmd;
+       cmd_hist[cmd_hist_index].resp = resp;
+       cmd_hist[cmd_hist_index].timestamp = jiffies;
+       cmd_hist_index = (cmd_hist_index + 1) % ES_MAX_ROUTE_MACRO_CMD;
+}
 #endif /* _ESCORE_H */