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

Commit cf3f8e68 authored by Surendar Karka's avatar Surendar Karka Committed by Gerrit - the friendly Code Review server
Browse files

dsp: Add support to set clock drift



- Add support to adjust drift in audio interface
  clock source PLL.
- ADSP adjusts the source clock based on clk id. Add support
  in AFE driver to get clk id based on the AFE port.

Change-Id: I45ceb6579bb15e32541051e0ba936a2d903e4923
Signed-off-by: default avatarSurendar Karka <skarka@codeaurora.org>
parent 15816c54
Loading
Loading
Loading
Loading
+191 −0
Original line number Diff line number Diff line
@@ -174,6 +174,43 @@ struct afe_ctl {
	uint32_t v_vali_flag;
};

struct afe_clkinfo_per_port {
	u16 port_id; /* AFE port ID */
	uint32_t clk_id; /* Clock ID */
};

struct afe_clkinfo_per_port clkinfo_per_port[] = {
	{ AFE_PORT_ID_PRIMARY_MI2S_RX, Q6AFE_LPASS_CLK_ID_PRI_MI2S_IBIT},
	{ AFE_PORT_ID_SECONDARY_MI2S_RX, Q6AFE_LPASS_CLK_ID_SEC_MI2S_IBIT},
	{ AFE_PORT_ID_TERTIARY_MI2S_RX, Q6AFE_LPASS_CLK_ID_TER_MI2S_IBIT},
	{ AFE_PORT_ID_QUATERNARY_MI2S_RX, Q6AFE_LPASS_CLK_ID_QUAD_MI2S_IBIT},
	{ AFE_PORT_ID_QUINARY_MI2S_RX, Q6AFE_LPASS_CLK_ID_QUI_MI2S_IBIT},
	{ AFE_PORT_ID_SENARY_MI2S_RX, Q6AFE_LPASS_CLK_ID_SEN_MI2S_IBIT},
	{ AFE_PORT_ID_PRIMARY_PCM_RX, Q6AFE_LPASS_CLK_ID_PRI_PCM_IBIT},
	{ AFE_PORT_ID_SECONDARY_PCM_RX, Q6AFE_LPASS_CLK_ID_SEC_PCM_IBIT},
	{ AFE_PORT_ID_TERTIARY_PCM_RX, Q6AFE_LPASS_CLK_ID_TER_PCM_IBIT},
	{ AFE_PORT_ID_QUATERNARY_PCM_RX, Q6AFE_LPASS_CLK_ID_QUAD_PCM_IBIT},
	{ AFE_PORT_ID_QUINARY_PCM_RX, Q6AFE_LPASS_CLK_ID_QUIN_PCM_IBIT},
	{ AFE_PORT_ID_SENARY_PCM_RX, Q6AFE_LPASS_CLK_ID_SEN_PCM_IBIT},
	{ AFE_PORT_ID_PRIMARY_TDM_RX, Q6AFE_LPASS_CLK_ID_PRI_TDM_IBIT},
	{ AFE_PORT_ID_SECONDARY_TDM_RX, Q6AFE_LPASS_CLK_ID_SEC_TDM_IBIT},
	{ AFE_PORT_ID_TERTIARY_TDM_RX, Q6AFE_LPASS_CLK_ID_TER_TDM_IBIT},
	{ AFE_PORT_ID_QUATERNARY_TDM_RX, Q6AFE_LPASS_CLK_ID_QUAD_TDM_IBIT},
	{ AFE_PORT_ID_QUINARY_TDM_RX, Q6AFE_LPASS_CLK_ID_QUIN_TDM_IBIT},
	{ AFE_PORT_ID_PRIMARY_SPDIF_RX,
		AFE_CLOCK_SET_CLOCK_ID_PRI_SPDIF_OUTPUT_CORE},
	{ AFE_PORT_ID_PRIMARY_SPDIF_TX,
		AFE_CLOCK_SET_CLOCK_ID_PRI_SPDIF_INPUT_CORE},
	{ AFE_PORT_ID_SECONDARY_SPDIF_RX,
		AFE_CLOCK_SET_CLOCK_ID_SEC_SPDIF_OUTPUT_CORE},
	{ AFE_PORT_ID_SECONDARY_SPDIF_TX,
		AFE_CLOCK_SET_CLOCK_ID_SEC_SPDIF_INPUT_CORE},
	{ AFE_PORT_ID_PRIMARY_META_MI2S_RX,
		Q6AFE_LPASS_CLK_ID_PRI_MI2S_IBIT},
	{ AFE_PORT_ID_SECONDARY_META_MI2S_RX,
		Q6AFE_LPASS_CLK_ID_PRI_MI2S_IBIT},
};

