kernel_samsung_a34x-permissive/sound/soc/mediatek/common_int/mtk-soc-pcm-anc.c

1125 lines
26 KiB
C
Raw Permalink Normal View History

// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2019 MediaTek Inc.
* Author: Michael Hsiao <michael.hsiao@mediatek.com>
*/
/*******************************************************************************
*
* Filename:
* ---------
* mt6583.c
*
* Project:
* --------
* MT6583 Audio Driver Kernel Function
*
* Description:
* ------------
* Audio register
*
* Author:
* -------
* Ship Hsu
*
*
*
******************************************************************************
*/
/*****************************************************************************
* C O M P I L E R F L A G S
*****************************************************************************/
/*****************************************************************************
* E X T E R N A L R E F E R E N C E S
*****************************************************************************/
#include <linux/dma-mapping.h>
#include "mtk-auddrv-afe.h"
#include "mtk-auddrv-ana.h"
#include "mtk-auddrv-clk.h"
#include "mtk-auddrv-common.h"
#include "mtk-auddrv-def.h"
#include "mtk-auddrv-kernel.h"
#include "mtk-auddrv-Gpio.h"
#include "mtk-soc-afe-control.h"
#include "mtk-soc-codec-63xx.h"
#include "mtk-soc-pcm-common.h"
#include <linux/mutex.h>
/*
* function implementation
*/
#define GIC_PRIVATE_SIGNALS (32)
#define AUDDRV_DL1_MAX_BUFFER_LENGTH (0x6000)
#define MT6595_AFE_MCU_IRQ_LINE (GIC_PRIVATE_SIGNALS + 0x86)
#define MT6595_AFE_MCU_ANC_TO_AP_LINE (0xC6)
#define ANC_DEVNAME "ancservice"
/* #define ANC_MD32_TO_HOST_IPC (ANC_MD32_BASE + 0x04)
* #define ANC_HOST_TO_MD32_IPC (ANC_MD32_BASE + 0x08)
* #define ANC_SEMAPHORE (ANC_MD32_BASE + 0x50)
*/
#define ANC_MD32_BASE 0x11025000
#define ANC_MD32_PTCM 0x11020000
#define ANC_MD32_DTCM 0x11022000
#define ANC_A2M_IPC_DATA (ANC_MD32_DTCM + 0x3800)
#define ANC_M2A_IPC_DATA (ANC_MD32_DTCM + 0x3000)
#define ANC_MD32_SRAM 0x11025000
#define MD32_PTCM_SIZE 0x4000
#define MD32_DTCM_SIZE 0x2800
#define MD32_CFGREG_SIZE 0x100
#define MD32_BASE_REG (*(unsigned int *)(MD32_REG_VIRTUAL_ADDR))
#define MD32_TO_HOST_REG \
(*(unsigned int *)(MD32_REG_VIRTUAL_ADDR + 0x0004))
#define HOST_TO_MD32_REG \
(*(unsigned int *)(MD32_REG_VIRTUAL_ADDR + 0x0008))
#define MD32_GENERAL_REG0 \
(*(unsigned int *)(MD32_REG_VIRTUAL_ADDR + 0x000C))
#define MD32_GENERAL_REG1 \
(*(unsigned int *)(MD32_REG_VIRTUAL_ADDR + 0x0010))
#define MD32_GENERAL_REG2 \
(*(unsigned int *)(MD32_REG_VIRTUAL_ADDR + 0x0014))
#define MD32_GENERAL_REG3 \
(*(unsigned int *)(MD32_REG_VIRTUAL_ADDR + 0x0018))
#define MD32_DEBUG_PC_REG \
(*(unsigned int *)(MD32_REG_VIRTUAL_ADDR + 0x0030))
#define MD32_DEBUG_R14_REG \
(*(unsigned int *)(MD32_REG_VIRTUAL_ADDR + 0x0034))
#define MD32_DEBUG_R15_REG \
(*(unsigned int *)(MD32_REG_VIRTUAL_ADDR + 0x0038))
#define MD32_WDT_REG \
(*(unsigned int *)(MD32_REG_VIRTUAL_ADDR + 0x0040))
#define MD32_AUD_MD32_D1 \
(*(unsigned int *)(MD32_REG_VIRTUAL_ADDR + 0x0020))
#define MD32_AUD_MD32_D2 \
(*(unsigned int *)(MD32_REG_VIRTUAL_ADDR + 0x0024))
#define MD32_MD32_AUD_D1 \
(*(unsigned int *)(MD32_REG_VIRTUAL_ADDR + 0x0028))
#define MD32_MD32_AUD_D2 \
(*(unsigned int *)(MD32_REG_VIRTUAL_ADDR + 0x002C))
#define ReadREG_ANC(_addr) (*(unsigned int *)(_addr))
#define WriteREG_ANC(_addr, _value) \
(*(unsigned int *)(_addr) = (_value))
#define ReadREG16_ANC(_addr, _value) \
((_value) = *(unsigned short *)(_addr))
#define WriteREG16_ANC(_addr, _value) \
(*(unsigned short *)(_addr) = (_value))
static int mtk_anc_probe(struct platform_device *pdev);
static int mtk_anc_close(struct snd_pcm_substream *substream);
static int mtk_anc_component_probe(struct snd_soc_component *component);
static DEFINE_MUTEX(to_md32_ipc_lock);
#define AUD_DRV_ANC_IOC_MAGIC 'C'
/* ANC Control */
#define SET_ANC_CONTROL _IOW(AUD_DRV_ANC_IOC_MAGIC, 0x1, int)
#define SET_ANC_PARAMETER _IOW(AUD_DRV_ANC_IOC_MAGIC, 0x2, int)
#define GET_ANC_PARAMETER _IOW(AUD_DRV_ANC_IOC_MAGIC, 0x3, int)
#define MD32_DATA_IMAGE_PATH "/system/etc/firmware/md32_d.bin"
#define MD32_PROGRAM_IMAGE_PATH "/system/etc/firmware/md32_p.bin"
#define MD32TCM_DM_BASE 0xF0028000
#define MD32TCM_PM_BASE 0xF0020000
#define MD32_BASE 0xf0050000
#define ANC_PC (MD32_BASE + 0x60)
#define ANC_PWR (MD32_BASE)
#define ANC_HANDSHAKE_ID_ADDR (MD32TCM_DM_BASE + 0x3FF0)
#define ANC_HANDSHAKE_VAL_ADDR (MD32TCM_DM_BASE + 0x3FF4)
#define MD32_COEF_OFFSET 0x1200
static kal_uint32 dump_analog;
static kal_uint32 IPC_wait_queue_flag;
#define MAX_TABS 68
int md32_coef[MAX_TABS];
DECLARE_WAIT_QUEUE_HEAD(IPC_Wait_Queue);
void *MD32_REG_VIRTUAL_ADDR;
void *MD32_DTCM_VIRTUAL_ADDR;
void *MD32_PTCM_VIRTUAL_ADDR;
/*void *SPM_AUDIO_PWR_CON;
* void *SPM_AUDIO_ACCESS;
* #define WriteREG(_addr, _value) (*(volatile unsigned int *)(_addr) =
* (unsigned int)(_value))
* #define ReadREG(_addr) (*(volatile unsigned int *)(_addr))
*/
enum {
M2A_DumpReady,
M2A_DebugMsgReady,
A2M_SetStatus,
M2A_SetStatusAck,
A2M_UpdateParameter,
M2A_UpdateParameterAck,
A2M_EnableDump,
M2A_EnableDumpAck,
A2M_EnableDebug,
M2A_EnableDebugAck,
};
static void memcpy_md32(void __iomem *trg, const void *src, int size)
{
int i;
u32 __iomem *t = trg;
const u32 *s = src;
for (i = 0; i < (size >> 2); i++)
*t++ = *s++;
}
int get_md32_img_sz(const char *IMAGE_PATH)
{
struct file *filp = NULL;
struct inode *inode;
off_t fsize = 0;
filp = -1;
if (!IS_ERR(filp)) {
inode = filp->f_dentry->d_inode;
fsize = inode->i_size;
} else {
pr_err("Open MD32 image %s FAIL!\n", IMAGE_PATH);
return -1;
}
filp_close(filp, NULL);
return fsize;
}
void upload_coef(void)
{
pr_debug("upload_coef\n");
memcpy((void *)(MD32_DTCM_VIRTUAL_ADDR + MD32_COEF_OFFSET), md32_coef,
MAX_TABS * 4);
}
void update_coef(void)
{
upload_coef();
MD32_GENERAL_REG1 = 0x1;
while (MD32_GENERAL_REG1 != 0)
;
pr_debug("update coff success\n");
}
int load_md32(const char *IMAGE_PATH, void *dst)
{
struct file *filp = NULL;
unsigned char *buf = NULL;
unsigned char *ptr;
struct inode *inode;
off_t fsize;
mm_segment_t fs;
ptr = buf;
filp = -1;
if (IS_ERR(filp)) {
pr_debug("[ANC_MD32] Open MD32 image %s FAIL!\n", IMAGE_PATH);
goto error;
} else {
inode = filp->f_dentry->d_inode;
fsize = inode->i_size;
pr_debug("[ANC_MD32] file %s size: %i\n", IMAGE_PATH,
(int)fsize);
buf = kmalloc((size_t)fsize + 1, GFP_KERNEL);
fs = get_fs();
set_fs(KERNEL_DS);
filp->f_op->read(filp, buf, fsize, &(filp->f_pos));
set_fs(fs);
buf[fsize] = '\0';
memcpy_md32(dst, buf, fsize);
}
filp_close(filp, NULL);
kfree(buf);
return fsize;
error:
if (filp != NULL)
filp_close(filp, NULL);
kfree(buf);
return -1;
}
#define IRQ3_FS_POS 16
#define IRQ3_FS_LEN 4
#define IRQ3_ON 2
#define ADDA_adda_afe_on_POS 0
#define ADDA_adda_afe_on_LEN 1
#define ADDA_afe_ul_dl_con0_reserved_POS 1
#define ADDA_afe_ul_dl_con0_reserved_LEN 14
void get_io_remap(void)
{
MD32_REG_VIRTUAL_ADDR =
ioremap_nocache(ANC_MD32_BASE, MD32_CFGREG_SIZE);
MD32_PTCM_VIRTUAL_ADDR = ioremap_nocache(ANC_MD32_PTCM, MD32_PTCM_SIZE);
MD32_DTCM_VIRTUAL_ADDR = ioremap_nocache(ANC_MD32_DTCM, MD32_DTCM_SIZE);
}
void setDebugDump(bool enable)
{
if (enable) {
/* bConnect IO_0/1 to O21/22 */
Afe_Set_Reg(AFE_ADDA2_TOP_CON0, 0x1 << 11, 0x1 << 11);
/* bConnect IO_2/3 to O5/6 */
Afe_Set_Reg(AFE_ADDA2_TOP_CON0, 0x1 << 12, 0x1 << 12);
} else {
/* bConnect IO_0/1 to O21/22 */
Afe_Set_Reg(AFE_ADDA2_TOP_CON0, 0x0 << 11, 0x1 << 11);
/* bConnect IO_2/3 to O5/6 */
Afe_Set_Reg(AFE_ADDA2_TOP_CON0, 0x0 << 12, 0x1 << 12);
}
}
void preset(void)
{
unsigned int *AFE_Register;
unsigned int *SPM_Register;
AFE_Register = (unsigned int *)Get_Afe_Powertop_Pointer();
SPM_Register = ioremap_nocache(0x10006000, 0x1000);
pr_debug("ANCService_ioctl test(before) AFE_Register: %x",
*AFE_Register);
*SPM_Register = 0x0B160001L;
/* AFE_Register |= 0xDL; */
*AFE_Register &= 0x00FFFFFFL;
*AFE_Register |= 0x00330000L;
/* AFE_Register |= 0x0003000DL; */
get_io_remap();
Afe_Set_Reg(AFE_ADDA2_TOP_CON0, 0x0, 0x3 << 1);
Afe_Set_Reg(AFE_ADDA2_TOP_CON0, 0x0,
0x7 << 4); /* adda2_anc_dl_input_mode:260k */
Afe_Set_Reg(AFE_ADDA2_TOP_CON0, 0x1 << 3,
0x1 << 3); /* afe adda2_dl_src_on */
Afe_Set_Reg(AFE_ADDA2_TOP_CON0, 0x1 << 7, 0x1 << 7); /* ul_dn25_sel */
Afe_Set_Reg(AFE_ADDA2_TOP_CON0, 0x0 << 1,
0x1 << 1); /* use md32, not sgen */
Afe_Set_Reg(AFE_ADDA2_TOP_CON0, 0x0 << 2,
0x1 << 2); /* use md32, not sgen */
/* anc_up8x_rxif_adc_voice_mode:8: time slot1 = 78, time slot2 = 24 @
* 260K interval
*/
Afe_Set_Reg(AFE_ADDA2_TOP_CON0, 0x8 << 28, 0xf << 28);
Afe_Set_Reg(AFE_ADDA_UL_DL_CON0,
0x3f << ADDA_afe_ul_dl_con0_reserved_POS,
((2 ^ ADDA_afe_ul_dl_con0_reserved_LEN) - 1)
<< ADDA_afe_ul_dl_con0_reserved_POS);
SetADDAEnable(true); /* adda_afe_on: 1: enable */
AudDrv_GPIO_Request(true, Soc_Aud_Digital_Block_ADDA_ANC);
pr_debug("ANCService_ioctl test(after) AFE_Register: %x",
*AFE_Register);
}
void enable_uplink_path(void)
{
/* mtkif rx rg_voice mode set to 260k */
Afe_Set_Reg(AFE_ADDA_NEWIF_CFG2, 0x8 << 28, 0xf << 28);
set_ul_src_enable(true); /* UL SRC on which will enable mtk if rx */
AudDrv_ADC_Clk_On();
}
void disable_uplink_path(void)
{
AudDrv_ADC_Clk_Off();
set_ul_src_enable(false);
/* anc_tx off */
Afe_Set_Reg(AFE_ADDA2_TOP_CON0, 0x0 << 1, 0x1 << 1);
}
void md32_write_processed(void)
{
MD32_GENERAL_REG0 = 0x0;
}
void md32_write_mic_data(void)
{
MD32_GENERAL_REG0 = 0x1;
}
void md32_write_tone(void)
{
MD32_GENERAL_REG0 = 0x2;
}
void md32_write_seq_data(void)
{
MD32_GENERAL_REG0 = 0x3;
}
void md32_write_silence(void)
{
MD32_GENERAL_REG0 = 0x4;
}
void download_md32_binary(void)
{
int p_sz, d_sz, ret;
msleep(50);
/* unsigned char *md32_data_image={0}; */
/* unsigned char *md32_program_image={0}; */
/* unsigned char *d_buf, *p_buf; */
p_sz = get_md32_img_sz(MD32_PROGRAM_IMAGE_PATH);
d_sz = get_md32_img_sz(MD32_DATA_IMAGE_PATH);
/* (*(volatile unsigned int *)(SPM_AUDIO_ACCESS)) = 0x0b160001; */
/* *AFE_Register |= 0x00330F0D */
pr_debug("ANC_Service %s p_sz:%d d_sz:%d\n", __func__, p_sz, d_sz);
MD32_BASE_REG = 0x0; /* turn off md32 */
do {
if (p_sz > 0)
ret = load_md32(MD32_PROGRAM_IMAGE_PATH,
MD32_PTCM_VIRTUAL_ADDR);
if (d_sz > 0)
ret = load_md32(MD32_DATA_IMAGE_PATH,
MD32_DTCM_VIRTUAL_ADDR);
MD32_TO_HOST_REG = 0x11220000;
upload_coef();
MD32_BASE_REG = 0x1;
pr_debug("[ANC_MD32] MD32 download success and bootup\n");
return;
} while (0);
pr_debug("[ANC_MD32] boot up failed!!! free images\n");
}
/* =============write file============= */
mm_segment_t oldfs;
void InitKernelEnv(void)
{
oldfs = get_fs();
set_fs(KERNEL_DS);
}
void DinitKernelEnv(void)
{
set_fs(oldfs);
}
struct file *OpenFile(char *path, int flag, int mode)
{
struct file *fp;
fp = 0;
if (fp)
return fp;
else
return NULL;
}
int WriteFile(struct file *fp, char *buf, int readlen)
{
if (fp->f_op && fp->f_op->read)
return fp->f_op->write(fp, buf, readlen, &fp->f_pos);
else
return -1;
}
int ReadFile(struct file *fp, char *buf, int readlen)
{
if (fp->f_op && fp->f_op->read)
return fp->f_op->read(fp, buf, readlen, &fp->f_pos);
else
return -1;
}
int CloseFile(struct file *fp)
{
filp_close(fp, NULL);
return 0;
}
/* ============================== */
static struct snd_pcm_hw_constraint_list constraints_sample_rates = {
.count = ARRAY_SIZE(soc_high_supported_sample_rates),
.list = soc_high_supported_sample_rates,
.mask = 0,
};
static int ANCService_open(struct inode *inode, struct file *fp)
{
pr_debug("%s inode:%p, file:%p\n", __func__, inode, fp);
return 0;
}
static int ANCService_release(struct inode *inode, struct file *fp)
{
pr_debug("%s inode:%p, file:%p\n", __func__, inode, fp);
if (!(fp->f_mode & FMODE_WRITE || fp->f_mode & FMODE_READ))
return -ENODEV;
return 0;
}
void md32_dump_memory(void)
{
struct file *fp;
InitKernelEnv();
/* write to file */
fp = OpenFile("/sdcard/mtklog/md32_mem.dat", O_CREAT | O_WRONLY, 0);
if (fp != NULL)
WriteFile(fp, (char *)ANC_MD32_DTCM, 16384);
CloseFile(fp);
DinitKernelEnv();
}
void md32_dump_reg(void)
{
md32_dump_memory();
}
void wait_ipc_ack(void)
{
int ret;
pr_debug("ANC wait_event_interruptible_timeout\n");
ret = wait_event_interruptible_timeout(
IPC_Wait_Queue, IPC_wait_queue_flag, msecs_to_jiffies(1000));
if (ret < 0)
pr_debug("ANC md32 irq failed, ret=%d", ret);
}
void trigger_ipc_l(void)
{
pr_debug("ANC trigger_ipc_l\n");
IPC_wait_queue_flag = 0;
HOST_TO_MD32_REG = 0x1;
/* ANC_M2A_IPC_DATA */
}
void trigger_ipc_wait_l(void)
{
trigger_ipc_l();
wait_ipc_ack();
}
void wake_up_ipc_wait(void)
{
pr_debug("ANC wake_up_ipc_wait\n");
IPC_wait_queue_flag = 1;
wake_up_interruptible(&IPC_Wait_Queue);
}
void require_ipc_lock(void)
{
pr_debug("ANC require_ipc_lock\n");
mutex_lock(&to_md32_ipc_lock);
}
void release_ipc_lock(void)
{
mutex_unlock(&to_md32_ipc_lock);
}
void notify_md32_update_parameter(void)
{
pr_debug("notify_md32_update_parameter\n");
require_ipc_lock();
WriteREG_ANC(ANC_A2M_IPC_DATA, A2M_UpdateParameter);
trigger_ipc_wait_l();
release_ipc_lock();
}
void notify_md32_set_status(bool Enable)
{
pr_debug("notify_md32_enable_debug\n");
require_ipc_lock();
WriteREG_ANC(ANC_A2M_IPC_DATA, A2M_SetStatus);
WriteREG_ANC(ANC_A2M_IPC_DATA + 0x4, Enable ? 0x1 : 0x0);
trigger_ipc_wait_l();
release_ipc_lock();
}
void notify_md32_enable_dump(bool Enable)
{
pr_debug("notify_md32_enable_dump\n");
require_ipc_lock();
WriteREG_ANC(ANC_A2M_IPC_DATA, A2M_EnableDump);
WriteREG_ANC(ANC_A2M_IPC_DATA + 0x4, Enable ? 0x1 : 0x0);
trigger_ipc_wait_l();
release_ipc_lock();
}
void notify_md32_enable_debug(bool Enable)
{
pr_debug("notify_md32_enable_debug\n");
require_ipc_lock();
WriteREG_ANC(ANC_A2M_IPC_DATA, A2M_EnableDebug);
WriteREG_ANC(ANC_A2M_IPC_DATA + 0x4, Enable ? 0x1 : 0x0);
trigger_ipc_wait_l();
release_ipc_lock();
}
void on_md32_debug_message_ready(void)
{
}
void on_md32_dump_data_ready(void)
{
}
void on_md32_ipc_trigger(void)
{
/* ANC_M2A_IPC_DATA */
int irq_type = ReadREG_ANC(ANC_M2A_IPC_DATA);
switch (irq_type) {
/* MD32 notify ap actively. */
case M2A_DumpReady:
on_md32_dump_data_ready();
break;
case M2A_DebugMsgReady:
on_md32_debug_message_ready();
break;
/* Types of Ack */
case M2A_SetStatusAck:
wake_up_ipc_wait();
break;
case M2A_UpdateParameterAck:
wake_up_ipc_wait();
break;
case M2A_EnableDumpAck:
wake_up_ipc_wait();
break;
case M2A_EnableDebugAck:
wake_up_ipc_wait();
break;
}
}
static long ANCService_ioctl(struct file *fp, unsigned int cmd,
unsigned long arg)
{
int ret = 0;
pr_debug("ANCService_ioctl cmd = %u arg = %lu\n", cmd, arg);
switch (cmd) {
case SET_ANC_CONTROL: {
pr_debug("SET_ANC_CONTROL(%lu)", arg);
switch (arg) {
case 1:
md32_dump_reg();
break;
case 2:
download_md32_binary();
break;
case 30:
md32_write_processed();
break;
case 31:
md32_write_silence();
break;
case 33:
md32_write_tone();
break;
case 34:
md32_write_seq_data();
break;
case 35:
md32_write_mic_data();
break;
case 40:
Afe_Log_Print();
break;
case 81:
AudDrv_Clk_On();
AudDrv_ANC_Clk_On();
SetMemoryPathEnable(Soc_Aud_Digital_Block_ADDA_ANC,
true);
EnableAfe(true);
preset();
download_md32_binary();
enable_uplink_path();
break;
case 82:
SetADDAEnable(false);
SetMemoryPathEnable(Soc_Aud_Digital_Block_ADDA_ANC,
false);
EnableAfe(false);
AudDrv_GPIO_Request(false,
Soc_Aud_Digital_Block_ADDA_ANC);
disable_uplink_path();
AudDrv_ANC_Clk_Off();
AudDrv_Clk_Off();
break;
case 91:
update_coef();
break;
case 21:
trigger_ipc_l();
break;
case 22:
notify_md32_set_status(true);
break;
case 23:
notify_md32_set_status(false);
break;
default:
pr_debug("SET_ANC_CONTROL no such command = %lu", arg);
break;
}
break;
}
case SET_ANC_PARAMETER: {
pr_debug("SET_ANC_CONTROL(%lu)", arg);
switch (arg) {
default:
pr_debug("SET_ANC_CONTROL no such command = %lu", arg);
break;
}
break;
}
case GET_ANC_PARAMETER: {
pr_debug("SET_ANC_CONTROL(%lu)", arg);
switch (arg) {
default:
pr_debug("SET_ANC_CONTROL no such command = %lu", arg);
break;
}
break;
}
}
return ret;
}
/*
* ioctl32 compat
*/
#ifdef CONFIG_COMPAT
static long ANCService_ioctl_compat(struct file *file, unsigned int cmd,
unsigned long arg)
{
file->f_op->unlocked_ioctl(file, cmd, arg);
return 0;
}
#else
#define ANCService_ioctl_compat NULL
#endif
static ssize_t ANCService_write(struct file *fp, const char __user *data,
size_t count, loff_t *offset)
{
char temp_str[MAX_TABS * 4];
pr_debug("ANCService_write write count %zu", count);
if (count > MAX_TABS * 4)
return -EINVAL;
if (copy_from_user(temp_str, data, count) != 0)
return -EFAULT;
memcpy((void *)md32_coef, (void *)temp_str, count);
pr_debug("ANCService_write write done");
return 0;
}
static ssize_t ANCService_read(struct file *fp, char __user *data, size_t count,
loff_t *offset)
{
char buffer[1380] = {0};
int n = 0;
char *cur = buffer;
int retval;
int i;
unsigned int *AFE_Register =
(unsigned int *)Get_Afe_Powertop_Pointer();
if (!dump_analog) {
cur += sprintf((char *)cur, "===DUMP MD32 Memory===\n");
cur += sprintf((char *)cur, "MD32_BASE_REG = 0x%x\n",
MD32_BASE_REG);
cur += sprintf((char *)cur, "MD32_TO_HOST_REG = 0x%x\n",
MD32_TO_HOST_REG);
cur += sprintf((char *)cur, "HOST_TO_MD32_REG = 0x%x\n",
HOST_TO_MD32_REG);
cur += sprintf((char *)cur, "MD32_DEBUG_PC_REG = 0x%x\n",
MD32_DEBUG_PC_REG);
cur += sprintf((char *)cur, "MD32_DEBUG_R14_REG = 0x%x\n",
MD32_DEBUG_R14_REG);
cur += sprintf((char *)cur, "MD32_DEBUG_R15_REG = 0x%x\n",
MD32_DEBUG_R15_REG);
cur += sprintf((char *)cur, "MD32_WDT_REG = 0x%x\n",
MD32_WDT_REG);
cur += sprintf((char *)cur, "MD32_AUD_MD32_D1 = 0x%x\n",
MD32_AUD_MD32_D1);
cur += sprintf((char *)cur, "MD32_AUD_MD32_D2 = 0x%x\n",
MD32_AUD_MD32_D2);
cur += sprintf((char *)cur, "MD32_MD32_AUD_D1 = 0x%x\n",
MD32_MD32_AUD_D1);
cur += sprintf((char *)cur, "MD32_MD32_AUD_D2 = 0x%x\n",
MD32_MD32_AUD_D2);
cur += sprintf((char *)cur, "MD32_GENERAL_REG0 = 0x%x\n",
MD32_GENERAL_REG0);
cur += sprintf((char *)cur, "MD32_GENERAL_REG1 = 0x%x\n",
MD32_GENERAL_REG1);
cur += sprintf((char *)cur, "MD32_GENERAL_REG2 = 0x%x\n",
MD32_GENERAL_REG2);
cur += sprintf((char *)cur, "MD32_GENERAL_REG3 = 0x%x\n",
MD32_GENERAL_REG3);
#ifdef _NON_COMMON_FEATURE_READY
cur += sprintf((char *)cur, "AFE_GENERAL_REG0 = 0x%x\n",
Afe_Get_Reg(AFE_GENERAL_REG0));
cur += sprintf((char *)cur, "AFE_GENERAL_REG1 = 0x%x\n",
Afe_Get_Reg(AFE_GENERAL_REG1));
cur += sprintf((char *)cur, "AFE_GENERAL_REG2 = 0x%x\n",
Afe_Get_Reg(AFE_GENERAL_REG2));
cur += sprintf((char *)cur, "AFE_GENERAL_REG3 = 0x%x\n",
Afe_Get_Reg(AFE_GENERAL_REG3));
cur += sprintf((char *)cur, "AFE_GENERAL_REG4 = 0x%x\n",
Afe_Get_Reg(AFE_GENERAL_REG4));
cur += sprintf((char *)cur, "AFE_GENERAL_REG5 = 0x%x\n",
Afe_Get_Reg(AFE_GENERAL_REG5));
cur += sprintf((char *)cur, "AFE_GENERAL_REG6 = 0x%x\n",
Afe_Get_Reg(AFE_GENERAL_REG6));
cur += sprintf((char *)cur, "AFE_GENERAL_REG7 = 0x%x\n",
Afe_Get_Reg(AFE_GENERAL_REG7));
cur += sprintf((char *)cur, "AFE_GENERAL_REG8 = 0x%x\n",
Afe_Get_Reg(AFE_GENERAL_REG8));
cur += sprintf((char *)cur, "AFE_GENERAL_REG9 = 0x%x\n",
Afe_Get_Reg(AFE_GENERAL_REG9));
#endif
cur += sprintf((char *)cur, "AFE_Register(SPM) = 0x%x\n",
*AFE_Register);
cur += sprintf((char *)cur, "MD32_Coef:\n");
for (i = 0; i < MAX_TABS; i++)
cur += sprintf((char *)cur, "%d,", md32_coef[i]);
cur += sprintf((char *)cur, "\n");
}
n = (int)(cur - (char *)buffer);
if (n > count)
n = count;
retval = copy_to_user(data, buffer, n);
return n;
}
static int ANCService_flush(struct file *flip, fl_owner_t id)
{
return 0;
}
static int ANCService_fasync(int fd, struct file *flip, int mode)
{
return 0;
}
static int ANCService_remap_mmap(struct file *flip, struct vm_area_struct *vma)
{
return -1;
}
static const struct file_operations ANCService_fops = {
.owner = THIS_MODULE,
.open = ANCService_open,
.release = ANCService_release,
.unlocked_ioctl = ANCService_ioctl,
.compat_ioctl = ANCService_ioctl_compat,
.write = ANCService_write,
.read = ANCService_read,
.flush = ANCService_flush,
.fasync = ANCService_fasync,
.mmap = ANCService_remap_mmap};
static struct miscdevice ANCService_misc_device = {
.minor = MISC_DYNAMIC_MINOR,
.name = ANC_DEVNAME,
.fops = &ANCService_fops,
};
static int mtk_anc_pcm_open(struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
int ret = 0;
ret = snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
&constraints_sample_rates);
ret = snd_pcm_hw_constraint_integer(runtime,
SNDRV_PCM_HW_PARAM_PERIODS);
/* print for hw pcm information */
pr_debug("mtk_anc_pcm_open runtime rate = %d channels = %d\n",
runtime->rate, runtime->channels);
if (substream->pcm->device & 1) {
runtime->hw.info &= ~SNDRV_PCM_INFO_INTERLEAVED;
runtime->hw.info |= SNDRV_PCM_INFO_NONINTERLEAVED;
}
if (substream->pcm->device & 2) {
runtime->hw.info &=
~(SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID);
}
if (ret < 0) {
pr_debug("mtk_anc_close\n");
mtk_anc_close(substream);
return ret;
}
pr_debug("mtk_anc_pcm_open return\n");
return 0;
}
static int mtk_anc_close(struct snd_pcm_substream *substream)
{
return 0;
}
static int mtk_anc_trigger(struct snd_pcm_substream *substream, int cmd)
{
pr_debug("mtk_anc_trigger cmd = %d\n", cmd);
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_RESUME:
case SNDRV_PCM_TRIGGER_STOP:
case SNDRV_PCM_TRIGGER_SUSPEND:
break;
}
return -EINVAL;
}
static int mtk_anc_copy(struct snd_pcm_substream *substream, int channel,
unsigned long pos, void __user *buf,
unsigned long bytes)
{
return 0;
}
static int mtk_anc_silence(struct snd_pcm_substream *substream, int channel,
unsigned long pos, unsigned long bytes)
{
return 0; /* do nothing */
}
static void *anc_page[2];
static struct page *mtk_anc_page(struct snd_pcm_substream *substream,
unsigned long offset)
{
return virt_to_page(anc_page[substream->stream]); /* the same page */
}
static int mtk_anc_prepare(struct snd_pcm_substream *substream)
{
return 0;
}
static int mtk_anc_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *hw_params)
{
int ret = 0;
return ret;
}
static int mtk_anc_hw_free(struct snd_pcm_substream *substream)
{
return snd_pcm_lib_free_pages(substream);
}
static struct snd_pcm_ops mtk_afe_ops = {
.open = mtk_anc_pcm_open,
.close = mtk_anc_close,
.ioctl = snd_pcm_lib_ioctl,
.hw_params = mtk_anc_hw_params,
.hw_free = mtk_anc_hw_free,
.prepare = mtk_anc_prepare,
.trigger = mtk_anc_trigger,
.copy_user = mtk_anc_copy,
.fill_silence = mtk_anc_silence,
.page = mtk_anc_page,
};
static struct snd_soc_component_driver mtk_soc_anc_component = {
.name = AFE_PCM_NAME,
.ops = &mtk_afe_ops,
.probe = mtk_anc_component_probe,
};
irqreturn_t AudDrv_ANC_IRQ_handler(int irq, void *dev_id)
{
pr_debug("AudDrv_ANC_IRQ_handler %d\n", irq);
/* MD32_TO_SPM_REG = 0x0;
* on_md32_ipc_trigger();
* MD32_TO_HOST_REG = 0x0;
*/
return IRQ_HANDLED;
}
bool Register_Aud_ANC_Irq(void *dev)
{
int ret = 0;
pr_debug("Register_Aud_ANC_Irq %s dev name =%s\n", __func__,
dev_name(dev));
/* ret = request_irq(MT6595_AFE_MCU_ANC_TO_AP_LINE,
* AudDrv_ANC_IRQ_handler, IRQF_TRIGGER_NONE, "MD32 IPC_MD2HOST", NULL);
*/
if (ret)
pr_debug("[anc md32] request irq failed : %d\n", ret);
return ret;
}
static int mtk_anc_probe(struct platform_device *pdev)
{
int ret;
dump_analog = 0;
IPC_wait_queue_flag = 0;
pr_debug("mtk_anc_probe\n");
pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
if (!pdev->dev.dma_mask)
pdev->dev.dma_mask = &pdev->dev.coherent_dma_mask;
if (pdev->dev.of_node)
dev_set_name(&pdev->dev, "%s", MT_SOC_ANC_PCM);
pdev->name = pdev->dev.kobj.name;
Register_Aud_ANC_Irq(&pdev->dev);
pr_debug("%s: dev name %s\n", __func__, dev_name(&pdev->dev));
ret = misc_register(&ANCService_misc_device);
/* register MISC device */
if (ret) {
pr_debug("ANCService misc_register Fail:%d\n", ret);
return ret;
}
return snd_soc_register_component(&pdev->dev,
&mtk_soc_anc_component,
NULL,
0);
}
static int mtk_anc_component_probe(struct snd_soc_component *component)
{
pr_debug("mtk_anc_component_probe\n");
return 0;
}
static int mtk_afeanc_remove(struct platform_device *pdev)
{
snd_soc_unregister_component(&pdev->dev);
return 0;
}
#ifdef CONFIG_OF
static const struct of_device_id mt_soc_anc_of_ids[] = {
{
.compatible = "mediatek,mt_soc_pcm_anc",
},
{} };
#endif
static struct platform_driver mtk_anc_driver = {
.driver = {
.name = MT_SOC_ANC_PCM,
.owner = THIS_MODULE,
#ifdef CONFIG_OF
.of_match_table = mt_soc_anc_of_ids,
#endif
},
.probe = mtk_anc_probe,
.remove = mtk_afeanc_remove,
};
#ifndef CONFIG_OF
static struct platform_device *soc_mtkafe_anc_dev;
#endif
static int __init mtk_soc_anc_platform_init(void)
{
int ret = 0;
pr_debug("%s\n", __func__);
#ifndef CONFIG_OF
soc_mtkafe_anc_dev = platform_device_alloc(MT_SOC_ANC_PCM, -1);
if (!soc_mtkafe_anc_dev)
return -ENOMEM;
ret = platform_device_add(soc_mtkafe_anc_dev);
if (ret != 0) {
platform_device_put(soc_mtkafe_anc_dev);
return ret;
}
#endif
ret = platform_driver_register(&mtk_anc_driver);
return ret;
}
module_init(mtk_soc_anc_platform_init);
static void __exit mtk_soc_anc_platform_exit(void)
{
platform_driver_unregister(&mtk_anc_driver);
}
module_exit(mtk_soc_anc_platform_exit);
MODULE_DESCRIPTION("AFE PCM module platform driver");
MODULE_LICENSE("GPL");