Loading include/sound/apr_audio-v2.h +9 −0 Original line number Diff line number Diff line Loading @@ -1998,6 +1998,14 @@ struct afe_param_id_pseudo_port_cfg { */ } __packed; #define AFE_PARAM_ID_DEVICE_HW_DELAY 0x00010243 #define AFE_API_VERSION_DEVICE_HW_DELAY 0x1 struct afe_param_id_device_hw_delay_cfg { uint32_t device_hw_delay_minor_version; uint32_t delay_in_us; } __packed; union afe_port_config { struct afe_param_id_pcm_cfg pcm; struct afe_param_id_i2s_cfg i2s; Loading @@ -2006,6 +2014,7 @@ union afe_port_config { struct afe_param_id_rt_proxy_port_cfg rtproxy; struct afe_param_id_internal_bt_fm_cfg int_bt_fm; struct afe_param_id_pseudo_port_cfg pseudo_port; struct afe_param_id_device_hw_delay_cfg hw_delay; } __packed; struct afe_audioif_config_command_no_payload { Loading include/uapi/linux/msm_audio_acdb.h +9 −0 Original line number Diff line number Diff line Loading @@ -63,6 +63,10 @@ (AUDIO_MAX_COMMON_IOCTL_NUM+28), unsigned) #define AUDIO_DEREGISTER_VOCPROC_VOL_TABLE _IOW(AUDIO_IOCTL_MAGIC, \ (AUDIO_MAX_COMMON_IOCTL_NUM+29), unsigned) #define AUDIO_SET_HW_DELAY_RX _IOW(AUDIO_IOCTL_MAGIC, \ (AUDIO_MAX_COMMON_IOCTL_NUM+30), struct hw_delay) #define AUDIO_SET_HW_DELAY_TX _IOW(AUDIO_IOCTL_MAGIC, \ (AUDIO_MAX_COMMON_IOCTL_NUM+31), struct hw_delay) #define AUDIO_MAX_ACDB_IOCTL (AUDIO_MAX_COMMON_IOCTL_NUM+40) /* ACDB structures */ Loading Loading @@ -96,6 +100,11 @@ struct msm_spk_prot_status { int status; }; struct hw_delay { uint32_t num_entries; void *delay_info; }; /* For Real-Time Audio Calibration */ #define AUDIO_GET_RTAC_ADM_INFO _IOR(AUDIO_IOCTL_MAGIC, \ (AUDIO_MAX_ACDB_IOCTL+1), unsigned) Loading sound/soc/msm/qdsp6v2/audio_acdb.c +153 −0 Original line number Diff line number Diff line Loading @@ -36,6 +36,7 @@ #define NUM_VOCPROC_BLOCKS (6 * MAX_NETWORKS) #define ACDB_TOTAL_VOICE_ALLOCATION (ACDB_BLOCK_SIZE * NUM_VOCPROC_BLOCKS) #define MAX_HW_DELAY_ENTRIES 25 struct sidetone_atomic_cal { atomic_t enable; Loading Loading @@ -98,6 +99,10 @@ struct acdb_data { /* Speaker protection */ struct msm_spk_prot_cfg spk_prot_cfg; /* Av sync delay info */ struct hw_delay hw_delay_rx; struct hw_delay hw_delay_tx; }; static struct acdb_data acdb_data; Loading Loading @@ -371,6 +376,122 @@ done: return result; } int get_hw_delay(int32_t path, struct hw_delay_entry *entry) { int i, result = 0; struct hw_delay *delay = NULL; struct hw_delay_entry *info = NULL; pr_debug("%s,\n", __func__); if (entry == NULL) { pr_err("ACDB=> NULL pointer sent to %s\n", __func__); result = -EINVAL; goto ret; } if ((path >= MAX_AUDPROC_TYPES) || (path < 0)) { pr_err("ACDB=> Bad path sent to %s, path: %d\n", __func__, path); result = -EINVAL; goto ret; } mutex_lock(&acdb_data.acdb_mutex); if (path == RX_CAL) delay = &acdb_data.hw_delay_rx; else if (path == TX_CAL) delay = &acdb_data.hw_delay_tx; if ((delay == NULL) || ((delay != NULL) && delay->num_entries == 0)) { pr_err("ACDB=> %s Invalid delay/ delay entries\n", __func__); result = -EINVAL; goto done; } info = (struct hw_delay_entry *)(delay->delay_info); if (info == NULL) { pr_err("ACDB=> %s Delay entries info is NULL\n", __func__); result = -EFAULT; goto done; } for (i = 0; i < delay->num_entries; i++) { if (info[i].sample_rate == entry->sample_rate) { entry->delay_usec = info[i].delay_usec; break; } } if (i == delay->num_entries) { pr_err("ACDB=> %s: Unable to find delay for sample rate %d\n", __func__, entry->sample_rate); result = -EFAULT; } done: mutex_unlock(&acdb_data.acdb_mutex); ret: pr_debug("ACDB=> %s: Path = %d samplerate = %u usec = %u status %d\n", __func__, path, entry->sample_rate, entry->delay_usec, result); return result; } int store_hw_delay(int32_t path, void *arg) { int result = 0; struct hw_delay delay; struct hw_delay *delay_dest = NULL; pr_debug("%s,\n", __func__); if ((path >= MAX_AUDPROC_TYPES) || (path < 0) || (arg == NULL)) { pr_err("ACDB=> Bad path/ pointer sent to %s, path: %d\n", __func__, path); result = -EINVAL; goto done; } result = copy_from_user((void *)&delay, (void *)arg, sizeof(struct hw_delay)); if (result) { pr_err("ACDB=> %s failed to copy hw delay: result=%d path=%d\n", __func__, result, path); result = -EFAULT; goto done; } if ((delay.num_entries <= 0) || (delay.num_entries > MAX_HW_DELAY_ENTRIES)) { pr_err("ACDB=> %s incorrect no of hw delay entries: %d\n", __func__, delay.num_entries); result = -EINVAL; goto done; } if ((path >= MAX_AUDPROC_TYPES) || (path < 0)) { pr_err("ACDB=> Bad path sent to %s, path: %d\n", __func__, path); result = -EINVAL; goto done; } pr_debug("ACDB=> %s : Path = %d num_entries = %d\n", __func__, path, delay.num_entries); mutex_lock(&acdb_data.acdb_mutex); if (path == RX_CAL) delay_dest = &acdb_data.hw_delay_rx; else if (path == TX_CAL) delay_dest = &acdb_data.hw_delay_tx; delay_dest->num_entries = delay.num_entries; result = copy_from_user(delay_dest->delay_info, delay.delay_info, (sizeof(struct hw_delay_entry)* delay.num_entries)); if (result) { pr_err("ACDB=> %s failed to copy hw delay info res=%d path=%d", __func__, result, path); result = -EFAULT; } mutex_unlock(&acdb_data.acdb_mutex); done: return result; } int get_anc_cal(struct acdb_cal_block *cal_block) { int result = 0; Loading Loading @@ -998,6 +1119,29 @@ static int acdb_open(struct inode *inode, struct file *f) atomic_set(&acdb_data.valid_adm_custom_top, 1); atomic_set(&acdb_data.valid_asm_custom_top, 1); atomic_inc(&usage_count); /* Allocate memory for hw delay entries */ mutex_lock(&acdb_data.acdb_mutex); acdb_data.hw_delay_rx.num_entries = 0; acdb_data.hw_delay_tx.num_entries = 0; acdb_data.hw_delay_rx.delay_info = kmalloc(sizeof(struct hw_delay_entry)* MAX_HW_DELAY_ENTRIES, GFP_KERNEL); if (acdb_data.hw_delay_rx.delay_info == NULL) { pr_err("%s : Failed to allocate av sync delay entries rx\n", __func__); } acdb_data.hw_delay_tx.delay_info = kmalloc(sizeof(struct hw_delay_entry)* MAX_HW_DELAY_ENTRIES, GFP_KERNEL); if (acdb_data.hw_delay_tx.delay_info == NULL) { pr_err("%s : Failed to allocate av sync delay entries tx\n", __func__); } mutex_unlock(&acdb_data.acdb_mutex); return result; } Loading Loading @@ -1238,6 +1382,12 @@ static long acdb_ioctl(struct file *f, case AUDIO_DEREGISTER_VOCPROC_VOL_TABLE: result = deregister_vocvol_table(); goto done; case AUDIO_SET_HW_DELAY_RX: result = store_hw_delay(RX_CAL, (void *)arg); goto done; case AUDIO_SET_HW_DELAY_TX: result = store_hw_delay(TX_CAL, (void *)arg); goto done; } if (copy_from_user(&size, (void *) arg, sizeof(size))) { Loading Loading @@ -1393,6 +1543,9 @@ static int acdb_release(struct inode *inode, struct file *f) else result = deregister_memory(); kfree(acdb_data.hw_delay_rx.delay_info); kfree(acdb_data.hw_delay_tx.delay_info); return result; } Loading sound/soc/msm/qdsp6v2/audio_acdb.h +6 −0 Original line number Diff line number Diff line Loading @@ -41,6 +41,11 @@ struct acdb_atomic_cal_block { atomic_t cal_paddr; }; struct hw_delay_entry { uint32_t sample_rate; uint32_t delay_usec; }; uint32_t get_voice_rx_topology(void); uint32_t get_voice_tx_topology(void); uint32_t get_adm_rx_topology(void); Loading @@ -65,5 +70,6 @@ int get_vocvol_cal(struct acdb_cal_block *cal_block); int get_sidetone_cal(struct sidetone_cal *cal_data); int get_spk_protection_cfg(struct msm_spk_prot_cfg *prot_cfg); int get_aanc_cal(struct acdb_cal_block *cal_block); int get_hw_delay(int32_t path, struct hw_delay_entry *delay_info); #endif sound/soc/msm/qdsp6v2/q6afe.c +67 −0 Original line number Diff line number Diff line Loading @@ -632,6 +632,72 @@ static void afe_send_cal_spkr_prot_rx(int port_id) } } static int afe_send_hw_delay(u16 port_id, u32 rate) { struct hw_delay_entry delay_entry; struct afe_audioif_config_command config; int index = 0; int ret = -EINVAL; pr_debug("%s\n", __func__); delay_entry.sample_rate = rate; if (afe_get_port_type(port_id) == MSM_AFE_PORT_TYPE_TX) ret = get_hw_delay(TX_CAL, &delay_entry); else if (afe_get_port_type(port_id) == MSM_AFE_PORT_TYPE_RX) ret = get_hw_delay(RX_CAL, &delay_entry); if (ret != 0) { pr_warn("%s: Failed to get hw delay info\n", __func__); goto fail_cmd; } index = q6audio_get_port_index(port_id); if (index < 0) { pr_debug("%s: AFE port index invalid!\n", __func__); goto fail_cmd; } config.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD, APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER); config.hdr.pkt_size = sizeof(config); config.hdr.src_port = 0; config.hdr.dest_port = 0; config.hdr.token = index; config.hdr.opcode = AFE_PORT_CMD_SET_PARAM_V2; config.param.port_id = q6audio_get_port_id(port_id); config.param.payload_size = sizeof(config) - sizeof(struct apr_hdr) - sizeof(config.param); config.param.payload_address_lsw = 0x00; config.param.payload_address_msw = 0x00; config.param.mem_map_handle = 0x00; config.pdata.module_id = AFE_MODULE_AUDIO_DEV_INTERFACE; config.pdata.param_id = AFE_PARAM_ID_DEVICE_HW_DELAY; config.pdata.param_size = sizeof(config.port); config.port.hw_delay.delay_in_us = delay_entry.delay_usec; config.port.hw_delay.device_hw_delay_minor_version = AFE_API_VERSION_DEVICE_HW_DELAY; ret = afe_apr_send_pkt(&config, &this_afe.wait[index]); if (ret) { pr_err("%s: AFE hw delay for port %#x failed\n", __func__, port_id); goto fail_cmd; } else if (atomic_read(&this_afe.status) != 0) { pr_err("%s: config cmd failed\n", __func__); ret = -EINVAL; goto fail_cmd; } fail_cmd: pr_debug("%s port_id %u rate %u delay_usec %d status %d\n", __func__, port_id, rate, delay_entry.delay_usec, ret); return ret; } void afe_send_cal(u16 port_id) { pr_debug("%s\n", __func__); Loading Loading @@ -1248,6 +1314,7 @@ int afe_port_start(u16 port_id, union afe_port_config *afe_config, return ret; afe_send_cal(port_id); afe_send_hw_delay(port_id, rate); /* Start SW MAD module */ mad_type = afe_port_get_mad_type(port_id); Loading Loading
include/sound/apr_audio-v2.h +9 −0 Original line number Diff line number Diff line Loading @@ -1998,6 +1998,14 @@ struct afe_param_id_pseudo_port_cfg { */ } __packed; #define AFE_PARAM_ID_DEVICE_HW_DELAY 0x00010243 #define AFE_API_VERSION_DEVICE_HW_DELAY 0x1 struct afe_param_id_device_hw_delay_cfg { uint32_t device_hw_delay_minor_version; uint32_t delay_in_us; } __packed; union afe_port_config { struct afe_param_id_pcm_cfg pcm; struct afe_param_id_i2s_cfg i2s; Loading @@ -2006,6 +2014,7 @@ union afe_port_config { struct afe_param_id_rt_proxy_port_cfg rtproxy; struct afe_param_id_internal_bt_fm_cfg int_bt_fm; struct afe_param_id_pseudo_port_cfg pseudo_port; struct afe_param_id_device_hw_delay_cfg hw_delay; } __packed; struct afe_audioif_config_command_no_payload { Loading
include/uapi/linux/msm_audio_acdb.h +9 −0 Original line number Diff line number Diff line Loading @@ -63,6 +63,10 @@ (AUDIO_MAX_COMMON_IOCTL_NUM+28), unsigned) #define AUDIO_DEREGISTER_VOCPROC_VOL_TABLE _IOW(AUDIO_IOCTL_MAGIC, \ (AUDIO_MAX_COMMON_IOCTL_NUM+29), unsigned) #define AUDIO_SET_HW_DELAY_RX _IOW(AUDIO_IOCTL_MAGIC, \ (AUDIO_MAX_COMMON_IOCTL_NUM+30), struct hw_delay) #define AUDIO_SET_HW_DELAY_TX _IOW(AUDIO_IOCTL_MAGIC, \ (AUDIO_MAX_COMMON_IOCTL_NUM+31), struct hw_delay) #define AUDIO_MAX_ACDB_IOCTL (AUDIO_MAX_COMMON_IOCTL_NUM+40) /* ACDB structures */ Loading Loading @@ -96,6 +100,11 @@ struct msm_spk_prot_status { int status; }; struct hw_delay { uint32_t num_entries; void *delay_info; }; /* For Real-Time Audio Calibration */ #define AUDIO_GET_RTAC_ADM_INFO _IOR(AUDIO_IOCTL_MAGIC, \ (AUDIO_MAX_ACDB_IOCTL+1), unsigned) Loading
sound/soc/msm/qdsp6v2/audio_acdb.c +153 −0 Original line number Diff line number Diff line Loading @@ -36,6 +36,7 @@ #define NUM_VOCPROC_BLOCKS (6 * MAX_NETWORKS) #define ACDB_TOTAL_VOICE_ALLOCATION (ACDB_BLOCK_SIZE * NUM_VOCPROC_BLOCKS) #define MAX_HW_DELAY_ENTRIES 25 struct sidetone_atomic_cal { atomic_t enable; Loading Loading @@ -98,6 +99,10 @@ struct acdb_data { /* Speaker protection */ struct msm_spk_prot_cfg spk_prot_cfg; /* Av sync delay info */ struct hw_delay hw_delay_rx; struct hw_delay hw_delay_tx; }; static struct acdb_data acdb_data; Loading Loading @@ -371,6 +376,122 @@ done: return result; } int get_hw_delay(int32_t path, struct hw_delay_entry *entry) { int i, result = 0; struct hw_delay *delay = NULL; struct hw_delay_entry *info = NULL; pr_debug("%s,\n", __func__); if (entry == NULL) { pr_err("ACDB=> NULL pointer sent to %s\n", __func__); result = -EINVAL; goto ret; } if ((path >= MAX_AUDPROC_TYPES) || (path < 0)) { pr_err("ACDB=> Bad path sent to %s, path: %d\n", __func__, path); result = -EINVAL; goto ret; } mutex_lock(&acdb_data.acdb_mutex); if (path == RX_CAL) delay = &acdb_data.hw_delay_rx; else if (path == TX_CAL) delay = &acdb_data.hw_delay_tx; if ((delay == NULL) || ((delay != NULL) && delay->num_entries == 0)) { pr_err("ACDB=> %s Invalid delay/ delay entries\n", __func__); result = -EINVAL; goto done; } info = (struct hw_delay_entry *)(delay->delay_info); if (info == NULL) { pr_err("ACDB=> %s Delay entries info is NULL\n", __func__); result = -EFAULT; goto done; } for (i = 0; i < delay->num_entries; i++) { if (info[i].sample_rate == entry->sample_rate) { entry->delay_usec = info[i].delay_usec; break; } } if (i == delay->num_entries) { pr_err("ACDB=> %s: Unable to find delay for sample rate %d\n", __func__, entry->sample_rate); result = -EFAULT; } done: mutex_unlock(&acdb_data.acdb_mutex); ret: pr_debug("ACDB=> %s: Path = %d samplerate = %u usec = %u status %d\n", __func__, path, entry->sample_rate, entry->delay_usec, result); return result; } int store_hw_delay(int32_t path, void *arg) { int result = 0; struct hw_delay delay; struct hw_delay *delay_dest = NULL; pr_debug("%s,\n", __func__); if ((path >= MAX_AUDPROC_TYPES) || (path < 0) || (arg == NULL)) { pr_err("ACDB=> Bad path/ pointer sent to %s, path: %d\n", __func__, path); result = -EINVAL; goto done; } result = copy_from_user((void *)&delay, (void *)arg, sizeof(struct hw_delay)); if (result) { pr_err("ACDB=> %s failed to copy hw delay: result=%d path=%d\n", __func__, result, path); result = -EFAULT; goto done; } if ((delay.num_entries <= 0) || (delay.num_entries > MAX_HW_DELAY_ENTRIES)) { pr_err("ACDB=> %s incorrect no of hw delay entries: %d\n", __func__, delay.num_entries); result = -EINVAL; goto done; } if ((path >= MAX_AUDPROC_TYPES) || (path < 0)) { pr_err("ACDB=> Bad path sent to %s, path: %d\n", __func__, path); result = -EINVAL; goto done; } pr_debug("ACDB=> %s : Path = %d num_entries = %d\n", __func__, path, delay.num_entries); mutex_lock(&acdb_data.acdb_mutex); if (path == RX_CAL) delay_dest = &acdb_data.hw_delay_rx; else if (path == TX_CAL) delay_dest = &acdb_data.hw_delay_tx; delay_dest->num_entries = delay.num_entries; result = copy_from_user(delay_dest->delay_info, delay.delay_info, (sizeof(struct hw_delay_entry)* delay.num_entries)); if (result) { pr_err("ACDB=> %s failed to copy hw delay info res=%d path=%d", __func__, result, path); result = -EFAULT; } mutex_unlock(&acdb_data.acdb_mutex); done: return result; } int get_anc_cal(struct acdb_cal_block *cal_block) { int result = 0; Loading Loading @@ -998,6 +1119,29 @@ static int acdb_open(struct inode *inode, struct file *f) atomic_set(&acdb_data.valid_adm_custom_top, 1); atomic_set(&acdb_data.valid_asm_custom_top, 1); atomic_inc(&usage_count); /* Allocate memory for hw delay entries */ mutex_lock(&acdb_data.acdb_mutex); acdb_data.hw_delay_rx.num_entries = 0; acdb_data.hw_delay_tx.num_entries = 0; acdb_data.hw_delay_rx.delay_info = kmalloc(sizeof(struct hw_delay_entry)* MAX_HW_DELAY_ENTRIES, GFP_KERNEL); if (acdb_data.hw_delay_rx.delay_info == NULL) { pr_err("%s : Failed to allocate av sync delay entries rx\n", __func__); } acdb_data.hw_delay_tx.delay_info = kmalloc(sizeof(struct hw_delay_entry)* MAX_HW_DELAY_ENTRIES, GFP_KERNEL); if (acdb_data.hw_delay_tx.delay_info == NULL) { pr_err("%s : Failed to allocate av sync delay entries tx\n", __func__); } mutex_unlock(&acdb_data.acdb_mutex); return result; } Loading Loading @@ -1238,6 +1382,12 @@ static long acdb_ioctl(struct file *f, case AUDIO_DEREGISTER_VOCPROC_VOL_TABLE: result = deregister_vocvol_table(); goto done; case AUDIO_SET_HW_DELAY_RX: result = store_hw_delay(RX_CAL, (void *)arg); goto done; case AUDIO_SET_HW_DELAY_TX: result = store_hw_delay(TX_CAL, (void *)arg); goto done; } if (copy_from_user(&size, (void *) arg, sizeof(size))) { Loading Loading @@ -1393,6 +1543,9 @@ static int acdb_release(struct inode *inode, struct file *f) else result = deregister_memory(); kfree(acdb_data.hw_delay_rx.delay_info); kfree(acdb_data.hw_delay_tx.delay_info); return result; } Loading
sound/soc/msm/qdsp6v2/audio_acdb.h +6 −0 Original line number Diff line number Diff line Loading @@ -41,6 +41,11 @@ struct acdb_atomic_cal_block { atomic_t cal_paddr; }; struct hw_delay_entry { uint32_t sample_rate; uint32_t delay_usec; }; uint32_t get_voice_rx_topology(void); uint32_t get_voice_tx_topology(void); uint32_t get_adm_rx_topology(void); Loading @@ -65,5 +70,6 @@ int get_vocvol_cal(struct acdb_cal_block *cal_block); int get_sidetone_cal(struct sidetone_cal *cal_data); int get_spk_protection_cfg(struct msm_spk_prot_cfg *prot_cfg); int get_aanc_cal(struct acdb_cal_block *cal_block); int get_hw_delay(int32_t path, struct hw_delay_entry *delay_info); #endif
sound/soc/msm/qdsp6v2/q6afe.c +67 −0 Original line number Diff line number Diff line Loading @@ -632,6 +632,72 @@ static void afe_send_cal_spkr_prot_rx(int port_id) } } static int afe_send_hw_delay(u16 port_id, u32 rate) { struct hw_delay_entry delay_entry; struct afe_audioif_config_command config; int index = 0; int ret = -EINVAL; pr_debug("%s\n", __func__); delay_entry.sample_rate = rate; if (afe_get_port_type(port_id) == MSM_AFE_PORT_TYPE_TX) ret = get_hw_delay(TX_CAL, &delay_entry); else if (afe_get_port_type(port_id) == MSM_AFE_PORT_TYPE_RX) ret = get_hw_delay(RX_CAL, &delay_entry); if (ret != 0) { pr_warn("%s: Failed to get hw delay info\n", __func__); goto fail_cmd; } index = q6audio_get_port_index(port_id); if (index < 0) { pr_debug("%s: AFE port index invalid!\n", __func__); goto fail_cmd; } config.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD, APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER); config.hdr.pkt_size = sizeof(config); config.hdr.src_port = 0; config.hdr.dest_port = 0; config.hdr.token = index; config.hdr.opcode = AFE_PORT_CMD_SET_PARAM_V2; config.param.port_id = q6audio_get_port_id(port_id); config.param.payload_size = sizeof(config) - sizeof(struct apr_hdr) - sizeof(config.param); config.param.payload_address_lsw = 0x00; config.param.payload_address_msw = 0x00; config.param.mem_map_handle = 0x00; config.pdata.module_id = AFE_MODULE_AUDIO_DEV_INTERFACE; config.pdata.param_id = AFE_PARAM_ID_DEVICE_HW_DELAY; config.pdata.param_size = sizeof(config.port); config.port.hw_delay.delay_in_us = delay_entry.delay_usec; config.port.hw_delay.device_hw_delay_minor_version = AFE_API_VERSION_DEVICE_HW_DELAY; ret = afe_apr_send_pkt(&config, &this_afe.wait[index]); if (ret) { pr_err("%s: AFE hw delay for port %#x failed\n", __func__, port_id); goto fail_cmd; } else if (atomic_read(&this_afe.status) != 0) { pr_err("%s: config cmd failed\n", __func__); ret = -EINVAL; goto fail_cmd; } fail_cmd: pr_debug("%s port_id %u rate %u delay_usec %d status %d\n", __func__, port_id, rate, delay_entry.delay_usec, ret); return ret; } void afe_send_cal(u16 port_id) { pr_debug("%s\n", __func__); Loading Loading @@ -1248,6 +1314,7 @@ int afe_port_start(u16 port_id, union afe_port_config *afe_config, return ret; afe_send_cal(port_id); afe_send_hw_delay(port_id, rate); /* Start SW MAD module */ mad_type = afe_port_get_mad_type(port_id); Loading