M7350/kernel/sound/soc/msm/qdsp6v2/msm-dolby-dap-config.c
2024-09-09 08:52:07 +00:00

711 lines
24 KiB
C

/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <linux/init.h>
#include <linux/err.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/platform_device.h>
#include <linux/bitops.h>
#include <linux/mutex.h>
#include <linux/of_device.h>
#include <linux/slab.h>
#include <sound/core.h>
#include <sound/soc.h>
#include <sound/soc-dapm.h>
#include <sound/pcm.h>
#include <sound/initval.h>
#include <sound/control.h>
#include <sound/q6adm-v2.h>
#include <sound/q6asm-v2.h>
#include <sound/q6afe-v2.h>
#include "msm-dolby-dap-config.h"
/* dolby endp based parameters */
struct dolby_dap_endp_params_s {
int device;
int device_ch_caps;
int dap_device;
int params_id[DOLBY_NUM_ENDP_DEPENDENT_PARAMS];
int params_len[DOLBY_NUM_ENDP_DEPENDENT_PARAMS];
int params_offset[DOLBY_NUM_ENDP_DEPENDENT_PARAMS];
int params_val[DOLBY_ENDDEP_PARAM_LENGTH];
};
const struct dolby_dap_endp_params_s
dolby_dap_endp_params[NUM_DOLBY_ENDP_DEVICE] = {
{EARPIECE, 2, DOLBY_ENDP_EXT_SPEAKERS,
{DOLBY_PARAM_ID_DVLO}, {DOLBY_ENDDEP_PARAM_DVLO_LENGTH},
{DOLBY_ENDDEP_PARAM_DVLO_OFFSET}, {-320} },
{SPEAKER, 2, DOLBY_ENDP_INT_SPEAKERS,
{DOLBY_PARAM_ID_DVLO}, {DOLBY_ENDDEP_PARAM_DVLO_LENGTH},
{DOLBY_ENDDEP_PARAM_DVLO_OFFSET}, {-320} },
{WIRED_HEADSET, 2, DOLBY_ENDP_HEADPHONES,
{DOLBY_PARAM_ID_DVLO}, {DOLBY_ENDDEP_PARAM_DVLO_LENGTH},
{DOLBY_ENDDEP_PARAM_DVLO_OFFSET}, {-320} },
{WIRED_HEADPHONE, 2, DOLBY_ENDP_HEADPHONES,
{DOLBY_PARAM_ID_DVLO}, {DOLBY_ENDDEP_PARAM_DVLO_LENGTH},
{DOLBY_ENDDEP_PARAM_DVLO_OFFSET}, {-320} },
{BLUETOOTH_SCO, 2, DOLBY_ENDP_EXT_SPEAKERS,
{DOLBY_PARAM_ID_DVLO}, {DOLBY_ENDDEP_PARAM_DVLO_LENGTH},
{DOLBY_ENDDEP_PARAM_DVLO_OFFSET}, {-320} },
{BLUETOOTH_SCO_HEADSET, 2, DOLBY_ENDP_EXT_SPEAKERS,
{DOLBY_PARAM_ID_DVLO}, {DOLBY_ENDDEP_PARAM_DVLO_LENGTH},
{DOLBY_ENDDEP_PARAM_DVLO_OFFSET}, {-320} },
{BLUETOOTH_SCO_CARKIT, 2, DOLBY_ENDP_EXT_SPEAKERS,
{DOLBY_PARAM_ID_DVLO}, {DOLBY_ENDDEP_PARAM_DVLO_LENGTH},
{DOLBY_ENDDEP_PARAM_DVLO_OFFSET}, {-320} },
{BLUETOOTH_A2DP, 2, DOLBY_ENDP_EXT_SPEAKERS,
{DOLBY_PARAM_ID_DVLO}, {DOLBY_ENDDEP_PARAM_DVLO_LENGTH},
{DOLBY_ENDDEP_PARAM_DVLO_OFFSET}, {-320} },
{BLUETOOTH_A2DP_HEADPHONES, 2, DOLBY_ENDP_HEADPHONES,
{DOLBY_PARAM_ID_DVLO}, {DOLBY_ENDDEP_PARAM_DVLO_LENGTH},
{DOLBY_ENDDEP_PARAM_DVLO_OFFSET}, {-320} },
{BLUETOOTH_A2DP_SPEAKER, 2, DOLBY_ENDP_EXT_SPEAKERS,
{DOLBY_PARAM_ID_DVLO}, {DOLBY_ENDDEP_PARAM_DVLO_LENGTH},
{DOLBY_ENDDEP_PARAM_DVLO_OFFSET}, {-320} },
{AUX_DIGITAL, 2, DOLBY_ENDP_HDMI,
{DOLBY_PARAM_ID_DVLO}, {DOLBY_ENDDEP_PARAM_DVLO_LENGTH},
{DOLBY_ENDDEP_PARAM_DVLO_OFFSET}, {-640} },
{AUX_DIGITAL, 6, DOLBY_ENDP_HDMI,
{DOLBY_PARAM_ID_DVLO}, {DOLBY_ENDDEP_PARAM_DVLO_LENGTH},
{DOLBY_ENDDEP_PARAM_DVLO_OFFSET}, {-640} },
{AUX_DIGITAL, 8, DOLBY_ENDP_HDMI,
{DOLBY_PARAM_ID_DVLO}, {DOLBY_ENDDEP_PARAM_DVLO_LENGTH},
{DOLBY_ENDDEP_PARAM_DVLO_OFFSET}, {-640} },
{ANLG_DOCK_HEADSET, 2, DOLBY_ENDP_HEADPHONES,
{DOLBY_PARAM_ID_DVLO}, {DOLBY_ENDDEP_PARAM_DVLO_LENGTH},
{DOLBY_ENDDEP_PARAM_DVLO_OFFSET}, {-320} },
{DGTL_DOCK_HEADSET, 2, DOLBY_ENDP_HEADPHONES,
{DOLBY_PARAM_ID_DVLO}, {DOLBY_ENDDEP_PARAM_DVLO_LENGTH},
{DOLBY_ENDDEP_PARAM_DVLO_OFFSET}, {-320} },
{USB_ACCESSORY, 2, DOLBY_ENDP_EXT_SPEAKERS,
{DOLBY_PARAM_ID_DVLO}, {DOLBY_ENDDEP_PARAM_DVLO_LENGTH},
{DOLBY_ENDDEP_PARAM_DVLO_OFFSET}, {-320} },
{USB_DEVICE, 2, DOLBY_ENDP_EXT_SPEAKERS,
{DOLBY_PARAM_ID_DVLO}, {DOLBY_ENDDEP_PARAM_DVLO_LENGTH},
{DOLBY_ENDDEP_PARAM_DVLO_OFFSET}, {-320} },
{REMOTE_SUBMIX, 2, DOLBY_ENDP_EXT_SPEAKERS,
{DOLBY_PARAM_ID_DVLO}, {DOLBY_ENDDEP_PARAM_DVLO_LENGTH},
{DOLBY_ENDDEP_PARAM_DVLO_OFFSET}, {-320} },
{ANC_HEADSET, 2, DOLBY_ENDP_HEADPHONES,
{DOLBY_PARAM_ID_DVLO}, {DOLBY_ENDDEP_PARAM_DVLO_LENGTH},
{DOLBY_ENDDEP_PARAM_DVLO_OFFSET}, {-320} },
{ANC_HEADPHONE, 2, DOLBY_ENDP_HEADPHONES,
{DOLBY_PARAM_ID_DVLO}, {DOLBY_ENDDEP_PARAM_DVLO_LENGTH},
{DOLBY_ENDDEP_PARAM_DVLO_OFFSET}, {-320} },
{PROXY, 2, DOLBY_ENDP_EXT_SPEAKERS,
{DOLBY_PARAM_ID_DVLO}, {DOLBY_ENDDEP_PARAM_DVLO_LENGTH},
{DOLBY_ENDDEP_PARAM_DVLO_OFFSET}, {-320} },
{FM, 2, DOLBY_ENDP_EXT_SPEAKERS,
{DOLBY_PARAM_ID_DVLO}, {DOLBY_ENDDEP_PARAM_DVLO_LENGTH},
{DOLBY_ENDDEP_PARAM_DVLO_OFFSET}, {-320} },
{FM_TX, 2, DOLBY_ENDP_EXT_SPEAKERS,
{DOLBY_PARAM_ID_DVLO}, {DOLBY_ENDDEP_PARAM_DVLO_LENGTH},
{DOLBY_ENDDEP_PARAM_DVLO_OFFSET}, {-320} },
};
/* dolby param ids to/from dsp */
static uint32_t dolby_dap_params_id[ALL_DOLBY_PARAMS] = {
DOLBY_PARAM_ID_VDHE, DOLBY_PARAM_ID_VSPE, DOLBY_PARAM_ID_DSSF,
DOLBY_PARAM_ID_DVLI, DOLBY_PARAM_ID_DVLO, DOLBY_PARAM_ID_DVLE,
DOLBY_PARAM_ID_DVMC, DOLBY_PARAM_ID_DVME, DOLBY_PARAM_ID_IENB,
DOLBY_PARAM_ID_IEBF, DOLBY_PARAM_ID_IEON, DOLBY_PARAM_ID_DEON,
DOLBY_PARAM_ID_NGON, DOLBY_PARAM_ID_GEON, DOLBY_PARAM_ID_GENB,
DOLBY_PARAM_ID_GEBF, DOLBY_PARAM_ID_AONB, DOLBY_PARAM_ID_AOBF,
DOLBY_PARAM_ID_AOBG, DOLBY_PARAM_ID_AOON, DOLBY_PARAM_ID_ARNB,
DOLBY_PARAM_ID_ARBF, DOLBY_PARAM_ID_PLB, DOLBY_PARAM_ID_PLMD,
DOLBY_PARAM_ID_DHSB, DOLBY_PARAM_ID_DHRG, DOLBY_PARAM_ID_DSSB,
DOLBY_PARAM_ID_DSSA, DOLBY_PARAM_ID_DVLA, DOLBY_PARAM_ID_IEBT,
DOLBY_PARAM_ID_IEA, DOLBY_PARAM_ID_DEA, DOLBY_PARAM_ID_DED,
DOLBY_PARAM_ID_GEBG, DOLBY_PARAM_ID_AOCC, DOLBY_PARAM_ID_ARBI,
DOLBY_PARAM_ID_ARBL, DOLBY_PARAM_ID_ARBH, DOLBY_PARAM_ID_AROD,
DOLBY_PARAM_ID_ARTP, DOLBY_PARAM_ID_VMON, DOLBY_PARAM_ID_VMB,
DOLBY_PARAM_ID_VCNB, DOLBY_PARAM_ID_VCBF, DOLBY_PARAM_ID_PREG,
DOLBY_PARAM_ID_VEN, DOLBY_PARAM_ID_PSTG, DOLBY_COMMIT_ALL_TO_DSP,
DOLBY_COMMIT_TO_DSP, DOLBY_USE_CACHE, DOLBY_AUTO_ENDP,
DOLBY_AUTO_ENDDEP_PARAMS
};
/* modifed state: 0x00000000 - Not updated
* > 0x00000000 && < 0x00010000
* Updated and not commited to DSP
* 0x00010001 - Updated and commited to DSP
* > 0x00010001 - Modified the commited value
*/
static int dolby_dap_params_modified[MAX_DOLBY_PARAMS] = { 0 };
/* param offset */
static uint32_t dolby_dap_params_offset[MAX_DOLBY_PARAMS] = {
DOLBY_PARAM_VDHE_OFFSET, DOLBY_PARAM_VSPE_OFFSET,
DOLBY_PARAM_DSSF_OFFSET, DOLBY_PARAM_DVLI_OFFSET,
DOLBY_PARAM_DVLO_OFFSET, DOLBY_PARAM_DVLE_OFFSET,
DOLBY_PARAM_DVMC_OFFSET, DOLBY_PARAM_DVME_OFFSET,
DOLBY_PARAM_IENB_OFFSET, DOLBY_PARAM_IEBF_OFFSET,
DOLBY_PARAM_IEON_OFFSET, DOLBY_PARAM_DEON_OFFSET,
DOLBY_PARAM_NGON_OFFSET, DOLBY_PARAM_GEON_OFFSET,
DOLBY_PARAM_GENB_OFFSET, DOLBY_PARAM_GEBF_OFFSET,
DOLBY_PARAM_AONB_OFFSET, DOLBY_PARAM_AOBF_OFFSET,
DOLBY_PARAM_AOBG_OFFSET, DOLBY_PARAM_AOON_OFFSET,
DOLBY_PARAM_ARNB_OFFSET, DOLBY_PARAM_ARBF_OFFSET,
DOLBY_PARAM_PLB_OFFSET, DOLBY_PARAM_PLMD_OFFSET,
DOLBY_PARAM_DHSB_OFFSET, DOLBY_PARAM_DHRG_OFFSET,
DOLBY_PARAM_DSSB_OFFSET, DOLBY_PARAM_DSSA_OFFSET,
DOLBY_PARAM_DVLA_OFFSET, DOLBY_PARAM_IEBT_OFFSET,
DOLBY_PARAM_IEA_OFFSET, DOLBY_PARAM_DEA_OFFSET,
DOLBY_PARAM_DED_OFFSET, DOLBY_PARAM_GEBG_OFFSET,
DOLBY_PARAM_AOCC_OFFSET, DOLBY_PARAM_ARBI_OFFSET,
DOLBY_PARAM_ARBL_OFFSET, DOLBY_PARAM_ARBH_OFFSET,
DOLBY_PARAM_AROD_OFFSET, DOLBY_PARAM_ARTP_OFFSET,
DOLBY_PARAM_VMON_OFFSET, DOLBY_PARAM_VMB_OFFSET,
DOLBY_PARAM_VCNB_OFFSET, DOLBY_PARAM_VCBF_OFFSET,
DOLBY_PARAM_PREG_OFFSET, DOLBY_PARAM_VEN_OFFSET,
DOLBY_PARAM_PSTG_OFFSET
};
/* param_length */
static uint32_t dolby_dap_params_length[MAX_DOLBY_PARAMS] = {
DOLBY_PARAM_VDHE_LENGTH, DOLBY_PARAM_VSPE_LENGTH,
DOLBY_PARAM_DSSF_LENGTH, DOLBY_PARAM_DVLI_LENGTH,
DOLBY_PARAM_DVLO_LENGTH, DOLBY_PARAM_DVLE_LENGTH,
DOLBY_PARAM_DVMC_LENGTH, DOLBY_PARAM_DVME_LENGTH,
DOLBY_PARAM_IENB_LENGTH, DOLBY_PARAM_IEBF_LENGTH,
DOLBY_PARAM_IEON_LENGTH, DOLBY_PARAM_DEON_LENGTH,
DOLBY_PARAM_NGON_LENGTH, DOLBY_PARAM_GEON_LENGTH,
DOLBY_PARAM_GENB_LENGTH, DOLBY_PARAM_GEBF_LENGTH,
DOLBY_PARAM_AONB_LENGTH, DOLBY_PARAM_AOBF_LENGTH,
DOLBY_PARAM_AOBG_LENGTH, DOLBY_PARAM_AOON_LENGTH,
DOLBY_PARAM_ARNB_LENGTH, DOLBY_PARAM_ARBF_LENGTH,
DOLBY_PARAM_PLB_LENGTH, DOLBY_PARAM_PLMD_LENGTH,
DOLBY_PARAM_DHSB_LENGTH, DOLBY_PARAM_DHRG_LENGTH,
DOLBY_PARAM_DSSB_LENGTH, DOLBY_PARAM_DSSA_LENGTH,
DOLBY_PARAM_DVLA_LENGTH, DOLBY_PARAM_IEBT_LENGTH,
DOLBY_PARAM_IEA_LENGTH, DOLBY_PARAM_DEA_LENGTH,
DOLBY_PARAM_DED_LENGTH, DOLBY_PARAM_GEBG_LENGTH,
DOLBY_PARAM_AOCC_LENGTH, DOLBY_PARAM_ARBI_LENGTH,
DOLBY_PARAM_ARBL_LENGTH, DOLBY_PARAM_ARBH_LENGTH,
DOLBY_PARAM_AROD_LENGTH, DOLBY_PARAM_ARTP_LENGTH,
DOLBY_PARAM_VMON_LENGTH, DOLBY_PARAM_VMB_LENGTH,
DOLBY_PARAM_VCNB_LENGTH, DOLBY_PARAM_VCBF_LENGTH,
DOLBY_PARAM_PREG_LENGTH, DOLBY_PARAM_VEN_LENGTH,
DOLBY_PARAM_PSTG_LENGTH
};
/* param_value */
static uint32_t dolby_dap_params_value[TOTAL_LENGTH_DOLBY_PARAM] = {0};
struct dolby_dap_params_get_s {
int32_t port_id;
uint32_t device_id;
uint32_t param_id;
uint32_t offset;
uint32_t length;
};
struct dolby_dap_params_states_s {
bool use_cache;
bool auto_endp;
bool enddep_params;
int port_id;
int port_open_count;
int port_ids_dolby_can_be_enabled;
int device;
};
static struct dolby_dap_params_get_s dolby_dap_params_get = {-1, DEVICE_OUT_ALL,
0, 0, 0};
static struct dolby_dap_params_states_s dolby_dap_params_states = { true, true,
true, DOLBY_INVALID_PORT_ID,
0, DEVICE_OUT_ALL, 0 };
/*
port_ids_dolby_can_be_enabled is set to 0x7FFFFFFF.
this needs to be removed after interface validation
*/
static int map_device_to_dolby_endpoint(int device)
{
int i, dolby_dap_device = DOLBY_ENDP_INT_SPEAKERS;
for (i = 0; i < NUM_DOLBY_ENDP_DEVICE; i++) {
if (dolby_dap_endp_params[i].device == device) {
dolby_dap_device = dolby_dap_endp_params[i].dap_device;
break;
}
}
/* default the endpoint to speaker if corresponding device entry */
/* not found */
if (i >= NUM_DOLBY_ENDP_DEVICE)
dolby_dap_params_states.device = SPEAKER;
return dolby_dap_device;
}
static int dolby_dap_send_end_point(int port_id)
{
int rc = 0;
char *params_value;
int *update_params_value;
uint32_t params_length = (DOLBY_PARAM_INT_ENDP_LENGTH +
DOLBY_PARAM_PAYLOAD_SIZE) * sizeof(uint32_t);
pr_debug("%s\n", __func__);
params_value = kzalloc(params_length, GFP_KERNEL);
if (!params_value) {
pr_err("%s, params memory alloc failed", __func__);
return -ENOMEM;
}
update_params_value = (int *)params_value;
*update_params_value++ = DOLBY_BUNDLE_MODULE_ID;
*update_params_value++ = DOLBY_PARAM_ID_INIT_ENDP;
*update_params_value++ = DOLBY_PARAM_INT_ENDP_LENGTH * sizeof(uint32_t);
*update_params_value++ =
map_device_to_dolby_endpoint(dolby_dap_params_states.device);
rc = adm_dolby_dap_send_params(port_id, params_value, params_length);
if (rc) {
pr_err("%s: send dolby params failed\n", __func__);
rc = -EINVAL;
}
kfree(params_value);
return rc;
}
static int dolby_dap_send_enddep_params(int port_id, int device_channels)
{
int i, j, rc = 0, idx, offset;
char *params_value;
int *update_params_value;
uint32_t params_length = (DOLBY_ENDDEP_PARAM_LENGTH +
DOLBY_NUM_ENDP_DEPENDENT_PARAMS *
DOLBY_PARAM_PAYLOAD_SIZE) *
sizeof(uint32_t);
pr_debug("%s\n", __func__);
params_value = kzalloc(params_length, GFP_KERNEL);
if (!params_value) {
pr_err("%s, params memory alloc failed", __func__);
return -ENOMEM;
}
update_params_value = (int *)params_value;
for (idx = 0; idx < NUM_DOLBY_ENDP_DEVICE; idx++) {
if (dolby_dap_endp_params[idx].device ==
dolby_dap_params_states.device) {
if (dolby_dap_params_states.device == AUX_DIGITAL) {
if (dolby_dap_endp_params[idx].device_ch_caps ==
device_channels)
break;
} else {
break;
}
}
}
if (idx >= NUM_DOLBY_ENDP_DEVICE) {
pr_err("%s: device is not set accordingly\n", __func__);
kfree(params_value);
return -EINVAL;
}
for (i = 0; i < DOLBY_ENDDEP_PARAM_LENGTH; i++) {
*update_params_value++ = DOLBY_BUNDLE_MODULE_ID;
*update_params_value++ =
dolby_dap_endp_params[idx].params_id[i];
*update_params_value++ =
dolby_dap_endp_params[idx].params_len[i] *
sizeof(uint32_t);
offset = dolby_dap_endp_params[idx].params_offset[i];
for (j = 0; j < dolby_dap_endp_params[idx].params_len[i]; j++)
*update_params_value++ =
dolby_dap_endp_params[idx].params_val[offset+j];
}
rc = adm_dolby_dap_send_params(port_id, params_value, params_length);
if (rc) {
pr_err("%s: send dolby params failed\n", __func__);
rc = -EINVAL;
}
kfree(params_value);
return rc;
}
static int dolby_dap_send_cached_params(int port_id, int commit)
{
char *params_value;
int *update_params_value, rc = 0;
uint32_t index_offset, i, j;
uint32_t params_length = (TOTAL_LENGTH_DOLBY_PARAM +
MAX_DOLBY_PARAMS * DOLBY_PARAM_PAYLOAD_SIZE) *
sizeof(uint32_t);
params_value = kzalloc(params_length, GFP_KERNEL);
if (!params_value) {
pr_err("%s, params memory alloc failed\n", __func__);
return -ENOMEM;
}
update_params_value = (int *)params_value;
params_length = 0;
for (i = 0; i < MAX_DOLBY_PARAMS; i++) {
if ((dolby_dap_params_modified[i] == 0) ||
((commit) &&
((dolby_dap_params_modified[i] & 0x00010000) &&
((dolby_dap_params_modified[i] & 0x0000FFFF) <= 1))))
continue;
*update_params_value++ = DOLBY_BUNDLE_MODULE_ID;
*update_params_value++ = dolby_dap_params_id[i];
*update_params_value++ = dolby_dap_params_length[i] *
sizeof(uint32_t);
index_offset = dolby_dap_params_offset[i];
for (j = 0; j < dolby_dap_params_length[i]; j++)
*update_params_value++ =
dolby_dap_params_value[index_offset+j];
params_length += (DOLBY_PARAM_PAYLOAD_SIZE +
dolby_dap_params_length[i]) * sizeof(uint32_t);
}
pr_debug("%s, valid param length: %d", __func__, params_length);
if (params_length) {
rc = adm_dolby_dap_send_params(port_id, params_value,
params_length);
if (rc) {
pr_err("%s: send dolby params failed\n", __func__);
kfree(params_value);
return -EINVAL;
}
for (i = 0; i < MAX_DOLBY_PARAMS; i++) {
if ((dolby_dap_params_modified[i] == 0) ||
((commit) &&
((dolby_dap_params_modified[i] & 0x00010000) &&
((dolby_dap_params_modified[i] & 0x0000FFFF) <= 1))
))
continue;
dolby_dap_params_modified[i] = 0x00010001;
}
}
kfree(params_value);
return 0;
}
int dolby_dap_init(int port_id, int channels)
{
int ret = 0;
if ((port_id != DOLBY_INVALID_PORT_ID) &&
(port_id &
dolby_dap_params_states.port_ids_dolby_can_be_enabled)) {
dolby_dap_params_states.port_id = port_id;
dolby_dap_params_states.port_open_count++;
if (dolby_dap_params_states.auto_endp) {
ret = dolby_dap_send_end_point(port_id);
if (ret) {
pr_err("%s: err sending endppoint\n", __func__);
return ret;
}
}
if (dolby_dap_params_states.use_cache) {
ret = dolby_dap_send_cached_params(port_id, 0);
if (ret) {
pr_err("%s: err sending cached params\n",
__func__);
return ret;
}
}
if (dolby_dap_params_states.enddep_params) {
dolby_dap_send_enddep_params(port_id,
channels);
if (ret) {
pr_err("%s: err sending endp dependent params\n",
__func__);
return ret;
}
}
}
return ret;
}
void dolby_dap_deinit(int port_id)
{
dolby_dap_params_states.port_open_count--;
if ((dolby_dap_params_states.port_id == port_id) &&
(!dolby_dap_params_states.port_open_count))
dolby_dap_params_states.port_id = DOLBY_INVALID_PORT_ID;
}
static int map_device_to_port_id(int device)
{
int port_id = SLIMBUS_0_RX;
device = DEVICE_OUT_ALL;
/*update the device when single stream to multiple device is handled*/
if (device == DEVICE_OUT_ALL) {
port_id = PRIMARY_I2S_RX | SLIMBUS_0_RX | HDMI_RX |
INT_BT_SCO_RX | INT_FM_RX |
RT_PROXY_PORT_001_RX |
AFE_PORT_ID_PRIMARY_PCM_RX |
MI2S_RX | SECONDARY_I2S_RX |
SLIMBUS_1_RX | SLIMBUS_4_RX | SLIMBUS_3_RX |
AFE_PORT_ID_SECONDARY_MI2S_RX;
} else {
/* update port_id based on the device */
}
return port_id;
}
int msm_routing_get_dolby_dap_param_to_set_control(
struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol) {
/* not used while setting the parameters */
return 0;
}
int msm_routing_put_dolby_dap_param_to_set_control(
struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol) {
int rc = 0;
uint32_t idx, j;
uint32_t device = ucontrol->value.integer.value[0];
uint32_t param_id = ucontrol->value.integer.value[1];
uint32_t offset = ucontrol->value.integer.value[2];
uint32_t length = ucontrol->value.integer.value[3];
int port_id = dolby_dap_params_states.port_id;
dolby_dap_params_states.port_ids_dolby_can_be_enabled =
map_device_to_port_id(device);
for (idx = 0; idx < ALL_DOLBY_PARAMS; idx++) {
/*paramid from user space*/
if (param_id == dolby_dap_params_id[idx])
break;
}
if (idx > ALL_DOLBY_PARAMS-1) {
pr_err("%s: invalid param id 0x%x to set\n", __func__,
param_id);
return -EINVAL;
}
switch (idx) {
case DOLBY_COMMIT_ALL_IDX: {
/* COMIIT ALL: Send all parameters to DSP */
pr_debug("%s: COMMIT_ALL recvd\n", __func__);
if (port_id != DOLBY_INVALID_PORT_ID)
rc = dolby_dap_send_cached_params(port_id, 0);
}
break;
case DOLBY_COMMIT_IDX: {
pr_debug("%s: COMMIT recvd\n", __func__);
/* COMMIT: Send only modified paramters to DSP */
if (port_id != DOLBY_INVALID_PORT_ID)
rc = dolby_dap_send_cached_params(port_id, 1);
}
break;
case DOLBY_USE_CACHE_IDX: {
pr_debug("%s: USE CACHE recvd val: %ld\n", __func__,
ucontrol->value.integer.value[4]);
dolby_dap_params_states.use_cache =
ucontrol->value.integer.value[4];
}
break;
case DOLBY_AUTO_ENDP_IDX: {
pr_debug("%s: AUTO_ENDP recvd val: %ld\n", __func__,
ucontrol->value.integer.value[4]);
dolby_dap_params_states.auto_endp =
ucontrol->value.integer.value[4];
}
break;
case DOLBY_AUTO_ENDDEP_IDX: {
pr_debug("%s: USE_ENDDEP_PARAMS recvd val: %ld\n",
__func__, ucontrol->value.integer.value[4]);
dolby_dap_params_states.enddep_params =
ucontrol->value.integer.value[4];
}
break;
default: {
/* cache the parameters */
dolby_dap_params_modified[idx] += 1;
dolby_dap_params_length[idx] = length;
pr_debug("%s: param recvd deviceId=0x%x paramId=0x%x offset=%d length=%d\n",
__func__, device, param_id, offset, length);
for (j = 0; j < length; j++) {
dolby_dap_params_value[
dolby_dap_params_offset[idx] +
offset + j]
= ucontrol->value.integer.value[4+j];
pr_debug("value[%d]: %ld\n", j,
ucontrol->value.integer.value[4+j]);
}
}
}
return rc;
}
int msm_routing_get_dolby_dap_param_to_get_control(
struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol) {
int rc = 0, i;
char *params_value;
int *update_params_value;
uint32_t params_length = DOLBY_MAX_LENGTH_INDIVIDUAL_PARAM *
sizeof(uint32_t);
uint32_t param_payload_len =
DOLBY_PARAM_PAYLOAD_SIZE * sizeof(uint32_t);
int port_id = dolby_dap_params_states.port_id;
if (port_id == DOLBY_INVALID_PORT_ID) {
pr_err("%s, port_id not set, returning error", __func__);
return -EINVAL;
}
params_value = kzalloc(params_length, GFP_KERNEL);
if (!params_value) {
pr_err("%s, params memory alloc failed\n", __func__);
return -ENOMEM;
}
if (DOLBY_PARAM_ID_VER == dolby_dap_params_get.param_id) {
rc = adm_dolby_dap_get_params(dolby_dap_params_get.port_id,
DOLBY_BUNDLE_MODULE_ID,
DOLBY_PARAM_ID_VER,
params_length +
param_payload_len,
params_value);
} else {
for (i = 0; i < MAX_DOLBY_PARAMS; i++)
if (dolby_dap_params_id[i] ==
dolby_dap_params_get.param_id)
break;
if (i > MAX_DOLBY_PARAMS-1) {
pr_err("%s: invalid param id to set", __func__);
rc = -EINVAL;
} else {
params_length = (dolby_dap_params_length[i] +
DOLBY_PARAM_PAYLOAD_SIZE) *
sizeof(uint32_t);
rc = adm_dolby_dap_get_params(
dolby_dap_params_get.port_id,
DOLBY_BUNDLE_MODULE_ID,
dolby_dap_params_id[i],
params_length +
param_payload_len,
params_value);
}
}
if (rc) {
pr_err("%s: get parameters failed\n", __func__);
kfree(params_value);
return -EINVAL;
}
update_params_value = (int *)params_value;
ucontrol->value.integer.value[0] = dolby_dap_params_get.device_id;
ucontrol->value.integer.value[1] = dolby_dap_params_get.param_id;
ucontrol->value.integer.value[2] = dolby_dap_params_get.offset;
ucontrol->value.integer.value[3] = dolby_dap_params_get.length;
pr_debug("%s: FROM DSP value[0] 0x%x value[1] %d value[2] 0x%x\n",
__func__, update_params_value[0],
update_params_value[1], update_params_value[2]);
for (i = 0; i < dolby_dap_params_get.length; i++) {
ucontrol->value.integer.value[DOLBY_PARAM_PAYLOAD_SIZE+i] =
update_params_value[i];
pr_debug("value[%d]:%d\n", i, update_params_value[i]);
}
pr_debug("%s: Returning param_id=0x%x offset=%d length=%d\n",
__func__, dolby_dap_params_get.param_id,
dolby_dap_params_get.offset,
dolby_dap_params_get.length);
kfree(params_value);
return 0;
}
int msm_routing_put_dolby_dap_param_to_get_control(
struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol) {
dolby_dap_params_get.device_id = ucontrol->value.integer.value[0];
dolby_dap_params_get.port_id =
(dolby_dap_params_get.device_id == DEVICE_OUT_ALL) ?
dolby_dap_params_states.port_id :
map_device_to_port_id(dolby_dap_params_get.device_id);
dolby_dap_params_get.param_id = ucontrol->value.integer.value[1];
dolby_dap_params_get.offset = ucontrol->value.integer.value[2];
dolby_dap_params_get.length = ucontrol->value.integer.value[3];
pr_debug("%s: param_id=0x%x offset=%d length=%d\n", __func__,
dolby_dap_params_get.param_id, dolby_dap_params_get.offset,
dolby_dap_params_get.length);
return 0;
}
int msm_routing_get_dolby_dap_param_visualizer_control(
struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol) {
uint32_t length = dolby_dap_params_value[DOLBY_PARAM_VCNB_OFFSET];
char *visualizer_data;
int i, rc;
int *update_visualizer_data;
uint32_t offset, params_length =
(2*length + DOLBY_VIS_PARAM_HEADER_SIZE)*sizeof(uint32_t);
uint32_t param_payload_len =
DOLBY_PARAM_PAYLOAD_SIZE * sizeof(uint32_t);
int port_id = dolby_dap_params_states.port_id;
if (port_id == DOLBY_INVALID_PORT_ID) {
pr_debug("%s, port_id not set, returning error", __func__);
ucontrol->value.integer.value[0] = 0;
return -EINVAL;
}
visualizer_data = kzalloc(params_length, GFP_KERNEL);
if (!visualizer_data) {
pr_err("%s, params memory alloc failed\n", __func__);
return -ENOMEM;
}
offset = 0;
params_length = length * sizeof(uint32_t);
rc = adm_dolby_dap_get_params(dolby_dap_params_states.port_id,
DOLBY_BUNDLE_MODULE_ID,
DOLBY_PARAM_ID_VCBG,
params_length + param_payload_len,
visualizer_data + offset);
if (rc) {
pr_err("%s: get parameters failed\n", __func__);
kfree(visualizer_data);
return -EINVAL;
}
offset = length * sizeof(uint32_t);
rc = adm_dolby_dap_get_params(dolby_dap_params_states.port_id,
DOLBY_BUNDLE_MODULE_ID,
DOLBY_PARAM_ID_VCBE,
params_length + param_payload_len,
visualizer_data + offset);
if (rc) {
pr_err("%s: get parameters failed\n", __func__);
kfree(visualizer_data);
return -EINVAL;
}
ucontrol->value.integer.value[0] = 2*length;
pr_debug("%s: visualizer data length %ld\n", __func__,
ucontrol->value.integer.value[0]);
update_visualizer_data = (int *)visualizer_data;
for (i = 0; i < 2*length; i++) {
ucontrol->value.integer.value[1+i] = update_visualizer_data[i];
pr_debug("value[%d] %d\n", i, update_visualizer_data[i]);
}
kfree(visualizer_data);
return 0;
}
int msm_routing_put_dolby_dap_param_visualizer_control(
struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol) {
/* not used while getting the visualizer data */
return 0;
}
int msm_routing_get_dolby_dap_endpoint_control(
struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol) {
/* not used while setting the endpoint */
return 0;
}
int msm_routing_put_dolby_dap_endpoint_control(
struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol) {
int device = ucontrol->value.integer.value[0];
dolby_dap_params_states.device = device;
return 0;
}