blob: 5d7cfd79ae73dc6f7da732b7648d6a089d297dfb [file] [log] [blame]
/* Copyright (c) 2009-2012, 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/module.h>
#include <linux/miscdevice.h>
#include <linux/kthread.h>
#include <linux/wait.h>
#include <linux/mutex.h>
#include <linux/io.h>
#include <linux/android_pmem.h>
#include <linux/delay.h>
#include <linux/dma-mapping.h>
#include <linux/uaccess.h>
#include <linux/msm_audio.h>
#include <linux/slab.h>
#include <linux/debugfs.h>
#include <linux/memory_alloc.h>
#include <linux/mfd/marimba.h>
#include <mach/dal.h>
#include <mach/iommu.h>
#include <mach/iommu_domains.h>
#include <mach/qdsp5v2/audio_dev_ctl.h>
#include <mach/qdsp5v2/audpp.h>
#include <mach/socinfo.h>
#include <mach/qdsp5v2/audpreproc.h>
#include <mach/qdsp5v2/qdsp5audppcmdi.h>
#include <mach/qdsp5v2/qdsp5audpreproccmdi.h>
#include <mach/qdsp5v2/qdsp5audpreprocmsg.h>
#include <mach/qdsp5v2/qdsp5audppmsg.h>
#include <mach/qdsp5v2/afe.h>
#include <mach/qdsp5v2/audio_acdbi.h>
#include <mach/qdsp5v2/acdb_commands.h>
#include <mach/qdsp5v2/audio_acdb_def.h>
#include <mach/debug_mm.h>
#include <mach/msm_memtypes.h>
/* this is the ACDB device ID */
#define DALDEVICEID_ACDB 0x02000069
#define ACDB_PORT_NAME "DAL00"
#define ACDB_CPU SMD_APPS_MODEM
#define ACDB_BUF_SIZE 4096
#define PBE_BUF_SIZE (33*1024)
#define FLUENCE_BUF_SIZE 498
#define ACDB_VALUES_NOT_FILLED 0
#define ACDB_VALUES_FILLED 1
#define MAX_RETRY 10
/*below macro is used to align the session info received from
Devctl driver with the state mentioned as not to alter the
Existing code*/
#define AUDREC_OFFSET 2
/* rpc table index */
enum {
ACDB_DalACDB_ioctl = DALDEVICE_FIRST_DEVICE_API_IDX
};
enum {
CAL_DATA_READY = 0x1,
AUDPP_READY = 0x2,
AUDREC0_READY = 0x4,
AUDREC1_READY = 0x8,
AUDREC2_READY = 0x10,
};
struct acdb_data {
void *handle;
u32 phys_addr;
u8 *virt_addr;
struct task_struct *cb_thread_task;
struct auddev_evt_audcal_info *device_info;
u32 acdb_state;
struct audpp_event_callback audpp_cb;
struct audpreproc_event_callback audpreproc_cb;
struct audpp_cmd_cfg_object_params_pcm *pp_iir;
struct audpp_cmd_cfg_cal_gain *calib_gain_rx;
struct audpp_cmd_cfg_pbe *pbe_block;
struct audpp_cmd_cfg_object_params_mbadrc *pp_mbadrc;
struct audpreproc_cmd_cfg_agc_params *preproc_agc;
struct audpreproc_cmd_cfg_iir_tuning_filter_params *preproc_iir;
struct audpreproc_cmd_cfg_cal_gain *calib_gain_tx;
struct acdb_mbadrc_block mbadrc_block;
struct audpreproc_cmd_cfg_lvnv_param preproc_lvnv;
wait_queue_head_t wait;
struct mutex acdb_mutex;
u32 device_cb_compl;
u32 audpp_cb_compl;
u32 preproc_cb_compl;
u8 preproc_stream_id;
u8 audrec_applied;
u32 multiple_sessions;
u32 cur_tx_session;
struct acdb_result acdb_result;
u16 *pbe_extbuff;
u16 *pbe_enable_flag;
u32 fluence_extbuff;
u8 *fluence_extbuff_virt;
void *map_v_fluence;
struct acdb_pbe_block *pbe_blk;
spinlock_t dsp_lock;
int dec_id;
struct audpp_cmd_cfg_object_params_eqalizer eq;
/*status to enable or disable the fluence*/
int fleuce_feature_status[MAX_AUDREC_SESSIONS];
struct audrec_session_info session_info;
/*pmem info*/
int pmem_fd;
unsigned long paddr;
unsigned long kvaddr;
unsigned long pmem_len;
struct file *file;
/* pmem for get acdb blk */
unsigned long get_blk_paddr;
u8 *get_blk_kvaddr;
void *map_v_get_blk;
char *build_id;
};
static struct acdb_data acdb_data;
struct acdb_cache_node {
u32 node_status;
s32 stream_id;
u32 phys_addr_acdb_values;
void *map_v_addr;
u8 *virt_addr_acdb_values;
struct auddev_evt_audcal_info device_info;
};
/*for RX devices acdb values are applied based on copp ID so
the depth of tx cache is MAX number of COPP supported in the system*/
struct acdb_cache_node acdb_cache_rx[MAX_COPP_NODE_SUPPORTED];
/*for TX devices acdb values are applied based on AUDREC session and
the depth of the tx cache is define by number of AUDREC sessions supported*/
struct acdb_cache_node acdb_cache_tx[MAX_AUDREC_SESSIONS];
/*Audrec session info includes Attributes Sampling frequency and enc_id */
struct audrec_session_info session_info[MAX_AUDREC_SESSIONS];
#ifdef CONFIG_DEBUG_FS
#define RTC_MAX_TIMEOUT 500 /* 500 ms */
#define PMEM_RTC_ACDB_QUERY_MEM 4096
#define EXTRACT_HIGH_WORD(x) ((x & 0xFFFF0000)>>16)
#define EXTRACT_LOW_WORD(x) (0x0000FFFF & x)
#define ACDB_RTC_TX 0xF1
#define ACDB_RTC_RX 0x1F
static u32 acdb_audpp_entry[][4] = {
{ ABID_AUDIO_RTC_VOLUME_PAN_RX,\
IID_AUDIO_RTC_VOLUME_PAN_PARAMETERS,\
AUDPP_CMD_VOLUME_PAN,\
ACDB_RTC_RX
},
{ ABID_AUDIO_IIR_RX,\
IID_AUDIO_IIR_COEFF,\
AUDPP_CMD_IIR_TUNING_FILTER,
ACDB_RTC_RX
},
{ ABID_AUDIO_RTC_EQUALIZER_PARAMETERS,\
IID_AUDIO_RTC_EQUALIZER_PARAMETERS,\
AUDPP_CMD_EQUALIZER,\
ACDB_RTC_RX
},
{ ABID_AUDIO_RTC_SPA,\
IID_AUDIO_RTC_SPA_PARAMETERS,\
AUDPP_CMD_SPECTROGRAM,
ACDB_RTC_RX
},
{ ABID_AUDIO_STF_RX,\
IID_AUDIO_IIR_COEFF,\
AUDPP_CMD_SIDECHAIN_TUNING_FILTER,\
ACDB_RTC_RX
},
{
ABID_AUDIO_MBADRC_RX,\
IID_AUDIO_RTC_MBADRC_PARAMETERS,\
AUDPP_CMD_MBADRC,\
ACDB_RTC_RX
},
{
ABID_AUDIO_AGC_TX,\
IID_AUDIO_AGC_PARAMETERS,\
AUDPREPROC_CMD_CFG_AGC_PARAMS,\
ACDB_RTC_TX
},
{
ABID_AUDIO_AGC_TX,\
IID_AUDIO_RTC_AGC_PARAMETERS,\
AUDPREPROC_CMD_CFG_AGC_PARAMS,\
ACDB_RTC_TX
},
{
ABID_AUDIO_NS_TX,\
IID_NS_PARAMETERS,\
AUDPREPROC_CMD_CFG_NS_PARAMS,\
ACDB_RTC_TX
},
{
ABID_AUDIO_IIR_TX,\
IID_AUDIO_RTC_TX_IIR_COEFF,\
AUDPREPROC_CMD_CFG_IIR_TUNING_FILTER_PARAMS,\
ACDB_RTC_TX
},
{
ABID_AUDIO_IIR_TX,\
IID_AUDIO_IIR_COEFF,\
AUDPREPROC_CMD_CFG_IIR_TUNING_FILTER_PARAMS,\
ACDB_RTC_TX
}
/*Any new entries should be added here*/
};
static struct dentry *get_set_abid_dentry;
static struct dentry *get_set_abid_data_dentry;
struct rtc_acdb_pmem {
u8 *viraddr;
int32_t phys;
void *map_v_rtc;
};
struct rtc_acdb_data {
u32 acdb_id;
u32 cmd_id;
u32 set_abid;
u32 set_iid;
u32 abid;
u32 err;
bool valid_abid;
u32 tx_rx_ctl;
struct rtc_acdb_pmem rtc_read;
struct rtc_acdb_pmem rtc_write;
wait_queue_head_t wait;
};
struct get_abid {
u32 cmd_id;
u32 acdb_id;
u32 set_abid;
u32 set_iid;
};
struct acdb_block_mbadrc_rtc {
u16 enable;
u16 num_bands;
u16 down_samp_level;
u16 adrc_delay;
u16 ext_buf_size;
u16 ext_partition;
u16 ext_buf_msw;
u16 ext_buf_lsw;
struct adrc_config adrc_band[AUDPP_MAX_MBADRC_BANDS];
signed int ExtBuff[196];
} __attribute__((packed));
enum {
ACDB_RTC_SUCCESS,
ACDB_RTC_ERR_INVALID_DEVICE,
ACDB_RTC_ERR_DEVICE_INACTIVE,
ACDB_RTC_ERR_INVALID_ABID,
ACDB_RTC_DSP_FAILURE,
ACDB_RTC_DSP_FEATURE_NOT_AVAILABLE,
ACDB_RTC_ERR_INVALID_LEN,
ACDB_RTC_ERR_UNKNOWN_FAILURE,
ACDB_RTC_PENDING_RESPONSE,
ACDB_RTC_INIT_FAILURE,
};
static struct rtc_acdb_data rtc_acdb;
static int rtc_getsetabid_dbg_open(struct inode *inode, struct file *file)
{
file->private_data = inode->i_private;
MM_INFO("GET-SET ABID Open debug intf %s\n",
(char *) file->private_data);
return 0;
}
static bool get_feature_id(u32 set_abid, u32 iid, unsigned short *feature_id)
{
bool ret_value = false;
int i = 0;
for (; i < (sizeof(acdb_audpp_entry) / sizeof(acdb_audpp_entry[0]));\
i++) {
if (acdb_audpp_entry[i][0] == set_abid &&
acdb_audpp_entry[i][1] == iid) {
*feature_id = acdb_audpp_entry[i][2];
rtc_acdb.tx_rx_ctl = acdb_audpp_entry[i][3];
ret_value = true;
break;
}
}
return ret_value;
}
static ssize_t rtc_getsetabid_dbg_write(struct file *filp,
const char __user *ubuf,
size_t cnt, loff_t *ppos)
{
struct get_abid write_abid;
unsigned short feat_id = 0;
rtc_acdb.valid_abid = false;
if (copy_from_user(&write_abid, \
(void *)ubuf, sizeof(struct get_abid))) {
MM_ERR("ACDB DATA WRITE - INVALID READ LEN\n");
rtc_acdb.err = ACDB_RTC_ERR_INVALID_LEN;
return cnt;
}
MM_INFO("SET ABID : Cmd ID: %d Device:%d ABID:%d IID : %d cnt: %d\n",\
write_abid.cmd_id, write_abid.acdb_id,
write_abid.set_abid, write_abid.set_iid, cnt);
if (write_abid.acdb_id > ACDB_ID_MAX ||
write_abid.acdb_id < ACDB_ID_HANDSET_SPKR){
rtc_acdb.err = ACDB_RTC_ERR_INVALID_DEVICE;
return cnt;
}
if (!is_dev_opened(write_abid.acdb_id)) {
rtc_acdb.err = ACDB_RTC_ERR_DEVICE_INACTIVE;
return cnt;
}
rtc_acdb.err = ACDB_RTC_ERR_INVALID_ABID;
rtc_acdb.abid = write_abid.set_abid;
if (get_feature_id(write_abid.set_abid, \
write_abid.set_iid, &feat_id)) {
rtc_acdb.err = ACDB_RTC_SUCCESS;
rtc_acdb.cmd_id = write_abid.cmd_id;
rtc_acdb.acdb_id = write_abid.acdb_id;
rtc_acdb.set_abid = feat_id;
rtc_acdb.valid_abid = true;
rtc_acdb.set_iid = write_abid.set_iid;
}
return cnt;
}
static ssize_t rtc_getsetabid_dbg_read(struct file *file, char __user *buf,
size_t count, loff_t *ppos)
{
static char buffer[1024];
int n = 0;
u32 msg = rtc_acdb.err;
memcpy(buffer, &rtc_acdb.cmd_id, sizeof(struct get_abid));
memcpy(buffer+16, &msg, 4);
n = 20;
MM_INFO("SET ABID : Cmd ID: %x Device:%x ABID:%x IID : %x Err: %d\n",\
rtc_acdb.cmd_id, rtc_acdb.acdb_id, rtc_acdb.set_abid,\
rtc_acdb.set_iid, rtc_acdb.err);
return simple_read_from_buffer(buf, count, ppos, buffer, n);
}
static int rtc_getsetabid_data_dbg_open(struct inode *inode, struct file *file)
{
file->private_data = inode->i_private;
MM_INFO("GET-SET ABID DATA Open debug intf %s\n",
(char *) file->private_data);
return 0;
}
void acdb_rtc_set_err(u32 ErrCode)
{
if (rtc_acdb.err == ACDB_RTC_PENDING_RESPONSE) {
if (ErrCode == 0xFFFF) {
rtc_acdb.err = ACDB_RTC_SUCCESS;
MM_INFO("RTC READ SUCCESS---\n");
} else if (ErrCode == 0) {
rtc_acdb.err = ACDB_RTC_DSP_FAILURE;
MM_INFO("RTC READ FAIL---\n");
} else if (ErrCode == 1) {
rtc_acdb.err = ACDB_RTC_DSP_FEATURE_NOT_AVAILABLE;
MM_INFO("RTC READ FEAT UNAVAILABLE---\n");
} else {
rtc_acdb.err = ACDB_RTC_DSP_FAILURE;
MM_ERR("RTC Err CODE---\n");
}
} else {
rtc_acdb.err = ACDB_RTC_DSP_FAILURE;
MM_ERR("RTC Err code Invalid State\n");
}
wake_up(&rtc_acdb.wait);
}
static ssize_t rtc_getsetabid_data_dbg_read(struct file *file,
char __user *buf, size_t count,
loff_t *ppos)
{
static char buffer[PMEM_RTC_ACDB_QUERY_MEM];
int rc, n = 0;
int counter = 0;
struct rtc_acdb_pmem *rtc_read = &rtc_acdb.rtc_read;
memset(&buffer, 0, PMEM_RTC_ACDB_QUERY_MEM);
if (rtc_acdb.valid_abid != true) {
MM_ERR("ACDB DATA READ ---INVALID ABID\n");
n = 0;
rtc_acdb.err = ACDB_RTC_ERR_INVALID_ABID;
} else {
if (PMEM_RTC_ACDB_QUERY_MEM < count) {
MM_ERR("ACDB DATA READ ---\
INVALID READ LEN %x\n", count);
n = 0;
rtc_acdb.err = ACDB_RTC_ERR_INVALID_LEN;
} else {
rtc_acdb.err = ACDB_RTC_PENDING_RESPONSE;
if (rtc_read->viraddr != NULL) {
memset(rtc_read->viraddr,
0, PMEM_RTC_ACDB_QUERY_MEM);
}
if (rtc_acdb.tx_rx_ctl == ACDB_RTC_RX) {
struct rtc_audpp_read_data rtc_read_cmd;
rtc_read_cmd.cmd_id =
AUDPP_CMD_PP_FEAT_QUERY_PARAMS;
rtc_read_cmd.obj_id =
AUDPP_CMD_COPP_STREAM;
rtc_read_cmd.route_id =
acdb_data.device_info->dev_id;
rtc_read_cmd.feature_id = rtc_acdb.set_abid;
rtc_read_cmd.extbufsizemsw =
EXTRACT_HIGH_WORD(\
PMEM_RTC_ACDB_QUERY_MEM);
rtc_read_cmd.extbufsizelsw =
EXTRACT_LOW_WORD(\
PMEM_RTC_ACDB_QUERY_MEM);
rtc_read_cmd.extpart = 0x0000;
rtc_read_cmd.extbufstartmsw =
EXTRACT_HIGH_WORD(rtc_read->phys);
rtc_read_cmd.extbufstartlsw =
EXTRACT_LOW_WORD(rtc_read->phys);
rc = audpp_send_queue2(&rtc_read_cmd,
sizeof(rtc_read_cmd));
MM_INFO("ACDB READ Command RC --->%x\
Route ID=%x\n", rc,\
acdb_data.device_info->dev_id);
} else if (rtc_acdb.tx_rx_ctl == ACDB_RTC_TX) {
struct rtc_audpreproc_read_data rtc_audpreproc;
rtc_audpreproc.cmd_id =
AUDPREPROC_CMD_FEAT_QUERY_PARAMS;
rtc_audpreproc.stream_id =
acdb_data.preproc_stream_id;
rtc_audpreproc.feature_id = rtc_acdb.set_abid;
rtc_audpreproc.extbufsizemsw =
EXTRACT_HIGH_WORD(\
PMEM_RTC_ACDB_QUERY_MEM);
rtc_audpreproc.extbufsizelsw =
EXTRACT_LOW_WORD(\
PMEM_RTC_ACDB_QUERY_MEM);
rtc_audpreproc.extpart = 0x0000;
rtc_audpreproc.extbufstartmsw =
EXTRACT_HIGH_WORD(rtc_read->phys);
rtc_audpreproc.extbufstartlsw =
EXTRACT_LOW_WORD(rtc_read->phys);
rc = audpreproc_send_preproccmdqueue(
&rtc_audpreproc,\
sizeof(rtc_audpreproc));
MM_INFO("ACDB READ Command RC --->%x,\
stream_id %x\n", rc,\
acdb_data.preproc_stream_id);
}
rc = wait_event_timeout(rtc_acdb.wait,
(rtc_acdb.err !=
ACDB_RTC_PENDING_RESPONSE),
msecs_to_jiffies(RTC_MAX_TIMEOUT));
MM_INFO("ACDB READ ACK Count = %x Err = %x\n",
count, rtc_acdb.err);
{
if (rtc_acdb.err == ACDB_RTC_SUCCESS
&& rtc_read->viraddr != NULL) {
memcpy(buffer, rtc_read->viraddr, count);
n = count;
while (counter < count) {
MM_DBG("%x", \
rtc_read->viraddr[counter]);
counter++;
}
}
}
}
}
return simple_read_from_buffer(buf, count, ppos, buffer, n);
}
static bool acdb_set_tx_rtc(const char *ubuf, size_t writecount)
{
struct audpreproc_cmd_cfg_iir_tuning_filter_params *preproc_iir;
struct audpreproc_cmd_cfg_agc_params *preproc_agc;
struct audpreproc_cmd_cfg_ns_params *preproc_ns;
s32 result = 0;
bool retval = false;
unsigned short iircmdsize =
sizeof(struct audpreproc_cmd_cfg_iir_tuning_filter_params);
unsigned short iircmdid = AUDPREPROC_CMD_CFG_IIR_TUNING_FILTER_PARAMS;
rtc_acdb.err = ACDB_RTC_ERR_UNKNOWN_FAILURE;
switch (rtc_acdb.set_abid) {
case AUDPREPROC_CMD_CFG_AGC_PARAMS:
case AUDPREPROC_CMD_CFG_AGC_PARAMS_2:
{
preproc_agc = kmalloc(sizeof(\
struct audpreproc_cmd_cfg_agc_params),\
GFP_KERNEL);
if ((sizeof(struct audpreproc_cmd_cfg_agc_params) -\
(2*sizeof(unsigned short)))
< writecount) {
MM_ERR("ACDB DATA WRITE --\
AGC TX writecount > DSP struct\n");
} else {
if (preproc_agc != NULL) {
char *base; unsigned short offset;
unsigned short *offset_addr;
base = (char *)preproc_agc;
offset = offsetof(struct \
audpreproc_cmd_cfg_agc_params,\
tx_agc_param_mask);
offset_addr = (unsigned short *)(base + offset);
if ((copy_from_user(offset_addr,\
(void *)ubuf, writecount)) == 0x00) {
preproc_agc->cmd_id =
AUDPREPROC_CMD_CFG_AGC_PARAMS;
preproc_agc->stream_id =
acdb_data.preproc_stream_id;
result = audpreproc_dsp_set_agc(
preproc_agc,
sizeof(struct \
audpreproc_cmd_cfg_agc_params));
if (result) {
MM_ERR("ACDB=> Failed to \
send AGC data to \
preproc)\n");
} else {
retval = true;
}
} else {
MM_ERR("ACDB DATA WRITE ---\
GC Tx copy_from_user Fail\n");
}
} else {
MM_ERR("ACDB DATA WRITE --\
AGC TX kalloc Failed LEN\n");
}
}
if (preproc_agc != NULL)
kfree(preproc_agc);
break;
}
case AUDPREPROC_CMD_CFG_NS_PARAMS:
{
preproc_ns = kmalloc(sizeof(struct \
audpreproc_cmd_cfg_ns_params),\
GFP_KERNEL);
if ((sizeof(struct audpreproc_cmd_cfg_ns_params) -\
(2 * sizeof(unsigned short)))
< writecount) {
MM_ERR("ACDB DATA WRITE --\
NS TX writecount > DSP struct\n");
} else {
if (preproc_ns != NULL) {
char *base; unsigned short offset;
unsigned short *offset_addr;
base = (char *)preproc_ns;
offset = offsetof(struct \
audpreproc_cmd_cfg_ns_params,\
ec_mode_new);
offset_addr = (unsigned short *)(base + offset);
if ((copy_from_user(offset_addr,\
(void *)ubuf, writecount)) == 0x00) {
preproc_ns->cmd_id =
AUDPREPROC_CMD_CFG_NS_PARAMS;
preproc_ns->stream_id =
acdb_data.preproc_stream_id;
result = audpreproc_dsp_set_ns(
preproc_ns,
sizeof(struct \
audpreproc_cmd_cfg_ns_params));
if (result) {
MM_ERR("ACDB=> Failed to send \
NS data to preproc\n");
} else {
retval = true;
}
} else {
MM_ERR("ACDB DATA WRITE ---NS Tx \
copy_from_user Fail\n");
}
} else {
MM_ERR("ACDB DATA WRITE --NS TX\
kalloc Failed LEN\n");
}
}
if (preproc_ns != NULL)
kfree(preproc_ns);
break;
}
case AUDPREPROC_CMD_CFG_IIR_TUNING_FILTER_PARAMS:
{
preproc_iir = kmalloc(sizeof(struct \
audpreproc_cmd_cfg_iir_tuning_filter_params),\
GFP_KERNEL);
if ((sizeof(struct \
audpreproc_cmd_cfg_iir_tuning_filter_params)-\
(2 * sizeof(unsigned short)))
< writecount) {
MM_ERR("ACDB DATA WRITE --IIR TX writecount\
> DSP struct\n");
} else {
if (preproc_iir != NULL) {
char *base; unsigned short offset;
unsigned short *offset_addr;
base = (char *)preproc_iir;
offset = offsetof(struct \
audpreproc_cmd_cfg_iir_tuning_filter_params,\
active_flag);
offset_addr = (unsigned short *)(base + \
offset);
if ((copy_from_user(offset_addr,\
(void *)ubuf, writecount)) == 0x00) {
preproc_iir->cmd_id = iircmdid;
preproc_iir->stream_id =
acdb_data.preproc_stream_id;
result = audpreproc_dsp_set_iir(\
preproc_iir,
iircmdsize);
if (result) {
MM_ERR("ACDB=> Failed to send\
IIR data to preproc\n");
} else {
retval = true;
}
} else {
MM_ERR("ACDB DATA WRITE ---IIR Tx \
copy_from_user Fail\n");
}
} else {
MM_ERR("ACDB DATA WRITE --IIR TX kalloc \
Failed LEN\n");
}
}
if (preproc_iir != NULL)
kfree(preproc_iir);
break;
}
}
return retval;
}
static bool acdb_set_rx_rtc(const char *ubuf, size_t writecount)
{
struct audpp_cmd_cfg_object_params_volpan *volpan_config;
struct audpp_cmd_cfg_object_params_mbadrc *mbadrc_config;
struct acdb_block_mbadrc_rtc *acdb_mbadrc_rtc;
struct audpp_cmd_cfg_object_params_sidechain *stf_config;
struct audpp_cmd_cfg_object_params_spectram *spa_config;
struct audpp_cmd_cfg_object_params_eqalizer *eq_config;
struct audpp_cmd_cfg_object_params_pcm *iir_config;
unsigned short temp_spa[34];
struct rtc_acdb_pmem *rtc_write = &rtc_acdb.rtc_write;
s32 result = 0;
bool retval = false;
switch (rtc_acdb.set_abid) {
case AUDPP_CMD_VOLUME_PAN:
{
volpan_config = kmalloc(sizeof(struct \
audpp_cmd_cfg_object_params_volpan),\
GFP_KERNEL);
if ((sizeof(struct audpp_cmd_cfg_object_params_volpan) -\
sizeof(struct audpp_cmd_cfg_object_params_common))
< writecount) {
MM_ERR("ACDB DATA WRITE --\
VolPan writecount > DSP struct\n");
} else {
if (volpan_config != NULL) {
char *base; unsigned short offset;
unsigned short *offset_addr;
base = (char *)volpan_config;
offset = offsetof(struct \
audpp_cmd_cfg_object_params_volpan,\
volume);
offset_addr = (unsigned short *)(base+offset);
if ((copy_from_user(offset_addr,\
(void *)ubuf, writecount)) == 0x00) {
MM_ERR("ACDB RX WRITE DATA:\
AUDPP_CMD_VOLUME_PAN\n");
result = audpp_set_volume_and_pan(
acdb_data.device_info->dev_id,\
volpan_config->volume,
volpan_config->pan,
COPP);
if (result) {
MM_ERR("ACDB=> Failed to \
send VOLPAN data to"
" postproc\n");
} else {
retval = true;
}
} else {
MM_ERR("ACDB DATA WRITE ---\
copy_from_user Fail\n");
}
} else {
MM_ERR("ACDB DATA WRITE --\
Vol Pan kalloc Failed LEN\n");
}
}
if (volpan_config != NULL)
kfree(volpan_config);
break;
}
case AUDPP_CMD_IIR_TUNING_FILTER:
{
iir_config = kmalloc(sizeof(struct \
audpp_cmd_cfg_object_params_pcm),\
GFP_KERNEL);
if ((sizeof(struct audpp_cmd_cfg_object_params_pcm) -\
sizeof(struct audpp_cmd_cfg_object_params_common))
< writecount) {
MM_ERR("ACDB DATA WRITE --\
IIR RX writecount > DSP struct\n");
} else {
if (iir_config != NULL) {
char *base; unsigned short offset;
unsigned short *offset_addr;
base = (char *)iir_config;
offset = offsetof(struct \
audpp_cmd_cfg_object_params_pcm,\
active_flag);
offset_addr = (unsigned short *)(base+offset);
if ((copy_from_user(offset_addr,\
(void *)ubuf, writecount)) == 0x00) {
iir_config->common.cmd_id =
AUDPP_CMD_CFG_OBJECT_PARAMS;
iir_config->common.stream =
AUDPP_CMD_COPP_STREAM;
iir_config->common.stream_id = 0;
iir_config->common.obj_cfg =
AUDPP_CMD_OBJ0_UPDATE;
iir_config->common.command_type = 0;
MM_ERR("ACDB RX WRITE DATA:\
AUDPP_CMD_IIR_TUNING_FILTER\n");
result = audpp_dsp_set_rx_iir(
acdb_data.device_info->dev_id,
iir_config->active_flag,\
iir_config, COPP);
if (result) {
MM_ERR("ACDB=> Failed to send\
IIR data to\
postproc\n");
} else {
retval = true;
}
} else {
MM_ERR("ACDB DATA WRITE ---\
IIR Rx copy_from_user Fail\n");
}
} else {
MM_ERR("ACDB DATA WRITE --\
acdb_iir_block kalloc Failed LEN\n");
}
}
if (iir_config != NULL)
kfree(iir_config);
break;
}
case AUDPP_CMD_EQUALIZER:
{
eq_config = kmalloc(sizeof(struct \
audpp_cmd_cfg_object_params_eqalizer),\
GFP_KERNEL);
if ((sizeof(struct audpp_cmd_cfg_object_params_eqalizer) -\
sizeof(struct audpp_cmd_cfg_object_params_common))
< writecount) {
MM_ERR("ACDB DATA WRITE --\
EQ RX writecount > DSP struct\n");
} else {
if (eq_config != NULL) {
char *base; unsigned short offset;
unsigned short *offset_addr;
base = (char *)eq_config;
offset = offsetof(struct \
audpp_cmd_cfg_object_params_eqalizer,\
eq_flag);
offset_addr = (unsigned short *)(base+offset);
if ((copy_from_user(offset_addr,\
(void *)ubuf, writecount)) == 0x00) {
eq_config->common.cmd_id =
AUDPP_CMD_CFG_OBJECT_PARAMS;
eq_config->common.stream =
AUDPP_CMD_COPP_STREAM;
eq_config->common.stream_id = 0;
eq_config->common.obj_cfg =
AUDPP_CMD_OBJ0_UPDATE;
eq_config->common.command_type = 0;
MM_ERR("ACDB RX WRITE\
DATA:AUDPP_CMD_EQUALIZER\n");
result = audpp_dsp_set_eq(
acdb_data.device_info->dev_id,
eq_config->eq_flag,\
eq_config,
COPP);
if (result) {
MM_ERR("ACDB=> Failed to \
send EQ data to postproc\n");
} else {
retval = true;
}
} else {
MM_ERR("ACDB DATA WRITE ---\
EQ Rx copy_from_user Fail\n");
}
} else {
MM_ERR("ACDB DATA WRITE --\
EQ kalloc Failed LEN\n");
}
}
if (eq_config != NULL)
kfree(eq_config);
break;
}
case AUDPP_CMD_SPECTROGRAM:
{
spa_config = kmalloc(sizeof(struct \
audpp_cmd_cfg_object_params_spectram),\
GFP_KERNEL);
if ((sizeof(struct audpp_cmd_cfg_object_params_spectram)-\
sizeof(struct \
audpp_cmd_cfg_object_params_common))
< (2 * sizeof(unsigned short))) {
MM_ERR("ACDB DATA WRITE --SPA \
RX writecount > DSP struct\n");
} else {
if (spa_config != NULL) {
if ((copy_from_user(&temp_spa[0],\
(void *)ubuf,
(34 * sizeof(unsigned short))))
== 0x00) {
spa_config->common.cmd_id =
AUDPP_CMD_CFG_OBJECT_PARAMS;
spa_config->common.stream =
AUDPP_CMD_COPP_STREAM;
spa_config->common.stream_id = 0;
spa_config->common.obj_cfg =
AUDPP_CMD_OBJ0_UPDATE;
spa_config->common.command_type = 0;
spa_config->sample_interval =
temp_spa[0];
spa_config->num_coeff = temp_spa[1];
MM_ERR("ACDB RX WRITE DATA:\
AUDPP_CMD_SPECTROGRAM\n");
result = audpp_dsp_set_spa(
acdb_data.device_info->dev_id,\
spa_config, COPP);
if (result) {
MM_ERR("ACDB=> Failed to \
send SPA data \
to postproc\n");
} else {
retval = true;
}
} else {
MM_ERR("ACDB DATA WRITE \
---SPA Rx copy_from_user\
Fail\n");
}
} else {
MM_ERR("ACDB DATA WRITE --\
SPA kalloc Failed LEN\n");
}
}
if (spa_config != NULL)
kfree(spa_config);
break;
}
case AUDPP_CMD_MBADRC:
{
acdb_mbadrc_rtc = kmalloc(sizeof(struct \
acdb_block_mbadrc_rtc),\
GFP_KERNEL);
mbadrc_config = kmalloc(sizeof(struct \
audpp_cmd_cfg_object_params_mbadrc),\
GFP_KERNEL);
if (mbadrc_config != NULL && acdb_mbadrc_rtc != NULL) {
if ((copy_from_user(acdb_mbadrc_rtc,\
(void *)ubuf,
sizeof(struct acdb_block_mbadrc_rtc)))
== 0x00) {
mbadrc_config->common.cmd_id =
AUDPP_CMD_CFG_OBJECT_PARAMS;
mbadrc_config->common.stream =
AUDPP_CMD_COPP_STREAM;
mbadrc_config->common.stream_id = 0;
mbadrc_config->common.obj_cfg =
AUDPP_CMD_OBJ0_UPDATE;
mbadrc_config->common.command_type = 0;
mbadrc_config->enable =
acdb_mbadrc_rtc->enable;
mbadrc_config->num_bands =
acdb_mbadrc_rtc->num_bands;
mbadrc_config->down_samp_level =
acdb_mbadrc_rtc->down_samp_level;
mbadrc_config->adrc_delay =
acdb_mbadrc_rtc->adrc_delay;
memcpy(mbadrc_config->adrc_band,\
acdb_mbadrc_rtc->adrc_band,\
AUDPP_MAX_MBADRC_BANDS *\
sizeof(struct adrc_config));
if (mbadrc_config->num_bands > 1) {
mbadrc_config->ext_buf_size =
(97 * 2) + (33 * 2 * \
(mbadrc_config->num_bands - 2));
}
mbadrc_config->ext_partition = 0;
mbadrc_config->ext_buf_lsw =
(u16) EXTRACT_LOW_WORD(\
rtc_write->phys);
mbadrc_config->ext_buf_msw =
(u16) EXTRACT_HIGH_WORD(\
rtc_write->phys);
memcpy(rtc_write->viraddr,
acdb_mbadrc_rtc->ExtBuff,
(196*sizeof(signed int)));
result = audpp_dsp_set_mbadrc(
acdb_data.device_info->dev_id,
mbadrc_config->enable,
mbadrc_config, COPP);
if (result) {
MM_ERR("ACDB=> Failed to \
Send MBADRC data \
to postproc\n");
} else {
retval = true;
}
} else {
MM_ERR("ACDB DATA WRITE ---\
MBADRC Rx copy_from_user Fail\n");
}
} else {
MM_ERR("ACDB DATA WRITE --MBADRC kalloc Failed LEN\n");
}
if (mbadrc_config != NULL)
kfree(mbadrc_config);
if (acdb_mbadrc_rtc != NULL)
kfree(acdb_mbadrc_rtc);
break;
}
case AUDPP_CMD_SIDECHAIN_TUNING_FILTER:
{
stf_config = kmalloc(sizeof(struct \
audpp_cmd_cfg_object_params_sidechain),\
GFP_KERNEL);
if ((sizeof(struct audpp_cmd_cfg_object_params_sidechain) -\
sizeof(struct audpp_cmd_cfg_object_params_common))
< writecount) {
MM_ERR("ACDB DATA WRITE --\
STF RX writecount > DSP struct\n");
} else {
if (stf_config != NULL) {
char *base; unsigned short offset;
unsigned short *offset_addr;
base = (char *)stf_config;
offset = offsetof(struct \
audpp_cmd_cfg_object_params_sidechain,\
active_flag);
offset_addr = (unsigned short *)(base+offset);
if ((copy_from_user(offset_addr,\
(void *)ubuf, writecount)) == 0x00) {
stf_config->common.cmd_id =
AUDPP_CMD_CFG_OBJECT_PARAMS;
stf_config->common.stream =
AUDPP_CMD_COPP_STREAM;
stf_config->common.stream_id = 0;
stf_config->common.obj_cfg =
AUDPP_CMD_OBJ0_UPDATE;
stf_config->common.command_type = 0;
MM_ERR("ACDB RX WRITE DATA:\
AUDPP_CMD_SIDECHAIN_TUNING_FILTER\n");
result = audpp_dsp_set_stf(
acdb_data.device_info->dev_id,\
stf_config->active_flag,\
stf_config, COPP);
if (result) {
MM_ERR("ACDB=> Failed to send \
STF data to postproc\n");
} else {
retval = true;
}
} else {
MM_ERR("ACDB DATA WRITE ---\
STF Rx copy_from_user Fail\n");
}
} else {
MM_ERR("ACDB DATA WRITE \
STF kalloc Failed LEN\n");
}
}
if (stf_config != NULL)
kfree(stf_config);
break;
}
}
return retval;
}
static ssize_t rtc_getsetabid_data_dbg_write(struct file *filp,
const char __user *ubuf,
size_t cnt, loff_t *ppos)
{
if (rtc_acdb.valid_abid != true) {
MM_INFO("ACDB DATA READ ---INVALID ABID\n");
rtc_acdb.err = ACDB_RTC_ERR_INVALID_ABID;
} else {
if (rtc_acdb.tx_rx_ctl == ACDB_RTC_RX) {
if (acdb_set_rx_rtc(ubuf, cnt)) {
rtc_acdb.err = ACDB_RTC_SUCCESS;
} else {
rtc_acdb.err = ACDB_RTC_ERR_UNKNOWN_FAILURE;
cnt = 0;
}
} else if (rtc_acdb.tx_rx_ctl == ACDB_RTC_TX) {
if (acdb_set_tx_rtc(ubuf, cnt)) {
rtc_acdb.err = ACDB_RTC_SUCCESS;
} else {
rtc_acdb.err = ACDB_RTC_ERR_UNKNOWN_FAILURE;
cnt = 0;
}
}
}
return cnt;
}
static const struct file_operations rtc_acdb_data_debug_fops = {
.open = rtc_getsetabid_data_dbg_open,
.write = rtc_getsetabid_data_dbg_write,
.read = rtc_getsetabid_data_dbg_read
};
static const struct file_operations rtc_acdb_debug_fops = {
.open = rtc_getsetabid_dbg_open,
.write = rtc_getsetabid_dbg_write,
.read = rtc_getsetabid_dbg_read
};
static void rtc_acdb_deinit(void)
{
struct rtc_acdb_pmem *rtc_read = &rtc_acdb.rtc_read;
struct rtc_acdb_pmem *rtc_write = &rtc_acdb.rtc_write;
if (get_set_abid_dentry) {
MM_DBG("GetSet ABID remove debugfs\n");
debugfs_remove(get_set_abid_dentry);
}
if (get_set_abid_data_dentry) {
MM_DBG("GetSet ABID remove debugfs\n");
debugfs_remove(get_set_abid_data_dentry);
}
rtc_acdb.abid = 0;
rtc_acdb.acdb_id = 0;
rtc_acdb.cmd_id = 0;
rtc_acdb.err = 1;
rtc_acdb.set_abid = 0;
rtc_acdb.set_iid = 0;
rtc_acdb.tx_rx_ctl = 0;
rtc_acdb.valid_abid = false;
if (rtc_read->viraddr != NULL || ((void *)rtc_read->phys) != NULL) {
iounmap(rtc_read->map_v_rtc);
free_contiguous_memory_by_paddr(rtc_read->phys);
}
if (rtc_write->viraddr != NULL || ((void *)rtc_write->phys) != NULL) {
iounmap(rtc_write->map_v_rtc);
free_contiguous_memory_by_paddr(rtc_write->phys);
}
}
static bool rtc_acdb_init(void)
{
struct rtc_acdb_pmem *rtc_read = &rtc_acdb.rtc_read;
struct rtc_acdb_pmem *rtc_write = &rtc_acdb.rtc_write;
s32 result = 0;
char name[sizeof "get_set_abid"+1];
char name1[sizeof "get_set_abid_data"+1];
rtc_acdb.abid = 0;
rtc_acdb.acdb_id = 0;
rtc_acdb.cmd_id = 0;
rtc_acdb.err = 1;
rtc_acdb.set_abid = 0;
rtc_acdb.set_iid = 0;
rtc_acdb.valid_abid = false;
rtc_acdb.tx_rx_ctl = 0;
if (acdb_data.build_id[17] == '1') {
snprintf(name, sizeof name, "get_set_abid");
get_set_abid_dentry = debugfs_create_file(name,
S_IFREG | S_IRUGO | S_IWUGO,
NULL, NULL, &rtc_acdb_debug_fops);
if (IS_ERR(get_set_abid_dentry)) {
MM_ERR("SET GET ABID debugfs_create_file failed\n");
return false;
}
snprintf(name1, sizeof name1, "get_set_abid_data");
get_set_abid_data_dentry = debugfs_create_file(name1,
S_IFREG | S_IRUGO | S_IWUGO,
NULL, NULL,
&rtc_acdb_data_debug_fops);
if (IS_ERR(get_set_abid_data_dentry)) {
MM_ERR("SET GET ABID DATA"
" debugfs_create_file failed\n");
return false;
}
}
rtc_read->phys = allocate_contiguous_ebi_nomap(PMEM_RTC_ACDB_QUERY_MEM,
SZ_4K);
if (!rtc_read->phys) {
MM_ERR("ACDB Cannot allocate physical memory\n");
result = -ENOMEM;
goto error;
}
rtc_read->map_v_rtc = ioremap(rtc_read->phys,
PMEM_RTC_ACDB_QUERY_MEM);
if (IS_ERR(rtc_read->map_v_rtc)) {
MM_ERR("ACDB Could not map physical address\n");
result = -ENOMEM;
goto error;
}
rtc_read->viraddr = rtc_read->map_v_rtc;
memset(rtc_read->viraddr, 0, PMEM_RTC_ACDB_QUERY_MEM);
rtc_write->phys = allocate_contiguous_ebi_nomap(PMEM_RTC_ACDB_QUERY_MEM,
SZ_4K);
if (!rtc_write->phys) {
MM_ERR("ACDB Cannot allocate physical memory\n");
result = -ENOMEM;
goto error;
}
rtc_write->map_v_rtc = ioremap(rtc_write->phys,
PMEM_RTC_ACDB_QUERY_MEM);
if (IS_ERR(rtc_write->map_v_rtc)) {
MM_ERR("ACDB Could not map physical address\n");
result = -ENOMEM;
goto error;
}
rtc_write->viraddr = rtc_write->map_v_rtc;
memset(rtc_write->viraddr, 0, PMEM_RTC_ACDB_QUERY_MEM);
init_waitqueue_head(&rtc_acdb.wait);
return true;
error:
MM_DBG("INIT RTC FAILED REMOVING RTC DEBUG FS\n");
if (get_set_abid_dentry) {
MM_DBG("GetSet ABID remove debugfs\n");
debugfs_remove(get_set_abid_dentry);
}
if (get_set_abid_data_dentry) {
MM_DBG("GetSet ABID remove debugfs\n");
debugfs_remove(get_set_abid_data_dentry);
}
if (rtc_read->viraddr != NULL || ((void *)rtc_read->phys) != NULL) {
iounmap(rtc_read->map_v_rtc);
free_contiguous_memory_by_paddr(rtc_read->phys);
}
if (rtc_write->viraddr != NULL || ((void *)rtc_write->phys) != NULL) {
iounmap(rtc_write->map_v_rtc);
free_contiguous_memory_by_paddr(rtc_write->phys);
}
return false;
}
#endif /*CONFIG_DEBUG_FS*/
static s32 acdb_set_calibration_blk(unsigned long arg)
{
struct acdb_cmd_device acdb_cmd;
s32 result = 0;
MM_DBG("acdb_set_calibration_blk\n");
if (copy_from_user(&acdb_cmd, (struct acdb_cmd_device *)arg,
sizeof(acdb_cmd))) {
MM_ERR("Failed copy command struct from user in"
"acdb_set_calibration_blk\n");
return -EFAULT;
}
acdb_cmd.phys_buf = (u32 *)acdb_data.paddr;
MM_DBG("acdb_cmd.phys_buf %x\n", (u32)acdb_cmd.phys_buf);
result = dalrpc_fcn_8(ACDB_DalACDB_ioctl, acdb_data.handle,
(const void *)&acdb_cmd, sizeof(acdb_cmd),
&acdb_data.acdb_result,
sizeof(acdb_data.acdb_result));
if (result < 0) {
MM_ERR("ACDB=> Device Set RPC failure"
" result = %d\n", result);
return -EINVAL;
} else {
MM_ERR("ACDB=> Device Set RPC success\n");
if (acdb_data.acdb_result.result == ACDB_RES_SUCCESS)
MM_DBG("ACDB_SET_DEVICE Success\n");
else if (acdb_data.acdb_result.result == ACDB_RES_FAILURE)
MM_ERR("ACDB_SET_DEVICE Failure\n");
else if (acdb_data.acdb_result.result == ACDB_RES_BADPARM)
MM_ERR("ACDB_SET_DEVICE BadParams\n");
else
MM_ERR("Unknown error\n");
}
return result;
}
static s32 acdb_get_calibration_blk(unsigned long arg)
{
s32 result = 0;
struct acdb_cmd_device acdb_cmd;
MM_DBG("acdb_get_calibration_blk\n");
if (copy_from_user(&acdb_cmd, (struct acdb_cmd_device *)arg,
sizeof(acdb_cmd))) {
MM_ERR("Failed copy command struct from user in"
"acdb_get_calibration_blk\n");
return -EFAULT;
}
acdb_cmd.phys_buf = (u32 *)acdb_data.paddr;
MM_ERR("acdb_cmd.phys_buf %x\n", (u32)acdb_cmd.phys_buf);
result = dalrpc_fcn_8(ACDB_DalACDB_ioctl, acdb_data.handle,
(const void *)&acdb_cmd, sizeof(acdb_cmd),
&acdb_data.acdb_result,
sizeof(acdb_data.acdb_result));
if (result < 0) {
MM_ERR("ACDB=> Device Get RPC failure"
" result = %d\n", result);
return -EINVAL;
} else {
MM_ERR("ACDB=> Device Get RPC Success\n");
if (acdb_data.acdb_result.result == ACDB_RES_SUCCESS)
MM_DBG("ACDB_GET_DEVICE Success\n");
else if (acdb_data.acdb_result.result == ACDB_RES_FAILURE)
MM_ERR("ACDB_GET_DEVICE Failure\n");
else if (acdb_data.acdb_result.result == ACDB_RES_BADPARM)
MM_ERR("ACDB_GET_DEVICE BadParams\n");
else
MM_ERR("Unknown error\n");
}
return result;
}
static int audio_acdb_open(struct inode *inode, struct file *file)
{
MM_DBG("%s\n", __func__);
return 0;
}
static int audio_acdb_release(struct inode *inode, struct file *file)
{
MM_DBG("%s\n", __func__);
return 0;
}
static long audio_acdb_ioctl(struct file *file, unsigned int cmd,
unsigned long arg)
{
int rc = 0;
unsigned long flags = 0;
struct msm_audio_pmem_info info;
MM_DBG("%s\n", __func__);
switch (cmd) {
case AUDIO_SET_EQ:
MM_DBG("IOCTL SET_EQ_CONFIG\n");
if (copy_from_user(&acdb_data.eq.num_bands, (void *) arg,
sizeof(acdb_data.eq) -
(AUDPP_CMD_CFG_OBJECT_PARAMS_COMMON_LEN + 2))) {
rc = -EFAULT;
break;
}
spin_lock_irqsave(&acdb_data.dsp_lock, flags);
acdb_data.dec_id = 0;
rc = audpp_dsp_set_eq(acdb_data.dec_id, 1,
&acdb_data.eq, COPP);
if (rc < 0)
MM_ERR("AUDPP returned err =%d\n", rc);
spin_unlock_irqrestore(&acdb_data.dsp_lock, flags);
break;
case AUDIO_REGISTER_PMEM:
MM_DBG("AUDIO_REGISTER_PMEM\n");
if (copy_from_user(&info, (void *) arg, sizeof(info))) {
MM_ERR("Cannot copy from user\n");
return -EFAULT;
}
rc = get_pmem_file(info.fd, &acdb_data.paddr,
&acdb_data.kvaddr,
&acdb_data.pmem_len,
&acdb_data.file);
if (rc == 0)
acdb_data.pmem_fd = info.fd;
break;
case AUDIO_DEREGISTER_PMEM:
if (acdb_data.pmem_fd)
put_pmem_file(acdb_data.file);
break;
case AUDIO_SET_ACDB_BLK:
MM_DBG("IOCTL AUDIO_SET_ACDB_BLK\n");
rc = acdb_set_calibration_blk(arg);
break;
case AUDIO_GET_ACDB_BLK:
MM_DBG("IOiCTL AUDIO_GET_ACDB_BLK\n");
rc = acdb_get_calibration_blk(arg);
break;
default:
MM_DBG("Unknown IOCTL%d\n", cmd);
rc = -EINVAL;
}
return rc;
}
static const struct file_operations acdb_fops = {
.owner = THIS_MODULE,
.open = audio_acdb_open,
.release = audio_acdb_release,
.llseek = no_llseek,
.unlocked_ioctl = audio_acdb_ioctl
};
struct miscdevice acdb_misc = {
.minor = MISC_DYNAMIC_MINOR,
.name = "msm_acdb",
.fops = &acdb_fops,
};
static s32 acdb_get_calibration(void)
{
struct acdb_cmd_get_device_table acdb_cmd;
s32 result = 0;
u32 iterations = 0;
MM_DBG("acdb state = %d\n", acdb_data.acdb_state);
acdb_cmd.command_id = ACDB_GET_DEVICE_TABLE;
acdb_cmd.device_id = acdb_data.device_info->acdb_id;
acdb_cmd.network_id = 0x0108B153;
acdb_cmd.sample_rate_id = acdb_data.device_info->sample_rate;
acdb_cmd.total_bytes = ACDB_BUF_SIZE;
acdb_cmd.phys_buf = (u32 *)acdb_data.phys_addr;
MM_DBG("device_id = %d, sampling_freq = %d\n",
acdb_cmd.device_id, acdb_cmd.sample_rate_id);
do {
result = dalrpc_fcn_8(ACDB_DalACDB_ioctl, acdb_data.handle,
(const void *)&acdb_cmd, sizeof(acdb_cmd),
&acdb_data.acdb_result,
sizeof(acdb_data.acdb_result));
if (result < 0) {
MM_ERR("ACDB=> Device table RPC failure"
" result = %d\n", result);
goto error;
}
/*following check is introduced to handle boot up race
condition between AUDCAL SW peers running on apps
and modem (ACDB_RES_BADSTATE indicates modem AUDCAL SW is
not in initialized sate) we need to retry to get ACDB
values*/
if (acdb_data.acdb_result.result == ACDB_RES_BADSTATE) {
msleep(500);
iterations++;
} else if (acdb_data.acdb_result.result == ACDB_RES_SUCCESS) {
MM_DBG("Modem query for acdb values is successful"
" (iterations = %d)\n", iterations);
acdb_data.acdb_state |= CAL_DATA_READY;
return result;
} else {
MM_ERR("ACDB=> modem failed to fill acdb values,"
" reuslt = %d, (iterations = %d)\n",
acdb_data.acdb_result.result,
iterations);
goto error;
}
} while (iterations < MAX_RETRY);
MM_ERR("ACDB=> AUDCAL SW on modem is not in intiailized state (%d)\n",
acdb_data.acdb_result.result);
error:
result = -EINVAL;
return result;
}
s32 acdb_get_calibration_data(struct acdb_get_block *get_block)
{
s32 result = -EINVAL;
struct acdb_cmd_device acdb_cmd;
struct acdb_result acdb_result;
MM_DBG("acdb_get_calibration_data\n");
acdb_cmd.command_id = ACDB_GET_DEVICE;
acdb_cmd.network_id = 0x0108B153;
acdb_cmd.device_id = get_block->acdb_id;
acdb_cmd.sample_rate_id = get_block->sample_rate_id;
acdb_cmd.interface_id = get_block->interface_id;
acdb_cmd.algorithm_block_id = get_block->algorithm_block_id;
acdb_cmd.total_bytes = get_block->total_bytes;
acdb_cmd.phys_buf = (u32 *)acdb_data.get_blk_paddr;
result = dalrpc_fcn_8(ACDB_DalACDB_ioctl, acdb_data.handle,
(const void *)&acdb_cmd, sizeof(acdb_cmd),
&acdb_result,
sizeof(acdb_result));
if (result < 0) {
MM_ERR("ACDB=> Device Get RPC failure"
" result = %d\n", result);
goto err_state;
} else {
MM_DBG("ACDB=> Device Get RPC Success\n");
if (acdb_result.result == ACDB_RES_SUCCESS) {
MM_DBG("ACDB_GET_DEVICE Success\n");
result = 0;
memcpy(get_block->buf_ptr, acdb_data.get_blk_kvaddr,
get_block->total_bytes);
} else if (acdb_result.result == ACDB_RES_FAILURE)
MM_ERR("ACDB_GET_DEVICE Failure\n");
else if (acdb_result.result == ACDB_RES_BADPARM)
MM_ERR("ACDB_GET_DEVICE BadParams\n");
else
MM_ERR("Unknown error\n");
}
err_state:
return result;
}
EXPORT_SYMBOL(acdb_get_calibration_data);
static u8 check_device_info_already_present(
struct auddev_evt_audcal_info audcal_info,
struct acdb_cache_node *acdb_cache_free_node)
{
if ((audcal_info.dev_id ==
acdb_cache_free_node->device_info.dev_id) &&
(audcal_info.sample_rate ==
acdb_cache_free_node->device_info.\
sample_rate) &&
(audcal_info.acdb_id ==
acdb_cache_free_node->device_info.acdb_id)) {
MM_DBG("acdb values are already present\n");
/*if acdb state is not set for CAL_DATA_READY and node status
is filled, acdb state should be updated with CAL_DATA_READY
state*/
acdb_data.acdb_state |= CAL_DATA_READY;
/*checking for cache node status if it is not filled then the
acdb values are not cleaned from node so update node status
with acdb value filled*/
if ((acdb_cache_free_node->node_status != ACDB_VALUES_FILLED) &&
((audcal_info.dev_type & RX_DEVICE) == 1)) {
MM_DBG("device was released earlier\n");
acdb_cache_free_node->node_status = ACDB_VALUES_FILLED;
return 2; /*node is presnet but status as not filled*/
}
return 1; /*node is present but status as filled*/
}
MM_DBG("copying device info into node\n");
/*as device information is not present in cache copy
the current device information into the node*/
memcpy(&acdb_cache_free_node->device_info,
&audcal_info, sizeof(audcal_info));
return 0; /*cant find the node*/
}
static struct acdb_iir_block *get_audpp_irr_block(void)
{
struct header *prs_hdr;
u32 index = 0;
while (index < acdb_data.acdb_result.used_bytes) {
prs_hdr = (struct header *)(acdb_data.virt_addr + index);
if (prs_hdr->dbor_signature == DBOR_SIGNATURE) {
if (prs_hdr->abid == ABID_AUDIO_IIR_RX) {
if (prs_hdr->iid == IID_AUDIO_IIR_COEFF)
return (struct acdb_iir_block *)
(acdb_data.virt_addr + index
+ sizeof(struct header));
} else {
index += prs_hdr->data_len +
sizeof(struct header);
}
} else {
break;
}
}
return NULL;
}
static s32 acdb_fill_audpp_iir(void)
{
struct acdb_iir_block *acdb_iir;
s32 i = 0;
acdb_iir = get_audpp_irr_block();
if (acdb_iir == NULL) {
MM_ERR("unable to find audpp iir block returning\n");
return -1;
}
memset(acdb_data.pp_iir, 0, sizeof(*acdb_data.pp_iir));
acdb_data.pp_iir->common.cmd_id = AUDPP_CMD_CFG_OBJECT_PARAMS;
acdb_data.pp_iir->common.stream = AUDPP_CMD_COPP_STREAM;
acdb_data.pp_iir->common.stream_id = 0;
acdb_data.pp_iir->common.obj_cfg = AUDPP_CMD_OBJ0_UPDATE;
acdb_data.pp_iir->common.command_type = 0;
acdb_data.pp_iir->active_flag = acdb_iir->enable_flag;
acdb_data.pp_iir->num_bands = acdb_iir->stage_count;
for (; i < acdb_iir->stage_count; i++) {
acdb_data.pp_iir->params_filter.filter_4_params.
numerator_filter[i].numerator_b0_filter_lsw =
acdb_iir->stages[i].b0_lo;
acdb_data.pp_iir->params_filter.filter_4_params.
numerator_filter[i].numerator_b0_filter_msw =
acdb_iir->stages[i].b0_hi;
acdb_data.pp_iir->params_filter.filter_4_params.
numerator_filter[i].numerator_b1_filter_lsw =
acdb_iir->stages[i].b1_lo;
acdb_data.pp_iir->params_filter.filter_4_params.
numerator_filter[i].numerator_b1_filter_msw =
acdb_iir->stages[i].b1_hi;
acdb_data.pp_iir->params_filter.filter_4_params.
numerator_filter[i].numerator_b2_filter_lsw =
acdb_iir->stages[i].b2_lo;
acdb_data.pp_iir->params_filter.filter_4_params.
numerator_filter[i].numerator_b2_filter_msw =
acdb_iir->stages[i].b2_hi;
acdb_data.pp_iir->params_filter.filter_4_params.
denominator_filter[i].denominator_a0_filter_lsw =
acdb_iir->stages_a[i].a1_lo;
acdb_data.pp_iir->params_filter.filter_4_params.
denominator_filter[i].denominator_a0_filter_msw =
acdb_iir->stages_a[i].a1_hi;
acdb_data.pp_iir->params_filter.filter_4_params.
denominator_filter[i].denominator_a1_filter_lsw =
acdb_iir->stages_a[i].a2_lo;
acdb_data.pp_iir->params_filter.filter_4_params.
denominator_filter[i].denominator_a1_filter_msw =
acdb_iir->stages_a[i].a2_hi;
acdb_data.pp_iir->params_filter.filter_4_params.
shift_factor_filter[i].shift_factor_0 =
acdb_iir->shift_factor[i];
acdb_data.pp_iir->params_filter.filter_4_params.pan_filter[i].
pan_filter_0 = acdb_iir->pan[i];
}
return 0;
}
static void extract_mbadrc(u32 *phy_addr, struct header *prs_hdr, u32 *index)
{
if (prs_hdr->iid == IID_MBADRC_EXT_BUFF) {
MM_DBG("Got IID = IID_MBADRC_EXT_BUFF\n");
*phy_addr = acdb_data.phys_addr + *index +
sizeof(struct header);
memcpy(acdb_data.mbadrc_block.ext_buf,
(acdb_data.virt_addr + *index +
sizeof(struct header)), 196*2);
MM_DBG("phy_addr = %x\n", *phy_addr);
*index += prs_hdr->data_len + sizeof(struct header);
} else if (prs_hdr->iid == IID_MBADRC_BAND_CONFIG) {
MM_DBG("Got IID == IID_MBADRC_BAND_CONFIG\n");
memcpy(acdb_data.mbadrc_block.band_config, (acdb_data.virt_addr
+ *index + sizeof(struct header)),
sizeof(struct mbadrc_band_config_type) *
acdb_data.mbadrc_block.parameters.\
mbadrc_num_bands);
*index += prs_hdr->data_len + sizeof(struct header);
} else if (prs_hdr->iid == IID_MBADRC_PARAMETERS) {
struct mbadrc_parameter *tmp;
tmp = (struct mbadrc_parameter *)(acdb_data.virt_addr + *index
+ sizeof(struct header));
MM_DBG("Got IID == IID_MBADRC_PARAMETERS\n");
acdb_data.mbadrc_block.parameters.mbadrc_enable =
tmp->mbadrc_enable;
acdb_data.mbadrc_block.parameters.mbadrc_num_bands =
tmp->mbadrc_num_bands;
acdb_data.mbadrc_block.parameters.mbadrc_down_sample_level =
tmp->mbadrc_down_sample_level;
acdb_data.mbadrc_block.parameters.mbadrc_delay =
tmp->mbadrc_delay;
*index += prs_hdr->data_len + sizeof(struct header);
}
}
static void get_audpp_mbadrc_block(u32 *phy_addr)
{
struct header *prs_hdr;
u32 index = 0;
while (index < acdb_data.acdb_result.used_bytes) {
prs_hdr = (struct header *)(acdb_data.virt_addr + index);
if (prs_hdr->dbor_signature == DBOR_SIGNATURE) {
if (prs_hdr->abid == ABID_AUDIO_MBADRC_RX) {
if ((prs_hdr->iid == IID_MBADRC_EXT_BUFF)
|| (prs_hdr->iid ==
IID_MBADRC_BAND_CONFIG)
|| (prs_hdr->iid ==
IID_MBADRC_PARAMETERS)) {
extract_mbadrc(phy_addr, prs_hdr,
&index);
}
} else {
index += prs_hdr->data_len +
sizeof(struct header);
}
} else {
break;
}
}
}
static s32 acdb_fill_audpp_mbadrc(void)
{
u32 mbadrc_phys_addr = -1;
get_audpp_mbadrc_block(&mbadrc_phys_addr);
if (IS_ERR_VALUE(mbadrc_phys_addr)) {
MM_ERR("failed to get mbadrc block\n");
return -1;
}
memset(acdb_data.pp_mbadrc, 0, sizeof(*acdb_data.pp_mbadrc));
acdb_data.pp_mbadrc->common.cmd_id = AUDPP_CMD_CFG_OBJECT_PARAMS;
acdb_data.pp_mbadrc->common.stream = AUDPP_CMD_COPP_STREAM;
acdb_data.pp_mbadrc->common.stream_id = 0;
acdb_data.pp_mbadrc->common.obj_cfg = AUDPP_CMD_OBJ0_UPDATE;
acdb_data.pp_mbadrc->common.command_type = 0;
acdb_data.pp_mbadrc->enable = acdb_data.mbadrc_block.\
parameters.mbadrc_enable;
acdb_data.pp_mbadrc->num_bands =
acdb_data.mbadrc_block.\
parameters.mbadrc_num_bands;
acdb_data.pp_mbadrc->down_samp_level =
acdb_data.mbadrc_block.parameters.\
mbadrc_down_sample_level;
acdb_data.pp_mbadrc->adrc_delay =
acdb_data.mbadrc_block.parameters.\
mbadrc_delay;
if (acdb_data.mbadrc_block.parameters.mbadrc_num_bands > 1)
acdb_data.pp_mbadrc->ext_buf_size = (97 * 2) +
(33 * 2 * (acdb_data.mbadrc_block.parameters.\
mbadrc_num_bands - 2));
acdb_data.pp_mbadrc->ext_partition = 0;
acdb_data.pp_mbadrc->ext_buf_lsw = (u16)(mbadrc_phys_addr\
& 0xFFFF);
acdb_data.pp_mbadrc->ext_buf_msw = (u16)((mbadrc_phys_addr\
& 0xFFFF0000) >> 16);
memcpy(acdb_data.pp_mbadrc->adrc_band, acdb_data.mbadrc_block.\
band_config,
sizeof(struct mbadrc_band_config_type) *
acdb_data.mbadrc_block.parameters.mbadrc_num_bands);
return 0;
}
static struct acdb_calib_gain_rx *get_audpp_cal_gain(void)
{
struct header *prs_hdr;
u32 index = 0;
while (index < acdb_data.acdb_result.used_bytes) {
prs_hdr = (struct header *)(acdb_data.virt_addr + index);
if (prs_hdr->dbor_signature == DBOR_SIGNATURE) {
if (prs_hdr->abid == ABID_AUDIO_CALIBRATION_GAIN_RX) {
if (prs_hdr->iid ==
IID_AUDIO_CALIBRATION_GAIN_RX) {
MM_DBG("Got audpp_calib_gain_rx"
" block\n");
return (struct acdb_calib_gain_rx *)
(acdb_data.virt_addr + index
+ sizeof(struct header));
}
} else {
index += prs_hdr->data_len +
sizeof(struct header);
}
} else {
break;
}
}
return NULL;
}
static s32 acdb_fill_audpp_cal_gain(void)
{
struct acdb_calib_gain_rx *acdb_calib_gain_rx = NULL;
acdb_calib_gain_rx = get_audpp_cal_gain();
if (acdb_calib_gain_rx == NULL) {
MM_ERR("unable to find audpp"
" calibration gain block returning\n");
return -1;
}
MM_DBG("Calibration value"
" for calib_gain_rx %d\n", acdb_calib_gain_rx->audppcalgain);
memset(acdb_data.calib_gain_rx, 0, sizeof(*acdb_data.calib_gain_rx));
acdb_data.calib_gain_rx->common.cmd_id = AUDPP_CMD_CFG_OBJECT_PARAMS;
acdb_data.calib_gain_rx->common.stream = AUDPP_CMD_COPP_STREAM;
acdb_data.calib_gain_rx->common.stream_id = 0;
acdb_data.calib_gain_rx->common.obj_cfg = AUDPP_CMD_OBJ0_UPDATE;
acdb_data.calib_gain_rx->common.command_type = 0;
acdb_data.calib_gain_rx->audppcalgain =
acdb_calib_gain_rx->audppcalgain;
return 0;
}
static void extract_pbe_block(struct header *prs_hdr, u32 *index)
{
if (prs_hdr->iid == IID_AUDIO_PBE_RX_ENABLE_FLAG) {
MM_DBG("Got IID = IID_AUDIO_PBE_RX_ENABLE\n");
acdb_data.pbe_enable_flag = (u16 *)(acdb_data.virt_addr +
*index +
sizeof(struct header));
*index += prs_hdr->data_len + sizeof(struct header);
} else if (prs_hdr->iid == IID_PBE_CONFIG_PARAMETERS) {
MM_DBG("Got IID == IID_PBE_CONFIG_PARAMETERS\n");
acdb_data.pbe_blk = (struct acdb_pbe_block *)
(acdb_data.virt_addr + *index
+ sizeof(struct header));
*index += prs_hdr->data_len + sizeof(struct header);
}
}
static s32 get_audpp_pbe_block(void)
{
struct header *prs_hdr;
u32 index = 0;
s32 result = -1;
while (index < acdb_data.acdb_result.used_bytes) {
prs_hdr = (struct header *)(acdb_data.virt_addr + index);
if (prs_hdr->dbor_signature == DBOR_SIGNATURE) {
if (prs_hdr->abid == ABID_AUDIO_PBE_RX) {
if ((prs_hdr->iid == IID_PBE_CONFIG_PARAMETERS)
|| (prs_hdr->iid ==
IID_AUDIO_PBE_RX_ENABLE_FLAG)) {
extract_pbe_block(prs_hdr, &index);
result = 0;
}
} else {
index += prs_hdr->data_len +
sizeof(struct header);
}
} else {
break;
}
}
return result;
}
static s32 acdb_fill_audpp_pbe(void)
{
s32 result = -1;
result = get_audpp_pbe_block();
if (IS_ERR_VALUE(result))
return result;
memset(acdb_data.pbe_block, 0, sizeof(*acdb_data.pbe_block));
acdb_data.pbe_block->common.cmd_id = AUDPP_CMD_CFG_OBJECT_PARAMS;
acdb_data.pbe_block->common.stream = AUDPP_CMD_COPP_STREAM;
acdb_data.pbe_block->common.stream_id = 0;
acdb_data.pbe_block->common.obj_cfg = AUDPP_CMD_OBJ0_UPDATE;
acdb_data.pbe_block->common.command_type = 0;
acdb_data.pbe_block->pbe_enable = *acdb_data.pbe_enable_flag;
acdb_data.pbe_block->realbassmix = acdb_data.pbe_blk->realbassmix;
acdb_data.pbe_block->basscolorcontrol =
acdb_data.pbe_blk->basscolorcontrol;
acdb_data.pbe_block->mainchaindelay = acdb_data.pbe_blk->mainchaindelay;
acdb_data.pbe_block->xoverfltorder = acdb_data.pbe_blk->xoverfltorder;
acdb_data.pbe_block->bandpassfltorder =
acdb_data.pbe_blk->bandpassfltorder;
acdb_data.pbe_block->adrcdelay = acdb_data.pbe_blk->adrcdelay;
acdb_data.pbe_block->downsamplelevel =
acdb_data.pbe_blk->downsamplelevel;
acdb_data.pbe_block->comprmstav = acdb_data.pbe_blk->comprmstav;
acdb_data.pbe_block->expthreshold = acdb_data.pbe_blk->expthreshold;
acdb_data.pbe_block->expslope = acdb_data.pbe_blk->expslope;
acdb_data.pbe_block->compthreshold = acdb_data.pbe_blk->compthreshold;
acdb_data.pbe_block->compslope = acdb_data.pbe_blk->compslope;
acdb_data.pbe_block->cpmpattack_lsw = acdb_data.pbe_blk->cpmpattack_lsw;
acdb_data.pbe_block->compattack_msw = acdb_data.pbe_blk->compattack_msw;
acdb_data.pbe_block->comprelease_lsw =
acdb_data.pbe_blk->comprelease_lsw;
acdb_data.pbe_block->comprelease_msw =
acdb_data.pbe_blk->comprelease_msw;
acdb_data.pbe_block->compmakeupgain = acdb_data.pbe_blk->compmakeupgain;
acdb_data.pbe_block->baselimthreshold =
acdb_data.pbe_blk->baselimthreshold;
acdb_data.pbe_block->highlimthreshold =
acdb_data.pbe_blk->highlimthreshold;
acdb_data.pbe_block->basslimmakeupgain =
acdb_data.pbe_blk->basslimmakeupgain;
acdb_data.pbe_block->highlimmakeupgain =
acdb_data.pbe_blk->highlimmakeupgain;
acdb_data.pbe_block->limbassgrc = acdb_data.pbe_blk->limbassgrc;
acdb_data.pbe_block->limhighgrc = acdb_data.pbe_blk->limhighgrc;
acdb_data.pbe_block->limdelay = acdb_data.pbe_blk->limdelay;
memcpy(acdb_data.pbe_block->filter_coeffs,
acdb_data.pbe_blk->filter_coeffs, sizeof(u16)*90);
acdb_data.pbe_block->extpartition = 0;
acdb_data.pbe_block->extbuffsize_lsw = PBE_BUF_SIZE;
acdb_data.pbe_block->extbuffsize_msw = 0;
acdb_data.pbe_block->extbuffstart_lsw = ((u32)acdb_data.pbe_extbuff
& 0xFFFF);
acdb_data.pbe_block->extbuffstart_msw = (((u32)acdb_data.pbe_extbuff
& 0xFFFF0000) >> 16);
return 0;
}
static s32 acdb_calibrate_audpp(void)
{
s32 result = 0;
result = acdb_fill_audpp_iir();
if (!IS_ERR_VALUE(result)) {
result = audpp_dsp_set_rx_iir(acdb_data.device_info->dev_id,
acdb_data.pp_iir->active_flag,
acdb_data.pp_iir, COPP);
if (result) {
MM_ERR("ACDB=> Failed to send IIR data to postproc\n");
result = -EINVAL;
goto done;
} else
MM_DBG("AUDPP is calibrated with IIR parameters"
" for COPP ID %d\n",
acdb_data.device_info->dev_id);
}
result = acdb_fill_audpp_mbadrc();
if (!IS_ERR_VALUE(result)) {
result = audpp_dsp_set_mbadrc(acdb_data.device_info->dev_id,
acdb_data.pp_mbadrc->enable,
acdb_data.pp_mbadrc, COPP);
if (result) {
MM_ERR("ACDB=> Failed to send MBADRC data to"
" postproc\n");
result = -EINVAL;
goto done;
} else
MM_DBG("AUDPP is calibrated with MBADRC parameters"
" for COPP ID %d\n",
acdb_data.device_info->dev_id);
}
result = acdb_fill_audpp_cal_gain();
if (!(IS_ERR_VALUE(result))) {
result = audpp_dsp_set_gain_rx(acdb_data.device_info->dev_id,
acdb_data.calib_gain_rx, COPP);
if (result) {
MM_ERR("ACDB=> Failed to send gain_rx"
" data to postproc\n");
result = -EINVAL;
goto done;
} else
MM_DBG("AUDPP is calibrated with calib_gain_rx\n");
}
result = acdb_fill_audpp_pbe();
if (!(IS_ERR_VALUE(result))) {
result = audpp_dsp_set_pbe(acdb_data.device_info->dev_id,
acdb_data.pbe_block->pbe_enable,
acdb_data.pbe_block, COPP);
if (result) {
MM_ERR("ACDB=> Failed to send pbe block"
"data to postproc\n");
result = -EINVAL;
goto done;
}
MM_DBG("AUDPP is calibarted with PBE\n");
}
done:
return result;
}
static struct acdb_agc_block *get_audpreproc_agc_block(void)
{
struct header *prs_hdr;
u32 index = 0;
while (index < acdb_data.acdb_result.used_bytes) {
prs_hdr = (struct header *)(acdb_data.virt_addr + index);
if (prs_hdr->dbor_signature == DBOR_SIGNATURE) {
if (prs_hdr->abid == ABID_AUDIO_AGC_TX) {
if (prs_hdr->iid == IID_AUDIO_AGC_PARAMETERS) {
MM_DBG("GOT ABID_AUDIO_AGC_TX\n");
return (struct acdb_agc_block *)
(acdb_data.virt_addr + index
+ sizeof(struct header));
}
} else {
index += prs_hdr->data_len +
sizeof(struct header);
}
} else {
break;
}
}
return NULL;
}
static s32 acdb_fill_audpreproc_agc(void)
{
struct acdb_agc_block *acdb_agc;
acdb_agc = get_audpreproc_agc_block();
if (!acdb_agc) {
MM_DBG("unable to find preproc agc parameters winding up\n");
return -1;
}
memset(acdb_data.preproc_agc, 0, sizeof(*acdb_data.preproc_agc));
acdb_data.preproc_agc->cmd_id = AUDPREPROC_CMD_CFG_AGC_PARAMS;
acdb_data.preproc_agc->stream_id = acdb_data.preproc_stream_id;
/* 0xFE00 to configure all parameters */
acdb_data.preproc_agc->tx_agc_param_mask = 0xFFFF;
if (acdb_agc->enable_status)
acdb_data.preproc_agc->tx_agc_enable_flag =
AUDPREPROC_CMD_TX_AGC_ENA_FLAG_ENA;
else
acdb_data.preproc_agc->tx_agc_enable_flag =
AUDPREPROC_CMD_TX_AGC_ENA_FLAG_DIS;
acdb_data.preproc_agc->comp_rlink_static_gain =
acdb_agc->comp_rlink_static_gain;
acdb_data.preproc_agc->comp_rlink_aig_flag =
acdb_agc->comp_rlink_aig_flag;
acdb_data.preproc_agc->expander_rlink_th =
acdb_agc->exp_rlink_threshold;
acdb_data.preproc_agc->expander_rlink_slope =
acdb_agc->exp_rlink_slope;
acdb_data.preproc_agc->compressor_rlink_th =
acdb_agc->comp_rlink_threshold;
acdb_data.preproc_agc->compressor_rlink_slope =
acdb_agc->comp_rlink_slope;
/* 0xFFF0 to configure all parameters */
acdb_data.preproc_agc->tx_adc_agc_param_mask = 0xFFFF;
acdb_data.preproc_agc->comp_rlink_aig_attackk =
acdb_agc->comp_rlink_aig_attack_k;
acdb_data.preproc_agc->comp_rlink_aig_leak_down =
acdb_agc->comp_rlink_aig_leak_down;
acdb_data.preproc_agc->comp_rlink_aig_leak_up =
acdb_agc->comp_rlink_aig_leak_up;
acdb_data.preproc_agc->comp_rlink_aig_max =
acdb_agc->comp_rlink_aig_max;
acdb_data.preproc_agc->comp_rlink_aig_min =
acdb_agc->comp_rlink_aig_min;
acdb_data.preproc_agc->comp_rlink_aig_releasek =
acdb_agc->comp_rlink_aig_release_k;
acdb_data.preproc_agc->comp_rlink_aig_leakrate_fast =
acdb_agc->comp_rlink_aig_sm_leak_rate_fast;
acdb_data.preproc_agc->comp_rlink_aig_leakrate_slow =
acdb_agc->comp_rlink_aig_sm_leak_rate_slow;
acdb_data.preproc_agc->comp_rlink_attackk_msw =
acdb_agc->comp_rlink_attack_k_msw;
acdb_data.preproc_agc->comp_rlink_attackk_lsw =
acdb_agc->comp_rlink_attack_k_lsw;
acdb_data.preproc_agc->comp_rlink_delay =
acdb_agc->comp_rlink_delay;
acdb_data.preproc_agc->comp_rlink_releasek_msw =
acdb_agc->comp_rlink_release_k_msw;
acdb_data.preproc_agc->comp_rlink_releasek_lsw =
acdb_agc->comp_rlink_release_k_lsw;
acdb_data.preproc_agc->comp_rlink_rms_tav =
acdb_agc->comp_rlink_rms_trav;
return 0;
}
static struct acdb_iir_block *get_audpreproc_irr_block(void)
{
struct header *prs_hdr;
u32 index = 0;
while (index < acdb_data.acdb_result.used_bytes) {
prs_hdr = (struct header *)(acdb_data.virt_addr + index);
if (prs_hdr->dbor_signature == DBOR_SIGNATURE) {
if (prs_hdr->abid == ABID_AUDIO_IIR_TX) {
if (prs_hdr->iid == IID_AUDIO_IIR_COEFF)
return (struct acdb_iir_block *)
(acdb_data.virt_addr + index
+ sizeof(struct header));
} else {
index += prs_hdr->data_len +
sizeof(struct header);
}
} else {
break;
}
}
return NULL;
}
static s32 acdb_fill_audpreproc_iir(void)
{
struct acdb_iir_block *acdb_iir;
acdb_iir = get_audpreproc_irr_block();
if (!acdb_iir) {
MM_DBG("unable to find preproc iir parameters winding up\n");
return -1;
}
memset(acdb_data.preproc_iir, 0, sizeof(*acdb_data.preproc_iir));
acdb_data.preproc_iir->cmd_id =
AUDPREPROC_CMD_CFG_IIR_TUNING_FILTER_PARAMS;
acdb_data.preproc_iir->stream_id = acdb_data.preproc_stream_id;
acdb_data.preproc_iir->active_flag = acdb_iir->enable_flag;
acdb_data.preproc_iir->num_bands = acdb_iir->stage_count;
acdb_data.preproc_iir->numerator_coeff_b0_filter0_lsw =
acdb_iir->stages[0].b0_lo;
acdb_data.preproc_iir->numerator_coeff_b0_filter0_msw =
acdb_iir->stages[0].b0_hi;
acdb_data.preproc_iir->numerator_coeff_b1_filter0_lsw =
acdb_iir->stages[0].b1_lo;
acdb_data.preproc_iir->numerator_coeff_b1_filter0_msw =
acdb_iir->stages[0].b1_hi;
acdb_data.preproc_iir->numerator_coeff_b2_filter0_lsw =
acdb_iir->stages[0].b2_lo;
acdb_data.preproc_iir->numerator_coeff_b2_filter0_msw =
acdb_iir->stages[0].b2_hi;
acdb_data.preproc_iir->numerator_coeff_b0_filter1_lsw =
acdb_iir->stages[1].b0_lo;
acdb_data.preproc_iir->numerator_coeff_b0_filter1_msw =
acdb_iir->stages[1].b0_hi;
acdb_data.preproc_iir->numerator_coeff_b1_filter1_lsw =
acdb_iir->stages[1].b1_lo;
acdb_data.preproc_iir->numerator_coeff_b1_filter1_msw =
acdb_iir->stages[1].b1_hi;
acdb_data.preproc_iir->numerator_coeff_b2_filter1_lsw =
acdb_iir->stages[1].b2_lo;
acdb_data.preproc_iir->numerator_coeff_b2_filter1_msw =
acdb_iir->stages[1].b2_hi;
acdb_data.preproc_iir->numerator_coeff_b0_filter2_lsw =
acdb_iir->stages[2].b0_lo;
acdb_data.preproc_iir->numerator_coeff_b0_filter2_msw =
acdb_iir->stages[2].b0_hi;
acdb_data.preproc_iir->numerator_coeff_b1_filter2_lsw =
acdb_iir->stages[2].b1_lo;
acdb_data.preproc_iir->numerator_coeff_b1_filter2_msw =
acdb_iir->stages[2].b1_hi;
acdb_data.preproc_iir->numerator_coeff_b2_filter2_lsw =
acdb_iir->stages[2].b2_lo;
acdb_data.preproc_iir->numerator_coeff_b2_filter2_msw =
acdb_iir->stages[2].b2_hi;
acdb_data.preproc_iir->numerator_coeff_b0_filter3_lsw =
acdb_iir->stages[3].b0_lo;
acdb_data.preproc_iir->numerator_coeff_b0_filter3_msw =
acdb_iir->stages[3].b0_hi;
acdb_data.preproc_iir->numerator_coeff_b1_filter3_lsw =
acdb_iir->stages[3].b1_lo;
acdb_data.preproc_iir->numerator_coeff_b1_filter3_msw =
acdb_iir->stages[3].b1_hi;
acdb_data.preproc_iir->numerator_coeff_b2_filter3_lsw =
acdb_iir->stages[3].b2_lo;
acdb_data.preproc_iir->numerator_coeff_b2_filter3_msw =
acdb_iir->stages[3].b2_hi;
acdb_data.preproc_iir->denominator_coeff_a0_filter0_lsw =
acdb_iir->stages_a[0].a1_lo;
acdb_data.preproc_iir->denominator_coeff_a0_filter0_msw =
acdb_iir->stages_a[0].a1_hi;
acdb_data.preproc_iir->denominator_coeff_a1_filter0_lsw =
acdb_iir->stages_a[0].a2_lo;
acdb_data.preproc_iir->denominator_coeff_a1_filter0_msw =
acdb_iir->stages_a[0].a2_hi;
acdb_data.preproc_iir->denominator_coeff_a0_filter1_lsw =
acdb_iir->stages_a[1].a1_lo;
acdb_data.preproc_iir->denominator_coeff_a0_filter1_msw =
acdb_iir->stages_a[1].a1_hi;
acdb_data.preproc_iir->denominator_coeff_a1_filter1_lsw =
acdb_iir->stages_a[1].a2_lo;
acdb_data.preproc_iir->denominator_coeff_a1_filter1_msw =
acdb_iir->stages_a[1].a2_hi;
acdb_data.preproc_iir->denominator_coeff_a0_filter2_lsw =
acdb_iir->stages_a[2].a1_lo;
acdb_data.preproc_iir->denominator_coeff_a0_filter2_msw =
acdb_iir->stages_a[2].a1_hi;
acdb_data.preproc_iir->denominator_coeff_a1_filter2_lsw =
acdb_iir->stages_a[2].a2_lo;
acdb_data.preproc_iir->denominator_coeff_a1_filter2_msw =
acdb_iir->stages_a[2].a2_hi;
acdb_data.preproc_iir->denominator_coeff_a0_filter3_lsw =
acdb_iir->stages_a[3].a1_lo;
acdb_data.preproc_iir->denominator_coeff_a0_filter3_msw =
acdb_iir->stages_a[3].a1_hi;
acdb_data.preproc_iir->denominator_coeff_a1_filter3_lsw =
acdb_iir->stages_a[3].a2_lo;
acdb_data.preproc_iir->denominator_coeff_a1_filter3_msw =
acdb_iir->stages_a[3].a2_hi;
acdb_data.preproc_iir->shift_factor_filter0 =
acdb_iir->shift_factor[0];
acdb_data.preproc_iir->shift_factor_filter1 =
acdb_iir->shift_factor[1];
acdb_data.preproc_iir->shift_factor_filter2 =
acdb_iir->shift_factor[2];
acdb_data.preproc_iir->shift_factor_filter3 =
acdb_iir->shift_factor[3];
acdb_data.preproc_iir->pan_of_filter0 =
acdb_iir->pan[0];
acdb_data.preproc_iir->pan_of_filter1 =
acdb_iir->pan[1];
acdb_data.preproc_iir->pan_of_filter2 =
acdb_iir->pan[2];
acdb_data.preproc_iir->pan_of_filter3 =
acdb_iir->pan[3];
return 0;
}
static struct acdb_calib_gain_tx *get_audpreproc_cal_gain(void)
{
struct header *prs_hdr;
u32 index = 0;
while (index < acdb_data.acdb_result.used_bytes) {
prs_hdr = (struct header *)(acdb_data.virt_addr + index);
if (prs_hdr->dbor_signature == DBOR_SIGNATURE) {
if (prs_hdr->abid == ABID_AUDIO_CALIBRATION_GAIN_TX) {
if (prs_hdr->iid ==
IID_AUDIO_CALIBRATION_GAIN_TX) {
MM_DBG("Got audpreproc_calib_gain_tx"
" block\n");
return (struct acdb_calib_gain_tx *)
(acdb_data.virt_addr + index
+ sizeof(struct header));
}
} else {
index += prs_hdr->data_len +
sizeof(struct header);
}
} else {
break;
}
}
return NULL;
}
static s32 acdb_fill_audpreproc_cal_gain(void)
{
struct acdb_calib_gain_tx *acdb_calib_gain_tx = NULL;
acdb_calib_gain_tx = get_audpreproc_cal_gain();
if (acdb_calib_gain_tx == NULL) {
MM_ERR("unable to find audpreproc"
" calibration block returning\n");
return -1;
}
MM_DBG("Calibration value"
" for calib_gain_tx %d\n", acdb_calib_gain_tx->audprecalgain);
memset(acdb_data.calib_gain_tx, 0, sizeof(*acdb_data.calib_gain_tx));
acdb_data.calib_gain_tx->cmd_id =
AUDPREPROC_CMD_CFG_CAL_GAIN_PARAMS;
acdb_data.calib_gain_tx->stream_id = acdb_data.preproc_stream_id;
acdb_data.calib_gain_tx->audprecalgain =
acdb_calib_gain_tx->audprecalgain;
return 0;
}
static struct acdb_rmc_block *get_rmc_blk(void)
{
struct header *prs_hdr;
u32 index = 0;
while (index < acdb_data.acdb_result.used_bytes) {
prs_hdr = (struct header *)(acdb_data.virt_addr + index);
if (prs_hdr->dbor_signature == DBOR_SIGNATURE) {
if (prs_hdr->abid == ABID_AUDIO_RMC_TX) {
if (prs_hdr->iid ==
IID_AUDIO_RMC_PARAM) {
MM_DBG("Got afe_rmc block\n");
return (struct acdb_rmc_block *)
(acdb_data.virt_addr + index
+ sizeof(struct header));
}
} else {
index += prs_hdr->data_len +
sizeof(struct header);
}
} else {
break;
}
}
return NULL;
}
struct acdb_fluence_block *get_audpp_fluence_block(void)
{
struct header *prs_hdr;
u32 index = 0;
while (index < acdb_data.acdb_result.used_bytes) {
prs_hdr = (struct header *)(acdb_data.virt_addr + index);
if (prs_hdr->dbor_signature == DBOR_SIGNATURE) {
if (prs_hdr->abid == ABID_AUDIO_FLUENCE_TX) {
if (prs_hdr->iid == IID_AUDIO_FLUENCE_TX) {
MM_DBG("got fluence block\n");
return (struct acdb_fluence_block *)
(acdb_data.virt_addr + index
+ sizeof(struct header));
}
} else {
index += prs_hdr->data_len +
sizeof(struct header);
}
} else {
break;
}
}
return NULL;
}
static s32 acdb_fill_audpreproc_fluence(void)
{
struct acdb_fluence_block *fluence_block = NULL;
fluence_block = get_audpp_fluence_block();
if (!fluence_block) {
MM_ERR("error in finding fluence block\n");
return -EPERM;
}
memset(&acdb_data.preproc_lvnv, 0, sizeof(
struct audpreproc_cmd_cfg_lvnv_param));
memcpy(acdb_data.fluence_extbuff_virt,
&fluence_block->cs_tuningMode,
(sizeof(struct acdb_fluence_block) -
sizeof(fluence_block->csmode)));
acdb_data.preproc_lvnv.cmd_id = AUDPREPROC_CMD_CFG_LVNV_PARMS;
acdb_data.preproc_lvnv.stream_id = acdb_data.preproc_stream_id;
acdb_data.preproc_lvnv.cs_mode = fluence_block->csmode;
acdb_data.preproc_lvnv.lvnv_ext_buf_size = FLUENCE_BUF_SIZE;
acdb_data.preproc_lvnv.lvnv_ext_buf_start_lsw =\
((u32)(acdb_data.fluence_extbuff)\
& 0x0000FFFF);
acdb_data.preproc_lvnv.lvnv_ext_buf_start_msw =\
(((u32)acdb_data.fluence_extbuff\
& 0xFFFF0000) >> 16);
return 0;
}
s32 acdb_calibrate_audpreproc(void)
{
s32 result = 0;
struct acdb_rmc_block *acdb_rmc = NULL;
result = acdb_fill_audpreproc_agc();
if (!IS_ERR_VALUE(result)) {
result = audpreproc_dsp_set_agc(acdb_data.preproc_agc, sizeof(
struct audpreproc_cmd_cfg_agc_params));
if (result) {
MM_ERR("ACDB=> Failed to send AGC data to preproc)\n");
result = -EINVAL;
goto done;
} else
MM_DBG("AUDPREC is calibrated with AGC parameters"
" for COPP ID %d and AUDREC session %d\n",
acdb_data.device_info->dev_id,
acdb_data.preproc_stream_id);
}
result = acdb_fill_audpreproc_iir();
if (!IS_ERR_VALUE(result)) {
result = audpreproc_dsp_set_iir(acdb_data.preproc_iir,
sizeof(struct\
audpreproc_cmd_cfg_iir_tuning_filter_params));
if (result) {
MM_ERR("ACDB=> Failed to send IIR data to preproc\n");
result = -EINVAL;
goto done;
} else
MM_DBG("audpreproc is calibrated with iir parameters"
" for COPP ID %d and AUREC session %d\n",
acdb_data.device_info->dev_id,
acdb_data.preproc_stream_id);
}
result = acdb_fill_audpreproc_cal_gain();
if (!(IS_ERR_VALUE(result))) {
result = audpreproc_dsp_set_gain_tx(acdb_data.calib_gain_tx,
sizeof(struct audpreproc_cmd_cfg_cal_gain));
if (result) {
MM_ERR("ACDB=> Failed to send calib_gain_tx"
" data to preproc\n");
result = -EINVAL;
goto done;
} else
MM_DBG("AUDPREPROC is calibrated"
" with calib_gain_tx\n");
}
if (acdb_data.build_id[17] != '0') {
acdb_rmc = get_rmc_blk();
if (acdb_rmc != NULL) {
result = afe_config_rmc_block(acdb_rmc);
if (result) {
MM_ERR("ACDB=> Failed to send rmc"
" data to afe\n");
result = -EINVAL;
goto done;
} else
MM_DBG("AFE is calibrated with rmc params\n");
} else
MM_DBG("RMC block was not found\n");
}
if (!acdb_data.fleuce_feature_status[acdb_data.preproc_stream_id]) {
result = acdb_fill_audpreproc_fluence();
if (!(IS_ERR_VALUE(result))) {
result = audpreproc_dsp_set_lvnv(
&acdb_data.preproc_lvnv,
sizeof(struct\
audpreproc_cmd_cfg_lvnv_param));
if (result) {
MM_ERR("ACDB=> Failed to send lvnv "
"data to preproc\n");
result = -EINVAL;
goto done;
} else
MM_DBG("AUDPREPROC is calibrated"
" with lvnv parameters\n");
} else
MM_ERR("fluence block is not found\n");
} else
MM_DBG("fluence block override\n");
done:
return result;
}
static s32 acdb_send_calibration(void)
{
s32 result = 0;
if ((acdb_data.device_info->dev_type & RX_DEVICE) == 1) {
result = acdb_calibrate_audpp();
if (result)
goto done;
} else if ((acdb_data.device_info->dev_type & TX_DEVICE) == 2) {
result = acdb_calibrate_audpreproc();
if (result)
goto done;
if (acdb_data.preproc_stream_id == 0)
acdb_data.audrec_applied |= AUDREC0_READY;
else if (acdb_data.preproc_stream_id == 1)
acdb_data.audrec_applied |= AUDREC1_READY;
else if (acdb_data.preproc_stream_id == 2)
acdb_data.audrec_applied |= AUDREC2_READY;
MM_DBG("acdb_data.audrec_applied = %x\n",
acdb_data.audrec_applied);
}
done:
return result;
}
static u8 check_tx_acdb_values_cached(void)
{
u8 stream_id = acdb_data.preproc_stream_id;
if ((acdb_data.device_info->dev_id ==
acdb_cache_tx[stream_id].device_info.dev_id) &&
(acdb_data.device_info->sample_rate ==
acdb_cache_tx[stream_id].device_info.sample_rate) &&
(acdb_data.device_info->acdb_id ==
acdb_cache_tx[stream_id].device_info.acdb_id) &&
(acdb_cache_tx[stream_id].node_status ==
ACDB_VALUES_FILLED))
return 0;
else
return 1;
}
static void handle_tx_device_ready_callback(void)
{
u8 i = 0;
u8 ret = 0;
u8 acdb_value_apply = 0;
u8 result = 0;
u8 stream_id = acdb_data.preproc_stream_id;
if (acdb_data.multiple_sessions) {
for (i = 0; i < MAX_AUDREC_SESSIONS; i++) {
/*check is to exclude copying acdb values in the
current node pointed by acdb_data structure*/
if (acdb_cache_tx[i].phys_addr_acdb_values !=
acdb_data.phys_addr) {
ret = check_device_info_already_present(\
*acdb_data.device_info,
&acdb_cache_tx[i]);
if (ret) {
memcpy((char *)acdb_cache_tx[i].\
virt_addr_acdb_values,
(char *)acdb_data.virt_addr,
ACDB_BUF_SIZE);
acdb_cache_tx[i].node_status =
ACDB_VALUES_FILLED;
}
}
}
acdb_data.multiple_sessions = 0;
}
/*check wheather AUDREC enabled before device call backs*/
if ((acdb_data.acdb_state & AUDREC0_READY) &&
!(acdb_data.audrec_applied & AUDREC0_READY)) {
MM_DBG("AUDREC0 already enabled apply acdb values\n");
acdb_value_apply |= AUDREC0_READY;
} else if ((acdb_data.acdb_state & AUDREC1_READY) &&
!(acdb_data.audrec_applied & AUDREC1_READY)) {
MM_DBG("AUDREC1 already enabled apply acdb values\n");
acdb_value_apply |= AUDREC1_READY;
} else if ((acdb_data.acdb_state & AUDREC2_READY) &&
!(acdb_data.audrec_applied & AUDREC2_READY)) {
MM_DBG("AUDREC2 already enabled apply acdb values\n");
acdb_value_apply |= AUDREC2_READY;
}
if (acdb_value_apply) {
if (session_info[stream_id].sampling_freq)
acdb_data.device_info->sample_rate =
session_info[stream_id].sampling_freq;
result = check_tx_acdb_values_cached();
if (result) {
result = acdb_get_calibration();
if (result < 0) {
MM_ERR("Not able to get calibration"
" data continue\n");
return;
}
}
acdb_cache_tx[stream_id].node_status = ACDB_VALUES_FILLED;
acdb_send_calibration();
}
}
static struct acdb_cache_node *get_acdb_values_from_cache_tx(u32 stream_id)
{
MM_DBG("searching node with stream_id %d\n", stream_id);
if ((acdb_cache_tx[stream_id].stream_id == stream_id) &&
(acdb_cache_tx[stream_id].node_status ==
ACDB_VALUES_NOT_FILLED)) {
return &acdb_cache_tx[stream_id];
}
MM_DBG("Error! in finding node\n");
return NULL;
}
static void update_acdb_data_struct(struct acdb_cache_node *cur_node)
{
if (cur_node) {
acdb_data.device_info = &cur_node->device_info;
acdb_data.virt_addr = cur_node->virt_addr_acdb_values;
acdb_data.phys_addr = cur_node->phys_addr_acdb_values;
} else
MM_ERR("error in curent node\n");
}
static void send_acdb_values_for_active_devices(void)
{
u32 i = 0;
for (i = 0; i < MAX_COPP_NODE_SUPPORTED; i++) {
if (acdb_cache_rx[i].node_status ==
ACDB_VALUES_FILLED) {
update_acdb_data_struct(&acdb_cache_rx[i]);
if (acdb_data.acdb_state & CAL_DATA_READY)
acdb_send_calibration();
}
}
}
static s32 initialize_rpc(void)
{
s32 result = 0;
result = daldevice_attach(DALDEVICEID_ACDB, ACDB_PORT_NAME,
ACDB_CPU, &acdb_data.handle);
if (result) {
MM_ERR("ACDB=> Device Attach failed\n");
result = -ENODEV;
goto done;
}
done:
return result;
}
static u32 allocate_memory_acdb_cache_tx(void)
{
u32 result = 0;
u32 i = 0;
u32 err = 0;
/*initialize local cache */
for (i = 0; i < MAX_AUDREC_SESSIONS; i++) {
acdb_cache_tx[i].phys_addr_acdb_values =
allocate_contiguous_ebi_nomap(ACDB_BUF_SIZE,
SZ_4K);
if (!acdb_cache_tx[i].phys_addr_acdb_values) {
MM_ERR("ACDB=> Cannot allocate physical memory\n");
result = -ENOMEM;
goto error;
}
acdb_cache_tx[i].map_v_addr = ioremap(
acdb_cache_tx[i].phys_addr_acdb_values,
ACDB_BUF_SIZE);
if (IS_ERR(acdb_cache_tx[i].map_v_addr)) {
MM_ERR("ACDB=> Could not map physical address\n");
result = -ENOMEM;
free_contiguous_memory_by_paddr(
acdb_cache_tx[i].phys_addr_acdb_values);
goto error;
}
acdb_cache_tx[i].virt_addr_acdb_values =
acdb_cache_tx[i].map_v_addr;
memset(acdb_cache_tx[i].virt_addr_acdb_values, 0,
ACDB_BUF_SIZE);
}
return result;
error:
for (err = 0; err < i; err++) {
iounmap(acdb_cache_tx[err].map_v_addr);
free_contiguous_memory_by_paddr(
acdb_cache_tx[err].phys_addr_acdb_values);
}
return result;
}
static u32 allocate_memory_acdb_cache_rx(void)
{
u32 result = 0;
u32 i = 0;
u32 err = 0;
/*initialize local cache */
for (i = 0; i < MAX_COPP_NODE_SUPPORTED; i++) {
acdb_cache_rx[i].phys_addr_acdb_values =
allocate_contiguous_ebi_nomap(
ACDB_BUF_SIZE, SZ_4K);
if (!acdb_cache_rx[i].phys_addr_acdb_values) {
MM_ERR("ACDB=> Can not allocate physical memory\n");
result = -ENOMEM;
goto error;
}
acdb_cache_rx[i].map_v_addr =
ioremap(acdb_cache_rx[i].phys_addr_acdb_values,
ACDB_BUF_SIZE);
if (IS_ERR(acdb_cache_rx[i].map_v_addr)) {
MM_ERR("ACDB=> Could not map physical address\n");
result = -ENOMEM;
free_contiguous_memory_by_paddr(
acdb_cache_rx[i].phys_addr_acdb_values);
goto error;
}
acdb_cache_rx[i].virt_addr_acdb_values =
acdb_cache_rx[i].map_v_addr;
memset(acdb_cache_rx[i].virt_addr_acdb_values, 0,
ACDB_BUF_SIZE);
}
return result;
error:
for (err = 0; err < i; err++) {
iounmap(acdb_cache_rx[err].map_v_addr);
free_contiguous_memory_by_paddr(
acdb_cache_rx[err].phys_addr_acdb_values);
}
return result;
}
static u32 allocate_memory_acdb_get_blk(void)
{
u32 result = 0;
acdb_data.get_blk_paddr = allocate_contiguous_ebi_nomap(
ACDB_BUF_SIZE, SZ_4K);
if (!acdb_data.get_blk_paddr) {
MM_ERR("ACDB=> Cannot allocate physical memory\n");
result = -ENOMEM;
goto error;
}
acdb_data.map_v_get_blk = ioremap(acdb_data.get_blk_paddr,
ACDB_BUF_SIZE);
if (IS_ERR(acdb_data.map_v_get_blk)) {
MM_ERR("ACDB=> Could not map physical address\n");
result = -ENOMEM;
free_contiguous_memory_by_paddr(
acdb_data.get_blk_paddr);
goto error;
}
acdb_data.get_blk_kvaddr = acdb_data.map_v_get_blk;
memset(acdb_data.get_blk_kvaddr, 0, ACDB_BUF_SIZE);
error:
return result;
}
static void free_memory_acdb_cache_rx(void)
{
u32 i = 0;
for (i = 0; i < MAX_COPP_NODE_SUPPORTED; i++) {
iounmap(acdb_cache_rx[i].map_v_addr);
free_contiguous_memory_by_paddr(
acdb_cache_rx[i].phys_addr_acdb_values);
}
}
static void free_memory_acdb_cache_tx(void)
{
u32 i = 0;
for (i = 0; i < MAX_AUDREC_SESSIONS; i++) {
iounmap(acdb_cache_tx[i].map_v_addr);
free_contiguous_memory_by_paddr(
acdb_cache_tx[i].phys_addr_acdb_values);
}
}
static void free_memory_acdb_get_blk(void)
{
iounmap(acdb_data.map_v_get_blk);
free_contiguous_memory_by_paddr(acdb_data.get_blk_paddr);
}
static s32 initialize_memory(void)
{
s32 result = 0;
result = allocate_memory_acdb_get_blk();
if (result < 0) {
MM_ERR("memory allocation for get blk failed\n");
goto done;
}
result = allocate_memory_acdb_cache_rx();
if (result < 0) {
MM_ERR("memory allocation for rx cache is failed\n");
free_memory_acdb_get_blk();
goto done;
}
result = allocate_memory_acdb_cache_tx();
if (result < 0) {
MM_ERR("memory allocation for tx cache is failed\n");
free_memory_acdb_get_blk();
free_memory_acdb_cache_rx();
goto done;
}
acdb_data.pp_iir = kmalloc(sizeof(*acdb_data.pp_iir),
GFP_KERNEL);
if (acdb_data.pp_iir == NULL) {
MM_ERR("ACDB=> Could not allocate postproc iir memory\n");
free_memory_acdb_get_blk();
free_memory_acdb_cache_rx();
free_memory_acdb_cache_tx();
result = -ENOMEM;
goto done;
}
acdb_data.pp_mbadrc = kmalloc(sizeof(*acdb_data.pp_mbadrc), GFP_KERNEL);
if (acdb_data.pp_mbadrc == NULL) {
MM_ERR("ACDB=> Could not allocate postproc mbadrc memory\n");
free_memory_acdb_get_blk();
free_memory_acdb_cache_rx();
free_memory_acdb_cache_tx();
kfree(acdb_data.pp_iir);
result = -ENOMEM;
goto done;
}
acdb_data.calib_gain_rx = kmalloc(sizeof(*acdb_data.calib_gain_rx),
GFP_KERNEL);
if (acdb_data.calib_gain_rx == NULL) {
MM_ERR("ACDB=> Could not allocate"
" postproc calib_gain_rx memory\n");
free_memory_acdb_get_blk();
free_memory_acdb_cache_rx();
free_memory_acdb_cache_tx();
kfree(acdb_data.pp_iir);
kfree(acdb_data.pp_mbadrc);
result = -ENOMEM;
goto done;
}
acdb_data.preproc_agc = kmalloc(sizeof(*acdb_data.preproc_agc),
GFP_KERNEL);
if (acdb_data.preproc_agc == NULL) {
MM_ERR("ACDB=> Could not allocate preproc agc memory\n");
free_memory_acdb_get_blk();
free_memory_acdb_cache_rx();
free_memory_acdb_cache_tx();
kfree(acdb_data.pp_iir);
kfree(acdb_data.pp_mbadrc);
kfree(acdb_data.calib_gain_rx);
result = -ENOMEM;
goto done;
}
acdb_data.preproc_iir = kmalloc(sizeof(*acdb_data.preproc_iir),
GFP_KERNEL);
if (acdb_data.preproc_iir == NULL) {
MM_ERR("ACDB=> Could not allocate preproc iir memory\n");
free_memory_acdb_get_blk();
free_memory_acdb_cache_rx();
free_memory_acdb_cache_tx();
kfree(acdb_data.pp_iir);
kfree(acdb_data.pp_mbadrc);
kfree(acdb_data.calib_gain_rx);
kfree(acdb_data.preproc_agc);
result = -ENOMEM;
goto done;
}
acdb_data.calib_gain_tx = kmalloc(sizeof(*acdb_data.calib_gain_tx),
GFP_KERNEL);
if (acdb_data.calib_gain_tx == NULL) {
MM_ERR("ACDB=> Could not allocate"
" preproc calib_gain_tx memory\n");
free_memory_acdb_get_blk();
free_memory_acdb_cache_rx();
free_memory_acdb_cache_tx();
kfree(acdb_data.pp_iir);
kfree(acdb_data.pp_mbadrc);
kfree(acdb_data.calib_gain_rx);
kfree(acdb_data.preproc_agc);
kfree(acdb_data.preproc_iir);
result = -ENOMEM;
goto done;
}
acdb_data.pbe_block = kmalloc(sizeof(*acdb_data.pbe_block),
GFP_KERNEL);
if (acdb_data.pbe_block == NULL) {
MM_ERR("ACDB=> Could not allocate pbe_block memory\n");
free_memory_acdb_get_blk();
free_memory_acdb_cache_rx();
free_memory_acdb_cache_tx();
kfree(acdb_data.pp_iir);
kfree(acdb_data.pp_mbadrc);
kfree(acdb_data.calib_gain_rx);
kfree(acdb_data.preproc_agc);
kfree(acdb_data.preproc_iir);
kfree(acdb_data.calib_gain_tx);
result = -ENOMEM;
goto done;
}
acdb_data.pbe_extbuff = (u16 *) allocate_contiguous_ebi_nomap(
PBE_BUF_SIZE, SZ_4K);
if (!acdb_data.pbe_extbuff) {
MM_ERR("ACDB=> Cannot allocate physical memory\n");
free_memory_acdb_get_blk();
free_memory_acdb_cache_rx();
free_memory_acdb_cache_tx();
kfree(acdb_data.pp_iir);
kfree(acdb_data.pp_mbadrc);
kfree(acdb_data.calib_gain_rx);
kfree(acdb_data.preproc_agc);
kfree(acdb_data.preproc_iir);
kfree(acdb_data.calib_gain_tx);
kfree(acdb_data.pbe_block);
result = -ENOMEM;
goto done;
}
acdb_data.fluence_extbuff = allocate_contiguous_ebi_nomap(
FLUENCE_BUF_SIZE, SZ_4K);
if (!acdb_data.fluence_extbuff) {
MM_ERR("ACDB=> cannot allocate physical memory for "
"fluence block\n");
free_memory_acdb_get_blk();
free_memory_acdb_cache_rx();
free_memory_acdb_cache_tx();
kfree(acdb_data.pp_iir);
kfree(acdb_data.pp_mbadrc);
kfree(acdb_data.calib_gain_rx);
kfree(acdb_data.preproc_agc);
kfree(acdb_data.preproc_iir);
kfree(acdb_data.calib_gain_tx);
kfree(acdb_data.pbe_block);
free_contiguous_memory_by_paddr((int32_t)acdb_data.pbe_extbuff);
result = -ENOMEM;
goto done;
}
acdb_data.map_v_fluence = ioremap(
acdb_data.fluence_extbuff,
FLUENCE_BUF_SIZE);
if (IS_ERR(acdb_data.map_v_fluence)) {
MM_ERR("ACDB=> Could not map physical address\n");
free_memory_acdb_get_blk();
free_memory_acdb_cache_rx();
free_memory_acdb_cache_tx();
kfree(acdb_data.pp_iir);
kfree(acdb_data.pp_mbadrc);
kfree(acdb_data.calib_gain_rx);
kfree(acdb_data.preproc_agc);
kfree(acdb_data.preproc_iir);
kfree(acdb_data.calib_gain_tx);
kfree(acdb_data.pbe_block);
free_contiguous_memory_by_paddr(
(int32_t)acdb_data.pbe_extbuff);
free_contiguous_memory_by_paddr(
(int32_t)acdb_data.fluence_extbuff);
result = -ENOMEM;
goto done;
} else
acdb_data.fluence_extbuff_virt =
acdb_data.map_v_fluence;
done:
return result;
}
static u32 free_acdb_cache_node(union auddev_evt_data *evt)
{
u32 session_id;
if ((evt->audcal_info.dev_type & TX_DEVICE) == 2) {
/*Second argument to find_first_bit should be maximum number
of bits interested
*/
session_id = find_first_bit(
(unsigned long *)&(evt->audcal_info.sessions),
sizeof(evt->audcal_info.sessions) * 8);
MM_DBG("freeing node %d for tx device", session_id);
acdb_cache_tx[session_id].
node_status = ACDB_VALUES_NOT_FILLED;
} else {
MM_DBG("freeing rx cache node %d\n",
evt->audcal_info.dev_id);
acdb_cache_rx[evt->audcal_info.dev_id].
node_status = ACDB_VALUES_NOT_FILLED;
}
return 0;
}
static u8 check_device_change(struct auddev_evt_audcal_info audcal_info)
{
if (!acdb_data.device_info) {
MM_ERR("not pointing to previous valid device detail\n");
return 1; /*device info will not be pointing to*/
/* valid device when acdb driver comes up*/
}
if ((audcal_info.dev_id == acdb_data.device_info->dev_id) &&
(audcal_info.sample_rate ==
acdb_data.device_info->sample_rate) &&
(audcal_info.acdb_id == acdb_data.device_info->acdb_id)) {
return 0;
}
return 1;
}
static void device_cb(u32 evt_id, union auddev_evt_data *evt, void *private)
{
struct auddev_evt_audcal_info audcal_info;
struct acdb_cache_node *acdb_cache_free_node = NULL;
u32 stream_id = 0;
u8 ret = 0;
u8 count = 0;
u8 i = 0;
u8 device_change = 0;
if (!((evt_id == AUDDEV_EVT_DEV_RDY) ||
(evt_id == AUDDEV_EVT_DEV_RLS))) {
goto done;
}
/*if session value is zero it indicates that device call back is for
voice call we will drop the request as acdb values for voice call is
not applied from acdb driver*/
if (!evt->audcal_info.sessions) {
MM_DBG("no active sessions and call back is for"
" voice call\n");
goto done;
}
if (evt_id == AUDDEV_EVT_DEV_RLS) {
MM_DBG("got release command for dev %d\n",
evt->audcal_info.dev_id);
acdb_data.acdb_state &= ~CAL_DATA_READY;
free_acdb_cache_node(evt);
/*reset the applied flag for the session routed to the device*/
acdb_data.audrec_applied &= ~(evt->audcal_info.sessions
<< AUDREC_OFFSET);
goto done;
}
if (((evt->audcal_info.dev_type & RX_DEVICE) == 1) &&
(evt->audcal_info.acdb_id == PSEUDO_ACDB_ID)) {
MM_INFO("device cb is for rx device with pseudo acdb id\n");
goto done;
}
audcal_info = evt->audcal_info;
MM_DBG("dev_id = %d\n", audcal_info.dev_id);
MM_DBG("sample_rate = %d\n", audcal_info.sample_rate);
MM_DBG("acdb_id = %d\n", audcal_info.acdb_id);
MM_DBG("sessions = %d\n", audcal_info.sessions);
MM_DBG("acdb_state = %x\n", acdb_data.acdb_state);
mutex_lock(&acdb_data.acdb_mutex);
device_change = check_device_change(audcal_info);
if (!device_change) {
if ((audcal_info.dev_type & TX_DEVICE) == 2) {
if (!(acdb_data.acdb_state & AUDREC0_READY))
acdb_data.audrec_applied &= ~AUDREC0_READY;
if (!(acdb_data.acdb_state & AUDREC1_READY))
acdb_data.audrec_applied &= ~AUDREC1_READY;
if (!(acdb_data.acdb_state & AUDREC2_READY))
acdb_data.audrec_applied &= ~AUDREC2_READY;
acdb_data.acdb_state &= ~CAL_DATA_READY;
goto update_cache;
}
} else
/* state is updated to querry the modem for values */
acdb_data.acdb_state &= ~CAL_DATA_READY;
update_cache:
if ((audcal_info.dev_type & TX_DEVICE) == 2) {
/*loop is to take care of use case:- multiple Audrec
sessions are routed before enabling the device in this use
case we will get the sessions value as bits set for all the
sessions routed before device enable, so we should take care
of copying device info to all the sessions*/
for (i = 0; i < MAX_AUDREC_SESSIONS; i++) {
stream_id = ((audcal_info.sessions >> i) & 0x01);
if (stream_id) {
acdb_cache_free_node = &acdb_cache_tx[i];
ret = check_device_info_already_present(
audcal_info,
acdb_cache_free_node);
acdb_cache_free_node->stream_id = i;
acdb_data.cur_tx_session = i;
count++;
}
}
if (count > 1)
acdb_data.multiple_sessions = 1;
} else {
acdb_cache_free_node = &acdb_cache_rx[audcal_info.dev_id];
ret = check_device_info_already_present(audcal_info,
acdb_cache_free_node);
if (ret == 1) {
MM_DBG("got device ready call back for another "
"audplay task sessions on same COPP\n");
/*stream_id is used to keep track of number of active*/
/*sessions active on this device*/
acdb_cache_free_node->stream_id++;
mutex_unlock(&acdb_data.acdb_mutex);
goto done;
}
acdb_cache_free_node->stream_id++;
}
update_acdb_data_struct(acdb_cache_free_node);
acdb_data.device_cb_compl = 1;
mutex_unlock(&acdb_data.acdb_mutex);
wake_up(&acdb_data.wait);
done:
return;
}
static s32 register_device_cb(void)
{
s32 result = 0;
result = auddev_register_evt_listner((AUDDEV_EVT_DEV_RDY
| AUDDEV_EVT_DEV_RLS),
AUDDEV_CLNT_AUDIOCAL, 0, device_cb, (void *)&acdb_data);
if (result) {
MM_ERR("ACDB=> Could not register device callback\n");
result = -ENODEV;
goto done;
}
done:
return result;
}
static void audpp_cb(void *private, u32 id, u16 *msg)
{
MM_DBG("\n");
if (id != AUDPP_MSG_CFG_MSG)
goto done;
if (msg[0] == AUDPP_MSG_ENA_DIS) {
if (--acdb_cache_rx[acdb_data.\
device_info->dev_id].stream_id <= 0) {
acdb_data.acdb_state &= ~AUDPP_READY;
acdb_cache_rx[acdb_data.device_info->dev_id]\
.stream_id = 0;
MM_DBG("AUDPP_MSG_ENA_DIS\n");
}
goto done;
}
acdb_data.acdb_state |= AUDPP_READY;
acdb_data.audpp_cb_compl = 1;
wake_up(&acdb_data.wait);
done:
return;
}
static s8 handle_audpreproc_cb(void)
{
struct acdb_cache_node *acdb_cached_values;
s8 result = 0;
u8 stream_id = acdb_data.preproc_stream_id;
acdb_data.preproc_cb_compl = 0;
acdb_cached_values = get_acdb_values_from_cache_tx(stream_id);
if (acdb_cached_values == NULL) {
MM_DBG("ERROR: to get chached acdb values\n");
return -EPERM;
}
update_acdb_data_struct(acdb_cached_values);
if (acdb_data.device_info->dev_id == PSEUDO_ACDB_ID) {
MM_INFO("audpreproc is routed to pseudo device\n");
return result;
}
if (acdb_data.build_id[17] == '1') {
if (session_info[stream_id].sampling_freq)
acdb_data.device_info->sample_rate =
session_info[stream_id].sampling_freq;
}
if (!(acdb_data.acdb_state & CAL_DATA_READY)) {
result = check_tx_acdb_values_cached();
if (result) {
result = acdb_get_calibration();
if (result < 0) {
MM_ERR("failed to get calibration data\n");
return result;
}
}
acdb_cached_values->node_status = ACDB_VALUES_FILLED;
}
return result;
}
void fluence_feature_update(int enable, int stream_id)
{
MM_INFO("Fluence feature over ride with = %d\n", enable);
acdb_data.fleuce_feature_status[stream_id] = enable;
}
EXPORT_SYMBOL(fluence_feature_update);
static void audpreproc_cb(void *private, u32 id, void *msg)
{
struct audpreproc_cmd_enc_cfg_done_msg *tmp;
u8 result = 0;
int stream_id = 0;
if (id != AUDPREPROC_CMD_ENC_CFG_DONE_MSG)
goto done;
tmp = (struct audpreproc_cmd_enc_cfg_done_msg *)msg;
acdb_data.preproc_stream_id = tmp->stream_id;
stream_id = acdb_data.preproc_stream_id;
get_audrec_session_info(stream_id, &session_info[stream_id]);
MM_DBG("rec_enc_type = %x\n", tmp->rec_enc_type);
if ((tmp->rec_enc_type & 0x8000) ==
AUD_PREPROC_CONFIG_DISABLED) {
if (acdb_data.preproc_stream_id == 0) {
acdb_data.acdb_state &= ~AUDREC0_READY;
acdb_data.audrec_applied &= ~AUDREC0_READY;
} else if (acdb_data.preproc_stream_id == 1) {
acdb_data.acdb_state &= ~AUDREC1_READY;
acdb_data.audrec_applied &= ~AUDREC1_READY;
} else if (acdb_data.preproc_stream_id == 2) {
acdb_data.acdb_state &= ~AUDREC2_READY;
acdb_data.audrec_applied &= ~AUDREC2_READY;
}
acdb_data.fleuce_feature_status[stream_id] = 0;
acdb_cache_tx[tmp->stream_id].node_status =\
ACDB_VALUES_NOT_FILLED;
acdb_data.acdb_state &= ~CAL_DATA_READY;
goto done;
}
/*Following check is added to make sure that device info
is updated. audpre proc layer enabled without device
callback at this scenario we should not access
device information
*/
if (acdb_data.build_id[17] != '0') {
if (acdb_data.device_info &&
session_info[stream_id].sampling_freq) {
acdb_data.device_info->sample_rate =
session_info[stream_id].sampling_freq;
result = check_tx_acdb_values_cached();
if (!result) {
MM_INFO("acdb values for the stream is" \
" querried from modem");
acdb_data.acdb_state |= CAL_DATA_READY;
} else {
acdb_data.acdb_state &= ~CAL_DATA_READY;
}
}
}
if (acdb_data.preproc_stream_id == 0)
acdb_data.acdb_state |= AUDREC0_READY;
else if (acdb_data.preproc_stream_id == 1)
acdb_data.acdb_state |= AUDREC1_READY;
else if (acdb_data.preproc_stream_id == 2)
acdb_data.acdb_state |= AUDREC2_READY;
acdb_data.preproc_cb_compl = 1;
MM_DBG("acdb_data.acdb_state = %x\n", acdb_data.acdb_state);
wake_up(&acdb_data.wait);
done:
return;
}
static s32 register_audpp_cb(void)
{
s32 result = 0;
acdb_data.audpp_cb.fn = audpp_cb;
acdb_data.audpp_cb.private = NULL;
result = audpp_register_event_callback(&acdb_data.audpp_cb);
if (result) {
MM_ERR("ACDB=> Could not register audpp callback\n");
result = -ENODEV;
goto done;
}
done:
return result;
}
static s32 register_audpreproc_cb(void)
{
s32 result = 0;
acdb_data.audpreproc_cb.fn = audpreproc_cb;
acdb_data.audpreproc_cb.private = NULL;
result = audpreproc_register_event_callback(&acdb_data.audpreproc_cb);
if (result) {
MM_ERR("ACDB=> Could not register audpreproc callback\n");
result = -ENODEV;
goto done;
}
done:
return result;
}
static s32 acdb_initialize_data(void)
{
s32 result = 0;
mutex_init(&acdb_data.acdb_mutex);
result = initialize_rpc();
if (result)
goto err;
result = initialize_memory();
if (result)
goto err1;
result = register_device_cb();
if (result)
goto err2;
result = register_audpp_cb();
if (result)
goto err3;
result = register_audpreproc_cb();
if (result)
goto err4;
return result;
err4:
result = audpreproc_unregister_event_callback(&acdb_data.audpreproc_cb);
if (result)
MM_ERR("ACDB=> Could not unregister audpreproc callback\n");
err3:
result = audpp_unregister_event_callback(&acdb_data.audpp_cb);
if (result)
MM_ERR("ACDB=> Could not unregister audpp callback\n");
err2:
result = auddev_unregister_evt_listner(AUDDEV_CLNT_AUDIOCAL, 0);
if (result)
MM_ERR("ACDB=> Could not unregister device callback\n");
err1:
daldevice_detach(acdb_data.handle);
acdb_data.handle = NULL;
err:
return result;
}
static s32 initialize_modem_acdb(void)
{
struct acdb_cmd_init_adie acdb_cmd;
u8 codec_type = -1;
s32 result = 0;
u8 iterations = 0;
codec_type = adie_get_detected_codec_type();
if (codec_type == MARIMBA_ID)
acdb_cmd.adie_type = ACDB_CURRENT_ADIE_MODE_MARIMBA;
else if (codec_type == TIMPANI_ID)
acdb_cmd.adie_type = ACDB_CURRENT_ADIE_MODE_TIMPANI;
else
acdb_cmd.adie_type = ACDB_CURRENT_ADIE_MODE_UNKNOWN;
acdb_cmd.command_id = ACDB_CMD_INITIALIZE_FOR_ADIE;
do {
/*Initialize ACDB software on modem based on codec type*/
result = dalrpc_fcn_8(ACDB_DalACDB_ioctl, acdb_data.handle,
(const void *)&acdb_cmd, sizeof(acdb_cmd),
&acdb_data.acdb_result,
sizeof(acdb_data.acdb_result));
if (result < 0) {
MM_ERR("ACDB=> RPC failure result = %d\n", result);
goto error;
}
/*following check is introduced to handle boot up race
condition between AUDCAL SW peers running on apps
and modem (ACDB_RES_BADSTATE indicates modem AUDCAL SW is
not in initialized sate) we need to retry to get ACDB
initialized*/
if (acdb_data.acdb_result.result == ACDB_RES_BADSTATE) {
msleep(500);
iterations++;
} else if (acdb_data.acdb_result.result == ACDB_RES_SUCCESS) {
MM_DBG("Modem ACDB SW initialized ((iterations = %d)\n",
iterations);
return result;
} else {
MM_ERR("ACDB=> Modem ACDB SW failed to initialize"
" reuslt = %d, (iterations = %d)\n",
acdb_data.acdb_result.result,
iterations);
goto error;
}
} while (iterations < MAX_RETRY);
MM_ERR("ACDB=> AUDCAL SW on modem is not in intiailized state (%d)\n",
acdb_data.acdb_result.result);
error:
result = -EINVAL;
return result;
}
static s32 acdb_calibrate_device(void *data)
{
s32 result = 0;
/* initialize driver */
result = acdb_initialize_data();
if (result)
goto done;
if (acdb_data.build_id[17] != '0') {
result = initialize_modem_acdb();
if (result < 0)
MM_ERR("failed to initialize modem ACDB\n");
}
while (!kthread_should_stop()) {
MM_DBG("Waiting for call back events\n");
wait_event_interruptible(acdb_data.wait,
(acdb_data.device_cb_compl
| acdb_data.audpp_cb_compl
| acdb_data.preproc_cb_compl));
mutex_lock(&acdb_data.acdb_mutex);
if (acdb_data.device_cb_compl) {
acdb_data.device_cb_compl = 0;
if (!(acdb_data.acdb_state & CAL_DATA_READY)) {
if ((acdb_data.device_info->dev_type
& RX_DEVICE) == 1) {
/*we need to get calibration values
only for RX device as resampler
moved to start of the pre - proc chain
tx calibration value will be based on
sampling frequency what audrec is
configured, calibration values for tx
device are fetch in audpreproc
callback*/
result = acdb_get_calibration();
if (result < 0) {
mutex_unlock(
&acdb_data.acdb_mutex);
MM_ERR("Not able to get "
"calibration "
"data continue\n");
continue;
}
}
}
MM_DBG("acdb state = %d\n",
acdb_data.acdb_state);
if ((acdb_data.device_info->dev_type & TX_DEVICE) == 2)
handle_tx_device_ready_callback();
else {
acdb_cache_rx[acdb_data.device_info->dev_id]\
.node_status =
ACDB_VALUES_FILLED;
if (acdb_data.acdb_state &
AUDPP_READY) {
MM_DBG("AUDPP already enabled "
"apply acdb values\n");
goto apply;
}
}
}
if (!(acdb_data.audpp_cb_compl ||
acdb_data.preproc_cb_compl)) {
MM_DBG("need to wait for either AUDPP / AUDPREPROC "
"Event\n");
mutex_unlock(&acdb_data.acdb_mutex);
continue;
} else {
MM_DBG("got audpp / preproc call back\n");
if (acdb_data.audpp_cb_compl) {
send_acdb_values_for_active_devices();
acdb_data.audpp_cb_compl = 0;
mutex_unlock(&acdb_data.acdb_mutex);
continue;
} else {
result = handle_audpreproc_cb();
if (result < 0) {
mutex_unlock(&acdb_data.acdb_mutex);
continue;
}
}
}
apply:
if (acdb_data.acdb_state & CAL_DATA_READY)
result = acdb_send_calibration();
mutex_unlock(&acdb_data.acdb_mutex);
}
done:
return 0;
}
static int __init acdb_init(void)
{
s32 result = 0;
memset(&acdb_data, 0, sizeof(acdb_data));
spin_lock_init(&acdb_data.dsp_lock);
acdb_data.cb_thread_task = kthread_run(acdb_calibrate_device,
NULL, "acdb_cb_thread");
if (IS_ERR(acdb_data.cb_thread_task)) {
MM_ERR("ACDB=> Could not register cb thread\n");
result = -ENODEV;
goto err;
}
acdb_data.build_id = socinfo_get_build_id();
MM_INFO("build id used is = %s\n", acdb_data.build_id);
#ifdef CONFIG_DEBUG_FS
/*This is RTC specific INIT used only with debugfs*/
if (!rtc_acdb_init())
MM_ERR("RTC ACDB=>INIT Failure\n");
#endif
init_waitqueue_head(&acdb_data.wait);
return misc_register(&acdb_misc);
err:
return result;
}
static void __exit acdb_exit(void)
{
s32 result = 0;
u32 i = 0;
result = auddev_unregister_evt_listner(AUDDEV_CLNT_AUDIOCAL, 0);
if (result)
MM_ERR("ACDB=> Could not unregister device callback\n");
result = audpp_unregister_event_callback(&acdb_data.audpp_cb);
if (result)
MM_ERR("ACDB=> Could not unregister audpp callback\n");
result = audpreproc_unregister_event_callback(&acdb_data.\
audpreproc_cb);
if (result)
MM_ERR("ACDB=> Could not unregister audpreproc callback\n");
result = kthread_stop(acdb_data.cb_thread_task);
if (result)
MM_ERR("ACDB=> Could not stop kthread\n");
free_memory_acdb_get_blk();
for (i = 0; i < MAX_COPP_NODE_SUPPORTED; i++) {
if (i < MAX_AUDREC_SESSIONS) {
iounmap(acdb_cache_tx[i].map_v_addr);
free_contiguous_memory_by_paddr(
acdb_cache_tx[i].phys_addr_acdb_values);
}
iounmap(acdb_cache_rx[i].map_v_addr);
free_contiguous_memory_by_paddr(
acdb_cache_rx[i].phys_addr_acdb_values);
}
kfree(acdb_data.device_info);
kfree(acdb_data.pp_iir);
kfree(acdb_data.pp_mbadrc);
kfree(acdb_data.preproc_agc);
kfree(acdb_data.preproc_iir);
free_contiguous_memory_by_paddr(
(int32_t)acdb_data.pbe_extbuff);
iounmap(acdb_data.map_v_fluence);
free_contiguous_memory_by_paddr(
(int32_t)acdb_data.fluence_extbuff);
mutex_destroy(&acdb_data.acdb_mutex);
memset(&acdb_data, 0, sizeof(acdb_data));
#ifdef CONFIG_DEBUG_FS
rtc_acdb_deinit();
#endif
}
late_initcall(acdb_init);
module_exit(acdb_exit);
MODULE_DESCRIPTION("MSM 7x30 Audio ACDB driver");
MODULE_LICENSE("GPL v2");