Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c31ae1e3 authored by Bhalchandra Gajare's avatar Bhalchandra Gajare Committed by Gerrit - the friendly Code Review server
Browse files

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 generalize the implementation to be able to
plug in a different CPU dai driver if the underlying bus interface
changes.

Change-Id: Iac059a2f81fa363f3178c69a4066224972521672
Signed-off-by: default avatarBhalchandra Gajare <gajare@codeaurora.org>
parent d3bd0080
Loading
Loading
Loading
Loading
+12 −15
Original line number Diff line number Diff line
/*
 * 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,
	int (*lab_ch_setup)(void *core_handle,
				   struct cpe_lsm_session *session,
				phys_addr_t phys, u8 *mem,
				u32 read_len);
				   enum wcd_cpe_event event);

	int (*lsm_set_data) (void *core_handle,
			struct cpe_lsm_session *session,
+85 −136
Original line number Diff line number Diff line
@@ -3000,156 +3000,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;
	int rc = 0;

	codec = core->codec;
	wcd9xxx = dev_get_drvdata(codec->dev->parent);
	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 || !core->codec) {
		pr_err("%s: Invalid handle to %s\n",
			__func__,
			(!core) ? "core" : "codec");
		rc = EINVAL;
		goto done;
	}

	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",
	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: Invalid codec callbacks\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;
		goto done;
	}
	rc = wcd9xxx_slim_ch_master_enable_read(wcd9xxx, lab_s->slim_handle);

	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) {
		pr_err("%s: Slim enable read rc %d\n",
			dev_err(core->dev,
				"%s: failed to enable cdc clk, err = %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;
			goto done;
		}

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 = dev_get_drvdata(codec->dev->parent);
	rc = wcd9xxx_slim_ch_master_status(wcd9xxx, lab->slim_handle,
					   phys, len);
	return rc;
		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;
		}
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;

	codec = core->codec;
	wcd9xxx = dev_get_drvdata(codec->dev->parent);
	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;
		break;

	codec = core->codec;
	wcd9xxx = dev_get_drvdata(codec->dev->parent);
	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__);
	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;

	rc = wcd9xxx_slim_ch_master_close(wcd9xxx, &lab_s->slim_handle);
	if (rc != 0)
		pr_err("%s: wcd9xxx_slim_pcm_close rc %d\n",
	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 != 0)
		if (rc)
			dev_err(core->dev,
			"%s: wcd_cpe_lsm_eob failed, rc %d\n",
				"%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: LAB Voice Tx codec error, rc %d\n",
			"%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;
		}

	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",
			__func__);
	WCD_CPE_REL_LOCK(&session->lsm_lock, "lsm");
		break;

	default:
		dev_err(core->dev,
			"%s: Invalid event 0x%x\n",
			__func__, event);
		rc = -EINVAL;
		break;
	}

done:
	return rc;
}

@@ -3171,10 +3123,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;
}
+126 −44
Original line number Diff line number Diff line
/*
 * 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 (PCM_RUNTIME_CHECK(substream))
		return -EINVAL;

	if (!core || !cpe) {
	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;
	if (!kthread_should_stop()) {
		rc = lsm_ops->lab_ch_setup(lab->core_handle,
					   lab->lsm_s,
					   WCD_CPE_PRE_ENABLE);
		if (rc) {
			dev_err(rtd->dev,
				"%s: PRE ch setup failed, err = %d\n",
				__func__, rc);
			goto done;
		}

	if (!hw_params || !substream || !cpe) {
		pr_err("%s: Lab thread pointers NULL\n", __func__);
		rc = -EINVAL;
		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;
		}

	if (!kthread_should_stop()) {
		rc = lsm_ops->lsm_lab_data_channel_read(core, lab->lsm_s,
		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,
					lab->pcm_buf[0].mem,
					hw_params->buf_sz);
				    hw_params->buf_sz, &lab->comp);
		if (rc) {
			pr_err("%s:Slim read error %d\n", __func__, 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,
		rc = slim_port_xfer(dma_data->sdev, dma_data->ph,
				    next_buf->phys,
						next_buf->mem,
						hw_params->buf_sz);
				    hw_params->buf_sz, &lab->comp);
		if (rc) {
			pr_err("%s: Thread read Slim read error %d\n",
			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"
			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