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

Commit b16674ba authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge "ASoC: audio-ext-clk: check AFE version before setting clocks"

parents 9ed71a99 957bcf41
Loading
Loading
Loading
Loading
+68 −0
Original line number Diff line number Diff line
@@ -8353,6 +8353,74 @@ struct asm_aptx_dec_fmt_blk_v2 {
 */
} __packed;

/* Q6Core Specific */
#define AVCS_CMD_GET_FWK_VERSION                (0x0001292C)
#define AVCS_CMDRSP_GET_FWK_VERSION             (0x0001292D)

#define AVCS_SERVICE_ID_ALL                     (0xFFFFFFFF)
#define AVCS_SERVICE_ID_AFE                     (0x4)

struct avcs_get_fwk_version {
	/*
	 * Indicates the major version of the AVS build.
	 * This value is incremented on chipset family boundaries.
	 */
	uint32_t build_major_version;

	/*
	 * Minor version of the AVS build.
	 * This value represents the mainline to which the AVS build belongs.
	 */
	uint32_t build_minor_version;

	/* Indicates the AVS branch version to which the image belongs. */
	uint32_t build_branch_version;

	/* Indicates the AVS sub-branch or customer product line information. */
	uint32_t build_subbranch_version;

	/* Number of supported AVS services in the current build. */
	uint32_t num_services;
};

struct avs_svc_api_info {
	/*
	 * APRV2 service IDs for the individual static services.
	 *
	 *	 @values
	 *	 - APRV2_IDS_SERVICE_ID_ADSP_CORE_V
	 *	 - APRV2_IDS_SERVICE_ID_ADSP_AFE_V
	 *	 - APRV2_IDS_SERVICE_ID_ADSP_ASM_V
	 *	 - APRV2_IDS_SERVICE_ID_ADSP_ADM_V
	 *	 - APRV2_IDS_SERVICE_ID_ADSP_MVM_V
	 *	 - APRV2_IDS_SERVICE_ID_ADSP_CVS_V
	 *	 - APRV2_IDS_SERVICE_ID_ADSP_CVP_V
	 *	 - APRV2_IDS_SERVICE_ID_ADSP_LSM_V
	 */
	uint32_t service_id;

	/*
	 * Indicates the API version of the service.
	 *
	 * Each new API update that warrants a change on the HLOS side triggers
	 * an increment in the version.
	 */
	uint32_t api_version;

	/*
	 * Indicates the API increments on a sub-branch (not on the mainline).
	 *
	 * API branch version numbers can increment independently on different
	 * sub-branches.
	 */
	uint32_t api_branch_version;
};

struct avcs_fwk_ver_info {
	struct avcs_get_fwk_version avcs_build;
	struct avs_svc_api_info services[0];
};

/* LSM Specific */
#define VW_FEAT_DIM					(39)

+6 −0
Original line number Diff line number Diff line
@@ -189,6 +189,11 @@ enum afe_cal_mode {
	AFE_CAL_MODE_NONE,
};

enum lpass_clk_ver {
	LPASS_CLK_VER_1,
	LPASS_CLK_VER_2,
};