static atomic_t afe_ports_mad_type[SLIMBUS_PORT_LAST - SLIMBUS_0_RX];
static unsigned long afe_configured_cmd;

@@ -7843,6 +7880,156 @@ int afe_set_lpass_clock(u16 port_id, struct afe_clk_cfg *cfg)
}
EXPORT_SYMBOL(afe_set_lpass_clock);

static int afe_get_port_idx(u16 port_id)
{
	u16 afe_port = 0;
	int i = -EINVAL;

	pr_debug("%s: port id 0x%x\n", __func__, port_id);

	if ((port_id >= AFE_PORT_ID_TDM_PORT_RANGE_START) &&
		(port_id <= AFE_PORT_ID_TDM_PORT_RANGE_END))
		afe_port = port_id & 0xFFF0;
	else if ((port_id == AFE_PORT_ID_PRIMARY_SPDIF_RX) ||
		 (port_id == AFE_PORT_ID_PRIMARY_SPDIF_TX) ||
		 (port_id == AFE_PORT_ID_SECONDARY_SPDIF_RX) ||
		 (port_id == AFE_PORT_ID_SECONDARY_SPDIF_TX))
		afe_port = port_id;
	else
		afe_port = port_id & 0xFFFE;

	for (i = 0; i < ARRAY_SIZE(clkinfo_per_port); i++) {
		if (afe_port == clkinfo_per_port[i].port_id) {
			pr_debug("%s: idx 0x%x port id 0x%x\n", __func__,
				  i, afe_port);
			return i;
		}
	}

	pr_debug("%s: cannot get idx for port id 0x%x\n", __func__,
		afe_port);

	return -EINVAL;
}

static int afe_get_clk_id(u16 port_id)
{
	u16 afe_port = 0;
	uint32_t clk_id = -EINVAL;
	int idx = 0;

	idx = afe_get_port_idx(port_id);
	if (idx < 0) {
		pr_err("%s: cannot get clock id for port id 0x%x\n", __func__,
			afe_port);
		return -EINVAL;
	}

	clk_id = clkinfo_per_port[idx].clk_id;
	pr_debug("%s: clk id 0x%x port id 0x%x\n", __func__, clk_id,
		  afe_port);

	return clk_id;
}

/**
 * afe_set_clk_id - Update clock id for AFE port
 *
 * @port_id: AFE port id
 * @clk_id: CLock ID
 *
 * Returns 0 on success, appropriate error code otherwise
 */
int afe_set_clk_id(u16 port_id, uint32_t clk_id)
{
	u16 afe_port = 0;
	int idx = 0;

	idx = afe_get_port_idx(port_id);
	if (idx < 0) {
		pr_debug("%s: cannot set clock id for port id 0x%x\n", __func__,
			afe_port);
		return -EINVAL;
	}

	clkinfo_per_port[idx].clk_id = clk_id;
	pr_debug("%s: updated clk id 0x%x port id 0x%x\n", __func__,
		  clkinfo_per_port[idx].clk_id, afe_port);

	return 0;
}
EXPORT_SYMBOL(afe_set_clk_id);

/**
 * afe_set_pll_clk_drift - Set audio interface PLL clock drift
 *
 * @port_id: AFE port id
 * @set_clk_drift: clk drift to adjust PLL
 * @clk_reset: reset Interface clock to original value
 *
 * Returns 0 on success, appropriate error code otherwise
 */
