ASoC: msm: Add support to use slimbus dai driver

For establishing data channel for look ahead bufferring, change to use
CPU dai driver in order to genarlize the implementation to be able to
plug in a different CPU dai driver if the underlying bus interface
changes.

Change-Id: I85d163c996bb157ae125fb8b1209380643b4993b
Signed-off-by: Bhalchandra Gajare <gajare@codeaurora.org>
This commit is contained in:
Bhalchandra Gajare 2015-03-24 12:51:27 -07:00 committed by Gerrit - the friendly Code Review server
parent 504174389b
commit 59786e3672
3 changed files with 236 additions and 208 deletions

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2013-2014, Linux Foundation. All rights reserved.
* Copyright (c) 2013-2015, Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@ -16,7 +16,6 @@
#include <linux/types.h>
#include <linux/wait.h>
#include <linux/msm_ion.h>
#include <linux/dma-mapping.h>
#include <sound/lsm_params.h>
#include <linux/mfd/wcd9xxx/wcd9xxx-slimslave.h>
@ -27,6 +26,13 @@ enum {
CMD_RESP_RCVD,
};
enum wcd_cpe_event {
WCD_CPE_PRE_ENABLE = 1,
WCD_CPE_POST_ENABLE,
WCD_CPE_PRE_DISABLE,
WCD_CPE_POST_DISABLE,
};
struct wcd_cpe_afe_port_cfg {
u8 port_id;
u16 bit_width;
@ -54,7 +60,6 @@ struct wcd_cpe_lab_hw_params {
struct wcd_cpe_lsm_lab {
u32 lab_enable;
void *slim_handle;
void *core_handle;
atomic_t in_count;
atomic_t abort_read;
@ -68,6 +73,7 @@ struct wcd_cpe_lsm_lab {
struct wcd_cpe_data_pcm_buf *pcm_buf;
wait_queue_head_t period_wait;
struct completion thread_complete;
struct completion comp;
};
struct cpe_lsm_session {
@ -153,18 +159,9 @@ struct wcd_cpe_lsm_ops {
u32 bufsz, u32 bufcnt,
bool enable);
int (*lsm_lab_stop)(void *core_handle, struct cpe_lsm_session *session);
int (*lsm_lab_data_channel_open)(void *core_handle,
struct cpe_lsm_session *session);
int (*lsm_lab_data_channel_read_status)(void *core_handle,
struct cpe_lsm_session *session,
phys_addr_t phys, u32 *len);
int (*lsm_lab_data_channel_read)(void *core_handle,
struct cpe_lsm_session *session,
phys_addr_t phys, u8 *mem,
u32 read_len);
int (*lab_ch_setup)(void *core_handle,
struct cpe_lsm_session *session,
enum wcd_cpe_event event);
int (*lsm_set_data) (void *core_handle,
struct cpe_lsm_session *session,

View file

@ -2980,156 +2980,108 @@ static int wcd_cpe_dealloc_lsm_session(void *core_handle,
return ret;
}
static int slim_master_read_enable(void *core_handle,
struct cpe_lsm_session *session)
static int wcd_cpe_lab_ch_setup(void *core_handle,
struct cpe_lsm_session *session,
enum wcd_cpe_event event)
{
int rc = 0;
struct wcd_cpe_lsm_lab *lab_s = NULL;
struct wcd_cpe_core *core = (struct wcd_cpe_core *)core_handle;
struct wcd_cpe_core *core = core_handle;
struct snd_soc_codec *codec;
struct wcd9xxx *wcd9xxx;
struct wcd_cpe_lab_hw_params *lsm_params;
codec = core->codec;
wcd9xxx = codec->control_data;
lab_s = &session->lab;
lsm_params = &lab_s->hw_params;
/* The sequence should be maintained strictly */
WCD_CPE_GRAB_LOCK(&session->lsm_lock, "lsm");
if (core->cpe_cdc_cb->cdc_ext_clk)
core->cpe_cdc_cb->cdc_ext_clk(codec, true, false);
else {
pr_err("%s: Invalid callback for codec ext clk\n",
__func__);
rc = -EINVAL;
goto exit;
}
if (core->cpe_cdc_cb->lab_cdc_ch_ctl)
core->cpe_cdc_cb->lab_cdc_ch_ctl(codec, 1);
else {
pr_err("%s: Failed to enable codec slave port\n",
__func__);
rc = -EINVAL;
goto fail_mclk;
}
lab_s->slim_handle = NULL;
rc = wcd9xxx_slim_ch_master_open(wcd9xxx, lsm_params->sample_rate,
lsm_params->sample_size,
&lab_s->slim_handle,
WCD_CPE_MAD_SLIM_CHANNEL);
if (rc || lab_s->slim_handle == NULL) {
pr_err("%s: Slim Open rc %d\n",
__func__, rc);
rc = -EINVAL;
goto fail_slim_open;
}
rc = wcd9xxx_slim_ch_master_enable_read(wcd9xxx, lab_s->slim_handle);
if (rc) {
pr_err("%s: Slim enable read rc %d\n",
__func__, rc);
rc = -EINVAL;
goto fail_slim_open;
}
rc = cpe_svc_toggle_lab(core->cpe_handle, true);
if (rc) {
pr_err("%s: SVC toggle codec LAB Enable error\n", __func__);
rc = -EINVAL;
goto fail_slim_open;
}
init_waitqueue_head(&lab_s->period_wait);
WCD_CPE_REL_LOCK(&session->lsm_lock, "lsm");
return 0;
fail_slim_open:
core->cpe_cdc_cb->lab_cdc_ch_ctl(codec, 0);
fail_mclk:
core->cpe_cdc_cb->cdc_ext_clk(codec, false, false);
exit:
WCD_CPE_REL_LOCK(&session->lsm_lock, "lsm");
return rc;
}
int slim_master_read_status(void *core_handle,
struct cpe_lsm_session *session,
phys_addr_t phys, u32 *len)
{
struct wcd_cpe_core *core = (struct wcd_cpe_core *)core_handle;
struct snd_soc_codec *codec;
struct wcd9xxx *wcd9xxx;
struct wcd_cpe_lsm_lab *lab = &session->lab;
int rc = 0;
codec = core->codec;
wcd9xxx = codec->control_data;
rc = wcd9xxx_slim_ch_master_status(wcd9xxx, lab->slim_handle,
phys, len);
return rc;
}
int slim_master_read(void *core_handle,
struct cpe_lsm_session *session,
phys_addr_t phys, u8 *mem,
u32 read_len)
{
struct wcd_cpe_core *core = (struct wcd_cpe_core *)core_handle;
struct snd_soc_codec *codec;
struct wcd9xxx *wcd9xxx;
struct wcd_cpe_lsm_lab *lab = &session->lab;
int rc = 0;
if (!core || !core->codec) {
pr_err("%s: Invalid handle to %s\n",
__func__,
(!core) ? "core" : "codec");
rc = EINVAL;
goto done;
}
codec = core->codec;
wcd9xxx = codec->control_data;
rc = wcd9xxx_slim_ch_master_read(wcd9xxx, lab->slim_handle,
phys, mem, read_len);
return rc;
}
static int wcd_cpe_lsm_stop_lab(void *core_handle,
struct cpe_lsm_session *session)
{
struct wcd_cpe_lsm_lab *lab_s = NULL;
struct wcd_cpe_core *core = (struct wcd_cpe_core *)core_handle;
struct snd_soc_codec *codec;
struct wcd9xxx *wcd9xxx;
int rc = 0;
codec = core->codec;
wcd9xxx = codec->control_data;
lab_s = &session->lab;
WCD_CPE_GRAB_LOCK(&session->lsm_lock, "lsm");
/* This seqeunce should be followed strictly for closing sequence */
if (core->cpe_cdc_cb->lab_cdc_ch_ctl)
core->cpe_cdc_cb->lab_cdc_ch_ctl(codec, 0);
else
pr_err("%s: Failed to disable codec slave port\n",
__func__);
rc = wcd9xxx_slim_ch_master_close(wcd9xxx, &lab_s->slim_handle);
if (rc != 0)
pr_err("%s: wcd9xxx_slim_pcm_close rc %d\n",
__func__, rc);
rc = wcd_cpe_lsm_eob(core, session);
if (rc != 0)
if (!core->cpe_cdc_cb ||
!core->cpe_cdc_cb->cdc_ext_clk ||
!core->cpe_cdc_cb->lab_cdc_ch_ctl) {
dev_err(core->dev,
"%s: wcd_cpe_lsm_eob failed, rc %d\n",
__func__, rc);
rc = cpe_svc_toggle_lab(core->cpe_handle, false);
if (rc)
dev_err(core->dev,
"%s: LAB Voice Tx codec error, rc %d\n",
__func__, rc);
lab_s->buf_idx = 0;
lab_s->thread_status = MSM_LSM_LAB_THREAD_STOP;
atomic_set(&lab_s->in_count, 0);
lab_s->dma_write = 0;
if (core->cpe_cdc_cb->cdc_ext_clk)
core->cpe_cdc_cb->cdc_ext_clk(codec, false, false);
else
pr_err("%s: Failed to disable cdc ext clk\n",
"%s: Invalid codec callbacks\n",
__func__);
WCD_CPE_REL_LOCK(&session->lsm_lock, "lsm");
rc = -EINVAL;
goto done;
}
codec = core->codec;
dev_dbg(core->dev,
"%s: event = 0x%x\n",
__func__, event);
switch (event) {
case WCD_CPE_PRE_ENABLE:
rc = core->cpe_cdc_cb->cdc_ext_clk(codec, true, false);
if (rc) {
dev_err(core->dev,
"%s: failed to enable cdc clk, err = %d\n",
__func__, rc);
goto done;
}
rc = core->cpe_cdc_cb->lab_cdc_ch_ctl(codec,
true);
if (rc) {
dev_err(core->dev,
"%s: failed to enable cdc port, err = %d\n",
__func__, rc);
rc = core->cpe_cdc_cb->cdc_ext_clk(codec, false, false);
goto done;
}
break;
case WCD_CPE_POST_ENABLE:
rc = cpe_svc_toggle_lab(core->cpe_handle, true);
if (rc)
dev_err(core->dev,
"%s: Failed to enable lab\n", __func__);
break;
case WCD_CPE_PRE_DISABLE:
rc = core->cpe_cdc_cb->lab_cdc_ch_ctl(codec,
false);
if (rc)
dev_err(core->dev,
"%s: failed to disable cdc port, err = %d\n",
__func__, rc);
break;
case WCD_CPE_POST_DISABLE:
rc = wcd_cpe_lsm_eob(core, session);
if (rc)
dev_err(core->dev,
"%s: eob send failed, err = %d\n",
__func__, rc);
/* Continue teardown even if eob failed */
rc = cpe_svc_toggle_lab(core->cpe_handle, false);
if (rc)
dev_err(core->dev,
"%s: Failed to disable lab\n", __func__);
/* Continue with disabling even if toggle lab fails */
rc = core->cpe_cdc_cb->cdc_ext_clk(codec, false, false);
if (rc) {
dev_err(core->dev,
"%s: failed to disable cdc clk, err = %d\n",
__func__, rc);
goto done;
}
break;
default:
dev_err(core->dev,
"%s: Invalid event 0x%x\n",
__func__, event);
rc = -EINVAL;
break;
}
done:
return rc;
}
@ -3151,10 +3103,7 @@ int wcd_cpe_get_lsm_ops(struct wcd_cpe_lsm_ops *lsm_ops)
lsm_ops->lsm_start = wcd_cpe_cmd_lsm_start;
lsm_ops->lsm_stop = wcd_cpe_cmd_lsm_stop;
lsm_ops->lsm_lab_control = wcd_cpe_lsm_control_lab;
lsm_ops->lsm_lab_stop = wcd_cpe_lsm_stop_lab;
lsm_ops->lsm_lab_data_channel_read = slim_master_read;
lsm_ops->lsm_lab_data_channel_read_status = slim_master_read_status;
lsm_ops->lsm_lab_data_channel_open = slim_master_read_enable;
lsm_ops->lab_ch_setup = wcd_cpe_lab_ch_setup;
lsm_ops->lsm_set_data = wcd_cpe_lsm_set_data;
return 0;
}

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2013-2014, Linux Foundation. All rights reserved.
* Copyright (c) 2013-2015, Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@ -26,7 +26,7 @@
#include <sound/cpe_core.h>
#include <sound/lsm_params.h>
#include <sound/pcm_params.h>
#include <sound/msm-slim-dma.h>
#define LSM_VOICE_WAKEUP_APP_V2 2
#define LISTEN_MIN_NUM_PERIODS 2
@ -251,6 +251,7 @@ static int msm_cpe_lsm_lab_stop(struct snd_pcm_substream *substream)
struct wcd_cpe_lsm_ops *lsm_ops;
struct cpe_lsm_session *session;
struct wcd_cpe_lsm_lab *lab_sess;
struct msm_slim_dma_data *dma_data = NULL;
int rc;
if (!cpe || !cpe->core_handle) {
@ -270,6 +271,15 @@ static int msm_cpe_lsm_lab_stop(struct snd_pcm_substream *substream)
lsm_ops = &cpe->lsm_ops;
session = lsm_d->lsm_session;
lab_sess = &session->lab;
if (rtd->cpu_dai)
dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai,
substream);
if (!dma_data || !dma_data->dai_channel_ctl) {
dev_err(rtd->dev,
"%s: dma_data is not set\n",
__func__);
return -EINVAL;
}
if (lab_sess->thread_status != MSM_LSM_LAB_THREAD_STOP) {
@ -292,13 +302,31 @@ static int msm_cpe_lsm_lab_stop(struct snd_pcm_substream *substream)
}
lab_sess->thread_status = MSM_LSM_LAB_THREAD_STOP;
rc = lsm_ops->lsm_lab_stop(cpe->core_handle, session);
if (rc) {
lab_sess->buf_idx = 0;
atomic_set(&lab_sess->in_count, 0);
lab_sess->dma_write = 0;
rc = lsm_ops->lab_ch_setup(lab_sess->core_handle,
lab_sess->lsm_s,
WCD_CPE_PRE_DISABLE);
if (rc)
dev_err(rtd->dev,
"%s: Lab stop failed, error = %d\n",
"%s: PRE ch teardown failed, err = %d\n",
__func__, rc);
/* continue with teardown even if any intermediate step fails */
rc = dma_data->dai_channel_ctl(dma_data, rtd->cpu_dai, false);
if (rc)
dev_err(rtd->dev,
"%s: open data failed %d\n", __func__, rc);
dma_data->ph = 0;
rc = lsm_ops->lab_ch_setup(lab_sess->core_handle,
lab_sess->lsm_s,
WCD_CPE_POST_DISABLE);
if (rc)
dev_err(rtd->dev,
"%s: POST ch teardown failed, err = %d\n",
__func__, rc);
return rc;
}
}
return 0;
@ -315,11 +343,13 @@ static int msm_cpe_lab_thread(void *data)
{
struct wcd_cpe_lsm_lab *lab = (struct wcd_cpe_lsm_lab *)data;
struct wcd_cpe_lab_hw_params *hw_params = &lab->hw_params;
struct wcd_cpe_core *core = (struct wcd_cpe_core *)lab->core_handle;
struct snd_pcm_substream *substream = lab->substream;
struct cpe_priv *cpe = cpe_get_private_data(substream);
struct wcd_cpe_lsm_ops *lsm_ops;
struct wcd_cpe_data_pcm_buf *cur_buf, *next_buf;
struct msm_slim_dma_data *dma_data = NULL;
struct snd_soc_pcm_runtime *rtd = NULL;
bool wait_timedout = false;
int rc = 0;
u32 done_len = 0;
u32 buf_count = 1;
@ -328,45 +358,79 @@ static int msm_cpe_lab_thread(void *data)
set_current_state(TASK_INTERRUPTIBLE);
pr_debug("%s: Lab thread start\n", __func__);
init_completion(&lab->comp);
if (!core || !cpe) {
if (PCM_RUNTIME_CHECK(substream))
return -EINVAL;
if (!lab->core_handle || !cpe) {
pr_err("%s: Handle to %s is invalid\n",
__func__,
(!core) ? "core" : "cpe");
(!lab->core_handle) ? "core" : "cpe");
rc = -EINVAL;
goto done;
}
rtd = substream->private_data;
if (rtd->cpu_dai)
dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai,
substream);
if (!dma_data || !dma_data->dai_channel_ctl) {
pr_err("%s: dma_data is not set\n", __func__);
rc = -EINVAL;
goto done;
}
lsm_ops = &cpe->lsm_ops;
memset(lab->pcm_buf[0].mem, 0, lab->pcm_size);
if (lsm_ops->lsm_lab_data_channel_read == NULL ||
lsm_ops->lsm_lab_data_channel_read_status == NULL) {
pr_err("%s: slim ops not present\n", __func__);
rc = -EINVAL;
goto done;
}
if (!hw_params || !substream || !cpe) {
pr_err("%s: Lab thread pointers NULL\n", __func__);
rc = -EINVAL;
goto done;
}
if (!kthread_should_stop()) {
rc = lsm_ops->lsm_lab_data_channel_read(core, lab->lsm_s,
lab->pcm_buf[0].phys,
lab->pcm_buf[0].mem,
hw_params->buf_sz);
rc = lsm_ops->lab_ch_setup(lab->core_handle,
lab->lsm_s,
WCD_CPE_PRE_ENABLE);
if (rc) {
pr_err("%s:Slim read error %d\n", __func__, rc);
dev_err(rtd->dev,
"%s: PRE ch setup failed, err = %d\n",
__func__, rc);
goto done;
}
rc = dma_data->dai_channel_ctl(dma_data, rtd->cpu_dai, true);
if (rc) {
dev_err(rtd->dev,
"%s: open data failed %d\n", __func__, rc);
goto done;
}
rc = lsm_ops->lab_ch_setup(lab->core_handle,
lab->lsm_s,
WCD_CPE_POST_ENABLE);
if (rc) {
dev_err(rtd->dev,
"%s: POST ch setup failed, err = %d\n",
__func__, rc);
goto done;
}
dev_dbg(rtd->dev, "%s: Established data channel\n",
__func__);
init_waitqueue_head(&lab->period_wait);
memset(lab->pcm_buf[0].mem, 0, lab->pcm_size);
rc = slim_port_xfer(dma_data->sdev, dma_data->ph,
lab->pcm_buf[0].phys,
hw_params->buf_sz, &lab->comp);
if (rc) {
dev_err(rtd->dev,
"%s: buf[0] slim_port_xfer failed, err = %d\n",
__func__, rc);
goto done;
}
cur_buf = &lab->pcm_buf[0];
next_buf = &lab->pcm_buf[1];
} else {
pr_debug("%s: LAB stopped before starting read\n",
dev_dbg(rtd->dev,
"%s: LAB stopped before starting read\n",
__func__);
goto done;
}
@ -374,22 +438,38 @@ static int msm_cpe_lab_thread(void *data)
while (!kthread_should_stop() &&
lab->thread_status != MSM_LSM_LAB_THREAD_ERROR) {
rc = lsm_ops->lsm_lab_data_channel_read(core, lab->lsm_s,
next_buf->phys,
next_buf->mem,
hw_params->buf_sz);
rc = slim_port_xfer(dma_data->sdev, dma_data->ph,
next_buf->phys,
hw_params->buf_sz, &lab->comp);
if (rc) {
pr_err("%s: Thread read Slim read error %d\n",
__func__, rc);
dev_err(rtd->dev,
"%s: slim_port_xfer failed, err = %d\n",
__func__, rc);
lab->thread_status = MSM_LSM_LAB_THREAD_ERROR;
}
rc = lsm_ops->lsm_lab_data_channel_read_status(core, lab->lsm_s,
cur_buf->phys, &done_len);
if (rc) {
pr_err("%s: Wait on current buf failed %d\n",
__func__, rc);
rc = wait_for_completion_timeout(&lab->comp, (2 * HZ/10));
if (!rc) {
dev_err(rtd->dev,
"%s: wait timedout for slim buffer\n",
__func__);
wait_timedout = true;
} else {
wait_timedout = false;
}
rc = slim_port_get_xfer_status(dma_data->sdev,
dma_data->ph,
&cur_buf->phys, &done_len);
if (rc ||
(!rc && wait_timedout)) {
dev_err(rtd->dev,
"%s: xfer_status failure, rc = %d, wait_timedout = %s\n",
__func__, rc,
(wait_timedout ? "true" : "false"));
lab->thread_status = MSM_LSM_LAB_THREAD_ERROR;
}
if (done_len ||
((!done_len) &&
lab->thread_status == MSM_LSM_LAB_THREAD_ERROR)) {
@ -405,11 +485,13 @@ static int msm_cpe_lab_thread(void *data)
next_buf = &lab->pcm_buf[buf_count + 1];
buf_count++;
}
pr_debug("%s: Cur buf = %p Next Buf = %p\n"
" buf count = 0x%x\n",
dev_dbg(rtd->dev,
"%s: Cur buf = %p Next Buf = %p\n"
" buf count = 0x%x\n",
__func__, cur_buf, next_buf, buf_count);
} else {
pr_err("%s: SB get status, invalid len = 0x%x\n",
dev_err(rtd->dev,
"%s: SB get status, invalid len = 0x%x\n",
__func__, done_len);
}
done_len = 0;
@ -507,6 +589,7 @@ static int msm_cpe_lsm_open(struct snd_pcm_substream *substream)
/* Explicitly Assign the LAB thread to STOP state */
lsm_d->lsm_session->lab.thread_status = MSM_LSM_LAB_THREAD_STOP;
lsm_d->lsm_session->started = false;
init_waitqueue_head(&lsm_d->lsm_session->lab.period_wait);
dev_dbg(rtd->dev, "%s: allocated session with id = %d\n",
__func__, lsm_d->lsm_session->id);
@ -747,6 +830,7 @@ static int msm_cpe_lsm_ioctl_shared(struct snd_pcm_substream *substream,
}
lab_sess->substream = substream;
lab_sess->lsm_s = session;
dma_buf->dev.type = SNDRV_DMA_TYPE_DEV;
dma_buf->dev.dev = substream->pcm->card->dev;
dma_buf->private_data = NULL;
@ -1134,8 +1218,6 @@ static int msm_cpe_lsm_lab_start(struct snd_pcm_substream *substream,
atomic_set(&lab_sess->abort_read, 0);
pr_debug("%s: KW detected,\n"
"scheduling LAB thread\n", __func__);
lsm_ops->lsm_lab_data_channel_open(
cpe->core_handle, session);
/*
* Even though thread might be only scheduled and