static int es705_set_tristate(struct snd_soc_dai *dai, int tristate) { unsigned int msg, resp; int ret; static int old_tristate = -1; return 0; if (escore_priv.flag.is_fw_ready == 0) { pr_warn("%s(): es705 firmware is not ready, abort\n", __func__); return 0; } //if (old_tristate == tristate) // return 0; printk("++%s()++: %s DHWPT\n", __func__, tristate == ES705_DHWPT_RST ? "disable" : "enable"); switch (tristate) { case ES705_DHWPT_RST: case ES705_DHWPT_A_B: case ES705_DHWPT_A_C: case ES705_DHWPT_A_D: case ES705_DHWPT_B_A: case ES705_DHWPT_B_C: case ES705_DHWPT_B_D: case ES705_DHWPT_C_A: case ES705_DHWPT_C_B: case ES705_DHWPT_C_D: case ES705_DHWPT_D_A: case ES705_DHWPT_D_B: case ES705_DHWPT_D_C: break; default: dev_err(dai->dev, "Unsupported dhwpt mode %d\n", tristate); ret = -EINVAL; goto out; } msg = ES705_DHWPT_COMMAND + tristate; ret = escore_cmd(&escore_priv, msg, &resp); if (ret < 0) { dev_err(dai->dev, "escore_cmd: send %08x failed\n", msg); goto out; } old_tristate = tristate; out: return ret; }
int macro_cmd(void *ctx, u32 cmd) { struct escore_priv *escore = (struct escore_priv *)ctx; int rc; rc = escore_cmd(escore, cmd); if (!(cmd & BIT(28))) { pr_debug("escore: cmd=0x%08x Response:0x%08x\n", cmd, escore->bus.last_response); } else { pr_debug("escore: cmd=0x%08x\n", cmd); } return rc; }
int escore_write(struct snd_soc_codec *codec, unsigned int reg, unsigned int value) { struct escore_priv *escore = &escore_priv; struct escore_api_access *api_access; u32 api_word[2] = {0}; int msg_len; unsigned int val_mask; int i; int rc = 0; if (reg > escore->api_addr_max) { pr_err("%s(): invalid address = 0x%04x\n", __func__, reg); return -EINVAL; } pr_debug("%s(): reg=%08x val=%d\n", __func__, reg, value); api_access = &escore->escore_api_access[reg]; msg_len = api_access->write_msg_len; val_mask = (1 << get_bitmask_order(api_access->val_max)) - 1; memcpy((char *)api_word, (char *)api_access->write_msg, msg_len); switch (msg_len) { case 8: api_word[1] |= (val_mask & value); break; case 4: api_word[0] |= (val_mask & value); break; } pr_debug("%s(): mutex lock\n", __func__); mutex_lock(&escore->api_mutex); for (i = 0; i < msg_len / 4; i++) { rc = escore_cmd(escore, api_word[i]); if (rc < 0) { pr_err("%s(): escore_cmd()", __func__); pr_info("%s(): mutex unlock\n", __func__); mutex_unlock(&escore->api_mutex); return rc; } } pr_debug("%s(): mutex unlock\n", __func__); mutex_unlock(&escore->api_mutex); return rc; }
int escore_write_block(struct escore_priv *escore, const u32 *cmd_block) { int rc = 0; pr_debug("%s(): pm_runtime_get_sync()\n", __func__); pr_debug("%s(): mutex lock\n", __func__); mutex_lock(&escore->api_mutex); while (*cmd_block != 0xffffffff) { escore_cmd(escore, *cmd_block); usleep_range(1000, 1000); cmd_block++; } pr_debug("%s(): mutex unlock\n", __func__); mutex_unlock(&escore->api_mutex); pr_debug("%s(): pm_runtime_put_autosuspend()\n", __func__); return rc; }
unsigned int escore_read(struct snd_soc_codec *codec, unsigned int reg) { struct escore_priv *escore = &escore_priv; struct escore_api_access *api_access; u32 api_word[2] = {0}; unsigned int msg_len; unsigned int value; int rc; if (reg > escore->api_addr_max) { pr_err("%s(): invalid address = 0x%04x\n", __func__, reg); return -EINVAL; } api_access = &escore->escore_api_access[reg]; msg_len = api_access->read_msg_len; memcpy((char *)api_word, (char *)api_access->read_msg, msg_len); pr_debug("%s(): mutex lock\n", __func__); mutex_lock(&escore->api_mutex); rc = escore_cmd(escore, api_word[0]); if (rc < 0) { pr_err("%s(): escore_xxxx_write()", __func__); pr_debug("%s(): mutex unlock\n", __func__); mutex_unlock(&escore->api_mutex); return rc; } api_word[0] = escore->last_response; pr_debug("%s(): mutex unlock\n", __func__); mutex_unlock(&escore->api_mutex); value = api_word[0] & 0xffff; return value; }
static int es705_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) { unsigned int base = dai->driver->base; unsigned int msg, resp; int ret, val; u32 cmd_block[3]; return 0; if (escore_priv.flag.is_fw_ready == 0) { pr_warn("%s(port-%c): es705 firmware is not ready, abort\n", __func__, PORT_NAME(base)); return 0; } /* word length */ //if (es705_ports[PORT_ID(base)].wl != params_format(params)) { printk("++%s(port-%c)++: format=%d\n", __func__, PORT_NAME(base), params_format(params)); val = snd_pcm_format_width(params_format(params)) - 1; cmd_block[0] = ES705_PORT_PARAM_ID + base + ES705_PORT_WORDLENGHT; cmd_block[1] = ES705_PORT_SET_PARAM + val; cmd_block[2] = 0xffffffff; ret = escore_write_block(&escore_priv, cmd_block); if (ret < 0) { dev_err(dai->dev, "escore_cmd: send [%08x %08x] failed\n", cmd_block[0], cmd_block[2]); goto out; } es705_ports[PORT_ID(base)].wl = params_format(params); } /* sample rate */ //if (es705_ports[PORT_ID(base)].rate != params_rate(params)) { printk("++%s(port-%c)++: rate=%d\n", __func__, PORT_NAME(base), params_rate(params)); msg = ES705_PORT_GET_PARAM + base + ES705_PORT_CLOCK; ret = escore_cmd(&escore_priv, msg, &resp); if (ret < 0) { dev_err(dai->dev, "escore_cmd: send %08x failed\n", msg); goto out; } val = (resp & 0x100) + (params_rate(params) / 1000); cmd_block[0] = ES705_PORT_PARAM_ID + base + ES705_PORT_CLOCK; cmd_block[1] = ES705_PORT_SET_PARAM + val; cmd_block[2] = 0xffffffff; ret = escore_write_block(&escore_priv, cmd_block); if (ret < 0) { dev_err(dai->dev, "escore_cmd: send [%08x %08x] failed\n", cmd_block[0], cmd_block[2]); goto out; } es705_ports[PORT_ID(base)].rate = params_rate(params); } out: return ret; }
static int es705_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) { unsigned int base = dai->driver->base; unsigned int msg, resp; int ret = 0, val; u32 cmd_block[3]; return 0; if (escore_priv.flag.is_fw_ready == 0) { pr_warn("%s(): es705 firmware is not ready, abort\n", __func__); return 0; } //if (es705_ports[PORT_ID(base)].fmt == fmt) // return 0; /* port mode */ if (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { printk("++%s(port-%c)++: port-mode=%s\n", __func__, PORT_NAME(base), (fmt & SND_SOC_DAIFMT_FORMAT_MASK) == SND_SOC_DAIFMT_I2S ? "i2s" : "pcm"); switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { case SND_SOC_DAIFMT_DSP_A: val = 0x00; break; case SND_SOC_DAIFMT_I2S: val = 0x01; break; default: dev_err(dai->dev, "Unsupported DAI format %d\n", fmt & SND_SOC_DAIFMT_FORMAT_MASK); ret = -EINVAL; goto out; } cmd_block[0] = ES705_PORT_PARAM_ID + base + ES705_PORT_MODE; cmd_block[1] = ES705_PORT_SET_PARAM + val; cmd_block[2] = 0xffffffff; ret = escore_write_block(&escore_priv, cmd_block); if (ret < 0) { dev_err(dai->dev, "escore_cmd: send [%08x %08x] failed\n", cmd_block[0], cmd_block[2]); goto out; } /* latch edge: Tx on Falling Edge, Rx on Rising Edge */ if ((fmt & SND_SOC_DAIFMT_FORMAT_MASK) == SND_SOC_DAIFMT_DSP_A) { cmd_block[0] = ES705_PORT_PARAM_ID + base + ES705_PORT_LATCHEDGE; cmd_block[1] = ES705_PORT_SET_PARAM + 0x01; cmd_block[2] = 0xffffffff; ret = escore_write_block(&escore_priv, cmd_block); if (ret < 0) { dev_err(dai->dev, "escore_cmd: send [%08x %08x] failed\n", cmd_block[0], cmd_block[2]); goto out; } } } /* master mode */ if (fmt & SND_SOC_DAIFMT_MASTER_MASK) { printk("++%s(port-%c)++: clock-mode=%s\n", __func__, PORT_NAME(base), (fmt & SND_SOC_DAIFMT_MASTER_MASK) == SND_SOC_DAIFMT_CBS_CFS ? "slave" : "master"); msg = ES705_PORT_GET_PARAM + base + ES705_PORT_CLOCK; ret = escore_cmd(&escore_priv, msg, &resp); if (ret < 0) { dev_err(dai->dev, "escore_cmd: send %08x failed\n", msg); goto out; } switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { case SND_SOC_DAIFMT_CBS_CFS: val = resp & 0xff; // slave: bit8 = 0 break; case SND_SOC_DAIFMT_CBM_CFM: val = (resp & 0xff) | 0x100; // master: bit8 = 1 break; default: dev_err(dai->dev, "Unsupported master mode %d\n", fmt & SND_SOC_DAIFMT_MASTER_MASK); ret = -EINVAL; goto out; } cmd_block[0] = ES705_PORT_PARAM_ID + base + ES705_PORT_CLOCK; cmd_block[1] = ES705_PORT_SET_PARAM + val; cmd_block[2] = 0xffffffff; ret = escore_write_block(&escore_priv, cmd_block); if (ret < 0) { dev_err(dai->dev, "escore_cmd: send [%08x %08x] failed\n", cmd_block[0], cmd_block[2]); goto out; } } es705_ports[PORT_ID(base)].fmt = fmt; out: return ret; }
/* This function must be called with access_lock acquired */ static int escore_uart_int_osc_calibration(struct escore_priv *escore) { u16 configure_uart = cpu_to_be16(0x00); int sync_retry = ES_SYNC_MAX_RETRY; u32 resp; int rc = 0; if (escore->bus.ops.high_bw_open) { rc = escore->bus.ops.high_bw_open(escore); if (rc < 0) { dev_err(escore->dev, "%s(): high_bw_open failed %d\n", __func__, rc); goto exit_osc_calib; } } do { rc = escore_cmd(escore, (ES_INT_OSC_MEASURE_START_VS << 16), &resp); if (rc) { dev_err(escore->dev, "%s(): sending start UART calibration command failed %d", __func__, rc); continue; } rc = escore->bus.ops.high_bw_write(escore, &configure_uart, sizeof(configure_uart)); if (rc < 0) { dev_err(escore->dev, "%s(): sending configure command on uart failed %d", __func__, rc); continue; } usleep_range(5000, 5005); rc = escore_cmd(escore, (ES_INT_OSC_MEASURE_QUERY_VS << 16), &resp); if (rc) { dev_err(escore->dev, "%s(): sending check UART calibration command failed %d", __func__, rc); } else if (resp == (ES_INT_OSC_MEASURE_QUERY_VS << 16)) { dev_dbg(escore->dev, "%s(): caliberation was successful", __func__); break; } else { dev_err(escore->dev, "%s(): caliberation response 0x%08x", __func__, resp); } } while (--sync_retry); dev_dbg(escore->dev, "%s(), number of tries made : %d", __func__, ES_SYNC_MAX_RETRY - sync_retry + 1); if (!sync_retry) { /* In case of any issue switch the clock to ext oscillator */ rc = escore_switch_ext_osc(escore); if (rc) { dev_err(escore->dev, "%s(): Error switching to external OSC %d\n", __func__, rc); } } usleep_range(2000, 2005); if (escore->bus.ops.high_bw_close) { dev_dbg(escore->dev, "%s(), closing the UART", __func__); escore->bus.ops.high_bw_close(escore); } exit_osc_calib: return rc; }
int escore_vs_load(struct escore_priv *escore) { struct escore_voice_sense *voice_sense = (struct escore_voice_sense *) escore->voice_sense; int rc = 0; int write_size = ES_VS_FW_CHUNK; int data_remaining = voice_sense->vs->size; u32 sync_cmd = (ES_EVENT_RESPONSE_CMD << 16) | ES_SYNC_INTR_RISING_EDGE; u32 resp; BUG_ON(voice_sense->vs->size == 0); if (!escore->boot_ops.setup || !escore->boot_ops.finish) { dev_err(escore->dev, "%s(): boot setup or finish function undefined\n", __func__); rc = -EIO; goto escore_vs_fw_download_failed; } rc = escore->boot_ops.setup(escore); if (rc) { dev_err(escore->dev, "%s(): fw download start error\n", __func__); goto escore_vs_fw_download_failed; } dev_dbg(escore->dev, "%s(): write vs firmware image\n", __func__); while (data_remaining) { rc = escore->bus.ops.high_bw_write(escore, ((char *)voice_sense->vs->data) + (voice_sense->vs->size - data_remaining), write_size); data_remaining -= write_size; dev_dbg(escore->dev, "data_remaining = %d, write_size = %d\n", data_remaining, write_size); if (rc) { dev_err(escore->dev, "%s(): vs firmware image write error\n", __func__); rc = -EIO; goto escore_vs_fw_download_failed; } else if (data_remaining < write_size) { write_size = data_remaining; } usleep_range(2000, 2000); } escore->mode = VOICESENSE; if (((struct escore_voice_sense *)escore->voice_sense)->vs_irq != true) escore_vs_init_intr(escore); rc = escore->boot_ops.finish(escore); if (rc) { dev_err(escore->dev, "%s() vs fw download finish error\n", __func__); goto escore_vs_fw_download_failed; } else { /* Enable Voice Sense Event INTR to Host */ rc = escore_cmd(escore, sync_cmd, &resp); if (rc) dev_err(escore->dev, "%s(): escore_cmd fail %d\n", __func__, rc); if (resp != sync_cmd) { dev_err(escore->dev, "%s(): Enable VS Event INTR fail\n", __func__); goto escore_vs_fw_download_failed; } } dev_dbg(escore->dev, "%s(): fw download done\n", __func__); escore_vs_fw_download_failed: return rc; }
static int escore_vs_isr(struct notifier_block *self, unsigned long action, void *dev) { struct escore_priv *escore = (struct escore_priv *)dev; struct escore_voice_sense *voice_sense = (struct escore_voice_sense *) escore->voice_sense; u32 smooth_mute = ES_SET_SMOOTH_MUTE << 16 | ES_SMOOTH_MUTE_ZERO; u32 es_set_power_level = ES_SET_POWER_LEVEL << 16 | ES_POWER_LEVEL_6; u32 resp; int rc = 0; dev_dbg(escore->dev, "%s(): Event: 0x%04x\n", __func__, (u32)action); if ((action & 0xFF) != ES_VS_INTR_EVENT) { dev_err(escore->dev, "%s(): Invalid event callback 0x%04x\n", __func__, (u32) action); return NOTIFY_DONE; } dev_info(escore->dev, "%s(): VS event detected 0x%04x\n", __func__, (u32) action); if (voice_sense->cvs_preset != 0xFFFF && voice_sense->cvs_preset != 0) { escore->escore_power_state = ES_SET_POWER_STATE_NORMAL; escore->vs_pm_state = ES_PM_NORMAL; escore->non_vs_pm_state = ES_PM_NORMAL; escore->mode = STANDARD; } mutex_lock(&voice_sense->vs_event_mutex); voice_sense->vs_get_event = action; mutex_unlock(&voice_sense->vs_event_mutex); /* If CVS preset is set (other than 0xFFFF), earSmart chip is * in CVS mode. To make it switch from internal to external * oscillator, send power level command with highest power * level */ if (voice_sense->cvs_preset != 0xFFFF && voice_sense->cvs_preset != 0) { rc = escore_cmd(escore, smooth_mute, &resp); if (rc < 0) { pr_err("%s(): Error setting smooth mute\n", __func__); goto voiceq_isr_exit; } usleep_range(2000, 2005); rc = escore_cmd(escore, es_set_power_level, &resp); if (rc < 0) { pr_err("%s(): Error setting power level\n", __func__); goto voiceq_isr_exit; } usleep_range(2000, 2005); /* Each time earSmart chip comes in BOSKO mode after * VS detect, CVS mode will be disabled */ voice_sense->cvs_preset = 0; } kobject_uevent(&escore->dev->kobj, KOBJ_CHANGE); return NOTIFY_OK; voiceq_isr_exit: return NOTIFY_DONE; }