int afe_set_pll_clk_drift(u16 port_id, int32_t set_clk_drift,
			  uint32_t clk_reset)
{
	struct afe_set_clk_drift clk_drift;
	struct param_hdr_v3 param_hdr;
	uint32_t clk_id;
	int index = 0, ret = 0;

	memset(&param_hdr, 0, sizeof(param_hdr));
	memset(&clk_drift, 0, sizeof(clk_drift));

	index = q6audio_get_port_index(port_id);
	if (index < 0 || index >= AFE_MAX_PORTS) {
		pr_err("%s: index[%d] invalid!\n", __func__, index);
		return -EINVAL;
	}

	ret = afe_q6_interface_prepare();
	if (ret != 0) {
		pr_err_ratelimited("%s: Q6 interface prepare failed %d\n",
				    __func__, ret);
		return ret;
	}

	clk_id = afe_get_clk_id(port_id);
	if (clk_id < 0) {
		pr_err("%s: cannot get clk id for port id 0x%x\n",
			__func__, port_id);
		return -EINVAL;
	}

	if (clk_id & 0x01) {
		pr_err("%s: cannot adjust clock drift for external clock id 0x%x\n",
			__func__, clk_id);
		return -EINVAL;
	}

	clk_drift.clk_drift = set_clk_drift;
	clk_drift.clk_reset = clk_reset;
	clk_drift.clk_id = clk_id;
	pr_debug("%s: clk id = 0x%x clk drift  = %d clk reset = %d port id 0x%x\n",
		  __func__, clk_drift.clk_id, clk_drift.clk_drift,
		 clk_drift.clk_reset, port_id);

	mutex_lock(&this_afe.afe_clk_lock);
	param_hdr.module_id = AFE_MODULE_CLOCK_SET;
	param_hdr.instance_id = INSTANCE_ID_0;
	param_hdr.param_id = AFE_PARAM_ID_CLOCK_ADJUST;
	param_hdr.param_size = sizeof(struct afe_set_clk_drift);

	ret = q6afe_svc_pack_and_set_param_in_band(index, param_hdr,
						   (u8 *) &clk_drift);
	if (ret < 0)
		pr_err_ratelimited("%s: AFE PLL clk drift failed with ret %d\n",
				    __func__, ret);

	mutex_unlock(&this_afe.afe_clk_lock);
	return ret;
}
EXPORT_SYMBOL(afe_set_pll_clk_drift);

/**
 * afe_set_lpass_clk_cfg - Set AFE clk config
 *
@@ -7929,6 +8116,10 @@ int afe_set_lpass_clock_v2(u16 port_id, struct afe_clk_set *cfg)
		return -EINVAL;
	}

	ret = afe_set_clk_id(port_id, cfg->clk_id);
	if (ret < 0)
		pr_debug("%s: afe_set_clk_id fail %d\n", __func__, ret);

	ret = afe_set_lpass_clk_cfg(index, cfg);
	if (ret)
		pr_err("%s: afe_set_lpass_clk_cfg_v2 failed %d\n",
+29 −0
Original line number Diff line number Diff line
@@ -11766,6 +11766,35 @@ struct afe_clk_cfg {
#define AFE_MODULE_CLOCK_SET		0x0001028F
#define AFE_PARAM_ID_CLOCK_SET		0x00010290

struct afe_set_clk_drift {
	/*
	 * Clock ID
	 *	@values
	 *	- 0x100 to 0x10E
	 *	- 0x200 to 0x20C
	 *	- 0x500 to 0x505
	 */
	uint32_t clk_id;

	/*
	 * Clock drift  (in PPB) to be set.
	 *	@values
	 *	- need to get values from DSP team
	 */
	int32_t clk_drift;

	/*
	 * Clock rest.
	 *	@values
	 *	- 1 -- Reset PLL with the original frequency
	 *	- 0 -- Adjust the clock with the clk drift value
	 */
	uint32_t clk_reset;
} __packed;

/* This param id is used to adjust audio interface PLL*/
#define AFE_PARAM_ID_CLOCK_ADJUST       0x000102C6

enum afe_lpass_digital_clk_src {
	Q6AFE_LPASS_DIGITAL_ROOT_INVALID,
	Q6AFE_LPASS_DIGITAL_ROOT_PRI_MI2S_OSR,
+3 −0
Original line number Diff line number Diff line
@@ -487,6 +487,9 @@ void afe_register_wakeup_irq_callback(
	void (*afe_cb_wakeup_irq)(void *handle));
int afe_get_doa_tracking_mon(u16 port_id,
	struct doa_tracking_mon_param *doa_tracking_data);
int afe_set_pll_clk_drift(u16 port_id, int32_t set_clk_drift,
			  uint32_t clk_reset);
int afe_set_clk_id(u16 port_id, uint32_t clk_id);

enum {
	AFE_LPASS_CORE_HW_BLOCK_ID_NONE,