Unverified Commit 2f206404 authored by Srinivas Kandagatla's avatar Srinivas Kandagatla Committed by Mark Brown
Browse files

ASoC: qdsp6: qdsp6: q6prm: handle clk disable correctly



Q6PRM clks need to be disabled using PRM_CMD_RELEASE_HW_RSC dsp command
rather then using PRM_CMD_RSP_REQUEST_HW_RSC cmd with rate set to zero.

DSP will throw errors if we try to disable the clock using existing code.

Fix this by properly handling the clk release.

Fixes: 9a0e5d6f ("ASoC: qdsp6: audioreach: add q6prm support")
Signed-off-by: default avatarSrinivas Kandagatla <srinivas.kandagatla@linaro.org>
Link: https://lore.kernel.org/r/20211116114721.12517-2-srinivas.kandagatla@linaro.org


Signed-off-by: default avatarMark Brown <broonie@kernel.org>
parent a6e849d0
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -550,6 +550,10 @@ struct audio_hw_clk_cfg {
	uint32_t clock_root;
} __packed;

struct audio_hw_clk_rel_cfg {
	uint32_t clock_id;
} __packed;

#define PARAM_ID_HW_EP_POWER_MODE_CFG	0x8001176
#define AR_HW_EP_POWER_MODE_0	0 /* default */
#define AR_HW_EP_POWER_MODE_1	1 /* XO Shutdown allowed */
+51 −2
Original line number Diff line number Diff line
@@ -42,6 +42,12 @@ struct prm_cmd_request_rsc {
	struct audio_hw_clk_cfg clock_id;
} __packed;

struct prm_cmd_release_rsc {
	struct apm_module_param_data param_data;
	uint32_t num_clk_id;
	struct audio_hw_clk_rel_cfg clock_id;
} __packed;

static int q6prm_send_cmd_sync(struct q6prm *prm, struct gpr_pkt *pkt, uint32_t rsp_opcode)
{
	return audioreach_send_cmd_sync(prm->dev, prm->gdev, &prm->result, &prm->lock,
@@ -102,7 +108,7 @@ int q6prm_unvote_lpass_core_hw(struct device *dev, uint32_t hw_block_id, uint32_
}
EXPORT_SYMBOL_GPL(q6prm_unvote_lpass_core_hw);

int q6prm_set_lpass_clock(struct device *dev, int clk_id, int clk_attr, int clk_root,
static int q6prm_request_lpass_clock(struct device *dev, int clk_id, int clk_attr, int clk_root,
				     unsigned int freq)
{
	struct q6prm *prm = dev_get_drvdata(dev->parent);
@@ -138,6 +144,49 @@ int q6prm_set_lpass_clock(struct device *dev, int clk_id, int clk_attr, int clk_

	return rc;
}

static int q6prm_release_lpass_clock(struct device *dev, int clk_id, int clk_attr, int clk_root,
			  unsigned int freq)
{
	struct q6prm *prm = dev_get_drvdata(dev->parent);
	struct apm_module_param_data *param_data;
	struct prm_cmd_release_rsc *rel;
	gpr_device_t *gdev = prm->gdev;
	struct gpr_pkt *pkt;
	int rc;

	pkt = audioreach_alloc_cmd_pkt(sizeof(*rel), PRM_CMD_RELEASE_HW_RSC, 0, gdev->svc.id,
				       GPR_PRM_MODULE_IID);
	if (IS_ERR(pkt))
		return PTR_ERR(pkt);

	rel = (void *)pkt + GPR_HDR_SIZE + APM_CMD_HDR_SIZE;

	param_data = &rel->param_data;

	param_data->module_instance_id = GPR_PRM_MODULE_IID;
	param_data->error_code = 0;
	param_data->param_id = PARAM_ID_RSC_AUDIO_HW_CLK;
	param_data->param_size = sizeof(*rel) - APM_MODULE_PARAM_DATA_SIZE;

	rel->num_clk_id = 1;
	rel->clock_id.clock_id = clk_id;

	rc = q6prm_send_cmd_sync(prm, pkt, PRM_CMD_RSP_RELEASE_HW_RSC);

	kfree(pkt);

	return rc;
}

int q6prm_set_lpass_clock(struct device *dev, int clk_id, int clk_attr, int clk_root,
			  unsigned int freq)
{
	if (freq)
		return q6prm_request_lpass_clock(dev, clk_id, clk_attr, clk_attr, freq);

	return q6prm_release_lpass_clock(dev, clk_id, clk_attr, clk_attr, freq);
}
EXPORT_SYMBOL_GPL(q6prm_set_lpass_clock);

static int prm_callback(struct gpr_resp_pkt *data, void *priv, int op)