struct afe_audio_buffer {
	dma_addr_t phys;
	void       *data;
@@ -234,6 +239,7 @@ struct aanc_data {

int afe_open(u16 port_id, union afe_port_config *afe_config, int rate);
int afe_close(int port_id);
enum lpass_clk_ver afe_get_lpass_clk_ver(void);
int afe_loopback(u16 enable, u16 rx_port, u16 tx_port);
int afe_sidetone(u16 tx_port_id, u16 rx_port_id, u16 enable, uint16_t gain);
int afe_loopback_gain(u16 port_id, u16 volume);
+5 −1
Original line number Diff line number Diff line
/* Copyright (c) 2012-2016, The Linux Foundation. All rights reserved.
/* Copyright (c) 2012-2017, The 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
@@ -13,6 +13,7 @@
#ifndef __Q6CORE_H__
#define __Q6CORE_H__
#include <linux/qdsp6v2/apr.h>
#include <sound/apr_audio-v2.h>



@@ -21,6 +22,9 @@

bool q6core_is_adsp_ready(void);

int q6core_get_avcs_fwk_ver_info(uint32_t service_id,
				 struct avcs_fwk_ver_info *ver_info);

#define ADSP_CMD_SET_DTS_EAGLE_DATA_ID 0x00012919
#define DTS_EAGLE_LICENSE_ID           0x00028346
struct adsp_dts_eagle {
+111 −67
Original line number Diff line number Diff line
@@ -31,6 +31,11 @@ enum clk_mux {
	LPASS_MCLK2,
};

enum clk_enablement {
	CLK_DISABLE = 0,
	CLK_ENABLE,
};

struct pinctrl_info {
	struct pinctrl *pinctrl;
	struct pinctrl_state *sleep;
@@ -169,44 +174,56 @@ static void audio_ext_clk2_unprepare(struct clk *clk)
		pr_err("%s: failed to reset clock, ret = %d\n", __func__, ret);
}

static int audio_ext_lpass_mclk_prepare(struct clk *clk)
static int audio_ext_set_lpass_mclk_v1(struct clk *clk,
				       enum clk_enablement enable)
{
	struct audio_ext_lpass_mclk *audio_lpass_mclk;
	struct pinctrl_info *pnctrl_info;
	struct afe_clk_cfg *lpass_clk = NULL;
	int ret, val = 0;
	struct pinctrl_state *pnctrl_state;
	struct afe_clk_cfg lpass_clks = lpass_default;
	int val = 0;
	int ret;

	audio_lpass_mclk = container_of(clk, struct audio_ext_lpass_mclk, c);
	pnctrl_info = &audio_lpass_mclk->pnctrl_info;
	pr_debug("%s: Setting clock using v1, enable(%d)\n", __func__, enable);

	lpass_clk = kzalloc(sizeof(struct afe_clk_cfg), GFP_KERNEL);
	if (!lpass_clk)
		return -ENOMEM;
	audio_lpass_mclk = container_of(clk, struct audio_ext_lpass_mclk, c);
	if (audio_lpass_mclk == NULL) {
		pr_err("%s: audio_lpass_mclk is NULL\n", __func__);
		ret = -EINVAL;
		goto done;
	}

	if (pnctrl_info->pinctrl) {
		ret = pinctrl_select_state(pnctrl_info->pinctrl,
				pnctrl_info->active);
	pnctrl_info = &audio_lpass_mclk->pnctrl_info;
	if (pnctrl_info && pnctrl_info->pinctrl) {
		pnctrl_state =
			enable ? pnctrl_info->active : pnctrl_info->sleep;
		ret = pinctrl_select_state(pnctrl_info->pinctrl, pnctrl_state);
		if (ret) {
			pr_err("%s: active state select failed with %d\n",
				__func__, ret);
			pr_err("%s: pinctrl state selection for %s failed with %d\n",
				__func__,
				(pnctrl_state == pnctrl_info->active) ?
					"active" : "sleep",
				ret);
			ret = -EIO;
			goto done;
		}
	}

	if (!audio_lpass_mclk->lpass_clock) {
		memcpy(lpass_clk, &lpass_default, sizeof(struct afe_clk_cfg));
		lpass_clk->clk_val2 = Q6AFE_LPASS_OSR_CLK_12_P288_MHZ;
		lpass_clk->clk_set_mode = Q6AFE_LPASS_MODE_CLK2_VALID;
		lpass_clks.clk_val2 =
			enable ? Q6AFE_LPASS_OSR_CLK_12_P288_MHZ : 0;
		lpass_clks.clk_set_mode = Q6AFE_LPASS_MODE_CLK2_VALID;
		ret = afe_set_lpass_clock(AFE_PORT_ID_SECONDARY_MI2S_RX,
				lpass_clk);
					  &lpass_clks);
		if (ret < 0) {
			pr_err("%s afe_set_lpass_clock failed, ret = %d\n",
			pr_err("%s: afe_set_lpass_clock failed with ret = %d\n",
			       __func__, ret);
			kfree(lpass_clk);
			return -EINVAL;
			ret = -EINVAL;
			goto done;
		}
	} else {
		if (audio_lpass_mclk->lpass_csr_gpio_mux_spkrctl_vaddr) {
		if (audio_lpass_mclk->lpass_csr_gpio_mux_spkrctl_vaddr &&
		    enable) {
			val = ioread32(audio_lpass_mclk->
					lpass_csr_gpio_mux_spkrctl_vaddr);
			val = val | 0x00000002;
@@ -214,65 +231,92 @@ static int audio_ext_lpass_mclk_prepare(struct clk *clk)
					lpass_csr_gpio_mux_spkrctl_vaddr);
		}

		digital_cdc_core_clk.enable = 1;
		digital_cdc_core_clk.enable = enable;
		ret = afe_set_lpass_clock_v2(AFE_PORT_ID_PRIMARY_MI2S_RX,
					     &digital_cdc_core_clk);
		if (ret < 0) {
			pr_err("%s afe_set_digital_codec_core_clock failed\n",
					__func__);
			kfree(lpass_clk);
			return ret;
			pr_err("%s: afe_set_digital_codec_core_clock failed with ret %d\n",
			       __func__, ret);
			goto done;
		}
	}

	ret = 0;

done:
	kfree(lpass_clk);
	return 0;
	return ret;
}

static void audio_ext_lpass_mclk_unprepare(struct clk *clk)
static int audio_ext_set_lpass_mclk_v2(enum clk_enablement enable)
{
	struct audio_ext_lpass_mclk *audio_lpass_mclk;
	struct pinctrl_info *pnctrl_info;
	struct afe_clk_cfg *lpass_clk = NULL;
	int ret;
	struct afe_clk_set m_clk = lpass_default2;
	struct afe_clk_set ibit_clk = lpass_default2;
	int ret = 0;

	audio_lpass_mclk = container_of(clk, struct audio_ext_lpass_mclk, c);
	pnctrl_info = &audio_lpass_mclk->pnctrl_info;
	pr_debug("%s: Setting clock using v2, enable(%d)\n", __func__, enable);

	lpass_clk = kzalloc(sizeof(struct afe_clk_cfg), GFP_KERNEL);
	if (!lpass_clk)
		return;
	/* Set both mclk and ibit clocks when using LPASS_CLK_VER_2 */
	m_clk.clk_id = Q6AFE_LPASS_CLK_ID_MCLK_3;
	m_clk.enable = enable;
	ret = afe_set_lpass_clock_v2(AFE_PORT_ID_PRIMARY_MI2S_RX, &m_clk);
	if (ret < 0) {
		pr_err("%s: afe_set_lpass_clock_v2 failed for mclk_3 with ret %d\n",
		       __func__, ret);
		goto done;
	}

	if (pnctrl_info->pinctrl) {
		ret = pinctrl_select_state(pnctrl_info->pinctrl,
					   pnctrl_info->sleep);
		if (ret) {
			pr_err("%s: active state select failed with %d\n",
	ibit_clk.clk_id = Q6AFE_LPASS_CLK_ID_PRI_MI2S_IBIT;
	ibit_clk.clk_freq_in_hz = Q6AFE_LPASS_IBIT_CLK_1_P536_MHZ;
	ibit_clk.enable = enable;
	ret = afe_set_lpass_clock_v2(AFE_PORT_ID_PRIMARY_MI2S_RX, &ibit_clk);
	if (ret < 0) {
		pr_err("%s: afe_set_lpass_clock_v2 failed for ibit with ret %d\n",
		       __func__, ret);
			ret = -EIO;
			goto err;
		goto err_ibit_clk_set;
	}

	ret = 0;

done:
	return ret;

err_ibit_clk_set:
	m_clk.enable = CLK_DISABLE;
	if (afe_set_lpass_clock_v2(AFE_PORT_ID_PRIMARY_MI2S_RX, &m_clk)) {
		pr_err("%s: afe_set_lpass_clock_v2 failed to disable mclk_3\n",
		       __func__);
	}
	return ret;
}
	if (!audio_lpass_mclk->lpass_clock) {
		memcpy(lpass_clk, &lpass_default, sizeof(struct afe_clk_cfg));
		lpass_clk->clk_val2 = 0;
		lpass_clk->clk_set_mode = Q6AFE_LPASS_MODE_CLK2_VALID;
		ret = afe_set_lpass_clock(AFE_PORT_ID_SECONDARY_MI2S_RX,
				lpass_clk);
		if (ret < 0)
			pr_err("%s: afe_set_lpass_clock failed, ret = %d\n",
				__func__, ret);

	} else {
		digital_cdc_core_clk.enable = 0;
		ret = afe_set_lpass_clock_v2(AFE_PORT_ID_PRIMARY_MI2S_RX,
				&digital_cdc_core_clk);
		if (ret < 0)
			pr_err("%s: afe_set_digital_codec_core_clock failed, ret = %d\n",
					__func__, ret);
static int audio_ext_lpass_mclk_prepare(struct clk *clk)
{
	enum lpass_clk_ver lpass_clk_ver;
	int ret;

	lpass_clk_ver = afe_get_lpass_clk_ver();

	if (lpass_clk_ver >= LPASS_CLK_VER_2)
		ret = audio_ext_set_lpass_mclk_v2(CLK_ENABLE);
	else
		ret = audio_ext_set_lpass_mclk_v1(clk, CLK_ENABLE);

	return ret;
}
err:
	kfree(lpass_clk);

static void audio_ext_lpass_mclk_unprepare(struct clk *clk)
{
	enum lpass_clk_ver lpass_clk_ver;
	int ret;

	lpass_clk_ver = afe_get_lpass_clk_ver();

	if (lpass_clk_ver >= LPASS_CLK_VER_2)
		ret = audio_ext_set_lpass_mclk_v2(CLK_DISABLE);
	else
		ret = audio_ext_set_lpass_mclk_v1(clk, CLK_DISABLE);

	pr_debug("%s: Unprepare of mclk returned %d\n", __func__, ret);
}

static int audio_ext_lpass_mclk2_prepare(struct clk *clk)
+34 −0
Original line number Diff line number Diff line
@@ -23,6 +23,7 @@
#include <sound/apr_audio-v2.h>
#include <sound/q6afe-v2.h>
#include <sound/q6audio-v2.h>
#include <sound/q6core.h>
#include "msm-pcm-routing-v2.h"
#include <sound/audio_cal_utils.h>
#include <sound/adsp_err.h>
@@ -5130,6 +5131,39 @@ int afe_set_lpass_clock_v2(u16 port_id, struct afe_clk_set *cfg)
	return ret;
}

static int afe_get_service_ver(void)
{
	int ret;

	ret = q6core_get_avcs_fwk_ver_info(AVCS_SERVICE_ID_AFE, NULL);
	if (ret)
		pr_err("%s: failed to get version info for AFE service %d\n",
		       __func__, AVCS_SERVICE_ID_AFE);

	return ret;
}

enum lpass_clk_ver afe_get_lpass_clk_ver(void)
{
	enum lpass_clk_ver lpass_clk_ver;

	/*
	 * Use different APIs to set the LPASS clock depending on the AFE
	 * version. On success afe_get_service_ver returns 0 signyfing the
	 * latest AFE version is supported. Use LPASS clock version 2 if the
	 * latest AFE version is supported, otherwise use LPASS clock version 1.
	 */
	lpass_clk_ver = (afe_get_service_ver() == 0) ?
		LPASS_CLK_VER_2 : LPASS_CLK_VER_1;

	pr_debug("%s: returning %s\n", __func__,
		 (lpass_clk_ver == LPASS_CLK_VER_2) ?
			"LPASS_CLK_VER_2" : "LPASS_CLK_VER_1");

	return lpass_clk_ver;
}
EXPORT_SYMBOL(afe_get_lpass_clk_ver);

int afe_set_lpass_internal_digital_codec_clock(u16 port_id,
			struct afe_digital_clk_cfg *cfg)
{
Loading