Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 3defd5d6 authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge "ASoC: msm: qdsp6v2: Propagate device HW delay to AFE"

parents f9cabe67 db58c58a
Loading
Loading
Loading
Loading
+9 −0
Original line number Diff line number Diff line
@@ -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;
@@ -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 {
+9 −0
Original line number Diff line number Diff line
@@ -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 */
@@ -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)
+153 −0
Original line number Diff line number Diff line
@@ -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;
@@ -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;
@@ -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;
@@ -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;
}

@@ -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))) {
@@ -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;
}

+6 −0
Original line number Diff line number Diff line
@@ -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);
@@ -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
+67 −0
Original line number Diff line number Diff line
@@ -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__);
@@ -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);