ASoC: msm: add kcontrol to support ASRC config
Added kcontrol to write clock drift to ASRC module in ADSP. There are two options: 1. read drift from an active AFE port, and write to target ASRC module. The read-and-write process will loop automatically with configurable delay. (50 ms by default) 2. write drift value to target ASRC module for one time operation. Change-Id: I2df7ed646d53612aca96074c0ca3d44a404cebf4 Signed-off-by: Han Lu <hanlu@codeaurora.org>
This commit is contained in:
parent
c285d08046
commit
4eb1a6ea14
@ -31513,6 +31513,637 @@ static const struct snd_kcontrol_new
|
||||
},
|
||||
};
|
||||
|
||||
#define ASRC_PARAM_MAX 10
|
||||
#define ASRC_SCHED_DELAY_MS 50
|
||||
|
||||
#define MODULE_ID_AUTO_ASRC 0x123A7000
|
||||
#define PARAM_ID_AUTO_ASRC_ENABLE 0x123A7001
|
||||
#define PARAM_ID_AUTO_ASRC_BASE_CONFIG 0x123A7002
|
||||
#define PARAM_ID_AUTO_ASRC_RATIO 0x123A7004
|
||||
#define PARAM_ID_AUTO_ASRC_STATE 0x123A7005
|
||||
#define PARAM_ID_AUTO_ASRC_INPUT_TIMING_STATS 0x123A7006
|
||||
#define PARAM_ID_AUTO_ASRC_OUTPUT_TIMING_STATS 0x123A7007
|
||||
|
||||
enum {
|
||||
DISABLE_ASRC = 0,
|
||||
ENABLE_ASRC_DRIFT_HW,
|
||||
ENABLE_ASRC_DRIFT_SW,
|
||||
ENABLE_ASRC_MAX,
|
||||
};
|
||||
|
||||
enum {
|
||||
MODULE_PORT_OUT = 0,
|
||||
MODULE_PORT_IN,
|
||||
MODULE_PORT_MAX,
|
||||
};
|
||||
|
||||
enum {
|
||||
DRIFT_SRC_SW = 0,
|
||||
DRIFT_SRC_AFE_PRI,
|
||||
DRIFT_SRC_AFE_SEC,
|
||||
DRIFT_SRC_AFE_TERT,
|
||||
DRIFT_SRC_AFE_QUAT,
|
||||
DRIFT_SRC_AFE_QUIN,
|
||||
DRIFT_SRC_MAX,
|
||||
};
|
||||
|
||||
struct asrc_module_config_params {
|
||||
int enable;
|
||||
int fe_id;
|
||||
int dir;
|
||||
int be_id;
|
||||
int m_io;
|
||||
int param;
|
||||
};
|
||||
|
||||
struct asrc_module_config_node {
|
||||
struct list_head list;
|
||||
struct asrc_module_config_params params;
|
||||
};
|
||||
|
||||
struct asrc_config {
|
||||
struct mutex lock;
|
||||
int drift_src;
|
||||
int idx;
|
||||
struct afe_param_id_dev_timing_stats timing_stats;
|
||||
struct list_head modules;
|
||||
struct delayed_work drift_work;
|
||||
};
|
||||
|
||||
static struct asrc_config asrc_cfg[ASRC_PARAM_MAX];
|
||||
|
||||
static int sched_delay_ms = ASRC_SCHED_DELAY_MS;
|
||||
|
||||
static int get_drift_src_idx(int drift_src)
|
||||
{
|
||||
if (drift_src == DRIFT_SRC_SW)
|
||||
return DRIFT_SRC_SW;
|
||||
else if ((drift_src >= AFE_PORT_ID_PRIMARY_TDM_RX)
|
||||
&& (drift_src <= AFE_PORT_ID_PRIMARY_TDM_TX_7))
|
||||
return DRIFT_SRC_AFE_PRI;
|
||||
else if ((drift_src >= AFE_PORT_ID_SECONDARY_TDM_RX)
|
||||
&& (drift_src <= AFE_PORT_ID_SECONDARY_TDM_TX_7))
|
||||
return DRIFT_SRC_AFE_SEC;
|
||||
else if ((drift_src >= AFE_PORT_ID_TERTIARY_TDM_RX)
|
||||
&& (drift_src <= AFE_PORT_ID_TERTIARY_TDM_TX_7))
|
||||
return DRIFT_SRC_AFE_TERT;
|
||||
else if ((drift_src >= AFE_PORT_ID_QUATERNARY_TDM_RX)
|
||||
&& (drift_src <= AFE_PORT_ID_QUATERNARY_TDM_TX_7))
|
||||
return DRIFT_SRC_AFE_QUAT;
|
||||
else if ((drift_src >= AFE_PORT_ID_QUINARY_TDM_RX)
|
||||
&& (drift_src <= AFE_PORT_ID_QUINARY_TDM_TX_7))
|
||||
return DRIFT_SRC_AFE_QUIN;
|
||||
else
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static bool asrc_modules_identical(struct asrc_module_config_params *p1,
|
||||
struct asrc_module_config_params *p2)
|
||||
{
|
||||
if (!p1 || !p2
|
||||
|| (p1->fe_id != p2->fe_id)
|
||||
|| (p1->dir != p2->dir)
|
||||
|| (p1->be_id != p2->be_id))
|
||||
return false;
|
||||
else
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool asrc_module_exists_in_config(int idx, struct asrc_module_config_params *params)
|
||||
{
|
||||
struct asrc_module_config_node *config_node = NULL;
|
||||
struct list_head *ptr, *next;
|
||||
|
||||
if (!params)
|
||||
return false;
|
||||
|
||||
mutex_lock(&asrc_cfg[idx].lock);
|
||||
list_for_each_safe(ptr, next, &asrc_cfg[idx].modules) {
|
||||
config_node = list_entry(ptr, struct asrc_module_config_node, list);
|
||||
if (asrc_modules_identical(&config_node->params, params)) {
|
||||
mutex_unlock(&asrc_cfg[idx].lock);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
mutex_unlock(&asrc_cfg[idx].lock);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static int asrc_del_modules_from_config(int idx, struct asrc_module_config_params *params)
|
||||
{
|
||||
struct asrc_module_config_node *config_node = NULL;
|
||||
struct list_head *ptr, *next;
|
||||
|
||||
if (!params)
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&asrc_cfg[idx].lock);
|
||||
list_for_each_safe(ptr, next, &asrc_cfg[idx].modules) {
|
||||
config_node = list_entry(ptr, struct asrc_module_config_node, list);
|
||||
if (asrc_modules_identical(&config_node->params, params)) {
|
||||
list_del_init(&config_node->list);
|
||||
kfree(config_node);
|
||||
}
|
||||
}
|
||||
mutex_unlock(&asrc_cfg[idx].lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool asrc_modules_and_ports_identical(struct asrc_module_config_params *p1,
|
||||
struct asrc_module_config_params *p2)
|
||||
{
|
||||
if (!p1 || !p2
|
||||
|| (p1->fe_id != p2->fe_id)
|
||||
|| (p1->dir != p2->dir)
|
||||
|| (p1->be_id != p2->be_id)
|
||||
|| (p1->m_io != p2->m_io))
|
||||
return false;
|
||||
else
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool asrc_module_and_port_exists_in_config(int idx,
|
||||
struct asrc_module_config_params *params)
|
||||
{
|
||||
struct asrc_module_config_node *config_node = NULL;
|
||||
struct list_head *ptr, *next;
|
||||
|
||||
if (!params)
|
||||
return false;
|
||||
|
||||
mutex_lock(&asrc_cfg[idx].lock);
|
||||
list_for_each_safe(ptr, next, &asrc_cfg[idx].modules) {
|
||||
config_node = list_entry(ptr, struct asrc_module_config_node, list);
|
||||
if (asrc_modules_and_ports_identical(&config_node->params, params)) {
|
||||
mutex_unlock(&asrc_cfg[idx].lock);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
mutex_unlock(&asrc_cfg[idx].lock);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static int asrc_add_module_and_port_to_config(int idx,
|
||||
struct asrc_module_config_params *params)
|
||||
{
|
||||
struct asrc_module_config_node *config_node = NULL;
|
||||
|
||||
if (!params)
|
||||
return -EINVAL;
|
||||
|
||||
/* asrc module does not exist, create a new node */
|
||||
config_node = kmalloc(sizeof(*config_node), GFP_KERNEL);
|
||||
if (config_node == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
mutex_lock(&asrc_cfg[idx].lock);
|
||||
INIT_LIST_HEAD(&config_node->list);
|
||||
memcpy(&config_node->params, params,
|
||||
sizeof(struct asrc_module_config_params));
|
||||
list_add_tail(&config_node->list, &asrc_cfg[idx].modules);
|
||||
mutex_unlock(&asrc_cfg[idx].lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int asrc_get_module_location(struct asrc_module_config_params *params,
|
||||
int *copp_index, int *port_id)
|
||||
{
|
||||
int ret = 0;
|
||||
int fe_id = params->fe_id;
|
||||
int dir = params->dir;
|
||||
int be_id = params->be_id;
|
||||
int copp_idx = 0;
|
||||
unsigned long copp = -1;
|
||||
bool copp_is_found = false;
|
||||
struct msm_pcm_routing_bdai_data *bedai = NULL;
|
||||
int port_type = (dir == SESSION_TYPE_RX) ? MSM_AFE_PORT_TYPE_RX :
|
||||
MSM_AFE_PORT_TYPE_TX;
|
||||
|
||||
mutex_lock(&routing_lock);
|
||||
|
||||
if (NULL == params || NULL == copp_index || NULL == port_id) {
|
||||
pr_err("%s: Invalid params\n", __func__);
|
||||
ret = -EINVAL;
|
||||
goto done;
|
||||
}
|
||||
|
||||
bedai = &msm_bedais[be_id];
|
||||
if (afe_get_port_type(bedai->port_id) != port_type) {
|
||||
pr_err("%s: port_type not match: be_dai %d type %d\n",
|
||||
__func__, be_id, port_type);
|
||||
ret = -EINVAL;
|
||||
goto done;
|
||||
}
|
||||
if (!bedai->active) {
|
||||
pr_err("%s: be_dai %d not active\n", __func__, be_id);
|
||||
ret = 0;
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (!test_bit(fe_id, &bedai->fe_sessions[0])) {
|
||||
pr_err("%s: fe %d session not active\n", __func__, fe_id);
|
||||
ret = -EINVAL;
|
||||
goto done;
|
||||
}
|
||||
|
||||
copp = session_copp_map[fe_id][dir][be_id];
|
||||
for (; copp_idx < MAX_COPPS_PER_PORT; copp_idx++) {
|
||||
if (test_bit(copp_idx, &copp)) {
|
||||
copp_is_found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (copp_is_found) {
|
||||
*copp_index = copp_idx;
|
||||
*port_id = bedai->port_id;
|
||||
} else {
|
||||
*copp_index = -1;
|
||||
*port_id = -1;
|
||||
}
|
||||
|
||||
done:
|
||||
mutex_unlock(&routing_lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int asrc_pack_and_set_params(int module_id, int instance_id, int param_id,
|
||||
int param_size, void *params, int port_id, int copp_idx)
|
||||
{
|
||||
int ret = 0;
|
||||
u8 *packed_params = NULL;
|
||||
struct param_hdr_v3 param_hdr = {0};
|
||||
u32 packed_param_size = (sizeof(struct param_hdr_v3) + param_size);
|
||||
|
||||
packed_params = kzalloc(packed_param_size, GFP_KERNEL);
|
||||
if (!packed_params)
|
||||
return -ENOMEM;
|
||||
|
||||
memset(¶m_hdr, 0, sizeof(param_hdr));
|
||||
param_hdr.module_id = module_id;
|
||||
param_hdr.instance_id = instance_id;
|
||||
param_hdr.param_id = param_id;
|
||||
param_hdr.param_size = param_size;
|
||||
|
||||
packed_param_size = 0;
|
||||
|
||||
mutex_lock(&routing_lock);
|
||||
|
||||
ret = q6common_pack_pp_params(packed_params,
|
||||
¶m_hdr,
|
||||
(u8 *) params,
|
||||
&packed_param_size);
|
||||
if (ret) {
|
||||
pr_err("%s: Failed to pack pp params, error=%d\n",
|
||||
__func__, ret);
|
||||
goto done;
|
||||
}
|
||||
|
||||
ret = adm_set_pp_params(port_id,
|
||||
copp_idx, NULL,
|
||||
packed_params,
|
||||
packed_param_size);
|
||||
if (ret) {
|
||||
pr_err("%s: Failed to set pp params, error=%d\n",
|
||||
__func__, ret);
|
||||
goto done;
|
||||
}
|
||||
done:
|
||||
mutex_unlock(&routing_lock);
|
||||
kfree(packed_params);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int asrc_enable_module(struct asrc_module_config_params *params)
|
||||
{
|
||||
int ret = 0;
|
||||
int module_id = MODULE_ID_AUTO_ASRC;
|
||||
int instance_id = 0;
|
||||
int param_id = PARAM_ID_AUTO_ASRC_ENABLE;
|
||||
int param_size = sizeof(params->enable);
|
||||
void *param_module = (void *)¶ms->enable;
|
||||
int port_id = -1;
|
||||
int copp_idx = -1;
|
||||
|
||||
ret = asrc_get_module_location(params, &copp_idx, &port_id);
|
||||
if (ret) {
|
||||
pr_err("%s: Failed to get module copp_idx, ret=%d\n",
|
||||
__func__, ret);
|
||||
goto done;
|
||||
}
|
||||
|
||||
ret = asrc_pack_and_set_params(module_id, instance_id,
|
||||
param_id, param_size,
|
||||
param_module, port_id, copp_idx);
|
||||
if (ret) {
|
||||
pr_err("%s: Failed to set module params, ret=%d \
|
||||
module_id=0x%x, instance_id=0x%x, param_id=0x%x, \
|
||||
param_size=%d, port_id=0x%x, copp_idx=%d\n",
|
||||
__func__, ret, module_id, instance_id, param_id,
|
||||
param_size, port_id, copp_idx);
|
||||
goto done;
|
||||
}
|
||||
done:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int asrc_put_drift_to_module(
|
||||
struct afe_param_id_dev_timing_stats *timing_stats,
|
||||
struct asrc_module_config_params *params)
|
||||
{
|
||||
int ret = 0;
|
||||
int module_id = MODULE_ID_AUTO_ASRC;
|
||||
int instance_id = 0;
|
||||
int param_id = ((params->m_io == MODULE_PORT_IN)
|
||||
? PARAM_ID_AUTO_ASRC_INPUT_TIMING_STATS
|
||||
: PARAM_ID_AUTO_ASRC_OUTPUT_TIMING_STATS);
|
||||
int param_size = sizeof(struct afe_param_id_dev_timing_stats);
|
||||
void *param_module = (void *)timing_stats;
|
||||
int port_id = -1;
|
||||
int copp_idx = -1;
|
||||
|
||||
ret = asrc_get_module_location(params, &copp_idx, &port_id);
|
||||
if (ret) {
|
||||
pr_err("%s: Failed to get module copp_idx, ret=%d\n",
|
||||
__func__, ret);
|
||||
goto done;
|
||||
}
|
||||
|
||||
ret = asrc_pack_and_set_params(module_id, instance_id,
|
||||
param_id, param_size,
|
||||
param_module, port_id, copp_idx);
|
||||
if (ret) {
|
||||
pr_err("%s: Failed to set module params, ret=%d \
|
||||
module_id=0x%x, instance_id=0x%x, param_id=0x%x, \
|
||||
param_size=%d, port_id=0x%x, copp_idx=%d\n",
|
||||
__func__, ret, module_id, instance_id, param_id,
|
||||
param_size, port_id, copp_idx);
|
||||
goto done;
|
||||
}
|
||||
done:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void get_drift_and_put_asrc(struct work_struct *work)
|
||||
{
|
||||
int ret = 0, continue_to_sched = 0;
|
||||
int be_id = -1;
|
||||
struct msm_pcm_routing_bdai_data *bedai = NULL;
|
||||
struct delayed_work *delayed_drift_work = NULL;
|
||||
struct asrc_config *p_asrc_cfg = NULL;
|
||||
struct afe_param_id_dev_timing_stats timing_stats = {0};
|
||||
struct asrc_module_config_node *config_node = NULL;
|
||||
struct list_head *ptr, *next;
|
||||
|
||||
delayed_drift_work = to_delayed_work(work);
|
||||
if (NULL == delayed_drift_work) {
|
||||
pr_err("%s: Failed to get delayed drift work\n", __func__);
|
||||
goto exit;
|
||||
}
|
||||
p_asrc_cfg = container_of(delayed_drift_work, struct asrc_config,
|
||||
drift_work);
|
||||
if (NULL == p_asrc_cfg) {
|
||||
pr_err("%s: Failed to get asrc config\n", __func__);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
mutex_lock(&p_asrc_cfg->lock);
|
||||
be_id = msm_pcm_get_be_id_from_port_id(p_asrc_cfg->drift_src);
|
||||
if (be_id < 0 || be_id >= MSM_BACKEND_DAI_MAX) {
|
||||
pr_err("%s: Invalid be_id %d\n", __func__, be_id);
|
||||
goto done;
|
||||
}
|
||||
bedai = &msm_bedais[be_id];
|
||||
if (!bedai->active) {
|
||||
pr_err("%s: bedai %d not active\n", __func__, be_id);
|
||||
goto done;
|
||||
}
|
||||
|
||||
ret = afe_get_av_dev_drift(&timing_stats, p_asrc_cfg->drift_src);
|
||||
if (ret)
|
||||
pr_err("%s: Failed to get drift\n", __func__);
|
||||
else
|
||||
pr_debug("%s: Succeed to get drift\n", __func__);
|
||||
|
||||
list_for_each_safe(ptr, next, &p_asrc_cfg->modules) {
|
||||
config_node = list_entry(ptr, struct asrc_module_config_node,
|
||||
list);
|
||||
if (NULL != config_node) {
|
||||
ret = asrc_put_drift_to_module(&timing_stats,
|
||||
&config_node->params);
|
||||
if (ret)
|
||||
pr_err("%s: Failed to set asrc\n", __func__);
|
||||
else
|
||||
pr_debug("%s: src_cfg[%d].drift_src=0x%x, \
|
||||
drift=%d\n", __func__, p_asrc_cfg->idx,
|
||||
p_asrc_cfg->drift_src,
|
||||
timing_stats.acc_drift_value);
|
||||
continue_to_sched = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (continue_to_sched)
|
||||
schedule_delayed_work(&p_asrc_cfg->drift_work,
|
||||
msecs_to_jiffies(sched_delay_ms));
|
||||
done:
|
||||
mutex_unlock(&p_asrc_cfg->lock);
|
||||
exit:
|
||||
return;
|
||||
}
|
||||
|
||||
static void asrc_drift_init(void)
|
||||
{
|
||||
int i = DRIFT_SRC_SW;
|
||||
|
||||
for (; i < DRIFT_SRC_MAX; ++i) {
|
||||
mutex_init(&asrc_cfg[i].lock);
|
||||
|
||||
mutex_lock(&asrc_cfg[i].lock);
|
||||
|
||||
asrc_cfg[i].drift_src = 0;
|
||||
asrc_cfg[i].idx = i;
|
||||
|
||||
INIT_LIST_HEAD(&asrc_cfg[i].modules);
|
||||
|
||||
memset(&asrc_cfg[i].timing_stats, 0,
|
||||
sizeof(struct afe_param_id_dev_timing_stats));
|
||||
|
||||
INIT_DELAYED_WORK(&asrc_cfg[i].drift_work,
|
||||
get_drift_and_put_asrc);
|
||||
mutex_unlock(&asrc_cfg[i].lock);
|
||||
}
|
||||
}
|
||||
|
||||
static void asrc_drift_deinit(void)
|
||||
{
|
||||
int i = DRIFT_SRC_SW;
|
||||
struct asrc_module_config_node *config_node = NULL;
|
||||
struct list_head *ptr, *next;
|
||||
|
||||
for (; i < DRIFT_SRC_MAX; ++i) {
|
||||
mutex_lock(&asrc_cfg[i].lock);
|
||||
|
||||
cancel_delayed_work(&asrc_cfg[i].drift_work);
|
||||
|
||||
list_for_each_safe(ptr, next, &asrc_cfg[i].modules) {
|
||||
config_node = list_entry(ptr,
|
||||
struct asrc_module_config_node, list);
|
||||
list_del_init(&config_node->list);
|
||||
kfree(config_node);
|
||||
}
|
||||
mutex_unlock(&asrc_cfg[i].lock);
|
||||
|
||||
mutex_destroy(&asrc_cfg[i].lock);
|
||||
}
|
||||
}
|
||||
|
||||
static int msm_dai_q6_asrc_config_get(
|
||||
struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
int i = DRIFT_SRC_AFE_PRI;
|
||||
|
||||
for (; i < DRIFT_SRC_MAX; ++i) {
|
||||
mutex_lock(&asrc_cfg[i].lock);
|
||||
ucontrol->value.integer.value[i] =
|
||||
asrc_cfg[i].drift_src;
|
||||
mutex_unlock(&asrc_cfg[i].lock);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int msm_dai_q6_asrc_config_put(
|
||||
struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
int ret = 0, idx = 0, i = 0, be_id = -1, module_enabled = 0;
|
||||
struct afe_param_id_dev_timing_stats timing_stats = {0};
|
||||
struct asrc_module_config_params params = {0};
|
||||
|
||||
int enable = ucontrol->value.integer.value[0];
|
||||
int fe_id = ucontrol->value.integer.value[1];
|
||||
int dir = ucontrol->value.integer.value[2];
|
||||
int be_afe = ucontrol->value.integer.value[3];
|
||||
int m_io = ucontrol->value.integer.value[4];
|
||||
int param = ucontrol->value.integer.value[5];
|
||||
int delay = ucontrol->value.integer.value[6];
|
||||
|
||||
/* group device */
|
||||
be_id = msm_pcm_get_be_id_from_port_id(be_afe & ~0x0100);
|
||||
|
||||
/* validate parameters */
|
||||
if (enable >= ENABLE_ASRC_MAX
|
||||
|| fe_id >= MSM_FRONTEND_DAI_MAX
|
||||
|| dir >= MAX_SESSION_TYPES
|
||||
|| be_id >= MSM_BACKEND_DAI_MAX
|
||||
|| m_io >= MODULE_PORT_MAX) {
|
||||
pr_err("%s:Invalid input param: enable=%d, fe_id=%d, dir=%d, \
|
||||
be_id=%d, m_io=%d, param=0x%x\n", __func__, enable,
|
||||
fe_id, dir, be_id, m_io, param);
|
||||
ret = -EINVAL;
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (delay <= 0 || delay > 10 * ASRC_SCHED_DELAY_MS)
|
||||
sched_delay_ms = ASRC_SCHED_DELAY_MS;
|
||||
else
|
||||
sched_delay_ms = delay;
|
||||
|
||||
params.fe_id = fe_id;
|
||||
params.dir = dir;
|
||||
params.be_id = be_id;
|
||||
params.m_io = m_io;
|
||||
params.param = param;
|
||||
|
||||
/* The module is already enabled if it exists in config */
|
||||
for (i = 0; i < DRIFT_SRC_MAX; ++i) {
|
||||
if (asrc_module_exists_in_config(i, ¶ms)) {
|
||||
module_enabled = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
switch (enable) {
|
||||
case ENABLE_ASRC_DRIFT_SW:
|
||||
idx = DRIFT_SRC_SW;
|
||||
timing_stats.reference_timer = 1; /* indicate SW drift */
|
||||
timing_stats.acc_drift_value = params.param;
|
||||
params.enable = 1;
|
||||
break;
|
||||
case ENABLE_ASRC_DRIFT_HW:
|
||||
idx = get_drift_src_idx(param & ~0x0100); /* group device */
|
||||
mutex_lock(&asrc_cfg[idx].lock);
|
||||
asrc_cfg[idx].drift_src = param & ~0x0100;
|
||||
mutex_unlock(&asrc_cfg[idx].lock);
|
||||
params.enable = 1;
|
||||
break;
|
||||
case DISABLE_ASRC:
|
||||
break;
|
||||
default:
|
||||
pr_err("%s Invalid enable: %d\n", __func__, enable);
|
||||
ret = -EINVAL;
|
||||
goto done;
|
||||
};
|
||||
|
||||
/* branch: disable module */
|
||||
if (enable == DISABLE_ASRC) {
|
||||
params.enable = 0;
|
||||
if (module_enabled) {
|
||||
if (asrc_enable_module(¶ms)) {
|
||||
pr_err("%s: Failed to disable module\n",
|
||||
__func__);
|
||||
ret = -EINVAL;
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
/* remove all modules from store */
|
||||
for (i = DRIFT_SRC_SW; i < DRIFT_SRC_MAX; ++i)
|
||||
asrc_del_modules_from_config(i, ¶ms);
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* branch: enable module */
|
||||
if (!asrc_module_and_port_exists_in_config(idx, ¶ms)) {
|
||||
if (!module_enabled) {
|
||||
if (asrc_enable_module(¶ms)) {
|
||||
pr_err("%s: Failed to enable module\n",
|
||||
__func__);
|
||||
ret = -EINVAL;
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
ret = asrc_add_module_and_port_to_config(idx, ¶ms);
|
||||
if (ret) {
|
||||
pr_err("%s: Failed to add module and port to config\n",
|
||||
__func__);
|
||||
ret = -EINVAL;
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
/* put drift to module */
|
||||
if (enable == ENABLE_ASRC_DRIFT_SW) {
|
||||
ret = asrc_put_drift_to_module(&timing_stats, ¶ms);
|
||||
goto done;
|
||||
} else if (enable == ENABLE_ASRC_DRIFT_HW) {
|
||||
mutex_lock(&asrc_cfg[idx].lock);
|
||||
schedule_delayed_work(&asrc_cfg[idx].drift_work, 0);
|
||||
mutex_unlock(&asrc_cfg[idx].lock);
|
||||
}
|
||||
|
||||
done:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct snd_kcontrol_new asrc_config_controls[] = {
|
||||
SOC_SINGLE_MULTI_EXT("ASRC Config", SND_SOC_NOPM, 0,
|
||||
0xFFFF, 0, ASRC_PARAM_MAX,
|
||||
msm_dai_q6_asrc_config_get,
|
||||
msm_dai_q6_asrc_config_put),
|
||||
};
|
||||
|
||||
static const struct snd_pcm_ops msm_routing_pcm_ops = {
|
||||
.hw_params = msm_pcm_routing_hw_params,
|
||||
.close = msm_pcm_routing_close,
|
||||
@ -31703,9 +32334,10 @@ static int msm_routing_probe(struct snd_soc_component *component)
|
||||
|
||||
snd_soc_add_component_controls(component, pll_clk_drift_controls,
|
||||
ARRAY_SIZE(pll_clk_drift_controls));
|
||||
|
||||
snd_soc_add_component_controls(component, mclk_src_controls,
|
||||
ARRAY_SIZE(mclk_src_controls));
|
||||
snd_soc_add_component_controls(component, asrc_config_controls,
|
||||
ARRAY_SIZE(asrc_config_controls));
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -31873,11 +32505,14 @@ int __init msm_soc_routing_platform_init(void)
|
||||
memset(&be_dai_name_table, 0, sizeof(be_dai_name_table));
|
||||
memset(&last_be_id_configured, 0, sizeof(last_be_id_configured));
|
||||
|
||||
asrc_drift_init();
|
||||
|
||||
return platform_driver_register(&msm_routing_pcm_driver);
|
||||
}
|
||||
|
||||
void msm_soc_routing_platform_exit(void)
|
||||
{
|
||||
asrc_drift_deinit();
|
||||
msm_routing_delete_cal_data();
|
||||
memset(&be_dai_name_table, 0, sizeof(be_dai_name_table));
|
||||
mutex_destroy(&routing_lock);
|
||||
|
Loading…
Reference in New Issue
Block a user