diff --git a/dsp/q6afe.c b/dsp/q6afe.c index 3ab1499c8e32..898ca06b0821 100644 --- a/dsp/q6afe.c +++ b/dsp/q6afe.c @@ -9858,8 +9858,8 @@ int afe_set_pll_clk_drift(u16 port_id, int32_t set_clk_drift, } EXPORT_SYMBOL(afe_set_pll_clk_drift); -static int afe_set_lpass_clk_cfg_ext_mclk(int index, struct afe_clk_set *cfg, - uint32_t mclk_freq) +int afe_set_lpass_clk_cfg_ext_mclk(int index, struct afe_clk_set *cfg, + uint32_t mclk_freq) { struct param_hdr_v3 param_hdr; struct afe_param_id_clock_set_v2_t dyn_mclk_cfg; @@ -9871,6 +9871,12 @@ static int afe_set_lpass_clk_cfg_ext_mclk(int index, struct afe_clk_set *cfg, return ret; } + if (!afe_ext_mclk.ext_mclk_cb) { + pr_debug("%s: ext_mclk_cb not registered; platform doesn't support ext clk\n", + __func__); + return -EOPNOTSUPP; + } + if (index < 0 || index >= AFE_MAX_PORTS) { pr_err("%s: index[%d] invalid!\n", __func__, index); return -EINVAL; @@ -9883,34 +9889,33 @@ static int afe_set_lpass_clk_cfg_ext_mclk(int index, struct afe_clk_set *cfg, param_hdr.param_size = sizeof(struct afe_param_id_clock_set_v2_t); memset(&dyn_mclk_cfg, 0, sizeof(dyn_mclk_cfg)); - dyn_mclk_cfg.clk_freq_in_hz = cfg->clk_freq_in_hz; - if (afe_ext_mclk.ext_mclk_cb) { - ret = afe_ext_mclk.ext_mclk_cb(afe_ext_mclk.private_data, - cfg->enable, mclk_freq, &dyn_mclk_cfg); - if (ret) { - pr_err_ratelimited("%s: get mclk cfg failed %d\n", - __func__, ret); - return ret; - } - } else { - pr_err_ratelimited("%s: mclk callback not registered\n", - __func__); - return -EINVAL; - } + dyn_mclk_cfg.clk_freq_in_hz = cfg->clk_freq_in_hz; dyn_mclk_cfg.clk_set_minor_version = 1; dyn_mclk_cfg.clk_id = cfg->clk_id; dyn_mclk_cfg.clk_attri = cfg->clk_attri; dyn_mclk_cfg.enable = cfg->enable; pr_debug("%s: Minor version =0x%x clk id = %d\n", __func__, - dyn_mclk_cfg.clk_set_minor_version, dyn_mclk_cfg.clk_id); + dyn_mclk_cfg.clk_set_minor_version, dyn_mclk_cfg.clk_id); pr_debug("%s: clk freq (Hz) = %d, clk attri = 0x%x\n", __func__, - dyn_mclk_cfg.clk_freq_in_hz, dyn_mclk_cfg.clk_attri); - pr_debug("%s: clk root = 0x%x clk enable = 0x%x\n", __func__, - dyn_mclk_cfg.clk_root, dyn_mclk_cfg.enable); - pr_debug("%s: divider_2x =%d m = %d n = %d, d =%d\n", __func__, - dyn_mclk_cfg.divider_2x, dyn_mclk_cfg.m, dyn_mclk_cfg.n, - dyn_mclk_cfg.d); + dyn_mclk_cfg.clk_freq_in_hz, dyn_mclk_cfg.clk_attri); + pr_debug("%s: clk input freq (Hz) = %d clk enable = 0x%x\n", __func__, + mclk_freq, dyn_mclk_cfg.enable); + + if (dyn_mclk_cfg.enable) { + /* callback to populate Div2x, M, N, D, clock root and enable GPIOs */ + ret = afe_ext_mclk.ext_mclk_cb(afe_ext_mclk.private_data, + dyn_mclk_cfg.enable, mclk_freq, &dyn_mclk_cfg); + if (ret) { + pr_err_ratelimited("%s: mclk cb during enable failed %d\n", + __func__, ret); + return ret; + } + + pr_debug("%s: clk root = 0x%x divider_2x = %d m = %d n = %d d = %d\n", + __func__, dyn_mclk_cfg.clk_root, dyn_mclk_cfg.divider_2x, + dyn_mclk_cfg.m, dyn_mclk_cfg.n, dyn_mclk_cfg.d); + } ret = afe_q6_interface_prepare(); if (ret != 0) { @@ -9922,23 +9927,37 @@ static int afe_set_lpass_clk_cfg_ext_mclk(int index, struct afe_clk_set *cfg, mutex_lock(&this_afe.afe_cmd_lock); ret = q6afe_svc_pack_and_set_param_in_band(index, param_hdr, (u8 *) &dyn_mclk_cfg); - if (ret < 0) + if (ret < 0) { pr_err_ratelimited("%s: ext MCLK clk cfg failed with ret %d\n", - __func__, ret); + __func__, ret); + mutex_unlock(&this_afe.afe_cmd_lock); + goto stop_mclk; + } mutex_unlock(&this_afe.afe_cmd_lock); + if (!dyn_mclk_cfg.enable) { + /* callback to disable GPIOs */ + ret = afe_ext_mclk.ext_mclk_cb(afe_ext_mclk.private_data, + dyn_mclk_cfg.enable, mclk_freq, &dyn_mclk_cfg); + if (ret) { + pr_err_ratelimited("%s: mclk cb during disable failed %d\n", + __func__, ret); + return ret; + } + } + if (ret >= 0) return ret; stop_mclk: - if (afe_ext_mclk.ext_mclk_cb && cfg->enable) { - afe_ext_mclk.ext_mclk_cb(afe_ext_mclk.private_data, - cfg->enable, mclk_freq, &dyn_mclk_cfg); - } + dyn_mclk_cfg.enable = 0; + afe_ext_mclk.ext_mclk_cb(afe_ext_mclk.private_data, + dyn_mclk_cfg.enable, mclk_freq, &dyn_mclk_cfg); return ret; } +EXPORT_SYMBOL(afe_set_lpass_clk_cfg_ext_mclk); static int ext_dyn_mclk_port_id; static int ext_dyn_clk_root = Q6AFE_LPASS_CLK_ROOT_DEFAULT; @@ -10162,7 +10181,8 @@ int afe_set_lpass_clock_v2(u16 port_id, struct afe_clk_set *cfg) build_branch_version, afe_api_version); if ((build_major_version != AVS_BUILD_MAJOR_VERSION_V2) || (build_minor_version != AVS_BUILD_MINOR_VERSION_V9) || - (build_branch_version != AVS_BUILD_BRANCH_VERSION_V3) || + ((build_branch_version != AVS_BUILD_BRANCH_VERSION_V0) && + (build_branch_version != AVS_BUILD_BRANCH_VERSION_V3)) || (afe_api_version < AFE_API_VERSION_V8)) { pr_err("%s: ext mclk not supported by AVS\n", __func__); return -EINVAL; diff --git a/include/dsp/q6afe-v2.h b/include/dsp/q6afe-v2.h index 900fe1699528..3056afc991fb 100644 --- a/include/dsp/q6afe-v2.h +++ b/include/dsp/q6afe-v2.h @@ -603,6 +603,8 @@ int afe_port_send_afe_limiter_param(u16 port_id, struct afe_param_id_port_afe_limiter_disable_t *disable_limiter); int afe_get_av_dev_drift(struct afe_param_id_dev_timing_stats *timing_stats, u16 port); +int afe_set_lpass_clk_cfg_ext_mclk(int index, struct afe_clk_set *cfg, + uint32_t mclk_freq); int afe_set_lpass_clk_cfg_ext_mclk_v2(int index, struct afe_param_id_clock_set_v2_t *dyn_mclk_cfg, uint32_t mclk_freq); int afe_get_sp_rx_tmax_xmax_logging_data( @@ -634,6 +636,14 @@ int afe_set_source_clk(u16 port_id, const char *clk_src); void afe_set_clk_src_array(const char *clk_src[CLK_SRC_MAX]); int afe_set_mclk_src_cfg(u16 port_id, uint32_t mclk_src_id, uint32_t mclk_freq); +/* Client of AFE registers afe_enable_mclk_and_get_info_cb_func callback function via + * afe_register_ext_mclk_cb() when external clock is supported by the platform. During + * clock enable sequence, AFE triggers this callback before requesting DSP for clock + * enable. Client can provide Div2X, M, N, D and clock root as part of this callback. + * Client can also enable required GPIO that are essential to route external clock in + * this callback. During clock disable sequence, AFE triggers this callback after + * requesting DSP for clock disable. Client can disable required GPIOs in this callback. + */ typedef int (*afe_enable_mclk_and_get_info_cb_func) (void *private_data, uint32_t enable, uint32_t mclk_freq, struct afe_param_id_clock_set_v2_t *dyn_mclk_cfg);