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 = {
|
static const struct snd_pcm_ops msm_routing_pcm_ops = {
|
||||||
.hw_params = msm_pcm_routing_hw_params,
|
.hw_params = msm_pcm_routing_hw_params,
|
||||||
.close = msm_pcm_routing_close,
|
.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,
|
snd_soc_add_component_controls(component, pll_clk_drift_controls,
|
||||||
ARRAY_SIZE(pll_clk_drift_controls));
|
ARRAY_SIZE(pll_clk_drift_controls));
|
||||||
|
|
||||||
snd_soc_add_component_controls(component, mclk_src_controls,
|
snd_soc_add_component_controls(component, mclk_src_controls,
|
||||||
ARRAY_SIZE(mclk_src_controls));
|
ARRAY_SIZE(mclk_src_controls));
|
||||||
|
snd_soc_add_component_controls(component, asrc_config_controls,
|
||||||
|
ARRAY_SIZE(asrc_config_controls));
|
||||||
return 0;
|
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(&be_dai_name_table, 0, sizeof(be_dai_name_table));
|
||||||
memset(&last_be_id_configured, 0, sizeof(last_be_id_configured));
|
memset(&last_be_id_configured, 0, sizeof(last_be_id_configured));
|
||||||
|
|
||||||
|
asrc_drift_init();
|
||||||
|
|
||||||
return platform_driver_register(&msm_routing_pcm_driver);
|
return platform_driver_register(&msm_routing_pcm_driver);
|
||||||
}
|
}
|
||||||
|
|
||||||
void msm_soc_routing_platform_exit(void)
|
void msm_soc_routing_platform_exit(void)
|
||||||
{
|
{
|
||||||
|
asrc_drift_deinit();
|
||||||
msm_routing_delete_cal_data();
|
msm_routing_delete_cal_data();
|
||||||
memset(&be_dai_name_table, 0, sizeof(be_dai_name_table));
|
memset(&be_dai_name_table, 0, sizeof(be_dai_name_table));
|
||||||
mutex_destroy(&routing_lock);
|
mutex_destroy(&routing_lock);
|
||||||
|
Loading…
Reference in New Issue
Block a user