Files
threeeye bc1d038eac REVVL 6 Pro kernel bring-up: full working tree snapshot (2026-09-12)
Squashed backup commit (no shallow-clone history issues) of
xiaomi-mt6833-dev/kernel_xiaomi_mt6833 (lineage-23.2 branch, upstream
commit 9eece662e) plus all fixes applied to get everpal_defconfig building
clean against a modern (GCC 15.2.0) toolchain -- see the previous commit
message on the lineage-23.2 branch (also in this repo history is not
available here since this is a squashed snapshot; full incremental history
lives in the local DL380 checkout and the upstream GitHub remote).

Upstream: https://github.com/xiaomi-mt6833-dev/kernel_xiaomi_mt6833 (lineage-23.2)
2026-09-12 13:36:46 +00:00

1039 lines
25 KiB
C

/*
* Copyright (C) 2018, SI-IN, Yun Shi (yun.shi@si-in.com).
*
* 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.
*/
//#define DEBUG
#define LOG_FLAG "sia81xx_afe"
#include <linux/slab.h>
#include <linux/wait.h>
//#include <linux/wakelock.h>
#include <linux/jiffies.h>
#include <linux/version.h>
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4,4,1))
#include <dsp/msm_audio_ion.h>
#include <dsp/q6afe-v2.h>
#include <dsp/q6audio-v2.h>
#else
#include <linux/msm_audio_ion.h>
#include <sound/q6afe-v2.h>
#include <sound/q6audio-v2.h>
#endif
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4,14,0))
#include <ipc/apr.h>
#endif
#include "sia81xx_tuning_if.h"
#define TIMEOUT_MS (1000) /* the same to q6afe.c */
#define CAL_BLOCK_MAP_SIZE (SZ_4K)
static DEFINE_MUTEX(sia81xx_afe_list_mutex);
static LIST_HEAD(sia81xx_afe_list);
struct sia81xx_cal_block_data {
#if (LINUX_VERSION_CODE > KERNEL_VERSION(4,11,12))
/* although now, the field is "struct dma_buf *",
* but maybe after linux 5.1.x, this field while be changed to "int fd"
* so, let this field as "long long" type for compatible consider */
long long fd;
#else
struct ion_client *ion_client;
struct ion_handle *ion_handle;
#endif
void *kvaddr;
phys_addr_t paddr;
size_t pa_size;
uint32_t dsp_mmap_handle;
};
typedef struct sia81xx_afe {
uint16_t afe_port_id;
void *apr;
wait_queue_head_t wait;
atomic_t state;
struct sia81xx_cal_block_data cal_block;
struct list_head list;
struct mutex afe_lock;
}SIA81XX_AFE;
/* unknown qcom modify apr_audio at which kernel version,
* but must been modified at 4.14.0 + */
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4,14,0))
typedef struct afe_port_cmd_set_param_v2 afe_cmd_sia81xx_set_cal;
typedef struct afe_port_cmd_get_param_v2 afe_cmd_sia81xx_get_cal;
typedef struct param_hdr_v1 afe_cmd_sia81xx_param_payload;
#else
typedef struct __afe_cmd_sia81xx_set_cal {
struct apr_hdr hdr;
struct afe_port_cmd_set_param_v2 param;
}__packed afe_cmd_sia81xx_set_cal;
typedef struct __afe_cmd_sia81xx_get_cal {
struct apr_hdr hdr;
struct afe_port_cmd_get_param_v2 param;
}__packed afe_cmd_sia81xx_get_cal;
typedef struct afe_port_param_data_v2 afe_cmd_sia81xx_param_payload;
#endif
typedef struct __afe_cmd_sia81xx_set_mmap {
struct afe_service_cmd_shared_mem_map_regions regions;
struct afe_service_shared_map_region_payload payload;
}__packed afe_cmd_sia81xx_set_mmap;
#ifdef SIA81XX_COMPILE_TO_MODULE
extern struct apr_svc *apr_register(
char *dest,
char *svc_name,
apr_fn svc_fn,
uint32_t src_port,
void *priv);
extern int apr_send_pkt(
void *handle,
uint32_t *buf);
extern int msm_audio_ion_alloc(
struct dma_buf **dma_buf,
size_t bufsz,
dma_addr_t *paddr,
size_t *plen,
void **vaddr);
extern int msm_audio_ion_free(
struct dma_buf *dma_buf);
extern int apr_deregister(
void *handle);
#endif
static int sia81xx_apr_cmd_memory_map(SIA81XX_AFE *afe);
static int afe_port_to_apr_port(
uint16_t afe_port)
{
/* range: 0x10 ~ APR_MAX_PORTS£¬ to avoid the port : 0x00 */
return (afe_port % (APR_MAX_PORTS - 0x10)) + 0x10;
}
static int sia81xx_fill_apr_hdr(
struct apr_hdr *apr_hdr,
uint32_t port,
uint32_t opcode,
uint32_t apr_msg_size)
{
if (apr_hdr == NULL) {
pr_err("[ err][%s] %s: invalid APR pointer \r\n",
LOG_FLAG, __func__);
return -EINVAL;
}
apr_hdr->hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
apr_hdr->pkt_size = apr_msg_size; /* total len, include the hdr */
apr_hdr->src_svc = APR_SVC_AFE;
apr_hdr->src_domain = APR_DOMAIN_APPS;
apr_hdr->src_port = port; /* apr port id, dsp will use this value */
/*as dest_port when response this cmd */
apr_hdr->dest_svc = APR_SVC_AFE;
apr_hdr->dest_domain = APR_DOMAIN_ADSP;
apr_hdr->dest_port = 0;
apr_hdr->token = port;
apr_hdr->opcode = opcode;
return 0;
}
static int32_t sia81xx_afe_callback(
struct apr_client_data *data,
void *priv)
{
SIA81XX_AFE *afe = NULL;
if (!data) {
pr_err("[ err][%s] %s: invalid param data \r\n",
LOG_FLAG, __func__);
return -EINVAL;
}
if (!priv) {
pr_err("[ err][%s] %s: invalid param priv \r\n",
LOG_FLAG, __func__);
return -EINVAL;
}
/* priv must a SIA81XX_AFE type pointer */
afe = (SIA81XX_AFE *)priv;
if(RESET_EVENTS == data->opcode) {
pr_info("[ info][%s] %s: RESET_EVENTS, event : %d !! \r\n",
LOG_FLAG, __func__, (int)data->reset_event);
afe->cal_block.dsp_mmap_handle = 0;
if (afe->apr) {
apr_reset(afe->apr);
atomic_set(&afe->state, 0);
afe->apr = NULL;
}
}
switch(data->opcode) {
case AFE_SERVICE_CMDRSP_SHARED_MEM_MAP_REGIONS:
{
struct afe_service_cmdrsp_shared_mem_map_regions *payload = NULL;
if(!data->payload_size) {
pr_err("[ err][%s] %s: invalid payload_size = %d "
"with opcode = 0x%08x \r\n",
LOG_FLAG, __func__, data->payload_size, data->opcode);
break;
}
payload =
(struct afe_service_cmdrsp_shared_mem_map_regions *)data->payload;
afe->cal_block.dsp_mmap_handle = payload->mem_map_handle;
atomic_set(&afe->state, 0);
wake_up(&afe->wait);
break;
}
case AFE_PORT_CMDRSP_GET_PARAM_V2:
{
atomic_set(&afe->state, 0);
wake_up(&afe->wait);
break;
}
case APR_BASIC_RSP_RESULT:
{
uint32_t *payload = NULL;
if(!data->payload_size) {
pr_err("[ err][%s] %s: invalid payload_size = %d "
"with opcode = 0x%08x \r\n",
LOG_FLAG, __func__, data->payload_size, data->opcode);
break;
}
payload = (uint32_t *)data->payload;
switch (payload[0]) {
case AFE_PORT_CMD_SET_PARAM_V2 :
{
atomic_set(&afe->state, 0);
wake_up(&afe->wait);
break;
}
case AFE_SERVICE_CMD_SHARED_MEM_UNMAP_REGIONS :
{
afe->cal_block.dsp_mmap_handle = 0;
atomic_set(&afe->state, 0);
wake_up(&afe->wait);
break;
}
default :
{
pr_err("[ err][%s] %s: unknow payload[0] = 0x%08x "
"with opcode = 0x%08x \r\n",
LOG_FLAG, __func__, payload[0], data->opcode);
break;
}
}
break;
}
default :
{
pr_err("[ err][%s] %s: invalid opcode = 0x%08x \r\n",
LOG_FLAG, __func__, data->opcode);
break;
}
}
return 0;
}
static int sia81xx_apr_send(
SIA81XX_AFE *afe,
void *cmd)
{
int ret = 0;
/* is afe sending */
if (1 == atomic_read(&afe->state)) {
ret = -EBUSY;
goto err;
}
/* set afe useing flag */
atomic_set(&afe->state, 1);
/* sending the cmd as a apr msg */
ret = apr_send_pkt(afe->apr, (uint32_t *)cmd);
if (ret < 0) {
ret = -EINVAL;
goto err;
}
/* timeout protect, avoid wating forever */
if (!(wait_event_timeout(afe->wait,
(atomic_read(&afe->state) == 0),
msecs_to_jiffies(TIMEOUT_MS)))) {
ret = -ENOTBLK;
goto err;
}
return ret;
err:
pr_err("[ err][%s] %s: error ret = %d \r\n",
LOG_FLAG, __func__, ret);
return ret;
}
static int check_apr(
SIA81XX_AFE *afe)
{
int ret = 0;
if (NULL == afe->apr) {
afe->apr = apr_register("ADSP", "AFE", sia81xx_afe_callback,
afe_port_to_apr_port(afe->afe_port_id), afe);
if (NULL == afe->apr) {
pr_err("[ err][%s] %s: Unable to register AFE \r\n",
LOG_FLAG, __func__);
ret = -EINVAL;
}
}
return ret;
}
static int check_cal_block(
SIA81XX_AFE *afe)
{
int ret = 0;
#if (LINUX_VERSION_CODE > KERNEL_VERSION(4,11,12))
if (0 == afe->cal_block.fd) {
ret = msm_audio_ion_alloc((struct dma_buf **)(&(afe->cal_block.fd)),
CAL_BLOCK_MAP_SIZE, &(afe->cal_block.paddr),
&(afe->cal_block.pa_size), &(afe->cal_block.kvaddr));
#else
if (NULL == afe->cal_block.ion_handle) {
ret = msm_audio_ion_alloc("sia81xx_cal",
&(afe->cal_block.ion_client),
&(afe->cal_block.ion_handle), CAL_BLOCK_MAP_SIZE,
&(afe->cal_block.paddr), &(afe->cal_block.pa_size),
&(afe->cal_block.kvaddr));
#endif
if (ret < 0) {
pr_err("[ err][%s] %s: allocate buffer failed! ret = %d\n \r\n",
LOG_FLAG, __func__, ret);
goto err;
} else {
pr_info("[ info][%s] %s: afe[0x%04x] allocate buffer success! "
"pa_size = %zu \r\n",
LOG_FLAG, __func__, afe->afe_port_id,
afe->cal_block.pa_size);
}
}
if (0 == afe->cal_block.dsp_mmap_handle) {
ret = sia81xx_apr_cmd_memory_map(afe);
if (ret != 0) {
pr_err("[ err][%s] %s: map buffer failed! ret = %d\n \r\n",
LOG_FLAG, __func__, ret);
goto err;
} else {
pr_info("[ info][%s] %s: afe[0x%04x] map buffer success! "
"handle = 0x%08x \r\n",
LOG_FLAG, __func__, afe->afe_port_id,
afe->cal_block.dsp_mmap_handle);
}
}
return ret;
err:
return ret;
}
static int check_afe_port_id(
SIA81XX_AFE *afe)
{
int ret = 0;
if (afe_port_to_apr_port(afe->afe_port_id) >= APR_MAX_PORTS) {
pr_err("[ err][%s] %s: invalid AFE port = 0x%04x \r\n",
LOG_FLAG, __func__, afe->afe_port_id);
ret = -EINVAL;
}
return ret;
}
static inline int chack_afe_validity(
SIA81XX_AFE *afe)
{
if(NULL == afe) {
pr_err("[ err][%s] %s: NULL == afe !! \r\n",
LOG_FLAG, __func__);
return -EINVAL;
}
if(0 != check_apr(afe)) {
pr_err("[ err][%s] %s: check_apr failed !! \r\n",
LOG_FLAG, __func__);
return -EINVAL;
}
if(0 != check_cal_block(afe)) {
pr_err("[ err][%s] %s: check_cal_block failed !! \r\n",
LOG_FLAG, __func__);
return -EINVAL;
}
if (0 != check_afe_port_id(afe)) {
pr_err("[err][%s] %s: check_afe_port_id failed !! \r\n",
LOG_FLAG, __func__);
return -EINVAL;
}
return 0;
}
static void sia81xx_write_param_to_payload(
afe_cmd_sia81xx_param_payload *payload,
uint32_t module_id,
uint32_t param_id,
uint32_t param_size,
uint8_t *param)
{
payload->module_id = module_id;
payload->param_id = param_id;
payload->param_size = param_size;
payload->reserved = 0;
memcpy((void *)(payload + 1), param, payload->param_size);
}
static int sia81xx_read_param_from_payload(
afe_cmd_sia81xx_param_payload *payload,
uint32_t module_id,
uint32_t param_id,
uint32_t param_size,
uint8_t *param)
{
if(payload->module_id != module_id) {
pr_err("[ err][%s] %s: unmatched module_id 0x%08x, "
"payload->module_id 0x%08x \r\n",
LOG_FLAG, __func__, module_id, payload->module_id);
return -EINVAL;
}
if(payload->param_id != param_id) {
pr_err("[ err][%s] %s: unmatched param_id 0x%08x, "
"payload->param_id 0x%08x \r\n",
LOG_FLAG, __func__, param_id, payload->param_id);
return -EINVAL;
}
if(payload->param_size > param_size) {
pr_err("[ err][%s] %s: unmatched param_size 0x%08x, "
"payload->param_size 0x%08x \r\n",
LOG_FLAG, __func__, param_size, payload->param_size);
return -EINVAL;
}
memcpy(param, (void *)(payload + 1), payload->param_size);
return payload->param_size;
}
static int sia81xx_apr_cmd_memory_map(
SIA81XX_AFE *afe)
{
int ret = 0;
afe_cmd_sia81xx_set_mmap apr_cmd;
if(NULL == afe) {
pr_err("[ err][%s] %s: NULL == afe !! \r\n",
LOG_FLAG, __func__);
ret = -EINVAL;
goto err;
}
if(0 != check_apr(afe)) {
pr_err("[ err][%s] %s: check_apr failed !! \r\n",
LOG_FLAG, __func__);
ret = -EINVAL;
goto err;
}
/* clear cmd */
memset((void *)(&apr_cmd), 0x00, sizeof(apr_cmd));
/* fill cmd head */
sia81xx_fill_apr_hdr(&(apr_cmd.regions.hdr),
afe_port_to_apr_port(afe->afe_port_id),
AFE_SERVICE_CMD_SHARED_MEM_MAP_REGIONS, sizeof(apr_cmd));
/* fill cmd entity */
apr_cmd.regions.mem_pool_id = ADSP_MEMORY_MAP_SHMEM8_4K_POOL;
apr_cmd.regions.num_regions = 1;
apr_cmd.regions.property_flag = 0x00;
apr_cmd.payload.shm_addr_lsw = lower_32_bits(afe->cal_block.paddr);
apr_cmd.payload.shm_addr_msw =
msm_audio_populate_upper_32_bits(afe->cal_block.paddr);
apr_cmd.payload.mem_size_bytes = afe->cal_block.pa_size;
/* clear old dsp mmp value, and wait a new value return from dsp,
* if the cmd command success */
afe->cal_block.dsp_mmap_handle = 0;
/* send the cmd to dsp through apr, and wait dsp returned msg */
if(0 > sia81xx_apr_send(afe, &apr_cmd)) {
goto err;
}
pr_debug("[debug][%s] %s: dsp map success !! ret = %d \r\n",
LOG_FLAG, __func__, ret);
return ret;
err:
pr_err("[ err][%s] %s: error ret = %d \r\n",
LOG_FLAG, __func__, ret);
return ret;
}
static int sia81xx_apr_cmd_memory_unmap(
SIA81XX_AFE *afe)
{
int ret = 0;
struct afe_service_cmd_shared_mem_unmap_regions apr_cmd;
if(NULL == afe) {
pr_err("[ err][%s] %s: NULL == afe !! \r\n",
LOG_FLAG, __func__);
ret = -EINVAL;
goto err;
}
if(0 == afe->cal_block.dsp_mmap_handle)
return 0;
if(0 != check_apr(afe)) {
pr_err("[ err][%s] %s: check_apr failed !! \r\n",
LOG_FLAG, __func__);
ret = -EINVAL;
goto err;
}
/* clear cmd */
memset((void *)(&apr_cmd), 0x00, sizeof(apr_cmd));
/* fill cmd head */
sia81xx_fill_apr_hdr(
&(apr_cmd.hdr),
afe_port_to_apr_port(afe->afe_port_id),
AFE_SERVICE_CMD_SHARED_MEM_UNMAP_REGIONS,
sizeof(apr_cmd));
/* fill cmd entity */
apr_cmd.mem_map_handle = afe->cal_block.dsp_mmap_handle;
/* send the cmd to dsp through apr, and wait dsp returned msg */
if(0 > sia81xx_apr_send(afe, &apr_cmd)) {
goto err;
}
pr_debug("[debug][%s] %s: dsp unmap success !! ret = %d \r\n",
LOG_FLAG, __func__, ret);
return ret;
err:
pr_err("[ err][%s] %s: error ret = %d \r\n",
LOG_FLAG, __func__, ret);
return ret;
}
static unsigned int sia81xx_afe_list_count(void)
{
unsigned count = 0;
SIA81XX_AFE *afe = NULL;
mutex_lock(&sia81xx_afe_list_mutex);
list_for_each_entry(afe, &sia81xx_afe_list, list) {
count ++;
}
mutex_unlock(&sia81xx_afe_list_mutex);
return count;
}
static SIA81XX_AFE *find_sia81xx_afe_list(
uint16_t afe_port_id)
{
SIA81XX_AFE *afe = NULL;
mutex_lock(&sia81xx_afe_list_mutex);
list_for_each_entry(afe, &sia81xx_afe_list, list) {
if(afe_port_id == afe->afe_port_id) {
mutex_unlock(&sia81xx_afe_list_mutex);
return afe;
}
}
mutex_unlock(&sia81xx_afe_list_mutex);
return NULL;
}
static void add_sia81xx_afe_list(
SIA81XX_AFE *afe)
{
if(NULL == afe) {
pr_err("[ err][%s] %s: NULL == afe \r\n", LOG_FLAG, __func__);
return ;
}
if(NULL != find_sia81xx_afe_list(afe->afe_port_id))
return ;
mutex_lock(&sia81xx_afe_list_mutex);
list_add(&afe->list, &sia81xx_afe_list);
mutex_unlock(&sia81xx_afe_list_mutex);
pr_debug("[debug][%s] %s: add afe port id : %u, count = %u \r\n",
LOG_FLAG, __func__, afe->afe_port_id, sia81xx_afe_list_count());
}
static void del_sia81xx_afe_list(
SIA81XX_AFE *afe)
{
if(NULL == afe) {
pr_err("[ err][%s] %s: NULL == afe \r\n", LOG_FLAG, __func__);
return ;
}
pr_debug("[debug][%s] %s: del fe port id : %u, count = %u \r\n",
LOG_FLAG, __func__, afe->afe_port_id, sia81xx_afe_list_count());
mutex_lock(&sia81xx_afe_list_mutex);
list_del(&afe->list);
mutex_unlock(&sia81xx_afe_list_mutex);
}
int sia81xx_afe_send(
unsigned long afe_handle,
uint32_t module_id,
uint32_t param_id,
uint32_t param_size,
uint8_t *buf)
{
int ret = 0;
afe_cmd_sia81xx_set_cal apr_cmd;
SIA81XX_AFE *afe = (SIA81XX_AFE *)afe_handle;
if(NULL == afe)
return -EINVAL;
if(APR_SUBSYS_LOADED != apr_get_q6_state()) {
pr_err("[ err][%s] %s: q6_state : %u \r\n",
LOG_FLAG, __func__, (unsigned int)apr_get_q6_state());
return -EINVAL;
}
mutex_lock(&afe->afe_lock);
ret = chack_afe_validity(afe);
if(0 != ret) {
pr_err("[ err][%s] %s: chack_afe_validity failed !! \r\n",
LOG_FLAG, __func__);
goto err;
}
/* is the pa size has a capacity of holding the param */
if (param_size >
(afe->cal_block.pa_size- sizeof(afe_cmd_sia81xx_param_payload))) {
pr_err("[ err][%s] %s: invalid payload size = %d \r\n",
LOG_FLAG, __func__, param_size);
ret = -EINVAL;
goto err;
}
/* write param to out-of-band payload */
sia81xx_write_param_to_payload(
(afe_cmd_sia81xx_param_payload *)(afe->cal_block.kvaddr),
module_id,
param_id,
param_size,
buf);
/* clear cmd */
memset((void *)(&apr_cmd), 0x00, sizeof(apr_cmd));
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4,14,0))
/* fill cmd head */
sia81xx_fill_apr_hdr(
(struct apr_hdr *)(&apr_cmd.apr_hdr),
afe_port_to_apr_port(afe->afe_port_id),
AFE_PORT_CMD_SET_PARAM_V2,
sizeof(apr_cmd));
/* fill cmd entity */
apr_cmd.port_id = afe->afe_port_id;
apr_cmd.payload_size =
param_size + sizeof(afe_cmd_sia81xx_param_payload);
apr_cmd.mem_hdr.data_payload_addr_lsw =
lower_32_bits(afe->cal_block.paddr);
apr_cmd.mem_hdr.data_payload_addr_msw =
msm_audio_populate_upper_32_bits(afe->cal_block.paddr);
apr_cmd.mem_hdr.mem_map_handle = afe->cal_block.dsp_mmap_handle;
#else
/* fill cmd head */
sia81xx_fill_apr_hdr(
(struct apr_hdr *)(&apr_cmd.hdr),
afe_port_to_apr_port(afe->afe_port_id),
AFE_PORT_CMD_SET_PARAM_V2,
sizeof(apr_cmd));
/* fill cmd entity */
apr_cmd.param.port_id = afe->afe_port_id;
apr_cmd.param.payload_size =
param_size + sizeof(afe_cmd_sia81xx_param_payload);
apr_cmd.param.payload_address_lsw =
lower_32_bits(afe->cal_block.paddr);
apr_cmd.param.payload_address_msw =
msm_audio_populate_upper_32_bits(afe->cal_block.paddr);
apr_cmd.param.mem_map_handle = afe->cal_block.dsp_mmap_handle;
#endif
/* send the cmd to dsp through apr, and wait dsp returned msg */
ret = sia81xx_apr_send(afe, &apr_cmd);
if(0 > ret) {
goto err;
}
pr_debug("[debug][%s] %s: afe send ret = %d, handle 0x%08x, "
"module_id 0x%08x, param_id 0x%08x, size %d \r\n",
LOG_FLAG, __func__, ret, afe->cal_block.dsp_mmap_handle,
module_id, param_id, param_size);
mutex_unlock(&afe->afe_lock);
return ret;
err:
pr_err("[ err][%s] %s: afe send failed ret = %d, "
"module_id 0x%08x, param_id 0x%08x, size %d \r\n",
LOG_FLAG, __func__, ret, module_id, param_id, param_size);
mutex_unlock(&afe->afe_lock);
return ret;
}
int sia81xx_afe_read(
unsigned long afe_handle,
uint32_t module_id,
uint32_t param_id,
uint32_t param_size,
uint8_t *buf)
{
int ret = 0;
afe_cmd_sia81xx_get_cal apr_cmd;
SIA81XX_AFE *afe = (SIA81XX_AFE *)afe_handle;
if(NULL == afe)
return -EINVAL;
if(APR_SUBSYS_LOADED != apr_get_q6_state()) {
pr_err("[ err][%s] %s: q6_state : %u \r\n",
LOG_FLAG, __func__, (unsigned int)apr_get_q6_state());
return -EINVAL;
}
mutex_lock(&afe->afe_lock);
ret = chack_afe_validity(afe);
if(0 != ret) {
pr_err("[ err][%s] %s: chack_afe_validity failed !! \r\n",
LOG_FLAG, __func__);
goto err;
}
/* is the pa size has a capacity of holding the param */
if (param_size >
(afe->cal_block.pa_size - sizeof(afe_cmd_sia81xx_param_payload))) {
pr_err("[ err][%s] %s: invalid payload size = %d \r\n",
LOG_FLAG, __func__, param_size);
ret = -EINVAL;
goto err;
}
/* write param to out-of-band payload */
sia81xx_write_param_to_payload(
(afe_cmd_sia81xx_param_payload *)(afe->cal_block.kvaddr),
module_id,
param_id,
param_size,
buf);
/* clear cmd */
memset((void *)(&apr_cmd), 0x00, sizeof(apr_cmd));
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4,14,0))
/* fill cmd head */
sia81xx_fill_apr_hdr(
(struct apr_hdr *)(&apr_cmd.apr_hdr),
afe_port_to_apr_port(afe->afe_port_id),
AFE_PORT_CMD_GET_PARAM_V2,
sizeof(apr_cmd));
/* fill cmd entity */
apr_cmd.port_id = afe->afe_port_id;
apr_cmd.payload_size =
param_size + sizeof(afe_cmd_sia81xx_param_payload);
apr_cmd.mem_hdr.data_payload_addr_lsw =
lower_32_bits(afe->cal_block.paddr);
apr_cmd.mem_hdr.data_payload_addr_msw =
msm_audio_populate_upper_32_bits(afe->cal_block.paddr);
apr_cmd.mem_hdr.mem_map_handle = afe->cal_block.dsp_mmap_handle;
apr_cmd.module_id = module_id;
apr_cmd.param_id = param_id;
apr_cmd.param_hdr.module_id = module_id;
apr_cmd.param_hdr.param_id = param_id;
apr_cmd.param_hdr.param_size = param_size;
#else
/* fill cmd head */
sia81xx_fill_apr_hdr(
(struct apr_hdr *)(&apr_cmd.hdr),
afe_port_to_apr_port(afe->afe_port_id),
AFE_PORT_CMD_GET_PARAM_V2,
sizeof(apr_cmd));
/* fill cmd entity */
apr_cmd.param.port_id = afe->afe_port_id;
apr_cmd.param.payload_size =
param_size + sizeof(afe_cmd_sia81xx_param_payload);
apr_cmd.param.payload_address_lsw =
lower_32_bits(afe->cal_block.paddr);
apr_cmd.param.payload_address_msw =
msm_audio_populate_upper_32_bits(afe->cal_block.paddr);
apr_cmd.param.mem_map_handle = afe->cal_block.dsp_mmap_handle;
apr_cmd.param.module_id = module_id;
apr_cmd.param.param_id = param_id;
#endif
/* send the cmd to dsp through apr, and wait dsp returned msg */
ret = sia81xx_apr_send(afe, &apr_cmd);
if(0 > ret) {
goto err;
}
/* read data from dsp returned, and copy this to the user buf */
ret = sia81xx_read_param_from_payload(
(afe_cmd_sia81xx_param_payload *)(afe->cal_block.kvaddr),
module_id,
param_id,
param_size,
buf);
if(0 > ret){
goto err;
}
pr_debug("[debug][%s] %s: afe read ret = %d, handle 0x%08x, "
"module_id 0x%08x, param_id 0x%08x, size %d \r\n",
LOG_FLAG, __func__, ret, afe->cal_block.dsp_mmap_handle,
module_id, param_id, param_size);
mutex_unlock(&afe->afe_lock);
return ret;
err:
pr_err("[ err][%s] %s: afe read failed ret = %d, "
"module_id 0x%08x, param_id 0x%08x, size %d \r\n",
LOG_FLAG, __func__, ret, module_id, param_id, param_size);
mutex_unlock(&afe->afe_lock);
return ret;
}
unsigned long sia81xx_afe_open(
uint32_t afe_prot_id) {
SIA81XX_AFE *afe;
/* when open afe, maybe q6 has not start,
* so must be considered this case.
* 0 == apr_get_q6_state() */
afe = find_sia81xx_afe_list(afe_prot_id);
if(NULL != afe)
return (unsigned long)afe;
afe = kzalloc(sizeof(SIA81XX_AFE), GFP_KERNEL);
if(NULL == afe) {
pr_err("[ err][%s] %s: kzalloc afe failed !! \r\n",
LOG_FLAG, __func__);
return 0;
}
#if (LINUX_VERSION_CODE > KERNEL_VERSION(4,11,12))
afe->cal_block.fd = 0;
#else
afe->cal_block.ion_client = NULL;
afe->cal_block.ion_handle = NULL;
#endif
atomic_set(&(afe->state), 0);
init_waitqueue_head(&(afe->wait));
afe->afe_port_id = afe_prot_id;
mutex_init(&afe->afe_lock);
add_sia81xx_afe_list(afe);
pr_info("[ info][%s] %s: afe open success !! "
"afe prot : 0x%04x \r\n",
LOG_FLAG, __func__, afe_prot_id);
return (unsigned long)afe;
}
int sia81xx_afe_close(
unsigned long afe_handle) {
int ret = 0;
SIA81XX_AFE *afe = (SIA81XX_AFE *)afe_handle;
if(NULL == afe) {
pr_warn("[ warn][%s] %s: NULL == afe \r\n",
LOG_FLAG, __func__);
return 0;
}
pr_info("[ info][%s] %s: afe closeing !! "
"afe prot : 0x%04x \r\n",
LOG_FLAG, __func__, afe->afe_port_id);
/* to ask dsp unmap memory */
ret = sia81xx_apr_cmd_memory_unmap(afe);
if(0 != ret) {
pr_err("[ err][%s] %s: unmap error, close failed !! ret = %d \r\n",
LOG_FLAG, __func__, ret);
return ret;
}
/* free ion buf */
#if (LINUX_VERSION_CODE > KERNEL_VERSION(4,11,12))
if(0 != afe->cal_block.fd) {
ret = msm_audio_ion_free((struct dma_buf *)afe->cal_block.fd);
if(0 != ret) {
pr_err("[ err][%s] %s: ion free error, close failed !! "
"ret = %d \r\n",
LOG_FLAG, __func__, ret);
return ret;
} else {
afe->cal_block.fd = 0;
}
}
#else
if((NULL != afe->cal_block.ion_client) ||
(NULL != afe->cal_block.ion_handle)) {
ret = msm_audio_ion_free(
afe->cal_block.ion_client, afe->cal_block.ion_handle);
if(0 != ret) {
pr_err("[ err][%s] %s: ion free error, close failed !! "
"ret = %d \r\n",
LOG_FLAG, __func__, ret);
return ret;
} else {
afe->cal_block.ion_client = NULL;
afe->cal_block.ion_handle = NULL;
}
}
#endif
/* unregister apr */
ret = apr_deregister(afe->apr);
if(0 != ret) {
pr_err("[ err][%s] %s: 0 != apr_deregister, close failed !! \r\n",
LOG_FLAG, __func__);
return ret;
} else {
afe->apr = NULL;
}
del_sia81xx_afe_list(afe);
kfree(afe);
return 0;
}
static int sia81xx_afe_init(void) {
int ret = 0;
pr_info("[ info][%s] %s: run !! \r\n",
LOG_FLAG, __func__);
return ret;
}
static void sia81xx_afe_exit(void) {
pr_info("[ info][%s] %s: run !! \r\n",
LOG_FLAG, __func__);
}
struct sia81xx_cal_opt tuning_if_opt = {
.init = sia81xx_afe_init,
.exit = sia81xx_afe_exit,
.open = sia81xx_afe_open,
.close = sia81xx_afe_close,
.read = sia81xx_afe_read,
.write = sia81xx_afe_send
};