/*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,
{"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"},
* 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;
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;
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,
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);
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;
}
}
- /* 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++) {
#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;
}
#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;
}
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;
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;
}
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 =
{"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"},
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
};
goto out;
}
}
-
if (reg == ES_HP_R_GAIN) {
ret = escore_cmd(escore, sync_cmd, &sync_ack);
if (ret < 0) {
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__);
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);
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) {
}
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;
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;
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;
goto btn_cfg_exit;
}
update = 0;
- }
+ }*/
btn_cfg_exit:
return rc;
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);
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) {
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;
goto intr_exit;
} else {
- pr_debug("%s(): Headphone detected\n",
+ pr_info("%s(): Headphone detected\n",
__func__);
snd_soc_jack_report(escore->jack,
}
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",
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,
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);
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;
* 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) {
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;
#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 |\
CDEV_STREAMING,
CDEV_DATABLOCK,
CDEV_DATALOGGING,
+ CDEV_CMD_HISTORY,
CDEV_MAX_DEV,
};
#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
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,
.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)
{
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:
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);
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) |
escore_priv.escore_power_state = escore_priv.non_vs_sleep_state;
suspend_out:
+ mutex_unlock(&escore_priv.api_mutex);
return ret;
}
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;
}
* 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)
* 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);
}
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",
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;
}
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;
escore->bus.last_response = *resp;
get_monotonic_boottime(&escore->last_resp_time);
}
-cmd_err:
+
+exit:
return err;
}
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);
__func__, rc);
escore_wakeup_exit:
- mutex_unlock(&escore->api_mutex);
return rc;
}
/* 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 */
struct escore_macro {
u32 cmd;
+ u32 resp;
unsigned long timestamp;
};
#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;
u16 es_vs_route_preset;
u16 es_cvs_preset;
int es_streaming_mode;
+ int cmd_history_size;
int sleep_abort;
unsigned long pm_time;
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;
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;
#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 */