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

Commit 52f3d1bd authored by Bhalchandra Gajare's avatar Bhalchandra Gajare
Browse files

ASoC: wcd_cpe_core: Split CPE initialization



Since CPE (Codec Processing Engine) initialization and enablement is
being done in one shot, the CPE initialization is also delayed if
enablement is delayed. This can possibly cause issues with userspace
interaction. Separate out CPE initialization from enablement such that
CPE  hardware block on the codec can be initialized early during probe
but can still remain disabled.

Change-Id: I732761ad1ad3628a0170fa29de8c46c5da448249
Signed-off-by: default avatarBhalchandra Gajare <gajare@codeaurora.org>
parent 79f7e503
Loading
Loading
Loading
Loading
+47 −23
Original line number Diff line number Diff line
@@ -2678,6 +2678,21 @@ static int tomtom_codec_enable_adc(struct snd_soc_dapm_widget *w,
	return 0;
}

static int tomtom_codec_ext_clk_en(struct snd_soc_codec *codec,
		int enable, bool dapm)
{
	struct tomtom_priv *tomtom = snd_soc_codec_get_drvdata(codec);

	if (!tomtom->codec_ext_clk_en_cb) {
		dev_err(codec->dev,
			"%s: Invalid ext_clk_callback\n",
			__func__);
		return -EINVAL;
	}

	return tomtom->codec_ext_clk_en_cb(codec, enable, dapm);
}

/* tomtom_codec_internal_rco_ctrl( )
 * Make sure that BG_CLK_LOCK is not acquired. Exit if acquired to avoid
 * potential deadlock as ext_clk_en_cb() also tries to acquire the same
@@ -2687,11 +2702,21 @@ static int tomtom_codec_internal_rco_ctrl(struct snd_soc_codec *codec,
					  bool enable)
{
	struct tomtom_priv *tomtom = snd_soc_codec_get_drvdata(codec);
	int ret = 0;

	if (mutex_is_locked(&tomtom->resmgr.codec_bg_clk_lock)) {
		dev_err(codec->dev, "%s: BG_CLK already acquired\n",
			__func__);
		return -EINVAL;
		ret = -EINVAL;
		goto done;
	}

	if (!tomtom->codec_ext_clk_en_cb) {
		dev_err(codec->dev,
			"%s: Invalid ext_clk_callback\n",
			__func__);
		ret = -EINVAL;
		goto done;
	}

	if (enable) {
@@ -2702,14 +2727,14 @@ static int tomtom_codec_internal_rco_ctrl(struct snd_soc_codec *codec,
						     WCD9XXX_CLK_RCO);
			WCD9XXX_BG_CLK_UNLOCK(&tomtom->resmgr);
		} else {
			tomtom->codec_ext_clk_en_cb(codec, true, false);
			tomtom_codec_ext_clk_en(codec, true, false);
			WCD9XXX_BG_CLK_LOCK(&tomtom->resmgr);
			tomtom->resmgr.ext_clk_users =
					tomtom->codec_get_ext_clk_cnt();
			wcd9xxx_resmgr_get_clk_block(&tomtom->resmgr,
						     WCD9XXX_CLK_RCO);
			WCD9XXX_BG_CLK_UNLOCK(&tomtom->resmgr);
			tomtom->codec_ext_clk_en_cb(codec, false, false);
			tomtom_codec_ext_clk_en(codec, false, false);
		}

	} else {
@@ -2719,7 +2744,8 @@ static int tomtom_codec_internal_rco_ctrl(struct snd_soc_codec *codec,
		WCD9XXX_BG_CLK_UNLOCK(&tomtom->resmgr);
	}

	return 0;
done:
	return ret;
}

static int tomtom_codec_enable_aux_pga(struct snd_soc_dapm_widget *w,
@@ -7832,38 +7858,29 @@ static int tomtom_codec_fll_enable(struct snd_soc_codec *codec,
	return 0;
}

static void tomtom_codec_cpe_setup_callbacks(
		struct wcd_cpe_cdc_cb *cpe_cb,
		int (*cdc_ext_clk)(struct snd_soc_codec *codec,
		int enable, bool dapm))
{
	cpe_cb->cdc_clk_en = tomtom_codec_internal_rco_ctrl;
	cpe_cb->cpe_clk_en = tomtom_codec_fll_enable;
	cpe_cb->slimtx_lab_en = tomtom_codec_enable_slimtx_mad;
	if (cdc_ext_clk == NULL)
		pr_err("%s: MCLK could not be set", __func__);
	cpe_cb->cdc_ext_clk = cdc_ext_clk;
}
static const struct wcd_cpe_cdc_cb cpe_cb = {
	.cdc_clk_en = tomtom_codec_internal_rco_ctrl,
	.cpe_clk_en = tomtom_codec_fll_enable,
	.slimtx_lab_en = tomtom_codec_enable_slimtx_mad,
	.cdc_ext_clk = tomtom_codec_ext_clk_en,
};

int tomtom_enable_cpe(struct snd_soc_codec *codec)
static int tomtom_cpe_initialize(struct snd_soc_codec *codec)
{
	struct tomtom_priv *tomtom = snd_soc_codec_get_drvdata(codec);
	struct wcd_cpe_params cpe_params;
	struct wcd_cpe_cdc_cb cpe_cdc_cb;

	tomtom_codec_cpe_setup_callbacks(&cpe_cdc_cb,
					 tomtom->codec_ext_clk_en_cb);
	memset(&cpe_params, 0,
	       sizeof(struct wcd_cpe_params));
	cpe_params.codec = codec;
	cpe_params.get_cpe_core = tomtom_codec_get_cpe_core;
	cpe_params.cdc_cb = &cpe_cdc_cb;
	cpe_params.cdc_cb = &cpe_cb;
	cpe_params.dbg_mode = cpe_debug_mode;
	cpe_params.cdc_major_ver = TOMTOM_CPE_MAJOR_VER;
	cpe_params.cdc_minor_ver = TOMTOM_CPE_MINOR_VER;
	cpe_params.cdc_id = TOMTOM_CPE_CDC_ID;

	tomtom->cpe_core = wcd_cpe_init_and_boot("cpe", codec,
	tomtom->cpe_core = wcd_cpe_init("cpe", codec,
						 &cpe_params);
	if (IS_ERR_OR_NULL(tomtom->cpe_core)) {
		dev_err(codec->dev,
@@ -7874,7 +7891,6 @@ int tomtom_enable_cpe(struct snd_soc_codec *codec)

	return 0;
}
EXPORT_SYMBOL(tomtom_enable_cpe);

int tomtom_enable_qfuse_sensing(struct snd_soc_codec *codec)
{
@@ -8052,6 +8068,14 @@ static int tomtom_codec_probe(struct snd_soc_codec *codec)
	snd_soc_dapm_sync(dapm);

	codec->ignore_pmdown_time = 1;
	ret = tomtom_cpe_initialize(codec);
	if (ret) {
		dev_info(codec->dev,
			"%s: cpe initialization failed, ret = %d\n",
			__func__, ret);
		/* Do not fail probe if CPE failed */
		ret = 0;
	}
	return ret;

err_pdata:
+0 −1
Original line number Diff line number Diff line
@@ -125,6 +125,5 @@ extern void tomtom_register_ext_clk_cb(
				int enable, bool dapm),
	int (*get_ext_clk_cnt) (void),
	struct snd_soc_codec *codec);
extern int tomtom_enable_cpe(struct snd_soc_codec *codec);
extern int tomtom_enable_qfuse_sensing(struct snd_soc_codec *codec);
#endif
+164 −39
Original line number Diff line number Diff line
@@ -98,6 +98,32 @@ static void wcd_cpe_svc_event_cb(const struct cpe_svc_notification *param);
static int wcd_cpe_setup_irqs(struct wcd_cpe_core *core);
static void wcd_cpe_cleanup_irqs(struct wcd_cpe_core *core);

struct cpe_load_priv {
	void *cdc_handle;
	int cpe_load;
	struct kobject *cpe_load_kobj;
	struct attribute_group *attr_group;
};

static ssize_t wcd_cpe_load_store(struct kobject *kobj,
	struct kobj_attribute *attr,
	const char *buf,
	size_t count);

static struct kobj_attribute cpe_load_attr =
	__ATTR(load, 0600, NULL, wcd_cpe_load_store);

static struct attribute *attrs[] = {
	&cpe_load_attr.attr,
	NULL,
};

static struct attribute_group attr_grp = {
	.attrs = attrs,
};

static struct cpe_load_priv cpe_priv;

/* wcd_cpe_lsm_session_active: check if any session is active
 * return true if any session is active.
 */
@@ -245,21 +271,21 @@ static int wcd_cpe_enable_cpe_clks(struct wcd_cpe_core *core, bool enable)
{
	int ret = 0;

	if (!core || !core->cpe_cdc_cb.cdc_clk_en ||
	    !core->cpe_cdc_cb.cpe_clk_en) {
	if (!core || !core->cpe_cdc_cb ||
	    !core->cpe_cdc_cb->cpe_clk_en) {
		pr_err("%s: invalid handle\n",
			__func__);
		return -EINVAL;
	}

	ret = core->cpe_cdc_cb.cdc_clk_en(core->codec, enable);
	ret = core->cpe_cdc_cb->cdc_clk_en(core->codec, enable);
	if (ret) {
		dev_err(core->dev, "%s: Failed to enable RCO\n",
			__func__);
		return ret;
	}

	ret = core->cpe_cdc_cb.cpe_clk_en(core->codec, enable);
	ret = core->cpe_cdc_cb->cpe_clk_en(core->codec, enable);
	if (ret) {
		dev_err(core->dev,
			"%s: cpe_clk_en() failed, err = %d\n",
@@ -730,6 +756,17 @@ int wcd_cpe_ssr_event(void *core_handle,
		return -EINVAL;
	}

	/*
	 * If CPE is not even enabled, the SSR event for
	 * CPE needs to be ignored
	 */
	if (core->ssr_type == WCD_CPE_INITIALIZED) {
		dev_info(core->dev,
			"%s: CPE initialized but not enabled, skip CPE ssr\n",
			 __func__);
		return 0;
	}

	dev_dbg(core->dev,
		"%s: Schedule ssr work, event = %d\n",
		__func__, core->ssr_type);
@@ -1052,16 +1089,99 @@ fail_engine_irq:
}

/*
 * wcd_cpe_init_and_boot: Initialize and bootup CPE hardware block
 * wcd_cpe_enable: setup the cpe interrupts and schedule
 *	the work to download image and bootup the CPE.
 * core: handle to cpe core structure
 */
static int wcd_cpe_enable(struct wcd_cpe_core *core)
{
	int ret = 0;

	if (!core) {
		pr_err("%s: Invalid handle to core\n",
			__func__);
		ret = -EINVAL;
		goto done;
	}

	if (core->ssr_type != WCD_CPE_INITIALIZED) {
		dev_err(core->dev,
			"%s: CPE not initialized, state = 0x%x\n",
			__func__, core->ssr_type);
		ret = -EINVAL;
		goto done;
	}

	ret = wcd_cpe_setup_irqs(core);
	if (ret) {
		dev_err(core->dev,
			"%s: CPE IRQs setup failed, error = %d\n",
			__func__, ret);
		goto done;
	}

	core->ssr_type = WCD_CPE_ENABLED;
	schedule_work(&core->load_fw_work);

done:
	return ret;
}

/*
 * wcd_cpe_load_store: Function invoked with sysfs property
 *	is written to. Enable CPE if value of the cpe_load
 *	property is non-zero.
 * kobj: Kobject associated with the sysfs property
 * attr: The attribute that is written to
 * buf: holds the data that is written
 * count: number of data bytes in the buffer
 */
static ssize_t wcd_cpe_load_store(struct kobject *kobj,
	struct kobj_attribute *attr,
	const char *buf,
	size_t count)
{
	struct wcd_cpe_core *core;
	int ret = 0;

	if (cpe_priv.cpe_load) {
		pr_err("%s: CPE already loaded\n",
			__func__);
		goto done;
	}

	core = wcd_cpe_get_core_handle(cpe_priv.cdc_handle);
	if (!core) {
		pr_err("%s: Invalid core handle\n",
			__func__);
		goto done;
	}

	sscanf(buf, "%du", &cpe_priv.cpe_load);

	if (cpe_priv.cpe_load) {
		ret = wcd_cpe_enable(core);
		if (IS_ERR_VALUE(ret))
			cpe_priv.cpe_load = 0;
		else
			pr_info("%s: CPE enabled for tomtom_codec\n",
				__func__);
	}

done:
	return count;
}

/*
 * wcd_cpe_init: Initialize CPE related structures
 * @img_fname: filename for firmware image
 * @codec: handle to codec requesting for image download
 * @params: parameter structure passed from caller
 *
 * This API will initialize the cpe core and schedule work
 * to perform firmware image download to CPE and bootup
 * CPE. Will also request for CPE related interrupts.
 * This API will initialize the cpe core but will not
 * download the image or boot the cpe core.
 */
struct wcd_cpe_core *wcd_cpe_init_and_boot(const char *img_fname,
struct wcd_cpe_core *wcd_cpe_init(const char *img_fname,
	struct snd_soc_codec *codec,
	struct wcd_cpe_params *params)
{
@@ -1114,10 +1234,7 @@ struct wcd_cpe_core *wcd_cpe_init_and_boot(const char *img_fname,
	core->cdc_info.minor_version = params->cdc_minor_ver;
	core->cdc_info.id = params->cdc_id;

	core->cpe_cdc_cb.cdc_clk_en = params->cdc_cb->cdc_clk_en;
	core->cpe_cdc_cb.cpe_clk_en = params->cdc_cb->cpe_clk_en;
	core->cpe_cdc_cb.cdc_ext_clk   = params->cdc_cb->cdc_ext_clk;
	core->cpe_cdc_cb.slimtx_lab_en = params->cdc_cb->slimtx_lab_en;
	core->cpe_cdc_cb = params->cdc_cb;

	INIT_WORK(&core->load_fw_work, wcd_cpe_load_fw_image);
	INIT_WORK(&core->ssr_work, wcd_cpe_ssr_work);
@@ -1154,13 +1271,6 @@ struct wcd_cpe_core *wcd_cpe_init_and_boot(const char *img_fname,
		goto fail_cpe_register;
	}

	ret = wcd_cpe_setup_irqs(core);
	if (ret) {
		dev_err(core->dev,
			"%s: CPE IRQs setup failed, error = %d\n",
			__func__, ret);
		goto fail_setup_irq;
	}

	card = codec->card->snd_card;
	snprintf(proc_name, (sizeof("cpe") + sizeof("_state") +
@@ -1192,11 +1302,24 @@ struct wcd_cpe_core *wcd_cpe_init_and_boot(const char *img_fname,
		 */
	}

	schedule_work(&core->load_fw_work);
	return core;
	cpe_priv.cdc_handle = codec;
	cpe_priv.attr_group = &attr_grp;
	cpe_priv.cpe_load_kobj = kobject_create_and_add("wcd_cpe",
					       kernel_kobj);
	if (!cpe_priv.cpe_load_kobj) {
		pr_err("%s: cpe_load: sysfs create_add failed\n",
			__func__);
		goto fail_cpe_register;
	} else if (sysfs_create_group(cpe_priv.cpe_load_kobj,
				      cpe_priv.attr_group)) {
		pr_err("%s: sysfs_create_group failed\n", __func__);
		kobject_del(cpe_priv.cpe_load_kobj);
		goto fail_cpe_register;
	}

	core->ssr_type = WCD_CPE_INITIALIZED;

fail_setup_irq:
	cpe_svc_deregister(core->cpe_handle, core->cpe_reg_handle);
	return core;

fail_cpe_register:
	cpe_svc_deinitialize(core->cpe_handle);
@@ -1205,7 +1328,7 @@ fail_cpe_initialize:
	kfree(core);
	return NULL;
}
EXPORT_SYMBOL(wcd_cpe_init_and_boot);
EXPORT_SYMBOL(wcd_cpe_init);

/*
 * wcd_cpe_cmi_lsm_callback: callback called from cpe services
@@ -2415,17 +2538,19 @@ static int slim_master_read_enable(void *core_handle,
	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);
	if (core->cpe_cdc_cb->cdc_ext_clk)
		core->cpe_cdc_cb->cdc_ext_clk(codec, true, false);
	else {
		pr_err("%s: MCLK cannot be enabled NULL\n", __func__);
		pr_err("%s: Invalid callback for codec ext clk\n",
			__func__);
		rc = -EINVAL;
		goto exit;
	}
	if (core->cpe_cdc_cb.slimtx_lab_en)
		core->cpe_cdc_cb.slimtx_lab_en(codec, 1);

	if (core->cpe_cdc_cb->slimtx_lab_en)
		core->cpe_cdc_cb->slimtx_lab_en(codec, 1);
	else {
		pr_err("%s: Err slim slave cannot be enabled\n",
		pr_err("%s: Failed to enable codec slave port\n",
			__func__);
		rc = -EINVAL;
		goto fail_mclk;
@@ -2459,9 +2584,9 @@ static int slim_master_read_enable(void *core_handle,
	return 0;

fail_slim_open:
	core->cpe_cdc_cb.slimtx_lab_en(codec, 0);
	core->cpe_cdc_cb->slimtx_lab_en(codec, 0);
fail_mclk:
	core->cpe_cdc_cb.cdc_ext_clk(codec, false, false);
	core->cpe_cdc_cb->cdc_ext_clk(codec, false, false);
exit:
	WCD_CPE_REL_LOCK(&session->lsm_lock, "lsm");
	return rc;
@@ -2514,10 +2639,10 @@ static int wcd_cpe_lsm_stop_lab(void *core_handle,
	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.slimtx_lab_en)
		core->cpe_cdc_cb.slimtx_lab_en(codec, 0);
	if (core->cpe_cdc_cb->slimtx_lab_en)
		core->cpe_cdc_cb->slimtx_lab_en(codec, 0);
	else
		pr_err("%s: Err slim slave cannot be enabled\n",
		pr_err("%s: Failed to disable codec slave port\n",
			__func__);

	rc = wcd9xxx_slim_ch_master_close(wcd9xxx, &lab_s->slim_handle);
@@ -2541,10 +2666,10 @@ static int wcd_cpe_lsm_stop_lab(void *core_handle,
	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);
	if (core->cpe_cdc_cb->cdc_ext_clk)
		core->cpe_cdc_cb->cdc_ext_clk(codec, false, false);
	else
		pr_err("%s: MCLK cannot be disable NULL\n",
		pr_err("%s: Failed to disable cdc ext clk\n",
			__func__);
	WCD_CPE_REL_LOCK(&session->lsm_lock, "lsm");
	return rc;
+8 −4
Original line number Diff line number Diff line
@@ -38,8 +38,12 @@ struct wcd_cpe_cdc_cb {
};

enum wcd_cpe_ssr_state_event {
	/* Indicates CPE is initialized */
	WCD_CPE_INITIALIZED = 0,
	/* Indicates CPE is enabled */
	WCD_CPE_ENABLED,
	/* Indicates that CPE is currently active */
	WCD_CPE_ACTIVE = 0,
	WCD_CPE_ACTIVE,
	/* Event from underlying bus notifying bus is down */
	WCD_CPE_BUS_DOWN_EVENT,
	/* Event from CPE block, notifying CPE is down */
@@ -84,7 +88,7 @@ struct wcd_cpe_core {
	int cpe_debug_mode;

	/* callbacks for codec specific implementation */
	struct wcd_cpe_cdc_cb cpe_cdc_cb;
	const struct wcd_cpe_cdc_cb *cpe_cdc_cb;

	/* work to handle CPE SSR*/
	struct work_struct ssr_work;
@@ -118,7 +122,7 @@ struct wcd_cpe_params {
	struct snd_soc_codec *codec;
	struct wcd_cpe_core * (*get_cpe_core) (
				struct snd_soc_codec *);
	struct wcd_cpe_cdc_cb *cdc_cb;
	const struct wcd_cpe_cdc_cb *cdc_cb;
	int dbg_mode;
	u16 cdc_major_ver;
	u16 cdc_minor_ver;
@@ -127,5 +131,5 @@ struct wcd_cpe_params {

int wcd_cpe_ssr_event(void *core_handle,
		      enum wcd_cpe_ssr_state_event event);
struct wcd_cpe_core *wcd_cpe_init_and_boot(const char *,
struct wcd_cpe_core *wcd_cpe_init(const char *,
struct snd_soc_codec *, struct wcd_cpe_params *params);
+0 −77
Original line number Diff line number Diff line
@@ -88,33 +88,6 @@ static void *adsp_state_notifier;

#define ADSP_STATE_READY_TIMEOUT_MS 3000

struct cpe_load_priv {
	void *cdc_handle;
	struct kobject *cpe_load_kobj;
	struct attribute_group *attr_group;
};

static int cpe_load;

static ssize_t cpe_load_store(struct kobject *kobj,
	struct kobj_attribute *attr,
	const char *buf,
	size_t count);

static struct kobj_attribute cpe_load_attr =
	__ATTR(cpe_load, 0600, NULL, cpe_load_store);

static struct attribute *attrs[] = {
	&cpe_load_attr.attr,
	NULL,
};

static struct attribute_group attr_grp = {
	.attrs = attrs,
};

static struct cpe_load_priv cpe_priv;

static inline int param_is_mask(int p)
{
	return ((p >= SNDRV_PCM_HW_PARAM_FIRST_MASK) &&
@@ -2111,44 +2084,6 @@ static int msm_snd_get_ext_clk_cnt(void)
	return clk_users;
}

static int apq8084_tomtom_cpe_enable(struct snd_soc_codec *codec)
{
	int ret = 0;

	ret = tomtom_enable_cpe(codec);
	if (IS_ERR_VALUE(ret))
		pr_err("%s: CPE enable failed, err (0x%x)\n",
			__func__, ret);
	return ret;
}

static ssize_t cpe_load_store(struct kobject *kobj,
	struct kobj_attribute *attr,
	const char *buf,
	size_t count)
{
	int ret = 0;

	if (cpe_load) {
		pr_err("%s: CPE already loaded\n",
			__func__);
		return count;
	}

	sscanf(buf, "%du", &cpe_load);

	if (cpe_load) {
		ret = apq8084_tomtom_cpe_enable(cpe_priv.cdc_handle);
		if (IS_ERR_VALUE(ret))
			cpe_load = 0;
		else
			pr_info("%s: CPE enabled for tomtom_codec\n",
				__func__);
	}

	return count;
}

static int msm_audrx_init(struct snd_soc_pcm_runtime *rtd)
{
	int err;
@@ -2326,18 +2261,6 @@ static int msm_audrx_init(struct snd_soc_pcm_runtime *rtd)
		tomtom_register_ext_clk_cb(msm_snd_enable_codec_ext_clk,
					   msm_snd_get_ext_clk_cnt,
					   rtd->codec);
		cpe_priv.cdc_handle = codec;
		cpe_priv.attr_group = &attr_grp;
		cpe_priv.cpe_load_kobj = kobject_create_and_add("snd_apq8084",
						       kernel_kobj);
		if (!cpe_priv.cpe_load_kobj) {
			pr_err("%s: cpe_load: sysfs create_add failed\n",
				__func__);
		} else if (sysfs_create_group(cpe_priv.cpe_load_kobj,
					      cpe_priv.attr_group)) {
			pr_err("%s: sysfs_create_group failed\n", __func__);
			kobject_del(cpe_priv.cpe_load_kobj);
		}

		err = msm_snd_enable_codec_ext_clk(rtd->codec, 1, false);
		if (IS_ERR_VALUE(err)) {