diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_gem.c b/drivers/gpu/drm/rockchip/rockchip_drm_gem.c index c82f3613bcd3..25f40653566a 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_gem.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_gem.c @@ -546,10 +546,6 @@ static int rockchip_drm_gem_object_mmap(struct drm_gem_object *obj, int ret; struct rockchip_gem_object *rk_obj = to_rockchip_obj(obj); - /* default is wc. */ - if (rk_obj->flags & ROCKCHIP_BO_CACHABLE) - vma->vm_page_prot = vm_get_page_prot(vma->vm_flags); - /* * Set vm_pgoff (used as a fake buffer offset by DRM) to 0 and map the * whole buffer from the start. @@ -562,7 +558,11 @@ static int rockchip_drm_gem_object_mmap(struct drm_gem_object *obj, */ vm_flags_mod(vma, VM_IO | VM_DONTEXPAND | VM_DONTDUMP, VM_PFNMAP); - vma->vm_page_prot = pgprot_writecombine(vm_get_page_prot(vma->vm_flags)); + /* default is wc. */ + if (rk_obj->flags & ROCKCHIP_BO_CACHABLE) + vma->vm_page_prot = vm_get_page_prot(vma->vm_flags); + else + vma->vm_page_prot = pgprot_writecombine(vm_get_page_prot(vma->vm_flags)); vma->vm_page_prot = pgprot_decrypted(vma->vm_page_prot); if (rk_obj->buf_type == ROCKCHIP_GEM_BUF_TYPE_SECURE) { diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index a8225756e720..d82aaa8afb9b 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -2272,5 +2272,7 @@ config SND_SOC_LPASS_TX_MACRO tristate "Qualcomm TX Macro in LPASS(Low Power Audio SubSystem)" source "sound/soc/codecs/aw87xxx/Kconfig" +source "sound/soc/codecs/aw882xx/Kconfig" source "sound/soc/codecs/aw883xx/Kconfig" +source "sound/soc/codecs/it6621/Kconfig" endmenu diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 3280820af716..a7ed3cdc885e 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -746,7 +746,9 @@ obj-$(CONFIG_SND_SOC_ZL38060) += snd-soc-zl38060.o # Amp obj-$(CONFIG_SND_SOC_AW87XXX) += aw87xxx/ +obj-$(CONFIG_SND_SOC_AW882XX) += aw882xx/ obj-$(CONFIG_SND_SOC_AW883XX) += aw883xx/ +obj-$(CONFIG_SND_SOC_IT6621) += it6621/ obj-$(CONFIG_SND_SOC_MAX9877) += snd-soc-max9877.o obj-$(CONFIG_SND_SOC_MAX98504) += snd-soc-max98504.o obj-$(CONFIG_SND_SOC_SIMPLE_AMPLIFIER) += snd-soc-simple-amplifier.o diff --git a/sound/soc/codecs/aw882xx/Kconfig b/sound/soc/codecs/aw882xx/Kconfig new file mode 100644 index 000000000000..dc01b6d347a7 --- /dev/null +++ b/sound/soc/codecs/aw882xx/Kconfig @@ -0,0 +1,5 @@ +config SND_SOC_AW882XX + tristate "SoC Audio for awinic AW883XX series Smart PA" + depends on I2C + help + This option enables support for AW883XX series Smart PA. diff --git a/sound/soc/codecs/aw882xx/Makefile b/sound/soc/codecs/aw882xx/Makefile new file mode 100644 index 000000000000..e44d7815a0f2 --- /dev/null +++ b/sound/soc/codecs/aw882xx/Makefile @@ -0,0 +1,5 @@ +#for AWINIC AW883XX Smart PA +snd-soc-aw882xx-objs := aw882xx.o aw882xx_device.o aw882xx_dsp.o aw882xx_monitor.o aw882xx_bin_parse.o aw882xx_init.o aw882xx_calib.o aw882xx_spin.o +obj-$(CONFIG_SND_SOC_AW882XX) += snd-soc-aw882xx.o + + diff --git a/sound/soc/codecs/aw882xx/aw882xx.c b/sound/soc/codecs/aw882xx/aw882xx.c new file mode 100644 index 000000000000..335dccf01f22 --- /dev/null +++ b/sound/soc/codecs/aw882xx/aw882xx.c @@ -0,0 +1,2755 @@ +// SPDX-License-Identifier: GPL-2.0 +/* aw882xx.c aw882xx codec module + * + * + * Copyright (c) 2020 AWINIC Technology CO., LTD + * + * Author: Nick Li + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +/*#define DEBUG*/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "aw882xx.h" +#include "aw882xx_log.h" +#include "aw882xx_dsp.h" +#include "aw882xx_bin_parse.h" +#include "aw882xx_spin.h" + +#define AW882XX_DRIVER_VERSION "v1.15.0" +#define AW882XX_I2C_NAME "aw882xx_smartpa" + +#define AW_READ_CHIPID_RETRIES 5 /* 5 times */ +#define AW_READ_CHIPID_RETRY_DELAY 5 /* 5 ms */ + +static unsigned int g_aw882xx_dev_cnt; +static unsigned int g_print_dbg; +static unsigned int g_algo_rx_en = true; +static unsigned int g_algo_tx_en = true; +static unsigned int g_algo_copp_en = true; + +static DEFINE_MUTEX(g_aw882xx_lock); +struct aw_container *g_awinic_cfg; + +static const char *const aw882xx_switch[] = {"Disable", "Enable"}; +static const char *const aw882xx_spin[] = {"spin_0", "spin_90", + "spin_180", "spin_270"}; + +/****************************************************** + * + * aw882xx distinguish between codecs and components by version + * + ******************************************************/ +#ifdef AW_KERNEL_VER_OVER_4_19_1 +static struct aw_componet_codec_ops aw_componet_codec_ops = { + .kcontrol_codec = snd_soc_kcontrol_component, + .codec_get_drvdata = snd_soc_component_get_drvdata, + .add_codec_controls = snd_soc_add_component_controls, + .unregister_codec = snd_soc_unregister_component, + .register_codec = snd_soc_register_component, +}; +#else +static struct aw_componet_codec_ops aw_componet_codec_ops = { + .kcontrol_codec = snd_soc_kcontrol_codec, + .codec_get_drvdata = snd_soc_codec_get_drvdata, + .add_codec_controls = snd_soc_add_codec_controls, + .unregister_codec = snd_soc_unregister_codec, + .register_codec = snd_soc_register_codec, +}; +#endif + +static aw_snd_soc_codec_t *aw_get_codec(struct snd_soc_dai *dai) +{ +#ifdef AW_KERNEL_VER_OVER_4_19_1 + return dai->component; +#else + return dai->codec; +#endif +} + + +/****************************************************** + * + * aw882xx i2c write/read + * + ******************************************************/ +int aw882xx_get_version(char *buf, int size) +{ + if (size > strlen(AW882XX_DRIVER_VERSION)) { + memcpy(buf, AW882XX_DRIVER_VERSION, strlen(AW882XX_DRIVER_VERSION)); + return strlen(AW882XX_DRIVER_VERSION); + } else { + return -ENOMEM; + } +} + +int aw882xx_get_dev_num(void) +{ + return g_aw882xx_dev_cnt; +} + +static int aw882xx_i2c_writes(struct aw882xx *aw882xx, + unsigned char reg_addr, unsigned char *buf, unsigned int len) +{ + int ret = -1; + unsigned char *data = NULL; + + data = kmalloc(len+1, GFP_KERNEL); + if (data == NULL) + return -ENOMEM; + + + data[0] = reg_addr; + memcpy(&data[1], buf, len); + + ret = i2c_master_send(aw882xx->i2c, data, len+1); + if (ret < 0) + aw_dev_err(aw882xx->dev, "i2c master send error"); + + kfree(data); + + return ret; +} + +static int aw882xx_i2c_reads(struct aw882xx *aw882xx, + unsigned char reg_addr, unsigned char *data_buf, unsigned int data_len) +{ + int ret; + struct i2c_msg msg[] = { + [0] = { + .addr = aw882xx->i2c->addr, + .flags = 0, + .len = sizeof(uint8_t), + .buf = ®_addr, + }, + [1] = { + .addr = aw882xx->i2c->addr, + .flags = I2C_M_RD, + .len = data_len, + .buf = data_buf, + }, + }; + + ret = i2c_transfer(aw882xx->i2c->adapter, msg, ARRAY_SIZE(msg)); + if (ret < 0) { + aw_dev_err(aw882xx->dev, "transfer failed."); + return ret; + } else if (ret != AW882XX_I2C_READ_MSG_NUM) { + aw_dev_err(aw882xx->dev, "transfer failed(size error)."); + return -ENXIO; + } + + return 0; +} + +int aw882xx_i2c_write(struct aw882xx *aw882xx, + unsigned char reg_addr, unsigned int reg_data) +{ + int ret = -1; + unsigned char cnt = 0; + unsigned char buf[2]; + + buf[0] = (reg_data&0xff00)>>8; + buf[1] = (reg_data&0x00ff)>>0; + + while (cnt < AW_I2C_RETRIES) { + ret = aw882xx_i2c_writes(aw882xx, reg_addr, buf, 2); + if (ret < 0) { + aw_dev_err(aw882xx->dev, "i2c_write cnt=%d error=%d", + cnt, ret); + } else { + if (g_print_dbg) + aw_dev_info(aw882xx->dev, "reg_addr: 0x%02x, reg_data :0x%04x", + (uint8_t)reg_addr, (uint16_t)reg_data); + break; + } + cnt++; + } + + return ret; +} + +int aw882xx_i2c_read(struct aw882xx *aw882xx, + unsigned char reg_addr, unsigned int *reg_data) +{ + int ret = -1; + unsigned char cnt = 0; + unsigned char buf[2]; + + while (cnt < AW_I2C_RETRIES) { + ret = aw882xx_i2c_reads(aw882xx, reg_addr, buf, 2); + if (ret < 0) { + aw_dev_err(aw882xx->dev, "i2c_read cnt=%d error=%d", + cnt, ret); + } else { + *reg_data = (buf[0]<<8) | (buf[1]<<0); + if (g_print_dbg) + aw_dev_info(aw882xx->dev, "reg_addr: 0x%02x, reg_data :0x%04x", + (uint8_t)reg_addr, (uint16_t)(*reg_data)); + break; + } + cnt++; + } + + return ret; +} + +int aw882xx_i2c_write_bits(struct aw882xx *aw882xx, + unsigned char reg_addr, unsigned int mask, unsigned int reg_data) +{ + int ret = -1; + unsigned int reg_val = 0; + + ret = aw882xx_i2c_read(aw882xx, reg_addr, ®_val); + if (ret < 0) { + aw_dev_err(aw882xx->dev, "i2c read error, ret=%d", ret); + return ret; + } + reg_val &= mask; + reg_val |= (reg_data & (~mask)); + ret = aw882xx_i2c_write(aw882xx, reg_addr, reg_val); + if (ret < 0) { + aw_dev_err(aw882xx->dev, "i2c read error, ret=%d", ret); + return ret; + } + + return 0; +} + +static void *aw882xx_devm_kstrdup(struct device *dev, char *buf) +{ + char *str = NULL; + + str = devm_kzalloc(dev, strlen(buf) + 1, GFP_KERNEL); + if (!str) + return str; + + memcpy(str, buf, strlen(buf)); + return str; +} + +/***************************************************** + * + * snd_soc_dai_driver ops + * + *****************************************************/ +static int aw882xx_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + aw_snd_soc_codec_t *codec = aw_get_codec(dai); + struct aw882xx *aw882xx = + aw_componet_codec_ops.codec_get_drvdata(codec); + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + aw_dev_info(aw882xx->dev, "playback enter"); + /*load cali re*/ + aw882xx_dev_init_cali_re(aw882xx->aw_pa); + } else { + aw_dev_info(aw882xx->dev, "capture enter"); + } + return 0; +} + +static int aw882xx_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) +{ + /*struct aw882xx *aw882xx = aw_snd_soc_codec_get_drvdata(dai->codec);*/ + aw_snd_soc_codec_t *codec = aw_get_codec(dai); + + aw_dev_info(codec->dev, "fmt=0x%x", fmt); + + return 0; +} + +static int aw882xx_set_dai_sysclk(struct snd_soc_dai *dai, + int clk_id, unsigned int freq, int dir) +{ + aw_snd_soc_codec_t *codec = aw_get_codec(dai); + struct aw882xx *aw882xx = + aw_componet_codec_ops.codec_get_drvdata(codec); + + aw_dev_info(aw882xx->dev, "freq=%d", freq); + + aw882xx->sysclk = freq; + return 0; +} + +static int aw882xx_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + aw_snd_soc_codec_t *codec = aw_get_codec(dai); + struct aw882xx *aw882xx = + aw_componet_codec_ops.codec_get_drvdata(codec); + + if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { + aw_dev_info(aw882xx->dev, "stream capture requested rate: %d, sample size: %d", + params_rate(params), params_width(params)); + } + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + aw_dev_info(aw882xx->dev, "stream playback requested rate: %d, sample size: %d", + params_rate(params), params_width(params)); + } + + return 0; +} + +static void aw882xx_shutdown(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + aw_snd_soc_codec_t *codec = aw_get_codec(dai); + struct aw882xx *aw882xx = + aw_componet_codec_ops.codec_get_drvdata(codec); + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + aw882xx->rate = 0; + aw_dev_info(aw882xx->dev, "stream playback"); + } else { + aw_dev_info(aw882xx->dev, "stream capture"); + } +} + +static void aw882xx_start_pa(struct aw882xx *aw882xx) +{ + int ret; + int i; + + aw_dev_info(aw882xx->dev, "enter"); + + if (aw882xx->fw_status == AW_DEV_FW_OK) { + if (aw882xx->allow_pw == false) { + aw_dev_info(aw882xx->dev, "dev can not allow power "); + return; + } + + for (i = 0; i < AW_START_RETRIES; i++) { + /*if PA already power ,stop PA then start*/ + if (aw882xx->aw_pa->status) { + aw_dev_info(aw882xx->dev, "already start"); + return; + } + + ret = aw882xx_dev_reg_update(aw882xx->aw_pa, aw882xx->phase_sync); + if (ret) { + aw_dev_err(aw882xx->dev, "fw update failed, cnt:%d", i); + continue; + } + + ret = aw882xx_device_start(aw882xx->aw_pa); + if (ret) { + aw_dev_err(aw882xx->dev, "start failed, cnt:%d", i); + continue; + } else { + if (aw882xx->dc_flag) + queue_delayed_work(aw882xx->work_queue, + &aw882xx->dc_work, + msecs_to_jiffies(AW882XX_DC_DELAY_TIME)); + aw_dev_info(aw882xx->dev, "start success"); + break; + } + } + } else { + aw_dev_info(aw882xx->dev, "dev acf load failed"); + } + +} + +static int aw882xx_mute(struct snd_soc_dai *dai, int mute, int stream) +{ + int ret = 0; + aw_snd_soc_codec_t *codec = aw_get_codec(dai); + struct aw882xx *aw882xx = + aw_componet_codec_ops.codec_get_drvdata(codec); + + aw_dev_info(aw882xx->dev, "mute state=%d", mute); + + if (stream != SNDRV_PCM_STREAM_PLAYBACK) { + aw_dev_info(aw882xx->dev, "capture"); + return 0; + } + + if (mute) { + aw882xx->pstream = false; + cancel_delayed_work_sync(&aw882xx->dc_work); + cancel_delayed_work_sync(&aw882xx->start_work); + mutex_lock(&aw882xx->lock); + g_algo_auth_st = AW_ALGO_AUTH_WAIT; + aw882xx_device_stop(aw882xx->aw_pa); + mutex_unlock(&aw882xx->lock); + } else { + if (aw882xx->fw_status == AW_DEV_FW_FAILED) { + aw_dev_info(aw882xx->dev, "fw_load failed ,can not start PA"); + return 0; + } + aw882xx->pstream = true; + mutex_lock(&aw882xx->lock); + /*aw882xx_start_pa(aw882xx);*/ + queue_delayed_work(aw882xx->work_queue, + &aw882xx->start_work, 0); + if (aw882xx->aw_pa->channel == 0) { + ret = aw882xx_spin_set_record_val(aw882xx->aw_pa); + if (ret) + aw_dev_err(aw882xx->dev, "set spin error, ret=%d", ret); + } + mutex_unlock(&aw882xx->lock); + } + + return ret; +} + +static const struct snd_soc_dai_ops aw882xx_dai_ops = { + .startup = aw882xx_startup, + .set_fmt = aw882xx_set_fmt, + .set_sysclk = aw882xx_set_dai_sysclk, + .hw_params = aw882xx_hw_params, + .mute_stream = aw882xx_mute, + .shutdown = aw882xx_shutdown, +}; + +/***************************************************** + * + * snd_soc_codec_driver | snd_soc_component_driver| + * + *****************************************************/ + +static int aw882xx_profile_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + int count, ret = 0; + int res = 0; + char *name = NULL; + aw_snd_soc_codec_t *codec = + aw_componet_codec_ops.kcontrol_codec(kcontrol); + struct aw882xx *aw882xx = + aw_componet_codec_ops.codec_get_drvdata(codec); + + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + uinfo->count = 1; + + count = aw882xx_dev_get_profile_count(aw882xx->aw_pa); + if (count <= 0) { + uinfo->value.enumerated.items = 0; + aw_dev_err(aw882xx->dev, "get count[%d] failed ", count); + return 0; + } + + uinfo->value.enumerated.items = count; + + if (uinfo->value.enumerated.item >= count) + uinfo->value.enumerated.item = count - 1; + + name = uinfo->value.enumerated.name; + count = uinfo->value.enumerated.item; + ret = aw88xx_dev_get_profile_name(aw882xx->aw_pa, name, count); + if (ret) { + res = strscpy(uinfo->value.enumerated.name, "null", strlen("null") + 1); + if (res < 0) + aw_dev_err(aw882xx->dev, "copy enumerated name failed"); + } + + return 0; +} + +static int aw882xx_profile_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + aw_snd_soc_codec_t *codec = + aw_componet_codec_ops.kcontrol_codec(kcontrol); + struct aw882xx *aw882xx = + aw_componet_codec_ops.codec_get_drvdata(codec); + + ucontrol->value.integer.value[0] = aw882xx_dev_get_profile_index(aw882xx->aw_pa); + aw_dev_dbg(codec->dev, "profile index [%d]", aw882xx_dev_get_profile_index(aw882xx->aw_pa)); + return 0; + +} + +static int aw882xx_profile_set(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int ret; + aw_snd_soc_codec_t *codec = + aw_componet_codec_ops.kcontrol_codec(kcontrol); + struct aw882xx *aw882xx = + aw_componet_codec_ops.codec_get_drvdata(codec); + int cur_index; + + if (aw882xx->dbg_en_prof == false) { + aw_dev_info(codec->dev, "profile close "); + return 0; + } + + /* check value valid */ + ret = aw882xx_dev_check_profile_index(aw882xx->aw_pa, ucontrol->value.integer.value[0]); + if (ret) { + aw_dev_info(codec->dev, "unsupported index %d", + (int)ucontrol->value.integer.value[0]); + return -EINVAL; + } + + /*check cur_index == set value*/ + cur_index = aw882xx_dev_get_profile_index(aw882xx->aw_pa); + if (cur_index == ucontrol->value.integer.value[0]) { + aw_dev_info(codec->dev, "index no change"); + return 0; + } + + mutex_lock(&aw882xx->lock); + aw882xx_dev_set_profile_index(aw882xx->aw_pa, ucontrol->value.integer.value[0]); + /*pstream = 0 no pcm just set status*/ + if (aw882xx->pstream && aw882xx->allow_pw) { + aw882xx_device_stop(aw882xx->aw_pa); + aw882xx_start_pa(aw882xx); + } + mutex_unlock(&aw882xx->lock); + aw_dev_info(codec->dev, "prof id %d", (int)ucontrol->value.integer.value[0]); + + return 1; +} + +static int aw882xx_switch_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + int count = 0; + int ret = 0; + + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + uinfo->count = 1; + count = 2; + + uinfo->value.enumerated.items = count; + + if (uinfo->value.enumerated.item >= count) + uinfo->value.enumerated.item = count - 1; + + ret = strscpy(uinfo->value.enumerated.name, + aw882xx_switch[uinfo->value.enumerated.item], + strlen(aw882xx_switch[uinfo->value.enumerated.item]) + 1); + if (ret < 0) + aw_pr_err("copy switch name failed"); + + return 0; +} + +static int aw882xx_switch_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + aw_snd_soc_codec_t *codec = + aw_componet_codec_ops.kcontrol_codec(kcontrol); + struct aw882xx *aw882xx = + aw_componet_codec_ops.codec_get_drvdata(codec); + + ucontrol->value.integer.value[0] = aw882xx->allow_pw; + + return 0; + +} + +static int aw882xx_switch_set(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + aw_snd_soc_codec_t *codec = + aw_componet_codec_ops.kcontrol_codec(kcontrol); + struct aw882xx *aw882xx = + aw_componet_codec_ops.codec_get_drvdata(codec); + + if (aw882xx->pstream) { + if (ucontrol->value.integer.value[0] == 0) { + cancel_delayed_work_sync(&aw882xx->dc_work); + cancel_delayed_work_sync(&aw882xx->start_work); + mutex_lock(&aw882xx->lock); + aw882xx_device_stop(aw882xx->aw_pa); + aw882xx->allow_pw = false; + mutex_unlock(&aw882xx->lock); + aw_dev_info(aw882xx->dev, "stop pa"); + } else { + cancel_delayed_work_sync(&aw882xx->start_work); + mutex_lock(&aw882xx->lock); + aw882xx->allow_pw = true; + if (aw882xx->fw_status == AW_DEV_FW_OK) + aw882xx_start_pa(aw882xx); + else + aw_dev_info(aw882xx->dev, "fw_load failed ,can not start PA"); + mutex_unlock(&aw882xx->lock); + } + } else { + mutex_lock(&aw882xx->lock); + if (ucontrol->value.integer.value[0]) + aw882xx->allow_pw = true; + else + aw882xx->allow_pw = false; + mutex_unlock(&aw882xx->lock); + } + + return 0; +} + +static int aw882xx_monitor_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + int count = 0; + int ret = 0; + + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + uinfo->count = 1; + count = 2; + + uinfo->value.enumerated.items = count; + + if (uinfo->value.enumerated.item >= count) + uinfo->value.enumerated.item = count - 1; + + ret = strscpy(uinfo->value.enumerated.name, + aw882xx_switch[uinfo->value.enumerated.item], + strlen(aw882xx_switch[uinfo->value.enumerated.item]) + 1); + if (ret < 0) + aw_pr_err("copy switch name failed"); + + return 0; +} + +static int aw882xx_monitor_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + aw_snd_soc_codec_t *codec = + aw_componet_codec_ops.kcontrol_codec(kcontrol); + struct aw882xx *aw882xx = + aw_componet_codec_ops.codec_get_drvdata(codec); + struct aw_device *aw_dev = aw882xx->aw_pa; + + ucontrol->value.integer.value[0] = + aw_dev->monitor_desc.monitor_cfg.monitor_switch; + + aw_dev_info(aw882xx->dev, "monitor switch is %ld", + ucontrol->value.integer.value[0]); + return 0; + +} + +static int aw882xx_monitor_set(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + aw_snd_soc_codec_t *codec = + aw_componet_codec_ops.kcontrol_codec(kcontrol); + struct aw882xx *aw882xx = + aw_componet_codec_ops.codec_get_drvdata(codec); + struct aw_device *aw_dev = aw882xx->aw_pa; + uint32_t ctrl_value = 0; + + ctrl_value = ucontrol->value.integer.value[0]; + + aw_dev_info(aw_dev->dev, "set monitor switch is %d", ctrl_value); + + if (aw_dev->monitor_desc.monitor_cfg.monitor_switch == ctrl_value) + return 0; + + aw_dev->monitor_desc.monitor_cfg.monitor_switch = ctrl_value; + if (ctrl_value) + aw882xx_monitor_start(&aw_dev->monitor_desc); + + return 1; +} + +static int aw882xx_hal_monitor_work_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = 1; + uinfo->value.integer.min = INT_MIN; + uinfo->value.integer.max = 0; + + return 0; +} + +static int aw882xx_hal_monitor_work_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + aw_snd_soc_codec_t *codec = + aw_componet_codec_ops.kcontrol_codec(kcontrol); + struct aw882xx *aw882xx = + aw_componet_codec_ops.codec_get_drvdata(codec); + struct aw_device *aw_dev = aw882xx->aw_pa; + uint32_t vmax = 0; + + mutex_lock(&aw882xx->lock); + aw882xx_dev_monitor_hal_work(aw_dev, &vmax); + + ucontrol->value.integer.value[0] = vmax; + mutex_unlock(&aw882xx->lock); + + aw_dev_dbg(aw882xx->dev, "vmax is 0x%x", vmax); + return 0; + +} + +static int aw882xx_volume_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + aw_snd_soc_codec_t *codec = + aw_componet_codec_ops.kcontrol_codec(kcontrol); + struct aw882xx *aw882xx = + aw_componet_codec_ops.codec_get_drvdata(codec); + struct aw_volume_desc *vol_desc = &aw882xx->aw_pa->volume_desc; + + /* set kcontrol info */ + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = 1; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = vol_desc->mute_volume; + + return 0; +} + +static int aw882xx_volume_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + aw_snd_soc_codec_t *codec = + aw_componet_codec_ops.kcontrol_codec(kcontrol); + struct aw882xx *aw882xx = + aw_componet_codec_ops.codec_get_drvdata(codec); + struct aw_volume_desc *vol_desc = &aw882xx->aw_pa->volume_desc; + + ucontrol->value.integer.value[0] = vol_desc->ctl_volume; + + aw_dev_info(aw882xx->dev, "ucontrol->value.integer.value[0]=%d", + vol_desc->ctl_volume); + + return 0; +} + +static int aw882xx_volume_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int value = 0; + int compared_vol = 0; + aw_snd_soc_codec_t *codec = + aw_componet_codec_ops.kcontrol_codec(kcontrol); + struct aw882xx *aw882xx = + aw_componet_codec_ops.codec_get_drvdata(codec); + struct aw_volume_desc *vol_desc = &aw882xx->aw_pa->volume_desc; + + value = ucontrol->value.integer.value[0]; + if ((value > vol_desc->mute_volume) || (value < 0)) { + aw_dev_err(aw882xx->dev, "value over range\n"); + return -EINVAL; + } + + aw_dev_info(aw882xx->dev, "ucontrol->value.integer.value[0]=%d", value); + + if (vol_desc->ctl_volume == value) + return 0; + + vol_desc->ctl_volume = value; + compared_vol = AW_GET_MAX_VALUE(vol_desc->ctl_volume, + vol_desc->monitor_volume); + + aw882xx_dev_set_volume(aw882xx->aw_pa, compared_vol); + + return 1; +} + +static int aw882xx_algo_auth_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES; + uinfo->count = sizeof(struct algo_auth_data); + return 0; +} + +/*op_flag: SNDRV_CTL_TLV_OP_READ = 0, SNDRV_CTL_TLV_OP_WRITE = 1*/ +static int aw882xx_algo_auth_tlv_rw(struct snd_kcontrol *kcontrol, int op_flag, + unsigned int size, unsigned int __user *tlv) +{ + int ret = 0; + aw_snd_soc_codec_t *codec = aw_componet_codec_ops.kcontrol_codec(kcontrol); + struct aw882xx *aw882xx = aw_componet_codec_ops.codec_get_drvdata(codec); + + struct aw_device *aw_pa = aw882xx->aw_pa; + struct algo_auth_data algo_data; + + aw_dev_dbg(aw882xx->dev, "op_flag = [%d]", op_flag); + + if (!tlv) { + aw_dev_err(aw882xx->dev, "tlv is NULL"); + return -EINVAL; + } + + if (size != sizeof(struct algo_auth_data)) { + aw_dev_err(aw882xx->dev, "size != algo_auth_data"); + return -EINVAL; + } + + switch (op_flag) { + case SNDRV_CTL_TLV_OP_READ: + aw_dev_dbg(aw882xx->dev, "get algo auth data"); + memset(&algo_data, 0x0, sizeof(struct algo_auth_data)); + + algo_data.auth_mode = aw_pa->auth_desc.auth_mode; + algo_data.chip_id = aw_pa->auth_desc.chip_id; + algo_data.random = aw_pa->auth_desc.random; + algo_data.reg_crc = aw_pa->auth_desc.reg_crc; + algo_data.check_result = aw_pa->auth_desc.check_result; + + if (copy_to_user((void __user *)tlv, (char *)&algo_data, size)) + ret = -EFAULT; + break; + case SNDRV_CTL_TLV_OP_WRITE: + aw_dev_dbg(aw882xx->dev, "set algo auth data"); + if (copy_from_user(&algo_data, (void __user *)tlv, size)) + ret = -EFAULT; + + aw882xx_dev_algo_auth_mode(aw_pa, &algo_data); + break; + default: + aw_dev_dbg(aw882xx->dev, "unsupport op flag[0x%x]", op_flag); + return -EINVAL; + } + + aw_dev_dbg(aw882xx->dev, "mode=%d,reg_crc=0x%x,random=0x%x,id=0x%x,res=%d", + algo_data.auth_mode, algo_data.reg_crc, algo_data.random, + algo_data.chip_id, algo_data.check_result); + + return ret; +} + +static int aw882xx_dynamic_create_controls(struct aw882xx *aw882xx) +{ + struct snd_kcontrol_new *aw882xx_dev_control = NULL; + char *kctl_name = NULL; + + aw882xx_dev_control = devm_kzalloc(aw882xx->codec->dev, + sizeof(struct snd_kcontrol_new) * AW_KCTL_NUM, GFP_KERNEL); + if (aw882xx_dev_control == NULL) + return -ENOMEM; + + + kctl_name = devm_kzalloc(aw882xx->codec->dev, AW_NAME_BUF_MAX, GFP_KERNEL); + if (!kctl_name) + return -ENOMEM; + + snprintf(kctl_name, AW_NAME_BUF_MAX, "aw_dev_%d_prof", aw882xx->aw_pa->channel); + + aw882xx_dev_control[KCTL_TYPE_PROFILE].name = kctl_name; + aw882xx_dev_control[KCTL_TYPE_PROFILE].iface = SNDRV_CTL_ELEM_IFACE_MIXER; + aw882xx_dev_control[KCTL_TYPE_PROFILE].info = aw882xx_profile_info; + aw882xx_dev_control[KCTL_TYPE_PROFILE].get = aw882xx_profile_get; + aw882xx_dev_control[KCTL_TYPE_PROFILE].put = aw882xx_profile_set; + + kctl_name = devm_kzalloc(aw882xx->codec->dev, AW_NAME_BUF_MAX, GFP_KERNEL); + if (!kctl_name) + return -ENOMEM; + + snprintf(kctl_name, AW_NAME_BUF_MAX, "aw_dev_%d_switch", aw882xx->aw_pa->channel); + + aw882xx_dev_control[KCTL_TYPE_SWITCH].name = kctl_name; + aw882xx_dev_control[KCTL_TYPE_SWITCH].iface = SNDRV_CTL_ELEM_IFACE_MIXER; + aw882xx_dev_control[KCTL_TYPE_SWITCH].info = aw882xx_switch_info; + aw882xx_dev_control[KCTL_TYPE_SWITCH].get = aw882xx_switch_get; + aw882xx_dev_control[KCTL_TYPE_SWITCH].put = aw882xx_switch_set; + + kctl_name = devm_kzalloc(aw882xx->codec->dev, AW_NAME_BUF_MAX, GFP_KERNEL); + if (!kctl_name) + return -ENOMEM; + + snprintf(kctl_name, AW_NAME_BUF_MAX, "aw_dev_%d_monitor", aw882xx->aw_pa->channel); + + aw882xx_dev_control[KCTL_TYPE_MONITOR].name = kctl_name; + aw882xx_dev_control[KCTL_TYPE_MONITOR].iface = SNDRV_CTL_ELEM_IFACE_MIXER; + aw882xx_dev_control[KCTL_TYPE_MONITOR].info = aw882xx_monitor_info; + aw882xx_dev_control[KCTL_TYPE_MONITOR].get = aw882xx_monitor_get; + aw882xx_dev_control[KCTL_TYPE_MONITOR].put = aw882xx_monitor_set; + + + kctl_name = devm_kzalloc(aw882xx->codec->dev, AW_NAME_BUF_MAX, GFP_KERNEL); + if (!kctl_name) + return -ENOMEM; + + snprintf(kctl_name, AW_NAME_BUF_MAX, "aw_dev_%d_volume", aw882xx->aw_pa->channel); + + aw882xx_dev_control[KCTL_TYPE_VOLUME].name = kctl_name; + aw882xx_dev_control[KCTL_TYPE_VOLUME].iface = SNDRV_CTL_ELEM_IFACE_MIXER; + aw882xx_dev_control[KCTL_TYPE_VOLUME].info = aw882xx_volume_info; + aw882xx_dev_control[KCTL_TYPE_VOLUME].get = aw882xx_volume_get; + aw882xx_dev_control[KCTL_TYPE_VOLUME].put = aw882xx_volume_put; + + + kctl_name = devm_kzalloc(aw882xx->codec->dev, AW_NAME_BUF_MAX, GFP_KERNEL); + if (!kctl_name) + return -ENOMEM; + + snprintf(kctl_name, AW_NAME_BUF_MAX, "aw_dev_%d_hal_mon_work", aw882xx->aw_pa->channel); + + aw882xx_dev_control[KCTL_TYPE_MON_HAL].name = kctl_name; + aw882xx_dev_control[KCTL_TYPE_MON_HAL].iface = SNDRV_CTL_ELEM_IFACE_MIXER; + aw882xx_dev_control[KCTL_TYPE_MON_HAL].access = SNDRV_CTL_ELEM_ACCESS_READ; + aw882xx_dev_control[KCTL_TYPE_MON_HAL].info = aw882xx_hal_monitor_work_info; + aw882xx_dev_control[KCTL_TYPE_MON_HAL].get = aw882xx_hal_monitor_work_get; + + aw_componet_codec_ops.add_codec_controls(aw882xx->codec, + aw882xx_dev_control, AW_KCTL_NUM); + + return 0; +} + +static void aw882xx_request_firmware(struct work_struct *work) +{ + int ret = -1; + struct aw882xx *aw882xx = + container_of(work, struct aw882xx, fw_work.work); + const struct firmware *cont = NULL; + struct aw_container *aw_cfg = NULL; + + aw882xx->fw_status = AW_DEV_FW_FAILED; + ret = request_firmware(&cont, ACF_BIN_NAME, aw882xx->dev); + if ((ret) || (!cont)) { + aw_dev_info(aw882xx->dev, "load [%s] failed!", ACF_BIN_NAME); + if (aw882xx->fw_retry_cnt == AW_READ_CHIPID_RETRIES) { + aw882xx->fw_retry_cnt = 0; + } else { + aw882xx->fw_retry_cnt++; + /* sleep 1s */ + msleep(1000); + aw_dev_info(aw882xx->dev, "load [%s] try [%d]!", + ACF_BIN_NAME, aw882xx->fw_retry_cnt); + aw882xx_request_firmware(work); + } + return; + } + + aw_dev_info(aw882xx->dev, "load [%s] , file size: [%zu]", + ACF_BIN_NAME, cont ? cont->size : 0); + + mutex_lock(&g_aw882xx_lock); + if (g_awinic_cfg == NULL) { + aw_cfg = vzalloc(cont->size + sizeof(int)); + if (aw_cfg == NULL) { + release_firmware(cont); + aw_dev_err(aw882xx->dev, "malloc failed"); + mutex_unlock(&g_aw882xx_lock); + return; + } + aw_cfg->len = cont->size; + memcpy(aw_cfg->data, cont->data, cont->size); + release_firmware(cont); + ret = aw882xx_dev_parse_check_acf(aw_cfg); + if (ret) { + aw_dev_err(aw882xx->dev, "Load [%s] failed ....!", ACF_BIN_NAME); + vfree(aw_cfg); + aw_cfg = NULL; + mutex_unlock(&g_aw882xx_lock); + return; + } + g_awinic_cfg = aw_cfg; + } else { + aw_cfg = g_awinic_cfg; + release_firmware(cont); + aw_dev_info(aw882xx->dev, "[%s] already loaded...", ACF_BIN_NAME); + } + mutex_unlock(&g_aw882xx_lock); + + mutex_lock(&aw882xx->lock); + /*aw device init*/ + ret = aw882xx_device_init(aw882xx->aw_pa, aw_cfg); + if (ret < 0) { + aw_dev_info(aw882xx->dev, "dev init failed"); + mutex_unlock(&aw882xx->lock); + return; + } + + /*create kcontrol by profile*/ + aw882xx_dynamic_create_controls(aw882xx); + + aw882xx->fw_status = AW_DEV_FW_OK; + aw882xx->fw_retry_cnt = 0; + + mutex_unlock(&aw882xx->lock); +} + +static void aw882xx_startup_work(struct work_struct *work) +{ + struct aw882xx *aw882xx = container_of(work, struct aw882xx, start_work.work); + + aw_dev_info(aw882xx->dev, "enter"); + + mutex_lock(&aw882xx->lock); + aw882xx_start_pa(aw882xx); + mutex_unlock(&aw882xx->lock); +} + +static void aw882xx_dc_prot_work(struct work_struct *work) +{ + struct aw882xx *aw882xx = container_of(work, struct aw882xx, dc_work.work); + int dc_status = -1; + int dev_status = aw882xx_dev_status(aw882xx->aw_pa); + + if (aw882xx->dc_flag) { + if (dev_status) { + dc_status = aw882xx_dev_dc_status(aw882xx->aw_pa); + if (dc_status > 0) { + cancel_delayed_work_sync(&aw882xx->start_work); + mutex_lock(&aw882xx->lock); + aw882xx_device_stop(aw882xx->aw_pa); + mutex_unlock(&aw882xx->lock); + } else { + queue_delayed_work(aw882xx->work_queue, + &aw882xx->dc_work, + msecs_to_jiffies(AW882XX_DC_DELAY_TIME)); + } + } + } +} + +#ifdef AW882XX_IRQ_START_FLAG +static void aw882xx_irq_restart(struct aw882xx *aw882xx) +{ + int ret; + + aw_dev_dbg(aw882xx->dev, "enter"); + + mutex_lock(&aw882xx->lock); + + /*stop pa*/ + aw882xx_device_stop(aw882xx->aw_pa); + + /*hw reset*/ + aw882xx_hw_reset(aw882xx); + + /*aw reinit*/ + if (aw882xx->fw_status == AW_DEV_FW_OK) { + ret = aw882xx_device_irq_reinit(aw882xx->aw_pa); + if (ret < 0) { + aw_dev_err(aw882xx->dev, "irq reinit failed"); + goto failed_exit; + } + + if (aw882xx->allow_pw && aw882xx->pstream) { + ret = aw882xx_device_start(aw882xx->aw_pa); + if (ret) { + aw_dev_err(aw882xx->dev, "start failed"); + goto failed_exit; + } + } else { + aw_dev_info(aw882xx->dev, "allow_pw [%d] ,pstream[%d], not start", + aw882xx->allow_pw, aw882xx->pstream); + } + } else { + aw_dev_err(aw882xx->dev, "fw not load ,cannot init device"); + } +failed_exit: + mutex_unlock(&aw882xx->lock); +} + +static void aw882xx_interrupt_work(struct work_struct *work) +{ + struct aw882xx *aw882xx = container_of(work, struct aw882xx, interrupt_work.work); + int16_t reg_value; + int ret; + + aw_dev_info(aw882xx->dev, "enter"); + + /*read reg value*/ + ret = aw882xx_dev_get_int_status(aw882xx->aw_pa, ®_value); + if (ret < 0) { + aw_dev_err(aw882xx->dev, "get init_reg value failed"); + } else { + aw_dev_info(aw882xx->dev, "int value 0x%x", reg_value); + if (aw882xx->aw_pa->ops.aw_get_irq_type) { + ret = aw882xx->aw_pa->ops.aw_get_irq_type(aw882xx->aw_pa, reg_value); + if (ret != INT_TYPE_NONE) { + aw882xx_irq_restart(aw882xx); + return; + } + } + } + + /*clear init reg*/ + aw882xx_dev_clear_int_status(aw882xx->aw_pa); + + /*unmask interrupt*/ + aw882xx_dev_set_intmask(aw882xx->aw_pa, true); +} +#else +static void aw882xx_interrupt_work(struct work_struct *work) +{ + struct aw882xx *aw882xx = container_of(work, struct aw882xx, interrupt_work.work); + struct aw_device *aw_dev = aw882xx->aw_pa; + unsigned int reg_value = 0; + + aw882xx_i2c_read(aw882xx, aw_dev->sysst_desc.reg, ®_value); + aw_dev_info(aw882xx->dev, "SYSST is 0x%04x", (uint16_t)reg_value); + + aw882xx_i2c_read(aw882xx, aw_dev->int_desc.st_reg, ®_value); + aw_dev_info(aw882xx->dev, "SYSINT is 0x%04x", (uint16_t)reg_value); + + /*unmask interrupt*/ + aw882xx_dev_set_intmask(aw882xx->aw_pa, true); +} +#endif + +static int aw882xx_set_rx_en(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int ret = -EINVAL; + uint32_t ctrl_value = 0; + aw_snd_soc_codec_t *codec = + aw_componet_codec_ops.kcontrol_codec(kcontrol); + struct aw882xx *aw882xx = + aw_componet_codec_ops.codec_get_drvdata(codec); + + aw_dev_dbg(aw882xx->dev, "ucontrol->value.integer.value[0]=%ld", + ucontrol->value.integer.value[0]); + + ctrl_value = ucontrol->value.integer.value[0]; + + if (aw882xx->pstream) { + ret = aw882xx_dev_set_afe_module_en(AW_RX_MODULE, ctrl_value); + if (ret) + aw_dev_err(aw882xx->dev, "dsp_msg error, ret=%d", ret); + } else { + aw_dev_info(aw882xx->dev, "stream no start only record"); + } + + g_algo_rx_en = ctrl_value; + aw_dev_info(aw882xx->dev, "set value %d", ctrl_value); + return 0; +} + +static int aw882xx_get_rx_en(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int ret = -EINVAL; + uint32_t ctrl_value = 0; + + aw_snd_soc_codec_t *codec = + aw_componet_codec_ops.kcontrol_codec(kcontrol); + struct aw882xx *aw882xx = + aw_componet_codec_ops.codec_get_drvdata(codec); + + if (aw882xx->pstream) { + ret = aw882xx_dev_get_afe_module_en(AW_RX_MODULE, &ctrl_value); + if (ret) + aw_dev_err(aw882xx->dev, "dsp_msg error, ret=%d", ret); + + ucontrol->value.integer.value[0] = ctrl_value; + } else { + ucontrol->value.integer.value[0] = g_algo_rx_en; + aw_dev_info(aw882xx->dev, "no stream, use record value"); + } + + aw_dev_dbg(aw882xx->dev, "aw882xx_rx_enable %ld", + ucontrol->value.integer.value[0]); + return 0; +} + +static int aw882xx_set_tx_en(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int ret = -EINVAL; + uint32_t ctrl_value = 0; + aw_snd_soc_codec_t *codec = + aw_componet_codec_ops.kcontrol_codec(kcontrol); + struct aw882xx *aw882xx = + aw_componet_codec_ops.codec_get_drvdata(codec); + + aw_dev_dbg(aw882xx->dev, "ucontrol->value.integer.value[0]=%ld", + ucontrol->value.integer.value[0]); + + ctrl_value = ucontrol->value.integer.value[0]; + + if (aw882xx->pstream) { + ret = aw882xx_dev_set_afe_module_en(AW_TX_MODULE, ctrl_value); + if (ret) + aw_dev_err(aw882xx->dev, "dsp_msg error, ret=%d", ret); + } else { + aw_dev_info(aw882xx->dev, "stream no start only record"); + } + + g_algo_tx_en = ctrl_value; + aw_dev_info(aw882xx->dev, "set value %d", ctrl_value); + return 0; +} + +static int aw882xx_get_tx_en(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int ret = -EINVAL; + uint32_t ctrl_value = 0; + aw_snd_soc_codec_t *codec = + aw_componet_codec_ops.kcontrol_codec(kcontrol); + struct aw882xx *aw882xx = + aw_componet_codec_ops.codec_get_drvdata(codec); + + if (aw882xx->pstream) { + ret = aw882xx_dev_get_afe_module_en(AW_TX_MODULE, &ctrl_value); + if (ret) { + aw_dev_err(aw882xx->dev, "dsp_msg error, ret=%d", ret); + ctrl_value = 0; + } + ucontrol->value.integer.value[0] = ctrl_value; + } else { + ucontrol->value.integer.value[0] = g_algo_tx_en; + aw_dev_info(aw882xx->dev, "no stream, use record value"); + } + + aw_dev_dbg(aw882xx->dev, "aw882xx_tx_enable %ld", + ucontrol->value.integer.value[0]); + return 0; +} + +static int aw882xx_set_copp_en(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int ret = -EINVAL; + uint32_t ctrl_value = 0; + aw_snd_soc_codec_t *codec = + aw_componet_codec_ops.kcontrol_codec(kcontrol); + struct aw882xx *aw882xx = + aw_componet_codec_ops.codec_get_drvdata(codec); + + aw_dev_dbg(aw882xx->dev, "ucontrol->value.integer.value[0]=%ld", + ucontrol->value.integer.value[0]); + ctrl_value = ucontrol->value.integer.value[0]; + + if (aw882xx->pstream) { + ret = aw882xx_dev_set_copp_module_en(ctrl_value); + if (ret) + aw_dev_err(aw882xx->dev, "dsp_msg error, ret=%d", ret); + } else { + aw_dev_info(aw882xx->dev, "stream no start only record"); + } + + g_algo_copp_en = ctrl_value; + aw_dev_info(aw882xx->dev, "set value %d", ctrl_value); + + return 0; +} + +static int aw882xx_get_copp_en(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + aw_snd_soc_codec_t *codec = + aw_componet_codec_ops.kcontrol_codec(kcontrol); + struct aw882xx *aw882xx = + aw_componet_codec_ops.codec_get_drvdata(codec); + + ucontrol->value.integer.value[0] = g_algo_copp_en; + + aw_dev_dbg(aw882xx->dev, "done nothing"); + return 0; +} + +void aw882xx_kcontorl_set(struct aw882xx *aw882xx) +{ + int ret; + + ret = aw882xx_dev_set_afe_module_en(AW_RX_MODULE, g_algo_rx_en); + if (ret) + aw_dev_err(aw882xx->dev, "afe set, ret=%d", ret); + + ret = aw882xx_dev_set_copp_module_en(g_algo_copp_en); + if (ret) + aw_dev_err(aw882xx->dev, "copp set error, ret=%d", ret); +} + +static int aw882xx_set_spin(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int ret = -EINVAL; + uint32_t ctrl_value = 0; + struct aw_device *aw_dev = NULL; + aw_snd_soc_codec_t *codec = + aw_componet_codec_ops.kcontrol_codec(kcontrol); + struct aw882xx *aw882xx = + aw_componet_codec_ops.codec_get_drvdata(codec); + + aw_dev_dbg(aw882xx->dev, "ucontrol->value.integer.value[0]=%ld", + ucontrol->value.integer.value[0]); + + aw_dev = aw882xx->aw_pa; + ctrl_value = ucontrol->value.integer.value[0]; + if (ctrl_value >= ARRAY_SIZE(aw882xx_spin)) { + aw_dev_err(aw_dev->dev, "spin value %d is unsupport", ctrl_value); + return -EINVAL; + } + + ret = aw882xx_spin_value_set(aw_dev, ctrl_value, aw882xx->pstream); + if (ret) + aw_dev_err(aw882xx->dev, "set spin error, ret = %d", ret); + return ret; +} + +static int aw882xx_get_spin(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int ret = -EINVAL; + struct aw_device *aw_dev = NULL; + aw_snd_soc_codec_t *codec = + aw_componet_codec_ops.kcontrol_codec(kcontrol); + struct aw882xx *aw882xx = + aw_componet_codec_ops.codec_get_drvdata(codec); + uint32_t ctrl_value = 0; + + aw_dev = aw882xx->aw_pa; + ret = aw882xx_spin_value_get(aw_dev, &ctrl_value, aw882xx->pstream); + if (ret) { + aw_dev_err(aw882xx->dev, "get spin failed!, ret = %d", ret); + ctrl_value = 0; + } + ucontrol->value.integer.value[0] = ctrl_value; + + aw_dev_dbg(aw882xx->dev, "spin value is %s", aw882xx_spin[ctrl_value]); + return 0; +} + +static int aw882xx_get_fade_in_time(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + unsigned int time; + + aw882xx_dev_get_fade_time(&time, true); + ucontrol->value.integer.value[0] = time; + + aw_pr_dbg("step time %ld", ucontrol->value.integer.value[0]); + + return 0; +} + +static int aw882xx_set_fade_in_time(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + + if (ucontrol->value.integer.value[0] > mc->max) { + aw_pr_dbg("set val %ld overflow %d", + ucontrol->value.integer.value[0], mc->max); + return 0; + } + aw882xx_dev_set_fade_time(ucontrol->value.integer.value[0], true); + + aw_pr_dbg("step time %ld", ucontrol->value.integer.value[0]); + return 0; +} + +static int aw882xx_get_fade_out_time(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + unsigned int time; + + aw882xx_dev_get_fade_time(&time, false); + ucontrol->value.integer.value[0] = time; + + aw_pr_dbg("step time %ld", ucontrol->value.integer.value[0]); + + return 0; +} + +static int aw882xx_set_fade_out_time(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + + if (ucontrol->value.integer.value[0] > mc->max) { + aw_pr_dbg("set val %ld overflow %d", + ucontrol->value.integer.value[0], mc->max); + return 0; + } + + aw882xx_dev_set_fade_time(ucontrol->value.integer.value[0], false); + + aw_pr_dbg("step time %ld", ucontrol->value.integer.value[0]); + + return 0; +} + + +static int aw882xx_hal_get_monitor_time(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + unsigned int time; + aw_snd_soc_codec_t *codec = + aw_componet_codec_ops.kcontrol_codec(kcontrol); + struct aw882xx *aw882xx = + aw_componet_codec_ops.codec_get_drvdata(codec); + + aw882xx_dev_monitor_hal_get_time(aw882xx->aw_pa, &time); + ucontrol->value.integer.value[0] = time; + + aw_pr_dbg("get monitor time %ld", ucontrol->value.integer.value[0]); + + return 0; +} + +static int aw882xx_hal_set_monitor_time(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + + return 0; +} + +static const struct soc_enum aw882xx_snd_enum[] = { + SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(aw882xx_switch), aw882xx_switch), + SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(aw882xx_spin), aw882xx_spin), +}; + +static struct snd_kcontrol_new aw882xx_controls[] = { + SOC_ENUM_EXT("aw882xx_rx_switch", aw882xx_snd_enum[0], + aw882xx_get_rx_en, aw882xx_set_rx_en), + SOC_ENUM_EXT("aw882xx_tx_switch", aw882xx_snd_enum[0], + aw882xx_get_tx_en, aw882xx_set_tx_en), + SOC_ENUM_EXT("aw882xx_copp_switch", aw882xx_snd_enum[0], + aw882xx_get_copp_en, aw882xx_set_copp_en), + SOC_SINGLE_EXT("aw882xx_fadein_us", 0, 0, 1000000, 0, + aw882xx_get_fade_in_time, aw882xx_set_fade_in_time), + SOC_SINGLE_EXT("aw882xx_fadeout_us", 0, 0, 1000000, 0, + aw882xx_get_fade_out_time, aw882xx_set_fade_out_time), + SOC_SINGLE_EXT("aw882xx_hal_monitor_time", 0, 0, 100000, 0, + aw882xx_hal_get_monitor_time, aw882xx_hal_set_monitor_time), + +}; + +static struct snd_kcontrol_new aw882xx_spin_control[] = { + SOC_ENUM_EXT("aw882xx_spin_switch", aw882xx_snd_enum[1], + aw882xx_get_spin, aw882xx_set_spin), +}; + +static void aw882xx_add_codec_controls(struct aw882xx *aw882xx) +{ + struct snd_kcontrol_new *aw882xx_dev_control = NULL; + char *kctl_name = NULL; + + aw_dev_info(aw882xx->dev, "enter"); + + aw882xx_dev_control = devm_kzalloc(aw882xx->codec->dev, + sizeof(struct snd_kcontrol_new), GFP_KERNEL); + + if (aw882xx_dev_control == NULL) + return; + + kctl_name = devm_kzalloc(aw882xx->codec->dev, AW_NAME_BUF_MAX, GFP_KERNEL); + if (!kctl_name) + return; + + snprintf(kctl_name, AW_NAME_BUF_MAX, "aw_algo_auth"); + + aw882xx_dev_control[0].name = kctl_name; + aw882xx_dev_control[0].iface = SNDRV_CTL_ELEM_IFACE_MIXER; + aw882xx_dev_control[0].access = SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK|SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE; + aw882xx_dev_control[0].info = aw882xx_algo_auth_info; + aw882xx_dev_control[0].tlv.c = aw882xx_algo_auth_tlv_rw; + + aw_componet_codec_ops.add_codec_controls(aw882xx->codec, aw882xx_dev_control, 1); + + aw_componet_codec_ops.add_codec_controls(aw882xx->codec, + &aw882xx_controls[0], ARRAY_SIZE(aw882xx_controls)); + + if (aw882xx->aw_pa->spin_desc.aw_spin_kcontrol_st == AW_SPIN_KCONTROL_ENABLE) + aw_componet_codec_ops.add_codec_controls(aw882xx->codec, + aw882xx_spin_control, ARRAY_SIZE(aw882xx_spin_control)); +} + +static int aw882xx_append_i2c_suffix(char *format, + const char **name, struct aw882xx *aw882xx) +{ + char buf[64]; + int i2cbus = aw882xx->i2c->adapter->nr; + int i2caddr = aw882xx->i2c->addr; + + snprintf(buf, sizeof(buf), format, *name, i2cbus, i2caddr); + (*name) = aw882xx_devm_kstrdup(aw882xx->dev, buf); + if (!(*name)) + return -ENOMEM; + + aw_dev_info(aw882xx->dev, "change name is %s", (*name)); + return 0; +} + +static int aw882xx_append_channel_suffix(char *format, + const char **name, struct aw882xx *aw882xx) +{ + char buf[64]; + int channel = aw882xx->aw_pa->channel; + + snprintf(buf, sizeof(buf), format, *name, channel); + (*name) = aw882xx_devm_kstrdup(aw882xx->dev, buf); + if (!(*name)) + return -ENOMEM; + + aw_dev_info(aw882xx->dev, "change name is %s", (*name)); + return 0; +} + +#ifdef AW_MTK_PLATFORM_WITH_DSP +static const struct snd_soc_dapm_widget aw882xx_dapm_widgets[] = { + /* playback */ + SND_SOC_DAPM_AIF_IN("AIF_RX", "Speaker_Playback", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_OUTPUT("audio_out"), + /* capture */ + SND_SOC_DAPM_AIF_OUT("AIF_TX", "Speaker_Capture", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_INPUT("iv_in"), +}; + +static const struct snd_soc_dapm_route aw882xx_audio_map[] = { + {"audio_out", NULL, "AIF_RX"}, + {"AIF_TX", NULL, "iv_in"}, +}; + +#if KERNEL_VERSION(4, 2, 0) > LINUX_VERSION_CODE +static struct snd_soc_dapm_context *snd_soc_codec_get_dapm(struct snd_soc_codec *codec) +{ + return &codec->dapm; +} +#endif +#endif + +static void aw882xx_add_widgets(struct aw882xx *aw882xx) +{ +#ifdef AW_MTK_PLATFORM_WITH_DSP + int ret; + int i = 0; + struct snd_soc_dapm_widget *aw_widgets = NULL; + struct snd_soc_dapm_route *aw_route = NULL; +#ifdef AW_KERNEL_VER_OVER_4_19_1 + struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(aw882xx->codec); +#else + struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(aw882xx->codec); +#endif + + + /*add widgets*/ + aw_widgets = devm_kzalloc(aw882xx->dev, + sizeof(struct snd_soc_dapm_widget) * ARRAY_SIZE(aw882xx_dapm_widgets), + GFP_KERNEL); + if (!aw_widgets) { + aw_dev_err(aw882xx->dev, "alloc widget memory failed!"); + return; + } + memcpy(aw_widgets, aw882xx_dapm_widgets, + sizeof(struct snd_soc_dapm_widget) * ARRAY_SIZE(aw882xx_dapm_widgets)); + + for (i = 0; i < ARRAY_SIZE(aw882xx_dapm_widgets); i++) { + if (aw882xx->rename_flag == AW_RENAME_ENABLE) { + if (aw_widgets[i].name) { + ret = aw882xx_append_channel_suffix("%s_%d", + &aw_widgets[i].name, aw882xx); + if (ret) { + aw_dev_err(aw882xx->dev, "append widget name channel suffix failed!"); + return; + } + } + + if (aw_widgets[i].sname) { + ret = aw882xx_append_channel_suffix("%s_%d", + &aw_widgets[i].sname, aw882xx); + if (ret) { + aw_dev_err(aw882xx->dev, "append widget sname channel suffix failed!"); + return; + } + } + } else { + if (aw_widgets[i].name) { + ret = aw882xx_append_i2c_suffix("%s_%d_%x", + &aw_widgets[i].name, aw882xx); + if (ret) { + aw_dev_err(aw882xx->dev, "append widget name i2c suffix failed!"); + return; + } + } + + if (aw_widgets[i].sname) { + ret = aw882xx_append_i2c_suffix("%s_%d_%x", + &aw_widgets[i].sname, aw882xx); + if (ret) { + aw_dev_err(aw882xx->dev, "append widget sname i2c suffix failed!"); + return; + } + } + } + + } + + snd_soc_dapm_new_controls(dapm, aw_widgets, ARRAY_SIZE(aw882xx_dapm_widgets)); + + /*add route*/ + aw_route = devm_kzalloc(aw882xx->dev, + sizeof(struct snd_soc_dapm_route) * ARRAY_SIZE(aw882xx_audio_map), + GFP_KERNEL); + if (!aw_route) { + aw_dev_err(aw882xx->dev, "alloc route memory failed!"); + return; + } + memcpy(aw_route, aw882xx_audio_map, + sizeof(struct snd_soc_dapm_route) * ARRAY_SIZE(aw882xx_audio_map)); + + for (i = 0; i < ARRAY_SIZE(aw882xx_audio_map); i++) { + if (aw882xx->rename_flag == AW_RENAME_ENABLE) { + if (aw_route[i].sink) { + ret = aw882xx_append_channel_suffix("%s_%d", + &aw_route[i].sink, aw882xx); + if (ret < 0) { + aw_dev_err(aw882xx->dev, "append sink channel suffix failed!"); + return; + } + } + + if (aw_route[i].source) { + ret = aw882xx_append_channel_suffix("%s_%d", + &aw_route[i].source, aw882xx); + if (ret < 0) { + aw_dev_err(aw882xx->dev, "append source channel suffix failed!"); + return; + } + } + } else { + if (aw_route[i].sink) { + ret = aw882xx_append_i2c_suffix("%s_%d_%x", + &aw_route[i].sink, aw882xx); + if (ret < 0) { + aw_dev_err(aw882xx->dev, "append sink i2c suffix failed!"); + return; + } + } + + if (aw_route[i].source) { + ret = aw882xx_append_i2c_suffix("%s_%d_%x", + &aw_route[i].source, aw882xx); + if (ret < 0) { + aw_dev_err(aw882xx->dev, "append source i2c suffix failed!"); + return; + } + } + } + + } + snd_soc_dapm_add_routes(dapm, aw_route, ARRAY_SIZE(aw882xx_audio_map)); +#endif +} + +static void aw882xx_load_fw(struct aw882xx *aw882xx) +{ + if (aw882xx->sync_load) { + aw882xx_request_firmware(&aw882xx->fw_work.work); + } else { + queue_delayed_work(aw882xx->work_queue, + &aw882xx->fw_work, + msecs_to_jiffies(AW882XX_LOAD_FW_DELAY_TIME)); + } +} + +static int aw882xx_codec_probe(aw_snd_soc_codec_t *aw_codec) +{ + struct aw882xx *aw882xx = + aw_componet_codec_ops.codec_get_drvdata(aw_codec); + aw_dev_info(aw882xx->dev, "enter"); + + aw882xx->work_queue = create_singlethread_workqueue("aw882xx"); + if (!aw882xx->work_queue) { + aw_dev_err(aw882xx->dev, "create workqueue failed !"); + return -EINVAL; + } + + INIT_DELAYED_WORK(&aw882xx->start_work, aw882xx_startup_work); + INIT_DELAYED_WORK(&aw882xx->interrupt_work, aw882xx_interrupt_work); + INIT_DELAYED_WORK(&aw882xx->dc_work, aw882xx_dc_prot_work); + INIT_DELAYED_WORK(&aw882xx->fw_work, aw882xx_request_firmware); + + aw882xx->codec = aw_codec; + + if (aw882xx->aw_pa->channel == 0) + aw882xx_add_codec_controls(aw882xx); + + aw882xx_add_widgets(aw882xx); + + /*load fw bin*/ + aw882xx_load_fw(aw882xx); + + /*load cali re*/ + aw882xx_dev_init_cali_re(aw882xx->aw_pa); + + return 0; +} + +#ifdef AW_KERNEL_VER_OVER_4_19_1 +static void aw882xx_codec_remove(aw_snd_soc_codec_t *aw_codec) +{ + struct aw882xx *aw882xx = + aw_componet_codec_ops.codec_get_drvdata(aw_codec); + aw_dev_info(aw882xx->dev, "enter"); + aw882xx_dev_deinit(aw882xx->aw_pa); + destroy_workqueue(aw882xx->work_queue); + aw882xx->work_queue = NULL; +} +#else +static int aw882xx_codec_remove(aw_snd_soc_codec_t *aw_codec) +{ + struct aw882xx *aw882xx = + aw_componet_codec_ops.codec_get_drvdata(aw_codec); + + aw_dev_info(aw882xx->dev, "enter"); + aw882xx_dev_deinit(aw882xx->aw_pa); + destroy_workqueue(aw882xx->work_queue); + aw882xx->work_queue = NULL; + return 0; +} +#endif + +static int aw882xx_dai_drv_append_suffix(struct aw882xx *aw882xx, + struct snd_soc_dai_driver *dai_drv, + int num_dai) +{ + int ret; + int i; + + if ((dai_drv != NULL) && (num_dai > 0)) + for (i = 0; i < num_dai; i++) { + if (aw882xx->rename_flag == AW_RENAME_ENABLE) { + ret = aw882xx_append_channel_suffix("%s-%d", + &dai_drv->name, aw882xx); + if (ret < 0) + return ret; + ret = aw882xx_append_channel_suffix("%s_%d", + &dai_drv->playback.stream_name, aw882xx); + if (ret < 0) + return ret; + ret = aw882xx_append_channel_suffix("%s_%d", + &dai_drv->capture.stream_name, aw882xx); + if (ret < 0) + return ret; + dev_set_name(aw882xx->dev, "%s_%d", + "aw882xx_smartpa", aw882xx->aw_pa->channel); + aw_dev_info(aw882xx->dev, "change dev_name:%s", + dev_name(aw882xx->dev)); + } else { + ret = aw882xx_append_i2c_suffix("%s-%d-%x", + &dai_drv->name, aw882xx); + if (ret < 0) + return ret; + ret = aw882xx_append_i2c_suffix("%s_%d_%x", + &dai_drv->playback.stream_name, aw882xx); + if (ret < 0) + return ret; + ret = aw882xx_append_i2c_suffix("%s_%d_%x", + &dai_drv->capture.stream_name, aw882xx); + if (ret < 0) + return ret; + } + + aw_dev_info(aw882xx->dev, "dai name [%s]", dai_drv[i].name); + aw_dev_info(aw882xx->dev, "pstream_name name [%s]", dai_drv[i].playback.stream_name); + aw_dev_info(aw882xx->dev, "cstream_name name [%s]", dai_drv[i].capture.stream_name); + } + + return 0; +} + +static struct snd_soc_dai_driver aw882xx_dai[] = { + { + .name = "aw882xx-aif", + .id = 1, + .playback = { + .stream_name = "Speaker_Playback", + .channels_min = 1, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_8000_48000 | SNDRV_PCM_RATE_96000, + .formats = (SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S24_LE | + SNDRV_PCM_FMTBIT_S32_LE), + }, + .capture = { + .stream_name = "Speaker_Capture", + .channels_min = 1, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_8000_48000 | SNDRV_PCM_RATE_96000, + .formats = (SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S24_LE | + SNDRV_PCM_FMTBIT_S32_LE), + }, + .ops = &aw882xx_dai_ops, + /* .symmetric_rates = 1,*/ + }, +}; + + +#ifdef AW_KERNEL_VER_OVER_4_19_1 +static const struct snd_soc_component_driver soc_codec_dev_aw882xx = { + .probe = aw882xx_codec_probe, + .remove = aw882xx_codec_remove, +}; +#else +static const struct snd_soc_codec_driver soc_codec_dev_aw882xx = { + .probe = aw882xx_codec_probe, + .remove = aw882xx_codec_remove, +}; +#endif + +static int aw_componet_codec_register(struct aw882xx *aw882xx) +{ + int ret = 0; + struct snd_soc_dai_driver *dai_drv = NULL; + + dai_drv = devm_kzalloc(aw882xx->dev, sizeof(aw882xx_dai), GFP_KERNEL); + if (dai_drv == NULL) + return -ENOMEM; + + + memcpy(dai_drv, aw882xx_dai, sizeof(aw882xx_dai)); + + aw882xx_dai_drv_append_suffix(aw882xx, dai_drv, ARRAY_SIZE(aw882xx_dai)); + + ret = aw882xx->codec_ops->register_codec(aw882xx->dev, + &soc_codec_dev_aw882xx, + dai_drv, ARRAY_SIZE(aw882xx_dai)); + if (ret < 0) { + aw_dev_err(aw882xx->dev, "failed to register aw882xx: %d", ret); + return -EINVAL; + } + + if (aw882xx->rename_flag == AW_RENAME_ENABLE) { + dev_set_name(aw882xx->dev, "%d-00%x", + aw882xx->i2c->adapter->nr, aw882xx->i2c->addr); + aw_dev_info(aw882xx->dev, "reset dev_name:%s", + dev_name(aw882xx->dev)); + } + + return 0; +} +/***************************************************** + * + * device tree + * + *****************************************************/ +static int aw882xx_parse_gpio_dt(struct aw882xx *aw882xx, + struct device_node *np) +{ + if (!np) { + aw882xx->reset_gpio = -1; + aw882xx->irq_gpio = -1; + return -EINVAL; + } + + aw882xx->reset_gpio = of_get_named_gpio(np, "reset-gpio", 0); + if (aw882xx->reset_gpio < 0) + aw_dev_info(aw882xx->dev, "no reset gpio provided, will not HW reset device"); + else + aw_dev_info(aw882xx->dev, "reset gpio provided ok"); + + aw882xx->irq_gpio = of_get_named_gpio(np, "irq-gpio", 0); + if (aw882xx->irq_gpio < 0) + aw_dev_info(aw882xx->dev, "no irq gpio provided."); + else + aw_dev_info(aw882xx->dev, "irq gpio provided ok."); + + + return 0; +} + +static struct aw882xx *aw882xx_malloc_init(struct i2c_client *i2c) +{ + struct aw882xx *aw882xx = devm_kzalloc(&i2c->dev, sizeof(struct aw882xx), GFP_KERNEL); + + if (aw882xx == NULL) + return NULL; + + aw882xx->aw_pa = devm_kzalloc(&i2c->dev, sizeof(struct aw_device), GFP_KERNEL); + if (aw882xx->aw_pa == NULL) + return NULL; + + aw882xx->dev = &i2c->dev; + aw882xx->i2c = i2c; + aw882xx->codec = NULL; + aw882xx->codec_ops = &aw_componet_codec_ops; + aw882xx->fw_status = AW_DEV_FW_FAILED; + aw882xx->fw_retry_cnt = 0; + aw882xx->dbg_en_prof = true; + aw882xx->allow_pw = true; + aw882xx->work_queue = NULL; + + mutex_init(&aw882xx->lock); + + return aw882xx; +} + +static int aw882xx_gpio_request(struct aw882xx *aw882xx) +{ + int ret = 0; + + if (gpio_is_valid(aw882xx->reset_gpio)) { + ret = devm_gpio_request_one(aw882xx->dev, aw882xx->reset_gpio, + GPIOF_OUT_INIT_LOW, "aw882xx_rst"); + if (ret) { + aw_dev_err(aw882xx->dev, "rst request failed"); + return ret; + } + } + + if (gpio_is_valid(aw882xx->irq_gpio)) { + ret = devm_gpio_request_one(aw882xx->dev, aw882xx->irq_gpio, + GPIOF_DIR_IN, "aw882xx_int"); + if (ret) { + aw_dev_err(aw882xx->dev, "int request failed"); + return ret; + } + } + + return 0; +} + +static void aw882xx_parse_rename_flag_dt(struct aw882xx *aw882xx) +{ + int ret; + uint32_t rename_enable = 0; + struct device_node *np = aw882xx->dev->of_node; + + ret = of_property_read_u32(np, "rename-flag", &rename_enable); + if (ret) + aw_dev_info(aw882xx->dev, "read rename flag failed, default rename off!"); + else + aw_dev_info(aw882xx->dev, "rename-flag = %d", rename_enable); + + + aw882xx->rename_flag = rename_enable; + +} + +static void aw882xx_parse_sync_load_dt(struct aw882xx *aw882xx) +{ + int ret = -1; + int32_t sync_load = 0; + struct device_node *np = aw882xx->dev->of_node; + + ret = of_property_read_u32(np, "sync-load", &sync_load); + if (ret < 0) { + aw_dev_info(aw882xx->dev, + "read sync load failed,default async loading fw"); + sync_load = false; + } else { + aw_dev_info(aw882xx->dev, + "sync load is %d", sync_load); + } + + aw882xx->sync_load = sync_load; +} + +static int aw882xx_parse_dt(struct device *dev, struct aw882xx *aw882xx, + struct device_node *np) +{ + int ret; + int32_t dc_enable = 0; + int32_t sync_enable = 0; + + /*gpio dts parser*/ + ret = aw882xx_parse_gpio_dt(aw882xx, np); + if (ret) + return ret; + + ret = of_property_read_u32(np, "dc-flag", &dc_enable); + if (ret) { + dc_enable = false; + aw_dev_info(aw882xx->dev, "close dc protect!"); + } else { + aw_dev_info(aw882xx->dev, "dc-flag = %d", dc_enable); + } + + aw882xx->dc_flag = dc_enable; + + + ret = of_property_read_u32(np, "sync-flag", &sync_enable); + if (ret < 0) { + aw_dev_info(aw882xx->dev, + "read sync flag failed,default phase sync off"); + sync_enable = false; + } else { + aw_dev_info(aw882xx->dev, + "sync flag is %d", sync_enable); + } + + aw882xx->phase_sync = sync_enable; + + aw882xx_parse_rename_flag_dt(aw882xx); + aw882xx_parse_sync_load_dt(aw882xx); + + return 0; +} + +int aw882xx_hw_reset(struct aw882xx *aw882xx) +{ + aw_dev_info(aw882xx->dev, "enter"); + + if (gpio_is_valid(aw882xx->reset_gpio)) { + gpio_set_value_cansleep(aw882xx->reset_gpio, 0); + mdelay(1); + gpio_set_value_cansleep(aw882xx->reset_gpio, 1); + mdelay(2); + } else { + aw_dev_info(aw882xx->dev, "has no reset gpio"); + } + return 0; +} + +static int aw882xx_read_chipid(struct aw882xx *aw882xx) +{ + int ret = -1; + unsigned int cnt = 0; + unsigned int reg_value = 0; + + while (cnt < AW_READ_CHIPID_RETRIES) { + ret = aw882xx_i2c_read(aw882xx, AW882XX_CHIP_ID_REG, ®_value); + if (ret < 0) { + aw_dev_err(aw882xx->dev, "failed to read REG_ID: %d", ret); + return -EIO; + } + switch (reg_value) { + case PID_1852_ID: { + aw_dev_info(aw882xx->dev, "aw882xx 1852 detected"); + aw882xx->aw_pa->chip_id = reg_value; + return 0; + } + case PID_2013_ID: { + aw_dev_info(aw882xx->dev, "aw882xx 2013 detected"); + aw882xx->aw_pa->chip_id = reg_value; + return 0; + } + case PID_2032_ID: { + aw_dev_info(aw882xx->dev, "aw882xx 2032 detected"); + aw882xx->aw_pa->chip_id = reg_value; + return 0; + } + case PID_2055_ID: { + aw_dev_info(aw882xx->dev, "aw882xx 2055 detected"); + aw882xx->aw_pa->chip_id = reg_value; + return 0; + } + case PID_2071_ID: { + aw_dev_info(aw882xx->dev, "aw882xx 2071 detected"); + aw882xx->aw_pa->chip_id = reg_value; + return 0; + } + case PID_2113_ID: { + aw_dev_info(aw882xx->dev, "aw882xx 2113 detected"); + aw882xx->aw_pa->chip_id = reg_value; + return 0; + } + case PID_2308_ID: { + aw_dev_info(aw882xx->dev, "aw882xx 2308 detected"); + aw882xx->aw_pa->chip_id = reg_value; + return 0; + } + default: + aw_dev_info(aw882xx->dev, "unsupported device revision (0x%x)", + reg_value); + break; + } + cnt++; + + msleep(AW_READ_CHIPID_RETRY_DELAY); + } + + return -EINVAL; +} + +static irqreturn_t aw882xx_irq(int irq, void *data) +{ + struct aw882xx *aw882xx = (struct aw882xx *)data; + + if (!aw882xx) { + aw_pr_err("pointer is NULL"); + return -EINVAL; + } + aw_dev_info(aw882xx->dev, "enter"); + + /* mask all irq */ + aw882xx_dev_set_intmask(aw882xx->aw_pa, false); + + /* upload workqueue */ + if (aw882xx->work_queue) + queue_delayed_work(aw882xx->work_queue, &aw882xx->interrupt_work, 0); + + return IRQ_HANDLED; +} + +static int aw882xx_interrupt_init(struct aw882xx *aw882xx) +{ + int ret; + int irq_flags; + + if (gpio_is_valid(aw882xx->irq_gpio)) { + irq_flags = IRQF_TRIGGER_FALLING | IRQF_ONESHOT; + ret = devm_request_threaded_irq(aw882xx->dev, + gpio_to_irq(aw882xx->irq_gpio), + NULL, aw882xx_irq, irq_flags, + "aw882xx", aw882xx); + if (ret != 0) { + aw_dev_err(aw882xx->dev, "Failed to request IRQ %d: %d", + gpio_to_irq(aw882xx->irq_gpio), ret); + return ret; + } + } else { + aw_dev_info(aw882xx->dev, "gpio invalid"); + /* disable interrupt */ + } + + return 0; +} + +static ssize_t reg_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct aw882xx *aw882xx = dev_get_drvdata(dev); + unsigned int databuf[2] = {0}; + + if (sscanf(buf, "%x %x", &databuf[0], &databuf[1]) == 2) + aw882xx_i2c_write(aw882xx, databuf[0], databuf[1]); + + return count; +} + +static ssize_t reg_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct aw882xx *aw882xx = dev_get_drvdata(dev); + ssize_t len = 0; + unsigned char i = 0; + unsigned int reg_val = 0; + int reg_num = aw882xx->aw_pa->ops.aw_get_reg_num(); + + for (i = 0; i < reg_num; i++) { + if (aw882xx->aw_pa->ops.aw_check_rd_access(i)) { + aw882xx_i2c_read(aw882xx, i, ®_val); + len += snprintf(buf+len, PAGE_SIZE-len, + "reg:0x%02x=0x%04x\n", i, reg_val); + } + } + + return len; +} + +static ssize_t rw_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct aw882xx *aw882xx = dev_get_drvdata(dev); + + unsigned int databuf[2] = {0}; + + if (sscanf(buf, "%x %x", &databuf[0], &databuf[1]) == 2) { + aw882xx->rw_reg_addr = (unsigned char)databuf[0]; + if (aw882xx->aw_pa->ops.aw_check_rd_access(databuf[0])) + aw882xx_i2c_write(aw882xx, databuf[0], databuf[1]); + } else if (kstrtouint(buf, 16, &databuf[0]) == 0) { + aw882xx->rw_reg_addr = (unsigned char)databuf[0]; + } + + return count; +} + +static ssize_t rw_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct aw882xx *aw882xx = dev_get_drvdata(dev); + ssize_t len = 0; + unsigned int reg_val = 0; + + if (aw882xx->aw_pa->ops.aw_check_rd_access(aw882xx->rw_reg_addr)) { + aw882xx_i2c_read(aw882xx, aw882xx->rw_reg_addr, ®_val); + len += snprintf(buf + len, PAGE_SIZE - len, + "reg:0x%02x=0x%04x\n", aw882xx->rw_reg_addr, reg_val); + } + return len; +} + +static int aw882xx_awrw_write(struct aw882xx *aw882xx, const char *buf, size_t count) +{ + int i, ret; + char *data_buf = NULL; + int str_len, data_len, temp_data; + char *reg_data = NULL; + struct aw882xx_i2c_packet *packet = &aw882xx->i2c_packet; + + aw_dev_info(aw882xx->dev, "write:reg_addr[0x%02x], reg_num[%d]", + packet->reg_addr, packet->reg_num); + + data_len = AWRW_DATA_BYTES * packet->reg_num; + + str_len = count - AWRW_HDR_LEN - 1; + + if ((data_len * 5 - 1) > str_len) { + aw_dev_err(aw882xx->dev, "data_str_len [%d], requeset len [%d]", + str_len, (data_len * 5 - 1)); + return -EINVAL; + } + + data_buf = kmalloc(data_len + 1, GFP_KERNEL); + if (data_buf == NULL) + return -ENOMEM; + + + data_buf[0] = packet->reg_addr; + reg_data = data_buf + 1; + + aw_dev_dbg(aw882xx->dev, "reg_addr: 0x%02x", data_buf[0]); + + for (i = 0; i < data_len; i++) { + if (sscanf(buf + AWRW_HDR_LEN + 1 + i * 5, "0x%02x", &temp_data) == 1) { + reg_data[i] = temp_data; + aw_dev_dbg(aw882xx->dev, "[%d] : 0x%02x", i, reg_data[i]); + } else { + return -EINVAL; + } + } + + ret = i2c_master_send(aw882xx->i2c, data_buf, data_len + 1); + if (ret < 0) { + aw_dev_err(aw882xx->dev, "write failed"); + kfree(data_buf); + data_buf = NULL; + return -EFAULT; + } + + kfree(data_buf); + data_buf = NULL; + + aw_dev_info(aw882xx->dev, "write success"); + return 0; +} + +static int aw882xx_awrw_data_check(struct aw882xx *aw882xx, int *data) +{ + int reg_num_max = aw882xx->aw_pa->ops.aw_get_reg_num(); + + if ((data[AWRW_HDR_ADDR_BYTES] != AWRW_ADDR_BYTES) || + (data[AWRW_HDR_DATA_BYTES] != AWRW_DATA_BYTES)) { + aw_dev_err(aw882xx->dev, "addr_bytes [%d] or data_bytes [%d] unsupport", + data[AWRW_HDR_ADDR_BYTES], data[AWRW_HDR_DATA_BYTES]); + return -EINVAL; + } + + if (data[AWRW_HDR_REG_ADDR] >= reg_num_max) { + aw_dev_err(aw882xx->dev, "reg_addr[%d] > reg_max[%d]", + data[AWRW_HDR_REG_ADDR], reg_num_max); + return -EINVAL; + } + + return 0; +} + +/* flag addr_bytes data_bytes reg_num reg_addr*/ +static int aw882xx_awrw_parse_buf(struct aw882xx *aw882xx, + const char *buf, size_t count) +{ + int ret; + int data[AWRW_HDR_MAX] = {0}; + struct aw882xx_i2c_packet *packet = &aw882xx->i2c_packet; + + if (sscanf(buf, "0x%02x 0x%02x 0x%02x 0x%02x 0x%02x", + &data[AWRW_HDR_WR_FLAG], + &data[AWRW_HDR_ADDR_BYTES], + &data[AWRW_HDR_DATA_BYTES], + &data[AWRW_HDR_REG_NUM], + &data[AWRW_HDR_REG_ADDR]) == 5) { + ret = aw882xx_awrw_data_check(aw882xx, data); + if (ret < 0) + return ret; + + packet->reg_addr = data[AWRW_HDR_REG_ADDR]; + packet->reg_num = data[AWRW_HDR_REG_NUM]; + + switch (data[AWRW_HDR_WR_FLAG]) { + case AWRW_FLAG_WRITE: + return aw882xx_awrw_write(aw882xx, buf, count); + case AWRW_FLAG_READ: + packet->status = AWRW_I2C_ST_READ; + aw_dev_info(aw882xx->dev, "read_cmd:reg_addr[0x%02x], reg_num[%d]", + packet->reg_addr, packet->reg_num); + return 0; + default: + aw_dev_err(aw882xx->dev, "please check str format, unsupport flag %d", + data[AWRW_HDR_WR_FLAG]); + return -EINVAL; + } + } + + aw_dev_err(aw882xx->dev, "can not parse string"); + + return -EINVAL; +} + +static ssize_t awrw_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + int ret; + struct aw882xx *aw882xx = dev_get_drvdata(dev); + + if (count < AWRW_HDR_LEN) { + aw_dev_err(dev, "data count too smaller, please check write format"); + aw_dev_err(dev, "string %s", buf); + return -EINVAL; + } + + ret = aw882xx_awrw_parse_buf(aw882xx, buf, count); + if (ret) + return -EINVAL; + + return count; +} + +static ssize_t awrw_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int ret, i; + struct aw882xx *aw882xx = dev_get_drvdata(dev); + struct aw882xx_i2c_packet *packet = &aw882xx->i2c_packet; + int data_len, len = 0; + char *reg_data = NULL; + + if (packet->status != AWRW_I2C_ST_READ) { + aw_dev_err(aw882xx->dev, "please write read cmd first"); + return -EINVAL; + } + + data_len = AWRW_DATA_BYTES * packet->reg_num; + reg_data = kmalloc(data_len, GFP_KERNEL); + if (reg_data == NULL) + return -ENOMEM; + + ret = aw882xx_i2c_reads(aw882xx, packet->reg_addr, (char *)reg_data, data_len); + if (ret < 0) { + ret = -EFAULT; + goto exit; + } + + aw_dev_info(aw882xx->dev, "reg_addr 0x%02x, reg_num %d", + packet->reg_addr, packet->reg_num); + + for (i = 0; i < data_len; i++) { + len += snprintf(buf + len, PAGE_SIZE - len, + "0x%02x,", reg_data[i]); + aw_dev_dbg(aw882xx->dev, "0x%02x", reg_data[i]); + } + + ret = len; + +exit: + + kfree(reg_data); + reg_data = NULL; + packet->status = AWRW_I2C_ST_NONE; + return ret; +} + + +static ssize_t drv_ver_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + ssize_t len = 0; + + len += snprintf(buf + len, PAGE_SIZE - len, + "driver_ver: %s\n", AW882XX_DRIVER_VERSION); + + return len; +} + +static ssize_t dsp_re_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int ret; + ssize_t len = 0; + int cali_re; + struct aw882xx *aw882xx = dev_get_drvdata(dev); + + ret = aw882xx_dev_get_cali_re(aw882xx->aw_pa, &cali_re); + if (ret) { + len += snprintf(buf + len, PAGE_SIZE - len, + "read dsp_re failed!\n"); + return len; + } + + len += snprintf(buf + len, PAGE_SIZE - len, + "%d\n", cali_re); + + return len; +} + +static ssize_t fade_step_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct aw882xx *aw882xx = dev_get_drvdata(dev); + unsigned int databuf[2] = {0}; + + /*step 0 - 12*/ + if (kstrtouint(buf, 10, &databuf[0]) == 0) { + if (databuf[0] > (aw882xx->aw_pa->volume_desc.mute_volume)) { + aw_dev_info(aw882xx->dev, "step overflow %d Db", databuf[0]); + return count; + } + aw882xx_dev_set_fade_vol_step(aw882xx->aw_pa, databuf[0]); + } + aw_dev_info(aw882xx->dev, "set step %d Done", databuf[0]); + + return count; +} + +static ssize_t fade_step_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + ssize_t len = 0; + struct aw882xx *aw882xx = dev_get_drvdata(dev); + + len += snprintf(buf + len, PAGE_SIZE - len, + "step: %d\n", aw882xx_dev_get_fade_vol_step(aw882xx->aw_pa)); + + return len; +} + +static ssize_t dbg_prof_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct aw882xx *aw882xx = dev_get_drvdata(dev); + + unsigned int databuf[2] = {0}; + + if (kstrtouint(buf, 10, &databuf[0]) == 0) { + if (databuf[0]) + aw882xx->dbg_en_prof = true; + else + aw882xx->dbg_en_prof = false; + } + aw_dev_info(aw882xx->dev, "en_prof %d Done", databuf[0]); + + return count; +} + +static ssize_t dbg_prof_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct aw882xx *aw882xx = dev_get_drvdata(dev); + ssize_t len = 0; + + len += snprintf(buf + len, PAGE_SIZE - len, + " %d\n", aw882xx->dbg_en_prof); + + return len; +} + +static ssize_t phase_sync_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + int ret = -1; + struct aw882xx *aw882xx = dev_get_drvdata(dev); + unsigned int flag = 0; + + ret = kstrtouint(buf, 10, &flag); + if (ret < 0) + return ret; + + flag = ((flag == false) ? false : true); + + aw_dev_info(aw882xx->dev, "set phase sync flag : [%d]", flag); + + aw882xx->phase_sync = flag; + + return count; +} + +static ssize_t phase_sync_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct aw882xx *aw882xx = dev_get_drvdata(dev); + ssize_t len = 0; + + len += snprintf(buf + len, PAGE_SIZE - len, + "sync flag : %d\n", aw882xx->phase_sync); + + return len; +} + +static ssize_t print_dbg_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + int ret; + struct aw882xx *aw882xx = dev_get_drvdata(dev); + + ret = kstrtouint(buf, 0, &g_print_dbg); + if (ret < 0) + return ret; + + g_print_dbg = ((g_print_dbg == false) ? false : true); + + aw_dev_info(aw882xx->dev, "set g_print_dbg : [%d]", g_print_dbg); + + return count; +} + +static ssize_t print_dbg_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + ssize_t len = 0; + + len += snprintf(buf + len, PAGE_SIZE - len, + "g_print_dbg : %d\n", g_print_dbg); + + return len; +} + +static ssize_t algo_ver_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int ret; + ssize_t len = 0; + char algo_ver_buf[ALGO_VERSION_MAX] = { 0 }; + struct aw882xx *aw882xx = dev_get_drvdata(dev); + + ret = aw882xx_get_algo_version(aw882xx->aw_pa, algo_ver_buf); + if (ret < 0) { + len += snprintf(buf + len, PAGE_SIZE - len, + "read algo version failed!\n"); + return len; + } + len += snprintf(buf + len, PAGE_SIZE - len, "%s\n", algo_ver_buf); + + return len; +} + +static DEVICE_ATTR_RW(reg); +static DEVICE_ATTR_RW(rw); +static DEVICE_ATTR_RW(awrw); +static DEVICE_ATTR_RO(drv_ver); +static DEVICE_ATTR_RO(dsp_re); +static DEVICE_ATTR_RW(fade_step); +static DEVICE_ATTR_RW(dbg_prof); +static DEVICE_ATTR_RW(phase_sync); +static DEVICE_ATTR_RW(print_dbg); +static DEVICE_ATTR_RO(algo_ver); + + +static struct attribute *aw882xx_attributes[] = { + &dev_attr_reg.attr, + &dev_attr_rw.attr, + &dev_attr_awrw.attr, + &dev_attr_drv_ver.attr, + &dev_attr_fade_step.attr, + &dev_attr_dbg_prof.attr, + &dev_attr_dsp_re.attr, + &dev_attr_phase_sync.attr, + &dev_attr_print_dbg.attr, + &dev_attr_algo_ver.attr, + NULL +}; + +static struct attribute_group aw882xx_attribute_group = { + .attrs = aw882xx_attributes, +}; + +static int aw882xx_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) +{ + int ret; + struct aw882xx *aw882xx = NULL; + struct device_node *np = i2c->dev.of_node; + + aw_pr_info("enter addr=0x%x", i2c->addr); + + if (!i2c_check_functionality(i2c->adapter, I2C_FUNC_I2C)) { + aw_dev_err(&i2c->dev, "check_functionality failed"); + return -EIO; + } + + /*dev free all auto free*/ + aw882xx = aw882xx_malloc_init(i2c); + if (aw882xx == NULL) { + aw_dev_err(&i2c->dev, "malloc aw882xx failed"); + return -ENOMEM; + } + + i2c_set_clientdata(i2c, aw882xx); + + ret = aw882xx_parse_dt(&i2c->dev, aw882xx, np); + if (ret) { + aw_dev_err(&i2c->dev, "failed to parse device tree node"); + return ret; + } + + /*get gpio resource*/ + ret = aw882xx_gpio_request(aw882xx); + if (ret) + return ret; + + /* hardware reset */ + aw882xx_hw_reset(aw882xx); + + /* aw882xx chip id */ + ret = aw882xx_read_chipid(aw882xx); + if (ret < 0) { + aw_dev_err(&i2c->dev, "aw882xx_read_chipid failed ret=%d", ret); + return ret; + } + + /*aw pa init*/ + ret = aw882xx_init(aw882xx); + if (ret) + return ret; + + /*aw882xx irq*/ + aw882xx_interrupt_init(aw882xx); + + /*codec register*/ + ret = aw_componet_codec_register(aw882xx); + if (ret) { + aw_dev_err(&i2c->dev, "codec register failde"); + return ret; + } + + /*create attr*/ + ret = sysfs_create_group(&i2c->dev.kobj, &aw882xx_attribute_group); + if (ret < 0) { + aw_dev_err(aw882xx->dev, "error creating sysfs attr files"); + goto err_sysfs; + } + + /*set aw882xx to dev private*/ + dev_set_drvdata(&i2c->dev, aw882xx); + + /*i2c packet init*/ + aw882xx->i2c_packet.status = AWRW_I2C_ST_NONE; + aw882xx->i2c_packet.reg_num = 0; + aw882xx->i2c_packet.reg_addr = 0xff; + aw882xx->i2c_packet.reg_data = NULL; + + /*add device to total list*/ + mutex_lock(&g_aw882xx_lock); + g_aw882xx_dev_cnt++; + mutex_unlock(&g_aw882xx_lock); + aw_dev_info(&i2c->dev, "dev_cnt %d", g_aw882xx_dev_cnt); + return ret; +err_sysfs: + aw_componet_codec_ops.unregister_codec(&i2c->dev); + + return ret; +} + +#ifdef AW_KERNEL_VER_OVER_6_1_0 +static void aw882xx_i2c_remove(struct i2c_client *i2c) +#else +static int aw882xx_i2c_remove(struct i2c_client *i2c) +#endif +{ + struct aw882xx *aw882xx = i2c_get_clientdata(i2c); + + aw_dev_info(aw882xx->dev, "enter"); + + /*rm irq*/ + if (gpio_to_irq(aw882xx->irq_gpio)) + devm_free_irq(&i2c->dev, + gpio_to_irq(aw882xx->irq_gpio), + aw882xx); + + /*rm attr node*/ + sysfs_remove_group(&i2c->dev.kobj, &aw882xx_attribute_group); + + /*free device resource */ + aw882xx_device_remove(aw882xx->aw_pa); + + /*unregister codec*/ + aw882xx->codec_ops->unregister_codec(&i2c->dev); + + /*remove device to total list*/ + mutex_lock(&g_aw882xx_lock); + g_aw882xx_dev_cnt--; + if (g_aw882xx_dev_cnt == 0) { + if (g_awinic_cfg) { + vfree(g_awinic_cfg); + g_awinic_cfg = NULL; + } + } + mutex_unlock(&g_aw882xx_lock); + +#ifdef AW_KERNEL_VER_OVER_6_1_0 +#else + return 0; +#endif +} + +static void aw882xx_i2c_shutdown(struct i2c_client *i2c) +{ + struct aw882xx *aw882xx = i2c_get_clientdata(i2c); + + aw_dev_info(aw882xx->dev, "enter"); + mutex_lock(&aw882xx->lock); + aw882xx_device_stop(aw882xx->aw_pa); + mutex_unlock(&aw882xx->lock); +} + +static const struct i2c_device_id aw882xx_i2c_id[] = { + { AW882XX_I2C_NAME, 0 }, + { } +}; + +MODULE_DEVICE_TABLE(i2c, aw882xx_i2c_id); + +static const struct of_device_id aw882xx_dt_match[] = { + { .compatible = "awinic,aw882xx_smartpa" }, + { }, +}; + +static struct i2c_driver aw882xx_i2c_driver = { + .driver = { + .name = AW882XX_I2C_NAME, + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(aw882xx_dt_match), + }, + .probe = aw882xx_i2c_probe, + .remove = aw882xx_i2c_remove, + .shutdown = aw882xx_i2c_shutdown, + .id_table = aw882xx_i2c_id, +}; + + +static int __init aw882xx_i2c_init(void) +{ + int ret = -1; + + aw_pr_info("aw882xx driver version %s", AW882XX_DRIVER_VERSION); + + ret = i2c_add_driver(&aw882xx_i2c_driver); + if (ret) + aw_pr_err("fail to add aw882xx device into i2c"); + + return ret; +} +module_init(aw882xx_i2c_init); + + +static void __exit aw882xx_i2c_exit(void) +{ + i2c_del_driver(&aw882xx_i2c_driver); +} +module_exit(aw882xx_i2c_exit); + + +MODULE_DESCRIPTION("ASoC AW882XX Smart PA Driver"); +MODULE_LICENSE("GPL v2"); + + + diff --git a/sound/soc/codecs/aw882xx/aw882xx.h b/sound/soc/codecs/aw882xx/aw882xx.h new file mode 100644 index 000000000000..8316eb113748 --- /dev/null +++ b/sound/soc/codecs/aw882xx/aw882xx.h @@ -0,0 +1,223 @@ +/* SPDX-License-Identifier: GPL-2.0 + * aw882xx.h + * + * Copyright (c) 2020 AWINIC Technology CO., LTD + * + * Author: Nick Li + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#ifndef _AW882XX_H_ +#define _AW882XX_H_ +#include +#include +#include "aw882xx_device.h" + +/* + * i2c transaction on Linux limited to 64k + * (See Linux kernel documentation: Documentation/i2c/writing-clients) + */ +#define AW882XX_CHIP_ID_REG (0x00) +#define MAX_I2C_BUFFER_SIZE 65536 +#define AW882XX_I2C_READ_MSG_NUM 2 +#define AW882XX_DC_DELAY_TIME (1000) +#define AW882XX_LOAD_FW_DELAY_TIME (0) +#define AW_START_RETRIES (5) + +#define AW_PID_2055_VERSION_DIFF_REG (0x23) + +#define AW_I2C_RETRIES 5 /* 5 times */ +#define AW_I2C_RETRY_DELAY 5 /* 5 ms */ + +#define ACF_BIN_NAME "aw882xx_acf.bin" + +#define AW882XX_RATES SNDRV_PCM_RATE_8000_48000 +#define AW882XX_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \ + SNDRV_PCM_FMTBIT_S24_LE | \ + SNDRV_PCM_FMTBIT_S32_LE) +/*#define AW882XX_IRQ_START_FLAG*/ +enum { + AW882XX_STREAM_CLOSE = 0, + AW882XX_STREAM_OPEN, +}; + +enum aw882xx_chipid { + PID_1852_ID = 0x1852, + PID_2013_ID = 0x2013, + PID_2032_ID = 0x2032, + PID_2055_ID = 0x2055, + PID_2055A_ID = 0x2055A, + PID_2071_ID = 0x2071, + PID_2113_ID = 0x2113, + PID_2308_ID = 0x2308, +}; + +#define AW882XX_SOFT_RESET_REG (0x00) +#define AW882XX_SOFT_RESET_VALUE (0x55aa) + +enum aw882xx_int_type { + INT_TYPE_NONE = 0, + INT_TYPE_UVLO = 0x1, + INT_TYPE_BSTOC = 0x2, + INT_TYPE_OCDI = 0x4, + INT_TYPE_OTHI = 0x8, +}; + +#if KERNEL_VERSION(4, 19, 1) <= LINUX_VERSION_CODE +#define AW_KERNEL_VER_OVER_4_19_1 +#endif + + +#if KERNEL_VERSION(5, 4, 0) <= LINUX_VERSION_CODE +#define AW_KERNEL_VER_OVER_5_4_0 +MODULE_IMPORT_NS(VFS_internal_I_am_really_a_filesystem_and_am_NOT_a_driver); +#endif + +#if KERNEL_VERSION(5, 10, 0) <= LINUX_VERSION_CODE +#define AW_KERNEL_VER_OVER_5_10_0 +#endif +#if KERNEL_VERSION(6, 1, 0) <= LINUX_VERSION_CODE +#define AW_KERNEL_VER_OVER_6_1_0 +#endif + + +#ifdef AW_KERNEL_VER_OVER_4_19_1 +typedef struct snd_soc_component aw_snd_soc_codec_t; +typedef const struct snd_soc_component_driver aw_snd_soc_codec_driver_t; +#else +typedef struct snd_soc_codec aw_snd_soc_codec_t; +typedef const struct snd_soc_codec_driver aw_snd_soc_codec_driver_t; +#endif + +struct aw_componet_codec_ops { + aw_snd_soc_codec_t *(*kcontrol_codec)(struct snd_kcontrol *kcontrol); + void *(*codec_get_drvdata)(aw_snd_soc_codec_t *codec); + int (*add_codec_controls)(aw_snd_soc_codec_t *codec, + const struct snd_kcontrol_new *controls, unsigned int num_controls); + void (*unregister_codec)(struct device *dev); + int (*register_codec)(struct device *dev, + const aw_snd_soc_codec_driver_t *codec_drv, + struct snd_soc_dai_driver *dai_drv, + int num_dai); +}; + +enum { + AWRW_I2C_ST_NONE = 0, + AWRW_I2C_ST_READ, + AWRW_I2C_ST_WRITE, +}; + +#define AWRW_ADDR_BYTES (1) +#define AWRW_DATA_BYTES (2) +#define AWRW_HDR_LEN (24) + + +enum { + KCTL_TYPE_PROFILE = 0, + KCTL_TYPE_SWITCH, + KCTL_TYPE_MONITOR, + KCTL_TYPE_VOLUME, + KCTL_TYPE_MON_HAL, + AW_KCTL_NUM, + +}; + +enum { + AWRW_FLAG_WRITE = 0, + AWRW_FLAG_READ, +}; + +enum { + AW_BSTCFG_DISABLE = 0, + AW_BSTCFG_ENABLE, +}; + +enum { + AW_FRCSET_DISABLE = 0, + AW_FRCSET_ENABLE, +}; + +enum { + AW_BOP_DISABLE = 0, + AW_BOP_ENABLE, +}; + +enum { + AW_RENAME_DISABLE = 0, + AW_RENAME_ENABLE, +}; + +enum { + AWRW_HDR_WR_FLAG = 0, + AWRW_HDR_ADDR_BYTES, + AWRW_HDR_DATA_BYTES, + AWRW_HDR_REG_NUM, + AWRW_HDR_REG_ADDR, + AWRW_HDR_MAX, +}; + +struct aw882xx_i2c_packet { + char status; + unsigned int reg_num; + unsigned int reg_addr; + char *reg_data; +}; + +/******************************************** + * struct aw882xx + *******************************************/ +struct aw882xx { + int sysclk; + int rate; + int pstream; + int cstream; + + unsigned char phase_sync; /* phase sync */ + unsigned char dc_flag; + unsigned char dbg_en_prof; /* debug enable/disable profile function */ + unsigned char allow_pw; /* allow power */ + uint32_t rename_flag; + unsigned char sync_load; /* sync load fw */ + + int reset_gpio; + int irq_gpio; + unsigned char fw_status; + unsigned char fw_retry_cnt; + unsigned char rw_reg_addr; /* rw attr node store read addr */ + + aw_snd_soc_codec_t *codec; + struct aw_componet_codec_ops *codec_ops; + + struct i2c_client *i2c; + struct device *dev; + struct aw882xx_i2c_packet i2c_packet; + struct aw_device *aw_pa; + + struct workqueue_struct *work_queue; + struct delayed_work start_work; + struct delayed_work interrupt_work; + struct delayed_work dc_work; + struct delayed_work fw_work; + + struct mutex lock; +}; + +void aw882xx_kcontorl_set(struct aw882xx *aw882xx); +int aw882xx_get_version(char *buf, int size); +int aw882xx_get_dev_num(void); +int aw882xx_i2c_write(struct aw882xx *aw882xx, + unsigned char reg_addr, unsigned int reg_data); +int aw882xx_i2c_read(struct aw882xx *aw882xx, + unsigned char reg_addr, unsigned int *reg_data); +int aw882xx_i2c_write_bits(struct aw882xx *aw882xx, + unsigned char reg_addr, unsigned int mask, unsigned int reg_data); +int aw882xx_init(struct aw882xx *aw882xx); +int aw882xx_hw_reset(struct aw882xx *aw882xx); + + +#endif + diff --git a/sound/soc/codecs/aw882xx/aw882xx_bin_parse.c b/sound/soc/codecs/aw882xx/aw882xx_bin_parse.c new file mode 100644 index 000000000000..e423a340abb5 --- /dev/null +++ b/sound/soc/codecs/aw882xx/aw882xx_bin_parse.c @@ -0,0 +1,1421 @@ +// SPDX-License-Identifier: GPL-2.0 +/* aw882xx_bin_parse.c + * + * Copyright (c) 2020 AWINIC Technology CO., LTD + * + * Author: Nick Li + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "aw882xx_bin_parse.h" +#include "aw882xx_device.h" +#include "aw882xx_data_type.h" +#include "aw882xx_log.h" + + +#define AWINIC_CODE_VERSION "V0.0.7-V1.0.4" /* "code version"-"excel version" */ + +#define DEBUG_LOG_LEVEL +#ifdef DEBUG_LOG_LEVEL +#define DBG(fmt, arg...) \ + pr_debug("AWINIC_BIN %s,line= %d,"fmt, __func__, __LINE__, ##arg) +#define DBG_ERR(fmt, arg...) \ + pr_err("AWINIC_BIN_ERR %s,line= %d,"fmt, __func__, __LINE__, ##arg) +#else +#define DBG(fmt, arg...) do {} while (0) +#define DBG_ERR(fmt, arg...) do {} while (0) +#endif + + +static char *profile_name[AW_PROFILE_MAX] = { + "Music", "Voice", "Voip", "Ringtone", "Ringtone_hs", + "Lowpower", "Bypass", "Mmi", "Fm", "Notification", "Receiver" +}; + +static int aw_parse_bin_header_1_0_0(struct aw_bin *bin); + +/******************************************************** + * + * check sum data + * + ********************************************************/ +static int aw_check_sum(struct aw_bin *bin, int bin_num) +{ + unsigned int i = 0; + unsigned int sum_data = 0; + unsigned int check_sum = 0; + unsigned char *p_check_sum = NULL; + + DBG("enter\n"); + + p_check_sum = &(bin->info.data[(bin->header_info[bin_num].valid_data_addr - + bin->header_info[bin_num].header_len)]); + DBG("aw_bin_parse p_check_sum = %p\n", p_check_sum); + check_sum = GET_32_DATA(*(p_check_sum + 3), + *(p_check_sum + 2), + *(p_check_sum + 1), *(p_check_sum)); + + for (i = 4; i < bin->header_info[bin_num].bin_data_len + + bin->header_info[bin_num].header_len; i++) { + sum_data += *(p_check_sum + i); + } + DBG("aw_bin_parse bin_num=%d, check_sum = 0x%x, sum_data = 0x%x\n", + bin_num, check_sum, sum_data); + if (sum_data != check_sum) { + p_check_sum = NULL; + DBG_ERR("aw_bin_parse check sum or check bin data len error\n"); + DBG_ERR("aw_bin_parse bin_num=%d, check_sum = 0x%x, sum_data = 0x%x\n", bin_num, check_sum, sum_data); + return -EINVAL; + } + p_check_sum = NULL; + + return 0; +} + +static int aw_check_data_version(struct aw_bin *bin, int bin_num) +{ + int i = 0; + + DBG("enter\n"); + + for (i = DATA_VERSION_V1; i < DATA_VERSION_MAX; i++) { + if (bin->header_info[bin_num].bin_data_ver == i) + return 0; + + } + DBG_ERR("aw_bin_parse Unrecognized this bin data version\n"); + return -EINVAL; +} + +static int aw_check_register_num_v1(struct aw_bin *bin, int bin_num) +{ + unsigned int check_register_num = 0; + unsigned int parse_register_num = 0; + char *p_check_sum = NULL; + + DBG("enter\n"); + + p_check_sum = &(bin->info.data[(bin->header_info[bin_num].valid_data_addr)]); + DBG("aw_bin_parse p_check_sum = %p\n", p_check_sum); + parse_register_num = GET_32_DATA(*(p_check_sum + 3), + *(p_check_sum + 2), + *(p_check_sum + 1), *(p_check_sum)); + check_register_num = (bin->header_info[bin_num].bin_data_len - 4) / + (bin->header_info[bin_num].reg_byte_len + + bin->header_info[bin_num].data_byte_len); + DBG("aw_bin_parse bin_num=%d, parse_register_num = 0x%x, check_register_num = 0x%x\n", + bin_num, parse_register_num, check_register_num); + if (parse_register_num != check_register_num) { + p_check_sum = NULL; + DBG_ERR("aw_bin_parse register num is error\n"); + DBG_ERR("aw_bin_parse bin_num=%d, parse_register_num = 0x%x, check_register_num = 0x%x\n", bin_num, parse_register_num, check_register_num); + return -EINVAL; + } + bin->header_info[bin_num].reg_num = parse_register_num; + bin->header_info[bin_num].valid_data_len = + bin->header_info[bin_num].bin_data_len - 4; + p_check_sum = NULL; + bin->header_info[bin_num].valid_data_addr = + bin->header_info[bin_num].valid_data_addr + 4; + return 0; +} + +static int aw_check_dsp_reg_num_v1(struct aw_bin *bin, int bin_num) +{ + unsigned int check_dsp_reg_num = 0; + unsigned int parse_dsp_reg_num = 0; + char *p_check_sum = NULL; + + DBG("enter\n"); + + p_check_sum = &(bin->info.data[(bin->header_info[bin_num].valid_data_addr)]); + DBG("aw_bin_parse p_check_sum = %p\n", p_check_sum); + parse_dsp_reg_num = GET_32_DATA(*(p_check_sum + 7), + *(p_check_sum + 6), + *(p_check_sum + 5), *(p_check_sum + 4)); + bin->header_info[bin_num].reg_data_byte_len = + GET_32_DATA(*(p_check_sum + 11), *(p_check_sum + 10), + *(p_check_sum + 9), *(p_check_sum + 8)); + check_dsp_reg_num = + (bin->header_info[bin_num].bin_data_len - + 12) / bin->header_info[bin_num].reg_data_byte_len; + DBG("aw_bin_parse bin_num=%d, parse_dsp_reg_num = 0x%x, check_dsp_reg_num = 0x%x\n", + bin_num, parse_dsp_reg_num, check_dsp_reg_num); + if (parse_dsp_reg_num != check_dsp_reg_num) { + p_check_sum = NULL; + DBG_ERR("aw_bin_parse dsp reg num is error\n"); + DBG_ERR("aw_bin_parse bin_num=%d, parse_dsp_reg_num = 0x%x, check_dsp_reg_num = 0x%x\n", bin_num, parse_dsp_reg_num, check_dsp_reg_num); + return -EINVAL; + } + bin->header_info[bin_num].download_addr = + GET_32_DATA(*(p_check_sum + 3), *(p_check_sum + 2), + *(p_check_sum + 1), *(p_check_sum)); + bin->header_info[bin_num].reg_num = parse_dsp_reg_num; + bin->header_info[bin_num].valid_data_len = + bin->header_info[bin_num].bin_data_len - 12; + p_check_sum = NULL; + bin->header_info[bin_num].valid_data_addr = + bin->header_info[bin_num].valid_data_addr + 12; + return 0; +} + +static int aw_check_soc_app_num_v1(struct aw_bin *bin, int bin_num) +{ + unsigned int check_soc_app_num = 0; + unsigned int parse_soc_app_num = 0; + char *p_check_sum = NULL; + + DBG("enter\n"); + + p_check_sum = + &(bin->info.data[(bin->header_info[bin_num].valid_data_addr)]); + DBG("aw_bin_parse p_check_sum = %p\n", p_check_sum); + bin->header_info[bin_num].app_version = GET_32_DATA(*(p_check_sum + 3), + *(p_check_sum + 2), + *(p_check_sum + 1), + *(p_check_sum)); + parse_soc_app_num = GET_32_DATA(*(p_check_sum + 11), + *(p_check_sum + 10), + *(p_check_sum + 9), *(p_check_sum + 8)); + check_soc_app_num = bin->header_info[bin_num].bin_data_len - 12; + DBG + ("aw_bin_parse bin_num=%d, parse_soc_app_num = 0x%x, check_soc_app_num = 0x%x\n", + bin_num, parse_soc_app_num, check_soc_app_num); + if (parse_soc_app_num != check_soc_app_num) { + p_check_sum = NULL; + DBG_ERR("aw_bin_parse soc app num is error\n"); + DBG_ERR("aw_bin_parse bin_num=%d, parse_soc_app_num = 0x%x, check_soc_app_num = 0x%x\n", bin_num, parse_soc_app_num, check_soc_app_num); + return -EINVAL; + } + bin->header_info[bin_num].reg_num = parse_soc_app_num; + bin->header_info[bin_num].download_addr = + GET_32_DATA(*(p_check_sum + 7), *(p_check_sum + 6), + *(p_check_sum + 5), *(p_check_sum + 4)); + bin->header_info[bin_num].valid_data_len = + bin->header_info[bin_num].bin_data_len - 12; + p_check_sum = NULL; + bin->header_info[bin_num].valid_data_addr = + bin->header_info[bin_num].valid_data_addr + 12; + return 0; +} + +/************************ + *** + ***bin header 1_0_0 + *** + ************************/ +static void aw_get_single_bin_header_1_0_0(struct aw_bin *bin) +{ + int i = 0; + + DBG("enter\n"); + bin->header_info[bin->all_bin_parse_num].header_len = 60; + bin->header_info[bin->all_bin_parse_num].check_sum = + GET_32_DATA(*(bin->p_addr + 3), *(bin->p_addr + 2), + *(bin->p_addr + 1), *(bin->p_addr)); + bin->header_info[bin->all_bin_parse_num].header_ver = + GET_32_DATA(*(bin->p_addr + 7), *(bin->p_addr + 6), + *(bin->p_addr + 5), *(bin->p_addr + 4)); + bin->header_info[bin->all_bin_parse_num].bin_data_type = + GET_32_DATA(*(bin->p_addr + 11), *(bin->p_addr + 10), + *(bin->p_addr + 9), *(bin->p_addr + 8)); + bin->header_info[bin->all_bin_parse_num].bin_data_ver = + GET_32_DATA(*(bin->p_addr + 15), *(bin->p_addr + 14), + *(bin->p_addr + 13), *(bin->p_addr + 12)); + bin->header_info[bin->all_bin_parse_num].bin_data_len = + GET_32_DATA(*(bin->p_addr + 19), *(bin->p_addr + 18), + *(bin->p_addr + 17), *(bin->p_addr + 16)); + bin->header_info[bin->all_bin_parse_num].ui_ver = + GET_32_DATA(*(bin->p_addr + 23), *(bin->p_addr + 22), + *(bin->p_addr + 21), *(bin->p_addr + 20)); + bin->header_info[bin->all_bin_parse_num].reg_byte_len = + GET_32_DATA(*(bin->p_addr + 35), *(bin->p_addr + 34), + *(bin->p_addr + 33), *(bin->p_addr + 32)); + bin->header_info[bin->all_bin_parse_num].data_byte_len = + GET_32_DATA(*(bin->p_addr + 39), *(bin->p_addr + 38), + *(bin->p_addr + 37), *(bin->p_addr + 36)); + bin->header_info[bin->all_bin_parse_num].device_addr = + GET_32_DATA(*(bin->p_addr + 43), *(bin->p_addr + 42), + *(bin->p_addr + 41), *(bin->p_addr + 40)); + for (i = 0; i < 8; i++) { + bin->header_info[bin->all_bin_parse_num].chip_type[i] = + *(bin->p_addr + 24 + i); + } + bin->header_info[bin->all_bin_parse_num].reg_num = 0x00000000; + bin->header_info[bin->all_bin_parse_num].reg_data_byte_len = 0x00000000; + bin->header_info[bin->all_bin_parse_num].download_addr = 0x00000000; + bin->header_info[bin->all_bin_parse_num].app_version = 0x00000000; + bin->header_info[bin->all_bin_parse_num].valid_data_len = 0x00000000; + bin->all_bin_parse_num += 1; +} + +static int aw_parse_each_of_multi_bins_1_0_0(unsigned int bin_num, int bin_serial_num, + struct aw_bin *bin) +{ + int ret = 0; + unsigned int bin_start_addr = 0; + unsigned int valid_data_len = 0; + + DBG("aw_bin_parse enter multi bin branch -- %s\n", __func__); + if (!bin_serial_num) { + bin_start_addr = GET_32_DATA(*(bin->p_addr + 67), + *(bin->p_addr + 66), + *(bin->p_addr + 65), + *(bin->p_addr + 64)); + bin->p_addr += (60 + bin_start_addr); + bin->header_info[bin->all_bin_parse_num].valid_data_addr = + bin->header_info[bin->all_bin_parse_num - + 1].valid_data_addr + 4 + 8 * bin_num + 60; + } else { + valid_data_len = + bin->header_info[bin->all_bin_parse_num - 1].bin_data_len; + bin->p_addr += (60 + valid_data_len); + bin->header_info[bin->all_bin_parse_num].valid_data_addr = + bin->header_info[bin->all_bin_parse_num - 1].valid_data_addr + + bin->header_info[bin->all_bin_parse_num - 1].bin_data_len + 60; + } + + ret = aw_parse_bin_header_1_0_0(bin); + return ret; +} + +/* Get the number of bins in multi bins, and set a for loop, loop processing each bin data */ +static int aw_get_multi_bin_header_1_0_0(struct aw_bin *bin) +{ + int i = 0; + int ret = 0; + unsigned int bin_num = 0; + + DBG("aw_bin_parse enter multi bin branch -- %s\n", __func__); + bin_num = GET_32_DATA(*(bin->p_addr + 63), + *(bin->p_addr + 62), + *(bin->p_addr + 61), *(bin->p_addr + 60)); + if (bin->multi_bin_parse_num == 1) + bin->header_info[bin->all_bin_parse_num].valid_data_addr = 60; + + aw_get_single_bin_header_1_0_0(bin); + + for (i = 0; i < bin_num; i++) { + DBG("aw_bin_parse enter multi bin for is %d\n", i); + ret = aw_parse_each_of_multi_bins_1_0_0(bin_num, i, bin); + if (ret < 0) + return ret; + + } + return 0; +} + +/******************************************************** + * + * If the bin framework header version is 1.0.0, + determine the data type of bin, and then perform different processing + according to the data type + If it is a single bin data type, write the data directly into the structure array + If it is a multi-bin data type, first obtain the number of bins, + and then recursively call the bin frame header processing function + according to the bin number to process the frame header information of each bin separately + * + ********************************************************/ +static int aw_parse_bin_header_1_0_0(struct aw_bin *bin) +{ + int ret = 0; + unsigned int bin_data_type; + + DBG("enter\n"); + bin_data_type = GET_32_DATA(*(bin->p_addr + 11), + *(bin->p_addr + 10), + *(bin->p_addr + 9), *(bin->p_addr + 8)); + DBG("aw_bin_parse bin_data_type 0x%x\n", bin_data_type); + switch (bin_data_type) { + case DATA_TYPE_REGISTER: + case DATA_TYPE_DSP_REG: + case DATA_TYPE_SOC_APP: + /* Divided into two processing methods, + * one is single bin processing, + * and the other is single bin processing in multi bin + */ + DBG("aw_bin_parse enter single bin branch\n"); + bin->single_bin_parse_num += 1; + DBG("%s bin->single_bin_parse_num is %d\n", __func__, + bin->single_bin_parse_num); + if (!bin->multi_bin_parse_num) + bin->header_info[bin->all_bin_parse_num].valid_data_addr = 60; + + aw_get_single_bin_header_1_0_0(bin); + break; + case DATA_TYPE_MULTI_BINS: + /* Get the number of times to enter multi bins */ + DBG("aw_bin_parse enter multi bin branch\n"); + bin->multi_bin_parse_num += 1; + DBG("%s bin->multi_bin_parse_num is %d\n", __func__, + bin->multi_bin_parse_num); + ret = aw_get_multi_bin_header_1_0_0(bin); + if (ret < 0) + return ret; + + break; + default: + DBG_ERR("aw_bin_parse Unrecognized this bin data type\n"); + return -EINVAL; + } + return 0; +} + +/* get the bin's header version */ +static int aw_check_bin_header_version(struct aw_bin *bin) +{ + int ret = 0; + unsigned int header_version = 0; + + header_version = GET_32_DATA(*(bin->p_addr + 7), + *(bin->p_addr + 6), + *(bin->p_addr + 5), *(bin->p_addr + 4)); + + DBG("aw_bin_parse header_version 0x%x\n", header_version); + + /* Write data to the corresponding structure array + * according to different formats of the bin frame header version + */ + switch (header_version) { + case HEADER_VERSION_1_0_0: + ret = aw_parse_bin_header_1_0_0(bin); + return ret; + default: + DBG_ERR("aw_bin_parse Unrecognized this bin header version\n"); + return -EINVAL; + } +} + +static int aw_parsing_bin_file(struct aw_bin *bin) +{ + int i = 0; + int ret = 0; + + DBG("aw_bin_parse code version:%s\n", AWINIC_CODE_VERSION); + if (!bin) { + DBG_ERR("aw_bin_parse bin is NULL\n"); + return -EINVAL; + } + bin->p_addr = bin->info.data; + bin->all_bin_parse_num = 0; + bin->multi_bin_parse_num = 0; + bin->single_bin_parse_num = 0; + + /* filling bins header info */ + ret = aw_check_bin_header_version(bin); + if (ret < 0) { + DBG_ERR("aw_bin_parse check bin header version error\n"); + return ret; + } + bin->p_addr = NULL; + + /* check bin header info */ + for (i = 0; i < bin->all_bin_parse_num; i++) { + /* check sum */ + ret = aw_check_sum(bin, i); + if (ret < 0) { + DBG_ERR("aw_bin_parse check sum data error\n"); + return ret; + } + /* check bin data version */ + ret = aw_check_data_version(bin, i); + if (ret < 0) { + DBG_ERR("aw_bin_parse check data version error\n"); + return ret; + } + /* check valid data */ + if (bin->header_info[i].bin_data_ver == DATA_VERSION_V1) { + /* check register num */ + if (bin->header_info[i].bin_data_type == + DATA_TYPE_REGISTER) { + ret = aw_check_register_num_v1(bin, i); + if (ret < 0) { + DBG_ERR("aw_bin_parse check register num error\n"); + return ret; + } + /* check dsp reg num */ + } else if (bin->header_info[i].bin_data_type == + DATA_TYPE_DSP_REG) { + ret = aw_check_dsp_reg_num_v1(bin, i); + if (ret < 0) { + DBG_ERR("aw_bin_parse check dsp reg num error\n"); + return ret; + } + /* check soc app num */ + } else if (bin->header_info[i].bin_data_type == + DATA_TYPE_SOC_APP) { + ret = aw_check_soc_app_num_v1(bin, i); + if (ret < 0) { + DBG_ERR + ("aw_bin_parse check soc app num error\n"); + return ret; + } + } else { + bin->header_info[i].valid_data_len = + bin->header_info[i].bin_data_len; + } + } + } + DBG("aw_bin_parse parsing success\n"); + + return 0; +} + +/*********************************awinic audio acf*************************************/ +static uint8_t aw_dev_parse_crc8_check(unsigned char *data, uint32_t data_size) +{ + uint8_t crc_value = 0x00; + uint8_t pdatabuf = 0; + int i; + + while (data_size--) { + pdatabuf = *data++; + for (i = 0; i < 8; i++) { + /*if the lowest bit is 1*/ + if ((crc_value ^ (pdatabuf)) & 0x01) { + /*Xor multinomial*/ + crc_value ^= 0x18; + crc_value >>= 1; + crc_value |= 0x80; + } else { + crc_value >>= 1; + } + pdatabuf >>= 1; + } + } + return crc_value; +} + +static int aw_dev_parse_check_acf_by_hdr(struct aw_container *aw_cfg) +{ + struct aw_cfg_hdr *cfg_hdr = NULL; + struct aw_cfg_dde *cfg_dde = NULL; + unsigned int end_data_offset = 0; + unsigned int act_data = 0; + unsigned int hdr_ddt_len = 0; + uint8_t act_crc8 = 0; + int i; + + cfg_hdr = (struct aw_cfg_hdr *)aw_cfg->data; + + /*check file type id is awinic acf file*/ + if (cfg_hdr->a_id != ACF_FILE_ID) { + aw_pr_err("not acf type file"); + return -EINVAL; + } + + hdr_ddt_len = cfg_hdr->a_hdr_offset + cfg_hdr->a_ddt_size; + if (hdr_ddt_len > aw_cfg->len) { + aw_pr_err("hdrlen with ddt_len [%d] overflow file size[%d]", + cfg_hdr->a_hdr_offset, aw_cfg->len); + return -EINVAL; + } + + /*check data size*/ + cfg_dde = (struct aw_cfg_dde *)((char *)aw_cfg->data + cfg_hdr->a_hdr_offset); + act_data += hdr_ddt_len; + for (i = 0; i < cfg_hdr->a_ddt_num; i++) + act_data += cfg_dde[i].data_size; + + if (act_data != aw_cfg->len) { + aw_pr_err("act_data[%d] not equal to file size[%d]!", + act_data, aw_cfg->len); + return -EINVAL; + } + + for (i = 0; i < cfg_hdr->a_ddt_num; i++) { + /* data check */ + end_data_offset = cfg_dde[i].data_offset + cfg_dde[i].data_size; + if (end_data_offset > aw_cfg->len) { + aw_pr_err("a_ddt_num[%d] end_data_offset[%d] overflow file size[%d]", + i, end_data_offset, aw_cfg->len); + return -EINVAL; + } + + /* crc check */ + act_crc8 = aw_dev_parse_crc8_check(aw_cfg->data + cfg_dde[i].data_offset, cfg_dde[i].data_size); + if (act_crc8 != cfg_dde[i].data_crc) { + aw_pr_err("a_ddt_num[%d] crc8 check failed, act_crc8:0x%x != data_crc 0x%x", + i, (uint32_t)act_crc8, cfg_dde[i].data_crc); + return -EINVAL; + } + } + + aw_pr_info("project name [%s]", cfg_hdr->a_project); + aw_pr_info("custom name [%s]", cfg_hdr->a_custom); + aw_pr_info("version name [%d.%d.%d.%d]", cfg_hdr->a_version[3], cfg_hdr->a_version[2], + cfg_hdr->a_version[1], cfg_hdr->a_version[0]); + aw_pr_info("author id %d", cfg_hdr->a_author_id); + + return 0; +} + +static int aw_dev_parse_check_acf_by_hdr_v_1_0_0_0(struct aw_container *aw_cfg) +{ + struct aw_cfg_hdr *cfg_hdr = NULL; + struct aw_cfg_dde_v_1_0_0_0 *cfg_dde = NULL; + unsigned int end_data_offset = 0; + unsigned int act_data = 0; + unsigned int hdr_ddt_len = 0; + uint8_t act_crc8 = 0; + int i; + + cfg_hdr = (struct aw_cfg_hdr *)aw_cfg->data; + + /*check file type id is awinic acf file*/ + if (cfg_hdr->a_id != ACF_FILE_ID) { + aw_pr_err("not acf type file"); + return -EINVAL; + } + + hdr_ddt_len = cfg_hdr->a_hdr_offset + cfg_hdr->a_ddt_size; + if (hdr_ddt_len > aw_cfg->len) { + aw_pr_err("hdrlen with ddt_len [%d] overflow file size[%d]", + cfg_hdr->a_hdr_offset, aw_cfg->len); + return -EINVAL; + } + + /*check data size*/ + cfg_dde = (struct aw_cfg_dde_v_1_0_0_0 *)((char *)aw_cfg->data + cfg_hdr->a_hdr_offset); + act_data += hdr_ddt_len; + for (i = 0; i < cfg_hdr->a_ddt_num; i++) + act_data += cfg_dde[i].data_size; + + if (act_data != aw_cfg->len) { + aw_pr_err("act_data[%d] not equal to file size[%d]!", + act_data, aw_cfg->len); + return -EINVAL; + } + + for (i = 0; i < cfg_hdr->a_ddt_num; i++) { + /* data check */ + end_data_offset = cfg_dde[i].data_offset + cfg_dde[i].data_size; + if (end_data_offset > aw_cfg->len) { + aw_pr_err("a_ddt_num[%d] end_data_offset[%d] overflow file size[%d]", + i, end_data_offset, aw_cfg->len); + return -EINVAL; + } + + /* crc check */ + act_crc8 = aw_dev_parse_crc8_check(aw_cfg->data + cfg_dde[i].data_offset, cfg_dde[i].data_size); + if (act_crc8 != cfg_dde[i].data_crc) { + aw_pr_err("a_ddt_num[%d] crc8 check failed, act_crc8:0x%x != data_crc 0x%x", + i, (uint32_t)act_crc8, cfg_dde[i].data_crc); + return -EINVAL; + } + } + + aw_pr_info("project name [%s]", cfg_hdr->a_project); + aw_pr_info("custom name [%s]", cfg_hdr->a_custom); + aw_pr_info("version name [%d.%d.%d.%d]", cfg_hdr->a_version[3], cfg_hdr->a_version[2], + cfg_hdr->a_version[1], cfg_hdr->a_version[0]); + aw_pr_info("author id %d", cfg_hdr->a_author_id); + + return 0; +} + + +int aw882xx_dev_parse_check_acf(struct aw_container *aw_cfg) +{ + struct aw_cfg_hdr *cfg_hdr = NULL; + + if (aw_cfg == NULL) { + aw_pr_err("aw_prof is NULL"); + return -ENOMEM; + } + + if (aw_cfg->len < sizeof(struct aw_cfg_hdr)) { + aw_pr_err("cfg hdr size[%d] overflow file size[%d]", + aw_cfg->len, (int)sizeof(struct aw_cfg_hdr)); + return -EINVAL; + } + + cfg_hdr = (struct aw_cfg_hdr *)aw_cfg->data; + switch (cfg_hdr->a_hdr_version) { + case AW_CFG_HDR_VER_0_0_0_1: + return aw_dev_parse_check_acf_by_hdr(aw_cfg); + case AW_CFG_HDR_VER_1_0_0_0: + return aw_dev_parse_check_acf_by_hdr_v_1_0_0_0(aw_cfg); + default: + aw_pr_err("unsupported hdr_version [0x%x]", cfg_hdr->a_hdr_version); + return -EINVAL; + } + + return 0; +} + +static int aw_dev_parse_raw_reg(struct aw_device *aw_dev, + uint8_t *data, uint32_t data_len, struct aw_prof_desc *prof_desc) +{ + aw_dev_info(aw_dev->dev, "data_size:%d enter", data_len); + + if (data_len % 4) { + aw_dev_err(aw_dev->dev, "bin data len get error!"); + return -EINVAL; + } + + prof_desc->sec_desc[AW_PROFILE_DATA_TYPE_REG].data = data; + prof_desc->sec_desc[AW_PROFILE_DATA_TYPE_REG].len = data_len; + + prof_desc->prof_st = AW_PROFILE_OK; + + return 0; +} + +static int aw_dev_parse_raw_dsp(struct aw_device *aw_dev, + uint8_t *data, uint32_t data_len, struct aw_prof_desc *prof_desc) +{ + aw_dev_info(aw_dev->dev, "data_size:%d enter", data_len); + + prof_desc->sec_desc[AW_PROFILE_DATA_TYPE_DSP].data = data; + prof_desc->sec_desc[AW_PROFILE_DATA_TYPE_DSP].len = data_len; + + return 0; +} + +static int aw_dev_parse_reg_bin_with_hdr(struct aw_device *aw_dev, + uint8_t *data, uint32_t data_len, struct aw_prof_desc *prof_desc) +{ + struct aw_bin *aw_bin = NULL; + int ret; + + aw_dev_info(aw_dev->dev, "data_size:%d enter", data_len); + + aw_bin = kzalloc(data_len + sizeof(struct aw_bin), GFP_KERNEL); + if (aw_bin == NULL) + return -ENOMEM; + + + aw_bin->info.len = data_len; + memcpy(aw_bin->info.data, data, data_len); + + ret = aw_parsing_bin_file(aw_bin); + if (ret < 0) { + aw_dev_err(aw_dev->dev, "parse bin failed"); + goto parse_bin_failed; + } + + if ((aw_bin->all_bin_parse_num != 1) || + (aw_bin->header_info[0].bin_data_type != DATA_TYPE_REGISTER)) { + aw_dev_err(aw_dev->dev, "bin num or type error"); + goto parse_bin_failed; + } + + if (aw_bin->header_info[0].valid_data_len % 4) { + aw_dev_err(aw_dev->dev, "bin data len get error!"); + return -EINVAL; + } + + prof_desc->sec_desc[AW_PROFILE_DATA_TYPE_REG].data = + data + aw_bin->header_info[0].valid_data_addr; + prof_desc->sec_desc[AW_PROFILE_DATA_TYPE_REG].len = + aw_bin->header_info[0].valid_data_len; + prof_desc->prof_st = AW_PROFILE_OK; + + kfree(aw_bin); + aw_bin = NULL; + + return 0; + +parse_bin_failed: + kfree(aw_bin); + aw_bin = NULL; + return ret; +} + +static int aw_dev_parse_data_by_sec_type(struct aw_device *aw_dev, struct aw_cfg_hdr *cfg_hdr, + struct aw_cfg_dde *prof_hdr, struct aw_prof_desc *scene_prof_desc) +{ + switch (prof_hdr->data_type) { + case ACF_SEC_TYPE_REG: + return aw_dev_parse_raw_reg(aw_dev, + (uint8_t *)cfg_hdr + prof_hdr->data_offset, + prof_hdr->data_size, + scene_prof_desc); + case ACF_SEC_TYPE_HDR_REG: + return aw_dev_parse_reg_bin_with_hdr(aw_dev, + (uint8_t *)cfg_hdr + prof_hdr->data_offset, + prof_hdr->data_size, + scene_prof_desc); + case ACF_SEC_TYPE_MONITOR: + return aw882xx_monitor_parse_fw(&aw_dev->monitor_desc, + (uint8_t *)cfg_hdr + prof_hdr->data_offset, + prof_hdr->data_size); + } + + return 0; +} + +static int aw_dev_parse_dev_type(struct aw_device *aw_dev, + struct aw_cfg_hdr *prof_hdr, struct aw_all_prof_info *all_prof_info) +{ + int i = 0; + int ret; + int sec_num = 0; + struct aw_cfg_dde *cfg_dde = + (struct aw_cfg_dde *)((char *)prof_hdr + prof_hdr->a_hdr_offset); + + aw_dev_info(aw_dev->dev, "enter"); + + for (i = 0; i < prof_hdr->a_ddt_num; i++) { + if ((aw_dev->i2c->adapter->nr == cfg_dde[i].dev_bus) && + (aw_dev->i2c->addr == cfg_dde[i].dev_addr) && + (cfg_dde[i].type == AW_DEV_TYPE_ID)) { + if (cfg_dde[i].data_type != ACF_SEC_TYPE_MONITOR) { + ret = aw_dev_parse_data_by_sec_type(aw_dev, prof_hdr, &cfg_dde[i], + &all_prof_info->prof_desc[cfg_dde[i].dev_profile]); + if (ret < 0) { + aw_dev_err(aw_dev->dev, "parse dev driver bin data failed"); + return ret; + } + sec_num++; + } else { + ret = aw_dev_parse_data_by_sec_type(aw_dev, prof_hdr, &cfg_dde[i], NULL); + if (ret < 0) { + aw_dev_err(aw_dev->dev, "parse monitor bin data failed"); + return ret; + } + sec_num++; + } + } + } + + if (sec_num == 0) { + aw_dev_info(aw_dev->dev, "get dev type num is %d, please use default", sec_num); + return AW_DEV_TYPE_NONE; + } + + return AW_DEV_TYPE_OK; +} + +static int aw_dev_parse_dev_default_type(struct aw_device *aw_dev, + struct aw_cfg_hdr *prof_hdr, struct aw_all_prof_info *all_prof_info) +{ + int i = 0; + int ret; + int sec_num = 0; + struct aw_cfg_dde *cfg_dde = + (struct aw_cfg_dde *)((char *)prof_hdr + prof_hdr->a_hdr_offset); + + aw_dev_info(aw_dev->dev, "enter"); + + for (i = 0; i < prof_hdr->a_ddt_num; i++) { + if ((aw_dev->channel == cfg_dde[i].dev_index) && + (cfg_dde[i].type == AW_DEV_DEFAULT_TYPE_ID)) { + if (cfg_dde[i].data_type != ACF_SEC_TYPE_MONITOR) { + ret = aw_dev_parse_data_by_sec_type(aw_dev, prof_hdr, &cfg_dde[i], + &all_prof_info->prof_desc[cfg_dde[i].dev_profile]); + if (ret < 0) { + aw_dev_err(aw_dev->dev, "parse dev driver bin data failed"); + return ret; + } + } else { + ret = aw_dev_parse_data_by_sec_type(aw_dev, prof_hdr, &cfg_dde[i], NULL); + if (ret < 0) { + aw_dev_err(aw_dev->dev, "parse monitor bin data failed"); + return ret; + } + } + sec_num++; + } + } + + if (sec_num == 0) { + aw_dev_err(aw_dev->dev, "get dev default type failed, get num[%d]", sec_num); + return -EINVAL; + } + + return 0; +} + +static int aw_dev_parse_skt_type(struct aw_device *aw_dev, + struct aw_cfg_hdr *prof_hdr, struct aw_all_prof_info *all_prof_info) +{ + int i = 0; + int ret; + int sec_num = 0; + struct aw_cfg_dde *cfg_dde = + (struct aw_cfg_dde *)((char *)prof_hdr + prof_hdr->a_hdr_offset); + + aw_dev_info(aw_dev->dev, "enter"); + + for (i = 0; i < prof_hdr->a_ddt_num; i++) { + if ((aw_dev->channel == cfg_dde[i].dev_index) && + (cfg_dde[i].type == AW_SKT_TYPE_ID)) { + if (cfg_dde[i].data_type == ACF_SEC_TYPE_DSP) { + ret = aw_dev_parse_raw_dsp(aw_dev, + (uint8_t *)prof_hdr + cfg_dde[i].data_offset, + cfg_dde[i].data_size, + &all_prof_info->prof_desc[cfg_dde[i].dev_profile]); + if (ret < 0) { + aw_dev_err(aw_dev->dev, "parse dsp bin data failed"); + return ret; + } + sec_num++; + } + } + } + + aw_dev_info(aw_dev->dev, "get dsp data prof cnt is %d ", sec_num); + return 0; +} + +static int aw_dev_parse_get_vaild_prof(struct aw_device *aw_dev, + struct aw_all_prof_info all_prof_info) +{ + int i; + int num = 0; + struct aw_prof_desc *prof_desc = all_prof_info.prof_desc; + struct aw_prof_info *prof_info = &aw_dev->prof_info; + + for (i = 0; i < AW_PROFILE_MAX; i++) { + if (prof_desc[i].prof_st == AW_PROFILE_OK) + aw_dev->prof_info.count++; + } + + aw_dev_info(aw_dev->dev, "get vaild profile:%d", aw_dev->prof_info.count); + + if (!aw_dev->prof_info.count) { + aw_dev_err(aw_dev->dev, "no profile data"); + return -EPERM; + } + + prof_info->prof_desc = kzalloc(prof_info->count * sizeof(struct aw_prof_desc), GFP_KERNEL); + if (prof_info->prof_desc == NULL) + return -ENOMEM; + + + for (i = 0; i < AW_PROFILE_MAX; i++) { + if (prof_desc[i].prof_st == AW_PROFILE_OK) { + if (num >= prof_info->count) { + aw_dev_err(aw_dev->dev, "get scene num[%d] overflow count[%d]", + num, prof_info->count); + return -ENOMEM; + } + prof_info->prof_desc[num] = prof_desc[i]; + prof_info->prof_desc[num].id = i; + num++; + } + } + + return 0; +} + +static int aw_dev_parse_acf_by_hdr(struct aw_device *aw_dev, + struct aw_cfg_hdr *prof_hdr) +{ + int ret; + struct aw_all_prof_info all_prof_info; + + memset(&all_prof_info, 0, sizeof(struct aw_all_prof_info)); + + ret = aw_dev_parse_dev_type(aw_dev, prof_hdr, &all_prof_info); + if (ret < 0) { + return ret; + } else if (ret == AW_DEV_TYPE_NONE) { + aw_dev_info(aw_dev->dev, "get dev type num is0, parse default dev type"); + ret = aw_dev_parse_dev_default_type(aw_dev, prof_hdr, &all_prof_info); + if (ret < 0) + return ret; + } + + ret = aw_dev_parse_skt_type(aw_dev, prof_hdr, &all_prof_info); + if (ret < 0) + return ret; + + ret = aw_dev_parse_get_vaild_prof(aw_dev, all_prof_info); + if (ret < 0) + return ret; + + aw_dev->prof_info.prof_name_list = profile_name; + + + return 0; +} + + +/******************************************bin format V1.0.0.0********************************************/ +static int aw_dev_parse_get_scene_count_v1_0_0_0(struct aw_device *aw_dev, + struct aw_container *aw_cfg, uint32_t *count, int *is_default) +{ + struct aw_cfg_hdr *cfg_hdr = (struct aw_cfg_hdr *)aw_cfg->data; + struct aw_cfg_dde_v_1_0_0_0 *cfg_dde = + (struct aw_cfg_dde_v_1_0_0_0 *)(aw_cfg->data + cfg_hdr->a_hdr_offset); + int i = 0; + + for (i = 0; i < cfg_hdr->a_ddt_num; ++i) { + if (((cfg_dde[i].data_type == ACF_SEC_TYPE_REG) || + (cfg_dde[i].data_type == ACF_SEC_TYPE_HDR_REG)) && + (cfg_dde[i].type == AW_DEV_TYPE_ID) && + ((aw_dev->i2c->adapter->nr == cfg_dde[i].dev_bus) && + (aw_dev->i2c->addr == cfg_dde[i].dev_addr)) && + (aw_dev->chip_id == cfg_dde[i].chip_id)) { + (*count)++; + (*is_default) = 0; + } + } + + if ((*count) == 0) { + for (i = 0; i < cfg_hdr->a_ddt_num; ++i) { + if (((cfg_dde[i].data_type == ACF_SEC_TYPE_REG) || + (cfg_dde[i].data_type == ACF_SEC_TYPE_HDR_REG)) && + (cfg_dde[i].type == AW_DEV_DEFAULT_TYPE_ID) && + (aw_dev->channel == cfg_dde[i].dev_index) && + (aw_dev->chip_id == cfg_dde[i].chip_id)) { + (*count)++; + (*is_default) = 1; + } + } + } + + if ((*count) == 0) { + aw_dev_err(aw_dev->dev, "can't find scene"); + return -EINVAL; + } + + aw_dev_info(aw_dev->dev, "scene count is %d", (*count)); + return 0; +} + + +static int aw_dev_parse_create_prof_name_list_v_1_0_0_0(struct aw_device *aw_dev) +{ + struct aw_prof_info *prof_info = &aw_dev->prof_info; + struct aw_prof_desc *prof_desc = prof_info->prof_desc; + int i; + + if (prof_desc == NULL) { + aw_dev_err(aw_dev->dev, "prof_desc is NULL"); + return -EINVAL; + } + + prof_info->prof_name_list = devm_kzalloc(aw_dev->dev, + prof_info->count * PROFILE_STR_MAX, + GFP_KERNEL); + if (prof_info->prof_name_list == NULL) { + aw_dev_err(aw_dev->dev, "prof_name_list devm_kzalloc failed"); + return -ENOMEM; + } + + for (i = 0; i < prof_info->count; i++) { + prof_desc[i].id = i; + prof_info->prof_name_list[i] = prof_desc[i].prf_str; + aw_dev_info(aw_dev->dev, "prof name is %s", prof_info->prof_name_list[i]); + } + + return 0; +} + +static int aw_dev_parse_drv_type_v_1_0_0_0(struct aw_device *aw_dev, + struct aw_cfg_hdr *prof_hdr, struct aw_cfg_dde_v_1_0_0_0 *cfg_dde, int *cur_scene_id) +{ + int ret = -1; + struct aw_prof_info *prof_info = &aw_dev->prof_info; + + switch (cfg_dde->data_type) { + case ACF_SEC_TYPE_REG: + ret = aw_dev_parse_raw_reg(aw_dev, + (uint8_t *)prof_hdr + cfg_dde->data_offset, + cfg_dde->data_size, &prof_info->prof_desc[*cur_scene_id]); + if (ret < 0) { + aw_dev_err(aw_dev->dev, "parse reg bin failed"); + return ret; + } + prof_info->prof_desc[*cur_scene_id].prf_str = cfg_dde->dev_profile_str; + prof_info->prof_desc[*cur_scene_id].id = cfg_dde->dev_profile; + (*cur_scene_id)++; + break; + case ACF_SEC_TYPE_HDR_REG: + ret = aw_dev_parse_reg_bin_with_hdr(aw_dev, + (uint8_t *)prof_hdr + cfg_dde->data_offset, + cfg_dde->data_size, &prof_info->prof_desc[*cur_scene_id]); + if (ret < 0) { + aw_dev_err(aw_dev->dev, "parse reg bin with hdr failed"); + return ret; + } + prof_info->prof_desc[*cur_scene_id].prf_str = cfg_dde->dev_profile_str; + prof_info->prof_desc[*cur_scene_id].id = cfg_dde->dev_profile; + (*cur_scene_id)++; + break; + case ACF_SEC_TYPE_MONITOR: + ret = aw882xx_monitor_parse_fw(&aw_dev->monitor_desc, + (uint8_t *)prof_hdr + cfg_dde->data_offset, + cfg_dde->data_size); + if (ret < 0) { + aw_dev_err(aw_dev->dev, "parse monitor bin failed"); + return ret; + } + break; + default: + aw_dev_err(aw_dev->dev, "unsupport bin type!"); + return -EINVAL; + } + + return ret; +} + +static int aw_dev_parse_dev_type_v_1_0_0_0(struct aw_device *aw_dev, + struct aw_cfg_hdr *prof_hdr) +{ + int i = 0; + int ret = -1; + int cur_scene_id = 0; + struct aw_cfg_dde_v_1_0_0_0 *cfg_dde = + (struct aw_cfg_dde_v_1_0_0_0 *)((char *)prof_hdr + prof_hdr->a_hdr_offset); + + aw_dev_info(aw_dev->dev, "enter"); + + for (i = 0; i < prof_hdr->a_ddt_num; i++) { + if ((cfg_dde[i].type == AW_DEV_TYPE_ID) && + (aw_dev->i2c->adapter->nr == cfg_dde[i].dev_bus) && + (aw_dev->i2c->addr == cfg_dde[i].dev_addr) && + (aw_dev->chip_id == cfg_dde[i].chip_id)) { + ret = aw_dev_parse_drv_type_v_1_0_0_0(aw_dev, + prof_hdr, &cfg_dde[i], &cur_scene_id); + if (ret < 0) + return ret; + } + } + + if (cur_scene_id == 0) { + aw_dev_info(aw_dev->dev, "get dev type num is %d", cur_scene_id); + return -EINVAL; + } + + return 0; +} + +static int aw_dev_parse_dev_default_type_v_1_0_0_0(struct aw_device *aw_dev, + struct aw_cfg_hdr *prof_hdr) +{ + int i = 0; + int ret; + int cur_scene_id = 0; + struct aw_cfg_dde_v_1_0_0_0 *cfg_dde = + (struct aw_cfg_dde_v_1_0_0_0 *)((char *)prof_hdr + prof_hdr->a_hdr_offset); + + aw_dev_info(aw_dev->dev, "enter"); + + for (i = 0; i < prof_hdr->a_ddt_num; i++) { + if ((cfg_dde[i].type == AW_DEV_DEFAULT_TYPE_ID) && + (aw_dev->channel == cfg_dde[i].dev_index) && + (aw_dev->chip_id == cfg_dde[i].chip_id)) { + ret = aw_dev_parse_drv_type_v_1_0_0_0(aw_dev, + prof_hdr, &cfg_dde[i], &cur_scene_id); + if (ret < 0) + return ret; + } + } + + if (cur_scene_id == 0) { + aw_dev_err(aw_dev->dev, "get dev default type failed, get num[%d]", cur_scene_id); + return -EINVAL; + } + + return 0; +} + +static int aw_dev_parse_get_scene_id_v_1_0_0_0(struct aw_device *aw_dev, char *scene_str, int *scene_id) +{ + struct aw_prof_info *prof_info = &aw_dev->prof_info; + int i; + + if (scene_str == NULL) { + aw_dev_err(aw_dev->dev, "scene_str is NULL"); + return -EINVAL; + } + + for (i = 0; i < prof_info->count; i++) { + if (prof_info->prof_desc[i].prf_str == NULL) { + aw_dev_err(aw_dev->dev, "porfile name is NULL"); + return -EINVAL; + } + + if (!strcmp(prof_info->prof_desc[i].prf_str, scene_str)) { + *scene_id = i; + return 0; + } + } + + aw_dev_err(aw_dev->dev, "not found scene:%s", scene_str); + + return -EINVAL; +} + +static int aw_dev_parse_skt_type_v_1_0_0_0(struct aw_device *aw_dev, + struct aw_cfg_hdr *prof_hdr) +{ + int i = 0; + int ret; + int scene_id = 0; + struct aw_prof_info *prof_info = &aw_dev->prof_info; + struct aw_cfg_dde_v_1_0_0_0 *cfg_dde = + (struct aw_cfg_dde_v_1_0_0_0 *)((char *)prof_hdr + prof_hdr->a_hdr_offset); + + aw_dev_info(aw_dev->dev, "enter"); + + for (i = 0; i < prof_hdr->a_ddt_num; i++) { + if ((cfg_dde[i].type == AW_SKT_TYPE_ID) && + (cfg_dde[i].data_type == ACF_SEC_TYPE_DSP) && + (aw_dev->channel == cfg_dde[i].dev_index) && + (aw_dev->chip_id == cfg_dde[i].chip_id)) { + ret = aw_dev_parse_get_scene_id_v_1_0_0_0(aw_dev, cfg_dde[i].dev_profile_str, &scene_id); + if (ret < 0) { + aw_dev_err(aw_dev->dev, "get scene id failed"); + return ret; + } + + ret = aw_dev_parse_raw_dsp(aw_dev, + (uint8_t *)prof_hdr + cfg_dde[i].data_offset, + cfg_dde[i].data_size, &prof_info->prof_desc[scene_id]); + if (ret < 0) { + aw_dev_err(aw_dev->dev, "parse dsp bin data failed"); + return ret; + } + } + } + + return 0; +} + + +static int aw_dev_parse_by_hdr_v_1_0_0_0(struct aw_device *aw_dev, + struct aw_cfg_hdr *cfg_hdr, int is_default) +{ + int ret; + + if (is_default) { + ret = aw_dev_parse_dev_default_type_v_1_0_0_0(aw_dev, cfg_hdr); + if (ret < 0) + return ret; + } else { + ret = aw_dev_parse_dev_type_v_1_0_0_0(aw_dev, cfg_hdr); + if (ret < 0) + return ret; + } + + ret = aw_dev_parse_skt_type_v_1_0_0_0(aw_dev, cfg_hdr); + if (ret < 0) + return ret; + + return 0; +} + +static int aw_dev_parse_acf_by_hdr_v_1_0_0_0(struct aw_device *aw_dev, struct aw_container *aw_cfg) +{ + struct aw_prof_info *prof_info = &aw_dev->prof_info; + struct aw_cfg_hdr *cfg_hdr = (struct aw_cfg_hdr *)aw_cfg->data; + int ret; + int is_default = 0; + + ret = aw_dev_parse_get_scene_count_v1_0_0_0(aw_dev, aw_cfg, &prof_info->count, &is_default); + if (ret < 0) { + aw_dev_err(aw_dev->dev, "get scene count failed"); + return ret; + } + + prof_info->prof_desc = devm_kzalloc(aw_dev->dev, + prof_info->count * sizeof(struct aw_prof_desc), + GFP_KERNEL); + if (prof_info->prof_desc == NULL) { + aw_dev_err(aw_dev->dev, "prof_desc devm_kzalloc failed"); + return -ENOMEM; + } + + ret = aw_dev_parse_by_hdr_v_1_0_0_0(aw_dev, cfg_hdr, is_default); + if (ret < 0) { + aw_dev_err(aw_dev->dev, " failed"); + return ret; + } + + ret = aw_dev_parse_create_prof_name_list_v_1_0_0_0(aw_dev); + if (ret < 0) { + aw_dev_err(aw_dev->dev, "create prof name list failed"); + return ret; + } + + return 0; +} + +int aw882xx_dev_parse_acf(struct aw_device *aw_dev, struct aw_container *aw_cfg) +{ + struct aw_cfg_hdr *cfg_hdr = NULL; + int ret; + + aw_dev_info(aw_dev->dev, "enter"); + + cfg_hdr = (struct aw_cfg_hdr *)aw_cfg->data; + switch (cfg_hdr->a_hdr_version) { + case AW_CFG_HDR_VER_0_0_0_1: + ret = aw_dev_parse_acf_by_hdr(aw_dev, cfg_hdr); + if (ret < 0) { + aw_dev_err(aw_dev->dev, "hdr_cersion[0x%x] parse failed", + cfg_hdr->a_hdr_version); + return ret; + } + break; + case AW_CFG_HDR_VER_1_0_0_0: + ret = aw_dev_parse_acf_by_hdr_v_1_0_0_0(aw_dev, aw_cfg); + if (ret < 0) { + aw_dev_err(aw_dev->dev, "hdr_cersion[0x%x] parse failed", + cfg_hdr->a_hdr_version); + return ret; + } + break; + default: + aw_pr_err("unsupported hdr_version [0x%x]", cfg_hdr->a_hdr_version); + return -EINVAL; + } + + aw_dev_info(aw_dev->dev, "parse cfg success"); + return 0; +} + +char *aw882xx_dev_get_prof_name(struct aw_device *aw_dev, int index) +{ + struct aw_prof_desc *prof_desc = NULL; + struct aw_prof_info *prof_info = &aw_dev->prof_info; + + if (index < 0) { + aw_dev_err(aw_dev->dev, "index[%d] error", index); + return NULL; + } + + if (index >= prof_info->count) { + aw_dev_err(aw_dev->dev, "index[%d] overflow count[%d]", + index, aw_dev->prof_info.count); + return NULL; + } + + prof_desc = &prof_info->prof_desc[index]; + + return prof_info->prof_name_list[prof_desc->id]; +} + +int aw88xx_dev_get_profile_name(struct aw_device *aw_dev, char *name, int index) +{ + int dev_profile_id = 0; + int ret = 0; + struct aw_prof_info *prof_info = &aw_dev->prof_info; + + if (index < 0) { + aw_dev_err(aw_dev->dev, "index[%d] error", index); + return -EINVAL; + } + + if (index > prof_info->count) { + aw_dev_err(aw_dev->dev, "index[%d] overflow dev prof num[%d]", + index, prof_info->count); + return -EINVAL; + } + + dev_profile_id = prof_info->prof_desc[index].id; + + ret = strscpy(name, prof_info->prof_name_list[dev_profile_id], + strlen(prof_info->prof_name_list[dev_profile_id]) + 1); + if (ret < 0) + return ret; + + return 0; +} + +struct aw_sec_data_desc *aw882xx_dev_get_prof_data(struct aw_device *aw_dev, int index, int data_type) +{ + struct aw_sec_data_desc *sec_data = NULL; + struct aw_prof_desc *prof_desc = NULL; + struct aw_prof_info *prof_info = &aw_dev->prof_info; + + if (index >= prof_info->count) { + aw_dev_err(aw_dev->dev, "index[%d] overflow count[%d]", + index, prof_info->count); + return NULL; + } + + prof_desc = &aw_dev->prof_info.prof_desc[index]; + + if (data_type >= AW_PROFILE_DATA_TYPE_MAX) { + aw_dev_err(aw_dev->dev, "unsupport data type id [%d]", data_type); + return NULL; + } + + sec_data = &prof_desc->sec_desc[data_type]; + + aw_dev_dbg(aw_dev->dev, "get prof[%s] data len[%d]", + prof_info->prof_name_list[prof_desc->id], sec_data->len); + + return sec_data; +} + +int aw882xx_dev_set_profile_index(struct aw_device *aw_dev, int index) +{ + struct aw_prof_info *prof_info = &aw_dev->prof_info; + struct mutex *ext_dsp_prof_wr_lock = NULL; + char *ext_dsp_prof_write = NULL; + + if (index >= prof_info->count || index < 0) + return -EINVAL; + + aw_dev->set_prof = index; + aw_dev_info(aw_dev->dev, "set prof[%s]", + prof_info->prof_name_list[prof_info->prof_desc[index].id]); + + + ext_dsp_prof_wr_lock = aw882xx_dev_get_ext_dsp_prof_wr_lock(); + ext_dsp_prof_write = aw882xx_dev_get_ext_dsp_prof_write(); + + mutex_lock(ext_dsp_prof_wr_lock); + *ext_dsp_prof_write = AW_EXT_DSP_WRITE_NONE; + mutex_unlock(ext_dsp_prof_wr_lock); + + return 0; +} + +int aw882xx_dev_get_profile_count(struct aw_device *aw_dev) +{ + if (aw_dev == NULL) { + aw_pr_err("aw_dev is NULL"); + return -ENOMEM; + } + + return aw_dev->prof_info.count; +} + +int aw882xx_dev_check_profile_index(struct aw_device *aw_dev, int index) +{ + if ((index >= aw_dev->prof_info.count) || (index < 0)) + return -EINVAL; + else + return 0; +} + +int aw882xx_dev_get_profile_index(struct aw_device *aw_dev) +{ + return aw_dev->set_prof; +} + diff --git a/sound/soc/codecs/aw882xx/aw882xx_bin_parse.h b/sound/soc/codecs/aw882xx/aw882xx_bin_parse.h new file mode 100644 index 000000000000..b47dbf66ccb7 --- /dev/null +++ b/sound/soc/codecs/aw882xx/aw882xx_bin_parse.h @@ -0,0 +1,102 @@ +/* SPDX-License-Identifier: GPL-2.0 + * aw882xx_bin_parse.h + * + * Copyright (c) 2020 AWINIC Technology CO., LTD + * + * Author: Nick Li + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#ifndef __AW882XX_BIN_PARSE_H__ +#define __AW882XX_BIN_PARSE_H__ + +#include "aw882xx_device.h" + +#define NULL ((void *)0) +#define GET_32_DATA(w, x, y, z) ((unsigned int)((((uint32_t)w) << 24) | (((uint32_t)x) << 16) | (((uint32_t)y) << 8) | ((uint32_t)z))) +#define BIN_NUM_MAX 100 +#define HEADER_LEN 60 +/********************************************************* + * + * header information + * + ********************************************************/ +enum bin_header_version_enum { + HEADER_VERSION_1_0_0 = 0x01000000, +}; + +enum data_type_enum { + DATA_TYPE_REGISTER = 0x00000000, + DATA_TYPE_DSP_REG = 0x00000010, + DATA_TYPE_DSP_CFG = 0x00000011, + DATA_TYPE_SOC_REG = 0x00000020, + DATA_TYPE_SOC_APP = 0x00000021, + DATA_TYPE_MULTI_BINS = 0x00002000, +}; + +enum data_version_enum { + DATA_VERSION_V1 = 0X00000001, /*default little edian */ + DATA_VERSION_MAX, +}; + +struct bin_header_info { + unsigned int header_len; /* Frame header length */ + unsigned int check_sum; /* Frame header information-Checksum */ + unsigned int header_ver; /* Frame header information-Frame header version */ + unsigned int bin_data_type; /* Frame header information-Data type */ + unsigned int bin_data_ver; /* Frame header information-Data version */ + unsigned int bin_data_len; /* Frame header information-Data length */ + unsigned int ui_ver; /* Frame header information-ui version */ + unsigned char chip_type[8]; /* Frame header information-chip type */ + unsigned int reg_byte_len; /* Frame header information-reg byte len */ + unsigned int data_byte_len; /* Frame header information-data byte len */ + unsigned int device_addr; /* Frame header information-device addr */ + unsigned int valid_data_len; /* Length of valid data obtained after parsing */ + unsigned int valid_data_addr; /* The offset address of the valid data obtained after parsing relative to info */ + + unsigned int reg_num; /* The number of registers obtained after parsing */ + unsigned int reg_data_byte_len; /* The byte length of the register obtained after parsing */ + unsigned int download_addr; /* The starting address or download address obtained after parsing */ + unsigned int app_version; /* The software version number obtained after parsing */ +}; + +/************************************************************ + * + * function define + * + ************************************************************/ +struct bin_container { + unsigned int len; /* The size of the bin file obtained from the firmware */ + unsigned char data[]; /* Store the bin file obtained from the firmware */ +}; + +struct aw_bin { + unsigned char *p_addr; /* Offset pointer (backward offset pointer to obtain frame header information and important information) */ + unsigned int all_bin_parse_num; /* The number of all bin files */ + unsigned int multi_bin_parse_num; /* The number of single bin files */ + unsigned int single_bin_parse_num; /* The number of multiple bin files */ + struct bin_header_info header_info[BIN_NUM_MAX]; /* Frame header information and other important data obtained after parsing */ + struct bin_container info; /* Obtained bin file data that needs to be parsed */ +}; + + +/*******************awinic audio parse acf***********************/ + +int aw882xx_dev_parse_check_acf(struct aw_container *aw_cfg); +int aw882xx_dev_parse_acf(struct aw_device *aw_dev, struct aw_container *aw_cfg); + + +int aw882xx_dev_get_profile_count(struct aw_device *aw_dev); +int aw88xx_dev_get_profile_name(struct aw_device *aw_dev, char *name, int index); +int aw882xx_dev_check_profile_index(struct aw_device *aw_dev, int index); +int aw882xx_dev_get_profile_index(struct aw_device *aw_dev); +int aw882xx_dev_set_profile_index(struct aw_device *aw_dev, int index); +char *aw882xx_dev_get_prof_name(struct aw_device *aw_dev, int index); +struct aw_sec_data_desc *aw882xx_dev_get_prof_data(struct aw_device *aw_dev, int index, int data_type); + + +#endif diff --git a/sound/soc/codecs/aw882xx/aw882xx_calib.c b/sound/soc/codecs/aw882xx/aw882xx_calib.c new file mode 100644 index 000000000000..fad7ba7c4175 --- /dev/null +++ b/sound/soc/codecs/aw882xx/aw882xx_calib.c @@ -0,0 +1,2453 @@ +// SPDX-License-Identifier: GPL-2.0 +/* aw882xx_calib.c cali_module + * + * Copyright (c) 2020 AWINIC Technology CO., LTD + * + * Author: Nick Li + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ +/*#define DEBUG*/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "aw882xx.h" +#include "aw882xx_dsp.h" +#include "aw882xx_log.h" +#include "aw882xx_calib.h" + +static bool is_single_cali; /*if mutli_dev cali false, single dev true*/ + +static const char *cali_str[CALI_STR_MAX] = {"none", "start_cali", "cali_re", + "cali_f0", "store_re", "show_re", "show_r0", "show_cali_f0", "show_f0", + "show_te", "show_st", "dev_sel", "get_ver", "get_dev_num", + "cali_q_f0", "show_q_f0", "get_re_range" +}; + +static char *ch_name[AW_DEV_CH_MAX] = {"pri_l", "pri_r", "sec_l", "sec_r", + "tert_l", "tert_r", "quat_l", "quat_r"}; +static unsigned int g_cali_re_time = AW_CALI_RE_DEFAULT_TIMER; +static unsigned int g_msic_wr_flag = CALI_STR_NONE; +static unsigned int g_dev_select = AW_DEV_CH_PRI_L; +static unsigned int g_cali_status; +static struct miscdevice *g_misc_dev; +static DEFINE_MUTEX(g_cali_lock); + +#ifndef AW_AUDIOREACH_PLATFORM +#define AW_CALI_STORE_EXAMPLE +#endif + +#ifdef AW_CALI_STORE_EXAMPLE + /*write cali to persist file example*/ +#define AWINIC_CALI_FILE "/mnt/vendor/persist/factory/audio/aw_cali.bin" +#define AW_INT_DEC_DIGIT 10 + +static void aw_fs_read(struct file *file, char *buf, size_t count, loff_t *pos) +{ +#ifdef AW_KERNEL_VER_OVER_5_4_0 + kernel_read(file, buf, count, pos); +#else + vfs_read(file, buf, count, pos); +#endif +} + +static void aw_fs_write(struct file *file, char *buf, size_t count, loff_t *pos) +{ +#ifdef AW_KERNEL_VER_OVER_5_4_0 + kernel_write(file, buf, count, pos); +#else + vfs_write(file, buf, count, pos); +#endif +} + +static int aw_cali_write_cali_re_to_file(int32_t cali_re, int channel) +{ + struct file *fp = NULL; + char buf[50] = {0}; + loff_t pos = 0; +#if !defined AW_KERNEL_VER_OVER_6_1_0 + mm_segment_t fs; +#endif + + fp = filp_open(AWINIC_CALI_FILE, O_RDWR | O_CREAT, 0644); + if (IS_ERR(fp)) { + aw_pr_err("channel:%d open %s failed, error=%ld", + channel, AWINIC_CALI_FILE, PTR_ERR(fp)); + return -EINVAL; + } + + pos = AW_INT_DEC_DIGIT * channel; + + snprintf(buf, sizeof(buf), "%10d", cali_re); + +#ifdef AW_KERNEL_VER_OVER_6_1_0 +#elif defined AW_KERNEL_VER_OVER_5_10_0 + fs = force_uaccess_begin(); +#else + fs = get_fs(); + set_fs(KERNEL_DS); +#endif + + aw_fs_write(fp, buf, strlen(buf), &pos); + +#ifdef AW_KERNEL_VER_OVER_6_1_0 +#elif defined AW_KERNEL_VER_OVER_5_10_0 + force_uaccess_end(fs); +#else + set_fs(fs); +#endif + + aw_pr_info("channel:%d buf:%s cali_re:%d", + channel, buf, cali_re); + + filp_close(fp, NULL); + return 0; +} + +static int aw_cali_get_read_cali_re(int32_t *cali_re, int channel) +{ + struct file *fp = NULL; + /*struct inode *node;*/ + int f_size; + char *buf = NULL; + int32_t int_cali_re = 0; + loff_t pos = 0; +#if !defined AW_KERNEL_VER_OVER_6_1_0 + mm_segment_t fs; +#endif + + char *re_buf = NULL; + + fp = filp_open(AWINIC_CALI_FILE, O_RDONLY, 0); + if (IS_ERR(fp)) { + aw_pr_err("channel:%d open %s failed, error=%ld", + channel, AWINIC_CALI_FILE, PTR_ERR(fp)); + return -EINVAL; + } + + pos = AW_INT_DEC_DIGIT * channel; + + /*node = fp->f_dentry->d_inode;*/ + /*f_size = node->i_size;*/ + f_size = AW_INT_DEC_DIGIT; + + buf = kzalloc(f_size + 1, GFP_ATOMIC); + if (!buf) { + filp_close(fp, NULL); + return -ENOMEM; + } + +#ifdef AW_KERNEL_VER_OVER_6_1_0 +#elif defined AW_KERNEL_VER_OVER_5_10_0 + fs = force_uaccess_begin(); +#else + fs = get_fs(); + set_fs(KERNEL_DS); +#endif + + aw_fs_read(fp, buf, f_size, &pos); + +#ifdef AW_KERNEL_VER_OVER_6_1_0 +#elif defined AW_KERNEL_VER_OVER_5_10_0 + force_uaccess_end(fs); +#else + set_fs(fs); +#endif + + re_buf = skip_spaces(buf); + + if (kstrtoint(re_buf, 10, &int_cali_re) == 0) + *cali_re = int_cali_re; + else + *cali_re = AW_ERRO_CALI_VALUE; + + re_buf = NULL; + aw_pr_info("channel:%d buf:%s int_cali_re: %d", + channel, buf, int_cali_re); + + kfree(buf); + buf = NULL; + filp_close(fp, NULL); + + return 0; +} +#endif + +/*custom need add to set/get cali_re form/to nv*/ +static int aw_cali_write_re_to_nvram(int32_t cali_re, int32_t channel) +{ +#ifdef AW_CALI_STORE_EXAMPLE + if (channel >= AW_DEV_CH_MAX) { + aw_pr_err("unsupported channel [%d]", channel); + return -EINVAL; + } + return aw_cali_write_cali_re_to_file(cali_re, channel); +#else + return 0; +#endif +} + +int aw882xx_cali_read_re_from_nvram(int32_t *cali_re, int32_t channel) +{ + /*custom add, if success return value is 0 , else -1*/ +#ifdef AW_CALI_STORE_EXAMPLE + if (channel >= AW_DEV_CH_MAX) { + aw_pr_err("unsupported channel [%d]", channel); + return -EINVAL; + } + return aw_cali_get_read_cali_re(cali_re, channel); +#else + return 0; +#endif +} + +bool aw882xx_cali_check_result(struct aw_cali_desc *cali_desc) +{ + if (cali_desc->cali_check_st && + (cali_desc->cali_result == CALI_RESULT_ERROR)) { + return false; + } else { + return true; + } +} + +static void aw_cali_svc_run_mute(struct aw_device *aw_dev, int8_t cali_result) +{ + aw_dev_dbg(aw_dev->dev, "enter"); + + if (aw_dev->cali_desc.cali_check_st) { + if (cali_result == CALI_RESULT_ERROR) + aw882xx_dev_mute(aw_dev, true); + else if (cali_result == CALI_RESULT_NORMAL) + aw882xx_dev_mute(aw_dev, false); + else + aw_dev_info(aw_dev->dev, "unsupported result"); + } else { + aw_dev_info(aw_dev->dev, "cali check disable"); + } + + aw_dev_info(aw_dev->dev, "done"); +} + +static int aw_cali_svc_get_dev_re_range(struct aw_device *aw_dev, + uint32_t *data_buf) +{ + data_buf[RE_MIN_FLAG] = aw_dev->re_min; + data_buf[RE_MAX_FLAG] = aw_dev->re_max; + + return 0; +} + +static int aw_cali_svc_get_devs_re_range(struct aw_device *aw_dev, + uint32_t *data_buf, int num) +{ + int ret, cnt = 0; + struct list_head *dev_list = NULL; + struct list_head *pos = NULL; + struct aw_device *local_dev = NULL; + + /*get dev list*/ + ret = aw882xx_dev_get_list_head(&dev_list); + if (ret) { + aw_dev_err(aw_dev->dev, "get dev list failed"); + return ret; + } + + list_for_each(pos, dev_list) { + local_dev = container_of(pos, struct aw_device, list_node); + if (local_dev->channel < num) { + /*buf[0]:pri_l_re_min, buf[1]:pri_l_re_min, buf[2]:pri_r_re_min, buf[3]:pri_r_re_min*/ + data_buf[RE_MIN_FLAG + local_dev->channel * 2] = + local_dev->re_min; + data_buf[RE_MAX_FLAG + local_dev->channel * 2] = + local_dev->re_max; + cnt++; + } else { + aw_dev_err(local_dev->dev, "channel num[%d] overflow buf num[%d]", + local_dev->channel, num); + return -EINVAL; + } + } + + return cnt; +} + +static int aw_cali_store_cali_re(struct aw_device *aw_dev, int32_t re) +{ + int ret = 0; + + if (((re >= aw_dev->re_min) && (re <= aw_dev->re_max)) || + aw_dev->cali_desc.cali_check_st) { + aw_dev->cali_desc.cali_re = re; + ret = aw_cali_write_re_to_nvram(re, aw_dev->channel); + if (ret) { + aw_dev_err(aw_dev->dev, "write re to nvram failed!"); + goto store_cali_re_failed; + } + aw_dev_info(aw_dev->dev, "store cali re is %d", re); + } + + if ((re < aw_dev->re_min) || (re > aw_dev->re_max)) { + aw_dev_info(aw_dev->dev, "re[%d] out of range {%d, %d}", + re, aw_dev->re_min, aw_dev->re_max); + ret = -EINVAL; + goto store_cali_re_failed; + } + + if (aw_dev->cali_desc.cali_check_st) + aw_dev->cali_desc.cali_result = CALI_RESULT_NORMAL; + + return 0; + +store_cali_re_failed: + if (aw_dev->cali_desc.cali_check_st) { + aw_dev->cali_desc.cali_result = CALI_RESULT_ERROR; + aw_cali_svc_run_mute(aw_dev, aw_dev->cali_desc.cali_result); + } + return ret; +} + +/*********************************aw_cali_sevice*********************************************************/ +static void aw_cali_svc_set_cali_status(struct aw_device *aw_dev, int status) +{ + if (status) + g_cali_status = true; + else + g_cali_status = false; + + aw_dev_info(aw_dev->dev, "cali %s", + (status == 0) ? ("disable") : ("enable")); +} + +int aw882xx_cali_svc_get_cali_status(void) +{ + return g_cali_status; +} + +static int aw_cali_svc_dev_get_re(struct aw_device *aw_dev) +{ + int ret, i; + int32_t re[AW_CALI_READ_RE_TIMES] = {0}; + int32_t sum = 0; + + for (i = 0; i < AW_CALI_READ_RE_TIMES; i++) { + ret = aw882xx_dsp_read_r0(aw_dev, &re[i]); + if (ret) { + aw_dev_err(aw_dev->dev, "get re failed!"); + if (aw_dev->cali_desc.cali_check_st) { + aw_dev->cali_desc.cali_result = CALI_RESULT_ERROR; + aw_cali_svc_run_mute(aw_dev, aw_dev->cali_desc.cali_result); + } + return ret; + } + sum += re[i]; + usleep_range(AW_32000_US, AW_32000_US + 10); + } + re[0] = sum / AW_CALI_READ_RE_TIMES; + + aw_dev->cali_desc.cali_re = re[0]; + + ret = aw_cali_store_cali_re(aw_dev, aw_dev->cali_desc.cali_re); + return ret; +} + +static int aw_cali_svc_dev_get_f0(struct aw_device *aw_dev) +{ + int ret, i; + int32_t f0[AW_CALI_READ_F0_Q_TIMES] = {0}; + int32_t sum = 0; + + for (i = 0; i < AW_CALI_READ_F0_Q_TIMES; i++) { + ret = aw882xx_dsp_read_f0(aw_dev, &f0[i]); + if (ret) { + aw_dev_err(aw_dev->dev, "get f0 failed!"); + return ret; + } + sum += f0[i]; + usleep_range(AW_70000_US, AW_70000_US + 10); + } + f0[0] = sum / AW_CALI_READ_F0_Q_TIMES; + + aw_dev->cali_desc.cali_f0 = f0[0]; + return 0; +} + +static int aw_cali_svc_dev_get_f0_q(struct aw_device *aw_dev) +{ + int ret, i; + int32_t f0[AW_CALI_READ_F0_Q_TIMES] = {0}; + int32_t q[AW_CALI_READ_F0_Q_TIMES] = {0}; + int32_t sum_f0 = 0, sum_q = 0; + + for (i = 0; i < AW_CALI_READ_F0_Q_TIMES; i++) { + ret = aw882xx_dsp_read_f0_q(aw_dev, &f0[i], &q[i]); + if (ret) { + aw_dev_err(aw_dev->dev, "get f0 failed!"); + return ret; + } + sum_f0 += f0[i]; + sum_q += q[i]; + usleep_range(AW_70000_US, AW_70000_US + 10); + } + f0[0] = sum_f0 / AW_CALI_READ_F0_Q_TIMES; + q[0] = sum_q / AW_CALI_READ_F0_Q_TIMES; + aw_dev->cali_desc.cali_f0 = f0[0]; + aw_dev->cali_desc.cali_q = q[0]; + aw_dev_dbg(aw_dev->dev, "cali f0 is %d, q is %d", + aw_dev->cali_desc.cali_f0, aw_dev->cali_desc.cali_q); + return 0; +} + + +static int aw_cali_svc_dev_cali_mode_en(struct aw_device *aw_dev, int type, bool is_enable, unsigned int flag) +{ + int ret; + + /* open cali mode */ + if (is_enable) { + aw882xx_dev_iv_forbidden_output(aw_dev, false); + + aw_cali_svc_set_cali_status(aw_dev, true); + + if (type == CALI_TYPE_RE) { + if (flag & CALI_OPS_HMUTE) { + ret = aw882xx_dsp_hmute_en(aw_dev, true); + if (ret < 0) + return ret; + } + ret = aw882xx_dsp_cali_en(aw_dev, MSG_CALI_RE_ENABLE_DATA); + if (ret < 0) + return ret; + } else { + if (flag & CALI_OPS_NOISE) { + ret = aw882xx_dsp_noise_en(aw_dev, true); + if (ret < 0) + return ret; + } + ret = aw882xx_dsp_cali_en(aw_dev, MSG_CALI_F0_ENABLE_DATA); + if (ret < 0) + return ret; + } + } else { + aw882xx_dsp_cali_en(aw_dev, MSG_CALI_DISABLE_DATA); + + if (type == CALI_TYPE_RE) { + /*close mute*/ + if (flag & CALI_OPS_HMUTE) + aw882xx_dsp_hmute_en(aw_dev, false); + } else { + /*close mute*/ + if (flag & CALI_OPS_NOISE) + aw882xx_dsp_noise_en(aw_dev, false); + } + + /*close cali mode*/ + aw_cali_svc_set_cali_status(aw_dev, false); + + aw882xx_dev_iv_forbidden_output(aw_dev, true); + } + return 0; +} + +static int aw_cali_svc_dev_cali_re(struct aw_device *aw_dev, unsigned int flag) +{ + int ret; + + aw_cali_svc_run_mute(aw_dev, CALI_RESULT_NORMAL); + + ret = aw_cali_svc_dev_cali_mode_en(aw_dev, CALI_TYPE_RE, true, flag); + if (ret < 0) + goto exit; + + /*wait time*/ + msleep(g_cali_re_time); + + /*dev get echo cali re*/ + ret = aw_cali_svc_dev_get_re(aw_dev); +exit: + aw_cali_svc_dev_cali_mode_en(aw_dev, CALI_TYPE_RE, false, flag); + return ret; +} + +static int aw_cali_svc_devs_get_cali_cali_data(struct list_head *dev_list, + unsigned int data_type) +{ + int ret = -1; + struct list_head *pos = NULL; + struct aw_device *local_dev = NULL; + + list_for_each(pos, dev_list) { + local_dev = container_of(pos, struct aw_device, list_node); + if (data_type == CALI_DATA_RE) { + ret = aw_cali_svc_dev_get_re(local_dev); + } else if (data_type == CALI_DATA_F0) { + ret = aw_cali_svc_dev_get_f0(local_dev); + } else if (data_type == CALI_DATA_F0_Q) { + ret = aw_cali_svc_dev_get_f0_q(local_dev); + } else { + aw_dev_err(local_dev->dev, "unsupport cali data type :%d", data_type); + return -EINVAL; + } + if (ret < 0) { + aw_dev_err(local_dev->dev, "get cali data type[%d] failed", data_type); + return ret; + } + } + + return ret; +} + +static int aw_cali_svc_devs_cali_mode_enable(struct list_head *dev_list, + int type, unsigned int flag, + bool is_enable) +{ + int ret = -1; + struct list_head *pos = NULL; + struct aw_device *local_dev = NULL; + + list_for_each(pos, dev_list) { + local_dev = container_of(pos, struct aw_device, list_node); + if (is_enable) + aw_cali_svc_run_mute(local_dev, CALI_RESULT_NORMAL); + ret = aw_cali_svc_dev_cali_mode_en(local_dev, type, is_enable, flag); + if (ret < 0) + return ret; + if (!is_enable && (type == CALI_TYPE_F0)) + aw_cali_svc_run_mute(local_dev, local_dev->cali_desc.cali_result); + } + + return ret; +} + +static int aw_cali_svc_devs_cali_re(struct aw_device *aw_dev, unsigned int flag) +{ + int ret; + struct list_head *dev_list = NULL; + + aw_dev_info(aw_dev->dev, "enter"); + + ret = aw882xx_dev_get_list_head(&dev_list); + if (ret) { + aw_dev_err(aw_dev->dev, " get dev list failed"); + return ret; + } + + ret = aw_cali_svc_devs_cali_mode_enable(dev_list, CALI_TYPE_RE, flag, true); + if (ret < 0) + goto exit; + + msleep(g_cali_re_time); + + ret = aw_cali_svc_devs_get_cali_cali_data(dev_list, CALI_DATA_RE); +exit: + aw_cali_svc_devs_cali_mode_enable(dev_list, CALI_TYPE_RE, flag, false); + return ret; +} + + +static int aw_cali_svc_cali_re(struct aw_device *aw_dev, bool is_single, unsigned int flag) +{ + if (is_single) + return aw_cali_svc_dev_cali_re(aw_dev, flag); + else + return aw_cali_svc_devs_cali_re(aw_dev, flag); + return 0; +} + +static int aw_cali_svc_dev_cali_f0(struct aw_device *aw_dev, unsigned int flag) +{ + int ret; + + aw_cali_svc_run_mute(aw_dev, CALI_RESULT_NORMAL); + + ret = aw_cali_svc_dev_cali_mode_en(aw_dev, CALI_TYPE_F0, true, flag); + if (ret < 0) + goto exit; + + /*wait time*/ + msleep(5 * 1000); + + /*dev get cali f0*/ + ret = aw_cali_svc_dev_get_f0(aw_dev); +exit: + aw_cali_svc_dev_cali_mode_en(aw_dev, CALI_TYPE_F0, false, flag); + aw_cali_svc_run_mute(aw_dev, aw_dev->cali_desc.cali_result); + return ret; +} + +static int aw_cali_svc_devs_cali_f0(struct aw_device *aw_dev, unsigned int flag) +{ + int ret; + struct list_head *dev_list = NULL; + + ret = aw882xx_dev_get_list_head(&dev_list); + if (ret) { + aw_dev_err(aw_dev->dev, " get dev list failed"); + return ret; + } + + ret = aw_cali_svc_devs_cali_mode_enable(dev_list, CALI_TYPE_F0, flag, true); + if (ret < 0) + goto exit; + + /*wait time*/ + msleep(5 * 1000); + + ret = aw_cali_svc_devs_get_cali_cali_data(dev_list, CALI_DATA_F0); +exit: + aw_cali_svc_devs_cali_mode_enable(dev_list, CALI_TYPE_F0, flag, false); + return ret; +} + +static int aw_cali_svc_cali_f0(struct aw_device *aw_dev, bool is_single, unsigned int flag) +{ + if (is_single) + return aw_cali_svc_dev_cali_f0(aw_dev, flag); + else + return aw_cali_svc_devs_cali_f0(aw_dev, flag); + return 0; +} + +static int aw_cali_svc_dev_cali_f0_q(struct aw_device *aw_dev, unsigned int flag) +{ + int ret; + + aw_cali_svc_run_mute(aw_dev, CALI_RESULT_NORMAL); + + ret = aw_cali_svc_dev_cali_mode_en(aw_dev, CALI_TYPE_F0, true, flag); + if (ret < 0) + goto exit; + + + /*wait time*/ + msleep(5 * 1000); + + /*dev get cali f0 q*/ + ret = aw_cali_svc_dev_get_f0_q(aw_dev); +exit: + aw_cali_svc_dev_cali_mode_en(aw_dev, CALI_TYPE_F0, false, flag); + aw_cali_svc_run_mute(aw_dev, aw_dev->cali_desc.cali_result); + return ret; + +} + +static int aw_cali_svc_devs_cali_f0_q(struct aw_device *aw_dev, unsigned int flag) +{ + int ret; + struct list_head *dev_list = NULL; + + ret = aw882xx_dev_get_list_head(&dev_list); + if (ret) { + aw_dev_err(aw_dev->dev, "get dev list failed "); + return ret; + } + + ret = aw_cali_svc_devs_cali_mode_enable(dev_list, CALI_TYPE_F0, flag, true); + if (ret < 0) + goto exit; + + /*wait time*/ + msleep(5 * 1000); + + /*dev get cali f0 q*/ + ret = aw_cali_svc_devs_get_cali_cali_data(dev_list, CALI_DATA_F0_Q); +exit: + aw_cali_svc_devs_cali_mode_enable(dev_list, CALI_TYPE_F0, flag, false); + return ret; +} + +static int aw_cali_svc_cali_f0_q(struct aw_device *aw_dev, bool is_single, unsigned int flag) +{ + if (is_single) + return aw_cali_svc_dev_cali_f0_q(aw_dev, flag); + else + return aw_cali_svc_devs_cali_f0_q(aw_dev, flag); + + return 0; +} + +static int aw_cali_svc_cali_re_f0(struct aw_device *aw_dev, bool is_single, unsigned int flag) +{ + int ret; + + ret = aw_cali_svc_cali_re(aw_dev, is_single, flag); + if (ret) + return ret; + + ret = aw_cali_svc_cali_f0(aw_dev, is_single, flag); + if (ret) + return ret; + + return 0; +} + +static int aw_cali_svc_cali_re_f0_q(struct aw_device *aw_dev, bool is_single, unsigned int flag) +{ + int ret; + + ret = aw_cali_svc_cali_re(aw_dev, is_single, flag); + if (ret) + return ret; + + ret = aw_cali_svc_cali_f0_q(aw_dev, is_single, flag); + if (ret) + return ret; + + return 0; +} + +static int aw_cali_svc_cali_cmd(struct aw_device *aw_dev, int cali_cmd, bool is_single, unsigned int flag) +{ + switch (cali_cmd) { + case AW_CALI_CMD_RE: + return aw_cali_svc_cali_re(aw_dev, is_single, flag); + case AW_CALI_CMD_F0: + return aw_cali_svc_cali_f0(aw_dev, is_single, flag); + case AW_CALI_CMD_F0_Q: + return aw_cali_svc_cali_f0_q(aw_dev, is_single, flag); + case AW_CALI_CMD_RE_F0: + return aw_cali_svc_cali_re_f0(aw_dev, is_single, flag); + case AW_CALI_CMD_RE_F0_Q: + return aw_cali_svc_cali_re_f0_q(aw_dev, is_single, flag); + default: + aw_dev_err(aw_dev->dev, "unsupported cmd %d", cali_cmd); + return -EINVAL; + } + return 0; +} + +static int aw_cali_svc_get_devs_cali_re(struct aw_device *aw_dev, int32_t *re_buf, int num) +{ + int ret, cnt = 0; + struct list_head *dev_list = NULL; + struct list_head *pos = NULL; + struct aw_device *local_dev = NULL; + + /* get dev list */ + ret = aw882xx_dev_get_list_head(&dev_list); + if (ret) { + aw_dev_err(aw_dev->dev, "get dev list failed"); + return ret; + } + + list_for_each(pos, dev_list) { + local_dev = container_of(pos, struct aw_device, list_node); + if (local_dev->channel < num) { + re_buf[local_dev->channel] = local_dev->cali_desc.cali_re; + cnt++; + } else { + aw_dev_err(aw_dev->dev, "channel num[%d] overflow buf num[%d]", + local_dev->channel, num); + return -EINVAL; + } + } + + return cnt; +} + +static int aw_cali_svc_get_devs_r0(struct aw_device *aw_dev, int32_t *re_buf, int num) +{ + int ret, cnt = 0; + struct list_head *dev_list = NULL; + struct list_head *pos = NULL; + struct aw_device *local_dev = NULL; + + /* get dev list */ + ret = aw882xx_dev_get_list_head(&dev_list); + if (ret) { + aw_dev_err(aw_dev->dev, "get dev list failed"); + return ret; + } + + list_for_each(pos, dev_list) { + local_dev = container_of(pos, struct aw_device, list_node); + if (local_dev->channel < num) { + ret = aw882xx_dsp_read_r0(local_dev, &re_buf[local_dev->channel]); + if (ret) { + aw_dev_err(local_dev->dev, "get re failed!"); + return ret; + } + cnt++; + } else { + aw_dev_err(aw_dev->dev, "channel num[%d] overflow buf num[%d] ", + local_dev->channel, num); + } + } + return cnt; +} + +static int aw_cali_svc_get_devs_te(struct aw_device *aw_dev, int32_t *te_buf, int num) +{ + int ret, cnt = 0; + struct list_head *dev_list = NULL; + struct list_head *pos = NULL; + struct aw_device *local_dev = NULL; + + /* get dev list */ + ret = aw882xx_dev_get_list_head(&dev_list); + if (ret) { + aw_dev_err(aw_dev->dev, "get dev list failed"); + return ret; + } + + list_for_each(pos, dev_list) { + local_dev = container_of(pos, struct aw_device, list_node); + if (local_dev->channel < num) { + ret = aw882xx_dsp_read_te(local_dev, &te_buf[local_dev->channel]); + if (ret) { + aw_dev_err(local_dev->dev, "get re failed!"); + return ret; + } + cnt++; + } else { + aw_dev_err(aw_dev->dev, "channel num[%d] overflow buf num[%d]", + local_dev->channel, num); + } + } + + return cnt; +} + +static int aw_cali_svc_get_devs_st(struct aw_device *aw_dev, int32_t *st_buf, int num) +{ + int ret, cnt = 0; + struct list_head *dev_list = NULL; + struct list_head *pos = NULL; + struct aw_device *local_dev = NULL; + + /*get dev list*/ + ret = aw882xx_dev_get_list_head(&dev_list); + if (ret) { + aw_dev_err(aw_dev->dev, "get dev list failed"); + return ret; + } + + list_for_each(pos, dev_list) { + local_dev = container_of(pos, struct aw_device, list_node); + if (local_dev->channel < num) { + ret = aw882xx_dsp_read_st(local_dev, &st_buf[local_dev->channel << 1], &st_buf[(local_dev->channel << 1) + 1]); + if (ret) { + aw_dev_err(local_dev->dev, "get re failed!"); + return ret; + } + cnt++; + } else { + aw_dev_err(aw_dev->dev, "channel num[%d] overflow buf num[%d]", + local_dev->channel, num); + } + } + return cnt; +} + +static int aw_cali_svc_get_devs_cali_f0(struct aw_device *aw_dev, int32_t *f0_buf, int num) +{ + int ret, cnt = 0; + struct list_head *dev_list = NULL; + struct list_head *pos = NULL; + struct aw_device *local_dev = NULL; + + /*get dev list*/ + ret = aw882xx_dev_get_list_head(&dev_list); + if (ret) { + aw_dev_err(aw_dev->dev, "get dev list failed"); + return ret; + } + + list_for_each(pos, dev_list) { + local_dev = container_of(pos, struct aw_device, list_node); + if (local_dev->channel < num) { + f0_buf[local_dev->channel] = local_dev->cali_desc.cali_f0; + cnt++; + } else { + aw_dev_err(aw_dev->dev, "channel num[%d] overflow buf num[%d]", + local_dev->channel, num); + } + } + + return cnt; +} + +static int aw_cali_svc_get_devs_f0(struct aw_device *aw_dev, int32_t *f0_buf, int num) +{ + int ret, cnt = 0; + struct list_head *dev_list = NULL; + struct list_head *pos = NULL; + struct aw_device *local_dev = NULL; + + /* get dev list */ + ret = aw882xx_dev_get_list_head(&dev_list); + if (ret) { + aw_dev_err(aw_dev->dev, "get dev list failed"); + return ret; + } + + list_for_each(pos, dev_list) { + local_dev = container_of(pos, struct aw_device, list_node); + if (local_dev->channel < num) { + ret = aw882xx_dsp_read_f0(local_dev, &f0_buf[local_dev->channel]); + if (ret) { + aw_dev_err(local_dev->dev, "get re failed!"); + return ret; + } + cnt++; + } else { + aw_dev_err(aw_dev->dev, "channel num[%d] overflow buf num[%d]", + local_dev->channel, num); + } + } + return cnt; +} + +static int aw_cali_svc_get_devs_cali_f0_q(struct aw_device *aw_dev, + int32_t *f0_buf, int32_t *q_buf, int num) +{ + int ret, cnt = 0; + struct list_head *dev_list = NULL; + struct list_head *pos = NULL; + struct aw_device *local_dev = NULL; + + /*get dev list*/ + ret = aw882xx_dev_get_list_head(&dev_list); + if (ret) { + aw_dev_err(aw_dev->dev, "get dev list failed"); + return ret; + } + + list_for_each(pos, dev_list) { + local_dev = container_of(pos, struct aw_device, list_node); + if (local_dev->channel < num) { + f0_buf[local_dev->channel] = local_dev->cali_desc.cali_f0; + q_buf[local_dev->channel] = local_dev->cali_desc.cali_q; + cnt++; + } else { + aw_dev_err(aw_dev->dev, "channel num[%d] overflow buf num[%d]", + local_dev->channel, num); + } + } + return cnt; +} + +static int aw_cali_svc_set_devs_re_str(struct aw_device *aw_dev, const char *re_str) +{ + int ret, cnt = 0; + struct list_head *dev_list, *pos = NULL; + struct aw_device *local_dev = NULL; + int re_data[AW_DEV_CH_MAX] = {0}; + + /* get dev list */ + ret = aw882xx_dev_get_list_head(&dev_list); + if (ret) { + aw_dev_err(aw_dev->dev, "get dev list failed"); + return ret; + } + + ret = sscanf(re_str, "pri_l:%d pri_r:%d sec_l:%d sec_r:%d tert_l:%d tert_r:%d quat_l:%d quat_r:%d", + &re_data[AW_DEV_CH_PRI_L], + &re_data[AW_DEV_CH_PRI_R], + &re_data[AW_DEV_CH_SEC_L], + &re_data[AW_DEV_CH_SEC_R], + &re_data[AW_DEV_CH_TERT_L], + &re_data[AW_DEV_CH_TERT_R], + &re_data[AW_DEV_CH_QUAT_L], + &re_data[AW_DEV_CH_QUAT_R]); + + if (ret <= 0) { + aw_dev_err(aw_dev->dev, "unsupport str[%s]", re_str); + return -EINVAL; + } + + aw_dev_dbg(aw_dev->dev, "pri_l:%d pri_r:%d sec_l:%d sec_r:%d tert_l:%d tert_r:%d quat_l:%d quat_r:%d", + re_data[AW_DEV_CH_PRI_L], + re_data[AW_DEV_CH_PRI_R], + re_data[AW_DEV_CH_SEC_L], + re_data[AW_DEV_CH_SEC_R], + re_data[AW_DEV_CH_TERT_L], + re_data[AW_DEV_CH_TERT_R], + re_data[AW_DEV_CH_QUAT_L], + re_data[AW_DEV_CH_QUAT_R]); + + list_for_each(pos, dev_list) { + local_dev = container_of(pos, struct aw_device, list_node); + if (local_dev->channel < AW_DEV_CH_MAX) { + ret = aw_cali_store_cali_re(local_dev, re_data[local_dev->channel]); + if (ret < 0) + return ret; + cnt++; + } + } + return cnt; + +} + +static int aw_cali_svc_get_cmd_form_str(struct aw_device *aw_dev, const char *buf) +{ + int i; + + for (i = 0; i < CALI_STR_MAX; i++) { + if (!strncmp(cali_str[i], buf, strlen(cali_str[i]))) + break; + + } + + if (i == CALI_STR_MAX) { + aw_dev_err(aw_dev->dev, "supported cmd [%s]!", buf); + return -EINVAL; + } + + aw_dev_info(aw_dev->dev, "find str [%s]", cali_str[i]); + return i; +} + +/*********************************aw_cali_sevice*********************************************************/ + + +/*****************************attr start***************************************************/ +static ssize_t cali_time_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + int ret; + uint32_t time; + struct aw882xx *aw882xx = dev_get_drvdata(dev); + struct aw_device *aw_dev = aw882xx->aw_pa; + + ret = kstrtoint(buf, 0, &time); + if (ret < 0) { + aw_dev_err(aw_dev->dev, "read buf %s failed\n", + buf); + return ret; + } + + if (time < 400) { + aw_dev_err(aw_dev->dev, "time:%d is too short, no set", + time); + return -EINVAL; + } + + g_cali_re_time = time; + aw_dev_dbg(aw_dev->dev, "time:%d", time); + + return count; +} + +static ssize_t cali_time_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + ssize_t len = 0; + + len += snprintf(buf+len, PAGE_SIZE-len, + "time: %d\n", g_cali_re_time); + + return len; +} + +static ssize_t cali_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + int ret; + struct aw882xx *aw882xx = dev_get_drvdata(dev); + struct aw_device *aw_dev = aw882xx->aw_pa; + + ret = aw_cali_svc_get_cmd_form_str(aw_dev, buf); + if (ret < 0) { + aw_dev_err(aw_dev->dev, "supported cmd [%s]!", buf); + return -EPERM; + } + + switch (ret) { + case CALI_STR_CALI_RE_F0: + aw_cali_svc_cali_cmd(aw_dev, AW_CALI_CMD_RE_F0, + is_single_cali, CALI_OPS_HMUTE|CALI_OPS_NOISE); + return count; + case CALI_STR_CALI_RE: + aw_cali_svc_cali_cmd(aw_dev, AW_CALI_CMD_RE, + is_single_cali, CALI_OPS_HMUTE); + return count; + case CALI_STR_CALI_F0: + aw_cali_svc_cali_cmd(aw_dev, AW_CALI_CMD_F0, + is_single_cali, CALI_OPS_NOISE); + return count; + default: + aw_dev_err(aw_dev->dev, "supported cmd [%s]!", buf); + return -EPERM; + } +} + +static ssize_t cali_re_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + int ret; + struct aw882xx *aw882xx = dev_get_drvdata(dev); + struct aw_device *aw_dev = aw882xx->aw_pa; + int data = 0; + + if (is_single_cali) { + ret = kstrtoint(buf, 0, &data); + if (ret < 0) { + aw_dev_err(aw882xx->dev, " read buf %s failed", buf); + return ret; + } + ret = aw_cali_store_cali_re(aw_dev, data); + if (ret < 0) { + aw_dev_err(aw_dev->dev, "set re %d failed", data); + return -EPERM; + } + } else { + ret = aw_cali_svc_set_devs_re_str(aw_dev, buf); + if (ret <= 0) { + aw_dev_err(aw_dev->dev, "set re str %s failed", buf); + return -EPERM; + } + } + + return count; +} + +static ssize_t cali_re_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int ret, i; + struct aw882xx *aw882xx = dev_get_drvdata(dev); + struct aw_device *aw_dev = aw882xx->aw_pa; + ssize_t len = 0; + int32_t cali_re[AW_DEV_CH_MAX] = {0}; + + ret = aw_cali_svc_cali_cmd(aw_dev, AW_CALI_CMD_RE, is_single_cali, CALI_OPS_HMUTE); + if (ret < 0) { + len += snprintf(buf+len, PAGE_SIZE-len, "cali Re cmd failed\n"); + return len; + } + + if (is_single_cali) { + len += snprintf(buf+len, PAGE_SIZE-len, "%d\n", aw_dev->cali_desc.cali_re); + } else { + ret = aw_cali_svc_get_devs_cali_re(aw_dev, cali_re, AW_DEV_CH_MAX); + if (ret <= 0) { + aw_dev_err(aw_dev->dev, "get re failed "); + len += snprintf(buf+len, PAGE_SIZE-len, "get re failed\n"); + } else { + for (i = 0; i < ret; i++) + len += snprintf(buf+len, PAGE_SIZE-len, "%s:%d mOhms ", ch_name[i], cali_re[i]); + len += snprintf(buf+len, PAGE_SIZE-len, "\n"); + } + } + + return len; +} + +static ssize_t cali_f0_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct aw882xx *aw882xx = dev_get_drvdata(dev); + struct aw_device *aw_dev = aw882xx->aw_pa; + + aw_cali_svc_cali_cmd(aw_dev, AW_CALI_CMD_F0, is_single_cali, CALI_OPS_NOISE); + return count; +} + +static ssize_t cali_f0_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int ret, i; + struct aw882xx *aw882xx = dev_get_drvdata(dev); + struct aw_device *aw_dev = aw882xx->aw_pa; + ssize_t len = 0; + int32_t cali_f0[AW_DEV_CH_MAX] = {0}; + + ret = aw_cali_svc_cali_cmd(aw_dev, AW_CALI_CMD_F0, is_single_cali, CALI_OPS_NOISE); + if (ret < 0) { + len += snprintf(buf+len, PAGE_SIZE-len, "cali f0 cmd failed\n"); + return len; + } + + if (is_single_cali) { + len += snprintf(buf+len, PAGE_SIZE-len, "%d\n", aw_dev->cali_desc.cali_f0); + } else { + ret = aw_cali_svc_get_devs_cali_f0(aw_dev, cali_f0, AW_DEV_CH_MAX); + if (ret <= 0) { + aw_dev_err(aw_dev->dev, "get f0 failed "); + len += snprintf(buf+len, PAGE_SIZE-len, "get f0 failed\n"); + } else { + for (i = 0; i < ret; i++) + len += snprintf(buf+len, PAGE_SIZE-len, "%s:%d ", ch_name[i], cali_f0[i]); + len += snprintf(buf+len, PAGE_SIZE-len, "\n"); + } + } + + return len; +} + +static ssize_t re_show_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int ret, i; + struct aw882xx *aw882xx = dev_get_drvdata(dev); + struct aw_device *aw_dev = aw882xx->aw_pa; + ssize_t len = 0; + int32_t cali_re[AW_DEV_CH_MAX] = {0}; + + if (is_single_cali) { + len += snprintf(buf+len, PAGE_SIZE-len, "%d\n", aw_dev->cali_desc.cali_re); + } else { + ret = aw_cali_svc_get_devs_cali_re(aw_dev, cali_re, AW_DEV_CH_MAX); + if (ret <= 0) { + aw_dev_err(aw_dev->dev, "get re failed "); + } else { + for (i = 0; i < ret; i++) + len += snprintf(buf+len, PAGE_SIZE-len, "%s:%d mOhms ", ch_name[i], cali_re[i]); + } + len += snprintf(buf+len, PAGE_SIZE-len, "\n"); + } + + return len; +} + +static ssize_t f0_show_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int ret, i; + struct aw882xx *aw882xx = dev_get_drvdata(dev); + struct aw_device *aw_dev = aw882xx->aw_pa; + ssize_t len = 0; + int32_t cali_f0[AW_DEV_CH_MAX] = {0}; + + if (is_single_cali) { + len += snprintf(buf+len, PAGE_SIZE-len, "%d\n", aw_dev->cali_desc.cali_f0); + } else { + ret = aw_cali_svc_get_devs_cali_f0(aw_dev, cali_f0, AW_DEV_CH_MAX); + if (ret <= 0) { + aw_dev_err(aw_dev->dev, "get f0 failed"); + } else { + for (i = 0; i < ret; i++) + len += snprintf(buf+len, PAGE_SIZE-len, "%s:%d", ch_name[i], cali_f0[i]); + len += snprintf(buf+len, PAGE_SIZE-len, "\n"); + } + } + + return len; +} + +static ssize_t re_range_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + ssize_t len = 0; + struct aw882xx *aw882xx = dev_get_drvdata(dev); + struct aw_device *aw_dev = aw882xx->aw_pa; + uint32_t range_buf[RE_RANGE_NUM] = { 0 }; + + aw_cali_svc_get_dev_re_range(aw_dev, range_buf); + + len += snprintf(buf + len, PAGE_SIZE - len, + "re_min value: [%d] mOhms\n", range_buf[RE_MIN_FLAG]); + len += snprintf(buf + len, PAGE_SIZE - len, + "re_max value: [%d] mOhms\n", range_buf[RE_MAX_FLAG]); + + return len; +} + +/*set cali time*/ +static DEVICE_ATTR_RW(cali_time); +/*start cali*/ +static DEVICE_ATTR_WO(cali); +/*cali re*/ +static DEVICE_ATTR_RW(cali_re); +/*cali_f0*/ +static DEVICE_ATTR_RW(cali_f0); +/*show cali_re*/ +static DEVICE_ATTR_RO(re_show); +/*show cali_f0*/ +static DEVICE_ATTR_RO(f0_show); +/*show re_range*/ +static DEVICE_ATTR_RO(re_range); + +static struct attribute *aw_cali_attr[] = { + &dev_attr_cali_time.attr, + &dev_attr_cali.attr, + &dev_attr_cali_re.attr, + &dev_attr_cali_f0.attr, + &dev_attr_re_show.attr, + &dev_attr_f0_show.attr, + &dev_attr_re_range.attr, + NULL +}; + +static struct attribute_group aw_cali_attr_group = { + .attrs = aw_cali_attr +}; + +static void aw_cali_attr_init(struct aw_device *aw_dev) +{ + int ret; + + aw_dev_info(aw_dev->dev, "enter"); + + ret = sysfs_create_group(&aw_dev->dev->kobj, &aw_cali_attr_group); + if (ret < 0) + aw_dev_info(aw_dev->dev, "error creating sysfs cali attr files"); +} + +static void aw_cali_attr_deinit(struct aw_device *aw_dev) +{ + sysfs_remove_group(&aw_dev->dev->kobj, &aw_cali_attr_group); + aw_dev_info(aw_dev->dev, "attr files deinit"); +} + +/*****************************attr end***************************************************/ + +/*****************************class node******************************************************/ +static ssize_t aw_cali_class_time_show(struct class *class, struct class_attribute *attr, char *buf) +{ + ssize_t len = 0; + + len += snprintf(buf+len, PAGE_SIZE-len, + "time: %d\n", g_cali_re_time); + + return len; +} + +static ssize_t aw_cali_class_time_store(struct class *class, + struct class_attribute *attr, const char *buf, size_t len) +{ + int ret; + uint32_t time; + + ret = kstrtoint(buf, 0, &time); + if (ret < 0) { + aw_pr_err("read buf %s failed", buf); + return ret; + } + + if (time < 400) { + aw_pr_err("time:%d is too short, no set", time); + return -EINVAL; + } + + g_cali_re_time = time; + aw_pr_dbg("time:%d", time); + + return len; +} + +static ssize_t aw_cali_class_cali_re_show(struct class *class, struct class_attribute *attr, char *buf) +{ + int ret, i; + struct list_head *dev_list = NULL; + struct aw_device *local_dev = NULL; + ssize_t len = 0; + int32_t cali_re[AW_DEV_CH_MAX] = {0}; + + ret = aw882xx_dev_get_list_head(&dev_list); + if (ret) { + aw_pr_err("get dev list failed"); + return ret; + } + + local_dev = list_first_entry(dev_list, struct aw_device, list_node); + + ret = aw_cali_svc_cali_cmd(local_dev, AW_CALI_CMD_RE, false, CALI_OPS_HMUTE); + if (ret < 0) { + len += snprintf(buf+len, PAGE_SIZE-len, "cali Re cmd failed\n"); + return len; + } + + ret = aw_cali_svc_get_devs_cali_re(local_dev, cali_re, AW_DEV_CH_MAX); + if (ret <= 0) { + aw_dev_err(local_dev->dev, "get re failed"); + len += snprintf(buf+len, PAGE_SIZE-len, "get re failed\n"); + } else { + for (i = 0; i < ret; i++) + len += snprintf(buf+len, PAGE_SIZE-len, "%s:%d mOhms ", ch_name[i], cali_re[i]); + len += snprintf(buf+len, PAGE_SIZE-len, "\n"); + } + + return len; +} + +static ssize_t aw_cali_class_cali_re_store(struct class *class, + struct class_attribute *attr, const char *buf, size_t len) +{ + int ret; + struct list_head *dev_list = NULL; + struct aw_device *local_dev = NULL; + + ret = aw882xx_dev_get_list_head(&dev_list); + if (ret) { + aw_pr_err("get dev list failed"); + return ret; + } + + local_dev = list_first_entry(dev_list, struct aw_device, list_node); + + ret = aw_cali_svc_set_devs_re_str(local_dev, buf); + if (ret <= 0) { + aw_dev_err(local_dev->dev, "set re str %s failed", buf); + return -EPERM; + } + + return len; +} + +static ssize_t aw_cali_class_cali_f0_show(struct class *class, struct class_attribute *attr, char *buf) +{ + int ret, i; + struct list_head *dev_list = NULL; + struct aw_device *local_dev = NULL; + ssize_t len = 0; + int32_t cali_f0[AW_DEV_CH_MAX] = {0}; + + ret = aw882xx_dev_get_list_head(&dev_list); + if (ret) { + aw_pr_err("get dev list failed"); + return ret; + } + + local_dev = list_first_entry(dev_list, struct aw_device, list_node); + + ret = aw_cali_svc_cali_cmd(local_dev, AW_CALI_CMD_F0, false, CALI_OPS_NOISE); + if (ret < 0) { + len += snprintf(buf+len, PAGE_SIZE-len, "cali f0 cmd failed\n"); + return len; + } + + ret = aw_cali_svc_get_devs_cali_f0(local_dev, cali_f0, AW_DEV_CH_MAX); + if (ret <= 0) { + aw_dev_err(local_dev->dev, "get f0 failed "); + len += snprintf(buf+len, PAGE_SIZE-len, "get f0 failed\n"); + } else { + for (i = 0; i < ret; i++) + len += snprintf(buf+len, PAGE_SIZE-len, "%s:%d ", ch_name[i], cali_f0[i]); + len += snprintf(buf+len, PAGE_SIZE-len, "\n"); + } + + return len; +} + +static ssize_t aw_cali_class_cali_f0_store(struct class *class, + struct class_attribute *attr, const char *buf, size_t len) +{ + int ret; + struct list_head *dev_list = NULL; + struct aw_device *local_dev = NULL; + + ret = aw882xx_dev_get_list_head(&dev_list); + if (ret) { + aw_pr_err("get dev list failed"); + return ret; + } + + local_dev = list_first_entry(dev_list, struct aw_device, list_node); + + aw_cali_svc_cali_cmd(local_dev, AW_CALI_CMD_F0, false, CALI_OPS_NOISE); + + return len; +} + +static ssize_t aw_cali_class_f0_show(struct class *class, struct class_attribute *attr, char *buf) +{ + int ret, i; + struct list_head *dev_list = NULL; + struct aw_device *local_dev = NULL; + ssize_t len = 0; + int32_t cali_f0[AW_DEV_CH_MAX] = {0}; + + ret = aw882xx_dev_get_list_head(&dev_list); + if (ret) { + aw_pr_err("get dev list failed"); + return ret; + } + + local_dev = list_first_entry(dev_list, struct aw_device, list_node); + + ret = aw_cali_svc_get_devs_cali_f0(local_dev, cali_f0, AW_DEV_CH_MAX); + if (ret <= 0) { + aw_dev_err(local_dev->dev, "get re failed"); + } else { + for (i = 0; i < ret; i++) + len += snprintf(buf+len, PAGE_SIZE-len, "%s:%d", ch_name[i], cali_f0[i]); + len += snprintf(buf+len, PAGE_SIZE-len, "\n"); + } + + return len; +} + +static ssize_t aw_cali_class_re_show(struct class *class, struct class_attribute *attr, char *buf) +{ + int ret, i; + struct list_head *dev_list = NULL; + struct aw_device *local_dev = NULL; + ssize_t len = 0; + int32_t cali_re[AW_DEV_CH_MAX] = {0}; + + ret = aw882xx_dev_get_list_head(&dev_list); + if (ret) { + aw_pr_err("get dev list failed"); + return ret; + } + + local_dev = list_first_entry(dev_list, struct aw_device, list_node); + + ret = aw_cali_svc_get_devs_cali_re(local_dev, cali_re, AW_DEV_CH_MAX); + if (ret <= 0) { + aw_dev_err(local_dev->dev, "get re failed"); + } else { + for (i = 0; i < ret; i++) + len += snprintf(buf+len, PAGE_SIZE-len, "%s:%d mOhms", ch_name[i], cali_re[i]); + len += snprintf(buf+len, PAGE_SIZE-len, "\n"); + } + + return len; +} + +static ssize_t aw_class_re_range_show(struct class *class, struct class_attribute *attr, char *buf) +{ + int ret, i; + ssize_t len = 0; + struct list_head *dev_list = NULL; + struct aw_device *local_dev = NULL; + uint32_t re_value[AW_DEV_RE_RANGE] = { 0 }; + + aw_pr_info("enter"); + + ret = aw882xx_dev_get_list_head(&dev_list); + if (ret < 0) { + aw_pr_err("get dev list failed"); + return ret; + } + + local_dev = list_first_entry(dev_list, struct aw_device, list_node); + ret = aw_cali_svc_get_devs_re_range(local_dev, re_value, AW_DEV_CH_MAX); + if (ret <= 0) { + aw_dev_err(local_dev->dev, "get re range failed"); + return -EINVAL; + } + + for (i = 0; i < ret; i++) { + len += snprintf(buf+len, PAGE_SIZE-len, "%s:re_min:%d mOhms re_max:%d mOhms ", + ch_name[i], re_value[RE_MIN_FLAG + i * RE_RANGE_NUM], + re_value[RE_MAX_FLAG + i * RE_RANGE_NUM]); + } + len += snprintf(buf+len, PAGE_SIZE-len, "\n"); + + return len; +} + +static struct class_attribute class_attr_cali_time = + __ATTR(cali_time, 0644, + aw_cali_class_time_show, aw_cali_class_time_store); + +static struct class_attribute class_attr_re25_calib = + __ATTR(re25_calib, 0644, + aw_cali_class_cali_re_show, aw_cali_class_cali_re_store); + +static struct class_attribute class_attr_f0_calib = + __ATTR(f0_calib, 0644, + aw_cali_class_cali_f0_show, aw_cali_class_cali_f0_store); + +static struct class_attribute class_attr_re_show = + __ATTR(re_show, 0444, + aw_cali_class_re_show, NULL); + +static struct class_attribute class_attr_f0_show = + __ATTR(f0_show, 0444, + aw_cali_class_f0_show, NULL); + +static struct class_attribute class_att_re_range = + __ATTR(re_range, 0444, + aw_class_re_range_show, NULL); + +static struct class aw_cali_class = { + .name = "smartpa", + .owner = THIS_MODULE, +}; + +static void aw_cali_class_attr_init(struct aw_device *aw_dev) +{ + int ret; + + if (aw_dev->channel != 0) { + aw_dev_info(aw_dev->dev, "class node already register"); + return; + } + + ret = class_register(&aw_cali_class); + if (ret < 0) { + aw_dev_info(aw_dev->dev, "error creating class node"); + return; + } + ret = class_create_file(&aw_cali_class, &class_attr_re25_calib); + if (ret) + aw_dev_info(aw_dev->dev, "creat class_attr_re25_calib fail"); + + ret = class_create_file(&aw_cali_class, &class_attr_f0_calib); + if (ret) + aw_dev_info(aw_dev->dev, "creat class_attr_re25_calib fail"); + + ret = class_create_file(&aw_cali_class, &class_attr_cali_time); + if (ret) + aw_dev_info(aw_dev->dev, "creat class_attr_cali_time fail"); + + ret = class_create_file(&aw_cali_class, &class_attr_re_show); + if (ret) + aw_dev_info(aw_dev->dev, "creat class_attr_re_show fail"); + + ret = class_create_file(&aw_cali_class, &class_attr_f0_show); + if (ret) + aw_dev_info(aw_dev->dev, "creat class_attr_f0_show fail"); + + ret = class_create_file(&aw_cali_class, &class_att_re_range); + if (ret) + aw_dev_err(aw_dev->dev, "creat class_att_re_range fail"); +} + +static void aw_cali_class_attr_deinit(struct aw_device *aw_dev) +{ + class_remove_file(&aw_cali_class, &class_att_re_range); + class_remove_file(&aw_cali_class, &class_attr_re25_calib); + class_remove_file(&aw_cali_class, &class_attr_f0_calib); + class_remove_file(&aw_cali_class, &class_attr_cali_time); + class_remove_file(&aw_cali_class, &class_attr_re_show); + class_remove_file(&aw_cali_class, &class_attr_f0_show); + + class_unregister(&aw_cali_class); + aw_dev_info(aw_dev->dev, "unregister class node"); +} +/*****************************class node******************************************************/ + +/*****************************misc node******************************************************/ +static int aw_cali_misc_open(struct inode *inode, struct file *file) +{ + int ret; + struct list_head *dev_list = NULL; + struct list_head *pos = NULL; + struct aw_device *local_dev = NULL; + + ret = aw882xx_dev_get_list_head(&dev_list); + if (ret) { + aw_pr_err("get dev list failed"); + file->private_data = NULL; + return -EINVAL; + } + + /* find select dev */ + list_for_each(pos, dev_list) { + local_dev = container_of(pos, struct aw_device, list_node); + if (local_dev->channel == g_dev_select) + break; + + } + + if (local_dev == NULL) { + aw_pr_err("can't find dev num %d", g_dev_select); + return -EINVAL; + } + + /* cannot find sel dev, use list first dev */ + if (local_dev->channel != g_dev_select) { + local_dev = list_first_entry(dev_list, struct aw_device, list_node); + aw_dev_dbg(local_dev->dev, "can not find dev num %d, use default", g_dev_select); + } + + file->private_data = (void *)local_dev; + + aw_dev_dbg(local_dev->dev, "misc open success"); + return 0; +} + +static int aw_cali_misc_release(struct inode *inode, struct file *file) +{ + file->private_data = (void *)NULL; + + aw_pr_dbg("misc release success"); + return 0; +} + +static int aw_cali_misc_params_ptr(struct aw_device *aw_dev, struct ptr_params_data *p_params) +{ + int ret = 0; + char *p_data = NULL; + + if (p_params->data == NULL || (!p_params->len)) { + aw_dev_err(aw_dev->dev, "p_params error"); + ret = -EFAULT; + return ret; + } + + p_data = kzalloc(p_params->len, GFP_KERNEL); + if (p_data == NULL) { + ret = -ENOMEM; + goto exit; + } + + if (copy_from_user(p_data, + (void __user *)p_params->data, + p_params->len)) { + ret = -EFAULT; + goto exit; + } + + ret = aw882xx_dsp_write_params(aw_dev, p_data, p_params->len); + if (ret < 0) { + aw_dev_err(aw_dev->dev, "write params failed "); + ret = -EFAULT; + goto exit; + } + +exit: + if (p_data != NULL) { + kfree(p_data); + p_data = NULL; + } + + return ret; +} + +static int aw_cali_misc_ops_write(struct aw_device *aw_dev, + unsigned int cmd, unsigned long arg) +{ + int ret = 0; + unsigned int data_len = _IOC_SIZE(cmd); + char *data_ptr = NULL; + int32_t data = 0; + + data_ptr = kzalloc(data_len, GFP_KERNEL); + if (!data_ptr) + return -ENOMEM; + + + if (copy_from_user(data_ptr, (void __user *)arg, data_len)) { + ret = -EFAULT; + goto exit; + } + + switch (cmd) { + case AW_IOCTL_ENABLE_CALI: { + if (aw_dev->cali_desc.cali_check_st) { + if (data_ptr[0]) + aw_cali_svc_run_mute(aw_dev, CALI_RESULT_NORMAL); + else + aw_cali_svc_run_mute(aw_dev, aw_dev->cali_desc.cali_result); + } + aw_cali_svc_set_cali_status(aw_dev, data_ptr[0]); + } break; + case AW_IOCTL_SET_CALI_CFG: { + ret = aw882xx_dsp_write_cali_cfg(aw_dev, data_ptr, data_len); + } break; + case AW_IOCTL_SET_NOISE: { + data = *(int32_t *)data_ptr; + ret = aw882xx_dsp_noise_en(aw_dev, data); + } break; + case AW_IOCTL_SET_VMAX: { + ret = aw882xx_dsp_write_vmax(aw_dev, data_ptr, data_len); + } break; + case AW_IOCTL_SET_PARAM: { + ret = aw882xx_dsp_write_params(aw_dev, data_ptr, data_len); + } break; + case AW_IOCTL_SET_PTR_PARAM_NUM: { + ret = aw_cali_misc_params_ptr(aw_dev, (struct ptr_params_data *)data_ptr); + } break; + case AW_IOCTL_SET_CALI_RE: { + ret = aw_cali_store_cali_re(aw_dev, *((int32_t *)data_ptr)); + /*ret = aw882xx_dsp_write_cali_re(aw_dev, *(int32_t *)data_ptr);*/ + } break; + case AW_IOCTL_SET_DSP_HMUTE: { + data = *(int32_t *)data_ptr; + ret = aw882xx_dsp_hmute_en(aw_dev, data); + } break; + case AW_IOCTL_SET_CALI_CFG_FLAG: { + data = *(int32_t *)data_ptr; + /*aw_cali_svc_set_cali_status(aw_dev, data);*/ + ret = aw882xx_dsp_cali_en(aw_dev, data); + } break; + default:{ + aw_dev_err(aw_dev->dev, "unsupported cmd %d", cmd); + ret = -EINVAL; + } break; + } + +exit: + kfree(data_ptr); + return ret; +} + +static int aw_cali_misc_ops_read(struct aw_device *aw_dev, + unsigned int cmd, unsigned long arg) +{ + int ret = 0; + int16_t data_len = _IOC_SIZE(cmd); + char *data_ptr = NULL; + int32_t *data_32_ptr = NULL; + + data_ptr = kzalloc(data_len, GFP_KERNEL); + if (!data_ptr) + return -ENOMEM; + + + switch (cmd) { + case AW_IOCTL_GET_CALI_CFG: { + ret = aw882xx_dsp_read_cali_cfg(aw_dev, data_ptr, data_len); + } break; + case AW_IOCTL_GET_CALI_DATA: { + ret = aw882xx_dsp_read_cali_data(aw_dev, data_ptr, data_len); + } break; + case AW_IOCTL_GET_F0: { + data_32_ptr = (int32_t *)data_ptr; + ret = aw882xx_dsp_read_f0(aw_dev, data_32_ptr); + } break; + case AW_IOCTL_GET_CALI_RE: { + data_32_ptr = (int32_t *)data_ptr; + ret = aw882xx_dsp_read_cali_re(aw_dev, data_32_ptr); + } break; + case AW_IOCTL_GET_VMAX: { + ret = aw882xx_dsp_read_vmax(aw_dev, data_ptr, data_len); + } break; + case AW_IOCTL_GET_F0_Q: { + data_32_ptr = (int32_t *)data_ptr; + ret = aw882xx_dsp_read_f0_q(aw_dev, &data_32_ptr[0], &data_32_ptr[1]); + } break; + case AW_IOCTL_GET_RE_RANGE: { + data_32_ptr = (uint32_t *)data_ptr; + ret = aw_cali_svc_get_dev_re_range(aw_dev, data_32_ptr); + } break; + default:{ + aw_dev_err(aw_dev->dev, "unsupported cmd %d", cmd); + ret = -EINVAL; + } break; + } + + if (copy_to_user((void __user *)arg, + data_ptr, data_len)) { + ret = -EFAULT; + } + + kfree(data_ptr); + return ret; +} + +static int aw_cali_misc_read_dsp(struct aw_device *aw_dev, aw_ioctl_msg_t *msg) +{ + int ret; + char __user *user_data = (char __user *)msg->data_buf; + uint32_t dsp_msg_id = (uint32_t)msg->opcode_id; + int data_len = msg->data_len; + char *data_ptr = NULL; + + data_ptr = kzalloc(data_len, GFP_KERNEL); + if (!data_ptr) + return -ENOMEM; + + + ret = aw882xx_dsp_read_dsp_msg(aw_dev, dsp_msg_id, data_ptr, data_len); + if (ret) { + aw_dev_err(aw_dev->dev, " write failed"); + goto exit; + } + + if (copy_to_user((void __user *)user_data, + data_ptr, data_len)) + ret = -EFAULT; +exit: + kfree(data_ptr); + return ret; +} + +static int aw_cali_misc_write_dsp(struct aw_device *aw_dev, aw_ioctl_msg_t *msg) +{ + int ret; + char __user *user_data = (char __user *)msg->data_buf; + uint32_t dsp_msg_id = (uint32_t)msg->opcode_id; + int data_len = msg->data_len; + char *data_ptr = NULL; + + data_ptr = kzalloc(data_len, GFP_KERNEL); + if (!data_ptr) + return -ENOMEM; + + + if (copy_from_user(data_ptr, (void __user *)user_data, data_len)) { + aw_dev_err(aw_dev->dev, "copy data failed"); + ret = -EFAULT; + goto exit; + } + + ret = aw882xx_dsp_write_dsp_msg(aw_dev, dsp_msg_id, data_ptr, data_len); + if (ret) + aw_dev_err(aw_dev->dev, "write failed"); + +exit: + kfree(data_ptr); + return ret; +} + + +static int aw_cali_misc_ops(struct aw_device *aw_dev, + unsigned int cmd, unsigned long arg); +static int aw_cali_misc_ops_msg(struct aw_device *aw_dev, unsigned long arg) +{ + aw_ioctl_msg_t ioctl_msg; + + if (copy_from_user(&ioctl_msg, (void __user *)arg, sizeof(aw_ioctl_msg_t))) + return -EFAULT; + + if (ioctl_msg.version != AW_IOCTL_MSG_VERSION) { + aw_dev_err(aw_dev->dev, "unsupported msg version %d", ioctl_msg.version); + return -EINVAL; + } + + switch (ioctl_msg.type) { + case AW_IOCTL_MSG_RD_DSP: + return aw_cali_misc_read_dsp(aw_dev, &ioctl_msg); + case AW_IOCTL_MSG_WR_DSP: + return aw_cali_misc_write_dsp(aw_dev, &ioctl_msg); + case AW_IOCTL_MSG_IOCTL: + return aw_cali_misc_ops(aw_dev, ioctl_msg.opcode_id, (unsigned long)ioctl_msg.data_buf); + default: + aw_dev_err(aw_dev->dev, "unsupported msg type %d", ioctl_msg.type); + return -EINVAL; + } +} + +static int aw_cali_misc_ops(struct aw_device *aw_dev, + unsigned int cmd, unsigned long arg) +{ + int ret = 0; + + switch (cmd) { + case AW_IOCTL_ENABLE_CALI: + case AW_IOCTL_SET_CALI_CFG: + case AW_IOCTL_SET_NOISE: + case AW_IOCTL_SET_VMAX: + case AW_IOCTL_SET_PARAM: + case AW_IOCTL_SET_PTR_PARAM_NUM: + case AW_IOCTL_SET_CALI_RE: + case AW_IOCTL_SET_DSP_HMUTE: + case AW_IOCTL_SET_CALI_CFG_FLAG: + ret = aw_cali_misc_ops_write(aw_dev, cmd, arg); + break; + case AW_IOCTL_GET_CALI_CFG: + case AW_IOCTL_GET_CALI_DATA: + case AW_IOCTL_GET_F0: + case AW_IOCTL_GET_CALI_RE: + case AW_IOCTL_GET_VMAX: + case AW_IOCTL_GET_F0_Q: + case AW_IOCTL_GET_RE_RANGE: + ret = aw_cali_misc_ops_read(aw_dev, cmd, arg); + break; + case AW_IOCTL_MSG: { + ret = aw_cali_misc_ops_msg(aw_dev, arg); + } break; + default: + aw_dev_err(aw_dev->dev, "unsupported cmd %d", cmd); + ret = -EINVAL; + break; + } + + return ret; +} + +static long aw_cali_misc_unlocked_ioctl(struct file *file, + unsigned int cmd, unsigned long arg) +{ + int ret = 0; + struct aw_device *aw_dev = NULL; + + if (((_IOC_TYPE(cmd)) != (AW_IOCTL_MAGIC))) { + aw_pr_err("cmd magic err"); + return -EINVAL; + } + aw_dev = (struct aw_device *)file->private_data; + ret = aw_cali_misc_ops(aw_dev, cmd, arg); + if (ret) + return -EINVAL; + + return 0; +} + +#ifdef CONFIG_COMPAT +static long aw_cali_misc_compat_ioctl(struct file *file, + unsigned int cmd, unsigned long arg) +{ + int ret = 0; + struct aw_device *aw_dev = NULL; + + if (((_IOC_TYPE(cmd)) != (AW_IOCTL_MAGIC))) { + aw_pr_err("cmd magic err"); + return -EINVAL; + } + aw_dev = (struct aw_device *)file->private_data; + ret = aw_cali_misc_ops(aw_dev, cmd, arg); + if (ret) + return -EINVAL; + + return 0; +} +#endif + +static ssize_t aw_cali_misc_read(struct file *filp, char __user *buf, size_t size, loff_t *pos) +{ + int i, ret; + int len = 0; + struct aw_device *aw_dev = (struct aw_device *)filp->private_data; + char local_buf[256] = { 0 }; + unsigned int dev_num; + int32_t temp_data[AW_DEV_CH_MAX << 1] = {0}; + int32_t temp_data1[AW_DEV_CH_MAX << 1] = {0}; + uint32_t re_value[AW_DEV_RE_RANGE] = { 0 }; + + aw_dev_info(aw_dev->dev, "enter"); + + if (*pos) { + *pos = 0; + return 0; + } + + switch (g_msic_wr_flag) { + case CALI_STR_SHOW_RE: { + ret = aw_cali_svc_get_devs_cali_re(aw_dev, temp_data, AW_DEV_CH_MAX); + if (ret <= 0) { + aw_dev_err(aw_dev->dev, "get cali_re failed"); + return ret; + } + for (i = 0; i < ret; i++) + len += snprintf(local_buf+len, sizeof(local_buf)-len, + "%s:%d mOhms ", ch_name[i], temp_data[i]); + + len += snprintf(local_buf+len, sizeof(local_buf)-len, "\n"); + + } break; + case CALI_STR_SHOW_CALI_F0: { + ret = aw_cali_svc_get_devs_cali_f0(aw_dev, temp_data, AW_DEV_CH_MAX); + if (ret <= 0) { + aw_dev_err(aw_dev->dev, "get cali f0 failed"); + return ret; + } + for (i = 0; i < ret; i++) + len += snprintf(local_buf+len, sizeof(local_buf)-len, + "%s:%d ", ch_name[i], temp_data[i]); + + len += snprintf(local_buf+len, sizeof(local_buf)-len, "\n"); + + } break; + case CALI_STR_SHOW_R0: { + ret = aw_cali_svc_get_devs_r0(aw_dev, temp_data, AW_DEV_CH_MAX); + if (ret <= 0) { + aw_dev_err(aw_dev->dev, "get r0 failed"); + return ret; + } + for (i = 0; i < ret; i++) + len += snprintf(local_buf+len, sizeof(local_buf)-len, + "%s:%d mOhms ", ch_name[i], temp_data[i]); + len += snprintf(local_buf+len, sizeof(local_buf)-len, "\n"); + + } break; + case CALI_STR_SHOW_TE: { + ret = aw_cali_svc_get_devs_te(aw_dev, temp_data, AW_DEV_CH_MAX); + if (ret <= 0) { + aw_dev_err(aw_dev->dev, "get te failed"); + return ret; + } + for (i = 0; i < ret; i++) + len += snprintf(local_buf+len, sizeof(local_buf)-len, + "%s:%d ", ch_name[i], temp_data[i]); + len += snprintf(local_buf+len, sizeof(local_buf)-len, "\n"); + + } break; + case CALI_STR_SHOW_ST: { + ret = aw_cali_svc_get_devs_st(aw_dev, temp_data, AW_DEV_CH_MAX); + if (ret <= 0) { + aw_dev_err(aw_dev->dev, "get spkr status failed"); + return ret; + } + for (i = 0; i < ret; i++) { + len += snprintf(local_buf+len, sizeof(local_buf)-len, + "%s:R0 %d mOhms Te %d ", + ch_name[i], temp_data[i << 1], temp_data[(i << 1) + 1]); + } + len += snprintf(local_buf+len, sizeof(local_buf)-len, "\n"); + + } break; + case CALI_STR_SHOW_F0: { + ret = aw_cali_svc_get_devs_f0(aw_dev, temp_data, AW_DEV_CH_MAX); + if (ret <= 0) { + aw_dev_err(aw_dev->dev, "get f0 failed"); + return ret; + } + for (i = 0; i < ret; i++) + len += snprintf(local_buf+len, sizeof(local_buf)-len, + "%s:%d ", ch_name[i], temp_data[i]); + + len += snprintf(local_buf+len, sizeof(local_buf) - len, "\n"); + + } break; + case CALI_STR_VER: { + if (aw_dev->ops.aw_get_version) { + len = aw_dev->ops.aw_get_version(local_buf, sizeof(local_buf)); + if (len < 0) { + aw_dev_err(aw_dev->dev, "get version failed"); + return -EINVAL; + } + len += snprintf(local_buf+len, sizeof(local_buf) - len, "\n"); + } else { + aw_dev_err(aw_dev->dev, "get version is NULL"); + return -EINVAL; + } + } break; + case CALI_STR_DEV_NUM: { + if (aw_dev->ops.aw_get_dev_num) { + dev_num = aw_dev->ops.aw_get_dev_num(); + len += snprintf(local_buf + len, sizeof(local_buf) - len, "dev_num:%d\n", dev_num); + } else { + aw_dev_err(aw_dev->dev, "get dev num is NULL"); + return -EINVAL; + } + break; + } + case CALI_STR_SHOW_F0_Q: { + ret = aw_cali_svc_get_devs_cali_f0_q(aw_dev, + temp_data, temp_data1, AW_DEV_CH_MAX); + if (ret <= 0) { + aw_dev_err(aw_dev->dev, "get q f0 failed"); + return ret; + } + for (i = 0; i < ret; i++) + len += snprintf(local_buf + len, sizeof(local_buf)-len, + "%s:f0:%d q:%d", ch_name[i], temp_data[i], temp_data1[i]); + + len += snprintf(local_buf+len, sizeof(local_buf) - len, "\n"); + + } break; + case CALI_STR_SHOW_RE_RANGE: { + ret = aw_cali_svc_get_devs_re_range(aw_dev, re_value, AW_DEV_CH_MAX); + if (ret <= 0) { + aw_dev_err(aw_dev->dev, "get re range failed"); + return -EINVAL; + } + for (i = 0; i < ret; i++) + len += snprintf(local_buf + len, sizeof(local_buf) - len, + "%s:re_min:%d re_max:%d ", + ch_name[i], re_value[RE_MIN_FLAG + i * RE_RANGE_NUM], + re_value[RE_MAX_FLAG + i * RE_RANGE_NUM]); + + len += snprintf(local_buf + len, sizeof(local_buf) - len, "\n"); + + } break; + default: { + if (g_msic_wr_flag == CALI_STR_NONE) { + aw_dev_info(aw_dev->dev, "please write cmd first"); + return -EINVAL; + } + aw_dev_err(aw_dev->dev, "unsupported flag [%d]", g_msic_wr_flag); + g_msic_wr_flag = CALI_STR_NONE; + return -EINVAL; + + } break; + } + + if (copy_to_user((void __user *)buf, local_buf, len)) { + aw_dev_err(aw_dev->dev, "copy_to_user error"); + g_msic_wr_flag = CALI_STR_NONE; + return -EFAULT; + } + + g_msic_wr_flag = CALI_STR_NONE; + *pos += len; + return len; +} + +static int aw_cali_misc_switch_dev(struct file *filp, struct aw_device *aw_dev, char *cmd_buf) +{ + int ret; + int i; + char dev_select[50] = { 0 }; + struct list_head *dev_list = NULL; + struct list_head *pos = NULL; + struct aw_device *local_dev = NULL; + + /* get sel dev str */ + ret = sscanf(cmd_buf, "dev_sel:%s", dev_select); + if (ret <= 0) + return -EINVAL; + + for (i = 0; i < AW_DEV_CH_MAX; i++) { + if (strnstr(dev_select, ch_name[i], strlen(ch_name[i]))) + break; + } + + if (i == AW_DEV_CH_MAX) { + aw_dev_err(aw_dev->dev, "unsupport dev [%s]", dev_select); + return -EINVAL; + } + + /* get dev list */ + ret = aw882xx_dev_get_list_head(&dev_list); + if (ret) { + aw_dev_err(aw_dev->dev, "get dev list failed "); + return ret; + } + + /* find sel dev */ + list_for_each(pos, dev_list) { + local_dev = container_of(pos, struct aw_device, list_node); + if (local_dev->channel == i) { + filp->private_data = (void *)local_dev; + g_dev_select = i; + aw_dev_info(local_dev->dev, "switch dev to [%s]", ch_name[i]); + return 0; + } + } + aw_dev_err(aw_dev->dev, " unsupport [%s]", dev_select); + return -EINVAL; +} + +static ssize_t aw_cali_misc_write(struct file *filp, const char __user *buf, size_t size, loff_t *pos) +{ + int ret = 0; + char *kernel_buf = NULL; + struct aw_device *aw_dev = (struct aw_device *)filp->private_data; + + aw_dev_info(aw_dev->dev, "enter, write size:%d", (int)size); + + kernel_buf = kzalloc(size + 1, GFP_KERNEL); + if (kernel_buf == NULL) + return -ENOMEM; + + + if (copy_from_user(kernel_buf, + (void __user *)buf, + size)) { + ret = -EFAULT; + goto exit; + } + + ret = aw_cali_svc_get_cmd_form_str(aw_dev, kernel_buf); + if (ret < 0) { + aw_dev_err(aw_dev->dev, "upported cmd [%s]! ", kernel_buf); + ret = -EINVAL; + goto exit; + } + + switch (ret) { + case CALI_STR_CALI_RE_F0: { + ret = aw_cali_svc_cali_cmd(aw_dev, AW_CALI_CMD_RE_F0, + is_single_cali, CALI_OPS_HMUTE|CALI_OPS_NOISE); + } break; + case CALI_STR_CALI_RE: { + ret = aw_cali_svc_cali_cmd(aw_dev, AW_CALI_CMD_RE, + is_single_cali, CALI_OPS_HMUTE); + } break; + case CALI_STR_CALI_F0: { + ret = aw_cali_svc_cali_cmd(aw_dev, AW_CALI_CMD_F0, + is_single_cali, CALI_OPS_HMUTE|CALI_OPS_NOISE); + } break; + case CALI_STR_SET_RE: { + /*skip store_re*/ + kernel_buf[size] = '\0'; + ret = aw_cali_svc_set_devs_re_str(aw_dev, + kernel_buf + strlen(cali_str[CALI_STR_SET_RE]) + 1); + } break; + case CALI_STR_DEV_SEL: { + ret = aw_cali_misc_switch_dev(filp, aw_dev, kernel_buf); + } break; + case CALI_STR_CALI_F0_Q: { + ret = aw_cali_svc_cali_cmd(aw_dev, AW_CALI_CMD_F0_Q, + is_single_cali, CALI_OPS_HMUTE|CALI_OPS_NOISE); + } break; + case CALI_STR_SHOW_RE: /*show cali_re*/ + case CALI_STR_SHOW_R0: /*show real r0*/ + case CALI_STR_SHOW_CALI_F0: /*GET DEV CALI_F0*/ + case CALI_STR_SHOW_F0: /*SHOW REAL F0*/ + case CALI_STR_SHOW_TE: + case CALI_STR_SHOW_ST: + case CALI_STR_VER: + case CALI_STR_DEV_NUM: + case CALI_STR_SHOW_F0_Q: + case CALI_STR_SHOW_RE_RANGE:{ + g_msic_wr_flag = ret; + ret = 0; + } break; + default: { + aw_dev_err(aw_dev->dev, "unsupported [%s]! ", kernel_buf); + ret = -EINVAL; + } break; + }; + +exit: + aw_dev_info(aw_dev->dev, "cmd [%s]! ", kernel_buf); + + kfree(kernel_buf); + kernel_buf = NULL; + + if (ret < 0) + return -EINVAL; + else + return size; +} + +static const struct file_operations aw_cali_misc_fops = { + .owner = THIS_MODULE, + .open = aw_cali_misc_open, + .read = aw_cali_misc_read, + .write = aw_cali_misc_write, + .release = aw_cali_misc_release, + .unlocked_ioctl = aw_cali_misc_unlocked_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = aw_cali_misc_compat_ioctl, +#endif + +}; + +static struct miscdevice misc_cali = { + .name = "aw882xx_smartpa", + .minor = MISC_DYNAMIC_MINOR, + .fops = &aw_cali_misc_fops, +}; + +static int aw_cali_misc_init(struct aw_device *aw_dev) +{ + int ret; + + mutex_lock(&g_cali_lock); + if (g_misc_dev == NULL) { + ret = misc_register(&misc_cali); + if (ret) { + aw_dev_err(aw_dev->dev, "misc register fail: %d\n", ret); + mutex_unlock(&g_cali_lock); + return -EINVAL; + } + g_misc_dev = &misc_cali; + aw_dev_dbg(aw_dev->dev, "misc register success"); + } else { + aw_dev_dbg(aw_dev->dev, "misc already register"); + } + mutex_unlock(&g_cali_lock); + + return 0; +} + +static void aw_cali_misc_deinit(struct aw_device *aw_dev) +{ + mutex_lock(&g_cali_lock); + if (g_misc_dev) { + misc_deregister(g_misc_dev); + g_misc_dev = NULL; + } + mutex_unlock(&g_cali_lock); + aw_dev_dbg(aw_dev->dev, " misc unregister done"); +} + +/*****************************misc node******************************************************/ +static void aw_cali_parse_dt(struct aw_device *aw_dev) +{ + int ret = -1; + struct device_node *np = aw_dev->dev->of_node; + const char *cali_mode_str = NULL; + uint32_t cali_check = CALI_CHECK_DISABLE; + struct aw_cali_desc *desc = &aw_dev->cali_desc; + + ret = of_property_read_u32(np, "aw-cali-check", &cali_check); + if (ret < 0) { + aw_dev_info(aw_dev->dev, "cali-check get failed ,default turn off"); + cali_check = CALI_CHECK_DISABLE; + } + + desc->cali_check_st = cali_check; + aw_dev_info(aw_dev->dev, "cali check :%s", + (desc->cali_check_st) ? "enable" : "disable"); + + ret = of_property_read_string(np, "aw-cali-mode", &cali_mode_str); + if (ret < 0) { + desc->mode = AW_CALI_MODE_ALL; + aw_dev_info(aw_dev->dev, "cali function in use"); + return; + } + + if (!strcmp(cali_mode_str, "none")) + desc->mode = AW_CALI_MODE_NONE; + else + desc->mode = AW_CALI_MODE_ALL; + + aw_dev_info(aw_dev->dev, "cali mode is %d", desc->mode); +} + +static int aw_cali_parse_re_dt(struct aw_device *aw_dev) +{ + int ret; + + ret = of_property_read_u32(aw_dev->dev->of_node, "aw-re-min", &aw_dev->re_min); + if (ret < 0) { + aw_dev->re_min = AW_CALI_RE_DEFAULT_MIN; + aw_dev_info(aw_dev->dev, "read aw-re-min failed, use default"); + } + + ret = of_property_read_u32(aw_dev->dev->of_node, "aw-re-max", &aw_dev->re_max); + if (ret < 0) { + aw_dev->re_max = AW_CALI_RE_DEFAULT_MAX; + aw_dev_info(aw_dev->dev, "read aw-re-max failed, use default"); + } + + if (aw_dev->re_min >= aw_dev->re_max) { + aw_dev_err(aw_dev->dev, "re max must be greater than re min"); + return -EINVAL; + } + + aw_dev_info(aw_dev->dev, "re min: %d, re max: %d", + aw_dev->re_min, aw_dev->re_max); + return 0; +} + +int aw882xx_cali_init(struct aw_cali_desc *cali_desc) +{ + int ret; + + struct aw_device *aw_dev = + container_of(cali_desc, struct aw_device, cali_desc); + + cali_desc->cali_f0 = 0; + cali_desc->cali_re = 0; + cali_desc->cali_q = 0; + cali_desc->status = 0; + + aw_cali_parse_dt(aw_dev); + + if (cali_desc->mode == AW_CALI_MODE_ALL) { + aw_cali_attr_init(aw_dev); + aw_cali_class_attr_init(aw_dev); + } else { + aw_dev_info(aw_dev->dev, "cali mode is %d", cali_desc->mode); + } + + aw_cali_misc_init(aw_dev); + + ret = aw_cali_parse_re_dt(aw_dev); + + cali_desc->cali_result = CALI_RESULT_NONE; + + return ret; +} + +void aw882xx_cali_deinit(struct aw_cali_desc *cali_desc) +{ + struct aw_device *aw_dev = + container_of(cali_desc, struct aw_device, cali_desc); + + if (cali_desc->mode == AW_CALI_MODE_ALL) { + aw_cali_attr_deinit(aw_dev); + aw_cali_class_attr_deinit(aw_dev); + } + + aw_cali_misc_deinit(aw_dev); +} + diff --git a/sound/soc/codecs/aw882xx/aw882xx_calib.h b/sound/soc/codecs/aw882xx/aw882xx_calib.h new file mode 100644 index 000000000000..c26ca8f74ec4 --- /dev/null +++ b/sound/soc/codecs/aw882xx/aw882xx_calib.h @@ -0,0 +1,193 @@ +/* SPDX-License-Identifier: GPL-2.0 + * aw882xx_calib.h + * + * Copyright (c) 2020 AWINIC Technology CO., LTD + * + * Author: Nick Li + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#ifndef __AW882XX_CALIBRATION_H__ +#define __AW882XX_CALIBRATION_H__ + +#define AW_CALI_READ_RE_TIMES (8) +#define AW_CALI_READ_F0_Q_TIMES (5) +#define AW_ERRO_CALI_VALUE (0) +#define AW_CALI_RE_DEFAULT_TIMER (3000) + +#define AW_CALI_RE_MAX (15000) +#define AW_CALI_RE_MIN (4000) + +#define AW_CALI_CFG_NUM (3) +#define AW_CALI_DATA_NUM (6) +#define AW_PARAMS_NUM (600) +#define AW_KILO_PARAMS_NUM (1000) + +#define AW_CALI_RE_DEFAULT_MAX (50000) +#define AW_CALI_RE_DEFAULT_MIN (1000) + +#define AW_DEV_RE_RANGE (RE_RANGE_NUM * AW_DEV_CH_MAX) + +struct aw_device; + +enum afe_module_type { + AW_RX_MODULE = 0, + AW_TX_MODULE = 1, +}; + +enum { + MSG_CALI_DISABLE_DATA = 0, + MSG_CALI_RE_ENABLE_DATA, + MSG_CALI_F0_ENABLE_DATA, +}; + +struct cali_cfg { + int32_t data[AW_CALI_CFG_NUM]; +}; + +struct cali_data { + int32_t data[AW_CALI_DATA_NUM]; +}; + +struct params_data { + int32_t data[AW_PARAMS_NUM]; +}; + +struct ptr_params_data { + int len; + int32_t *data; +}; + +struct f0_q_data { + int32_t data[4]; +}; + +enum { + AW_IOCTL_MSG_IOCTL = 0, + AW_IOCTL_MSG_RD_DSP, + AW_IOCTL_MSG_WR_DSP +}; + +enum { + CALI_CHECK_DISABLE = 0, + CALI_CHECK_ENABLE = 1, +}; + +enum { + CALI_RESULT_NONE = 0, + CALI_RESULT_NORMAL = 1, + CALI_RESULT_ERROR = -1, +}; + +enum { + RE_MIN_FLAG = 0, + RE_MAX_FLAG = 1, + RE_RANGE_NUM = 2, +}; + +enum { + CALI_DATA_RE = 0, + CALI_DATA_F0, + CALI_DATA_F0_Q, +}; + +struct re_data { + uint32_t re_range[2]; +}; + +#define AW_IOCTL_MSG_VERSION (0) +typedef struct { + int32_t type; + int32_t opcode_id; + int32_t version; + int32_t data_len; + char *data_buf; + int32_t reseriver[2]; +} aw_ioctl_msg_t; + +#define AW_IOCTL_MAGIC 'a' +#define AW_IOCTL_SET_CALI_CFG _IOWR(AW_IOCTL_MAGIC, 1, struct cali_cfg) +#define AW_IOCTL_GET_CALI_CFG _IOWR(AW_IOCTL_MAGIC, 2, struct cali_cfg) +#define AW_IOCTL_GET_CALI_DATA _IOWR(AW_IOCTL_MAGIC, 3, struct cali_data) +#define AW_IOCTL_SET_NOISE _IOWR(AW_IOCTL_MAGIC, 4, int32_t) +#define AW_IOCTL_GET_F0 _IOWR(AW_IOCTL_MAGIC, 5, int32_t) +#define AW_IOCTL_SET_CALI_RE _IOWR(AW_IOCTL_MAGIC, 6, int32_t) +#define AW_IOCTL_GET_CALI_RE _IOWR(AW_IOCTL_MAGIC, 7, int32_t) +#define AW_IOCTL_SET_VMAX _IOWR(AW_IOCTL_MAGIC, 8, int32_t) +#define AW_IOCTL_GET_VMAX _IOWR(AW_IOCTL_MAGIC, 9, int32_t) +#define AW_IOCTL_SET_PARAM _IOWR(AW_IOCTL_MAGIC, 10, struct params_data) +#define AW_IOCTL_ENABLE_CALI _IOWR(AW_IOCTL_MAGIC, 11, int8_t) +#define AW_IOCTL_SET_PTR_PARAM_NUM _IOWR(AW_IOCTL_MAGIC, 12, struct ptr_params_data) +#define AW_IOCTL_GET_F0_Q _IOWR(AW_IOCTL_MAGIC, 13, struct f0_q_data) +#define AW_IOCTL_SET_DSP_HMUTE _IOWR(AW_IOCTL_MAGIC, 14, int32_t) +#define AW_IOCTL_SET_CALI_CFG_FLAG _IOWR(AW_IOCTL_MAGIC, 15, int32_t) +#define AW_IOCTL_MSG _IOWR(AW_IOCTL_MAGIC, 16, aw_ioctl_msg_t) +#define AW_IOCTL_GET_RE_RANGE _IOWR(AW_IOCTL_MAGIC, 17, struct re_data) + +enum{ + AW_CALI_MODE_NONE = 0, + AW_CALI_MODE_ALL, + AW_CALI_MODE_MAX, +}; + +enum { + AW_CALI_CMD_RE = 0, + AW_CALI_CMD_F0, + AW_CALI_CMD_RE_F0, + AW_CALI_CMD_F0_Q, + AW_CALI_CMD_RE_F0_Q, +}; + +enum { + CALI_OPS_HMUTE = 0X0001, + CALI_OPS_NOISE = 0X0002, +}; + +enum { + CALI_TYPE_RE = 0, + CALI_TYPE_F0, +}; + +enum { + CALI_STR_NONE = 0, + CALI_STR_CALI_RE_F0, + CALI_STR_CALI_RE, + CALI_STR_CALI_F0, + CALI_STR_SET_RE, + CALI_STR_SHOW_RE, /*show cali_re*/ + CALI_STR_SHOW_R0, /*show real r0*/ + CALI_STR_SHOW_CALI_F0, /*GET DEV CALI_F0*/ + CALI_STR_SHOW_F0, /*SHOW REAL F0*/ + CALI_STR_SHOW_TE, + CALI_STR_SHOW_ST, + CALI_STR_DEV_SEL, /*switch device*/ + CALI_STR_VER, + CALI_STR_DEV_NUM, + CALI_STR_CALI_F0_Q, + CALI_STR_SHOW_F0_Q, + CALI_STR_SHOW_RE_RANGE, + CALI_STR_MAX, +}; + +struct aw_cali_desc { + unsigned char status; + unsigned char mode; /*0:NONE 1:ATTR 2:CLASS 3:MISC */ + int32_t cali_re; /*set cali_re*/ + int32_t cali_f0; /*store cali_f0*/ + int32_t cali_q; /*store cali q*/ + int8_t cali_result; + uint8_t cali_check_st; +}; + +int aw882xx_cali_init(struct aw_cali_desc *cali_desc); +void aw882xx_cali_deinit(struct aw_cali_desc *cali_desc); +int aw882xx_cali_svc_get_cali_status(void); +int aw882xx_cali_read_re_from_nvram(int32_t *cali_re, int32_t ch_index); +bool aw882xx_cali_check_result(struct aw_cali_desc *cali_desc); + + +#endif diff --git a/sound/soc/codecs/aw882xx/aw882xx_data_type.h b/sound/soc/codecs/aw882xx/aw882xx_data_type.h new file mode 100644 index 000000000000..13213243b59a --- /dev/null +++ b/sound/soc/codecs/aw882xx/aw882xx_data_type.h @@ -0,0 +1,165 @@ +/* SPDX-License-Identifier: GPL-2.0 + * aw882xx_data_type.h + * + * Copyright (c) 2020 AWINIC Technology CO., LTD + * + * Author: Nick Li + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#ifndef __AW882XX_DATA_TYPE_H__ +#define __AW882XX_DATA_TYPE_H__ + +#define AW_NAME_BUF_MAX (50) + +struct aw_msg_hdr { + int32_t type; + int32_t opcode_id; + int32_t version; + int32_t reseriver[3]; +}; + + +/****************************************************************** + * aw profile + *******************************************************************/ +#define PROJECT_NAME_MAX (24) +#define CUSTOMER_NAME_MAX (16) +#define CFG_VERSION_MAX (4) +#define DEV_NAME_MAX (16) +#define PROFILE_STR_MAX (32) +#define AW_INIT_PROFILE (0) + +#define ACF_FILE_ID (0xa15f908) + + +enum aw_cfg_hdr_version { + AW_CFG_HDR_VER_0_0_0_1 = 0x00000001, + AW_CFG_HDR_VER_1_0_0_0 = 0x01000000, +}; + +enum aw_cfg_dde_type { + AW_DEV_TYPE_ID = 0x00000000, + AW_SKT_TYPE_ID = 0x00000001, + AW_DEV_DEFAULT_TYPE_ID = 0x00000002, +}; + +enum aw_sec_type { + ACF_SEC_TYPE_REG = 0, + ACF_SEC_TYPE_DSP, + ACF_SEC_TYPE_DSP_CFG, + ACF_SEC_TYPE_DSP_FW, + ACF_SEC_TYPE_HDR_REG, + ACF_SEC_TYPE_HDR_DSP_CFG, + ACF_SEC_TYPE_HDR_DSP_FW, + ACF_SEC_TYPE_MUTLBIN, + ACF_SEC_TYPE_SKT_PROJECT, + ACF_SEC_TYPE_DSP_PROJECT, + ACF_SEC_TYPE_MONITOR, + ACF_SEC_TYPE_MAX, +}; + +enum profile_data_type { + AW_PROFILE_DATA_TYPE_REG = 0, + AW_PROFILE_DATA_TYPE_DSP, + AW_PROFILE_DATA_TYPE_MAX, +}; + +enum aw_prof_type { + AW_PROFILE_MUSIC = 0, + AW_PROFILE_VOICE, + AW_PROFILE_VOIP, + AW_PROFILE_RINGTONE, + AW_PROFILE_RINGTONE_HS, + AW_PROFILE_LOWPOWER, + AW_PROFILE_BYPASS, + AW_PROFILE_MMI, + AW_PROFILE_FM, + AW_PROFILE_NOTIFICATION, + AW_PROFILE_RECEIVER, + AW_PROFILE_MAX, +}; + +enum aw_profile_status { + AW_PROFILE_WAIT = 0, + AW_PROFILE_OK, +}; + +struct aw_cfg_hdr { + uint32_t a_id; /*acf file ID 0xa15f908*/ + char a_project[PROJECT_NAME_MAX]; /*project name*/ + char a_custom[CUSTOMER_NAME_MAX]; /*custom name :huawei xiaomi vivo oppo*/ + char a_version[CFG_VERSION_MAX]; /*author update version*/ + uint32_t a_author_id; /*author id*/ + uint32_t a_ddt_size; /*sub section table entry size*/ + uint32_t a_ddt_num; /*sub section table entry num*/ + uint32_t a_hdr_offset; /*sub section table offset in file*/ + uint32_t a_hdr_version; /*sub section table version*/ + uint32_t reserve[3]; +}; + +struct aw_cfg_dde { + uint32_t type; /*DDE type id*/ + char dev_name[DEV_NAME_MAX]; + uint16_t dev_index; /*dev id*/ + uint16_t dev_bus; /*dev bus id*/ + uint16_t dev_addr; /*dev addr id*/ + uint16_t dev_profile; /*dev profile id*/ + uint32_t data_type; /*data type id*/ + uint32_t data_size; + uint32_t data_offset; + uint32_t data_crc; + uint32_t reserve[5]; +}; + +struct aw_cfg_dde_v_1_0_0_0 { + uint32_t type; /*DDE type id*/ + char dev_name[DEV_NAME_MAX]; + uint16_t dev_index; /*dev id*/ + uint16_t dev_bus; /*dev bus id*/ + uint16_t dev_addr; /*dev addr id*/ + uint16_t dev_profile; /*dev profile id*/ + uint32_t data_type; /*data type id*/ + uint32_t data_size; + uint32_t data_offset; + uint32_t data_crc; + char dev_profile_str[PROFILE_STR_MAX]; + uint32_t chip_id; + uint32_t reserve[4]; +}; + + +struct aw_container { + unsigned int len; + unsigned char data[]; +}; + +struct aw_sec_data_desc { + uint32_t len; + char *data; +}; + +struct aw_prof_desc { + uint32_t prof_st; /*Only used in V0.0.0.1 header*/ + uint32_t id; + char *prf_str; + struct aw_sec_data_desc sec_desc[AW_PROFILE_DATA_TYPE_MAX]; +}; + +struct aw_all_prof_info { + struct aw_prof_desc prof_desc[AW_PROFILE_MAX]; +}; + +struct aw_prof_info { + uint32_t count; + char **prof_name_list; + struct aw_prof_desc *prof_desc; +}; + + +#endif + diff --git a/sound/soc/codecs/aw882xx/aw882xx_device.c b/sound/soc/codecs/aw882xx/aw882xx_device.c new file mode 100644 index 000000000000..100ee6da8260 --- /dev/null +++ b/sound/soc/codecs/aw882xx/aw882xx_device.c @@ -0,0 +1,1593 @@ +// SPDX-License-Identifier: GPL-2.0 +/* aw882xx_device.c + * + * Copyright (c) 2020 AWINIC Technology CO., LTD + * + * Author: Nick Li + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +/* #define DEBUG */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#include "aw882xx_log.h" +#include "aw882xx_device.h" +#include "aw882xx_dsp.h" +/*#include "aw_afe.h"*/ +#include "aw882xx_bin_parse.h" +#include "aw882xx_spin.h" + +#define AW_DEV_SYSST_CHECK_MAX (10) + + +char ext_dsp_prof_write = AW_EXT_DSP_WRITE_NONE; +static DEFINE_MUTEX(g_ext_dsp_prof_wr_lock); /*lock ext wr flag*/ +static unsigned int g_fade_in_time = AW_1000_US / 10; +static unsigned int g_fade_out_time = AW_1000_US >> 1; +static LIST_HEAD(g_dev_list); +static DEFINE_MUTEX(g_dev_lock); + +static DEFINE_MUTEX(g_algo_auth_dsp_lock); +int g_algo_auth_st; + +/*********************************algo auth*************************************/ +static int aw882xx_dev_get_encrypted_value(struct aw_device *aw_dev, + unsigned int in, unsigned int *out) +{ + int ret = 0; + struct aw_auth_desc *desc = &aw_dev->auth_desc; + + if ((!desc->reg_in) || (!desc->reg_out)) { + aw_dev_dbg(aw_dev->dev, "Missing encryption register"); + return -EINVAL; + } + + ret = aw_dev->ops.aw_i2c_write(aw_dev, desc->reg_in, in); + if (ret < 0) + return ret; + + ret = aw_dev->ops.aw_i2c_read(aw_dev, desc->reg_out, out); + + return ret; +} + +int aw882xx_dev_algo_auth_mode(struct aw_device *aw_dev, struct algo_auth_data *algo_data) +{ + int ret = 0; + unsigned int encrypted_out = 0; + + aw_dev_info(aw_dev->dev, "algo auth mode: %d", algo_data->auth_mode); + + aw_dev->auth_desc.auth_mode = algo_data->auth_mode; + aw_dev->auth_desc.random = algo_data->random; + aw_dev->auth_desc.chip_id = AW_ALGO_AUTH_MAGIC_ID; + aw_dev->auth_desc.check_result = algo_data->check_result; + + switch (algo_data->auth_mode) { + case AW_ALGO_AUTH_MODE_MAGIC_ID: + aw_dev->auth_desc.reg_crc = algo_data->reg_crc; + break; + case AW_ALGO_AUTH_MODE_REG_CRC: + ret = aw882xx_dev_get_encrypted_value(aw_dev, algo_data->random, &encrypted_out); + if (ret < 0) + aw_dev_err(aw_dev->dev, "get encrypted value failed"); + + aw_dev->auth_desc.reg_crc = encrypted_out; + break; + default: + aw_dev_err(aw_dev->dev, "unsupport auth mode[%d]", algo_data->auth_mode); + ret = -EINVAL; + } + return ret; +} + +#ifdef AW_ALGO_AUTH_DSP +int aw882xx_dev_algo_auth_dsp_mode(struct aw_device *aw_dev, struct algo_auth_data *algo_data) +{ + int ret = 0; + unsigned int encrypted_out = 0; + + aw_dev_info(aw_dev->dev, "algo auth mode: %d", algo_data->auth_mode); + + algo_data->chip_id = AW_ALGO_AUTH_MAGIC_ID; + + if (algo_data->auth_mode == AW_ALGO_AUTH_MODE_REG_CRC) { + ret = aw882xx_dev_get_encrypted_value(aw_dev, algo_data->random, &encrypted_out); + if (ret < 0) + aw_dev_err(aw_dev->dev, "get encrypted value failed"); + + algo_data->reg_crc = encrypted_out; + } + + return ret; +} + +void aw882xx_dev_algo_authentication(struct aw_device *aw_dev) +{ + int ret = 0; + struct algo_auth_data algo_data; + + mutex_lock(&g_algo_auth_dsp_lock); + + aw_dev_dbg(aw_dev->dev, "g_algo_auth_st=%d", g_algo_auth_st); + + if (g_algo_auth_st == AW_ALGO_AUTH_OK) { + aw_dev_dbg(aw_dev->dev, "algo auth complete"); + goto exit; + } + + ret = aw882xx_dsp_read_algo_auth_data(aw_dev, (char *)&algo_data, sizeof(struct algo_auth_data)); + if (ret < 0) + goto exit; + + ret = aw882xx_dev_algo_auth_dsp_mode(aw_dev, &algo_data); + if (ret < 0) + goto exit; + + ret = aw882xx_dsp_write_algo_auth_data(aw_dev, (char *)&algo_data, sizeof(struct algo_auth_data)); + if (ret < 0) + goto exit; + + g_algo_auth_st = AW_ALGO_AUTH_OK; + aw_dev_info(aw_dev->dev, "g_algo_auth_st=%d", g_algo_auth_st); + + aw_dev_dbg(aw_dev->dev, "mode=%d,reg_crc=0x%x,random=0x%x,id=0x%x,res=%d", + algo_data.auth_mode, algo_data.reg_crc, algo_data.random, + algo_data.chip_id, algo_data.check_result); + +exit: + mutex_unlock(&g_algo_auth_dsp_lock); +} +#endif +/*********************************algo_auth_misc*************************************/ +static int aw_algo_auth_misc_ops_write(struct aw_device *aw_dev, + unsigned int cmd, unsigned long arg) +{ + int ret = 0; + unsigned int data_len = _IOC_SIZE(cmd); + struct algo_auth_data algo_data; + + aw_dev_dbg(aw_dev->dev, "write algo auth data, len=%d", data_len); + + if (copy_from_user(&algo_data, (void __user *)arg, data_len)) + ret = -EFAULT; + + aw882xx_dev_algo_auth_mode(aw_dev, &algo_data); + + aw_dev_dbg(aw_dev->dev, "ret=%d,mode=%d,reg_crc=0x%x,random=0x%x,id=0x%x,res=%d", + ret, algo_data.auth_mode, algo_data.reg_crc, algo_data.random, + algo_data.chip_id, algo_data.check_result); + + return ret; +} + +static int aw_algo_auth_misc_ops_read(struct aw_device *aw_dev, + unsigned int cmd, unsigned long arg) +{ + int ret = 0; + int16_t data_len = _IOC_SIZE(cmd); + struct algo_auth_data algo_data; + + aw_dev_dbg(aw_dev->dev, "read algo auth data, len=%d", data_len); + memset(&algo_data, 0x0, sizeof(struct algo_auth_data)); + + algo_data.auth_mode = aw_dev->auth_desc.auth_mode; + algo_data.chip_id = aw_dev->auth_desc.chip_id; + algo_data.random = aw_dev->auth_desc.random; + algo_data.reg_crc = aw_dev->auth_desc.reg_crc; + algo_data.check_result = aw_dev->auth_desc.check_result; + + if (copy_to_user((void __user *)arg, (char *)&algo_data, data_len)) + ret = -EFAULT; + + aw_dev_dbg(aw_dev->dev, "ret=%d,mode=%d,reg_crc=0x%x,random=0x%x,id=0x%x,res=%d", + ret, algo_data.auth_mode, algo_data.reg_crc, algo_data.random, + algo_data.chip_id, algo_data.check_result); + + return ret; +} + +static int aw_algo_auth_misc_ops(struct aw_device *aw_dev, + unsigned int cmd, unsigned long arg) +{ + int ret = 0; + + switch (cmd) { + case AW_IOCTL_SET_ALGO_AUTH: { + ret = aw_algo_auth_misc_ops_write(aw_dev, cmd, arg); + } break; + case AW_IOCTL_GET_ALGO_AUTH: { + ret = aw_algo_auth_misc_ops_read(aw_dev, cmd, arg); + } break; + default: + aw_dev_err(aw_dev->dev, "unsupported cmd %d", cmd); + ret = -EINVAL; + break; + } + + return ret; +} + +static long aw_algo_auth_misc_unlocked_ioctl(struct file *file, + unsigned int cmd, unsigned long arg) +{ + int ret = 0; + struct aw_device *aw_dev = NULL; + + if (((_IOC_TYPE(cmd)) != (AW_IOCTL_MAGIC_S))) { + aw_pr_err("cmd magic err"); + return -EINVAL; + } + aw_dev = (struct aw_device *)file->private_data; + ret = aw_algo_auth_misc_ops(aw_dev, cmd, arg); + if (ret) + return -EINVAL; + + return 0; +} + +#ifdef CONFIG_COMPAT +static long aw_algo_auth_misc_compat_ioctl(struct file *file, + unsigned int cmd, unsigned long arg) +{ + int ret = 0; + struct aw_device *aw_dev = NULL; + + if (((_IOC_TYPE(cmd)) != (AW_IOCTL_MAGIC_S))) { + aw_pr_err("cmd magic err"); + return -EINVAL; + } + aw_dev = (struct aw_device *)file->private_data; + ret = aw_algo_auth_misc_ops(aw_dev, cmd, arg); + if (ret) + return -EINVAL; + + return 0; +} +#endif + +static int aw_algo_auth_misc_open(struct inode *inode, struct file *file) +{ + int ret; + struct list_head *dev_list = NULL; + struct list_head *pos = NULL; + struct aw_device *local_dev = NULL; + + ret = aw882xx_dev_get_list_head(&dev_list); + if (ret) { + aw_pr_err("get dev list failed"); + file->private_data = NULL; + return -EINVAL; + } + + /* find select dev */ + list_for_each(pos, dev_list) { + local_dev = container_of(pos, struct aw_device, list_node); + if (local_dev->channel == 0) + break; + } + + if (local_dev == NULL) { + aw_pr_err("can't find dev num %d", 0); + return -EINVAL; + } + + file->private_data = (void *)local_dev; + + aw_dev_dbg(local_dev->dev, "misc open success"); + return 0; +} + + +static int aw_algo_auth_misc_release(struct inode *inode, struct file *file) +{ + file->private_data = (void *)NULL; + + aw_pr_dbg("misc release success"); + return 0; +} + +static const struct file_operations aw_algo_auth_misc_fops = { + .owner = THIS_MODULE, + .open = aw_algo_auth_misc_open, + .release = aw_algo_auth_misc_release, + .unlocked_ioctl = aw_algo_auth_misc_unlocked_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = aw_algo_auth_misc_compat_ioctl, +#endif +}; + +static struct miscdevice misc_algo_auth = { + .name = "awinic_ctl", + .minor = MISC_DYNAMIC_MINOR, + .fops = &aw_algo_auth_misc_fops, +}; + +static int aw882xx_algo_auth_misc_init(struct aw_device *aw_dev) +{ + int ret; + + ret = misc_register(&misc_algo_auth); + if (ret) { + aw_dev_err(aw_dev->dev, "misc register fail: %d\n", ret); + return -EINVAL; + } + + return 0; +} + +static void aw882xx_algo_auth_misc_deinit(struct aw_device *aw_dev) +{ + misc_deregister(&misc_algo_auth); + + aw_dev_dbg(aw_dev->dev, " misc unregister done"); +} + +void aw882xx_dev_monitor_hal_get_time(struct aw_device *aw_dev, uint32_t *time) +{ + aw882xx_monitor_hal_get_time(&aw_dev->monitor_desc, time); +} + +void aw882xx_dev_monitor_hal_work(struct aw_device *aw_dev, uint32_t *vmax) +{ + aw882xx_monitor_hal_work(&aw_dev->monitor_desc, vmax); +} + +static void aw_dev_reg_dump(struct aw_device *aw_dev) +{ + int reg_num = aw_dev->ops.aw_get_reg_num(); + uint8_t i = 0; + unsigned int reg_val = 0; + + for (i = 0; i < reg_num; i++) { + if (aw_dev->ops.aw_check_rd_access(i)) { + aw_dev->ops.aw_i2c_read(aw_dev, i, ®_val); + aw_dev_info(aw_dev->dev, "read: reg = 0x%02x, val = 0x%04x", + i, reg_val); + } + } +} + +char *aw882xx_dev_get_ext_dsp_prof_write(void) +{ + return &ext_dsp_prof_write; +} + +struct mutex *aw882xx_dev_get_ext_dsp_prof_wr_lock(void) +{ + return &g_ext_dsp_prof_wr_lock; +} + +static int aw_dev_get_icalk(struct aw_device *aw_dev, int16_t *icalk) +{ + int ret = -1; + unsigned int reg_val = 0; + uint16_t reg_icalk = 0; + uint16_t reg_icalkl = 0; + struct aw_vcalb_desc *desc = &aw_dev->vcalb_desc; + + if (desc->icalkl_reg == AW_REG_NONE) { + ret = aw_dev->ops.aw_i2c_read(aw_dev, desc->icalk_reg, ®_val); + reg_icalk = (uint16_t)reg_val & (~desc->icalk_reg_mask); + } else { + ret = aw_dev->ops.aw_i2c_read(aw_dev, desc->icalk_reg, ®_val); + reg_icalk = (uint16_t)reg_val & (~desc->icalk_reg_mask); + ret = aw_dev->ops.aw_i2c_read(aw_dev, desc->icalkl_reg, ®_val); + reg_icalkl = (uint16_t)reg_val & (~desc->icalkl_reg_mask); + if (aw_dev->efuse_check == AW_EF_OR_CHECK) + reg_icalk = (reg_icalk >> desc->icalk_shift) | (reg_icalkl >> desc->icalkl_shift); + else + reg_icalk = (reg_icalk >> desc->icalk_shift) & (reg_icalkl >> desc->icalkl_shift); + } + + if (reg_icalk & (~desc->icalk_sign_mask)) + reg_icalk = reg_icalk | (~desc->icalk_neg_mask); + + *icalk = (int16_t)reg_icalk; + + return ret; +} + +static int aw_dev_get_vcalk(struct aw_device *aw_dev, int16_t *vcalk) +{ + int ret = -1; + unsigned int reg_val = 0; + uint16_t reg_vcalk = 0; + uint16_t reg_vcalkl = 0; + struct aw_vcalb_desc *desc = &aw_dev->vcalb_desc; + + if (desc->vcalkl_reg == AW_REG_NONE) { + ret = aw_dev->ops.aw_i2c_read(aw_dev, desc->vcalk_reg, ®_val); + reg_vcalk = (uint16_t)reg_val & (~desc->vcalk_reg_mask); + } else { + ret = aw_dev->ops.aw_i2c_read(aw_dev, desc->vcalk_reg, ®_val); + reg_vcalk = (uint16_t)reg_val & (~desc->vcalk_reg_mask); + ret = aw_dev->ops.aw_i2c_read(aw_dev, desc->vcalkl_reg, ®_val); + reg_vcalkl = (uint16_t)reg_val & (~desc->vcalkl_reg_mask); + if (aw_dev->efuse_check == AW_EF_OR_CHECK) + reg_vcalk = (reg_vcalk >> desc->vcalk_shift) | (reg_vcalkl >> desc->vcalkl_shift); + else + reg_vcalk = (reg_vcalk >> desc->vcalk_shift) & (reg_vcalkl >> desc->vcalkl_shift); + } + + if (reg_vcalk & (~desc->vcalk_sign_mask)) + reg_vcalk = reg_vcalk | (~desc->vcalk_neg_mask); + + *vcalk = (int16_t)reg_vcalk; + + return ret; +} + +static int aw_dev_set_vcalb(struct aw_device *aw_dev) +{ + int ret = -1; + unsigned int reg_val; + int vcalb; + int icalk; + int vcalk; + int16_t icalk_val = 0; + int16_t vcalk_val = 0; + + struct aw_vcalb_desc *desc = &aw_dev->vcalb_desc; + + if (desc->icalk_reg == AW_REG_NONE || desc->vcalb_reg == AW_REG_NONE) { + aw_dev_info(aw_dev->dev, "REG None!"); + return 0; + } + + ret = aw_dev_get_icalk(aw_dev, &icalk_val); + if (ret < 0) + return ret; + + ret = aw_dev_get_vcalk(aw_dev, &vcalk_val); + if (ret < 0) + return ret; + + icalk = desc->cabl_base_value + desc->icalk_value_factor * icalk_val; + vcalk = desc->cabl_base_value + desc->vcalk_value_factor * vcalk_val; + if (!vcalk) { + aw_dev_err(aw_dev->dev, "vcalk is 0"); + return -EINVAL; + } + + vcalb = desc->vcal_factor * icalk / vcalk; + + reg_val = (unsigned int)vcalb; + aw_dev_info(aw_dev->dev, "icalk=%d, vcalk=%d, vcalb=%d, reg_val=0x%04x", + icalk, vcalk, vcalb, reg_val); + + ret = aw_dev->ops.aw_i2c_write(aw_dev, desc->vcalb_reg, reg_val); + + aw_dev_info(aw_dev->dev, "done"); + + return ret; +} + +/*pwd enable update reg*/ +static int aw_dev_reg_fw_update(struct aw_device *aw_dev) +{ + int ret = -1; + int i = 0; + unsigned int reg_addr = 0; + unsigned int reg_val = 0; + unsigned int read_val = 0; + unsigned int read_vol = 0; + unsigned int efcheck_val = 0; + struct aw_int_desc *int_desc = &aw_dev->int_desc; + struct aw_profctrl_desc *profctrl_desc = &aw_dev->profctrl_desc; + struct aw_bstctrl_desc *bstctrl_desc = &aw_dev->bstctrl_desc; + struct aw_work_mode *work_mode = &aw_dev->work_mode; + struct aw_cali_desc *cali_desc = &aw_dev->cali_desc; + struct aw_volume_desc *vol_desc = &aw_dev->volume_desc; + struct aw_sec_data_desc *reg_data; + int16_t *data; + int data_len; + + char *prof_name = aw882xx_dev_get_prof_name(aw_dev, aw_dev->set_prof); + + if (prof_name == NULL) { + aw_dev_err(aw_dev->dev, "get prof name failed"); + return -EINVAL; + } + + reg_data = aw882xx_dev_get_prof_data(aw_dev, aw_dev->set_prof, AW_PROFILE_DATA_TYPE_REG); + if (reg_data == NULL) + return -EINVAL; + + data = (int16_t *)reg_data->data; + data_len = reg_data->len >> 1; + + for (i = 0; i < data_len; i += 2) { + reg_addr = data[i]; + reg_val = data[i + 1]; + + if (reg_addr == int_desc->mask_reg) { + int_desc->int_mask = reg_val; + reg_val = int_desc->mask_default; + } + + if (aw_dev->bstcfg_enable) { + if (reg_addr == profctrl_desc->reg) { + profctrl_desc->cfg_prof_mode = + reg_val & (~profctrl_desc->mask); + } + + if (reg_addr == bstctrl_desc->reg) { + bstctrl_desc->cfg_bst_type = + reg_val & (~bstctrl_desc->mask); + } + } + + /*keep amppd status*/ + if (reg_addr == aw_dev->amppd_desc.reg) { + aw_dev->amppd_st = reg_val & (~aw_dev->amppd_desc.mask); + aw_dev_info(aw_dev->dev, "amppd_st=0x%04x", aw_dev->amppd_st); + aw_dev->ops.aw_i2c_read(aw_dev, + (unsigned char)reg_addr, + (unsigned int *)&read_val); + read_val &= (~aw_dev->amppd_desc.mask); + reg_val &= aw_dev->amppd_desc.mask; + reg_val |= read_val; + } + + if (reg_addr == aw_dev->efcheck_desc.reg) { + efcheck_val = reg_val & (~aw_dev->efcheck_desc.mask); + if (efcheck_val == aw_dev->efcheck_desc.or_val) + aw_dev->efuse_check = AW_EF_OR_CHECK; + else + aw_dev->efuse_check = AW_EF_AND_CHECK; + + aw_dev_info(aw_dev->dev, "efuse check: %d", aw_dev->efuse_check); + } + + if (reg_addr == work_mode->reg) { + if ((reg_val & (~work_mode->mask)) == work_mode->rcv_val) + aw_dev->monitor_start = false; + else + aw_dev->monitor_start = true; + } + + /*keep pwd status*/ + if (reg_addr == aw_dev->pwd_desc.reg) { + aw_dev->ops.aw_i2c_read(aw_dev, + (unsigned char)reg_addr, + (unsigned int *)&read_val); + read_val &= (~aw_dev->pwd_desc.mask); + reg_val &= aw_dev->pwd_desc.mask; + reg_val |= read_val; + } + /*keep mute status*/ + if (reg_addr == aw_dev->mute_desc.reg) { + /*get bin value*/ + aw_dev->mute_st = reg_val & (~aw_dev->mute_desc.mask); + aw_dev_info(aw_dev->dev, "mute_st=0x%04x", aw_dev->mute_st); + aw_dev->ops.aw_i2c_read(aw_dev, + (unsigned char)reg_addr, + (unsigned int *)&read_val); + read_val &= (~aw_dev->mute_desc.mask); + reg_val &= aw_dev->mute_desc.mask; + reg_val |= read_val; + } + + /*enable uls hmute*/ + if (reg_addr == aw_dev->uls_hmute_desc.reg) { + reg_val &= aw_dev->uls_hmute_desc.mask; + reg_val |= aw_dev->uls_hmute_desc.enable; + } + + if ((cali_desc->mode == AW_CALI_MODE_NONE) && + (reg_addr == aw_dev->txen_desc.reg)) { + aw_dev->txen_desc.reserve_val = reg_val & (~aw_dev->txen_desc.mask); + aw_dev_info(aw_dev->dev, "reserve_val = 0x%04x", + aw_dev->txen_desc.reserve_val); + } + + if (reg_addr == aw_dev->txen_desc.reg) { + /*get bin value*/ + aw_dev->txen_st = reg_val & (~aw_dev->txen_desc.mask); + aw_dev_dbg(aw_dev->dev, "txen_st=0x%04x", aw_dev->txen_st); + + reg_val &= aw_dev->txen_desc.mask; + reg_val |= aw_dev->txen_desc.disable; + } + + if (reg_addr == aw_dev->volume_desc.reg) { + read_vol = (reg_val & (~aw_dev->volume_desc.mask)) >> + aw_dev->volume_desc.shift; + aw_dev->volume_desc.init_volume = + aw_dev->ops.aw_reg_val_to_db(read_vol); + } + if (reg_addr == aw_dev->dither_desc.reg) { + aw_dev->dither_st = reg_val & (~aw_dev->dither_desc.mask); + aw_dev_info(aw_dev->dev, "dither_st=0x%04x", aw_dev->dither_st); + } + + if (reg_addr == aw_dev->vcalb_desc.vcalb_reg) + continue; + + aw_dev_dbg(aw_dev->dev, "reg=0x%04x, val = 0x%04x", + (uint16_t)reg_addr, (uint16_t)reg_val); + ret = aw_dev->ops.aw_i2c_write(aw_dev, + (unsigned char)reg_addr, + (unsigned int)reg_val); + if (ret < 0) + break; + } + + aw882xx_spin_set_record_val(aw_dev); + ret = aw_dev_set_vcalb(aw_dev); + if (ret < 0) { + aw_dev_err(aw_dev->dev, "can't set vcalb"); + return ret; + } + + if (aw_dev->cur_prof != aw_dev->set_prof) + /*clear control volume when PA change profile*/ + vol_desc->ctl_volume = 0; + + + if (aw_dev->fade_en) { + /*keep min volume*/ + aw882xx_dev_set_volume(aw_dev, vol_desc->mute_volume); + } + + aw_dev_info(aw_dev->dev, "load %s done", prof_name); + + return ret; +} + +int aw882xx_dev_set_volume(struct aw_device *aw_dev, unsigned int set_vol) +{ + int ret = -1; + unsigned int hw_vol = 0; + struct aw_volume_desc *vol_desc = &aw_dev->volume_desc; + + hw_vol = set_vol + vol_desc->init_volume; + + ret = aw_dev->ops.aw_set_hw_volume(aw_dev, hw_vol); + if (ret < 0) { + aw_dev_err(aw_dev->dev, "set volume failed"); + return ret; + } + + return 0; +} + +int aw882xx_dev_get_volume(struct aw_device *aw_dev, unsigned int *get_vol) +{ + int ret = -1; + unsigned int hw_vol = 0; + struct aw_volume_desc *vol_desc = &aw_dev->volume_desc; + + ret = aw_dev->ops.aw_get_hw_volume(aw_dev, &hw_vol); + if (ret < 0) { + aw_dev_err(aw_dev->dev, "read volume failed"); + return ret; + } + + *get_vol = hw_vol - vol_desc->init_volume; + + return 0; +} + +static void aw_dev_fade_in(struct aw_device *aw_dev) +{ + int i = 0; + int fade_step = aw_dev->vol_step; + struct aw_volume_desc *desc = &aw_dev->volume_desc; + int fade_in_vol = desc->ctl_volume; + + if (!aw_dev->fade_en) + return; + + + if (fade_step == 0 || g_fade_in_time == 0) { + aw882xx_dev_set_volume(aw_dev, fade_in_vol); + return; + } + + /*volume up*/ + for (i = desc->mute_volume; i >= fade_in_vol; i -= fade_step) { + aw882xx_dev_set_volume(aw_dev, i); + usleep_range(g_fade_in_time, g_fade_in_time + 10); + } + + if (i != fade_in_vol) + aw882xx_dev_set_volume(aw_dev, fade_in_vol); + +} + +static void aw_dev_fade_out(struct aw_device *aw_dev) +{ + int i = 0; + int fade_step = aw_dev->vol_step; + struct aw_volume_desc *desc = &aw_dev->volume_desc; + + if (!aw_dev->fade_en) + return; + + + if (fade_step == 0 || g_fade_out_time == 0) { + aw882xx_dev_set_volume(aw_dev, desc->mute_volume); + return; + } + + for (i = desc->ctl_volume; i <= desc->mute_volume; i += fade_step) { + aw882xx_dev_set_volume(aw_dev, i); + usleep_range(g_fade_out_time, g_fade_out_time + 10); + } + + if (i != desc->mute_volume) { + aw882xx_dev_set_volume(aw_dev, desc->mute_volume); + usleep_range(g_fade_out_time, g_fade_out_time + 10); + } +} + +static void aw_dev_pwd(struct aw_device *aw_dev, bool pwd) +{ + struct aw_pwd_desc *pwd_desc = &aw_dev->pwd_desc; + + aw_dev_dbg(aw_dev->dev, "enter, pwd: %d", pwd); + + if (pwd) { + aw_dev->ops.aw_i2c_write_bits(aw_dev, pwd_desc->reg, + pwd_desc->mask, + pwd_desc->enable); + } else { + aw_dev->ops.aw_i2c_write_bits(aw_dev, pwd_desc->reg, + pwd_desc->mask, + pwd_desc->disable); + } + aw_dev_info(aw_dev->dev, "done"); +} + +static void aw_dev_amppd(struct aw_device *aw_dev, bool amppd) +{ + struct aw_amppd_desc *amppd_desc = &aw_dev->amppd_desc; + + aw_dev_dbg(aw_dev->dev, "enter, amppd: %d", amppd); + + if (amppd) { + aw_dev->ops.aw_i2c_write_bits(aw_dev, amppd_desc->reg, + amppd_desc->mask, + amppd_desc->enable); + } else { + aw_dev->ops.aw_i2c_write_bits(aw_dev, amppd_desc->reg, + amppd_desc->mask, + amppd_desc->disable); + } + aw_dev_info(aw_dev->dev, "done"); +} + +void aw882xx_dev_mute(struct aw_device *aw_dev, bool mute) +{ + struct aw_mute_desc *mute_desc = &aw_dev->mute_desc; + + aw_dev_dbg(aw_dev->dev, "enter, mute: %d, cali_result: %d", + mute, aw_dev->cali_desc.cali_result); + + if (mute) { + aw_dev_fade_out(aw_dev); + aw_dev->ops.aw_i2c_write_bits(aw_dev, mute_desc->reg, + mute_desc->mask, + mute_desc->enable); + usleep_range(AW_5000_US, AW_5000_US + 50); + } else { + aw_dev->ops.aw_i2c_write_bits(aw_dev, mute_desc->reg, + mute_desc->mask, + mute_desc->disable); + aw_dev_fade_in(aw_dev); + } + aw_dev_info(aw_dev->dev, "done"); +} + +static void aw_dev_uls_hmute(struct aw_device *aw_dev, bool uls_hmute) +{ + struct aw_uls_hmute_desc *uls_hmute_desc = &aw_dev->uls_hmute_desc; + + aw_dev_dbg(aw_dev->dev, "enter, uls_hmute: %d", uls_hmute); + + if (uls_hmute_desc->reg == AW_REG_NONE) + return; + + if (uls_hmute) { + aw_dev->ops.aw_i2c_write_bits(aw_dev, uls_hmute_desc->reg, + uls_hmute_desc->mask, + uls_hmute_desc->enable); + } else { + aw_dev->ops.aw_i2c_write_bits(aw_dev, uls_hmute_desc->reg, + uls_hmute_desc->mask, + uls_hmute_desc->disable); + } + aw_dev_info(aw_dev->dev, "done"); +} + +static void aw_dev_set_dither(struct aw_device *aw_dev, bool dither) +{ + struct aw_dither_desc *dither_desc = &aw_dev->dither_desc; + + aw_dev_dbg(aw_dev->dev, "enter, dither: %d", dither); + + if (dither_desc->reg == AW_REG_NONE) + return; + + if (dither) { + aw_dev->ops.aw_i2c_write_bits(aw_dev, dither_desc->reg, + dither_desc->mask, + dither_desc->enable); + } else { + aw_dev->ops.aw_i2c_write_bits(aw_dev, dither_desc->reg, + dither_desc->mask, + dither_desc->disable); + } + + aw_dev_info(aw_dev->dev, "done"); +} + +static void aw_dev_set_psm(struct aw_device *aw_dev, bool psm) +{ + struct aw_psm_desc *desc = &aw_dev->psm_desc; + + aw_dev_dbg(aw_dev->dev, "enter, psm: %d", psm); + if (desc->reg == AW_REG_NONE) + return; + + if (psm) + aw_dev->ops.aw_i2c_write_bits(aw_dev, desc->reg, + desc->mask, desc->enable); + else + aw_dev->ops.aw_i2c_write_bits(aw_dev, desc->reg, + desc->mask, desc->disable); + + aw_dev_info(aw_dev->dev, "done"); +} + +static void aw_dev_set_mpd(struct aw_device *aw_dev, bool mpd) +{ + struct aw_mpd_desc *desc = &aw_dev->mpd_desc; + + aw_dev_dbg(aw_dev->dev, "enter, mpd: %d", mpd); + if (desc->reg == AW_REG_NONE) + return; + + if (mpd) + aw_dev->ops.aw_i2c_write_bits(aw_dev, desc->reg, + desc->mask, desc->enable); + else + aw_dev->ops.aw_i2c_write_bits(aw_dev, desc->reg, + desc->mask, desc->disable); + + aw_dev_info(aw_dev->dev, "done"); +} + +static void aw_dev_set_dsmzth(struct aw_device *aw_dev, bool dsmzth) +{ + struct aw_dsmzth_desc *desc = &aw_dev->dsmzth_desc; + + aw_dev_dbg(aw_dev->dev, "enter, dsmzth: %d", dsmzth); + if (desc->reg == AW_REG_NONE) + return; + + if (dsmzth) + aw_dev->ops.aw_i2c_write_bits(aw_dev, desc->reg, + desc->mask, desc->enable); + else + aw_dev->ops.aw_i2c_write_bits(aw_dev, desc->reg, + desc->mask, desc->disable); + + aw_dev_info(aw_dev->dev, "done"); +} + +void aw882xx_dev_iv_forbidden_output(struct aw_device *aw_dev, bool power_waste) +{ + aw_dev_set_psm(aw_dev, power_waste); + aw_dev_set_mpd(aw_dev, power_waste); + aw_dev_set_dsmzth(aw_dev, power_waste); +} + +int aw882xx_dev_get_int_status(struct aw_device *aw_dev, uint16_t *int_status) +{ + int ret = -1; + unsigned int reg_val = 0; + + ret = aw_dev->ops.aw_i2c_read(aw_dev, aw_dev->int_desc.st_reg, ®_val); + if (ret < 0) + aw_dev_err(aw_dev->dev, "read interrupt reg fail, ret=%d", ret); + else + *int_status = reg_val; + + aw_dev_dbg(aw_dev->dev, "read interrupt reg = 0x%04x", *int_status); + return ret; +} + +void aw882xx_dev_clear_int_status(struct aw_device *aw_dev) +{ + uint16_t int_status = 0; + + /*read int status and clear*/ + aw882xx_dev_get_int_status(aw_dev, &int_status); + /*make suer int status is clear*/ + aw882xx_dev_get_int_status(aw_dev, &int_status); + aw_dev_info(aw_dev->dev, "done"); +} + +int aw882xx_dev_set_intmask(struct aw_device *aw_dev, bool flag) +{ + struct aw_int_desc *desc = &aw_dev->int_desc; + int ret = -1; + + if (flag) + ret = aw_dev->ops.aw_i2c_write(aw_dev, desc->mask_reg, + desc->int_mask); + else + ret = aw_dev->ops.aw_i2c_write(aw_dev, desc->mask_reg, + desc->mask_default); + aw_dev_info(aw_dev->dev, "done"); + return ret; +} + +static int aw_dev_mode1_pll_check(struct aw_device *aw_dev) +{ + int ret = -1; + unsigned char i; + unsigned int reg_val = 0; + struct aw_sysst_desc *desc = &aw_dev->sysst_desc; + + for (i = 0; i < AW_DEV_SYSST_CHECK_MAX; i++) { + aw_dev->ops.aw_i2c_read(aw_dev, desc->reg, ®_val); + if ((reg_val & desc->pll_check) == desc->pll_check) { + ret = 0; + break; + } + aw_dev_dbg(aw_dev->dev, "check pll lock fail, cnt=%d, reg_val=0x%04x", + i, reg_val); + usleep_range(AW_2000_US, AW_2000_US + 10); + + } + if (ret < 0) + aw_dev_err(aw_dev->dev, "pll&clk check fail"); + else + aw_dev_info(aw_dev->dev, "done"); + + return ret; +} + +static int aw_dev_mode2_pll_check(struct aw_device *aw_dev) +{ + int ret = -1; + unsigned int reg_val = 0; + struct aw_cco_mux_desc *cco_mux_desc = &aw_dev->cco_mux_desc; + + aw_dev->ops.aw_i2c_read(aw_dev, cco_mux_desc->reg, ®_val); + reg_val &= (~cco_mux_desc->mask); + aw_dev_dbg(aw_dev->dev, "REG_PLLCTRL1_bit14 = 0x%04x", reg_val); + if (reg_val == cco_mux_desc->divided_val) { + aw_dev_dbg(aw_dev->dev, "CCO_MUX is already divided"); + return ret; + } + + /* change mode2 */ + aw_dev->ops.aw_i2c_write_bits(aw_dev, cco_mux_desc->reg, + cco_mux_desc->mask, cco_mux_desc->divided_val); + ret = aw_dev_mode1_pll_check(aw_dev); + + /* change mode1 */ + aw_dev->ops.aw_i2c_write_bits(aw_dev, cco_mux_desc->reg, + cco_mux_desc->mask, cco_mux_desc->bypass_val); + if (ret == 0) { + usleep_range(AW_2000_US, AW_2000_US + 10); + ret = aw_dev_mode1_pll_check(aw_dev); + } + + return ret; +} + +static int aw_dev_syspll_check(struct aw_device *aw_dev) +{ + int ret = -1; + + ret = aw_dev_mode1_pll_check(aw_dev); + if (ret < 0) { + aw_dev_err(aw_dev->dev, + "mode1 check iis failed try switch to mode2 check"); + + ret = aw_dev_mode2_pll_check(aw_dev); + if (ret < 0) + aw_dev_err(aw_dev->dev, "mode2 check iis failed"); + } + + return ret; +} + +static int aw_dev_sysst_check(struct aw_device *aw_dev) +{ + int ret = -1; + unsigned char i; + unsigned int reg_val = 0; + unsigned int check_value = 0; + struct aw_sysst_desc *desc = &aw_dev->sysst_desc; + struct aw_noise_gate_desc *noise_gate_desc = &aw_dev->noise_gate_desc; + + check_value = desc->st_check; + + if (noise_gate_desc->reg != AW_REG_NONE) { + aw_dev->ops.aw_i2c_read(aw_dev, noise_gate_desc->reg, ®_val); + if (reg_val & (~noise_gate_desc->mask)) + check_value = desc->st_check; + else + check_value = desc->st_sws_check; + } + + for (i = 0; i < AW_DEV_SYSST_CHECK_MAX; i++) { + aw_dev->ops.aw_i2c_read(aw_dev, desc->reg, ®_val); + if (((reg_val & (~desc->mask)) & check_value) == check_value) { + ret = 0; + break; + } + aw_dev_info(aw_dev->dev, "check fail, cnt=%d, reg_val=0x%04x", + i, reg_val); + usleep_range(AW_2000_US, AW_2000_US + 10); + + } + if (ret < 0) + aw_dev_err(aw_dev->dev, "check fail"); + else + aw_dev_info(aw_dev->dev, "done"); + + return ret; +} + +int aw882xx_dev_get_fade_vol_step(struct aw_device *aw_dev) +{ + return aw_dev->vol_step; +} + +void aw882xx_dev_set_fade_vol_step(struct aw_device *aw_dev, unsigned int step) +{ + aw_dev->vol_step = step; +} + +void aw882xx_dev_get_fade_time(unsigned int *time, bool fade_in) +{ + if (fade_in) + *time = g_fade_in_time; + else + *time = g_fade_out_time; +} + +void aw882xx_dev_set_fade_time(unsigned int time, bool fade_in) +{ + if (fade_in) + g_fade_in_time = time; + else + g_fade_out_time = time; +} + +/*init aw_device*/ +void aw882xx_dev_deinit(struct aw_device *aw_dev) +{ + if (aw_dev == NULL) + return; + + if (aw_dev->prof_info.prof_desc != NULL) { + kfree(aw_dev->prof_info.prof_desc); + aw_dev->prof_info.prof_desc = NULL; + aw_dev->prof_info.count = 0; + } +} + +int aw882xx_dev_get_cali_re(struct aw_device *aw_dev, int32_t *cali_re) +{ + + return aw882xx_dsp_read_cali_re(aw_dev, cali_re); +} + +int aw882xx_dev_dc_status(struct aw_device *aw_dev) +{ + return aw882xx_dsp_get_dc_status(aw_dev); +} + +int aw882xx_dev_status(struct aw_device *aw_dev) +{ + return aw_dev->status; +} + +int aw882xx_dev_init_cali_re(struct aw_device *aw_dev) +{ + int ret = 0; + struct aw_cali_desc *cali_desc = &aw_dev->cali_desc; + + if (cali_desc->mode) { + if (cali_desc->cali_re == AW_ERRO_CALI_VALUE) { + ret = aw882xx_cali_read_re_from_nvram(&cali_desc->cali_re, aw_dev->channel); + if (ret) { + aw_dev_info(aw_dev->dev, "read nvram cali failed, use default Re"); + cali_desc->cali_re = AW_ERRO_CALI_VALUE; + cali_desc->cali_result = CALI_RESULT_NONE; + return 0; + } + + if (cali_desc->cali_re < aw_dev->re_min || + cali_desc->cali_re > aw_dev->re_max) { + aw_dev_err(aw_dev->dev, "out range re value: %d", + cali_desc->cali_re); + cali_desc->cali_re = AW_ERRO_CALI_VALUE; + /*cali_result is error when aw-cali-check enable*/ + if (aw_dev->cali_desc.cali_check_st) + cali_desc->cali_result = CALI_RESULT_ERROR; + + return -EINVAL; + } + + aw_dev_dbg(aw_dev->dev, "read re value: %d", cali_desc->cali_re); + + if (aw_dev->cali_desc.cali_check_st) + cali_desc->cali_result = CALI_RESULT_NORMAL; + + } + } else { + aw_dev_info(aw_dev->dev, "no cali, needn't init cali re"); + } + return ret; +} + +static void aw_dev_soft_reset(struct aw_device *aw_dev) +{ + struct aw_soft_rst *reset = &aw_dev->soft_rst; + + aw_dev->ops.aw_i2c_write(aw_dev, reset->reg, reset->reg_value); + aw_dev_info(aw_dev->dev, "soft reset done"); +} + +int aw882xx_device_irq_reinit(struct aw_device *aw_dev) +{ + int ret; + + /*reg re load*/ + ret = aw_dev_reg_fw_update(aw_dev); + if (ret < 0) + return ret; + + return 0; +} + +int aw882xx_device_init(struct aw_device *aw_dev, struct aw_container *aw_cfg) +{ + /*acf_hdr_t *hdr;*/ + int ret; + + if (aw_cfg == NULL) { + aw_dev_err(aw_dev->dev, "aw_cfg is NULL"); + return -ENOMEM; + } + + ret = aw882xx_dev_parse_acf(aw_dev, aw_cfg); + if (ret) { + aw882xx_dev_deinit(aw_dev); + aw_dev_err(aw_dev->dev, "aw_dev acf load failed"); + return -EINVAL; + } + + aw_dev_soft_reset(aw_dev); + + aw_dev->cur_prof = AW_INIT_PROFILE; + aw_dev->set_prof = AW_INIT_PROFILE; + ret = aw_dev_reg_fw_update(aw_dev); + if (ret < 0) + return ret; + + if (aw_dev->ops.aw_frcset_check) { + ret = aw_dev->ops.aw_frcset_check(aw_dev); + if (ret) + return ret; + } + + aw_dev->status = AW_DEV_PW_ON; + aw882xx_device_stop(aw_dev); + + aw_dev_info(aw_dev->dev, "init done"); + return 0; +} + +int aw882xx_dev_reg_update(struct aw_device *aw_dev, bool force) +{ + int ret; + + if (force) { + aw_dev_soft_reset(aw_dev); + ret = aw_dev_reg_fw_update(aw_dev); + if (ret < 0) + return ret; + } else { + if (aw_dev->cur_prof != aw_dev->set_prof) { + ret = aw_dev_reg_fw_update(aw_dev); + if (ret < 0) + return ret; + } + } + + aw_dev->cur_prof = aw_dev->set_prof; + + aw_dev_info(aw_dev->dev, "done"); + return 0; +} + +static void aw_dev_cali_re_update(struct aw_device *aw_dev) +{ + struct aw_cali_desc *desc = &aw_dev->cali_desc; + + if (desc->mode && (desc->cali_re != AW_ERRO_CALI_VALUE)) { + if ((desc->cali_re >= aw_dev->re_min) && + (desc->cali_re <= aw_dev->re_max)) + aw882xx_dsp_write_cali_re(aw_dev, desc->cali_re); + else + aw_dev_err(aw_dev->dev, "cali re is out of range"); + } +} + +static void aw_dev_boost_type_set(struct aw_device *aw_dev) +{ + struct aw_profctrl_desc *profctrl_desc = &aw_dev->profctrl_desc; + struct aw_bstctrl_desc *bstctrl_desc = &aw_dev->bstctrl_desc; + + aw_dev_dbg(aw_dev->dev, "enter"); + + if (aw_dev->bstcfg_enable) { + /*set spk mode*/ + aw_dev->ops.aw_i2c_write_bits(aw_dev, profctrl_desc->reg, + profctrl_desc->mask, profctrl_desc->spk_mode); + + /*force boost*/ + aw_dev->ops.aw_i2c_write_bits(aw_dev, bstctrl_desc->reg, + bstctrl_desc->mask, bstctrl_desc->frc_bst); + + aw_dev_dbg(aw_dev->dev, "boost type set done"); + } +} + +static void aw_dev_boost_type_recover(struct aw_device *aw_dev) +{ + + struct aw_profctrl_desc *profctrl_desc = &aw_dev->profctrl_desc; + struct aw_bstctrl_desc *bstctrl_desc = &aw_dev->bstctrl_desc; + + aw_dev_dbg(aw_dev->dev, "enter"); + + if (aw_dev->bstcfg_enable) { + /*set transprant*/ + aw_dev->ops.aw_i2c_write_bits(aw_dev, bstctrl_desc->reg, + bstctrl_desc->mask, bstctrl_desc->tsp_type); + + usleep_range(AW_5000_US, AW_5000_US + 50); + /*set cfg boost type*/ + aw_dev->ops.aw_i2c_write_bits(aw_dev, bstctrl_desc->reg, + bstctrl_desc->mask, bstctrl_desc->cfg_bst_type); + + /*set cfg prof mode*/ + aw_dev->ops.aw_i2c_write_bits(aw_dev, profctrl_desc->reg, + profctrl_desc->mask, profctrl_desc->cfg_prof_mode); + + aw_dev_dbg(aw_dev->dev, "boost type recover done"); + } +} + +static void aw_dev_i2s_enable(struct aw_device *aw_dev, bool flag) +{ + struct aw_txen_desc *txen_desc = &aw_dev->txen_desc; + struct aw_cali_desc *cali_desc = &aw_dev->cali_desc; + + aw_dev_dbg(aw_dev->dev, "enter, i2s_enable: %d", flag); + + if (txen_desc->reg == AW_REG_NONE) { + aw_dev_info(aw_dev->dev, "needn't set i2s status"); + return; + } + + if (flag) { + if (cali_desc->mode == AW_CALI_MODE_NONE) + aw_dev->ops.aw_i2c_write_bits(aw_dev, + txen_desc->reg, txen_desc->mask, txen_desc->reserve_val); + else + aw_dev->ops.aw_i2c_write_bits(aw_dev, + txen_desc->reg, txen_desc->mask, txen_desc->enable); + } else { + aw_dev->ops.aw_i2c_write_bits(aw_dev, + txen_desc->reg, txen_desc->mask, txen_desc->disable); + } +} + + +int aw882xx_device_start(struct aw_device *aw_dev) +{ + int ret; + struct aw_dither_desc *dither_desc = &aw_dev->dither_desc; + + aw_dev_dbg(aw_dev->dev, "enter"); + + if (aw_dev->status == AW_DEV_PW_ON) { + aw_dev_info(aw_dev->dev, "already power on"); + return 0; + } + + /*set froce boost*/ + aw_dev_boost_type_set(aw_dev); + + aw_dev_set_dither(aw_dev, false); + + /*power on*/ + aw_dev_pwd(aw_dev, false); + usleep_range(AW_2000_US, AW_2000_US + 10); + + ret = aw_dev_syspll_check(aw_dev); + if (ret < 0) { + aw_dev_reg_dump(aw_dev); + aw_dev_pwd(aw_dev, true); + aw_dev_dbg(aw_dev->dev, "pll check failed cannot start"); + return ret; + } + + /*amppd on*/ + aw_dev_amppd(aw_dev, false); + usleep_range(AW_1000_US, AW_1000_US + 50); + + /*check i2s status*/ + ret = aw_dev_sysst_check(aw_dev); + if (ret < 0) { + aw_dev_reg_dump(aw_dev); + /*close tx feedback*/ + aw_dev_i2s_enable(aw_dev, false); + /*clear interrupt*/ + aw882xx_dev_clear_int_status(aw_dev); + /*close amppd*/ + aw_dev_amppd(aw_dev, true); + /*power down*/ + aw_dev_pwd(aw_dev, true); + return -EINVAL; + } + + /*boost type recover*/ + aw_dev_boost_type_recover(aw_dev); + + /*enable tx feedback*/ + if (aw_dev->txen_st) + aw_dev_i2s_enable(aw_dev, true); + + if (aw_dev->amppd_st) + aw_dev_amppd(aw_dev, true); + + + if (aw_dev->ops.aw_reg_force_set) + aw_dev->ops.aw_reg_force_set(aw_dev); + + /*close uls hmute*/ + aw_dev_uls_hmute(aw_dev, false); + + if (aw_dev->dither_st == dither_desc->enable) + aw_dev_set_dither(aw_dev, true); + + + if (!aw_dev->mute_st) { + /*close mute*/ + if (aw882xx_cali_check_result(&aw_dev->cali_desc)) + aw882xx_dev_mute(aw_dev, false); + else + aw882xx_dev_mute(aw_dev, true); + } + + /*clear inturrupt*/ + aw882xx_dev_clear_int_status(aw_dev); + /*set inturrupt mask*/ + aw882xx_dev_set_intmask(aw_dev, true); + + aw882xx_monitor_start(&aw_dev->monitor_desc); + aw_dev_cali_re_update(aw_dev); +#ifdef AW_ALGO_AUTH_DSP + aw882xx_dev_algo_authentication(aw_dev); +#endif + aw_dev->status = AW_DEV_PW_ON; + aw_dev_info(aw_dev->dev, "done"); + return 0; +} + +int aw882xx_device_stop(struct aw_device *aw_dev) +{ + aw_dev_dbg(aw_dev->dev, "enter"); + + if (aw_dev->status == AW_DEV_PW_OFF) { + aw_dev_dbg(aw_dev->dev, "already power off"); + return 0; + } + + aw_dev->status = AW_DEV_PW_OFF; + + aw882xx_monitor_stop(&aw_dev->monitor_desc); + /*clear interrupt*/ + aw882xx_dev_clear_int_status(aw_dev); + + /*set defaut int mask*/ + aw882xx_dev_set_intmask(aw_dev, false); + + /*set uls hmute*/ + aw_dev_uls_hmute(aw_dev, true); + + /*set mute*/ + aw882xx_dev_mute(aw_dev, true); + + usleep_range(AW_5000_US, AW_5000_US + 10); + + /*close tx feedback*/ + aw_dev_i2s_enable(aw_dev, false); + + usleep_range(AW_1000_US, AW_1000_US + 100); + + /*enable amppd*/ + aw_dev_amppd(aw_dev, true); + + /*set power down*/ + aw_dev_pwd(aw_dev, true); + + ext_dsp_prof_write = AW_EXT_DSP_WRITE_NONE; + aw_dev_info(aw_dev->dev, "done"); + return 0; +} + +int aw882xx_dev_set_afe_module_en(int type, int enable) +{ + return aw882xx_dsp_set_afe_module_en(type, enable); +} + +int aw882xx_dev_get_afe_module_en(int type, int *status) +{ + return aw882xx_dsp_get_afe_module_en(type, status); +} + +int aw882xx_dev_set_copp_module_en(bool enable) +{ + return aw882xx_dsp_set_copp_module_en(enable); +} + +static int aw_device_parse_sound_channel_dt(struct aw_device *aw_dev) +{ + int ret = 0; + uint32_t channel_value = 0; + struct list_head *dev_list = NULL; + struct list_head *pos = NULL; + struct aw_device *local_dev = NULL; + + ret = of_property_read_u32(aw_dev->dev->of_node, "sound-channel", &channel_value); + if (ret < 0) { + channel_value = AW_DEV_CH_PRI_L; + aw_dev_info(aw_dev->dev, "read sound-channel failed,use default"); + } + + aw_dev_info(aw_dev->dev, "read sound-channel value is : %d", channel_value); + if (channel_value >= AW_DEV_CH_MAX) + channel_value = AW_DEV_CH_PRI_L; + + /* when dev_num > 0, get dev list to compare*/ + if (aw_dev->ops.aw_get_dev_num() > 0) { + ret = aw882xx_dev_get_list_head(&dev_list); + if (ret) { + aw_dev_err(aw_dev->dev, "get dev list failed"); + return ret; + } + + list_for_each(pos, dev_list) { + local_dev = container_of(pos, struct aw_device, list_node); + if (local_dev->channel == channel_value) { + aw_dev_err(local_dev->dev, "sound-channel:%d already exists", + channel_value); + return -EINVAL; + } + } + } + + aw_dev->channel = channel_value; + + return 0; + +} + +static void aw_device_parse_fade_flag_dt(struct aw_device *aw_dev) +{ + int ret; + uint32_t fade_en = 0; + + ret = of_property_read_u32(aw_dev->dev->of_node, "fade-flag", &fade_en); + if (ret < 0) + aw_dev_info(aw_dev->dev, "read fade-flag failed,use default"); + + + aw_dev->fade_en = fade_en; + aw_dev_info(aw_dev->dev, "fade-flag: %d", fade_en); + +} + +static int aw_device_parse_dt(struct aw_device *aw_dev) +{ + int ret = 0; + + ret = aw_device_parse_sound_channel_dt(aw_dev); + if (ret) { + aw_dev_err(aw_dev->dev, "parse sound-channel failed!"); + return ret; + } + aw882xx_device_parse_topo_id_dt(aw_dev); + aw882xx_device_parse_port_id_dt(aw_dev); + aw_device_parse_fade_flag_dt(aw_dev); + + return ret; +} + +int aw882xx_dev_get_list_head(struct list_head **head) +{ + if (list_empty(&g_dev_list)) + return -EINVAL; + + *head = &g_dev_list; + + return 0; +} + +int aw882xx_device_probe(struct aw_device *aw_dev) +{ + int ret = 0; + + INIT_LIST_HEAD(&aw_dev->list_node); + + ret = aw_device_parse_dt(aw_dev); + if (ret) + return ret; + + if (aw_dev->channel == 0) + aw882xx_algo_auth_misc_init(aw_dev); + + ret = aw882xx_cali_init(&aw_dev->cali_desc); + if (ret) + return ret; + + aw882xx_monitor_init(&aw_dev->monitor_desc); + /*aw_afe_init();*/ + + ret = aw882xx_spin_init(&aw_dev->spin_desc); + if (ret) + return ret; + + mutex_lock(&g_dev_lock); + list_add(&aw_dev->list_node, &g_dev_list); + mutex_unlock(&g_dev_lock); + + return 0; +} + +int aw882xx_device_remove(struct aw_device *aw_dev) +{ + aw882xx_monitor_deinit(&aw_dev->monitor_desc); + aw882xx_cali_deinit(&aw_dev->cali_desc); + if (aw_dev->channel == 0) + aw882xx_algo_auth_misc_deinit(aw_dev); + /*aw_afe_deinit();*/ + return 0; +} + diff --git a/sound/soc/codecs/aw882xx/aw882xx_device.h b/sound/soc/codecs/aw882xx/aw882xx_device.h new file mode 100644 index 000000000000..78c7efb31836 --- /dev/null +++ b/sound/soc/codecs/aw882xx/aw882xx_device.h @@ -0,0 +1,463 @@ +/* SPDX-License-Identifier: GPL-2.0 + * aw882xx_device.h + * + * Copyright (c) 2020 AWINIC Technology CO., LTD + * + * Author: Nick Li + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#ifndef __AW882XX_DEVICE_FILE_H__ +#define __AW882XX_DEVICE_FILE_H__ +#include "aw882xx_data_type.h" +#include "aw882xx_calib.h" +#include "aw882xx_monitor.h" +#include "aw882xx_dsp.h" + +#define AW_VOLUME_STEP_DB (6 * 2) +#define AW_REG_NONE (0xFF) +#define AW_NAME_MAX (50) +#define ALGO_VERSION_MAX (80) + +#define AW_GET_MIN_VALUE(value1, value2) \ + ((value1) > (value2) ? (value2) : (value1)) + +#define AW_GET_MAX_VALUE(value1, value2) \ + ((value1) > (value2) ? (value1) : (value2)) + +extern int g_algo_auth_st; + +enum { + AW_1000_US = 1000, + AW_2000_US = 2000, + AW_3000_US = 3000, + AW_4000_US = 4000, + AW_5000_US = 5000, + AW_10000_US = 10000, + AW_32000_US = 32000, + AW_70000_US = 70000, + AW_100000_US = 100000, +}; + +struct aw_device; + +enum { + AW_DEV_TYPE_NONE = 0, + AW_DEV_TYPE_OK, +}; + +enum { + AW_EF_AND_CHECK = 0, + AW_EF_OR_CHECK, +}; + +enum { + AW_DEV_CH_PRI_L = 0, + AW_DEV_CH_PRI_R = 1, + AW_DEV_CH_SEC_L = 2, + AW_DEV_CH_SEC_R = 3, + AW_DEV_CH_TERT_L = 4, + AW_DEV_CH_TERT_R = 5, + AW_DEV_CH_QUAT_L = 6, + AW_DEV_CH_QUAT_R = 7, + AW_DEV_CH_MAX, +}; + +enum AW_DEV_INIT { + AW_DEV_INIT_ST = 0, + AW_DEV_INIT_OK = 1, + AW_DEV_INIT_NG = 2, +}; + +enum AW_DEV_STATUS { + AW_DEV_PW_OFF = 0, + AW_DEV_PW_ON, +}; + +enum AW_DEV_FW_STATUS { + AW_DEV_FW_FAILED = 0, + AW_DEV_FW_OK, +}; + + +enum { + AW_EXT_DSP_WRITE_NONE = 0, + AW_EXT_DSP_WRITE, +}; + +enum AW_SPIN_KCONTROL_STATUS { + AW_SPIN_KCONTROL_DISABLE = 0, + AW_SPIN_KCONTROL_ENABLE, +}; + +enum AW_ALGO_AUTH_MODE { + AW_ALGO_AUTH_DISABLE = 0, + AW_ALGO_AUTH_MODE_MAGIC_ID, + AW_ALGO_AUTH_MODE_REG_CRC, +}; + +enum AW_ALGO_AUTH_ID { + AW_ALGO_AUTH_MAGIC_ID = 0x4157, +}; + +enum AW_ALGO_AUTH_STATUS { + AW_ALGO_AUTH_WAIT = 0, + AW_ALGO_AUTH_OK = 1, +}; + +struct aw_device_ops { + int (*aw_i2c_write)(struct aw_device *aw_dev, unsigned char reg_addr, unsigned int reg_data); + int (*aw_i2c_read)(struct aw_device *aw_dev, unsigned char reg_addr, unsigned int *reg_data); + int (*aw_i2c_write_bits)(struct aw_device *aw_dev, unsigned char reg_addr, unsigned int mask, unsigned int reg_data); + int (*aw_set_hw_volume)(struct aw_device *aw_dev, unsigned int value); + int (*aw_get_hw_volume)(struct aw_device *aw_dev, unsigned int *value); + unsigned int (*aw_reg_val_to_db)(unsigned int value); + bool (*aw_check_wr_access)(int reg); + bool (*aw_check_rd_access)(int reg); + int (*aw_get_reg_num)(void); + int (*aw_get_version)(char *buf, int size); + int (*aw_get_dev_num)(void); + void (*aw_set_algo)(struct aw_device *aw_dev); + unsigned int (*aw_get_irq_type)(struct aw_device *aw_dev, unsigned int value); + void (*aw_reg_force_set)(struct aw_device *aw_dev); + int (*aw_frcset_check)(struct aw_device *aw_dev); +}; + +struct aw_int_desc { + unsigned int mask_reg; /*interrupt mask reg*/ + unsigned int st_reg; /*interrupt status reg*/ + unsigned int mask_default; /*default mask close all*/ + unsigned int int_mask; /*set mask*/ +}; + +struct aw_work_mode { + unsigned int reg; + unsigned int mask; + unsigned int spk_val; + unsigned int rcv_val; +}; + +struct aw_soft_rst { + int reg; + int reg_value; +}; + +struct aw_pwd_desc { + unsigned int reg; + unsigned int mask; + unsigned int enable; + unsigned int disable; +}; + +struct aw_amppd_desc { + unsigned int reg; + unsigned int mask; + unsigned int enable; + unsigned int disable; +}; + +struct aw_bop_desc { + unsigned int reg; + unsigned int mask; + unsigned int enable; + unsigned int disbale; +}; + +struct aw_vcalb_desc { + unsigned int icalk_reg; + unsigned int icalk_reg_mask; + unsigned int icalk_shift; + unsigned int icalkl_reg; + unsigned int icalkl_reg_mask; + unsigned int icalkl_shift; + unsigned int icalk_sign_mask; + unsigned int icalk_neg_mask; + int icalk_value_factor; + + unsigned int vcalk_reg; + unsigned int vcalk_reg_mask; + unsigned int vcalk_shift; + unsigned int vcalkl_reg; + unsigned int vcalkl_reg_mask; + unsigned int vcalkl_shift; + unsigned int vcalk_sign_mask; + unsigned int vcalk_neg_mask; + int vcalk_value_factor; + + unsigned int vcalb_reg; + int cabl_base_value; + int vcal_factor; +}; + +struct aw_mute_desc { + unsigned int reg; + unsigned int mask; + unsigned int enable; + unsigned int disable; +}; + +struct aw_uls_hmute_desc { + unsigned int reg; + unsigned int mask; + unsigned int enable; + unsigned int disable; +}; + +struct aw_txen_desc { + unsigned int reg; + unsigned int mask; + unsigned int enable; + unsigned int disable; + unsigned int reserve_val; +}; + +struct aw_sysst_desc { + unsigned int reg; + unsigned int mask; + unsigned int st_check; + unsigned int st_sws_check; + unsigned int pll_check; +}; + +struct aw_profctrl_desc { + unsigned int reg; + unsigned int mask; + unsigned int spk_mode; + unsigned int cfg_prof_mode; +}; + +struct aw_bstctrl_desc { + unsigned int reg; + unsigned int mask; + unsigned int frc_bst; + unsigned int tsp_type; + unsigned int cfg_bst_type; +}; + +struct aw_cco_mux_desc { + unsigned int reg; + unsigned int mask; + unsigned int divided_val; + unsigned int bypass_val; +}; + +struct aw_volume_desc { + unsigned int reg; + unsigned int mask; + unsigned int shift; + int init_volume; + int mute_volume; + int ctl_volume; + int monitor_volume; +}; + +struct aw_voltage_desc { + unsigned int reg; + unsigned int vbat_range; + unsigned int int_bit; +}; + +struct aw_temperature_desc { + unsigned int reg; + unsigned int sign_mask; + unsigned int neg_mask; +}; + +struct aw_ipeak_desc { + unsigned int reg; + unsigned int mask; +}; + +struct aw_spin_ch { + uint16_t rx_val; +}; + +struct aw_reg_ch { + unsigned int reg; + unsigned int mask; + unsigned int left_val; + unsigned int right_val; +}; + +struct aw_spin_desc { + int aw_spin_kcontrol_st; + struct aw_spin_ch spin_table[AW_SPIN_MAX]; + struct aw_reg_ch rx_desc; +}; + +struct aw_efcheck_desc { + unsigned int reg; + unsigned int mask; + unsigned int and_val; + unsigned int or_val; +}; + +struct aw_dither_desc { + unsigned int reg; + unsigned int mask; + unsigned int enable; + unsigned int disable; +}; + +struct aw_noise_gate_desc { + unsigned int reg; + unsigned int mask; +}; + +struct aw_psm_desc { + unsigned int reg; + unsigned int mask; + unsigned int enable; + unsigned int disable; +}; + +struct aw_mpd_desc { + unsigned int reg; + unsigned int mask; + unsigned int enable; + unsigned int disable; +}; + +struct aw_dsmzth_desc { + unsigned int reg; + unsigned int mask; + unsigned int enable; + unsigned int disable; +}; + +struct aw_auth_desc { + uint8_t reg_in; + uint8_t reg_out; + int32_t auth_mode; + int32_t reg_crc; + int32_t random; + int32_t chip_id; + int32_t check_result; +}; + +struct algo_auth_data { + int32_t auth_mode; /* 0: disable 1 : chip ID 2 : reg crc */ + int32_t reg_crc; + int32_t random; + int32_t chip_id; + int32_t check_result; +}; + +#define AW_IOCTL_MAGIC_S 'w' +#define AW_IOCTL_GET_ALGO_AUTH _IOWR(AW_IOCTL_MAGIC_S, 1, struct algo_auth_data) +#define AW_IOCTL_SET_ALGO_AUTH _IOWR(AW_IOCTL_MAGIC_S, 2, struct algo_auth_data) + + +struct aw_device { + int status; + unsigned int chip_id; + unsigned int monitor_start; + int bstcfg_enable; + int frcset_en; + int bop_en; + int efuse_check; + int fade_en; + unsigned int mute_st; + unsigned int amppd_st; + unsigned int dither_st; + unsigned int txen_st; + + unsigned char cur_prof; /*current profile index*/ + unsigned char set_prof; /*set profile index*/ + unsigned int channel; /*pa channel select*/ + unsigned int vol_step; + unsigned int re_max; + unsigned int re_min; + + struct device *dev; + struct i2c_client *i2c; + char monitor_name[AW_NAME_MAX]; + void *private_data; + + struct aw_int_desc int_desc; + struct aw_work_mode work_mode; + struct aw_pwd_desc pwd_desc; + struct aw_amppd_desc amppd_desc; + struct aw_mute_desc mute_desc; + struct aw_uls_hmute_desc uls_hmute_desc; + struct aw_txen_desc txen_desc; + struct aw_vcalb_desc vcalb_desc; + struct aw_sysst_desc sysst_desc; + struct aw_profctrl_desc profctrl_desc; + struct aw_bstctrl_desc bstctrl_desc; + struct aw_cco_mux_desc cco_mux_desc; + struct aw_voltage_desc voltage_desc; + struct aw_temperature_desc temp_desc; + struct aw_ipeak_desc ipeak_desc; + struct aw_volume_desc volume_desc; + struct aw_prof_info prof_info; + struct aw_cali_desc cali_desc; + struct aw_monitor_desc monitor_desc; + struct aw_soft_rst soft_rst; + struct aw_spin_desc spin_desc; + struct aw_bop_desc bop_desc; + struct aw_efcheck_desc efcheck_desc; + struct aw_dither_desc dither_desc; + struct aw_noise_gate_desc noise_gate_desc; + struct aw_psm_desc psm_desc; + struct aw_mpd_desc mpd_desc; + struct aw_dsmzth_desc dsmzth_desc; + struct aw_auth_desc auth_desc; + struct aw_device_ops ops; + struct list_head list_node; +}; + + +void aw882xx_dev_deinit(struct aw_device *aw_dev); +int aw882xx_device_init(struct aw_device *aw_dev, struct aw_container *aw_cfg); +int aw882xx_device_start(struct aw_device *aw_dev); +int aw882xx_device_stop(struct aw_device *aw_dev); +int aw882xx_dev_reg_update(struct aw_device *aw_dev, bool force); +int aw882xx_device_irq_reinit(struct aw_device *aw_dev); + +struct mutex *aw882xx_dev_get_ext_dsp_prof_wr_lock(void); +char *aw882xx_dev_get_ext_dsp_prof_write(void); + +/*re*/ +int aw882xx_dev_get_cali_re(struct aw_device *aw_dev, int32_t *cali_re); +int aw882xx_dev_init_cali_re(struct aw_device *aw_dev); +int aw882xx_dev_dc_status(struct aw_device *aw_dev); + +/*interrupt*/ +int aw882xx_dev_status(struct aw_device *aw_dev); +int aw882xx_dev_get_int_status(struct aw_device *aw_dev, uint16_t *int_status); +void aw882xx_dev_clear_int_status(struct aw_device *aw_dev); +int aw882xx_dev_set_intmask(struct aw_device *aw_dev, bool flag); + +/*fade int / out*/ +void aw882xx_dev_set_fade_vol_step(struct aw_device *aw_dev, unsigned int step); +int aw882xx_dev_get_fade_vol_step(struct aw_device *aw_dev); +void aw882xx_dev_get_fade_time(unsigned int *time, bool fade_in); +void aw882xx_dev_set_fade_time(unsigned int time, bool fade_in); + +/*dsp kcontrol*/ +int aw882xx_dev_set_afe_module_en(int type, int enable); +int aw882xx_dev_get_afe_module_en(int type, int *status); +int aw882xx_dev_set_copp_module_en(bool enable); + +int aw882xx_device_probe(struct aw_device *aw_dev); +int aw882xx_device_remove(struct aw_device *aw_dev); +int aw882xx_dev_get_list_head(struct list_head **head); + +int aw882xx_dev_set_volume(struct aw_device *aw_dev, unsigned int set_vol); +int aw882xx_dev_get_volume(struct aw_device *aw_dev, unsigned int *get_vol); +void aw882xx_dev_mute(struct aw_device *aw_dev, bool mute); + + +void aw882xx_dev_monitor_hal_get_time(struct aw_device *aw_dev, uint32_t *time); +void aw882xx_dev_monitor_hal_work(struct aw_device *aw_dev, uint32_t *vmax); + +int aw882xx_dev_algo_auth_mode(struct aw_device *aw_dev, struct algo_auth_data *algo_data); +void aw882xx_dev_iv_forbidden_output(struct aw_device *aw_dev, bool power_waste); + +#endif + diff --git a/sound/soc/codecs/aw882xx/aw882xx_dsp.c b/sound/soc/codecs/aw882xx/aw882xx_dsp.c new file mode 100644 index 000000000000..0083c261fc16 --- /dev/null +++ b/sound/soc/codecs/aw882xx/aw882xx_dsp.c @@ -0,0 +1,1309 @@ +// SPDX-License-Identifier: GPL-2.0 +/* aw882xx_dsp.c + * + * Copyright (c) 2020 AWINIC Technology CO., LTD + * + * Author: Nick Li + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +/*#define DEBUG*/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "aw882xx_device.h" +#include "aw882xx_dsp.h" +#include "aw882xx_log.h" +/*#include "aw882xx_afe.h"*/ + +static DEFINE_MUTEX(g_aw_dsp_msg_lock); +static DEFINE_MUTEX(g_aw_dsp_lock); + +#define AW_MSG_ID_ENABLE_CALI (0x00000001) +#define AW_MSG_ID_ENABLE_HMUTE (0x00000002) +#define AW_MSG_ID_F0_Q (0x00000003) +#define AW_MSG_ID_DIRECT_CUR_FLAG (0x00000006) +#define AW_MSG_ID_SPK_STATUS (0x00000007) +#define AW_MSG_ID_VERSION (0x00000008) +#define AW_MSG_ID_AUDIO_MIX (0x0000000B) +#define AW_MSG_ID_VERSION_NEW (0x00000012) + +/*dsp params id*/ +#define AW_MSG_ID_RX_SET_ENABLE (0x10013D11) +#define AW_MSG_ID_TX_SET_ENABLE (0x10013D13) +#define AW_MSG_ID_VMAX_L (0x10013D17) +#define AW_MSG_ID_VMAX_R (0x10013D18) +#define AW_MSG_ID_CALI_CFG_L (0x10013D19) +#define AW_MSG_ID_CALI_CFG_R (0x10013d1A) +#define AW_MSG_ID_RE_L (0x10013d1B) +#define AW_MSG_ID_RE_R (0x10013D1C) +#define AW_MSG_ID_NOISE_L (0x10013D1D) +#define AW_MSG_ID_NOISE_R (0x10013D1E) +#define AW_MSG_ID_F0_L (0x10013D1F) +#define AW_MSG_ID_F0_R (0x10013D20) +#define AW_MSG_ID_REAL_DATA_L (0x10013D21) +#define AW_MSG_ID_REAL_DATA_R (0x10013D22) +#define AW_MSG_ID_ALGO_AUTHENTICATION (0x10013D46) + +#define AFE_MSG_ID_MSG_0 (0x10013D2A) +#define AFE_MSG_ID_MSG_1 (0x10013D2B) +#define AFE_MSG_ID_MSG_2 (0x10013D36) +#define AFE_MSG_ID_MSG_3 (0x10013D33) + +#define AW_MSG_ID_PARAMS (0x10013D12) +#define AW_MSG_ID_PARAMS_1 (0x10013D2D) +#define AW_MSG_ID_PARAMS_2 (0x10013D32) +#define AW_MSG_ID_PARAMS_3 (0x10013D35) +#define AW_MSG_ID_PARAMS_DEFAULT (0x10013D37) + +#define AW_MSG_ID_SPIN (0x10013D2E) + +static int g_tx_topo_id = AW_TX_DEFAULT_TOPO_ID; +static int g_rx_topo_id = AW_RX_DEFAULT_TOPO_ID; +static int g_tx_port_id = AW_TX_DEFAULT_PORT_ID; +static int g_rx_port_id = AW_RX_DEFAULT_PORT_ID; + +enum { + MSG_PARAM_ID_0 = 0, + MSG_PARAM_ID_1, + MSG_PARAM_ID_2, + MSG_PARAM_ID_3, + MSG_PARAM_ID_MAX, +}; + +static uint32_t afe_param_msg_id[MSG_PARAM_ID_MAX] = { + AFE_MSG_ID_MSG_0, + AFE_MSG_ID_MSG_1, + AFE_MSG_ID_MSG_2, + AFE_MSG_ID_MSG_3, +}; + +/***************dsp communicate**************/ +#ifdef AW_QCOM_PLATFORM +#if (KERNEL_VERSION(4, 4, 1) <= LINUX_VERSION_CODE) +#include +#include +#include +#include +#else +#include +#include +#include +#include +#include +#endif +#endif + +#define AW_COPP_MODULE_ID (0X10013D02) /*SKT module id*/ +#define AW_COPP_PARAMS_ID_AWDSP_ENABLE (0X10013D14) /*SKT enable param id*/ + +#ifdef AW_MTK_PLATFORM_WITH_DSP +extern int mtk_spk_send_ipi_buf_to_dsp(void *data_buffer, uint32_t data_size); +extern int mtk_spk_recv_ipi_buf_from_dsp(int8_t *buffer, int16_t size, uint32_t *buf_len); +#elif defined AW_QCOM_PLATFORM +extern int afe_get_topology(int port_id); +extern int aw_send_afe_cal_apr(uint32_t param_id, + void *buf, int cmd_size, bool write); +extern int aw_send_afe_rx_module_enable(void *buf, int size); +extern int aw_send_afe_tx_module_enable(void *buf, int size); +#else +static int aw_send_afe_cal_apr(uint32_t param_id, + void *buf, int cmd_size, bool write) +{ + return 0; +} +static int aw_send_afe_rx_module_enable(void *buf, int size) +{ + return 0; +} +static int aw_send_afe_tx_module_enable(void *buf, int size) +{ + return 0; +} +static int afe_get_topology(int port_id) +{ + return 0; +} + +#endif + +#ifdef AW_QCOM_PLATFORM +extern void aw_set_port_id(int tx_port_id, int rx_port_id); +#else +static void aw_set_port_id(int tx_port_id, int rx_port_id) +{ + +} +#endif + +static int aw_adm_param_enable(int port_id, int module_id, int param_id, int enable) +{ +#ifdef AW_QCOM_ADM_MSG + /*for v3*/ + int copp_idx = 0; + uint32_t enable_param; + struct param_hdr_v3 param_hdr; + int rc = 0; + + aw_pr_dbg("port_id %d, module_id 0x%x, enable %d", + port_id, module_id, enable); + + copp_idx = adm_get_default_copp_idx(port_id); + if (copp_idx < 0 || copp_idx >= MAX_COPPS_PER_PORT) { + aw_pr_err("Invalid copp_num: %d", copp_idx); + return -EINVAL; + } + + if (enable < 0 || enable > 1) { + aw_pr_err("Invalid value for enable %d", enable); + return -EINVAL; + } + + aw_pr_dbg("port_id %d, module_id 0x%x, copp_idx 0x%x, enable %d", + port_id, module_id, copp_idx, enable); + + memset(¶m_hdr, 0, sizeof(param_hdr)); + param_hdr.module_id = module_id; + param_hdr.instance_id = INSTANCE_ID_0; + param_hdr.param_id = param_id; + param_hdr.param_size = sizeof(enable_param); + enable_param = enable; + + rc = adm_pack_and_set_one_pp_param(port_id, copp_idx, param_hdr, + (uint8_t *) &enable_param); + if (rc) + aw_pr_err("Failed to set enable of module(%d) instance(%d) to %d, err %d", + module_id, INSTANCE_ID_0, enable, rc); + return rc; +#else + return 0; +#endif +} + +static int aw_dsp_get_msg_num(int dev_ch, int *msg_num) +{ + switch (dev_ch) { + case AW_DEV_CH_PRI_L: + *msg_num = MSG_PARAM_ID_0; + break; + case AW_DEV_CH_PRI_R: + *msg_num = MSG_PARAM_ID_0; + break; + case AW_DEV_CH_SEC_L: + *msg_num = MSG_PARAM_ID_1; + break; + case AW_DEV_CH_SEC_R: + *msg_num = MSG_PARAM_ID_1; + break; + case AW_DEV_CH_TERT_L: + *msg_num = MSG_PARAM_ID_2; + break; + case AW_DEV_CH_TERT_R: + *msg_num = MSG_PARAM_ID_2; + break; + case AW_DEV_CH_QUAT_L: + *msg_num = MSG_PARAM_ID_3; + break; + case AW_DEV_CH_QUAT_R: + *msg_num = MSG_PARAM_ID_3; + break; + default: + aw_pr_err("can not find msg num, channel %d ", dev_ch); + return -EINVAL; + } + + aw_pr_dbg("msg num[%d] ", *msg_num); + return 0; +} + +static void aw_dsp_get_check_sum(int pos, void *data, int size, int *check_sum) +{ + int i = 0; + int sum_data = 0; + + for (i = pos; i < size / sizeof(uint8_t); i++) + sum_data += *((uint8_t *)data + sizeof(uint8_t) * i); + + + *check_sum = sum_data; +} + +#ifdef AW_MTK_PLATFORM_WITH_DSP +/*****************mtk dsp communication function start**********************/ +static int aw_mtk_write_data_to_dsp(int param_id, void *data, int size) +{ + int ret = 0; + int32_t *dsp_data = NULL; + aw_dsp_msg_t *hdr = NULL; + + dsp_data = kzalloc(sizeof(aw_dsp_msg_t) + size, GFP_KERNEL); + if (!dsp_data) + return -ENOMEM; + + + hdr = (aw_dsp_msg_t *)dsp_data; + hdr->type = AW_DSP_MSG_TYPE_DATA; + hdr->opcode_id = param_id; + hdr->version = AW_DSP_MSG_HDR_VER; + + memcpy(((char *)dsp_data) + sizeof(aw_dsp_msg_t), + data, size); + + ret = mtk_spk_send_ipi_buf_to_dsp(dsp_data, + sizeof(aw_dsp_msg_t) + size); + if (ret < 0) { + aw_pr_err("write data failed"); + kfree(dsp_data); + dsp_data = NULL; + return ret; + } + + kfree(dsp_data); + dsp_data = NULL; + return ret; +} + +static int aw_mtk_read_data_from_dsp(int param_id, void *data, int size) +{ + int ret = 0; + aw_dsp_msg_t hdr; + + hdr.type = AW_DSP_MSG_TYPE_CMD; + hdr.opcode_id = param_id; + hdr.version = AW_DSP_MSG_HDR_VER; + + mutex_lock(&g_aw_dsp_msg_lock); + ret = mtk_spk_send_ipi_buf_to_dsp(&hdr, sizeof(aw_dsp_msg_t)); + if (ret < 0) { + aw_pr_err("send cmd failed"); + goto dsp_msg_failed; + } + + ret = mtk_spk_recv_ipi_buf_from_dsp(data, size, &size); + if (ret < 0) { + aw_pr_err("get data failed"); + goto dsp_msg_failed; + } + mutex_unlock(&g_aw_dsp_msg_lock); + return ret; + +dsp_msg_failed: + mutex_unlock(&g_aw_dsp_msg_lock); + return ret; +} + +/*****************mtk dsp communication function end**********************/ +#else +/*****************qcom dsp communication function start**********************/ +static int aw_afe_get_topology(uint32_t param_id) +{ + if (param_id == AW_MSG_ID_TX_SET_ENABLE) + return afe_get_topology(g_tx_port_id); + else + return afe_get_topology(g_rx_port_id); +} + +static void aw_check_dsp_ready(uint32_t param_id) +{ + int ret; + + ret = aw_afe_get_topology(param_id); + + if (param_id == AW_MSG_ID_TX_SET_ENABLE) { + if (ret != g_tx_topo_id) + aw_pr_err("tx topo id is 0x%x", ret); + } else { + if (ret != g_rx_topo_id) + aw_pr_err("rx topo id is 0x%x", ret); + } +} + +static int aw_qcom_write_data_to_dsp(uint32_t param_id, void *data, int size) +{ + int ret = 0; + + aw_check_dsp_ready(param_id); + mutex_lock(&g_aw_dsp_lock); + ret = aw_send_afe_cal_apr(param_id, data, size, true); + mutex_unlock(&g_aw_dsp_lock); + return ret; +} + +static int aw_qcom_read_data_from_dsp(uint32_t param_id, void *data, int size) +{ + int ret = 0; + + aw_check_dsp_ready(param_id); + mutex_lock(&g_aw_dsp_lock); + ret = aw_send_afe_cal_apr(param_id, data, size, false); + mutex_unlock(&g_aw_dsp_lock); + + return ret; +} +#endif + +/******************* afe module communication function ************************/ +static int aw_dsp_set_afe_rx_module_enable(void *buf, int size) +{ +#ifdef AW_MTK_PLATFORM_WITH_DSP + return aw_mtk_write_data_to_dsp(AW_MSG_ID_RX_SET_ENABLE, buf, size); +#else + return aw_send_afe_rx_module_enable(buf, size); +#endif +} + +static int aw_dsp_set_afe_tx_module_enable(void *buf, int size) +{ +#ifdef AW_MTK_PLATFORM_WITH_DSP + return aw_mtk_write_data_to_dsp(AW_MSG_ID_TX_SET_ENABLE, buf, size); +#else + return aw_send_afe_tx_module_enable(buf, size); +#endif +} + +static int aw_dsp_get_afe_rx_module_enable(void *buf, int size) +{ +#ifdef AW_MTK_PLATFORM_WITH_DSP + return aw_mtk_read_data_from_dsp(AW_MSG_ID_RX_SET_ENABLE, buf, size); +#else + return aw_qcom_read_data_from_dsp(AW_MSG_ID_RX_SET_ENABLE, buf, size); +#endif +} + +static int aw_dsp_get_afe_tx_module_enable(void *buf, int size) +{ +#ifdef AW_MTK_PLATFORM_WITH_DSP + return aw_mtk_read_data_from_dsp(AW_MSG_ID_TX_SET_ENABLE, buf, size); +#else + return aw_qcom_read_data_from_dsp(AW_MSG_ID_TX_SET_ENABLE, buf, size); +#endif +} + +/******************* read/write msg communication function ***********************/ +static int aw_read_msg_from_dsp(struct aw_device *aw_dev, + uint32_t msg_id, char *data_ptr, unsigned int data_size) +{ + int ret = 0; + int msg_num = -EINVAL; + aw_dsp_msg_t hdr[2]; + + ret = aw_dsp_get_msg_num(aw_dev->channel, &msg_num); + if (ret < 0) { + aw_dev_err(aw_dev->dev, "get msg_num failed"); + return ret; + } + + hdr[0].type = AW_DSP_MSG_TYPE_DATA; + hdr[0].opcode_id = afe_param_msg_id[msg_num]; + hdr[0].version = AW_DSP_MSG_HDR_VER; + hdr[1].type = AW_DSP_MSG_TYPE_CMD; + hdr[1].opcode_id = msg_id; + hdr[1].version = AW_DSP_MSG_HDR_VER; + + mutex_lock(&g_aw_dsp_msg_lock); + +#ifdef AW_MTK_PLATFORM_WITH_DSP + ret = mtk_spk_send_ipi_buf_to_dsp(&hdr, 2 * sizeof(aw_dsp_msg_t)); +#else + ret = aw_qcom_write_data_to_dsp(afe_param_msg_id[msg_num], + &hdr[1], sizeof(aw_dsp_msg_t)); +#endif + if (ret < 0) { + aw_pr_err("msg_id:0x%x, send cmd failed", msg_id); + goto dsp_msg_failed; + } + +#ifdef AW_MTK_PLATFORM_WITH_DSP + ret = mtk_spk_recv_ipi_buf_from_dsp(data_ptr, data_size, &data_size); +#else + ret = aw_qcom_read_data_from_dsp(afe_param_msg_id[msg_num], + data_ptr, (int)data_size); +#endif + if (ret < 0) { + aw_pr_err("msg_id:0x%x, read data failed", msg_id); + goto dsp_msg_failed; + } + + + mutex_unlock(&g_aw_dsp_msg_lock); + return 0; + +dsp_msg_failed: + mutex_unlock(&g_aw_dsp_msg_lock); + return ret; +} + +static int aw_read_msg_from_dsp_v_1_0_0_0(struct aw_device *aw_dev, + uint32_t params_id, char *data_ptr, unsigned int len, int num) +{ + int ret = 0; + int sum_data = 0; + int32_t *dsp_msg = NULL; + aw_msg_hdr_t write_hdr; + aw_msg_hdr_t *read_hdr = NULL; +#ifdef AW_MTK_PLATFORM_WITH_DSP + int real_len = 0; +#endif + memset(&write_hdr, 0, sizeof(aw_msg_hdr_t)); + write_hdr.version = AW_DSP_MSG_VER; + write_hdr.type = DSP_MSG_TYPE_WRITE_CMD; + write_hdr.params_id = params_id; + write_hdr.channel = aw_dev->channel; + write_hdr.num = num; + write_hdr.data_size = len / num; + + aw_dsp_get_check_sum(sizeof(int32_t), &write_hdr, sizeof(aw_msg_hdr_t), &write_hdr.checksum); + + mutex_lock(&g_aw_dsp_msg_lock); +#ifdef AW_MTK_PLATFORM_WITH_DSP + ret = mtk_spk_send_ipi_buf_to_dsp(&write_hdr, sizeof(aw_msg_hdr_t)); +#else + ret = aw_qcom_write_data_to_dsp(AW_MSG_ID_PARAMS_DEFAULT, &write_hdr, sizeof(aw_msg_hdr_t)); +#endif + if (ret < 0) { + aw_pr_err("write data to dsp failed"); + goto write_hdr_error; + } + + dsp_msg = kzalloc(sizeof(aw_msg_hdr_t) + len, GFP_KERNEL); + if (!dsp_msg) { + ret = -ENOMEM; + goto kalloc_msg_error; + } + +#ifdef AW_MTK_PLATFORM_WITH_DSP + ret = mtk_spk_recv_ipi_buf_from_dsp((char *)dsp_msg, sizeof(aw_msg_hdr_t) + len, &real_len); +#else + ret = aw_qcom_read_data_from_dsp(AW_MSG_ID_PARAMS_DEFAULT, (char *)dsp_msg, + sizeof(aw_msg_hdr_t) + len); +#endif + + if (ret < 0) { + aw_pr_err("read data from dsp failed"); + goto read_msg_error; + } + + read_hdr = (aw_msg_hdr_t *)dsp_msg; + if (read_hdr->type != DSP_MSG_TYPE_READ_DATA) { + aw_pr_err("read_hdr type = %d not read data!", read_hdr->type); + ret = -EINVAL; + goto read_msg_error; + } + + aw_dsp_get_check_sum(sizeof(int32_t), dsp_msg, sizeof(aw_msg_hdr_t) + len, &sum_data); + + if (sum_data != read_hdr->checksum) { + aw_pr_err("aw_dsp_msg check sum error!"); + aw_pr_err("read_hdr->checksum=%d sum_data=%d", read_hdr->checksum, sum_data); + ret = -EINVAL; + goto read_msg_error; + } + + memcpy(data_ptr, ((char *)dsp_msg) + sizeof(aw_msg_hdr_t), len); + +read_msg_error: + kfree(dsp_msg); + dsp_msg = NULL; +write_hdr_error: +kalloc_msg_error: + mutex_unlock(&g_aw_dsp_msg_lock); + return ret; + +} + +int aw882xx_dsp_read_dsp_msg(struct aw_device *aw_dev, uint32_t msg_id, char *data_ptr, unsigned int size) +{ + int ret = 0; + + if (aw_dev->channel < AW_DEV_CH_TERT_L) { + ret = aw_read_msg_from_dsp(aw_dev, msg_id, data_ptr, size); + } else { + ret = aw_read_msg_from_dsp_v_1_0_0_0(aw_dev, msg_id, data_ptr, + size, AW_DSP_CHANNEL_DEFAULT_NUM); + } + + return ret; +} + +static int aw_write_msg_to_dsp(struct aw_device *aw_dev, + uint32_t msg_id, char *data_ptr, unsigned int data_size) +{ + int ret = 0; + int msg_num = -EINVAL; + int32_t *dsp_msg = NULL; + aw_dsp_msg_t *hdr = NULL; + + ret = aw_dsp_get_msg_num(aw_dev->channel, &msg_num); + if (ret < 0) { + aw_dev_err(aw_dev->dev, "get msg_num failed"); + return ret; + } + + dsp_msg = kzalloc(sizeof(aw_dsp_msg_t) + data_size, + GFP_KERNEL); + if (!dsp_msg) + return -ENOMEM; + + hdr = (aw_dsp_msg_t *)dsp_msg; + hdr->type = AW_DSP_MSG_TYPE_DATA; + hdr->opcode_id = msg_id; + hdr->version = AW_DSP_MSG_HDR_VER; + + memcpy(((char *)dsp_msg) + sizeof(aw_dsp_msg_t), + data_ptr, data_size); + +#ifdef AW_MTK_PLATFORM_WITH_DSP + ret = aw_mtk_write_data_to_dsp(afe_param_msg_id[msg_num], (void *)dsp_msg, + sizeof(aw_dsp_msg_t) + data_size); +#else + ret = aw_qcom_write_data_to_dsp(afe_param_msg_id[msg_num], (void *)dsp_msg, + sizeof(aw_dsp_msg_t) + data_size); +#endif + if (ret < 0) { + aw_pr_err("msg_id:0x%x, write data failed", msg_id); + kfree(dsp_msg); + dsp_msg = NULL; + return ret; + } + + kfree(dsp_msg); + dsp_msg = NULL; + return ret; +} + +static int aw_write_msg_to_dsp_v_1_0_0_0(struct aw_device *aw_dev, + uint32_t params_id, void *data, unsigned int len, int num) +{ + int ret = 0; + int32_t *dsp_msg = NULL; + aw_msg_hdr_t *hdr = NULL; + + mutex_lock(&g_aw_dsp_msg_lock); + dsp_msg = kzalloc(sizeof(aw_msg_hdr_t) + len, GFP_KERNEL); + if (!dsp_msg) { + aw_pr_err("kzalloc dsp_msg error"); + ret = -ENOMEM; + goto kalloc_error; + } + hdr = (aw_msg_hdr_t *)dsp_msg; + hdr->version = AW_DSP_MSG_VER; + hdr->type = DSP_MSG_TYPE_WRITE_DATA; + hdr->params_id = params_id; + hdr->channel = aw_dev->channel; + hdr->num = num; + hdr->data_size = len / num; + + memcpy(((char *)dsp_msg) + sizeof(aw_msg_hdr_t), data, len); + + aw_dsp_get_check_sum(sizeof(int32_t), dsp_msg, sizeof(aw_msg_hdr_t) + len, &hdr->checksum); + +#ifdef AW_MTK_PLATFORM_WITH_DSP + ret = mtk_spk_send_ipi_buf_to_dsp(dsp_msg, sizeof(aw_msg_hdr_t) + len); +#else + ret = aw_qcom_write_data_to_dsp(AW_MSG_ID_PARAMS_DEFAULT, dsp_msg, sizeof(aw_msg_hdr_t) + len); +#endif + if (ret < 0) { + aw_pr_err("write data failed"); + goto write_msg_error; + } + +write_msg_error: + kfree(dsp_msg); + dsp_msg = NULL; +kalloc_error: + mutex_unlock(&g_aw_dsp_msg_lock); + return ret; + +} + +int aw882xx_dsp_write_dsp_msg(struct aw_device *aw_dev, uint32_t msg_id, char *data_ptr, unsigned int size) +{ + int ret = 0; + + if (aw_dev->channel < AW_DEV_CH_TERT_L) { + ret = aw_write_msg_to_dsp(aw_dev, msg_id, data_ptr, size); + } else { + ret = aw_write_msg_to_dsp_v_1_0_0_0(aw_dev, msg_id, data_ptr, + size, AW_DSP_CHANNEL_DEFAULT_NUM); + } + + return ret; +} + +/******************* read/write data communication function ***********************/ +static int aw_read_data_from_dsp(uint32_t param_id, void *data, int size) +{ +#ifdef AW_MTK_PLATFORM_WITH_DSP + return aw_mtk_read_data_from_dsp(param_id, data, size); +#else + return aw_qcom_read_data_from_dsp(param_id, data, size); +#endif +} + +static int aw_write_data_to_dsp(uint32_t param_id, void *data, int size) +{ +#ifdef AW_MTK_PLATFORM_WITH_DSP + return aw_mtk_write_data_to_dsp(param_id, data, size); +#else + return aw_qcom_write_data_to_dsp(param_id, data, size); +#endif +} + +/************************* dsp communication function *****************************/ +int aw882xx_dsp_set_afe_module_en(int type, int enable) +{ + int ret = 0; + + switch (type) { + case AW_RX_MODULE: + ret = aw_dsp_set_afe_rx_module_enable(&enable, sizeof(int32_t)); + break; + case AW_TX_MODULE: + ret = aw_dsp_set_afe_tx_module_enable(&enable, sizeof(int32_t)); + break; + default: + aw_pr_err("unsupported type %d", type); + return -EINVAL; + } + + return ret; +} + +int aw882xx_dsp_get_afe_module_en(int type, int *status) +{ + int ret = 0; + + switch (type) { + case AW_RX_MODULE: + ret = aw_dsp_get_afe_rx_module_enable(status, sizeof(int32_t)); + break; + case AW_TX_MODULE: + ret = aw_dsp_get_afe_tx_module_enable(status, sizeof(int32_t)); + break; + default: + aw_pr_err("unsupported type %d", type); + return -EINVAL; + } + + return ret; +} + +int aw882xx_dsp_read_te(struct aw_device *aw_dev, int32_t *te) +{ + int ret = 0; + int32_t data[8] = {0}; /*[re:r0:Te:r0_te]*/ + + ret = aw882xx_dsp_read_dsp_msg(aw_dev, AW_MSG_ID_SPK_STATUS, + (char *)data, sizeof(int32_t) * 8); + if (ret) { + aw_dev_err(aw_dev->dev, " read Te failed "); + return ret; + } + + if ((aw_dev->channel % 2) == 0) + *te = data[2]; + else + *te = data[6]; + + aw_dev_dbg(aw_dev->dev, "read Te %d", *te); + return ret; +} + +int aw882xx_dsp_read_st(struct aw_device *aw_dev, int32_t *r0, int32_t *te) +{ + int ret = 0; + int32_t data[8] = {0}; /*[re:r0:Te:r0_te]*/ + + ret = aw882xx_dsp_read_dsp_msg(aw_dev, AW_MSG_ID_SPK_STATUS, + (char *)data, sizeof(int32_t) * 8); + if (ret) { + aw_dev_err(aw_dev->dev, "read spk st failed"); + return ret; + } + + if ((aw_dev->channel % 2) == 0) { + *r0 = AW_DSP_RE_TO_SHOW_RE(data[0]); + *te = data[2]; + } else { + *r0 = AW_DSP_RE_TO_SHOW_RE(data[4]); + *te = data[6]; + } + aw_dev_dbg(aw_dev->dev, "read Re %d , Te %d", *r0, *te); + return ret; +} + +int aw882xx_dsp_read_spin(int *spin_mode) +{ + int ret = 0; + int32_t spin = 0; + + ret = aw_read_data_from_dsp(AW_MSG_ID_SPIN, &spin, sizeof(int32_t)); + if (ret) { + *spin_mode = 0; + aw_pr_err("read spin failed "); + return ret; + } + *spin_mode = spin; + aw_pr_dbg("read spin done"); + return ret; +} + +int aw882xx_dsp_write_spin(int spin_mode) +{ + int ret = 0; + int32_t spin = spin_mode; + + if (spin >= AW_SPIN_MAX) { + aw_pr_err("spin [%d] unsupported ", spin); + return -EINVAL; + } + + ret = aw_write_data_to_dsp(AW_MSG_ID_SPIN, &spin, sizeof(int32_t)); + if (ret) { + aw_pr_err("write spin failed "); + return ret; + } + aw_pr_dbg("write spin done"); + return ret; +} + +int aw882xx_dsp_read_r0(struct aw_device *aw_dev, int32_t *r0) +{ + uint32_t msg_id = -EINVAL; + int ret = 0; + int32_t data[6] = {0}; + + if (aw_dev->channel == AW_DEV_CH_PRI_L || + aw_dev->channel == AW_DEV_CH_SEC_L || + aw_dev->channel == AW_DEV_CH_TERT_L || + aw_dev->channel == AW_DEV_CH_QUAT_L) { + msg_id = AW_MSG_ID_REAL_DATA_L; + } else if (aw_dev->channel == AW_DEV_CH_PRI_R || + aw_dev->channel == AW_DEV_CH_SEC_R || + aw_dev->channel == AW_DEV_CH_TERT_R || + aw_dev->channel == AW_DEV_CH_QUAT_R) { + msg_id = AW_MSG_ID_REAL_DATA_R; + } else { + aw_dev_err(aw_dev->dev, "unsupport dev channel"); + return -EINVAL; + } + + ret = aw882xx_dsp_read_dsp_msg(aw_dev, msg_id, (char *)data, sizeof(int32_t) * 6); + if (ret) { + aw_dev_err(aw_dev->dev, "read real re failed "); + return ret; + } + + *r0 = AW_DSP_RE_TO_SHOW_RE(data[0]); + aw_dev_dbg(aw_dev->dev, "read r0 %d\n", *r0); + return ret; +} + +int aw882xx_dsp_read_cali_data(struct aw_device *aw_dev, char *data, unsigned int data_len) +{ + uint32_t msg_id = -EINVAL; + int ret = 0; + + if (aw_dev->channel == AW_DEV_CH_PRI_L || + aw_dev->channel == AW_DEV_CH_SEC_L || + aw_dev->channel == AW_DEV_CH_TERT_L || + aw_dev->channel == AW_DEV_CH_QUAT_L) { + msg_id = AW_MSG_ID_REAL_DATA_L; + } else if (aw_dev->channel == AW_DEV_CH_PRI_R || + aw_dev->channel == AW_DEV_CH_SEC_R || + aw_dev->channel == AW_DEV_CH_TERT_R || + aw_dev->channel == AW_DEV_CH_QUAT_R) { + msg_id = AW_MSG_ID_REAL_DATA_R; + } else { + aw_dev_err(aw_dev->dev, "unsupport dev channel"); + return -EINVAL; + } + + ret = aw882xx_dsp_read_dsp_msg(aw_dev, msg_id, data, data_len); + if (ret) { + aw_dev_err(aw_dev->dev, "read cali dara failed "); + return ret; + } + aw_dev_dbg(aw_dev->dev, "read cali_data"); + return ret; +} + + +int aw882xx_dsp_get_dc_status(struct aw_device *aw_dev) +{ + int ret = 0; + int32_t data[2] = {0}; + + ret = aw882xx_dsp_read_dsp_msg(aw_dev, AW_MSG_ID_DIRECT_CUR_FLAG, (char *)data, sizeof(int32_t) * 2); + if (ret) { + aw_dev_err(aw_dev->dev, "read dc flag failed"); + return ret; + } + + if ((aw_dev->channel % 2) == 0) + ret = data[0]; + else + ret = data[1]; + + aw_dev_dbg(aw_dev->dev, "read direct current status:%d", ret); + return ret; +} + +int aw882xx_dsp_read_f0_q(struct aw_device *aw_dev, int32_t *f0, int32_t *q) +{ + int ret = 0; + int32_t data[4] = {0}; + + ret = aw882xx_dsp_read_dsp_msg(aw_dev, AW_MSG_ID_F0_Q, (char *)data, sizeof(int32_t) * 4); + if (ret) { + aw_dev_err(aw_dev->dev, "read f0 & q failed"); + return ret; + } + + if ((aw_dev->channel % 2) == 0) { + *f0 = data[0]; + *q = data[1]; + } else { + *f0 = data[2]; + *q = data[3]; + } + aw_dev_dbg(aw_dev->dev, "read f0 is %d, q is %d", *f0, *q); + return ret; +} + +int aw882xx_dsp_read_f0(struct aw_device *aw_dev, int32_t *f0) +{ + int ret = 0; + uint32_t msg_id = -EINVAL; + + if (aw_dev->channel == AW_DEV_CH_PRI_L || + aw_dev->channel == AW_DEV_CH_SEC_L || + aw_dev->channel == AW_DEV_CH_TERT_L || + aw_dev->channel == AW_DEV_CH_QUAT_L) { + msg_id = AW_MSG_ID_F0_L; + } else if (aw_dev->channel == AW_DEV_CH_PRI_R || + aw_dev->channel == AW_DEV_CH_SEC_R || + aw_dev->channel == AW_DEV_CH_TERT_R || + aw_dev->channel == AW_DEV_CH_QUAT_R) { + msg_id = AW_MSG_ID_F0_R; + } else { + aw_dev_err(aw_dev->dev, "unsupport dev channel"); + return -EINVAL; + } + + ret = aw882xx_dsp_read_dsp_msg(aw_dev, msg_id, (char *)f0, sizeof(int32_t)); + if (ret) { + aw_dev_err(aw_dev->dev, "read f0 failed"); + return ret; + } + aw_dev_dbg(aw_dev->dev, "read f0"); + return ret; +} + +int aw882xx_dsp_cali_en(struct aw_device *aw_dev, int32_t cali_msg_data) +{ + int ret = 0; + + ret = aw882xx_dsp_write_dsp_msg(aw_dev, AW_MSG_ID_ENABLE_CALI, (char *)&cali_msg_data, sizeof(int32_t)); + if (ret) { + aw_dev_err(aw_dev->dev, "write cali en failed"); + return ret; + } + aw_dev_dbg(aw_dev->dev, "write cali_en[%d]", cali_msg_data); + return ret; +} + +int aw882xx_dsp_hmute_en(struct aw_device *aw_dev, bool is_hmute) +{ + int ret = 0; + int32_t hmute = is_hmute; + + ret = aw882xx_dsp_write_dsp_msg(aw_dev, AW_MSG_ID_ENABLE_HMUTE, (char *)&hmute, sizeof(int32_t)); + if (ret) { + aw_dev_err(aw_dev->dev, "write hmue failed "); + return ret; + } + aw_dev_dbg(aw_dev->dev, "write hmute[%d]", is_hmute); + return ret; +} + +int aw882xx_dsp_read_cali_re(struct aw_device *aw_dev, int32_t *cali_re) +{ + int ret = 0; + uint32_t msg_id = -EINVAL; + int32_t read_re = 0; + + if (aw_dev->channel == AW_DEV_CH_PRI_L || + aw_dev->channel == AW_DEV_CH_SEC_L || + aw_dev->channel == AW_DEV_CH_TERT_L || + aw_dev->channel == AW_DEV_CH_QUAT_L) { + msg_id = AW_MSG_ID_RE_L; + } else if (aw_dev->channel == AW_DEV_CH_PRI_R || + aw_dev->channel == AW_DEV_CH_SEC_R || + aw_dev->channel == AW_DEV_CH_TERT_R || + aw_dev->channel == AW_DEV_CH_QUAT_R) { + msg_id = AW_MSG_ID_RE_R; + } else { + aw_dev_err(aw_dev->dev, "unsupport dev channel"); + return -EINVAL; + } + + + ret = aw882xx_dsp_read_dsp_msg(aw_dev, msg_id, (char *)&read_re, sizeof(int32_t)); + if (ret) { + aw_dev_err(aw_dev->dev, "read cali re failed "); + return ret; + } + *cali_re = AW_DSP_RE_TO_SHOW_RE(read_re); + aw_dev_dbg(aw_dev->dev, "read cali re done"); + return ret; +} + +int aw882xx_dsp_write_cali_re(struct aw_device *aw_dev, int32_t cali_re) +{ + int ret = 0; + uint32_t msg_id = -EINVAL; + int32_t local_re = AW_SHOW_RE_TO_DSP_RE(cali_re); + + if (aw_dev->channel == AW_DEV_CH_PRI_L || + aw_dev->channel == AW_DEV_CH_SEC_L || + aw_dev->channel == AW_DEV_CH_TERT_L || + aw_dev->channel == AW_DEV_CH_QUAT_L) { + msg_id = AW_MSG_ID_RE_L; + } else if (aw_dev->channel == AW_DEV_CH_PRI_R || + aw_dev->channel == AW_DEV_CH_SEC_R || + aw_dev->channel == AW_DEV_CH_TERT_R || + aw_dev->channel == AW_DEV_CH_QUAT_R) { + msg_id = AW_MSG_ID_RE_R; + } else { + aw_dev_err(aw_dev->dev, "unsupport dev channel"); + return -EINVAL; + } + + ret = aw882xx_dsp_write_dsp_msg(aw_dev, msg_id, (char *)&local_re, sizeof(int32_t)); + if (ret) { + aw_dev_err(aw_dev->dev, "write cali re failed "); + return ret; + } + aw_dev_dbg(aw_dev->dev, "write cali re done"); + return ret; +} + +int aw882xx_dsp_write_params(struct aw_device *aw_dev, char *data, unsigned int data_len) +{ + int ret = 0; + uint32_t msg_id = -EINVAL; + int msg_num = -EINVAL; + + ret = aw_dsp_get_msg_num(aw_dev->channel, &msg_num); + if (ret < 0) { + aw_dev_err(aw_dev->dev, "get msg_num failed"); + return ret; + } + + if (msg_num == MSG_PARAM_ID_0) { + msg_id = AW_MSG_ID_PARAMS; + } else if (msg_num == MSG_PARAM_ID_1) { + msg_id = AW_MSG_ID_PARAMS_1; + } else if (msg_num == MSG_PARAM_ID_2) { + msg_id = AW_MSG_ID_PARAMS_2; + } else if (msg_num == MSG_PARAM_ID_3) { + msg_id = AW_MSG_ID_PARAMS_3; + } else { + aw_dev_err(aw_dev->dev, "unsupport msg num"); + return ret; + } + + ret = aw_write_data_to_dsp(msg_id, data, data_len); + if (ret) { + aw_dev_err(aw_dev->dev, "write params failed"); + return ret; + } + aw_dev_dbg(aw_dev->dev, "write params done"); + return ret; +} + +#ifdef AW_ALGO_AUTH_DSP +int aw882xx_dsp_read_algo_auth_data(struct aw_device *aw_dev, + char *data, unsigned int data_len) +{ + int ret = 0; + + ret = aw_read_data_from_dsp(AW_MSG_ID_ALGO_AUTHENTICATION, data, data_len); + if (ret) + aw_dev_err(aw_dev->dev, "read algo auth failed"); + + aw_dev_dbg(aw_dev->dev, "read algo auth data done"); + + return ret; +} + +int aw882xx_dsp_write_algo_auth_data(struct aw_device *aw_dev, + char *data, unsigned int data_len) +{ + int ret = 0; + + ret = aw_write_data_to_dsp(AW_MSG_ID_ALGO_AUTHENTICATION, data, data_len); + if (ret) { + aw_pr_err("write algo auth failed "); + return ret; + } + aw_pr_dbg("write algo auth done"); + + return ret; +} +#endif + +int aw882xx_dsp_read_vmax(struct aw_device *aw_dev, char *data, unsigned int data_len) +{ + int ret = 0; + uint32_t msg_id = -EINVAL; + + if (aw_dev->channel == AW_DEV_CH_PRI_L || + aw_dev->channel == AW_DEV_CH_SEC_L || + aw_dev->channel == AW_DEV_CH_TERT_L || + aw_dev->channel == AW_DEV_CH_QUAT_L) { + msg_id = AW_MSG_ID_VMAX_L; + } else if (aw_dev->channel == AW_DEV_CH_PRI_R || + aw_dev->channel == AW_DEV_CH_SEC_R || + aw_dev->channel == AW_DEV_CH_TERT_R || + aw_dev->channel == AW_DEV_CH_QUAT_R) { + msg_id = AW_MSG_ID_VMAX_R; + } else { + aw_dev_err(aw_dev->dev, "unsupport dev channel"); + return -EINVAL; + } + + ret = aw882xx_dsp_read_dsp_msg(aw_dev, msg_id, data, data_len); + if (ret) { + aw_dev_err(aw_dev->dev, "read vmax failed"); + return ret; + } + aw_dev_dbg(aw_dev->dev, "read vmax done"); + return ret; +} + +int aw882xx_dsp_write_vmax(struct aw_device *aw_dev, char *data, unsigned int data_len) +{ + int ret = 0; + uint32_t msg_id = -EINVAL; + + if (aw_dev->channel == AW_DEV_CH_PRI_L || + aw_dev->channel == AW_DEV_CH_SEC_L || + aw_dev->channel == AW_DEV_CH_TERT_L || + aw_dev->channel == AW_DEV_CH_QUAT_L) { + msg_id = AW_MSG_ID_VMAX_L; + } else if (aw_dev->channel == AW_DEV_CH_PRI_R || + aw_dev->channel == AW_DEV_CH_SEC_R || + aw_dev->channel == AW_DEV_CH_TERT_R || + aw_dev->channel == AW_DEV_CH_QUAT_R) { + msg_id = AW_MSG_ID_VMAX_R; + } else { + aw_dev_err(aw_dev->dev, "unsupport dev channel"); + return -EINVAL; + } + + ret = aw882xx_dsp_write_dsp_msg(aw_dev, msg_id, data, data_len); + if (ret) { + aw_dev_err(aw_dev->dev, "write vmax failed "); + return ret; + } + aw_dev_dbg(aw_dev->dev, "write vmax done"); + return ret; +} + +int aw882xx_dsp_noise_en(struct aw_device *aw_dev, bool is_noise) +{ + int ret = 0; + int32_t noise = is_noise; + uint32_t msg_id = -EINVAL; + + if (aw_dev->channel == AW_DEV_CH_PRI_L || + aw_dev->channel == AW_DEV_CH_SEC_L || + aw_dev->channel == AW_DEV_CH_TERT_L || + aw_dev->channel == AW_DEV_CH_QUAT_L) { + msg_id = AW_MSG_ID_NOISE_L; + } else if (aw_dev->channel == AW_DEV_CH_PRI_R || + aw_dev->channel == AW_DEV_CH_SEC_R || + aw_dev->channel == AW_DEV_CH_TERT_R || + aw_dev->channel == AW_DEV_CH_QUAT_R) { + msg_id = AW_MSG_ID_NOISE_R; + } else { + aw_dev_err(aw_dev->dev, "unsupport dev channel"); + return -EINVAL; + } + + ret = aw882xx_dsp_write_dsp_msg(aw_dev, msg_id, (char *)&noise, sizeof(int32_t)); + if (ret) { + aw_dev_err(aw_dev->dev, "write noise failed "); + return ret; + } + aw_dev_dbg(aw_dev->dev, "write noise[%d] done", noise); + return ret; +} + +int aw882xx_dsp_read_cali_cfg(struct aw_device *aw_dev, char *data, unsigned int data_len) +{ + int ret = 0; + uint32_t msg_id = -EINVAL; + + if (aw_dev->channel == AW_DEV_CH_PRI_L || + aw_dev->channel == AW_DEV_CH_SEC_L || + aw_dev->channel == AW_DEV_CH_TERT_L || + aw_dev->channel == AW_DEV_CH_QUAT_L) { + msg_id = AW_MSG_ID_CALI_CFG_L; + } else if (aw_dev->channel == AW_DEV_CH_PRI_R || + aw_dev->channel == AW_DEV_CH_SEC_R || + aw_dev->channel == AW_DEV_CH_TERT_R || + aw_dev->channel == AW_DEV_CH_QUAT_R) { + msg_id = AW_MSG_ID_CALI_CFG_R; + } else { + aw_dev_err(aw_dev->dev, "unsupport dev channel"); + return -EINVAL; + } + + ret = aw882xx_dsp_read_dsp_msg(aw_dev, msg_id, data, data_len); + if (ret) { + aw_dev_err(aw_dev->dev, "read cali_cfg failed "); + return ret; + } + aw_dev_dbg(aw_dev->dev, "read cali_cfg done"); + return ret; +} + +int aw882xx_dsp_write_cali_cfg(struct aw_device *aw_dev, char *data, unsigned int data_len) +{ + int ret = 0; + uint32_t msg_id = -EINVAL; + + if (aw_dev->channel == AW_DEV_CH_PRI_L || + aw_dev->channel == AW_DEV_CH_SEC_L || + aw_dev->channel == AW_DEV_CH_TERT_L || + aw_dev->channel == AW_DEV_CH_QUAT_L) { + msg_id = AW_MSG_ID_CALI_CFG_L; + } else if (aw_dev->channel == AW_DEV_CH_PRI_R || + aw_dev->channel == AW_DEV_CH_SEC_R || + aw_dev->channel == AW_DEV_CH_TERT_R || + aw_dev->channel == AW_DEV_CH_QUAT_R) { + msg_id = AW_MSG_ID_CALI_CFG_R; + } else { + aw_dev_err(aw_dev->dev, "unsupport dev channel"); + return -EINVAL; + } + + ret = aw882xx_dsp_write_dsp_msg(aw_dev, msg_id, data, data_len); + if (ret) { + aw_dev_err(aw_dev->dev, "write cali_cfg failed "); + return ret; + } + + aw_dev_dbg(aw_dev->dev, "write cali_cfg done"); + return ret; +} + +int aw882xx_dsp_set_copp_module_en(bool enable) +{ + int ret = 0; + + ret = aw_adm_param_enable(g_rx_port_id, AW_COPP_MODULE_ID, + AW_COPP_PARAMS_ID_AWDSP_ENABLE, enable); + if (ret) + return -EINVAL; + + aw_pr_info("set skt %s", enable == 1 ? "enable" : "disable"); + return ret; +} + + +int aw882xx_dsp_set_mixer_en(struct aw_device *aw_dev, uint32_t mixer_en) +{ + int ret = 0; + + ret = aw882xx_dsp_write_dsp_msg(aw_dev, AW_MSG_ID_AUDIO_MIX, (char *)&mixer_en, sizeof(uint32_t)); + if (ret) { + aw_dev_err(aw_dev->dev, "write mixer_en failed"); + return ret; + } + aw_dev_dbg(aw_dev->dev, "write mixer_en[%d]", mixer_en); + return ret; + +} + +int aw882xx_get_algo_version(struct aw_device *aw_dev, char *algo_ver_buf) +{ + int ret = 0; + unsigned int algo_ver = 0; + char *algo_data = NULL; + + ret = aw882xx_dsp_read_dsp_msg(aw_dev, AW_MSG_ID_VERSION, + (char *)&algo_ver, sizeof(uint32_t)); + if ((ret < 0) || (algo_ver == 0)) { + ret = aw882xx_dsp_read_dsp_msg(aw_dev, AW_MSG_ID_VERSION_NEW, + algo_ver_buf, ALGO_VERSION_MAX); + if (ret < 0) + return ret; + } else { + algo_data = (char *)&algo_ver; + snprintf(algo_ver_buf, ALGO_VERSION_MAX, "aw_algo_v%d.%d.%d.%d", + algo_data[3], algo_data[2], algo_data[1], algo_data[0]); + } + + aw_dev_dbg(aw_dev->dev, "%s", algo_ver_buf); + return ret; +} + +void aw882xx_device_parse_topo_id_dt(struct aw_device *aw_dev) +{ + int ret = 0; + + ret = of_property_read_u32(aw_dev->dev->of_node, "aw-tx-topo-id", &g_tx_topo_id); + if (ret < 0) { + g_tx_topo_id = AW_TX_DEFAULT_TOPO_ID; + aw_dev_info(aw_dev->dev, "read aw-tx-topo-id failed,use default"); + } + + ret = of_property_read_u32(aw_dev->dev->of_node, "aw-rx-topo-id", &g_rx_topo_id); + if (ret < 0) { + g_rx_topo_id = AW_RX_DEFAULT_TOPO_ID; + aw_dev_info(aw_dev->dev, "read aw-rx-topo-id failed,use default"); + } + + aw_dev_info(aw_dev->dev, "tx-topo-id: 0x%x, rx-topo-id: 0x%x", + g_tx_topo_id, g_rx_topo_id); +} + +void aw882xx_device_parse_port_id_dt(struct aw_device *aw_dev) +{ + int ret = 0; + + ret = of_property_read_u32(aw_dev->dev->of_node, "aw-tx-port-id", &g_tx_port_id); + if (ret < 0) { + g_tx_port_id = AW_TX_DEFAULT_PORT_ID; + aw_dev_info(aw_dev->dev, "read aw-tx-port-id failed,use default"); + } + + ret = of_property_read_u32(aw_dev->dev->of_node, "aw-rx-port-id", &g_rx_port_id); + if (ret < 0) { + g_rx_port_id = AW_RX_DEFAULT_PORT_ID; + aw_dev_info(aw_dev->dev, "read aw-rx-port-id failed,use default"); + } + + aw_set_port_id(g_tx_port_id, g_rx_port_id); + aw_dev_info(aw_dev->dev, "tx-port-id: 0x%x, rx-port-id: 0x%x", + g_tx_port_id, g_rx_port_id); + +} + diff --git a/sound/soc/codecs/aw882xx/aw882xx_dsp.h b/sound/soc/codecs/aw882xx/aw882xx_dsp.h new file mode 100644 index 000000000000..f2a36d68c9c3 --- /dev/null +++ b/sound/soc/codecs/aw882xx/aw882xx_dsp.h @@ -0,0 +1,109 @@ +/* SPDX-License-Identifier: GPL-2.0 + * aw882xx_dsp.h + * + * Copyright (c) 2020 AWINIC Technology CO., LTD + * + * Author: Nick Li + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#ifndef __AW882XX_DSP_H__ +#define __AW882XX_DSP_H__ + +//#define AW_MTK_PLATFORM_WITH_DSP + +//#define AW_QCOM_ADM_MSG +/*#define AW_ALGO_AUTH_DSP*/ +/*factor form 12bit(4096) to 1000*/ +#define AW_DSP_RE_TO_SHOW_RE(re) (((re) * (1000)) >> (12)) +#define AW_SHOW_RE_TO_DSP_RE(re) (((re) << 12) / (1000)) + +#define AW_DSP_SLEEP_TIME (10) + +#define AW_TX_DEFAULT_TOPO_ID (0x1000FF00) +#define AW_RX_DEFAULT_TOPO_ID (0x1000FF01) +#define AW_TX_DEFAULT_PORT_ID (0x1007) +#define AW_RX_DEFAULT_PORT_ID (0x1006) + +#define AW_DSP_MSG_VER (0x10000000) +#define AW_DSP_CHANNEL_DEFAULT_NUM (1) + +enum aw_dsp_msg_type { + AW_DSP_MSG_TYPE_DATA = 0, + AW_DSP_MSG_TYPE_CMD = 1, +}; + +enum { + AW_SPIN_0 = 0, + AW_SPIN_90, + AW_SPIN_180, + AW_SPIN_270, + AW_SPIN_MAX, +}; + + +enum { + AW_AUDIO_MIX_DSIABLE = 0, + AW_AUDIO_MIX_ENABLE, +}; + +#define AW_DSP_MSG_HDR_VER (1) +typedef struct aw_msg_hdr aw_dsp_msg_t; + +enum { + DSP_MSG_TYPE_WRITE_CMD = 0, + DSP_MSG_TYPE_WRITE_DATA, + DSP_MSG_TYPE_READ_DATA, +}; + +typedef struct aw_msg_hdr_v_1_0_0_0 { + int32_t checksum; + int32_t version; + int32_t type; + int32_t params_id; + int32_t channel; + int32_t num; + int32_t data_size; + int32_t reseriver[3]; +} aw_msg_hdr_t; + +int aw882xx_dsp_read_dsp_msg(struct aw_device *aw_dev, uint32_t msg_id, char *data_ptr, unsigned int size); +int aw882xx_dsp_write_dsp_msg(struct aw_device *aw_dev, uint32_t msg_id, char *data_ptr, unsigned int size); +int aw882xx_dsp_write_cali_cfg(struct aw_device *aw_dev, char *data, unsigned int data_len); +int aw882xx_dsp_read_cali_cfg(struct aw_device *aw_dev, char *data, unsigned int data_len); +int aw882xx_dsp_noise_en(struct aw_device *aw_dev, bool is_noise); +int aw882xx_dsp_write_vmax(struct aw_device *aw_dev, char *data, unsigned int data_len); +int aw882xx_dsp_read_vmax(struct aw_device *aw_dev, char *data, unsigned int data_len); +int aw882xx_dsp_write_params(struct aw_device *aw_dev, char *data, unsigned int data_len); +int aw882xx_dsp_write_cali_re(struct aw_device *aw_dev, int32_t cali_re); +int aw882xx_dsp_read_cali_re(struct aw_device *aw_dev, int32_t *cali_re); +int aw882xx_dsp_read_r0(struct aw_device *aw_dev, int32_t *r0); +int aw882xx_dsp_read_st(struct aw_device *aw_dev, int32_t *r0, int32_t *te); +int aw882xx_dsp_read_te(struct aw_device *aw_dev, int32_t *te); +int aw882xx_dsp_get_dc_status(struct aw_device *aw_dev); +int aw882xx_dsp_hmute_en(struct aw_device *aw_dev, bool is_hmute); +int aw882xx_dsp_cali_en(struct aw_device *aw_dev, int32_t cali_msg_data); +int aw882xx_dsp_read_f0(struct aw_device *aw_dev, int32_t *f0); +int aw882xx_dsp_read_f0_q(struct aw_device *aw_dev, int32_t *f0, int32_t *q); +int aw882xx_dsp_read_cali_data(struct aw_device *aw_dev, char *data, unsigned int data_len); +int aw882xx_dsp_set_afe_module_en(int type, int enable); +int aw882xx_dsp_get_afe_module_en(int type, int *status); +int aw882xx_dsp_set_copp_module_en(bool enable); +int aw882xx_dsp_write_spin(int spin_mode); +int aw882xx_dsp_read_spin(int *spin_mode); +int aw882xx_get_algo_version(struct aw_device *aw_dev, char *algo_ver_buf); +void aw882xx_device_parse_topo_id_dt(struct aw_device *aw_dev); +void aw882xx_device_parse_port_id_dt(struct aw_device *aw_dev); +int aw882xx_dsp_set_mixer_en(struct aw_device *aw_dev, uint32_t mixer_en); +#ifdef AW_ALGO_AUTH_DSP +int aw882xx_dsp_read_algo_auth_data(struct aw_device *aw_dev, + char *data, unsigned int data_len); +int aw882xx_dsp_write_algo_auth_data(struct aw_device *aw_dev, + char *data, unsigned int data_len); +#endif +#endif + diff --git a/sound/soc/codecs/aw882xx/aw882xx_init.c b/sound/soc/codecs/aw882xx/aw882xx_init.c new file mode 100644 index 000000000000..a4ce5fc91c85 --- /dev/null +++ b/sound/soc/codecs/aw882xx/aw882xx_init.c @@ -0,0 +1,2277 @@ +// SPDX-License-Identifier: GPL-2.0 +/* aw_init.c aw882xx codec module + * + * + * Copyright (c) 2019 AWINIC Technology CO., LTD + * + * Author: Nick Li + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +/* #define DEBUG */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "aw882xx.h" +#include "aw882xx_pid_1852_reg.h" +#include "aw882xx_pid_2013_reg.h" +#include "aw882xx_pid_2032_reg.h" +#include "aw882xx_pid_2055a_reg.h" +#include "aw882xx_pid_2055_reg.h" +#include "aw882xx_pid_2071_reg.h" +#include "aw882xx_pid_2113_reg.h" +#include "aw882xx_pid_2308_reg.h" +#include "aw882xx_log.h" + +static int aw882xx_dev_i2c_write_bits(struct aw_device *aw_dev, + unsigned char reg_addr, unsigned int mask, unsigned int reg_data) +{ + struct aw882xx *aw882xx = (struct aw882xx *)aw_dev->private_data; + + return aw882xx_i2c_write_bits(aw882xx, reg_addr, mask, reg_data); +} + +static int aw882xx_dev_i2c_write(struct aw_device *aw_dev, + unsigned char reg_addr, unsigned int reg_data) +{ + struct aw882xx *aw882xx = (struct aw882xx *)aw_dev->private_data; + + return aw882xx_i2c_write(aw882xx, reg_addr, reg_data); +} + +static int aw882xx_dev_i2c_read(struct aw_device *aw_dev, + unsigned char reg_addr, unsigned int *reg_data) +{ + struct aw882xx *aw882xx = (struct aw882xx *)aw_dev->private_data; + + return aw882xx_i2c_read(aw882xx, reg_addr, reg_data); +} + +static void aw882xx_dev_set_algo_en(struct aw_device *aw_dev) +{ + struct aw882xx *aw882xx = (struct aw882xx *)aw_dev->private_data; + + aw882xx_kcontorl_set(aw882xx); +} + +/* [7 : 4]: -6DB ; [3 : 0]: 0.5DB real_value = value * 2 : 0.5db --> 1 */ +static unsigned int aw_pid_1852_reg_val_to_db(unsigned int value) +{ + return ((value >> 4) * AW_PID_1852_VOL_STEP_DB + (value & 0x0f)); +} + +/* [7 : 4]: -6DB ; [3 : 0]: -0.5DB reg_value = value / step << 4 + value % step ; step = 6 * 2 */ +static unsigned int aw_pid_1852_db_val_to_reg(unsigned int value) +{ + return (((value / AW_PID_1852_VOL_STEP_DB) << 4) + (value % AW_PID_1852_VOL_STEP_DB)); +} + +static int aw_pid_1852_set_volume(struct aw_device *aw_dev, unsigned int value) +{ + unsigned int reg_value = 0; + unsigned int real_value = 0; + struct aw882xx *aw882xx = (struct aw882xx *)aw_dev->private_data; + struct aw_volume_desc *vol_desc = &aw882xx->aw_pa->volume_desc; + + real_value = aw_pid_1852_db_val_to_reg(AW_GET_MIN_VALUE(value, vol_desc->mute_volume)); + + /* cal real value */ + aw882xx_i2c_read(aw882xx, AW_PID_1852_HAGCCFG4_REG, ®_value); + + aw_dev_dbg(aw882xx->dev, "value %d , 0x%x", value, real_value); + + /* 15 : 8] volume */ + real_value = (real_value << 8) | (reg_value & 0x00ff); + + /* write value */ + aw882xx_i2c_write(aw882xx, AW_PID_1852_HAGCCFG4_REG, real_value); + return 0; +} + +static int aw_pid_1852_get_volume(struct aw_device *aw_dev, unsigned int *value) +{ + unsigned int reg_value = 0; + unsigned int real_value = 0; + struct aw882xx *aw882xx = (struct aw882xx *)aw_dev->private_data; + + /* read value */ + aw882xx_i2c_read(aw882xx, AW_PID_1852_HAGCCFG4_REG, ®_value); + + /* [15 : 8] volume */ + real_value = reg_value >> 8; + + real_value = aw_pid_1852_reg_val_to_db(real_value); + *value = real_value; + + return 0; +} + +static bool aw_pid_1852_check_rd_access(int reg) +{ + if (reg >= AW_PID_1852_REG_MAX) + return false; + + + if (aw_pid_1852_reg_access[reg] & AW_PID_1852_REG_RD_ACCESS) + return true; + else + return false; +} + +static bool aw_pid_1852_check_wr_access(int reg) +{ + if (reg >= AW_PID_1852_REG_MAX) + return false; + + + if (aw_pid_1852_reg_access[reg] & AW_PID_1852_REG_WR_ACCESS) + return true; + else + return false; +} + +static int aw_pid_1852_get_reg_num(void) +{ + return AW_PID_1852_REG_MAX; +} + +static unsigned int aw_pid_1852_get_irq_type(struct aw_device *aw_dev, + unsigned int value) +{ + unsigned int ret = INT_TYPE_NONE; + /* UVL0 */ + if (value & (~AW_PID_1852_UVLI_MASK)) { + aw_dev_info(aw_dev->dev, "UVLO: occur"); + ret |= INT_TYPE_UVLO; + } + + /* BSTOCM */ + if (value & (~AW_PID_1852_BSTOCI_MASK)) { + aw_dev_info(aw_dev->dev, "BSTOCI: occur"); + ret |= INT_TYPE_BSTOC; + } + + /* OCDI */ + if (value & (~AW_PID_1852_OCDI_MASK)) { + aw_dev_info(aw_dev->dev, "OCDI: occur"); + ret |= INT_TYPE_OCDI; + } + + /* OTHI */ + if (value & (~AW_PID_1852_OTHI_MASK)) { + aw_dev_info(aw_dev->dev, "OTHI: occur"); + ret |= INT_TYPE_OTHI; + } + + return ret; +} + +static int aw_pid_1852_dev_init(struct aw882xx *aw882xx) +{ + int ret; + struct aw_device *aw_pa = aw882xx->aw_pa; + + /* call aw device init func */ + memset(aw_pa->monitor_name, 0, AW_NAME_MAX); + memcpy(aw_pa->monitor_name, AW_PID_1852_MONITOR_FILE, strlen(AW_PID_1852_MONITOR_FILE)); + + aw_pa->prof_info.prof_desc = NULL; + aw_pa->prof_info.count = 0; + aw_pa->channel = 0; + aw_pa->bstcfg_enable = AW_BSTCFG_DISABLE; + aw_pa->bop_en = AW_BOP_DISABLE; + aw_pa->vol_step = AW_PID_1852_VOL_STEP; + + aw_pa->private_data = (void *)aw882xx; + aw_pa->dev = aw882xx->dev; + aw_pa->i2c = aw882xx->i2c; + aw_pa->ops.aw_get_version = aw882xx_get_version; + aw_pa->ops.aw_get_dev_num = aw882xx_get_dev_num; + aw_pa->ops.aw_set_algo = aw882xx_dev_set_algo_en; + aw_pa->ops.aw_i2c_read = aw882xx_dev_i2c_read; + aw_pa->ops.aw_i2c_write = aw882xx_dev_i2c_write; + aw_pa->ops.aw_i2c_write_bits = aw882xx_dev_i2c_write_bits; + aw_pa->ops.aw_get_hw_volume = aw_pid_1852_get_volume; + aw_pa->ops.aw_set_hw_volume = aw_pid_1852_set_volume; + aw_pa->ops.aw_reg_val_to_db = aw_pid_1852_reg_val_to_db; + aw_pa->ops.aw_check_rd_access = aw_pid_1852_check_rd_access; + aw_pa->ops.aw_check_wr_access = aw_pid_1852_check_wr_access; + aw_pa->ops.aw_get_reg_num = aw_pid_1852_get_reg_num; + aw_pa->ops.aw_get_irq_type = aw_pid_1852_get_irq_type; + + aw_pa->int_desc.mask_reg = AW_PID_1852_SYSINTM_REG; + aw_pa->int_desc.mask_default = AW_PID_1852_SYSINTM_DEFAULT; + aw_pa->int_desc.int_mask = AW_PID_1852_SYSINTM_DEFAULT; + aw_pa->int_desc.st_reg = AW_PID_1852_SYSINT_REG; + + aw_pa->work_mode.reg = AW_PID_1852_SYSCTRL_REG; + aw_pa->work_mode.mask = AW_PID_1852_RCV_MODE_MASK; + aw_pa->work_mode.spk_val = AW_PID_1852_RCV_MODE_SPEAKER_MODE_VCOM13PVDD_VALUE; + aw_pa->work_mode.rcv_val = AW_PID_1852_RCV_MODE_RECEIVER_MODE_VCOM12PVDD_VALUE; + + aw_pa->pwd_desc.reg = AW_PID_1852_SYSCTRL_REG; + aw_pa->pwd_desc.mask = AW_PID_1852_PWDN_MASK; + aw_pa->pwd_desc.enable = AW_PID_1852_PWDN_POWER_DOWN_VALUE; + aw_pa->pwd_desc.disable = AW_PID_1852_PWDN_NORMAL_WORKING_VALUE; + + aw_pa->amppd_desc.reg = AW_PID_1852_SYSCTRL_REG; + aw_pa->amppd_desc.mask = AW_PID_1852_AMPPD_MASK; + aw_pa->amppd_desc.enable = AW_PID_1852_AMPPD_POWER_DOWN_VALUE; + aw_pa->amppd_desc.disable = AW_PID_1852_AMPPD_NORMAL_WORKING_VALUE; + + aw_pa->mute_desc.reg = AW_PID_1852_SYSCTRL2_REG; + aw_pa->mute_desc.mask = AW_PID_1852_HMUTE_MASK; + aw_pa->mute_desc.enable = AW_PID_1852_HMUTE_ENABLE_VALUE; + aw_pa->mute_desc.disable = AW_PID_1852_HMUTE_DISABLE_VALUE; + + aw_pa->uls_hmute_desc.reg = AW_REG_NONE; + + aw_pa->txen_desc.reg = AW_PID_1852_I2SCFG1_REG; + aw_pa->txen_desc.mask = AW_PID_1852_I2STXEN_MASK; + aw_pa->txen_desc.enable = AW_PID_1852_I2STXEN_ENABLE_VALUE; + aw_pa->txen_desc.disable = AW_PID_1852_I2STXEN_DISABLE_VALUE; + + aw_pa->vcalb_desc.vcalb_reg = AW_PID_1852_VTMCTRL3_REG; + aw_pa->vcalb_desc.vcal_factor = AW_PID_1852_VCAL_FACTOR; + aw_pa->vcalb_desc.cabl_base_value = AW_PID_1852_CABL_BASE_VALUE; + + aw_pa->vcalb_desc.icalk_value_factor = AW_PID_1852_ICABLK_FACTOR; + aw_pa->vcalb_desc.icalk_reg = AW_PID_1852_EFRM1_REG; + aw_pa->vcalb_desc.icalkl_reg = AW_REG_NONE; + aw_pa->vcalb_desc.icalk_reg_mask = AW_PID_1852_EF_ISN_GESLP_MASK; + aw_pa->vcalb_desc.icalk_sign_mask = AW_PID_1852_EF_ISN_GESLP_SIGN_MASK; + aw_pa->vcalb_desc.icalk_neg_mask = AW_PID_1852_EF_ISN_GESLP_NEG; + + aw_pa->vcalb_desc.vcalk_reg = AW_PID_1852_EFRH_REG; + aw_pa->vcalb_desc.vcalk_reg_mask = AW_PID_1852_EF_VSN_GESLP_MASK; + aw_pa->vcalb_desc.vcalkl_reg = AW_REG_NONE; + aw_pa->vcalb_desc.vcalk_sign_mask = AW_PID_1852_EF_VSN_GESLP_SIGN_MASK; + aw_pa->vcalb_desc.vcalk_neg_mask = AW_PID_1852_EF_VSN_GESLP_NEG; + aw_pa->vcalb_desc.vcalk_value_factor = AW_PID_1852_VCABLK_FACTOR; + + aw_pa->sysst_desc.reg = AW_PID_1852_SYSST_REG; + aw_pa->sysst_desc.mask = AW_PID_1852_SYSST_CHECK_MASK; + aw_pa->sysst_desc.st_check = AW_PID_1852_SYSST_CHECK; + aw_pa->sysst_desc.pll_check = AW_PID_1852_IIS_CHECK; + + aw_pa->spin_desc.rx_desc.reg = AW_PID_1852_I2SCTRL_REG; + aw_pa->spin_desc.rx_desc.mask = AW_PID_1852_CHSEL_MASK; + aw_pa->spin_desc.rx_desc.left_val = AW_PID_1852_CHSEL_LEFT_VALUE; + aw_pa->spin_desc.rx_desc.right_val = AW_PID_1852_CHSEL_RIGHT_VALUE; + + aw_pa->cco_mux_desc.reg = AW_PID_1852_PLLCTRL1_REG; + aw_pa->cco_mux_desc.mask = AW_PID_1852_I2S_CCO_MUX_MASK; + aw_pa->cco_mux_desc.divided_val = AW_PID_1852_I2S_CCO_MUX_8_16_32KHZ_VALUE; + aw_pa->cco_mux_desc.bypass_val = AW_PID_1852_I2S_CCO_MUX_EXC_8_16_32KHZ_VALUE; + + aw_pa->voltage_desc.reg = AW_PID_1852_VBAT_REG; + aw_pa->voltage_desc.int_bit = AW_PID_1852_MONITOR_INT_10BIT; + aw_pa->voltage_desc.vbat_range = AW_PID_1852_MONITOR_VBAT_RANGE; + + aw_pa->temp_desc.reg = AW_PID_1852_TEMP_REG; + aw_pa->temp_desc.neg_mask = AW_PID_1852_MONITOR_TEMP_NEG_MASK; + aw_pa->temp_desc.sign_mask = AW_PID_1852_MONITOR_TEMP_SIGN_MASK; + + aw_pa->ipeak_desc.reg = AW_PID_1852_SYSCTRL2_REG; + aw_pa->ipeak_desc.mask = AW_PID_1852_BST_IPEAK_MASK; + + aw_pa->volume_desc.reg = AW_PID_1852_HAGCCFG4_REG; + aw_pa->volume_desc.mask = AW_PID_1852_VOL_MASK; + aw_pa->volume_desc.shift = AW_PID_1852_VOL_START_BIT; + aw_pa->volume_desc.mute_volume = AW_PID_1852_MUTE_VOL; + aw_pa->volume_desc.ctl_volume = AW_PID_1852_VOL_DEFAULT_VALUE; + + aw_pa->bop_desc.reg = AW_REG_NONE; + aw_pa->efcheck_desc.reg = AW_REG_NONE; + + aw_pa->soft_rst.reg = AW882XX_SOFT_RESET_REG; + aw_pa->soft_rst.reg_value = AW882XX_SOFT_RESET_VALUE; + + aw_pa->dither_desc.reg = AW_PID_1852_TESTCTRL2_REG; + aw_pa->dither_desc.mask = AW_PID_1852_DITHER_MASK; + aw_pa->dither_desc.enable = AW_PID_1852_DITHER_ENABLE_VALUE; + aw_pa->dither_desc.disable = AW_PID_1852_DITHER_DISABLE_VALUE; + + aw_pa->noise_gate_desc.reg = AW_REG_NONE; + + aw_pa->auth_desc.reg_in = AW_PID_1852_CRCIN_REG; + aw_pa->auth_desc.reg_out = AW_PID_1852_CRCOUT_REG; + + aw_pa->psm_desc.reg = AW_REG_NONE; + aw_pa->mpd_desc.reg = AW_REG_NONE; + aw_pa->dsmzth_desc.reg = AW_REG_NONE; + + ret = aw882xx_device_probe(aw_pa); + + aw882xx->aw_pa = aw_pa; + return ret; +} + +/****************************************************** + * + * A2013 init + * + ******************************************************/ +/*[9 : 6]: -6DB ; [5 : 0]: 0.125DB real_value = value * 8 : 0.125db --> 1*/ +static unsigned int aw_pid_2013_reg_val_to_db(unsigned int value) +{ + return ((value >> 6) * AW_PID_2013_VOL_STEP_DB + (value & 0x003f)); +} + +/*[9 : 6]: -6DB ; [5 : 0]: -0.125DB reg_value = value / step << 6 + value % step ; step = 6 * 8*/ +static unsigned int aw_pid_2013_db_val_to_reg(unsigned int value) +{ + return (((value / AW_PID_2013_VOL_STEP_DB) << 6) + (value % AW_PID_2013_VOL_STEP_DB)); +} + +static int aw_pid_2013_set_volume(struct aw_device *aw_dev, unsigned int value) +{ + unsigned int reg_value = 0; + unsigned int real_value = 0; + struct aw882xx *aw882xx = (struct aw882xx *)aw_dev->private_data; + struct aw_volume_desc *vol_desc = &aw882xx->aw_pa->volume_desc; + + real_value = aw_pid_2013_db_val_to_reg(AW_GET_MIN_VALUE(value, vol_desc->mute_volume)); + + /* cal real value */ + aw882xx_i2c_read(aw882xx, AW_PID_2013_SYSCTRL2_REG, ®_value); + + aw_dev_dbg(aw882xx->dev, "value %d , 0x%x", value, real_value); + + /*9 : 0] volume*/ + real_value = real_value | (reg_value & 0xfc00); + + /* write value */ + aw882xx_i2c_write(aw882xx, AW_PID_2013_SYSCTRL2_REG, real_value); + return 0; +} + +static int aw_pid_2013_get_volume(struct aw_device *aw_dev, unsigned int *value) +{ + unsigned int reg_value = 0; + unsigned int real_value = 0; + struct aw882xx *aw882xx = (struct aw882xx *)aw_dev->private_data; + + /* read value */ + aw882xx_i2c_read(aw882xx, AW_PID_2013_SYSCTRL2_REG, ®_value); + + /*[9 : 0] volume*/ + real_value = reg_value & 0x03ff; + + real_value = aw_pid_2013_reg_val_to_db(real_value); + *value = real_value; + + return 0; +} + +static bool aw_pid_2013_check_rd_access(int reg) +{ + if (reg >= AW_PID_2013_REG_MAX) + return false; + + if (aw_pid_2013_reg_access[reg] & AW_PID_2013_REG_RD_ACCESS) + return true; + else + return false; +} + +static bool aw_pid_2013_check_wr_access(int reg) +{ + if (reg >= AW_PID_2013_REG_MAX) + return false; + + if (aw_pid_2013_reg_access[reg] & AW_PID_2013_REG_WR_ACCESS) + return true; + else + return false; +} + +static int aw_pid_2013_get_reg_num(void) +{ + return AW_PID_2013_REG_MAX; +} + +static unsigned int aw_pid_2013_get_irq_type(struct aw_device *aw_dev, + unsigned int value) +{ + unsigned int ret = INT_TYPE_NONE; + + /*UVL0*/ + if (value & (~AW_PID_2013_UVLI_MASK)) { + aw_dev_info(aw_dev->dev, "UVLO: occur"); + ret |= INT_TYPE_UVLO; + } + + /*BSTOCM*/ + if (value & (~AW_PID_2013_BSTOCI_MASK)) { + aw_dev_info(aw_dev->dev, "BSTOCI: occur"); + ret |= INT_TYPE_BSTOC; + } + + /*OCDI*/ + if (value & (~AW_PID_2013_OCDI_MASK)) { + aw_dev_info(aw_dev->dev, "OCDI: occur"); + ret |= INT_TYPE_OCDI; + } + + /*OTHI*/ + if (value & (~AW_PID_2013_OTHI_MASK)) { + aw_dev_info(aw_dev->dev, "OTHI: occur"); + ret |= INT_TYPE_OTHI; + } + + return ret; +} + +static void aw_pid_2013_efver_check(struct aw_device *aw_dev) +{ + unsigned int reg_val = 0; + unsigned int efverh = 0; + unsigned int efverl = 0; + + aw_dev->ops.aw_i2c_read(aw_dev, + AW_PID_2013_EFRM1_REG, ®_val); + + efverh = (((reg_val & (~AW_PID_2013_EFVERH_MASK)) >> + AW_PID_2013_EFVERH_START_BIT) ^ + AW_PID_2013_EFVER_CHECK); + efverl = (((reg_val & (~AW_PID_2013_EFVERL_MASK)) >> + AW_PID_2013_EFVERL_START_BIT) ^ + AW_PID_2013_EFVER_CHECK); + + aw_dev_dbg(aw_dev->dev, "efverh: 0x%0x, efverl: 0x%0x", efverh, efverl); + + if (efverh && efverl) { + aw_dev->bstcfg_enable = AW_BSTCFG_ENABLE; + aw_dev_info(aw_dev->dev, "A2013 EFVER A"); + } else if (efverh && !efverl) { + aw_dev->bstcfg_enable = AW_BSTCFG_DISABLE; + aw_dev_info(aw_dev->dev, "A2013 EFVER B"); + } else { + aw_dev->bstcfg_enable = AW_BSTCFG_DISABLE; + aw_dev_info(aw_dev->dev, "unsupport A2013 EFVER"); + } + aw_dev_info(aw_dev->dev, "bstcfg enable: %d", aw_dev->bstcfg_enable); +} + +static int aw_pid_2013_dev_init(struct aw882xx *aw882xx) +{ + int ret = 0; + struct aw_device *aw_pa = aw882xx->aw_pa; + + /*call aw device init func*/ + memset(aw_pa->monitor_name, 0, AW_NAME_MAX); + memcpy(aw_pa->monitor_name, AW_PID_2013_MONITOR_FILE, strlen(AW_PID_2013_MONITOR_FILE)); + + aw_pa->prof_info.prof_desc = NULL; + aw_pa->prof_info.count = 0; + aw_pa->channel = 0; + aw_pa->bop_en = AW_BOP_DISABLE; + aw_pa->vol_step = AW_PID_2013_VOL_STEP; + + aw_pa->private_data = (void *)aw882xx; + aw_pa->dev = aw882xx->dev; + aw_pa->i2c = aw882xx->i2c; + aw_pa->ops.aw_get_version = aw882xx_get_version; + aw_pa->ops.aw_get_dev_num = aw882xx_get_dev_num; + aw_pa->ops.aw_set_algo = aw882xx_dev_set_algo_en; + aw_pa->ops.aw_i2c_read = aw882xx_dev_i2c_read; + aw_pa->ops.aw_i2c_write = aw882xx_dev_i2c_write; + aw_pa->ops.aw_i2c_write_bits = aw882xx_dev_i2c_write_bits; + aw_pa->ops.aw_get_hw_volume = aw_pid_2013_get_volume; + aw_pa->ops.aw_set_hw_volume = aw_pid_2013_set_volume; + aw_pa->ops.aw_reg_val_to_db = aw_pid_2013_reg_val_to_db; + aw_pa->ops.aw_check_rd_access = aw_pid_2013_check_rd_access; + aw_pa->ops.aw_check_wr_access = aw_pid_2013_check_wr_access; + aw_pa->ops.aw_get_reg_num = aw_pid_2013_get_reg_num; + aw_pa->ops.aw_get_irq_type = aw_pid_2013_get_irq_type; + + aw_pa->int_desc.mask_reg = AW_PID_2013_SYSINTM_REG; + aw_pa->int_desc.mask_default = AW_PID_2013_SYSINTM_DEFAULT; + aw_pa->int_desc.int_mask = AW_PID_2013_SYSINTM_DEFAULT; + aw_pa->int_desc.st_reg = AW_PID_2013_SYSINT_REG; + + aw_pa->work_mode.reg = AW_PID_2013_SYSCTRL_REG; + aw_pa->work_mode.mask = AW_PID_2013_EN_TRAN_MASK; + aw_pa->work_mode.spk_val = AW_PID_2013_EN_TRAN_SPK_VALUE; + aw_pa->work_mode.rcv_val = AW_PID_2013_EN_TRAN_RCV_VALUE; + + aw_pa->pwd_desc.reg = AW_PID_2013_SYSCTRL_REG; + aw_pa->pwd_desc.mask = AW_PID_2013_PWDN_MASK; + aw_pa->pwd_desc.enable = AW_PID_2013_PWDN_POWER_DOWN_VALUE; + aw_pa->pwd_desc.disable = AW_PID_2013_PWDN_WORKING_VALUE; + + aw_pa->amppd_desc.reg = AW_PID_2013_SYSCTRL_REG; + aw_pa->amppd_desc.mask = AW_PID_2013_AMPPD_MASK; + aw_pa->amppd_desc.enable = AW_PID_2013_AMPPD_POWER_DOWN_VALUE; + aw_pa->amppd_desc.disable = AW_PID_2013_AMPPD_WORKING_VALUE; + + aw_pa->mute_desc.reg = AW_PID_2013_SYSCTRL_REG; + aw_pa->mute_desc.mask = AW_PID_2013_HMUTE_MASK; + aw_pa->mute_desc.enable = AW_PID_2013_HMUTE_ENABLE_VALUE; + aw_pa->mute_desc.disable = AW_PID_2013_HMUTE_DISABLE_VALUE; + + aw_pa->uls_hmute_desc.reg = AW_REG_NONE; + + aw_pa->txen_desc.reg = AW_PID_2013_I2SCTRL1_REG; + aw_pa->txen_desc.mask = AW_PID_2013_I2STXEN_MASK; + aw_pa->txen_desc.enable = AW_PID_2013_I2STXEN_ENABLE_VALUE; + aw_pa->txen_desc.disable = AW_PID_2013_I2STXEN_DISABLE_VALUE; + + aw_pa->vcalb_desc.vcalb_reg = AW_PID_2013_VSNTM1_REG; + aw_pa->vcalb_desc.vcal_factor = AW_PID_2013_VCAL_FACTOR; + aw_pa->vcalb_desc.cabl_base_value = AW_PID_2013_CABL_BASE_VALUE; + + aw_pa->vcalb_desc.icalk_value_factor = AW_PID_2013_ICABLK_FACTOR; + aw_pa->vcalb_desc.icalk_reg = AW_PID_2013_EFRH_REG; + aw_pa->vcalb_desc.icalkl_reg = AW_REG_NONE; + aw_pa->vcalb_desc.icalk_reg_mask = AW_PID_2013_EF_ISN_GESLP_MASK; + aw_pa->vcalb_desc.icalk_sign_mask = AW_PID_2013_EF_ISN_GESLP_SIGN_MASK; + aw_pa->vcalb_desc.icalk_neg_mask = AW_PID_2013_EF_ISN_GESLP_NEG; + + aw_pa->vcalb_desc.vcalk_reg = AW_PID_2013_EFRM2_REG; + aw_pa->vcalb_desc.vcalk_reg_mask = AW_PID_2013_EF_VSN_GESLP_MASK; + aw_pa->vcalb_desc.vcalkl_reg = AW_REG_NONE; + aw_pa->vcalb_desc.vcalk_sign_mask = AW_PID_2013_EF_ISN_GESLP2_SIGN_MASK; + aw_pa->vcalb_desc.vcalk_neg_mask = AW_PID_2013_EF_ISN_GESLP2_NEG; + aw_pa->vcalb_desc.vcalk_value_factor = AW_PID_2013_VCABLK_FACTOR; + + aw_pa->sysst_desc.reg = AW_PID_2013_SYSST_REG; + aw_pa->sysst_desc.mask = AW_PID_2013_SYSST_CHECK_MASK; + aw_pa->sysst_desc.st_check = AW_PID_2013_SYSST_CHECK; + aw_pa->sysst_desc.pll_check = AW_PID_2013_IIS_CHECK; + + aw_pa->profctrl_desc.reg = AW_PID_2013_SYSCTRL_REG; + aw_pa->profctrl_desc.mask = AW_PID_2013_EN_TRAN_MASK; + aw_pa->profctrl_desc.spk_mode = AW_PID_2013_EN_TRAN_SPK_VALUE; + + aw_pa->bstctrl_desc.reg = AW_PID_2013_BSTCTRL2_REG; + aw_pa->bstctrl_desc.mask = AW_PID_2013_BST_MODE_MASK; + aw_pa->bstctrl_desc.frc_bst = AW_PID_2013_BST_MODE_FORCE_BOOST_VALUE; + aw_pa->bstctrl_desc.tsp_type = AW_PID_2013_BST_MODE_TRANSPARENT_VALUE; + + aw_pa->spin_desc.rx_desc.reg = AW_PID_2013_I2SCTRL1_REG; + aw_pa->spin_desc.rx_desc.mask = AW_PID_2013_CHSEL_MASK; + aw_pa->spin_desc.rx_desc.left_val = AW_PID_2013_CHSEL_LEFT_VALUE; + aw_pa->spin_desc.rx_desc.right_val = AW_PID_2013_CHSEL_RIGHT_VALUE; + + aw_pa->voltage_desc.reg = AW_PID_2013_VBAT_REG; + aw_pa->voltage_desc.int_bit = AW_PID_2013_MONITOR_INT_10BIT; + aw_pa->voltage_desc.vbat_range = AW_PID_2013_MONITOR_VBAT_RANGE; + + aw_pa->temp_desc.reg = AW_PID_2013_TEMP_REG; + aw_pa->temp_desc.neg_mask = AW_PID_2013_MONITOR_TEMP_NEG_MASK; + aw_pa->temp_desc.sign_mask = AW_PID_2013_MONITOR_TEMP_SIGN_MASK; + + aw_pa->cco_mux_desc.reg = AW_PID_2013_PLLCTRL3_REG; + aw_pa->cco_mux_desc.mask = AW_PID_2013_CCO_MUX_MASK; + aw_pa->cco_mux_desc.divided_val = AW_PID_2013_CCO_MUX_DIVIDED_VALUE; + aw_pa->cco_mux_desc.bypass_val = AW_PID_2013_CCO_MUX_BYPASS_VALUE; + + aw_pa->ipeak_desc.reg = AW_PID_2013_BSTCTRL2_REG; + aw_pa->ipeak_desc.mask = AW_PID_2013_BST_IPEAK_MASK; + + aw_pa->volume_desc.reg = AW_PID_2013_SYSCTRL2_REG; + aw_pa->volume_desc.mask = AW_PID_2013_VOL_MASK; + aw_pa->volume_desc.shift = AW_PID_2013_VOL_START_BIT; + aw_pa->volume_desc.mute_volume = AW_PID_2013_MUTE_VOL; + aw_pa->volume_desc.ctl_volume = AW_PID_2013_VOL_DEFAULT_VALUE; + + aw_pa->bop_desc.reg = AW_REG_NONE; + aw_pa->efcheck_desc.reg = AW_REG_NONE; + + aw_pa->soft_rst.reg = AW882XX_SOFT_RESET_REG; + aw_pa->soft_rst.reg_value = AW882XX_SOFT_RESET_VALUE; + + aw_pa->dither_desc.reg = AW_PID_2013_DBGCTRL_REG; + aw_pa->dither_desc.mask = AW_PID_2013_DITHER_MASK; + aw_pa->dither_desc.enable = AW_PID_2013_DITHER_ENABLE_VALUE; + aw_pa->dither_desc.disable = AW_PID_2013_DITHER_DISABLE_VALUE; + + aw_pa->noise_gate_desc.reg = AW_REG_NONE; + + aw_pa->auth_desc.reg_in = AW_PID_2013_TESTIN_REG; + aw_pa->auth_desc.reg_out = AW_PID_2013_TESTOUT_REG; + + aw_pa->psm_desc.reg = AW_REG_NONE; + aw_pa->mpd_desc.reg = AW_REG_NONE; + aw_pa->dsmzth_desc.reg = AW_REG_NONE; + + aw_pid_2013_efver_check(aw_pa); + ret = aw882xx_device_probe(aw_pa); + + aw882xx->aw_pa = aw_pa; + return ret; +} + +/****************************************************** + * + * A2032 init + * + ******************************************************/ +/*[7 : 4]: -6DB ; [3 : 0]: 0.5DB real_value = value * 2 : 0.5db --> 1*/ +static unsigned int aw_pid_2032_reg_val_to_db(unsigned int value) +{ + return ((value >> 6) * AW_PID_2032_VOL_STEP_DB + (value & 0x3f)); +} + +/* [7 : 4]: -6DB ; [3 : 0]: -0.5DB reg_value = value / step << 4 + value % step ; step = 6 * 2 */ +static unsigned int aw_pid_2032_db_val_to_reg(unsigned int value) +{ + return (((value / AW_PID_2032_VOL_STEP_DB) << 6) + (value % AW_PID_2032_VOL_STEP_DB)); +} + + +static int aw_pid_2032_set_volume(struct aw_device *aw_dev, unsigned int value) +{ + struct aw882xx *aw882xx = (struct aw882xx *)aw_dev->private_data; + unsigned int reg_value = 0; + unsigned int real_value = 0; + struct aw_volume_desc *vol_desc = &aw882xx->aw_pa->volume_desc; + + real_value = aw_pid_2032_db_val_to_reg(AW_GET_MIN_VALUE(value, vol_desc->mute_volume)); + + /* cal real value */ + aw882xx_i2c_read(aw882xx, AW_PID_2032_SYSCTRL2_REG, ®_value); + + aw_dev_dbg(aw882xx->dev, "value %d , 0x%x", value, real_value); + + /* [15 : 6] volume */ + real_value = (real_value << 6) | (reg_value & 0x003f); + + /* write value */ + aw882xx_i2c_write(aw882xx, AW_PID_2032_SYSCTRL2_REG, real_value); + return 0; +} + +static int aw_pid_2032_get_volume(struct aw_device *aw_dev, unsigned int *value) +{ + unsigned int reg_value = 0; + unsigned int real_value = 0; + struct aw882xx *aw882xx = (struct aw882xx *)aw_dev->private_data; + + /* read value */ + aw882xx_i2c_read(aw882xx, AW_PID_2032_SYSCTRL2_REG, ®_value); + + /* [15 : 6] volume */ + real_value = reg_value >> 6; + + real_value = aw_pid_2032_reg_val_to_db(real_value); + *value = real_value; + + return 0; +} + +static bool aw_pid_2032_check_rd_access(int reg) +{ + if (reg >= AW_PID_2032_REG_MAX) + return false; + + if (aw_pid_2032_reg_access[reg] & AW_PID_2032_REG_RD_ACCESS) + return true; + else + return false; +} + +static bool aw_pid_2032_check_wr_access(int reg) +{ + if (reg >= AW_PID_2032_REG_MAX) + return false; + + if (aw_pid_2032_reg_access[reg] & + AW_PID_2032_REG_WR_ACCESS) + return true; + else + return false; +} + +static int aw_pid_2032_get_reg_num(void) +{ + return AW_PID_2032_REG_MAX; +} + +static unsigned int aw_pid_2032_get_irq_type(struct aw_device *aw_dev, + unsigned int value) +{ + unsigned int ret = INT_TYPE_NONE; + + /* UVL0 */ + if (value & (~AW_PID_2032_UVLI_MASK)) { + aw_dev_info(aw_dev->dev, "UVLO: occur"); + ret |= INT_TYPE_UVLO; + } + + /* BSTOCM */ + if (value & (~AW_PID_2032_BSTOCI_MASK)) { + aw_dev_info(aw_dev->dev, "BSTOCI: occur"); + ret |= INT_TYPE_BSTOC; + } + + /* OCDI */ + if (value & (~AW_PID_2032_OCDI_MASK)) { + aw_dev_info(aw_dev->dev, "OCDI: occur"); + ret |= INT_TYPE_OCDI; + } + + /* OTHI */ + if (value & (~AW_PID_2032_OTHI_MASK)) { + aw_dev_info(aw_dev->dev, "OTHI: occur"); + ret |= INT_TYPE_OTHI; + } + + return ret; +} + +static int aw_pid_2032_dev_init(struct aw882xx *aw882xx) +{ + int ret = 0; + struct aw_device *aw_pa = aw882xx->aw_pa; + + /* call aw device init func */ + memset(aw_pa->monitor_name, 0, AW_NAME_MAX); + memcpy(aw_pa->monitor_name, AW_PID_2032_MONITOR_FILE, strlen(AW_PID_2032_MONITOR_FILE)); + + aw_pa->prof_info.prof_desc = NULL; + aw_pa->prof_info.count = 0; + aw_pa->channel = 0; + aw_pa->bstcfg_enable = AW_BSTCFG_DISABLE; + aw_pa->bop_en = AW_BOP_DISABLE; + aw_pa->vol_step = AW_PID_2032_VOL_STEP; + + aw_pa->private_data = (void *)aw882xx; + aw_pa->dev = aw882xx->dev; + aw_pa->i2c = aw882xx->i2c; + aw_pa->ops.aw_get_version = aw882xx_get_version; + aw_pa->ops.aw_get_dev_num = aw882xx_get_dev_num; + aw_pa->ops.aw_set_algo = aw882xx_dev_set_algo_en; + aw_pa->ops.aw_i2c_read = aw882xx_dev_i2c_read; + aw_pa->ops.aw_i2c_write = aw882xx_dev_i2c_write; + aw_pa->ops.aw_i2c_write_bits = aw882xx_dev_i2c_write_bits; + aw_pa->ops.aw_get_hw_volume = aw_pid_2032_get_volume; + aw_pa->ops.aw_set_hw_volume = aw_pid_2032_set_volume; + aw_pa->ops.aw_reg_val_to_db = aw_pid_2032_reg_val_to_db; + aw_pa->ops.aw_check_rd_access = aw_pid_2032_check_rd_access; + aw_pa->ops.aw_check_wr_access = aw_pid_2032_check_wr_access; + aw_pa->ops.aw_get_reg_num = aw_pid_2032_get_reg_num; + aw_pa->ops.aw_get_irq_type = aw_pid_2032_get_irq_type; + + aw_pa->int_desc.mask_reg = AW_PID_2032_SYSINTM_REG; + aw_pa->int_desc.mask_default = AW_PID_2032_SYSINTM_DEFAULT; + aw_pa->int_desc.int_mask = AW_PID_2032_SYSINTM_DEFAULT; + aw_pa->int_desc.st_reg = AW_PID_2032_SYSINT_REG; + + aw_pa->work_mode.reg = AW_PID_2032_SYSCTRL_REG; + aw_pa->work_mode.mask = AW_PID_2032_RCV_MODE_MASK; + aw_pa->work_mode.spk_val = AW_PID_2032_RCV_MODE_SPEAKER_VALUE; + aw_pa->work_mode.rcv_val = AW_PID_2032_RCV_MODE_RECEIVER_VALUE; + + aw_pa->pwd_desc.reg = AW_PID_2032_SYSCTRL_REG; + aw_pa->pwd_desc.mask = AW_PID_2032_PWDN_MASK; + aw_pa->pwd_desc.enable = AW_PID_2032_PWDN_POWER_DOWN_VALUE; + aw_pa->pwd_desc.disable = AW_PID_2032_PWDN_WORKING_VALUE; + + aw_pa->amppd_desc.reg = AW_PID_2032_SYSCTRL_REG; + aw_pa->amppd_desc.mask = AW_PID_2032_AMPPD_MASK; + aw_pa->amppd_desc.enable = AW_PID_2032_AMPPD_POWER_DOWN_VALUE; + aw_pa->amppd_desc.disable = AW_PID_2032_AMPPD_WORKING_VALUE; + + aw_pa->mute_desc.reg = AW_PID_2032_SYSCTRL2_REG; + aw_pa->mute_desc.mask = AW_PID_2032_HMUTE_MASK; + aw_pa->mute_desc.enable = AW_PID_2032_HMUTE_ENABLE_VALUE; + aw_pa->mute_desc.disable = AW_PID_2032_HMUTE_DISABLE_VALUE; + + aw_pa->uls_hmute_desc.reg = AW_REG_NONE; + + aw_pa->txen_desc.reg = AW_PID_2032_I2SCFG1_REG; + aw_pa->txen_desc.mask = AW_PID_2032_I2STXEN_MASK; + aw_pa->txen_desc.enable = AW_PID_2032_I2STXEN_ENABLE_VALUE; + aw_pa->txen_desc.disable = AW_PID_2032_I2STXEN_DISABLE_VALUE; + + aw_pa->vcalb_desc.vcalb_reg = AW_PID_2032_VTMCTRL3_REG; + aw_pa->vcalb_desc.vcal_factor = AW_PID_2032_VCAL_FACTOR; + aw_pa->vcalb_desc.cabl_base_value = AW_PID_2032_CABL_BASE_VALUE; + + aw_pa->vcalb_desc.icalk_value_factor = AW_PID_2032_ICABLK_FACTOR; + aw_pa->vcalb_desc.icalk_reg = AW_PID_2032_EFRM1_REG; + aw_pa->vcalb_desc.icalkl_reg = AW_REG_NONE; + aw_pa->vcalb_desc.icalk_reg_mask = AW_PID_2032_EF_ISN_GESLP_MASK; + aw_pa->vcalb_desc.icalk_sign_mask = AW_PID_2032_EF_ISN_GESLP_SIGN_MASK; + aw_pa->vcalb_desc.icalk_neg_mask = AW_PID_2032_EF_ISN_GESLP_NEG; + + aw_pa->vcalb_desc.vcalk_reg = AW_PID_2032_EFRH_REG; + aw_pa->vcalb_desc.vcalk_reg_mask = AW_PID_2032_EF_VSN_GESLP_MASK; + aw_pa->vcalb_desc.vcalkl_reg = AW_REG_NONE; + aw_pa->vcalb_desc.vcalk_sign_mask = AW_PID_2032_EF_VSN_GESLP_SIGN_MASK; + aw_pa->vcalb_desc.vcalk_neg_mask = AW_PID_2032_EF_VSN_GESLP_NEG; + aw_pa->vcalb_desc.vcalk_value_factor = AW_PID_2032_VCABLK_FACTOR; + + aw_pa->spin_desc.rx_desc.reg = AW_PID_2032_I2SCTRL_REG; + aw_pa->spin_desc.rx_desc.mask = AW_PID_2032_CHSEL_MASK; + aw_pa->spin_desc.rx_desc.left_val = AW_PID_2032_CHSEL_LEFT_VALUE; + aw_pa->spin_desc.rx_desc.right_val = AW_PID_2032_CHSEL_RIGHT_VALUE; + + aw_pa->sysst_desc.reg = AW_PID_2032_SYSST_REG; + aw_pa->sysst_desc.mask = AW_PID_2032_SYSST_CHECK_MASK; + aw_pa->sysst_desc.st_check = AW_PID_2032_SYSST_CHECK; + aw_pa->sysst_desc.pll_check = AW_PID_2032_IIS_CHECK; + + aw_pa->cco_mux_desc.reg = AW_PID_2032_PLLCTRL1_REG; + aw_pa->cco_mux_desc.mask = AW_PID_2032_CCO_MUX_MASK; + aw_pa->cco_mux_desc.divided_val = AW_PID_2032_CCO_MUX_DIVIDED_VALUE; + aw_pa->cco_mux_desc.bypass_val = AW_PID_2032_CCO_MUX_BYPASS_VALUE; + + aw_pa->voltage_desc.reg = AW_PID_2032_VBAT_REG; + aw_pa->voltage_desc.int_bit = AW_PID_2032_MONITOR_INT_10BIT; + aw_pa->voltage_desc.vbat_range = AW_PID_2032_MONITOR_VBAT_RANGE; + + aw_pa->temp_desc.reg = AW_PID_2032_TEMP_REG; + aw_pa->temp_desc.neg_mask = AW_PID_2032_MONITOR_TEMP_NEG_MASK; + aw_pa->temp_desc.sign_mask = AW_PID_2032_MONITOR_TEMP_SIGN_MASK; + + aw_pa->ipeak_desc.reg = AW_PID_2032_SYSCTRL2_REG; + aw_pa->ipeak_desc.mask = AW_PID_2032_BST_IPEAK_MASK; + + aw_pa->volume_desc.reg = AW_PID_2032_SYSCTRL2_REG; + aw_pa->volume_desc.mask = AW_PID_2032_VOL_MASK; + aw_pa->volume_desc.shift = AW_PID_2032_VOL_START_BIT; + aw_pa->volume_desc.mute_volume = AW_PID_2032_MUTE_VOL; + aw_pa->volume_desc.ctl_volume = AW_PID_2032_VOL_DEFAULT_VALUE; + + aw_pa->bop_desc.reg = AW_REG_NONE; + aw_pa->efcheck_desc.reg = AW_REG_NONE; + + aw_pa->soft_rst.reg = AW882XX_SOFT_RESET_REG; + aw_pa->soft_rst.reg_value = AW882XX_SOFT_RESET_VALUE; + + aw_pa->dither_desc.reg = AW_PID_2032_DBGCTRL_REG; + aw_pa->dither_desc.mask = AW_PID_2032_DITHER_MASK; + aw_pa->dither_desc.enable = AW_PID_2032_DITHER_ENABLE_VALUE; + aw_pa->dither_desc.disable = AW_PID_2032_DITHER_DISABLE_VALUE; + + aw_pa->noise_gate_desc.reg = AW_REG_NONE; + + aw_pa->auth_desc.reg_in = AW_PID_2032_TESTIN_REG; + aw_pa->auth_desc.reg_out = AW_PID_2032_TESTOUT_REG; + + aw_pa->psm_desc.reg = AW_REG_NONE; + aw_pa->mpd_desc.reg = AW_REG_NONE; + aw_pa->dsmzth_desc.reg = AW_REG_NONE; + + ret = aw882xx_device_probe(aw_pa); + + aw882xx->aw_pa = aw_pa; + return ret; +} + +/* [9 : 6]: -6DB ; [5 : 0]: 0.125DB real_value = value * 8 : 0.125db --> 1 */ +static unsigned int aw_pid_2055a_reg_val_to_db(unsigned int value) +{ + return ((value >> 6) * AW_PID_2055A_VOL_STEP_DB + (value & 0x3f)); +} + +/* [9 : 6]: -6DB ; [5 : 0]: 0.125DB reg_value = value / step << 6 + value % step ; step = 6 * 8 */ +static unsigned int aw_pid_2055a_db_val_to_reg(unsigned int value) +{ + return (((value / AW_PID_2055A_VOL_STEP_DB) << 6) + (value % AW_PID_2055A_VOL_STEP_DB)); +} + +static int aw_pid_2055a_set_volume(struct aw_device *aw_dev, unsigned int value) +{ + struct aw882xx *aw882xx = (struct aw882xx *)aw_dev->private_data; + unsigned int reg_value = 0; + unsigned int real_value = 0; + struct aw_volume_desc *vol_desc = &aw882xx->aw_pa->volume_desc; + + real_value = aw_pid_2055a_db_val_to_reg(AW_GET_MIN_VALUE(value, vol_desc->mute_volume)); + + /* cal real value */ + aw882xx_i2c_read(aw882xx, AW_PID_2055A_SYSCTRL2_REG, ®_value); + + aw_dev_dbg(aw882xx->dev, "value %d , 0x%x", value, real_value); + + /*[9 : 0] volume*/ + real_value = (real_value | (reg_value & 0xfc00)); + + /* write value */ + aw882xx_i2c_write(aw882xx, AW_PID_2055A_SYSCTRL2_REG, real_value); + return 0; +} + +static int aw_pid_2055a_get_volume(struct aw_device *aw_dev, unsigned int *value) +{ + unsigned int reg_value = 0; + unsigned int real_value = 0; + struct aw882xx *aw882xx = (struct aw882xx *)aw_dev->private_data; + + /* read value */ + aw882xx_i2c_read(aw882xx, AW_PID_2055A_SYSCTRL2_REG, ®_value); + + /* [9 : 0] volume */ + real_value = (reg_value & 0x03ff); + + real_value = aw_pid_2055a_reg_val_to_db(real_value); + *value = real_value; + + return 0; +} + +static bool aw_pid_2055a_check_rd_access(int reg) +{ + if (reg >= AW_PID_2055A_REG_MAX) + return false; + + + if (aw_pid_2055a_reg_access[reg] & AW_PID_2055A_REG_RD_ACCESS) + return true; + + return false; + +} + +static bool aw_pid_2055a_check_wr_access(int reg) +{ + if (reg >= AW_PID_2055A_REG_MAX) + return false; + + if (aw_pid_2055a_reg_access[reg] & + AW_PID_2055A_REG_WR_ACCESS) + return true; + + return false; +} + +static int aw_pid_2055a_get_reg_num(void) +{ + return AW_PID_2055A_REG_MAX; +} + +static unsigned int aw_pid_2055a_get_irq_type(struct aw_device *aw_dev, + unsigned int value) +{ + unsigned int ret = INT_TYPE_NONE; + + /* UVL0 */ + if (value & (~AW_PID_2055A_UVLI_MASK)) { + aw_dev_info(aw_dev->dev, "UVLO: occur"); + ret |= INT_TYPE_UVLO; + } + + /* BSTOCM */ + if (value & (~AW_PID_2055A_BSTOCI_MASK)) { + aw_dev_info(aw_dev->dev, "BSTOCI: occur"); + ret |= INT_TYPE_BSTOC; + } + + /* OCDI */ + if (value & (~AW_PID_2055A_OCDI_MASK)) { + aw_dev_info(aw_dev->dev, "OCDI: occur"); + ret |= INT_TYPE_OCDI; + } + + /* OTHI */ + if (value & (~AW_PID_2055A_OTHI_MASK)) { + aw_dev_info(aw_dev->dev, "OTHI: occur"); + ret |= INT_TYPE_OTHI; + } + + return ret; +} + +static int aw_pid_2055a_dev_init(struct aw882xx *aw882xx) +{ + int ret = 0; + struct aw_device *aw_pa = aw882xx->aw_pa; + + aw_pa->chip_id = PID_2055A_ID; + + /*call aw device init func*/ + memset(aw_pa->monitor_name, 0, AW_NAME_MAX); + memcpy(aw_pa->monitor_name, AW_PID_2055A_MONITOR_FILE, strlen(AW_PID_2055A_MONITOR_FILE)); + + aw_pa->prof_info.prof_desc = NULL; + aw_pa->prof_info.count = 0; + aw_pa->channel = 0; + aw_pa->bstcfg_enable = AW_BSTCFG_DISABLE; + aw_pa->bop_en = AW_BOP_DISABLE; + aw_pa->vol_step = AW_PID_2055A_VOL_STEP; + + aw_pa->private_data = (void *)aw882xx; + aw_pa->dev = aw882xx->dev; + aw_pa->i2c = aw882xx->i2c; + aw_pa->ops.aw_get_version = aw882xx_get_version; + aw_pa->ops.aw_get_dev_num = aw882xx_get_dev_num; + aw_pa->ops.aw_set_algo = aw882xx_dev_set_algo_en; + aw_pa->ops.aw_i2c_read = aw882xx_dev_i2c_read; + aw_pa->ops.aw_i2c_write = aw882xx_dev_i2c_write; + aw_pa->ops.aw_i2c_write_bits = aw882xx_dev_i2c_write_bits; + aw_pa->ops.aw_get_hw_volume = aw_pid_2055a_get_volume; + aw_pa->ops.aw_set_hw_volume = aw_pid_2055a_set_volume; + aw_pa->ops.aw_reg_val_to_db = aw_pid_2055a_reg_val_to_db; + aw_pa->ops.aw_check_rd_access = aw_pid_2055a_check_rd_access; + aw_pa->ops.aw_check_wr_access = aw_pid_2055a_check_wr_access; + aw_pa->ops.aw_get_reg_num = aw_pid_2055a_get_reg_num; + aw_pa->ops.aw_get_irq_type = aw_pid_2055a_get_irq_type; + + aw_pa->int_desc.mask_reg = AW_PID_2055A_SYSINTM_REG; + aw_pa->int_desc.mask_default = AW_PID_2055A_SYSINTM_DEFAULT; + aw_pa->int_desc.int_mask = AW_PID_2055A_SYSINTM_DEFAULT; + aw_pa->int_desc.st_reg = AW_PID_2055A_SYSINT_REG; + + aw_pa->pwd_desc.reg = AW_PID_2055A_SYSCTRL_REG; + aw_pa->pwd_desc.mask = AW_PID_2055A_PWDN_MASK; + aw_pa->pwd_desc.enable = AW_PID_2055A_PWDN_POWER_DOWN_VALUE; + aw_pa->pwd_desc.disable = AW_PID_2055A_PWDN_WORKING_VALUE; + + aw_pa->amppd_desc.reg = AW_PID_2055A_SYSCTRL_REG; + aw_pa->amppd_desc.mask = AW_PID_2055A_AMPPD_MASK; + aw_pa->amppd_desc.enable = AW_PID_2055A_AMPPD_POWER_DOWN_VALUE; + aw_pa->amppd_desc.disable = AW_PID_2055A_AMPPD_WORKING_VALUE; + + aw_pa->mute_desc.reg = AW_PID_2055A_SYSCTRL_REG; + aw_pa->mute_desc.mask = AW_PID_2055A_HMUTE_MASK; + aw_pa->mute_desc.enable = AW_PID_2055A_HMUTE_ENABLE_VALUE; + aw_pa->mute_desc.disable = AW_PID_2055A_HMUTE_DISABLE_VALUE; + + aw_pa->uls_hmute_desc.reg = AW_REG_NONE; + + aw_pa->txen_desc.reg = AW_PID_2055A_I2SCTRL1_REG; + aw_pa->txen_desc.mask = AW_PID_2055A_I2STXEN_MASK; + aw_pa->txen_desc.enable = AW_PID_2055A_I2STXEN_ENABLE_VALUE; + aw_pa->txen_desc.disable = AW_PID_2055A_I2STXEN_DISABLE_VALUE; + + aw_pa->vcalb_desc.vcalb_reg = AW_REG_NONE; + aw_pa->vcalb_desc.vcalk_reg = AW_REG_NONE; + aw_pa->vcalb_desc.icalk_reg = AW_REG_NONE; + + aw_pa->sysst_desc.reg = AW_PID_2055A_SYSST_REG; + aw_pa->sysst_desc.mask = AW_PID_2055A_SYSST_CHECK_MASK; + aw_pa->sysst_desc.st_check = AW_PID_2055A_SYSST_CHECK; + aw_pa->sysst_desc.pll_check = AW_PID_2055A_IIS_CHECK; + + aw_pa->spin_desc.rx_desc.reg = AW_PID_2055A_I2SCTRL1_REG; + aw_pa->spin_desc.rx_desc.mask = AW_PID_2055A_CHSEL_MASK; + aw_pa->spin_desc.rx_desc.left_val = AW_PID_2055A_CHSEL_LEFT_VALUE; + aw_pa->spin_desc.rx_desc.right_val = AW_PID_2055A_CHSEL_RIGHT_VALUE; + + aw_pa->voltage_desc.reg = AW_REG_NONE; + aw_pa->temp_desc.reg = AW_REG_NONE; + + aw_pa->txen_desc.reg = AW_PID_2055A_I2SCTRL1_REG; + aw_pa->txen_desc.mask = AW_PID_2055A_I2STXEN_MASK; + + aw_pa->ipeak_desc.reg = AW_PID_2055A_BSTCTRL2_REG; + aw_pa->ipeak_desc.mask = AW_PID_2055A_BST_IPEAK_MASK; + + aw_pa->volume_desc.reg = AW_PID_2055A_SYSCTRL2_REG; + aw_pa->volume_desc.mask = AW_PID_2055A_VOL_MASK; + aw_pa->volume_desc.shift = AW_PID_2055A_VOL_START_BIT; + aw_pa->volume_desc.mute_volume = AW_PID_2055A_MUTE_VOL; + aw_pa->volume_desc.ctl_volume = AW_PID_2055A_VOL_DEFAULT_VALUE; + + aw_pa->cco_mux_desc.reg = AW_PID_2055A_PLLCTRL3_REG; + aw_pa->cco_mux_desc.mask = AW_PID_2055A_CCO_MUX_MASK; + aw_pa->cco_mux_desc.divided_val = AW_PID_2055A_CCO_MUX_DIVIDED_VALUE; + aw_pa->cco_mux_desc.bypass_val = AW_PID_2055A_CCO_MUX_BYPASS_VALUE; + + aw_pa->bop_desc.reg = AW_REG_NONE; + aw_pa->efcheck_desc.reg = AW_REG_NONE; + + aw_pa->soft_rst.reg = AW882XX_SOFT_RESET_REG; + aw_pa->soft_rst.reg_value = AW882XX_SOFT_RESET_VALUE; + + aw_pa->dither_desc.reg = AW_PID_2055A_DBGCTRL_REG; + aw_pa->dither_desc.mask = AW_PID_2055A_DITHER_MASK; + aw_pa->dither_desc.enable = AW_PID_2055A_DITHER_ENABLE_VALUE; + aw_pa->dither_desc.disable = AW_PID_2055A_DITHER_DISABLE_VALUE; + + aw_pa->noise_gate_desc.reg = AW_REG_NONE; + + aw_pa->auth_desc.reg_in = AW_PID_2055A_TESTIN_REG; + aw_pa->auth_desc.reg_out = AW_PID_2055A_TESTOUT_REG; + + aw_pa->psm_desc.reg = AW_REG_NONE; + aw_pa->mpd_desc.reg = AW_REG_NONE; + aw_pa->dsmzth_desc.reg = AW_REG_NONE; + + usleep_range(AW_2000_US, AW_2000_US + 10); + aw_pa->ops.aw_i2c_write(aw_pa, AW_PID_2055A_INIT_CHECK_REG, + AW_PID_2055A_INIT_CHECK_VALUE); + usleep_range(AW_3000_US, AW_3000_US + 10); + + ret = aw882xx_device_probe(aw_pa); + + aw882xx->aw_pa = aw_pa; + return ret; +} + + +/* [9 : 6]: -6DB ; [5 : 0]: 0.125DB real_value = value * 8 : 0.125db --> 1 */ +static unsigned int aw_pid_2055_reg_val_to_db(unsigned int value) +{ + return ((value >> 6) * AW_PID_2055_VOL_STEP_DB + (value & 0x3f)); +} + +/* [9 : 6]: -6DB ; [5 : 0]: 0.125DB reg_value = value / step << 6 + value % step ; step = 6 * 8 */ +static unsigned int aw_pid_2055_db_val_to_reg(unsigned int value) +{ + return (((value / AW_PID_2055_VOL_STEP_DB) << 6) + (value % AW_PID_2055_VOL_STEP_DB)); +} + +static int aw_pid_2055_set_volume(struct aw_device *aw_dev, unsigned int value) +{ + struct aw882xx *aw882xx = (struct aw882xx *)aw_dev->private_data; + unsigned int reg_value = 0; + unsigned int real_value = 0; + struct aw_volume_desc *vol_desc = &aw882xx->aw_pa->volume_desc; + + real_value = aw_pid_2055_db_val_to_reg(AW_GET_MIN_VALUE(value, vol_desc->mute_volume)); + + /* cal real value */ + aw882xx_i2c_read(aw882xx, AW_PID_2055_SYSCTRL2_REG, ®_value); + + aw_dev_dbg(aw882xx->dev, "value %d , 0x%x", value, real_value); + + /*[9 : 0] volume*/ + real_value = (real_value | (reg_value & 0xfc00)); + + /* write value */ + aw882xx_i2c_write(aw882xx, AW_PID_2055_SYSCTRL2_REG, real_value); + return 0; +} + +static int aw_pid_2055_get_volume(struct aw_device *aw_dev, unsigned int *value) +{ + unsigned int reg_value = 0; + unsigned int real_value = 0; + struct aw882xx *aw882xx = (struct aw882xx *)aw_dev->private_data; + + /* read value */ + aw882xx_i2c_read(aw882xx, AW_PID_2055_SYSCTRL2_REG, ®_value); + + /* [9 : 0] volume */ + real_value = (reg_value & 0x03ff); + + real_value = aw_pid_2055_reg_val_to_db(real_value); + *value = real_value; + + return 0; +} + +static bool aw_pid_2055_check_rd_access(int reg) +{ + if (reg >= AW_PID_2055_REG_MAX) + return false; + + + if (aw_pid_2055_reg_access[reg] & AW_PID_2055_REG_RD_ACCESS) + return true; + + return false; +} + +static bool aw_pid_2055_check_wr_access(int reg) +{ + if (reg >= AW_PID_2055_REG_MAX) + return false; + + if (aw_pid_2055_reg_access[reg] & + AW_PID_2055_REG_WR_ACCESS) + return true; + + return false; +} + +static int aw_pid_2055_get_reg_num(void) +{ + return AW_PID_2055_REG_MAX; +} + +static unsigned int aw_pid_2055_get_irq_type(struct aw_device *aw_dev, + unsigned int value) +{ + unsigned int ret = INT_TYPE_NONE; + + /* UVL0 */ + if (value & (~AW_PID_2055_UVLI_MASK)) { + aw_dev_info(aw_dev->dev, "UVLO: occur"); + ret |= INT_TYPE_UVLO; + } + + /* BSTOCM */ + if (value & (~AW_PID_2055_BSTOCI_MASK)) { + aw_dev_info(aw_dev->dev, "BSTOCI: occur"); + ret |= INT_TYPE_BSTOC; + } + + /* OCDI */ + if (value & (~AW_PID_2055_OCDI_MASK)) { + aw_dev_info(aw_dev->dev, "OCDI: occur"); + ret |= INT_TYPE_OCDI; + } + + /* OTHI */ + if (value & (~AW_PID_2055_OTHI_MASK)) { + aw_dev_info(aw_dev->dev, "OTHI: occur"); + ret |= INT_TYPE_OTHI; + } + + return ret; +} + +static int aw_pid_2055_dev_init(struct aw882xx *aw882xx) +{ + int ret = 0; + struct aw_device *aw_pa = aw882xx->aw_pa; + + /*call aw device init func*/ + memset(aw_pa->monitor_name, 0, AW_NAME_MAX); + memcpy(aw_pa->monitor_name, AW_PID_2055_MONITOR_FILE, strlen(AW_PID_2055_MONITOR_FILE)); + + aw_pa->prof_info.prof_desc = NULL; + aw_pa->prof_info.count = 0; + aw_pa->channel = 0; + aw_pa->bstcfg_enable = AW_BSTCFG_DISABLE; + aw_pa->bop_en = AW_BOP_DISABLE; + aw_pa->vol_step = AW_PID_2055_VOL_STEP; + + aw_pa->private_data = (void *)aw882xx; + aw_pa->dev = aw882xx->dev; + aw_pa->i2c = aw882xx->i2c; + aw_pa->ops.aw_get_version = aw882xx_get_version; + aw_pa->ops.aw_get_dev_num = aw882xx_get_dev_num; + aw_pa->ops.aw_set_algo = aw882xx_dev_set_algo_en; + aw_pa->ops.aw_i2c_read = aw882xx_dev_i2c_read; + aw_pa->ops.aw_i2c_write = aw882xx_dev_i2c_write; + aw_pa->ops.aw_i2c_write_bits = aw882xx_dev_i2c_write_bits; + aw_pa->ops.aw_get_hw_volume = aw_pid_2055_get_volume; + aw_pa->ops.aw_set_hw_volume = aw_pid_2055_set_volume; + aw_pa->ops.aw_reg_val_to_db = aw_pid_2055_reg_val_to_db; + aw_pa->ops.aw_check_rd_access = aw_pid_2055_check_rd_access; + aw_pa->ops.aw_check_wr_access = aw_pid_2055_check_wr_access; + aw_pa->ops.aw_get_reg_num = aw_pid_2055_get_reg_num; + aw_pa->ops.aw_get_irq_type = aw_pid_2055_get_irq_type; + + aw_pa->int_desc.mask_reg = AW_PID_2055_SYSINTM_REG; + aw_pa->int_desc.mask_default = AW_PID_2055_SYSINTM_DEFAULT; + aw_pa->int_desc.int_mask = AW_PID_2055_SYSINTM_DEFAULT; + aw_pa->int_desc.st_reg = AW_PID_2055_SYSINT_REG; + + aw_pa->pwd_desc.reg = AW_PID_2055_SYSCTRL_REG; + aw_pa->pwd_desc.mask = AW_PID_2055_PWDN_MASK; + aw_pa->pwd_desc.enable = AW_PID_2055_PWDN_POWER_DOWN_VALUE; + aw_pa->pwd_desc.disable = AW_PID_2055_PWDN_WORKING_VALUE; + + aw_pa->amppd_desc.reg = AW_PID_2055_SYSCTRL_REG; + aw_pa->amppd_desc.mask = AW_PID_2055_AMPPD_MASK; + aw_pa->amppd_desc.enable = AW_PID_2055_AMPPD_POWER_DOWN_VALUE; + aw_pa->amppd_desc.disable = AW_PID_2055_AMPPD_WORKING_VALUE; + + aw_pa->mute_desc.reg = AW_PID_2055_SYSCTRL_REG; + aw_pa->mute_desc.mask = AW_PID_2055_HMUTE_MASK; + aw_pa->mute_desc.enable = AW_PID_2055_HMUTE_ENABLE_VALUE; + aw_pa->mute_desc.disable = AW_PID_2055_HMUTE_DISABLE_VALUE; + + aw_pa->uls_hmute_desc.reg = AW_REG_NONE; + + aw_pa->work_mode.reg = AW_PID_2055_SYSCTRL_REG; + aw_pa->work_mode.mask = AW_PID_2055_RCV_MODE_MASK; + aw_pa->work_mode.spk_val = AW_PID_2055_RCV_MODE_SPEAKER_VALUE; + aw_pa->work_mode.rcv_val = AW_PID_2055_RCV_MODE_RECEIVER_VALUE; + + aw_pa->vcalb_desc.vcalb_reg = AW_REG_NONE; + aw_pa->vcalb_desc.vcalk_reg = AW_REG_NONE; + aw_pa->vcalb_desc.icalk_reg = AW_REG_NONE; + + aw_pa->txen_desc.reg = AW_PID_2055_I2SCTRL1_REG; + aw_pa->txen_desc.mask = AW_PID_2055_I2STXEN_MASK; + aw_pa->txen_desc.enable = AW_PID_2055_I2STXEN_ENABLE_VALUE; + aw_pa->txen_desc.disable = AW_PID_2055_I2STXEN_DISABLE_VALUE; + + aw_pa->sysst_desc.reg = AW_PID_2055_SYSST_REG; + aw_pa->sysst_desc.mask = AW_PID_2055_SYSST_CHECK_MASK; + aw_pa->sysst_desc.st_check = AW_PID_2055_SYSST_CHECK; + aw_pa->sysst_desc.pll_check = AW_PID_2055_IIS_CHECK; + + aw_pa->spin_desc.rx_desc.reg = AW_PID_2055_I2SCTRL1_REG; + aw_pa->spin_desc.rx_desc.mask = AW_PID_2055_CHSEL_MASK; + aw_pa->spin_desc.rx_desc.left_val = AW_PID_2055_CHSEL_LEFT_VALUE; + aw_pa->spin_desc.rx_desc.right_val = AW_PID_2055_CHSEL_RIGHT_VALUE; + + aw_pa->voltage_desc.reg = AW_PID_2055_VBAT_REG; + aw_pa->voltage_desc.int_bit = AW_PID_2055_MONITOR_INT_10BIT; + aw_pa->voltage_desc.vbat_range = AW_PID_2055_MONITOR_VBAT_RANGE; + + aw_pa->temp_desc.reg = AW_PID_2055_TEMP_REG; + aw_pa->temp_desc.neg_mask = AW_PID_2055_MONITOR_TEMP_NEG_MASK; + aw_pa->temp_desc.sign_mask = AW_PID_2055_MONITOR_TEMP_SIGN_MASK; + + aw_pa->ipeak_desc.reg = AW_PID_2055_BSTCTRL2_REG; + aw_pa->ipeak_desc.mask = AW_PID_2055_BST_IPEAK_MASK; + + aw_pa->volume_desc.reg = AW_PID_2055_SYSCTRL2_REG; + aw_pa->volume_desc.mask = AW_PID_2055_VOL_MASK; + aw_pa->volume_desc.shift = AW_PID_2055_VOL_START_BIT; + aw_pa->volume_desc.mute_volume = AW_PID_2055_MUTE_VOL; + aw_pa->volume_desc.ctl_volume = AW_PID_2055_VOL_DEFAULT_VALUE; + + aw_pa->cco_mux_desc.reg = AW_PID_2055_PLLCTRL3_REG; + aw_pa->cco_mux_desc.mask = AW_PID_2055_CCO_MUX_MASK; + aw_pa->cco_mux_desc.divided_val = AW_PID_2055_CCO_MUX_DIVIDED_VALUE; + aw_pa->cco_mux_desc.bypass_val = AW_PID_2055_CCO_MUX_BYPASS_VALUE; + + aw_pa->bop_desc.reg = AW_PID_2055_SADCCTRL3_REG; + aw_pa->bop_desc.mask = AW_PID_2055_BOP_EN_MASK; + aw_pa->bop_desc.enable = AW_PID_2055_BOP_EN_ENABLE_VALUE; + aw_pa->bop_desc.disbale = AW_PID_2055_BOP_EN_DISABLE_VALUE; + + aw_pa->soft_rst.reg = AW882XX_SOFT_RESET_REG; + aw_pa->soft_rst.reg_value = AW882XX_SOFT_RESET_VALUE; + + aw_pa->efcheck_desc.reg = AW_REG_NONE; + + aw_pa->dither_desc.reg = AW_PID_2055_DBGCTRL_REG; + aw_pa->dither_desc.mask = AW_PID_2055_DITHER_MASK; + aw_pa->dither_desc.enable = AW_PID_2055_DITHER_ENABLE_VALUE; + aw_pa->dither_desc.disable = AW_PID_2055_DITHER_DISABLE_VALUE; + + aw_pa->noise_gate_desc.reg = AW_REG_NONE; + + aw_pa->auth_desc.reg_in = AW_PID_2055_TESTIN_REG; + aw_pa->auth_desc.reg_out = AW_PID_2055_TESTOUT_REG; + + aw_pa->psm_desc.reg = AW_REG_NONE; + aw_pa->mpd_desc.reg = AW_REG_NONE; + aw_pa->dsmzth_desc.reg = AW_REG_NONE; + + usleep_range(AW_2000_US, AW_2000_US + 10); + aw_pa->ops.aw_i2c_write(aw_pa, AW_PID_2055_INIT_CHECK_REG, + AW_PID_2055_INIT_CHECK_VALUE); + usleep_range(AW_3000_US, AW_3000_US + 10); + + ret = aw882xx_device_probe(aw_pa); + + aw882xx->aw_pa = aw_pa; + return ret; +} + +static int aw_pid_2055_dev_check(struct aw882xx *aw882xx) +{ + unsigned int reg_data = 0; + + aw882xx_i2c_write(aw882xx, AW882XX_SOFT_RESET_REG, AW882XX_SOFT_RESET_VALUE); + usleep_range(AW_1000_US, AW_1000_US + 100); + + aw882xx_i2c_read(aw882xx, AW_PID_2055_VERSION_DIFF_REG, ®_data); + if (reg_data == AW_PID_2055A_VERSION_VALUE) + return aw_pid_2055a_dev_init(aw882xx); + else if (reg_data == AW_PID_2055_VERSION_VALUE) + return aw_pid_2055_dev_init(aw882xx); + + aw_dev_err(aw882xx->dev, "unsupported 2055 verison, 0x%04x", reg_data); + + return -EINVAL; +} + +/* [9 : 6]: -6DB ; [5 : 0]: 0.125DB real_value = value * 8 : 0.125db --> 1 */ +static unsigned int aw_pid_2071_reg_val_to_db(unsigned int value) +{ + return ((value >> 6) * AW_PID_2071_VOL_STEP_DB + (value & 0x3f)); +} + +/* [9 : 6]: -6DB ; [5 : 0]: 0.125DB reg_value = value / step << 6 + value % step ; step = 6 * 8 */ +static unsigned int aw_pid_2071_db_val_to_reg(unsigned int value) +{ + return (((value / AW_PID_2071_VOL_STEP_DB) << 6) + (value % AW_PID_2071_VOL_STEP_DB)); +} + +static int aw_pid_2071_set_volume(struct aw_device *aw_dev, unsigned int value) +{ + unsigned int reg_value = 0; + unsigned int real_value = 0; + struct aw882xx *aw882xx = (struct aw882xx *)aw_dev->private_data; + struct aw_volume_desc *vol_desc = &aw882xx->aw_pa->volume_desc; + + real_value = aw_pid_2071_db_val_to_reg(AW_GET_MIN_VALUE(value, vol_desc->mute_volume)); + + /* cal real value */ + aw882xx_i2c_read(aw882xx, AW_PID_2071_SYSCTRL2_REG, ®_value); + + aw_dev_dbg(aw882xx->dev, "value %d , 0x%x", value, real_value); + + /* [15 : 6] volume */ + real_value = (real_value << 6) | (reg_value & 0x003f); + + /* write value */ + aw882xx_i2c_write(aw882xx, AW_PID_2071_SYSCTRL2_REG, real_value); + return 0; +} + +static int aw_pid_2071_get_volume(struct aw_device *aw_dev, unsigned int *value) +{ + unsigned int reg_value = 0; + unsigned int real_value = 0; + struct aw882xx *aw882xx = (struct aw882xx *)aw_dev->private_data; + + /* read value */ + aw882xx_i2c_read(aw882xx, AW_PID_2071_SYSCTRL2_REG, ®_value); + + /* [15 : 6] volume */ + real_value = reg_value >> 6; + + real_value = aw_pid_2071_reg_val_to_db(real_value); + *value = real_value; + + return 0; +} + +static bool aw_pid_2071_check_rd_access(int reg) +{ + if (reg >= AW_PID_2071_REG_MAX) + return false; + + if (aw_pid_2071_reg_access[reg] & AW_PID_2071_REG_RD_ACCESS) + return true; + else + return false; +} + +static bool aw_pid_2071_check_wr_access(int reg) +{ + if (reg >= AW_PID_2071_REG_MAX) + return false; + + if (aw_pid_2071_reg_access[reg] & + AW_PID_2071_REG_WR_ACCESS) + return true; + else + return false; +} + +static int aw_pid_2071_get_reg_num(void) +{ + return AW_PID_2071_REG_MAX; +} + +static unsigned int aw_pid_2071_get_irq_type(struct aw_device *aw_dev, + unsigned int value) +{ + unsigned int ret = INT_TYPE_NONE; + + /* UVL0 */ + if (value & (~AW_PID_2071_UVLI_MASK)) { + aw_dev_info(aw_dev->dev, "UVLO: occur"); + ret |= INT_TYPE_UVLO; + } + + /* BSTOCM */ + if (value & (~AW_PID_2071_BSTOCI_MASK)) { + aw_dev_info(aw_dev->dev, "BSTOCI: occur"); + ret |= INT_TYPE_BSTOC; + } + + /* OCDI */ + if (value & (~AW_PID_2071_OCDI_MASK)) { + aw_dev_info(aw_dev->dev, "OCDI: occur"); + ret |= INT_TYPE_OCDI; + } + + /* OTHI */ + if (value & (~AW_PID_2071_OTHI_MASK)) { + aw_dev_info(aw_dev->dev, "OTHI: occur"); + ret |= INT_TYPE_OTHI; + } + + return ret; +} + +static int aw_pid_2071_dev_init(struct aw882xx *aw882xx) +{ + int ret = 0; + struct aw_device *aw_pa = aw882xx->aw_pa; + + /*call aw device init func*/ + memset(aw_pa->monitor_name, 0, AW_NAME_MAX); + memcpy(aw_pa->monitor_name, AW_PID_2071_MONITOR_FILE, strlen(AW_PID_2071_MONITOR_FILE)); + + aw_pa->prof_info.prof_desc = NULL; + aw_pa->prof_info.count = 0; + aw_pa->channel = 0; + aw_pa->bstcfg_enable = AW_BSTCFG_DISABLE; + aw_pa->bop_en = AW_BOP_DISABLE; + aw_pa->vol_step = AW_PID_2071_VOL_STEP; + + aw_pa->private_data = (void *)aw882xx; + aw_pa->dev = aw882xx->dev; + aw_pa->i2c = aw882xx->i2c; + aw_pa->ops.aw_get_version = aw882xx_get_version; + aw_pa->ops.aw_get_dev_num = aw882xx_get_dev_num; + aw_pa->ops.aw_set_algo = aw882xx_dev_set_algo_en; + aw_pa->ops.aw_i2c_read = aw882xx_dev_i2c_read; + aw_pa->ops.aw_i2c_write = aw882xx_dev_i2c_write; + aw_pa->ops.aw_i2c_write_bits = aw882xx_dev_i2c_write_bits; + aw_pa->ops.aw_get_hw_volume = aw_pid_2071_get_volume; + aw_pa->ops.aw_set_hw_volume = aw_pid_2071_set_volume; + aw_pa->ops.aw_reg_val_to_db = aw_pid_2071_reg_val_to_db; + aw_pa->ops.aw_check_rd_access = aw_pid_2071_check_rd_access; + aw_pa->ops.aw_check_wr_access = aw_pid_2071_check_wr_access; + aw_pa->ops.aw_get_reg_num = aw_pid_2071_get_reg_num; + aw_pa->ops.aw_get_irq_type = aw_pid_2071_get_irq_type; + + aw_pa->int_desc.mask_reg = AW_PID_2071_SYSINTM_REG; + aw_pa->int_desc.mask_default = AW_PID_2071_SYSINTM_DEFAULT; + aw_pa->int_desc.int_mask = AW_PID_2071_SYSINTM_DEFAULT; + aw_pa->int_desc.st_reg = AW_PID_2071_SYSINT_REG; + + aw_pa->work_mode.reg = AW_PID_2071_SYSCTRL_REG; + aw_pa->work_mode.mask = AW_PID_2071_RCV_MODE_MASK; + aw_pa->work_mode.spk_val = AW_PID_2071_RCV_MODE_SPEAKER_VALUE; + aw_pa->work_mode.rcv_val = AW_PID_2071_RCV_MODE_RECEIVER_VALUE; + + aw_pa->pwd_desc.reg = AW_PID_2071_SYSCTRL_REG; + aw_pa->pwd_desc.mask = AW_PID_2071_PWDN_MASK; + aw_pa->pwd_desc.enable = AW_PID_2071_PWDN_POWER_DOWN_VALUE; + aw_pa->pwd_desc.disable = AW_PID_2071_PWDN_WORKING_VALUE; + + aw_pa->amppd_desc.reg = AW_PID_2071_SYSCTRL_REG; + aw_pa->amppd_desc.mask = AW_PID_2071_AMPPD_MASK; + aw_pa->amppd_desc.enable = AW_PID_2071_AMPPD_POWER_DOWN_VALUE; + aw_pa->amppd_desc.disable = AW_PID_2071_AMPPD_WORKING_VALUE; + + aw_pa->mute_desc.reg = AW_PID_2071_SYSCTRL2_REG; + aw_pa->mute_desc.mask = AW_PID_2071_HMUTE_MASK; + aw_pa->mute_desc.enable = AW_PID_2071_HMUTE_ENABLE_VALUE; + aw_pa->mute_desc.disable = AW_PID_2071_HMUTE_DISABLE_VALUE; + + aw_pa->uls_hmute_desc.reg = AW_REG_NONE; + + aw_pa->txen_desc.reg = AW_PID_2071_I2SCFG1_REG; + aw_pa->txen_desc.mask = AW_PID_2071_I2STXEN_MASK; + aw_pa->txen_desc.enable = AW_PID_2071_I2STXEN_ENABLE_VALUE; + aw_pa->txen_desc.disable = AW_PID_2071_I2STXEN_DISABLE_VALUE; + + aw_pa->vcalb_desc.vcalb_reg = AW_PID_2071_VTMCTRL3_REG; + aw_pa->vcalb_desc.vcal_factor = AW_PID_2071_VCAL_FACTOR; + aw_pa->vcalb_desc.cabl_base_value = AW_PID_2071_CABL_BASE_VALUE; + + aw_pa->vcalb_desc.icalk_value_factor = AW_PID_2071_ICABLK_FACTOR; + aw_pa->vcalb_desc.icalk_reg = AW_PID_2071_EFRH_REG; + aw_pa->vcalb_desc.icalk_reg_mask = AW_PID_2071_EF_VSN_OFFSET_MASK; + aw_pa->vcalb_desc.icalk_shift = AW_PID_2071_ICALK_SHIFT; + aw_pa->vcalb_desc.icalkl_reg = AW_PID_2071_EFRM1_REG; + aw_pa->vcalb_desc.icalkl_reg_mask = AW_PID_2071_EF_ISN_OFFSET_MASK; + aw_pa->vcalb_desc.icalkl_shift = AW_PID_2071_ICALKL_SHIFT; + aw_pa->vcalb_desc.icalk_sign_mask = AW_PID_2071_EF_ISN_GESLP_SIGN_MASK; + aw_pa->vcalb_desc.icalk_neg_mask = AW_PID_2071_EF_ISN_GESLP_NEG; + + aw_pa->vcalb_desc.vcalk_reg = AW_PID_2071_EFRH_REG; + aw_pa->vcalb_desc.vcalk_reg_mask = AW_PID_2071_EF_VSN_GESLP_MASK; + aw_pa->vcalb_desc.vcalkl_reg = AW_REG_NONE; + aw_pa->vcalb_desc.vcalk_sign_mask = AW_PID_2071_EF_VSN_GESLP_SIGN_MASK; + aw_pa->vcalb_desc.vcalk_neg_mask = AW_PID_2071_EF_VSN_GESLP_NEG; + aw_pa->vcalb_desc.vcalk_value_factor = AW_PID_2071_VCABLK_FACTOR; + + aw_pa->spin_desc.rx_desc.reg = AW_PID_2071_I2SCTRL_REG; + aw_pa->spin_desc.rx_desc.mask = AW_PID_2071_CHSEL_MASK; + aw_pa->spin_desc.rx_desc.left_val = AW_PID_2071_CHSEL_LEFT_VALUE; + aw_pa->spin_desc.rx_desc.right_val = AW_PID_2071_CHSEL_RIGHT_VALUE; + + aw_pa->sysst_desc.reg = AW_PID_2071_SYSST_REG; + aw_pa->sysst_desc.mask = AW_PID_2071_SYSST_CHECK_MASK; + aw_pa->sysst_desc.st_check = AW_PID_2071_SYSST_CHECK; + aw_pa->sysst_desc.pll_check = AW_PID_2071_IIS_CHECK; + + aw_pa->cco_mux_desc.reg = AW_PID_2071_PLLCTRL1_REG; + aw_pa->cco_mux_desc.mask = AW_PID_2071_CCO_MUX_MASK; + aw_pa->cco_mux_desc.divided_val = AW_PID_2071_CCO_MUX_DIVIDED_VALUE; + aw_pa->cco_mux_desc.bypass_val = AW_PID_2071_CCO_MUX_BYPASS_VALUE; + + aw_pa->voltage_desc.reg = AW_PID_2071_VBAT_REG; + aw_pa->voltage_desc.int_bit = AW_PID_2071_MONITOR_INT_10BIT; + aw_pa->voltage_desc.vbat_range = AW_PID_2071_MONITOR_VBAT_RANGE; + + aw_pa->temp_desc.reg = AW_PID_2071_TEMP_REG; + aw_pa->temp_desc.neg_mask = AW_PID_2071_MONITOR_TEMP_NEG_MASK; + aw_pa->temp_desc.sign_mask = AW_PID_2071_MONITOR_TEMP_SIGN_MASK; + + aw_pa->ipeak_desc.reg = AW_PID_2071_SYSCTRL2_REG; + aw_pa->ipeak_desc.mask = AW_PID_2071_BST_IPEAK_MASK; + + aw_pa->volume_desc.reg = AW_PID_2071_SYSCTRL2_REG; + aw_pa->volume_desc.mask = AW_PID_2071_VOL_MASK; + aw_pa->volume_desc.shift = AW_PID_2071_VOL_START_BIT; + aw_pa->volume_desc.mute_volume = AW_PID_2071_MUTE_VOL; + aw_pa->volume_desc.ctl_volume = AW_PID_2071_VOL_DEFAULT_VALUE; + + aw_pa->efcheck_desc.reg = AW_REG_NONE; + aw_pa->efuse_check = AW_EF_OR_CHECK; + + aw_pa->bop_desc.reg = AW_REG_NONE; + + aw_pa->dither_desc.reg = AW_PID_2071_DBGCTRL_REG; + aw_pa->dither_desc.mask = AW_PID_2071_DITHER_MASK; + aw_pa->dither_desc.enable = AW_PID_2071_DITHER_ENABLE_VALUE; + aw_pa->dither_desc.disable = AW_PID_2071_DITHER_DISABLE_VALUE; + + aw_pa->soft_rst.reg = AW882XX_SOFT_RESET_REG; + aw_pa->soft_rst.reg_value = AW882XX_SOFT_RESET_VALUE; + + aw_pa->noise_gate_desc.reg = AW_REG_NONE; + + aw_pa->auth_desc.reg_in = AW_PID_2071_TESTIN_REG; + aw_pa->auth_desc.reg_out = AW_PID_2071_TESTOUT_REG; + + aw_pa->psm_desc.reg = AW_REG_NONE; + aw_pa->mpd_desc.reg = AW_REG_NONE; + aw_pa->dsmzth_desc.reg = AW_REG_NONE; + + ret = aw882xx_device_probe(aw_pa); + + aw882xx->aw_pa = aw_pa; + return ret; +} + +/* [9 : 6]: -6DB ; [5 : 0]: 0.125DB real_value = value * 8 : 0.125db --> 1 */ +static unsigned int aw_pid_2113_reg_val_to_db(unsigned int value) +{ + return ((value >> 6) * AW_PID_2113_VOL_STEP_DB + (value & 0x3f)); +} + +/* [9 : 6]: -6DB ; [5 : 0]: 0.125DB reg_value = value / step << 6 + value % step ; step = 6 * 8 */ +static unsigned int aw_pid_2113_db_val_to_reg(unsigned int value) +{ + return (((value / AW_PID_2113_VOL_STEP_DB) << 6) + (value % AW_PID_2113_VOL_STEP_DB)); +} + +static int aw_pid_2113_set_volume(struct aw_device *aw_dev, unsigned int value) +{ + unsigned int reg_value = 0; + unsigned int real_value = 0; + struct aw882xx *aw882xx = (struct aw882xx *)aw_dev->private_data; + struct aw_volume_desc *vol_desc = &aw882xx->aw_pa->volume_desc; + + real_value = aw_pid_2113_db_val_to_reg(AW_GET_MIN_VALUE(value, vol_desc->mute_volume)); + + aw_dev_dbg(aw882xx->dev, "value:%d, min_val: %d, real_value: 0x%x", + value, AW_GET_MIN_VALUE(value, vol_desc->mute_volume), real_value); + + /* cal real value */ + aw882xx_i2c_read(aw882xx, AW_PID_2113_SYSCTRL2_REG, ®_value); + + /*[9 : 0] volume*/ + real_value = (real_value | (reg_value & 0xfc00)); + + /* write value */ + aw882xx_i2c_write(aw882xx, AW_PID_2113_SYSCTRL2_REG, real_value); + + return 0; +} + +static int aw_pid_2113_get_volume(struct aw_device *aw_dev, unsigned int *value) +{ + unsigned int reg_value = 0; + unsigned int real_value = 0; + struct aw882xx *aw882xx = (struct aw882xx *)aw_dev->private_data; + + /* read value */ + aw882xx_i2c_read(aw882xx, AW_PID_2113_SYSCTRL2_REG, ®_value); + + /* [9 : 0] volume */ + real_value = (reg_value & 0x03ff); + + real_value = aw_pid_2113_reg_val_to_db(real_value); + *value = real_value; + + return 0; +} + +static bool aw_pid_2113_check_rd_access(int reg) +{ + if (reg >= AW_PID_2113_REG_MAX) + return false; + + if (aw_pid_2113_reg_access[reg] & AW_PID_2113_REG_RD_ACCESS) + return true; + else + return false; +} + +static bool aw_pid_2113_check_wr_access(int reg) +{ + if (reg >= AW_PID_2113_REG_MAX) + return false; + + if (aw_pid_2113_reg_access[reg] & + AW_PID_2113_REG_WR_ACCESS) + return true; + else + return false; +} + +static int aw_pid_2113_get_reg_num(void) +{ + return AW_PID_2113_REG_MAX; +} + +static unsigned int aw_pid_2113_get_irq_type(struct aw_device *aw_dev, + unsigned int value) +{ + unsigned int ret = INT_TYPE_NONE; + + /* UVL0 */ + if (value & (~AW_PID_2113_UVLI_MASK)) { + aw_dev_info(aw_dev->dev, "UVLO: occur"); + ret |= INT_TYPE_UVLO; + } + + /* BSTOCM */ + if (value & (~AW_PID_2113_BSTOCI_MASK)) { + aw_dev_info(aw_dev->dev, "BSTOCI: occur"); + ret |= INT_TYPE_BSTOC; + } + + /* OCDI */ + if (value & (~AW_PID_2113_OCDI_MASK)) { + aw_dev_info(aw_dev->dev, "OCDI: occur"); + ret |= INT_TYPE_OCDI; + } + + /* OTHI */ + if (value & (~AW_PID_2113_OTHI_MASK)) { + aw_dev_info(aw_dev->dev, "OTHI: occur"); + ret |= INT_TYPE_OTHI; + } + + return ret; +} + +static int aw_pid_2113_frcset_check(struct aw_device *aw_dev) +{ + unsigned int reg_val = 0; + uint16_t temh = 0; + uint16_t teml = 0; + uint16_t tem = 0; + + aw_dev->ops.aw_i2c_read(aw_dev, + AW_PID_2113_EFRH3_REG, ®_val); + temh = ((uint16_t)reg_val & (~AW_PID_2113_TEMH_MASK)); + + aw_dev->ops.aw_i2c_read(aw_dev, + AW_PID_2113_EFRL3_REG, ®_val); + teml = ((uint16_t)reg_val & (~AW_PID_2113_TEML_MASK)); + + if (aw_dev->efuse_check == AW_EF_OR_CHECK) + tem = (temh | teml); + else + tem = (temh & teml); + + if (tem == AW_PID_2113_DEFAULT_CFG) + aw_dev->frcset_en = AW_FRCSET_ENABLE; + else + aw_dev->frcset_en = AW_FRCSET_DISABLE; + + aw_dev_info(aw_dev->dev, "tem is 0x%04x, frcset_en is %d", + tem, aw_dev->frcset_en); + return 0; +} + +static void aw_pid_2113_reg_force_set(struct aw_device *aw_dev) +{ + aw_dev_dbg(aw_dev->dev, "enter"); + + if (aw_dev->frcset_en == AW_FRCSET_ENABLE) { + /*set FORCE_PWM*/ + aw_dev->ops.aw_i2c_write_bits(aw_dev, AW_PID_2113_BSTCTRL3_REG, + AW_PID_2113_FORCE_PWM_MASK, AW_PID_2113_FORCE_PWM_FORCEMINUS_PWM_VALUE); + /*set BOOST_OS_WIDTH*/ + aw_dev->ops.aw_i2c_write_bits(aw_dev, AW_PID_2113_BSTCTRL5_REG, + AW_PID_2113_BST_OS_WIDTH_MASK, AW_PID_2113_BST_OS_WIDTH_50NS_VALUE); + /*set BURST_LOOPR*/ + aw_dev->ops.aw_i2c_write_bits(aw_dev, AW_PID_2113_BSTCTRL6_REG, + AW_PID_2113_BST_LOOPR_MASK, AW_PID_2113_BST_LOOPR_340K_VALUE); + /*set RSQN_DLY*/ + aw_dev->ops.aw_i2c_write_bits(aw_dev, AW_PID_2113_BSTCTRL7_REG, + AW_PID_2113_RSQN_DLY_MASK, AW_PID_2113_RSQN_DLY_35NS_VALUE); + /*set BURST_SSMODE*/ + aw_dev->ops.aw_i2c_write_bits(aw_dev, AW_PID_2113_BSTCTRL8_REG, + AW_PID_2113_BURST_SSMODE_MASK, AW_PID_2113_BURST_SSMODE_FAST_VALUE); + /*set BST_BURST*/ + aw_dev->ops.aw_i2c_write_bits(aw_dev, AW_PID_2113_BSTCTRL9_REG, + AW_PID_2113_BST_BURST_MASK, AW_PID_2113_BST_BURST_30MA_VALUE); + aw_dev_dbg(aw_dev->dev, "force set reg done!"); + } else { + aw_dev_info(aw_dev->dev, "needn't set reg value"); + } +} + +static int aw_pid_2113_dev_init(struct aw882xx *aw882xx) +{ + int ret = 0; + struct aw_device *aw_pa = aw882xx->aw_pa; + + /*call aw device init func*/ + memset(aw_pa->monitor_name, 0, AW_NAME_MAX); + memcpy(aw_pa->monitor_name, AW_PID_2113_MONITOR_FILE, strlen(AW_PID_2113_MONITOR_FILE)); + + aw_pa->prof_info.prof_desc = NULL; + aw_pa->prof_info.count = 0; + aw_pa->channel = 0; + aw_pa->bstcfg_enable = AW_BSTCFG_DISABLE; + aw_pa->bop_en = AW_BOP_DISABLE; + aw_pa->vol_step = AW_PID_2113_VOL_STEP; + + aw_pa->private_data = (void *)aw882xx; + aw_pa->dev = aw882xx->dev; + aw_pa->i2c = aw882xx->i2c; + aw_pa->ops.aw_get_version = aw882xx_get_version; + aw_pa->ops.aw_get_dev_num = aw882xx_get_dev_num; + aw_pa->ops.aw_set_algo = aw882xx_dev_set_algo_en; + aw_pa->ops.aw_i2c_read = aw882xx_dev_i2c_read; + aw_pa->ops.aw_i2c_write = aw882xx_dev_i2c_write; + aw_pa->ops.aw_i2c_write_bits = aw882xx_dev_i2c_write_bits; + aw_pa->ops.aw_get_hw_volume = aw_pid_2113_get_volume; + aw_pa->ops.aw_set_hw_volume = aw_pid_2113_set_volume; + aw_pa->ops.aw_reg_val_to_db = aw_pid_2113_reg_val_to_db; + aw_pa->ops.aw_check_rd_access = aw_pid_2113_check_rd_access; + aw_pa->ops.aw_check_wr_access = aw_pid_2113_check_wr_access; + aw_pa->ops.aw_get_reg_num = aw_pid_2113_get_reg_num; + aw_pa->ops.aw_get_irq_type = aw_pid_2113_get_irq_type; + aw_pa->ops.aw_reg_force_set = aw_pid_2113_reg_force_set; + aw_pa->ops.aw_frcset_check = aw_pid_2113_frcset_check; + + aw_pa->int_desc.mask_reg = AW_PID_2113_SYSINTM_REG; + aw_pa->int_desc.mask_default = AW_PID_2113_SYSINTM_DEFAULT; + aw_pa->int_desc.int_mask = AW_PID_2113_SYSINTM_DEFAULT; + aw_pa->int_desc.st_reg = AW_PID_2113_SYSINT_REG; + + aw_pa->work_mode.reg = AW_PID_2113_SYSCTRL_REG; + aw_pa->work_mode.mask = AW_PID_2113_EN_TRAN_MASK; + aw_pa->work_mode.spk_val = AW_PID_2113_EN_TRAN_SPK_VALUE; + aw_pa->work_mode.rcv_val = AW_PID_2113_EN_TRAN_RCV_VALUE; + + aw_pa->pwd_desc.reg = AW_PID_2113_SYSCTRL_REG; + aw_pa->pwd_desc.mask = AW_PID_2113_PWDN_MASK; + aw_pa->pwd_desc.enable = AW_PID_2113_PWDN_POWER_DOWN_VALUE; + aw_pa->pwd_desc.disable = AW_PID_2113_PWDN_WORKING_VALUE; + + aw_pa->work_mode.reg = AW_PID_2113_SYSCTRL_REG; + aw_pa->work_mode.mask = AW_PID_2113_EN_TRAN_MASK; + aw_pa->work_mode.spk_val = AW_PID_2113_EN_TRAN_SPK_VALUE; + aw_pa->work_mode.rcv_val = AW_PID_2113_EN_TRAN_RCV_VALUE; + + aw_pa->amppd_desc.reg = AW_PID_2113_SYSCTRL_REG; + aw_pa->amppd_desc.mask = AW_PID_2113_AMPPD_MASK; + aw_pa->amppd_desc.enable = AW_PID_2113_AMPPD_POWER_DOWN_VALUE; + aw_pa->amppd_desc.disable = AW_PID_2113_AMPPD_WORKING_VALUE; + + aw_pa->mute_desc.reg = AW_PID_2113_SYSCTRL_REG; + aw_pa->mute_desc.mask = AW_PID_2113_HMUTE_MASK; + aw_pa->mute_desc.enable = AW_PID_2113_HMUTE_ENABLE_VALUE; + aw_pa->mute_desc.disable = AW_PID_2113_HMUTE_DISABLE_VALUE; + + aw_pa->uls_hmute_desc.reg = AW_PID_2113_SYSCTRL_REG; + aw_pa->uls_hmute_desc.mask = AW_PID_2113_ULS_HMUTE_MASK; + aw_pa->uls_hmute_desc.enable = AW_PID_2113_ULS_HMUTE_ENABLE_VALUE; + aw_pa->uls_hmute_desc.disable = AW_PID_2113_ULS_HMUTE_DISABLE_VALUE; + + aw_pa->vcalb_desc.vcalb_reg = AW_PID_2113_VSNTM1_REG; + aw_pa->vcalb_desc.vcal_factor = AW_PID_2113_VCAL_FACTOR; + aw_pa->vcalb_desc.cabl_base_value = AW_PID_2113_CABL_BASE_VALUE; + + aw_pa->txen_desc.reg = AW_PID_2113_I2SCTRL3_REG; + aw_pa->txen_desc.mask = AW_PID_2113_I2STXEN_MASK; + aw_pa->txen_desc.enable = AW_PID_2113_I2STXEN_ENABLE_VALUE; + aw_pa->txen_desc.disable = AW_PID_2113_I2STXEN_DISABLE_VALUE; + + aw_pa->vcalb_desc.icalk_reg = AW_PID_2113_EFRH4_REG; + aw_pa->vcalb_desc.icalk_reg_mask = AW_PID_2113_EF_ISN_GESLP_H_MASK; + aw_pa->vcalb_desc.icalk_shift = AW_PID_2113_ICALK_SHIFT; + aw_pa->vcalb_desc.icalkl_reg = AW_PID_2113_EFRL4_REG; + aw_pa->vcalb_desc.icalkl_reg_mask = AW_PID_2113_EF_ISN_GESLP_L_MASK; + aw_pa->vcalb_desc.icalkl_shift = AW_PID_2113_ICALKL_SHIFT; + aw_pa->vcalb_desc.icalk_sign_mask = AW_PID_2113_EF_ISN_GESLP_SIGN_MASK; + aw_pa->vcalb_desc.icalk_neg_mask = AW_PID_2113_EF_ISN_GESLP_NEG; + aw_pa->vcalb_desc.icalk_value_factor = AW_PID_2113_ICABLK_FACTOR; + + aw_pa->vcalb_desc.vcalk_reg = AW_PID_2113_EFRH3_REG; + aw_pa->vcalb_desc.vcalk_reg_mask = AW_PID_2113_EF_VSN_GESLP_H_MASK; + aw_pa->vcalb_desc.vcalk_shift = AW_PID_2113_VCALK_SHIFT; + aw_pa->vcalb_desc.vcalkl_reg = AW_PID_2113_EFRL3_REG; + aw_pa->vcalb_desc.vcalkl_reg_mask = AW_PID_2113_EF_VSN_GESLP_L_MASK; + aw_pa->vcalb_desc.vcalkl_shift = AW_PID_2113_VCALKL_SHIFT; + aw_pa->vcalb_desc.vcalk_sign_mask = AW_PID_2113_EF_VSN_GESLP_SIGN_MASK; + aw_pa->vcalb_desc.vcalk_neg_mask = AW_PID_2113_EF_VSN_GESLP_NEG; + aw_pa->vcalb_desc.vcalk_value_factor = AW_PID_2113_VCABLK_FACTOR; + + aw_pa->spin_desc.rx_desc.reg = AW_PID_2113_I2SCTRL1_REG; + aw_pa->spin_desc.rx_desc.mask = AW_PID_2113_CHSEL_MASK; + aw_pa->spin_desc.rx_desc.left_val = AW_PID_2113_CHSEL_LEFT_VALUE; + aw_pa->spin_desc.rx_desc.right_val = AW_PID_2113_CHSEL_RIGHT_VALUE; + + aw_pa->sysst_desc.reg = AW_PID_2113_SYSST_REG; + aw_pa->sysst_desc.mask = AW_PID_2113_SYSST_CHECK_MASK; + aw_pa->sysst_desc.st_check = AW_PID_2113_SYSST_CHECK; + aw_pa->sysst_desc.pll_check = AW_PID_2113_IIS_CHECK; + + aw_pa->cco_mux_desc.reg = AW_PID_2113_PLLCTRL1_REG; + aw_pa->cco_mux_desc.mask = AW_PID_2113_CCO_MUX_MASK; + aw_pa->cco_mux_desc.divided_val = AW_PID_2113_CCO_MUX_DIVIDED_VALUE; + aw_pa->cco_mux_desc.bypass_val = AW_PID_2113_CCO_MUX_BYPASS_VALUE; + + aw_pa->voltage_desc.reg = AW_PID_2113_VBAT_REG; + aw_pa->voltage_desc.int_bit = AW_PID_2113_MONITOR_INT_10BIT; + aw_pa->voltage_desc.vbat_range = AW_PID_2113_MONITOR_VBAT_RANGE; + + aw_pa->temp_desc.reg = AW_PID_2113_TEMP_REG; + aw_pa->temp_desc.neg_mask = AW_PID_2113_MONITOR_TEMP_NEG_MASK; + aw_pa->temp_desc.sign_mask = AW_PID_2113_MONITOR_TEMP_SIGN_MASK; + + aw_pa->ipeak_desc.reg = AW_PID_2113_BSTCTRL2_REG; + aw_pa->ipeak_desc.mask = AW_PID_2113_BST_IPEAK_MASK; + + aw_pa->volume_desc.reg = AW_PID_2113_SYSCTRL2_REG; + aw_pa->volume_desc.mask = AW_PID_2113_VOL_MASK; + aw_pa->volume_desc.shift = AW_PID_2113_VOL_START_BIT; + aw_pa->volume_desc.mute_volume = AW_PID_2113_MUTE_VOL; + aw_pa->volume_desc.ctl_volume = AW_PID_2113_VOL_DEFAULT_VALUE; + + aw_pa->bop_desc.reg = AW_PID_2113_SADCCTRL3_REG; + aw_pa->bop_desc.mask = AW_PID_2113_BOP_EN_MASK; + aw_pa->bop_desc.enable = AW_PID_2113_BOP_EN_ENABLE_VALUE; + aw_pa->bop_desc.disbale = AW_PID_2113_BOP_EN_DISABLE_VALUE; + + aw_pa->soft_rst.reg = AW882XX_SOFT_RESET_REG; + aw_pa->soft_rst.reg_value = AW882XX_SOFT_RESET_VALUE; + + usleep_range(AW_2000_US, AW_2000_US + 10); + aw_pa->ops.aw_i2c_write(aw_pa, AW_PID_2113_INIT_CHECK_REG, + AW_PID_2113_INIT_CHECK_VALUE); + usleep_range(AW_3000_US, AW_3000_US + 10); + + aw_pa->efcheck_desc.reg = AW_PID_2113_DBGCTRL_REG; + aw_pa->efcheck_desc.mask = AW_PID_2113_EF_DBMD_MASK; + aw_pa->efcheck_desc.and_val = AW_PID_2113_AND_VALUE; + aw_pa->efcheck_desc.or_val = AW_PID_2113_OR_VALUE; + + aw_pa->dither_desc.reg = AW_PID_2113_DBGCTRL_REG; + aw_pa->dither_desc.mask = AW_PID_2113_DITHER_MASK; + aw_pa->dither_desc.enable = AW_PID_2113_DITHER_ENABLE_VALUE; + aw_pa->dither_desc.disable = AW_PID_2113_DITHER_DISABLE_VALUE; + + aw_pa->noise_gate_desc.reg = AW_REG_NONE; + + aw_pa->auth_desc.reg_in = AW_PID_2113_TESTIN_REG; + aw_pa->auth_desc.reg_out = AW_PID_2113_TESTOUT_REG; + + aw_pa->psm_desc.reg = AW_REG_NONE; + aw_pa->mpd_desc.reg = AW_REG_NONE; + aw_pa->dsmzth_desc.reg = AW_REG_NONE; + + ret = aw882xx_device_probe(aw_pa); + + aw882xx->aw_pa = aw_pa; + return ret; +} + +/* [9 : 0]: -0.0940625DB*/ +static unsigned int aw_pid_2308_reg_val_to_db(unsigned int value) +{ + return value; +} + +/* [9 : 0]: -0.0940625DB*/ +static unsigned int aw_pid_2308_db_val_to_reg(unsigned int value) +{ + return value; +} + +static int aw_pid_2308_set_volume(struct aw_device *aw_dev, unsigned int value) +{ + unsigned int reg_value = 0; + unsigned int real_value = 0; + struct aw882xx *aw882xx = (struct aw882xx *)aw_dev->private_data; + struct aw_volume_desc *vol_desc = &aw882xx->aw_pa->volume_desc; + + real_value = aw_pid_2308_db_val_to_reg(AW_GET_MIN_VALUE(value, vol_desc->mute_volume)); + + aw_dev_dbg(aw882xx->dev, "value:%d, min_val: %d, real_value: 0x%x", + value, AW_GET_MIN_VALUE(value, vol_desc->mute_volume), real_value); + + /* cal real value */ + aw882xx_i2c_read(aw882xx, AW_PID_2308_SYSCTRL2_REG, ®_value); + + /*[9 : 0] volume*/ + real_value = (real_value | (reg_value & 0xfc00)); + + /* write value */ + aw882xx_i2c_write(aw882xx, AW_PID_2308_SYSCTRL2_REG, real_value); + + return 0; +} + +static int aw_pid_2308_get_volume(struct aw_device *aw_dev, unsigned int *value) +{ + unsigned int reg_value = 0; + unsigned int real_value = 0; + struct aw882xx *aw882xx = (struct aw882xx *)aw_dev->private_data; + + /* read value */ + aw882xx_i2c_read(aw882xx, AW_PID_2308_SYSCTRL2_REG, ®_value); + + /* [9 : 0] volume */ + real_value = (reg_value & 0x03ff); + + real_value = aw_pid_2308_reg_val_to_db(real_value); + *value = real_value; + + return 0; +} + +static bool aw_pid_2308_check_rd_access(int reg) +{ + if (reg >= AW_PID_2308_REG_MAX) + return false; + + if (aw_pid_2308_reg_access[reg] & REG_RD_ACCESS) + return true; + else + return false; +} + +static bool aw_pid_2308_check_wr_access(int reg) +{ + if (reg >= AW_PID_2308_REG_MAX) + return false; + + if (aw_pid_2113_reg_access[reg] & REG_WR_ACCESS) + return true; + else + return false; +} + +static int aw_pid_2308_get_reg_num(void) +{ + return AW_PID_2308_REG_MAX; +} + +static unsigned int aw_pid_2308_get_irq_type(struct aw_device *aw_dev, + unsigned int value) +{ + unsigned int ret = INT_TYPE_NONE; + + /* UVL0 */ + if (value & (~AW_PID_2308_UVLI_MASK)) { + aw_dev_info(aw_dev->dev, "UVLO: occur"); + ret |= INT_TYPE_UVLO; + } + + /* BSTOCM */ + if (value & (~AW_PID_2308_BSTOCI_MASK)) { + aw_dev_info(aw_dev->dev, "BSTOCI: occur"); + ret |= INT_TYPE_BSTOC; + } + + /* OCDI */ + if (value & (~AW_PID_2308_OCDI_MASK)) { + aw_dev_info(aw_dev->dev, "OCDI: occur"); + ret |= INT_TYPE_OCDI; + } + + /* OTHI */ + if (value & (~AW_PID_2308_OTHI_MASK)) { + aw_dev_info(aw_dev->dev, "OTHI: occur"); + ret |= INT_TYPE_OTHI; + } + + return ret; + +} + +static int aw_pid_2308_dev_init(struct aw882xx *aw882xx) +{ + int ret = 0; + struct aw_device *aw_pa = aw882xx->aw_pa; + + /*call aw device init func*/ + memset(aw_pa->monitor_name, 0, AW_NAME_MAX); + memcpy(aw_pa->monitor_name, AW_PID_2308_MONITOR_FILE, strlen(AW_PID_2308_MONITOR_FILE)); + + aw_pa->prof_info.prof_desc = NULL; + aw_pa->prof_info.count = 0; + aw_pa->channel = 0; + aw_pa->bstcfg_enable = AW_BSTCFG_DISABLE; + aw_pa->bop_en = AW_BOP_DISABLE; + aw_pa->vol_step = AW_PID_2308_VOL_STEP; + + aw_pa->private_data = (void *)aw882xx; + aw_pa->dev = aw882xx->dev; + aw_pa->i2c = aw882xx->i2c; + + aw_pa->ops.aw_get_version = aw882xx_get_version; + aw_pa->ops.aw_get_dev_num = aw882xx_get_dev_num; + aw_pa->ops.aw_set_algo = aw882xx_dev_set_algo_en; + aw_pa->ops.aw_i2c_read = aw882xx_dev_i2c_read; + aw_pa->ops.aw_i2c_write = aw882xx_dev_i2c_write; + aw_pa->ops.aw_i2c_write_bits = aw882xx_dev_i2c_write_bits; + aw_pa->ops.aw_get_hw_volume = aw_pid_2308_get_volume; + aw_pa->ops.aw_set_hw_volume = aw_pid_2308_set_volume; + aw_pa->ops.aw_reg_val_to_db = aw_pid_2308_reg_val_to_db; + aw_pa->ops.aw_check_rd_access = aw_pid_2308_check_rd_access; + aw_pa->ops.aw_check_wr_access = aw_pid_2308_check_wr_access; + aw_pa->ops.aw_get_reg_num = aw_pid_2308_get_reg_num; + aw_pa->ops.aw_get_irq_type = aw_pid_2308_get_irq_type; + + aw_pa->int_desc.mask_reg = AW_PID_2308_SYSINTM_REG; + aw_pa->int_desc.mask_default = AW_PID_2308_SYSINTM_DEFAULT; + aw_pa->int_desc.int_mask = AW_PID_2308_SYSINTM_DEFAULT; + aw_pa->int_desc.st_reg = AW_PID_2308_SYSINT_REG; + + aw_pa->work_mode.reg = AW_PID_2308_SYSCTRL_REG; + aw_pa->work_mode.mask = AW_PID_2308_RCV_MODE_MASK; + aw_pa->work_mode.spk_val = AW_PID_2308_RCV_MODE_SPEAKER_VALUE; + aw_pa->work_mode.rcv_val = AW_PID_2308_RCV_MODE_RECEIVER_VALUE; + + aw_pa->pwd_desc.reg = AW_PID_2308_SYSCTRL_REG; + aw_pa->pwd_desc.mask = AW_PID_2308_PWDN_MASK; + aw_pa->pwd_desc.enable = AW_PID_2308_PWDN_POWER_DOWN_VALUE; + aw_pa->pwd_desc.disable = AW_PID_2308_PWDN_WORKING_VALUE; + + aw_pa->amppd_desc.reg = AW_PID_2308_SYSCTRL_REG; + aw_pa->amppd_desc.mask = AW_PID_2308_AMPPD_MASK; + aw_pa->amppd_desc.enable = AW_PID_2308_AMPPD_POWER_DOWN_VALUE; + aw_pa->amppd_desc.disable = AW_PID_2308_AMPPD_WORKING_VALUE; + + aw_pa->mute_desc.reg = AW_PID_2308_SYSCTRL_REG; + aw_pa->mute_desc.mask = AW_PID_2308_HMUTE_MASK; + aw_pa->mute_desc.enable = AW_PID_2308_HMUTE_ENABLE_VALUE; + aw_pa->mute_desc.disable = AW_PID_2308_HMUTE_DISABLE_VALUE; + + aw_pa->uls_hmute_desc.reg = AW_PID_2308_SYSCTRL_REG; + aw_pa->uls_hmute_desc.mask = AW_PID_2308_ULS_HMUTE_MASK; + aw_pa->uls_hmute_desc.enable = AW_PID_2308_ULS_HMUTE_MUTE_VALUE; + aw_pa->uls_hmute_desc.disable = AW_PID_2308_ULS_HMUTE_NORMAL_VALUE; + + aw_pa->txen_desc.reg = AW_PID_2308_SYSCTRL_REG; + aw_pa->txen_desc.mask = AW_PID_2308_I2STXEN_MASK; + aw_pa->txen_desc.enable = AW_PID_2308_I2STXEN_ENABLE_VALUE; + aw_pa->txen_desc.disable = AW_PID_2308_I2STXEN_DISABLE_VALUE; + + aw_pa->vcalb_desc.vcalb_reg = AW_REG_NONE; + aw_pa->vcalb_desc.icalk_reg = AW_REG_NONE; + aw_pa->vcalb_desc.vcalk_reg = AW_REG_NONE; + + aw_pa->spin_desc.rx_desc.reg = AW_PID_2308_I2SCTRL1_REG; + aw_pa->spin_desc.rx_desc.mask = AW_PID_2308_CHSEL_MASK; + aw_pa->spin_desc.rx_desc.left_val = AW_PID_2308_CHSEL_LEFT_VALUE; + aw_pa->spin_desc.rx_desc.right_val = AW_PID_2308_CHSEL_RIGHT_VALUE; + + aw_pa->sysst_desc.reg = AW_PID_2308_SYSST_REG; + aw_pa->sysst_desc.mask = AW_PID_2308_SYSST_CHECK_MASK; + aw_pa->sysst_desc.st_check = AW_PID_2308_NO_SWS_SYSST_CHECK; + aw_pa->sysst_desc.st_sws_check = AW_PID_2308_SWS_SYSST_CHECK; + aw_pa->sysst_desc.pll_check = AW_PID_2308_IIS_CHECK; + + aw_pa->cco_mux_desc.reg = AW_PID_2308_DBGCTRL_REG; + aw_pa->cco_mux_desc.mask = AW_PID_2308_CCO_MUX_MASK; + aw_pa->cco_mux_desc.divided_val = AW_PID_2308_CCO_MUX_DIVIDED_VALUE; + aw_pa->cco_mux_desc.bypass_val = AW_PID_2308_CCO_MUX_BYPASS_VALUE; + + aw_pa->voltage_desc.reg = AW_PID_2308_VBAT_REG; + aw_pa->voltage_desc.int_bit = AW_PID_2308_MONITOR_INT_10BIT; + aw_pa->voltage_desc.vbat_range = AW_PID_2308_MONITOR_VBAT_RANGE; + + aw_pa->temp_desc.reg = AW_PID_2308_TEMP_REG; + aw_pa->temp_desc.neg_mask = AW_PID_2308_MONITOR_TEMP_NEG_MASK; + aw_pa->temp_desc.sign_mask = AW_PID_2308_MONITOR_TEMP_SIGN_MASK; + + aw_pa->ipeak_desc.reg = AW_PID_2308_BSTCTRL2_REG; + aw_pa->ipeak_desc.mask = AW_PID_2308_BST_IPEAK_MASK; + + aw_pa->volume_desc.reg = AW_PID_2308_SYSCTRL2_REG; + aw_pa->volume_desc.mask = AW_PID_2308_VOL_MASK; + aw_pa->volume_desc.shift = AW_PID_2308_VOL_START_BIT; + aw_pa->volume_desc.mute_volume = AW_PID_2308_MUTE_VOL; + aw_pa->volume_desc.ctl_volume = AW_PID_2308_VOL_DEFAULT_VALUE; + + aw_pa->bop_desc.reg = AW_PID_2308_SYSCTRL_REG; + aw_pa->bop_desc.mask = AW_PID_2308_BOP_EN_MASK; + aw_pa->bop_desc.enable = AW_PID_2308_BOP_EN_ENABLE_VALUE; + aw_pa->bop_desc.disbale = AW_PID_2308_BOP_EN_DISABLE_VALUE; + + aw_pa->soft_rst.reg = AW882XX_SOFT_RESET_REG; + aw_pa->soft_rst.reg_value = AW882XX_SOFT_RESET_VALUE; + + aw_pa->efcheck_desc.reg = AW_REG_NONE; + + aw_pa->dither_desc.reg = AW_REG_NONE; + + aw_pa->auth_desc.reg_in = AW_PID_2308_TESTIN_REG; + aw_pa->auth_desc.reg_out = AW_PID_2308_TESTOUT_REG; + + aw_pa->noise_gate_desc.reg = AW_PID_2308_NGCTRL3_REG; + aw_pa->noise_gate_desc.mask = AW_PID_2308_NOISE_GATE_EN_MASK; + + aw_pa->psm_desc.reg = AW_PID_2308_SYSCTRL2_REG; + aw_pa->psm_desc.mask = AW_PID_2308_PSM_EN_MASK; + aw_pa->psm_desc.enable = AW_PID_2308_PSM_EN_ENABLE_VALUE; + aw_pa->psm_desc.disable = AW_PID_2308_PSM_EN_DISABLE_VALUE; + + aw_pa->mpd_desc.reg = AW_PID_2308_SYSCTRL2_REG; + aw_pa->mpd_desc.mask = AW_PID_2308_EN_MPD_MASK; + aw_pa->mpd_desc.enable = AW_PID_2308_EN_MPD_ENABLE_VALUE; + aw_pa->mpd_desc.disable = AW_PID_2308_EN_MPD_DISABLE_VALUE; + + aw_pa->dsmzth_desc.reg = AW_PID_2308_NGCTRL3_REG; + aw_pa->dsmzth_desc.mask = AW_PID_2308_DSMZTH_MASK; + aw_pa->dsmzth_desc.enable = AW_PID_2308_DSMZTH_21P33MS_VALUE; + aw_pa->dsmzth_desc.disable = AW_PID_2308_DSMZTH_NO_RESET_VALUE; + + ret = aw882xx_device_probe(aw_pa); + + aw882xx->aw_pa = aw_pa; + return ret; +} + +int aw882xx_init(struct aw882xx *aw882xx) +{ + switch (aw882xx->aw_pa->chip_id) { + case PID_1852_ID: + return aw_pid_1852_dev_init(aw882xx); + case PID_2013_ID: + return aw_pid_2013_dev_init(aw882xx); + case PID_2032_ID: + return aw_pid_2032_dev_init(aw882xx); + case PID_2055_ID: + return aw_pid_2055_dev_check(aw882xx); + case PID_2071_ID: + return aw_pid_2071_dev_init(aw882xx); + case PID_2113_ID: + return aw_pid_2113_dev_init(aw882xx); + case PID_2308_ID: + return aw_pid_2308_dev_init(aw882xx); + default: + aw_dev_err(aw882xx->dev, "unsupported chip id 0x%04x", aw882xx->aw_pa->chip_id); + break; + } + + return -EINVAL; +} + diff --git a/sound/soc/codecs/aw882xx/aw882xx_log.h b/sound/soc/codecs/aw882xx/aw882xx_log.h new file mode 100644 index 000000000000..cae62bf01683 --- /dev/null +++ b/sound/soc/codecs/aw882xx/aw882xx_log.h @@ -0,0 +1,35 @@ +/* SPDX-License-Identifier: GPL-2.0 + * aw882xx_log.h + * + * Copyright (c) 2020 AWINIC Technology CO., LTD + * + * Author: Nick Li + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#ifndef __AW882XX_LOG_H__ +#define __AW882XX_LOG_H__ + +/******************************************** + * print information control + *******************************************/ +#define aw_dev_err(dev, format, ...) \ + pr_err("[Awinic][%s]%s: " format "\n", dev_name(dev), __func__, ##__VA_ARGS__) +#define aw_dev_info(dev, format, ...) \ + pr_info("[Awinic][%s]%s: " format "\n", dev_name(dev), __func__, ##__VA_ARGS__) +#define aw_dev_dbg(dev, format, ...) \ + pr_debug("[Awinic][%s]%s: " format "\n", dev_name(dev), __func__, ##__VA_ARGS__) + +#define aw_pr_err(format, ...) \ + pr_err("[Awinic]%s: " format "\n", __func__, ##__VA_ARGS__) +#define aw_pr_info(format, ...) \ + pr_info("[Awinic]%s: " format "\n", __func__, ##__VA_ARGS__) +#define aw_pr_dbg(format, ...) \ + pr_debug("[Awinic]%s: " format "\n", __func__, ##__VA_ARGS__) + +#endif + diff --git a/sound/soc/codecs/aw882xx/aw882xx_monitor.c b/sound/soc/codecs/aw882xx/aw882xx_monitor.c new file mode 100644 index 000000000000..486c87214870 --- /dev/null +++ b/sound/soc/codecs/aw882xx/aw882xx_monitor.c @@ -0,0 +1,1431 @@ +// SPDX-License-Identifier: GPL-2.0 +/* aw882xx_monitor.c monitor_module + * + * Copyright (c) 2019 AWINIC Technology CO., LTD + * + * Author: Nick Li + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "aw882xx.h" +#include "aw882xx_dsp.h" +#include "aw882xx_monitor.h" +#include "aw882xx_log.h" + + +/***************************************************** + * device monitor + *****************************************************/ +static int aw_get_hmute(struct aw_device *aw_dev) +{ + int ret; + unsigned int reg_val = 0; + struct aw_mute_desc *desc = &aw_dev->mute_desc; + + aw_dev_dbg(aw_dev->dev, "enter"); + + ret = aw_dev->ops.aw_i2c_read(aw_dev, desc->reg, ®_val); + if (ret < 0) + return ret; + + if (reg_val & (~desc->mask)) + ret = 1; + else + ret = 0; + + return ret; +} + +static int aw_monitor_get_data_form_system(struct aw_device *aw_dev, + int *data, int data_type) +{ + int ret; + char name[] = "battery"; + union power_supply_propval prop = { 0 }; + struct power_supply *psy = NULL; + + psy = power_supply_get_by_name(name); + if (psy) { + ret = power_supply_get_property(psy, data_type, &prop); + if (ret < 0) { + aw_dev_err(aw_dev->dev, "get data failed"); + return -EINVAL; + } + *data = prop.intval; + aw_dev_dbg(aw_dev->dev, "data: %d", *data); + } else { + aw_dev_err(aw_dev->dev, "no struct power supply name : %s", name); + return -EINVAL; + } + return 0; + +} + +static int aw_monitor_get_voltage(struct aw_device *aw_dev, unsigned int *vol) +{ + int ret = -1; + uint16_t local_vol = 0; + struct aw_voltage_desc *desc = &aw_dev->voltage_desc; + + if (desc->reg == AW_REG_NONE) { + ret = aw_monitor_get_data_form_system(aw_dev, (int *)vol, POWER_SUPPLY_PROP_VOLTAGE_NOW); + if (ret) { + aw_dev_err(aw_dev->dev, "get voltage from system failed!"); + return ret; + } + *vol = (*vol) / 1000; + } else { + ret = aw_dev->ops.aw_i2c_read(aw_dev, desc->reg, vol); + if (ret < 0) { + aw_dev_err(aw_dev->dev, "read voltage failed!"); + return ret; + } + local_vol = ((*vol) * desc->vbat_range) / desc->int_bit; + *vol = local_vol; + } + + aw_dev_info(aw_dev->dev, "chip voltage is %d", *vol); + + return 0; +} + +static int aw_monitor_get_temperature(struct aw_device *aw_dev, int *temp) +{ + int ret = -1; + unsigned int reg_val = 0; + uint16_t local_temp; + struct aw_temperature_desc *desc = &aw_dev->temp_desc; + + if (desc->reg == AW_REG_NONE) { + ret = aw_monitor_get_data_form_system(aw_dev, temp, POWER_SUPPLY_PROP_TEMP); + if (ret) { + aw_dev_err(aw_dev->dev, "get temperature from system failed!"); + return ret; + } + *temp = (*temp) / 10; + } else { + ret = aw_dev->ops.aw_i2c_read(aw_dev, desc->reg, ®_val); + if (ret < 0) { + aw_dev_err(aw_dev->dev, "get temperature failed!"); + return ret; + } + aw_dev_info(aw_dev->dev, "reg val is 0x%04x", reg_val); + local_temp = reg_val; + if (local_temp & (~desc->sign_mask)) + local_temp = local_temp | desc->neg_mask; + + *temp = (int16_t)local_temp; + } + + aw_dev_info(aw_dev->dev, "chip temperature = %d", *temp); + return 0; +} + +static int aw_monitor_get_temp_and_vol(struct aw_device *aw_dev) +{ + int ret = -1; + struct aw_monitor_desc *monitor = &aw_dev->monitor_desc; + unsigned int voltage = 0; + int current_temp = 0; + +#ifdef AW_DEBUG + if (monitor->test_vol == 0) { + ret = aw_monitor_get_voltage(aw_dev, &voltage); + if (ret < 0) + return ret; + } else { + voltage = monitor->test_vol; + } + + if (monitor->test_temp == 0) { + ret = aw_monitor_get_temperature(aw_dev, ¤t_temp); + if (ret) + return ret; + } else { + current_temp = monitor->test_temp; + } +#else + ret = aw_monitor_get_voltage(aw_dev, &voltage); + if (ret < 0) + return ret; + + ret = aw_monitor_get_temperature(aw_dev, ¤t_temp); + if (ret < 0) + return ret; +#endif + + monitor->vol_trace.sum_val += voltage; + monitor->temp_trace.sum_val += current_temp; + monitor->samp_count++; + + return 0; +} + +static int aw_monitor_first_get_data_form_table(struct aw_device *aw_dev, + struct aw_table_info table_info, + struct aw_monitor_trace *data_trace) +{ + int i; + + if (table_info.aw_table == NULL) { + aw_dev_err(aw_dev->dev, "table_info.aw_table is null"); + return -EINVAL; + } + + for (i = 0; i < table_info.table_num; i++) { + if (data_trace->sum_val >= table_info.aw_table[i].min_val) { + memcpy(&data_trace->aw_table, &table_info.aw_table[i], + sizeof(struct aw_table)); + break; + } + } + return 0; +} + +static int aw_monitor_trace_data_from_table(struct aw_device *aw_dev, + struct aw_table_info table_info, + struct aw_monitor_trace *data_trace) +{ + int i; + + if (table_info.aw_table == NULL) { + aw_dev_err(aw_dev->dev, "table_info.aw_table is null"); + return -EINVAL; + } + + for (i = 0; i < table_info.table_num; i++) { + if (data_trace->sum_val >= table_info.aw_table[i].min_val && + data_trace->sum_val <= table_info.aw_table[i].max_val) { + memcpy(&data_trace->aw_table, &table_info.aw_table[i], + sizeof(struct aw_table)); + break; + } + } + + return 0; +} + +static int aw_monitor_get_data_from_table(struct aw_device *aw_dev, + struct aw_table_info table_info, + struct aw_monitor_trace *data_trace, + uint32_t aplha) +{ + struct aw_monitor_desc *monitor = &aw_dev->monitor_desc; + + if (monitor->first_entry == AW_FIRST_ENTRY) { + return aw_monitor_first_get_data_form_table(aw_dev, + table_info, data_trace); + } else { + data_trace->sum_val = data_trace->sum_val / monitor->samp_count; + data_trace->sum_val = ((int32_t)aplha * data_trace->sum_val + + (1000 - (int32_t)aplha) * data_trace->pre_val) / 1000; + return aw_monitor_trace_data_from_table(aw_dev, + table_info, data_trace); + } + + return 0; +} + +static int aw_monitor_get_data(struct aw_device *aw_dev) +{ + int ret; + struct aw_monitor_desc *monitor = &aw_dev->monitor_desc; + struct aw_monitor_cfg *monitor_cfg = &monitor->monitor_cfg; + struct aw_monitor_trace *vol_trace = &monitor->vol_trace; + struct aw_monitor_trace *temp_trace = &monitor->temp_trace; + + if (monitor_cfg->vol_switch) { + ret = aw_monitor_get_data_from_table(aw_dev, + monitor_cfg->vol_info, vol_trace, + monitor_cfg->vol_aplha); + if (ret < 0) + return ret; + } else { + vol_trace->aw_table.ipeak = IPEAK_NONE; + vol_trace->aw_table.gain = GAIN_NONE; + vol_trace->aw_table.vmax = VMAX_NONE; + } + + if (monitor_cfg->temp_switch) { + ret = aw_monitor_get_data_from_table(aw_dev, + monitor_cfg->temp_info, temp_trace, + monitor_cfg->temp_aplha); + if (ret < 0) + return ret; + } else { + temp_trace->aw_table.ipeak = IPEAK_NONE; + temp_trace->aw_table.gain = GAIN_NONE; + temp_trace->aw_table.vmax = VMAX_NONE; + } + + aw_dev_dbg(aw_dev->dev, "filter_vol:%d, vol: ipeak = 0x%x, gain = 0x%x, vmax = 0x%x", + monitor->vol_trace.sum_val, vol_trace->aw_table.ipeak, + vol_trace->aw_table.gain, vol_trace->aw_table.vmax); + + aw_dev_dbg(aw_dev->dev, "filter_temp:%d, temp: ipeak = 0x%x, gain = 0x%x, vmax = 0x%x", + monitor->temp_trace.sum_val, temp_trace->aw_table.ipeak, + temp_trace->aw_table.gain, temp_trace->aw_table.vmax); + return 0; +} + +static void aw_monitor_get_cfg(struct aw_device *aw_dev, + struct aw_table *set_table) +{ + struct aw_monitor_desc *monitor = &aw_dev->monitor_desc; + struct aw_table *temp_data = &monitor->temp_trace.aw_table; + struct aw_table *vol_data = &monitor->vol_trace.aw_table; + + if (temp_data->ipeak == IPEAK_NONE && vol_data->ipeak == IPEAK_NONE) { + memcpy(set_table, temp_data, sizeof(struct aw_table)); + } else if (temp_data->ipeak == IPEAK_NONE) { + memcpy(set_table, vol_data, sizeof(struct aw_table)); + } else if (vol_data->ipeak == IPEAK_NONE) { + memcpy(set_table, temp_data, sizeof(struct aw_table)); + } else { + if (monitor->monitor_cfg.logic_switch == AW_MON_LOGIC_OR) { + set_table->ipeak = (temp_data->ipeak < vol_data->ipeak ? + temp_data->ipeak : vol_data->ipeak); + set_table->gain = (temp_data->gain < vol_data->gain ? + vol_data->gain : temp_data->gain); + set_table->vmax = (temp_data->vmax < vol_data->vmax ? + vol_data->vmax : temp_data->vmax); + } else { + set_table->ipeak = (temp_data->ipeak < vol_data->ipeak ? + vol_data->ipeak : temp_data->ipeak); + set_table->gain = (temp_data->gain < vol_data->gain ? + temp_data->gain : vol_data->gain); + set_table->vmax = (temp_data->vmax < vol_data->vmax ? + temp_data->vmax : vol_data->vmax); + } + } +} + +static void aw_monitor_set_ipeak(struct aw_device *aw_dev, + uint16_t ipeak) +{ + int ret; + struct aw_monitor_cfg *monitor_cfg = &aw_dev->monitor_desc.monitor_cfg; + unsigned int reg_val = 0; + unsigned int read_reg_val; + struct aw_ipeak_desc *desc = &aw_dev->ipeak_desc; + + if (ipeak == IPEAK_NONE || (!monitor_cfg->ipeak_switch)) + return; + + ret = aw_dev->ops.aw_i2c_read(aw_dev, desc->reg, ®_val); + if (ret < 0) { + aw_dev_err(aw_dev->dev, "read ipeak failed"); + return; + } + + read_reg_val = reg_val; + + read_reg_val &= (~desc->mask); + + if (read_reg_val == ipeak) { + aw_dev_dbg(aw_dev->dev, "ipeak = 0x%x, no change", + read_reg_val); + return; + } + + reg_val &= desc->mask; + read_reg_val = ipeak; + reg_val |= read_reg_val; + + ret = aw_dev->ops.aw_i2c_write(aw_dev, desc->reg, reg_val); + if (ret < 0) { + aw_dev_err(aw_dev->dev, "write ipeak failed"); + return; + } + aw_dev_info(aw_dev->dev, "set reg val = 0x%x, ipeak = 0x%x", + reg_val, ipeak); + +} + +static void aw_monitor_set_gain(struct aw_device *aw_dev, uint16_t gain) +{ + int compared_vol = 0; + struct aw_monitor_cfg *monitor_cfg = &aw_dev->monitor_desc.monitor_cfg; + struct aw_volume_desc *vol_desc = &aw_dev->volume_desc; + + if (gain == GAIN_NONE || (!monitor_cfg->gain_switch)) + return; + + vol_desc->monitor_volume = aw_dev->ops.aw_reg_val_to_db(gain); + + compared_vol = AW_GET_MAX_VALUE(vol_desc->ctl_volume, + vol_desc->monitor_volume); + + aw882xx_dev_set_volume(aw_dev, compared_vol); +} + +static void aw_monitor_set_vmax(struct aw_device *aw_dev, + uint32_t vmax) +{ + int ret; + struct aw_monitor_cfg *monitor_cfg = &aw_dev->monitor_desc.monitor_cfg; + + if (vmax == VMAX_NONE || (!monitor_cfg->vmax_switch)) + return; + + if ((vmax == aw_dev->monitor_desc.pre_vmax) && + (aw_dev->monitor_desc.first_entry != AW_FIRST_ENTRY)) { + aw_dev_dbg(aw_dev->dev, "vmax = 0x%x, no change", vmax); + return; + } + + aw_dev->monitor_desc.pre_vmax = vmax; + + if (aw_dev->monitor_desc.monitor_mode == AW_MON_KERNEL_MODE) { + ret = aw882xx_dsp_write_vmax(aw_dev, (char *)&vmax, sizeof(uint32_t)); + if (ret) + return; + + aw_dev_dbg(aw_dev->dev, "set vmax = 0x%x", vmax); + } +} + +static int aw_monitor_work(struct aw_device *aw_dev) +{ + int ret = -1; + struct aw_monitor_desc *monitor = &aw_dev->monitor_desc; + struct aw_monitor_cfg *monitor_cfg = &monitor->monitor_cfg; + struct aw_table set_table; + + if (aw882xx_cali_svc_get_cali_status()) { + aw_dev_info(aw_dev->dev, "done nothing during calibration"); + return 0; + } + + ret = aw_monitor_get_temp_and_vol(aw_dev); + if (ret < 0) + return ret; + + if (monitor->samp_count < monitor_cfg->monitor_count && + (monitor->first_entry == AW_NOT_FIRST_ENTRY)) + return 0; + + ret = aw_monitor_get_data(aw_dev); + if (ret < 0) + return ret; + + aw_monitor_get_cfg(aw_dev, &set_table); + + aw_dev_dbg(aw_dev->dev, "set_ipeak = 0x%x, set_gain = 0x%x, set_vmax = 0x%x", + set_table.ipeak, set_table.gain, set_table.vmax); + + aw_monitor_set_ipeak(aw_dev, set_table.ipeak); + + aw_monitor_set_gain(aw_dev, set_table.gain); + + aw_monitor_set_vmax(aw_dev, set_table.vmax); + + monitor->samp_count = 0; + monitor->temp_trace.pre_val = monitor->temp_trace.sum_val; + monitor->temp_trace.sum_val = 0; + + monitor->vol_trace.pre_val = monitor->vol_trace.sum_val; + monitor->vol_trace.sum_val = 0; + + if (monitor->first_entry == AW_FIRST_ENTRY) + monitor->first_entry = AW_NOT_FIRST_ENTRY; + + return 0; +} + +static void aw_monitor_work_func(struct work_struct *work) +{ + struct aw_device *aw_dev = container_of(work, + struct aw_device, monitor_desc.delay_work.work); + struct aw882xx *aw882xx = (struct aw882xx *)aw_dev->private_data; + struct aw_monitor_cfg *monitor_cfg = &aw_dev->monitor_desc.monitor_cfg; + struct aw_monitor_desc *monitor = &aw_dev->monitor_desc; + + aw_dev_dbg(aw_dev->dev, "monitor_start:%d, monitor_status:%d, monitor_switch:%d", + aw_dev->monitor_start, monitor_cfg->monitor_status, + monitor_cfg->monitor_switch); + + if ((monitor_cfg->monitor_status == AW_MON_CFG_OK) && (aw_dev->monitor_start) && + monitor_cfg->monitor_switch) { + if (!aw_get_hmute(aw_dev)) { + aw_monitor_work(aw_dev); + if (monitor->monitor_mode == AW_MON_KERNEL_MODE) { + queue_delayed_work(aw882xx->work_queue, + &monitor->delay_work, + msecs_to_jiffies(monitor_cfg->monitor_time)); + } + } + } +} + +static void aw_monitor_check_bop_status(struct aw_device *aw_dev) +{ + struct aw_bop_desc *bop_desc = &aw_dev->bop_desc; + unsigned int reg_val = 0; + + aw_dev_dbg(aw_dev->dev, "enter"); + + if (aw_dev->bop_desc.reg == AW_REG_NONE) + return; + + aw_dev->ops.aw_i2c_read(aw_dev, bop_desc->reg, ®_val); + reg_val = (uint16_t)reg_val & (~bop_desc->mask); + if (reg_val == bop_desc->enable) + aw_dev->bop_en = AW_BOP_ENABLE; + else + aw_dev->bop_en = AW_BOP_DISABLE; + + aw_dev_dbg(aw_dev->dev, "check done! bop status is %d", aw_dev->bop_en); +} + +void aw882xx_monitor_start(struct aw_monitor_desc *monitor_desc) +{ + struct aw_device *aw_dev = container_of(monitor_desc, + struct aw_device, monitor_desc); + struct aw882xx *aw882xx = (struct aw882xx *)aw_dev->private_data; + + aw_dev_info(aw_dev->dev, "enter"); + + monitor_desc->first_entry = AW_FIRST_ENTRY; + monitor_desc->samp_count = 0; + monitor_desc->vol_trace.sum_val = 0; + monitor_desc->temp_trace.sum_val = 0; + + aw_monitor_check_bop_status(aw_dev); + + if (aw_dev->bop_en == AW_BOP_ENABLE) { + aw_dev_info(aw_dev->dev, "bop status is enable, monitor can't start"); + return; + } + + monitor_desc->mon_start_flag = true; + if (monitor_desc->monitor_mode == AW_MON_KERNEL_MODE) { + queue_delayed_work(aw882xx->work_queue, + &monitor_desc->delay_work, 0); + } +} + +int aw882xx_monitor_stop(struct aw_monitor_desc *monitor_desc) +{ + struct aw_device *aw_dev = container_of(monitor_desc, + struct aw_device, monitor_desc); + + aw_dev_info(aw_dev->dev, "enter"); + aw_dev->volume_desc.monitor_volume = 0; + monitor_desc->mon_start_flag = false; + + if (monitor_desc->monitor_mode == AW_MON_KERNEL_MODE) + cancel_delayed_work_sync(&monitor_desc->delay_work); + + + return 0; +} + +void aw882xx_monitor_hal_work(struct aw_monitor_desc *monitor_desc, uint32_t *vmax) +{ + struct aw_device *aw_dev = container_of(monitor_desc, + struct aw_device, monitor_desc); + + if (monitor_desc->mon_start_flag) { + aw_monitor_work_func(&monitor_desc->delay_work.work); + *vmax = aw_dev->monitor_desc.pre_vmax; + } else { + *vmax = VMAX_NONE; + } +} + +void aw882xx_monitor_hal_get_time(struct aw_monitor_desc *monitor_desc, uint32_t *time) +{ + struct aw_device *aw_dev = container_of(monitor_desc, + struct aw_device, monitor_desc); + struct aw_monitor_cfg *monitor_cfg = &aw_dev->monitor_desc.monitor_cfg; + + *time = monitor_cfg->monitor_time; +} + + +/***************************************************** + * load monitor config + *****************************************************/ +static int aw_monitor_param_check_sum(struct aw_device *aw_dev, + uint8_t *data, uint32_t data_len) +{ + int i, check_sum = 0; + struct aw_monitor_hdr *monitor_hdr = + (struct aw_monitor_hdr *)data; + + if (data_len < sizeof(struct aw_monitor_hdr)) { + aw_dev_err(aw_dev->dev, "data size smaller than hdr , please check monitor bin"); + return -ENOMEM; + } + + for (i = 4; i < data_len; i++) + check_sum += (uint8_t)data[i]; + + if (monitor_hdr->check_sum != check_sum) { + aw_dev_err(aw_dev->dev, "check_sum[%d] is not equal to actual check_sum[%d]", + monitor_hdr->check_sum, check_sum); + return -ENOMEM; + } + + return 0; +} + +static int aw_monitor_check_fw(struct aw_device *aw_dev, + uint8_t *data, uint32_t data_len) +{ + struct aw_monitor_hdr *monitor_hdr = + (struct aw_monitor_hdr *)data; + int temp_size, vol_size; + + if (data_len < sizeof(struct aw_monitor_hdr)) { + aw_dev_err(aw_dev->dev, "params size[%d] < struct aw_monitor_hdr size[%d]!", + data_len, (int)sizeof(struct aw_monitor_hdr)); + return -ENOMEM; + } + + if (monitor_hdr->temp_offset > data_len) { + aw_dev_err(aw_dev->dev, "temp_offset[%d] overflow file size[%d]!", + monitor_hdr->temp_offset, data_len); + return -ENOMEM; + } + + if (monitor_hdr->vol_offset > data_len) { + aw_dev_err(aw_dev->dev, "vol_offset[%d] overflow file size[%d]!", + monitor_hdr->vol_offset, data_len); + return -ENOMEM; + } + + temp_size = monitor_hdr->temp_num * monitor_hdr->single_temp_size; + if (temp_size > data_len) { + aw_dev_err(aw_dev->dev, "temp_size:[%d] overflow file size[%d]!", + temp_size, data_len); + return -ENOMEM; + } + + vol_size = monitor_hdr->vol_num * monitor_hdr->single_vol_size; + if (vol_size > data_len) { + aw_dev_err(aw_dev->dev, "vol_size:[%d] overflow file size[%d]!", + vol_size, data_len); + return -ENOMEM; + } + + return 0; +} + +static int aw_monitor_check_fw_v_0_1_1(struct aw_device *aw_dev, + uint8_t *data, uint32_t data_len) +{ + struct aw_monitor_hdr_v_0_1_1 *monitor_hdr = + (struct aw_monitor_hdr_v_0_1_1 *)data; + int temp_size, vol_size; + + if (data_len < sizeof(struct aw_monitor_hdr_v_0_1_1)) { + aw_dev_err(aw_dev->dev, "params size[%d] < struct aw_monitor_hdr size[%d]!", + data_len, (int)sizeof(struct aw_monitor_hdr_v_0_1_1)); + return -ENOMEM; + } + + if (monitor_hdr->temp_offset > data_len) { + aw_dev_err(aw_dev->dev, "temp_offset[%d] overflow file size[%d]!", + monitor_hdr->temp_offset, data_len); + return -ENOMEM; + } + + if (monitor_hdr->vol_offset > data_len) { + aw_dev_err(aw_dev->dev, "vol_offset[%d] overflow file size[%d]!", + monitor_hdr->vol_offset, data_len); + return -ENOMEM; + } + + temp_size = monitor_hdr->temp_num * monitor_hdr->single_temp_size; + if (temp_size > data_len) { + aw_dev_err(aw_dev->dev, "temp_size:[%d] overflow file size[%d]!", + temp_size, data_len); + return -ENOMEM; + } + + vol_size = monitor_hdr->vol_num * monitor_hdr->single_vol_size; + if (vol_size > data_len) { + aw_dev_err(aw_dev->dev, "vol_size:[%d] overflow file size[%d]!", + vol_size, data_len); + return -ENOMEM; + } + + return 0; +} + +static int aw_monitor_check_fw_v_0_1_2(struct aw_device *aw_dev, + uint8_t *data, uint32_t data_len) +{ + struct aw_monitor_hdr_v_0_1_2 *monitor_hdr = + (struct aw_monitor_hdr_v_0_1_2 *)data; + int temp_size, vol_size; + + if (data_len < sizeof(struct aw_monitor_hdr_v_0_1_2)) { + aw_dev_err(aw_dev->dev, "params size[%d] < struct aw_monitor_hdr size[%d]!", + data_len, (int)sizeof(struct aw_monitor_hdr_v_0_1_2)); + return -ENOMEM; + } + + if (monitor_hdr->temp_offset > data_len) { + aw_dev_err(aw_dev->dev, "temp_offset[%d] overflow file size[%d]!", + monitor_hdr->temp_offset, data_len); + return -ENOMEM; + } + + if (monitor_hdr->vol_offset > data_len) { + aw_dev_err(aw_dev->dev, "vol_offset[%d] overflow file size[%d]!", + monitor_hdr->vol_offset, data_len); + return -ENOMEM; + } + + temp_size = monitor_hdr->temp_num * monitor_hdr->single_temp_size; + if (temp_size > data_len) { + aw_dev_err(aw_dev->dev, "temp_size:[%d] overflow file size[%d]!", + temp_size, data_len); + return -ENOMEM; + } + + vol_size = monitor_hdr->vol_num * monitor_hdr->single_vol_size; + if (vol_size > data_len) { + aw_dev_err(aw_dev->dev, "vol_size:[%d] overflow file size[%d]!", + vol_size, data_len); + return -ENOMEM; + } + + return 0; +} + +static void aw_monitor_parse_hdr(struct aw_device *aw_dev, uint8_t *data) +{ + struct aw_monitor_hdr *monitor_hdr = + (struct aw_monitor_hdr *)data; + struct aw_monitor_cfg *monitor_cfg = &aw_dev->monitor_desc.monitor_cfg; + + monitor_cfg->monitor_switch = monitor_hdr->monitor_switch; + monitor_cfg->monitor_time = monitor_hdr->monitor_time; + monitor_cfg->monitor_count = monitor_hdr->monitor_count; + monitor_cfg->ipeak_switch = monitor_hdr->ipeak_switch; + monitor_cfg->gain_switch = monitor_hdr->gain_switch; + monitor_cfg->vmax_switch = monitor_hdr->vmax_switch; + monitor_cfg->temp_switch = monitor_hdr->temp_switch; + monitor_cfg->temp_aplha = monitor_hdr->temp_aplha; + monitor_cfg->vol_switch = monitor_hdr->vol_switch; + monitor_cfg->vol_aplha = monitor_hdr->vol_aplha; + + aw_dev_info(aw_dev->dev, "chip name:%s", + monitor_hdr->chip_type); + aw_dev_info(aw_dev->dev, "ui ver:0x%x", + monitor_hdr->ui_ver); + + aw_dev_info(aw_dev->dev, "monitor_switch:%d, monitor_time:%d (ms), monitor_count:%d", + monitor_cfg->monitor_switch, monitor_cfg->monitor_time, + monitor_cfg->monitor_count); + + aw_dev_info(aw_dev->dev, "ipeak_switch:%d, gain_switch:%d, vmax_switch:%d", + monitor_cfg->ipeak_switch, monitor_cfg->gain_switch, + monitor_cfg->vmax_switch); + + aw_dev_info(aw_dev->dev, "temp_switch:%d, temp_aplha:%d, vol_switch:%d, vol_aplha:%d", + monitor_cfg->temp_switch, monitor_cfg->temp_aplha, + monitor_cfg->vol_switch, monitor_cfg->vol_aplha); +} + +static void aw_monitor_parse_hdr_v_0_1_1(struct aw_device *aw_dev, uint8_t *data) +{ + struct aw_monitor_hdr_v_0_1_1 *monitor_hdr = + (struct aw_monitor_hdr_v_0_1_1 *)data; + struct aw_monitor_cfg *monitor_cfg = &aw_dev->monitor_desc.monitor_cfg; + + monitor_cfg->monitor_switch = (monitor_hdr->enable_flag >> MONITOR_EN_BIT) & MONITOR_EN_MASK; + monitor_cfg->monitor_time = monitor_hdr->monitor_time; + monitor_cfg->monitor_count = monitor_hdr->monitor_count; + monitor_cfg->ipeak_switch = (monitor_hdr->enable_flag >> MONITOR_IPEAK_EN_BIT) & MONITOR_EN_MASK; + monitor_cfg->logic_switch = (monitor_hdr->enable_flag >> MONITOR_LOGIC_BIT) & MONITOR_EN_MASK; + monitor_cfg->gain_switch = (monitor_hdr->enable_flag >> MONITOR_GAIN_EN_BIT) & MONITOR_EN_MASK; + monitor_cfg->vmax_switch = (monitor_hdr->enable_flag >> MONITOR_VMAX_EN_BIT) & MONITOR_EN_MASK; + monitor_cfg->temp_switch = (monitor_hdr->enable_flag >> MONITOR_TEMP_EN_BIT) & MONITOR_EN_MASK; + monitor_cfg->temp_aplha = monitor_hdr->temp_aplha; + monitor_cfg->vol_switch = (monitor_hdr->enable_flag >> MONITOR_VOL_EN_BIT) & MONITOR_EN_MASK; + monitor_cfg->vol_aplha = monitor_hdr->vol_aplha; + + aw_dev_info(aw_dev->dev, "chip name:%s", + monitor_hdr->chip_type); + aw_dev_info(aw_dev->dev, "ui ver:0x%x", + monitor_hdr->ui_ver); + + aw_dev_info(aw_dev->dev, "monitor_switch:%d, monitor_time:%d (ms), monitor_count:%d", + monitor_cfg->monitor_switch, monitor_cfg->monitor_time, + monitor_cfg->monitor_count); + + aw_dev_info(aw_dev->dev, "logic_switch:%d, ipeak_switch:%d, gain_switch:%d, vmax_switch:%d", + monitor_cfg->logic_switch, monitor_cfg->ipeak_switch, + monitor_cfg->gain_switch, monitor_cfg->vmax_switch); + + aw_dev_info(aw_dev->dev, "temp_switch:%d, temp_aplha:%d, vol_switch:%d, vol_aplha:%d", + monitor_cfg->temp_switch, monitor_cfg->temp_aplha, + monitor_cfg->vol_switch, monitor_cfg->vol_aplha); +} + +static void aw_monitor_parse_hdr_v_0_1_2(struct aw_device *aw_dev, uint8_t *data) +{ + struct aw_monitor_hdr_v_0_1_2 *monitor_hdr = + (struct aw_monitor_hdr_v_0_1_2 *)data; + struct aw_monitor_cfg *monitor_cfg = &aw_dev->monitor_desc.monitor_cfg; + + monitor_cfg->monitor_switch = (monitor_hdr->enable_flag >> MONITOR_EN_BIT) & MONITOR_EN_MASK; + monitor_cfg->monitor_time = monitor_hdr->monitor_time; + monitor_cfg->monitor_count = monitor_hdr->monitor_count; + monitor_cfg->ipeak_switch = (monitor_hdr->enable_flag >> MONITOR_IPEAK_EN_BIT) & MONITOR_EN_MASK; + monitor_cfg->logic_switch = (monitor_hdr->enable_flag >> MONITOR_LOGIC_BIT) & MONITOR_EN_MASK; + monitor_cfg->gain_switch = (monitor_hdr->enable_flag >> MONITOR_GAIN_EN_BIT) & MONITOR_EN_MASK; + monitor_cfg->vmax_switch = (monitor_hdr->enable_flag >> MONITOR_VMAX_EN_BIT) & MONITOR_EN_MASK; + monitor_cfg->temp_switch = (monitor_hdr->enable_flag >> MONITOR_TEMP_EN_BIT) & MONITOR_EN_MASK; + monitor_cfg->temp_aplha = monitor_hdr->temp_aplha; + monitor_cfg->vol_switch = (monitor_hdr->enable_flag >> MONITOR_VOL_EN_BIT) & MONITOR_EN_MASK; + monitor_cfg->vol_aplha = monitor_hdr->vol_aplha; + monitor_cfg->temp_source = + (monitor_hdr->enable_flag >> MONITOR_TEMPERATURE_SOURCE_BIT) & MONITOR_EN_MASK; + monitor_cfg->vol_source = + (monitor_hdr->enable_flag >> MONITOR_VOLTAGE_SOURCE_BIT) & MONITOR_EN_MASK; + monitor_cfg->vol_mode = + (monitor_hdr->enable_flag >> MONITOR_VOLTAGE_MODE_BIT) & MONITOR_EN_MASK; + + aw_dev_info(aw_dev->dev, "chip name:%s", + monitor_hdr->chip_type); + aw_dev_info(aw_dev->dev, "ui ver:0x%x", + monitor_hdr->ui_ver); + + aw_dev_info(aw_dev->dev, "voltage mode:%d, voltage source:%d , temperature source:%d", + monitor_cfg->vol_mode, monitor_cfg->vol_source, + monitor_cfg->temp_source); + + aw_dev_info(aw_dev->dev, "monitor_switch:%d, monitor_time:%d (ms), monitor_count:%d", + monitor_cfg->monitor_switch, monitor_cfg->monitor_time, + monitor_cfg->monitor_count); + + aw_dev_info(aw_dev->dev, "logic_switch:%d, ipeak_switch:%d, gain_switch:%d, vmax_switch:%d", + monitor_cfg->logic_switch, monitor_cfg->ipeak_switch, + monitor_cfg->gain_switch, monitor_cfg->vmax_switch); + + aw_dev_info(aw_dev->dev, "temp_switch:%d, temp_aplha:%d, vol_switch:%d, vol_aplha:%d", + monitor_cfg->temp_switch, monitor_cfg->temp_aplha, + monitor_cfg->vol_switch, monitor_cfg->vol_aplha); +} + +static void aw_monitor_write_data_to_table(struct aw_device *aw_dev, + struct aw_table_info *table_info, const char *offset_ptr) +{ + int i; + + for (i = 0; i < table_info->table_num * AW_TABLE_SIZE; i += AW_TABLE_SIZE) { + table_info->aw_table[i / AW_TABLE_SIZE].min_val = + AW_GET_16_DATA(offset_ptr[1 + i], offset_ptr[i]); + table_info->aw_table[i / AW_TABLE_SIZE].max_val = + AW_GET_16_DATA(offset_ptr[3 + i], offset_ptr[2 + i]); + table_info->aw_table[i / AW_TABLE_SIZE].ipeak = + AW_GET_16_DATA(offset_ptr[5 + i], offset_ptr[4 + i]); + table_info->aw_table[i / AW_TABLE_SIZE].gain = + AW_GET_16_DATA(offset_ptr[7 + i], offset_ptr[6 + i]); + table_info->aw_table[i / AW_TABLE_SIZE].vmax = + AW_GET_32_DATA(offset_ptr[11 + i], offset_ptr[10 + i], + offset_ptr[9 + i], offset_ptr[8 + i]); + } + + for (i = 0; i < table_info->table_num; i++) + aw_dev_info(aw_dev->dev, + "min_val:%d, max_val:%d, ipeak:0x%x, gain:0x%x, vmax:0x%x", + table_info->aw_table[i].min_val, + table_info->aw_table[i].max_val, + table_info->aw_table[i].ipeak, + table_info->aw_table[i].gain, + table_info->aw_table[i].vmax); + +} + + +static int aw_monitor_parse_temp_data(struct aw_device *aw_dev, uint8_t *data) +{ + struct aw_monitor_hdr *monitor_hdr = + (struct aw_monitor_hdr *)data; + struct aw_table_info *temp_info = + &aw_dev->monitor_desc.monitor_cfg.temp_info; + + aw_dev_info(aw_dev->dev, "===parse temp start ==="); + + if (temp_info->aw_table != NULL) { + devm_kfree(aw_dev->dev, temp_info->aw_table); + temp_info->aw_table = NULL; + } + + temp_info->aw_table = devm_kzalloc(aw_dev->dev, + (monitor_hdr->temp_num * AW_TABLE_SIZE), + GFP_KERNEL); + if (temp_info->aw_table == NULL) + return -ENOMEM; + + temp_info->table_num = monitor_hdr->temp_num; + aw_monitor_write_data_to_table(aw_dev, temp_info, + &data[monitor_hdr->temp_offset]); + aw_dev_info(aw_dev->dev, "===parse temp end ==="); + return 0; +} + +static int aw_monitor_parse_temp_data_v_0_1_1(struct aw_device *aw_dev, uint8_t *data) +{ + struct aw_monitor_hdr_v_0_1_1 *monitor_hdr = + (struct aw_monitor_hdr_v_0_1_1 *)data; + struct aw_table_info *temp_info = + &aw_dev->monitor_desc.monitor_cfg.temp_info; + + aw_dev_info(aw_dev->dev, "===parse temp start ==="); + + if (temp_info->aw_table != NULL) { + devm_kfree(aw_dev->dev, temp_info->aw_table); + temp_info->aw_table = NULL; + } + + temp_info->aw_table = devm_kzalloc(aw_dev->dev, + (monitor_hdr->temp_num * AW_TABLE_SIZE), + GFP_KERNEL); + if (temp_info->aw_table == NULL) + return -ENOMEM; + + temp_info->table_num = monitor_hdr->temp_num; + aw_monitor_write_data_to_table(aw_dev, temp_info, + &data[monitor_hdr->temp_offset]); + aw_dev_info(aw_dev->dev, "===parse temp end ==="); + return 0; +} + +static int aw_monitor_parse_temp_data_v_0_1_2(struct aw_device *aw_dev, uint8_t *data) +{ + struct aw_monitor_hdr_v_0_1_2 *monitor_hdr = + (struct aw_monitor_hdr_v_0_1_2 *)data; + struct aw_table_info *temp_info = + &aw_dev->monitor_desc.monitor_cfg.temp_info; + + aw_dev_info(aw_dev->dev, "===parse temp start ==="); + + if (temp_info->aw_table != NULL) { + devm_kfree(aw_dev->dev, temp_info->aw_table); + temp_info->aw_table = NULL; + } + + temp_info->aw_table = devm_kzalloc(aw_dev->dev, + (monitor_hdr->temp_num * AW_TABLE_SIZE), + GFP_KERNEL); + if (temp_info->aw_table == NULL) + return -ENOMEM; + + temp_info->table_num = monitor_hdr->temp_num; + aw_monitor_write_data_to_table(aw_dev, temp_info, + &data[monitor_hdr->temp_offset]); + aw_dev_info(aw_dev->dev, "===parse temp end ==="); + return 0; +} + +static int aw_monitor_parse_vol_data(struct aw_device *aw_dev, uint8_t *data) +{ + struct aw_monitor_hdr *monitor_hdr = + (struct aw_monitor_hdr *)data; + struct aw_table_info *vol_info = + &aw_dev->monitor_desc.monitor_cfg.vol_info; + + aw_dev_info(aw_dev->dev, "===parse vol start ==="); + if (vol_info->aw_table != NULL) { + devm_kfree(aw_dev->dev, vol_info->aw_table); + vol_info->aw_table = NULL; + } + + vol_info->aw_table = devm_kzalloc(aw_dev->dev, + (monitor_hdr->vol_num * AW_TABLE_SIZE), + GFP_KERNEL); + if (vol_info->aw_table == NULL) + return -ENOMEM; + + vol_info->table_num = monitor_hdr->vol_num; + aw_monitor_write_data_to_table(aw_dev, vol_info, + &data[monitor_hdr->vol_offset]); + aw_dev_info(aw_dev->dev, "===parse vol end ==="); + return 0; +} + +static int aw_monitor_parse_vol_data_v_0_1_1(struct aw_device *aw_dev, uint8_t *data) +{ + struct aw_monitor_hdr_v_0_1_1 *monitor_hdr = + (struct aw_monitor_hdr_v_0_1_1 *)data; + struct aw_table_info *vol_info = + &aw_dev->monitor_desc.monitor_cfg.vol_info; + + aw_dev_info(aw_dev->dev, "===parse vol start ==="); + if (vol_info->aw_table != NULL) { + devm_kfree(aw_dev->dev, vol_info->aw_table); + vol_info->aw_table = NULL; + } + + vol_info->aw_table = devm_kzalloc(aw_dev->dev, + (monitor_hdr->vol_num * AW_TABLE_SIZE), + GFP_KERNEL); + if (vol_info->aw_table == NULL) + return -ENOMEM; + + vol_info->table_num = monitor_hdr->vol_num; + aw_monitor_write_data_to_table(aw_dev, vol_info, + &data[monitor_hdr->vol_offset]); + aw_dev_info(aw_dev->dev, "===parse vol end ==="); + return 0; +} + +static int aw_monitor_parse_vol_data_v_0_1_2(struct aw_device *aw_dev, uint8_t *data) +{ + struct aw_monitor_hdr_v_0_1_2 *monitor_hdr = + (struct aw_monitor_hdr_v_0_1_2 *)data; + struct aw_table_info *vol_info = + &aw_dev->monitor_desc.monitor_cfg.vol_info; + + aw_dev_info(aw_dev->dev, "===parse vol start ==="); + if (vol_info->aw_table != NULL) { + devm_kfree(aw_dev->dev, vol_info->aw_table); + vol_info->aw_table = NULL; + } + + vol_info->aw_table = devm_kzalloc(aw_dev->dev, + (monitor_hdr->vol_num * AW_TABLE_SIZE), + GFP_KERNEL); + if (vol_info->aw_table == NULL) + return -ENOMEM; + + vol_info->table_num = monitor_hdr->vol_num; + aw_monitor_write_data_to_table(aw_dev, vol_info, + &data[monitor_hdr->vol_offset]); + aw_dev_info(aw_dev->dev, "===parse vol end ==="); + return 0; +} + +static int aw_monitor_parse_data(struct aw_device *aw_dev, + uint8_t *data, uint32_t data_len) +{ + int ret; + struct aw_monitor_cfg *monitor_cfg = &aw_dev->monitor_desc.monitor_cfg; + + ret = aw_monitor_check_fw(aw_dev, data, data_len); + if (ret < 0) { + aw_dev_err(aw_dev->dev, "check monitor failed"); + return ret; + } + + aw_monitor_parse_hdr(aw_dev, data); + + ret = aw_monitor_parse_temp_data(aw_dev, data); + if (ret < 0) + return ret; + + ret = aw_monitor_parse_vol_data(aw_dev, data); + if (ret < 0) { + if (monitor_cfg->temp_info.aw_table != NULL) { + devm_kfree(aw_dev->dev, monitor_cfg->temp_info.aw_table); + monitor_cfg->temp_info.aw_table = NULL; + monitor_cfg->temp_info.table_num = 0; + } + return ret; + } + + monitor_cfg->monitor_status = AW_MON_CFG_OK; + return 0; +} + + +static int aw_monitor_parse_data_v_0_1_1(struct aw_device *aw_dev, + uint8_t *data, uint32_t data_len) +{ + int ret; + struct aw_monitor_cfg *monitor_cfg = &aw_dev->monitor_desc.monitor_cfg; + + ret = aw_monitor_check_fw_v_0_1_1(aw_dev, data, data_len); + if (ret < 0) { + aw_dev_err(aw_dev->dev, "check monitor failed"); + return ret; + } + + aw_monitor_parse_hdr_v_0_1_1(aw_dev, data); + + ret = aw_monitor_parse_temp_data_v_0_1_1(aw_dev, data); + if (ret < 0) + return ret; + + ret = aw_monitor_parse_vol_data_v_0_1_1(aw_dev, data); + if (ret < 0) { + if (monitor_cfg->temp_info.aw_table != NULL) { + devm_kfree(aw_dev->dev, monitor_cfg->temp_info.aw_table); + monitor_cfg->temp_info.aw_table = NULL; + monitor_cfg->temp_info.table_num = 0; + } + return ret; + } + + monitor_cfg->monitor_status = AW_MON_CFG_OK; + return 0; +} + +static int aw_monitor_parse_data_v_0_1_2(struct aw_device *aw_dev, + uint8_t *data, uint32_t data_len) +{ + int ret; + struct aw_monitor_cfg *monitor_cfg = &aw_dev->monitor_desc.monitor_cfg; + + ret = aw_monitor_check_fw_v_0_1_2(aw_dev, data, data_len); + if (ret < 0) { + aw_dev_err(aw_dev->dev, "check monitor failed"); + return ret; + } + + aw_monitor_parse_hdr_v_0_1_2(aw_dev, data); + + ret = aw_monitor_parse_temp_data_v_0_1_2(aw_dev, data); + if (ret < 0) + return ret; + + ret = aw_monitor_parse_vol_data_v_0_1_2(aw_dev, data); + if (ret < 0) { + if (monitor_cfg->temp_info.aw_table != NULL) { + devm_kfree(aw_dev->dev, monitor_cfg->temp_info.aw_table); + monitor_cfg->temp_info.aw_table = NULL; + monitor_cfg->temp_info.table_num = 0; + } + return ret; + } + + monitor_cfg->monitor_status = AW_MON_CFG_OK; + return 0; +} + +int aw882xx_monitor_parse_fw(struct aw_monitor_desc *monitor_desc, + uint8_t *data, uint32_t data_len) +{ + int ret; + struct aw_monitor_hdr *monitor_hdr = NULL; + struct aw_device *aw_dev = NULL; + + if (monitor_desc == NULL || data == NULL) { + pr_err("monitor_desc or data is NULL"); + return -EINVAL; + } + + monitor_hdr = (struct aw_monitor_hdr *)data; + aw_dev = container_of(monitor_desc, + struct aw_device, monitor_desc); + + ret = aw_monitor_param_check_sum(aw_dev, data, data_len); + if (ret < 0) + return ret; + + switch (monitor_hdr->monitor_ver) { + case AW_MONITOR_HDR_VER_0_1_0: + return aw_monitor_parse_data(aw_dev, data, data_len); + case AW_MONITOR_HDR_VER_0_1_1: + return aw_monitor_parse_data_v_0_1_1(aw_dev, data, data_len); + case AW_MONITOR_HDR_VER_0_1_2: + return aw_monitor_parse_data_v_0_1_2(aw_dev, data, data_len); + default: + aw_dev_err(aw_dev->dev, "cfg version:0x%x unsupported", + monitor_hdr->monitor_ver); + return -EINVAL; + } +} + +static void aw_monitor_free_firmware(struct aw_device *aw_dev) +{ + struct aw_monitor_cfg *monitor_cfg = + &aw_dev->monitor_desc.monitor_cfg; + + monitor_cfg->monitor_status = AW_MON_CFG_ST; + + if (monitor_cfg->temp_info.aw_table != NULL) { + devm_kfree(aw_dev->dev, monitor_cfg->temp_info.aw_table); + monitor_cfg->temp_info.aw_table = NULL; + } + + if (monitor_cfg->vol_info.aw_table != NULL) { + devm_kfree(aw_dev->dev, monitor_cfg->vol_info.aw_table); + monitor_cfg->vol_info.aw_table = NULL; + } + + memset(monitor_cfg, 0, sizeof(struct aw_monitor_cfg)); +} + +static int aw_monitor_real_time_update_monitor(struct aw_device *aw_dev) +{ + int ret; + const struct firmware *cont = NULL; + struct aw_container *aw_monitor_cnt = NULL; + + ret = request_firmware(&cont, aw_dev->monitor_name, aw_dev->dev); + if (ret < 0) { + aw_dev_err(aw_dev->dev, "failed to read %s", aw_dev->monitor_name); + release_firmware(cont); + return ret; + } + + aw_monitor_cnt = devm_kzalloc(aw_dev->dev, + cont->size + sizeof(uint32_t), GFP_KERNEL); + if (aw_monitor_cnt == NULL) { + release_firmware(cont); + return -ENOMEM; + } + + aw_monitor_cnt->len = cont->size; + memcpy(aw_monitor_cnt->data, cont->data, cont->size); + release_firmware(cont); + + ret = aw882xx_monitor_parse_fw(&aw_dev->monitor_desc, + aw_monitor_cnt->data, aw_monitor_cnt->len); + if (ret < 0) + aw_dev_err(aw_dev->dev, "parse monitor firmware failed!"); + + devm_kfree(aw_dev->dev, aw_monitor_cnt); + aw_monitor_cnt = NULL; + + return ret; +} + +/***************************************************** + * monitor init + *****************************************************/ +#ifdef AW_DEBUG +static ssize_t vol_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + int ret = -1; + struct aw882xx *aw882xx = dev_get_drvdata(dev); + struct aw_device *aw_dev = aw882xx->aw_pa; + uint32_t vol = 0; + + if (count == 0) + return 0; + + ret = kstrtouint(buf, 0, &vol); + if (ret < 0) + return ret; + + aw_dev_info(aw_dev->dev, "vol set =%d", vol); + aw_dev->monitor_desc.test_vol = vol; + + return count; +} + +static ssize_t vol_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct aw882xx *aw882xx = dev_get_drvdata(dev); + struct aw_device *aw_dev = aw882xx->aw_pa; + ssize_t len = 0; + + len += snprintf(buf+len, PAGE_SIZE-len, + "vol: %d\n", + aw_dev->monitor_desc.test_vol); + return len; +} + +static ssize_t temp_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + int ret = -1; + struct aw882xx *aw882xx = dev_get_drvdata(dev); + struct aw_device *aw_dev = aw882xx->aw_pa; + int32_t temp = 0; + + if (count == 0) + return 0; + + ret = kstrtoint(buf, 0, &temp); + if (ret < 0) + return ret; + + aw_dev_info(aw_dev->dev, "temp set =%d", temp); + + aw_dev->monitor_desc.test_temp = temp; + + return count; +} + +static ssize_t temp_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct aw882xx *aw882xx = dev_get_drvdata(dev); + struct aw_device *aw_dev = aw882xx->aw_pa; + ssize_t len = 0; + + len += snprintf(buf+len, PAGE_SIZE-len, + "aw882xx temp: %d\n", + aw_dev->monitor_desc.test_temp); + + return len; +} + +static DEVICE_ATTR_RW(vol); +static DEVICE_ATTR_RW(temp); +#endif + +static ssize_t monitor_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + int ret = -1; + struct aw882xx *aw882xx = dev_get_drvdata(dev); + struct aw_device *aw_dev = aw882xx->aw_pa; + uint32_t enable = 0; + + if (count == 0) + return 0; + + ret = kstrtouint(buf, 0, &enable); + if (ret < 0) + return ret; + + aw_dev_info(aw_dev->dev, "monitor enable set =%d", enable); + + if (aw_dev->monitor_desc.monitor_cfg.monitor_switch == enable) + return count; + + aw_dev->monitor_desc.monitor_cfg.monitor_switch = enable; + if (enable) + aw882xx_monitor_start(&aw_dev->monitor_desc); + + return count; +} + +static ssize_t monitor_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct aw882xx *aw882xx = dev_get_drvdata(dev); + struct aw_device *aw_dev = aw882xx->aw_pa; + ssize_t len = 0; + + len += snprintf(buf+len, PAGE_SIZE-len, + "monitor enable: %d\n", + aw_dev->monitor_desc.monitor_cfg.monitor_switch); + return len; +} + +static ssize_t monitor_update_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + int ret = -1; + struct aw882xx *aw882xx = dev_get_drvdata(dev); + struct aw_device *aw_dev = aw882xx->aw_pa; + uint32_t update = 0; + + if (count == 0) + return 0; + + ret = kstrtouint(buf, 0, &update); + if (ret < 0) + return ret; + + aw_dev_info(aw_dev->dev, "monitor update = %d", update); + + if (update) { + aw882xx_monitor_stop(&aw_dev->monitor_desc); + aw_monitor_free_firmware(aw_dev); + ret = aw_monitor_real_time_update_monitor(aw_dev); + if (ret < 0) + return ret; + aw882xx_monitor_start(&aw_dev->monitor_desc); + } + + return count; +} + +static DEVICE_ATTR_RW(monitor); +static DEVICE_ATTR_WO(monitor_update); + +static struct attribute *aw_monitor_attr[] = { + &dev_attr_monitor.attr, + &dev_attr_monitor_update.attr, +#ifdef AW_DEBUG + &dev_attr_vol.attr, + &dev_attr_temp.attr, +#endif + NULL +}; + +static struct attribute_group aw_monitor_attr_group = { + .attrs = aw_monitor_attr, +}; + +static void aw_monitor_parse_mode(struct aw_device *aw_dev) +{ + int ret = 0; + const char *mon_mode_str = NULL; + struct aw_monitor_desc *monitor = &aw_dev->monitor_desc; + + ret = of_property_read_string(aw_dev->dev->of_node, "monitor-mode", &mon_mode_str); + if (ret < 0) { + aw_dev_info(aw_dev->dev, "use default monitor mode"); + return; + } + + if (!strcmp(mon_mode_str, "kernel_monitor")) + monitor->monitor_mode = AW_MON_KERNEL_MODE; + else if (!strcmp(mon_mode_str, "hal_monitor")) + monitor->monitor_mode = AW_MON_HAL_MODE; + else + monitor->monitor_mode = AW_MON_KERNEL_MODE; + + aw_dev_info(aw_dev->dev, "read monitor-mode value is : %d", monitor->monitor_mode); +} + +void aw882xx_monitor_init(struct aw_monitor_desc *monitor_desc) +{ + int ret; + struct aw_device *aw_dev = container_of(monitor_desc, + struct aw_device, monitor_desc); + + aw_dev_info(aw_dev->dev, "enter"); +#ifdef AW_DEBUG + monitor_desc->test_vol = 0; + monitor_desc->test_temp = 0; +#endif + + + aw_monitor_parse_mode(aw_dev); + INIT_DELAYED_WORK(&monitor_desc->delay_work, aw_monitor_work_func); + + ret = sysfs_create_group(&aw_dev->dev->kobj, + &aw_monitor_attr_group); + if (ret < 0) + aw_dev_err(aw_dev->dev, "error creating sysfs attr files"); +} + +void aw882xx_monitor_deinit(struct aw_monitor_desc *monitor_desc) +{ + struct aw_device *aw_dev = + container_of(monitor_desc, struct aw_device, monitor_desc); + + aw882xx_monitor_stop(monitor_desc); + + sysfs_remove_group(&aw_dev->dev->kobj, &aw_monitor_attr_group); +} + diff --git a/sound/soc/codecs/aw882xx/aw882xx_monitor.h b/sound/soc/codecs/aw882xx/aw882xx_monitor.h new file mode 100644 index 000000000000..832eeaa98c2a --- /dev/null +++ b/sound/soc/codecs/aw882xx/aw882xx_monitor.h @@ -0,0 +1,234 @@ +/* SPDX-License-Identifier: GPL-2.0 + * aw882xx_monitor.h + * + * Copyright (c) 2020 AWINIC Technology CO., LTD + * + * Author: Nick Li + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#ifndef __AW882XX_MONITOR_H__ +#define __AW882XX_MONITOR_H__ + +/*#define AW_DEBUG*/ + +struct aw_table; + +#define AW_TABLE_SIZE sizeof(struct aw_table) +#define AW_MONITOR_DEFAULT_FLAG (0) + +#define IPEAK_NONE (0xFF) +#define GAIN_NONE (0xFF) +#define VMAX_NONE (0xFFFFFFFF) + + +#define AW_GET_32_DATA(w, x, y, z) \ + ((uint32_t)((((uint8_t)w) << 24) | (((uint8_t)x) << 16) | (((uint8_t)y) << 8) | ((uint8_t)z))) +#define AW_GET_16_DATA(x, y) \ + ((uint16_t)((((uint8_t)x) << 8) | (uint8_t)y)) + +enum { + AW_MON_LOGIC_OR = 0, + AW_MON_LOGIC_AND = 1, +}; + +enum { + AW_FIRST_ENTRY = 0, + AW_NOT_FIRST_ENTRY = 1, +}; + +enum aw_monitor_hdr_ver { + AW_MONITOR_HDR_VER_0_1_0 = 0x00010000, + AW_MONITOR_HDR_VER_0_1_1 = 0x00010100, + AW_MONITOR_HDR_VER_0_1_2 = 0x00010200, +}; + +enum aw_monitor_init { + AW_MON_CFG_ST = 0, + AW_MON_CFG_OK = 1, +}; + +struct aw_monitor_hdr { + uint32_t check_sum; + uint32_t monitor_ver; + char chip_type[8]; + uint32_t ui_ver; + uint32_t monitor_switch; + uint32_t monitor_time; + uint32_t monitor_count; + uint32_t ipeak_switch; + uint32_t gain_switch; + uint32_t vmax_switch; + uint32_t temp_switch; + uint32_t temp_aplha; + uint32_t temp_num; + uint32_t single_temp_size; + uint32_t temp_offset; + uint32_t vol_switch; + uint32_t vol_aplha; + uint32_t vol_num; + uint32_t single_vol_size; + uint32_t vol_offset; +}; + +#define MONITOR_EN_MASK (0x01) + +enum { + MONITOR_EN_BIT = 0, + MONITOR_LOGIC_BIT = 1, + MONITOR_IPEAK_EN_BIT = 2, + MONITOR_GAIN_EN_BIT = 3, + MONITOR_VMAX_EN_BIT = 4, + MONITOR_TEMP_EN_BIT = 5, + MONITOR_VOL_EN_BIT = 6, + MONITOR_TEMPERATURE_SOURCE_BIT = 7, + MONITOR_VOLTAGE_SOURCE_BIT = 8, + MONITOR_VOLTAGE_MODE_BIT = 9, +}; + +struct aw_monitor_hdr_v_0_1_1 { + uint32_t check_sum; + uint32_t monitor_ver; + char chip_type[16]; + uint32_t ui_ver; + uint32_t monitor_time; + uint32_t monitor_count; + uint32_t enable_flag; + /* [bit 31:7] */ + /* [bit 6: vol en] */ + /* [bit 5: temp en] */ + /* [bit 4: vmax en] */ + /* [bit 3: gain en] */ + /* [bit 2: ipeak en] */ + /* [bit 1: & or | flag] */ + /* [bit 0: monitor en] */ + uint32_t temp_aplha; + uint32_t temp_num; + uint32_t single_temp_size; + uint32_t temp_offset; + uint32_t vol_aplha; + uint32_t vol_num; + uint32_t single_vol_size; + uint32_t vol_offset; + uint32_t reserver[3]; +}; + +/* v0.1.2 */ +struct aw_monitor_hdr_v_0_1_2 { + uint32_t check_sum; + uint32_t monitor_ver; + char chip_type[16]; + uint32_t ui_ver; + uint32_t monitor_time; + uint32_t monitor_count; + uint32_t enable_flag; + /* [bit 31:7]*/ + /* [bit 9: voltage mode]*/ + /* [bit 8: voltage source]*/ + /* [bit 7: temperature source]*/ + /* [bit 6: vol en]*/ + /* [bit 5: temp en]*/ + /* [bit 4: vmax en]*/ + /* [bit 3: gain en]*/ + /* [bit 2: ipeak en]*/ + /* [bit 1: & or | flag]*/ + /* [bit 0: monitor en]*/ + uint32_t temp_aplha; + uint32_t temp_num; + uint32_t single_temp_size; + uint32_t temp_offset; + uint32_t vol_aplha; + uint32_t vol_num; + uint32_t single_vol_size; + uint32_t vol_offset; + uint32_t reserver[3]; +}; + +struct aw_table { + int16_t min_val; + int16_t max_val; + uint16_t ipeak; + uint16_t gain; + uint32_t vmax; +}; + +struct aw_table_info { + uint8_t table_num; + struct aw_table *aw_table; +}; + +struct aw_monitor_cfg { + uint8_t monitor_status; + uint32_t monitor_switch; + uint32_t monitor_time; + uint32_t monitor_count; + uint32_t logic_switch; + uint32_t temp_switch; + uint32_t temp_aplha; + uint32_t vol_switch; + uint32_t vol_aplha; + uint32_t ipeak_switch; + uint32_t gain_switch; + uint32_t vmax_switch; + uint32_t temp_source; + uint32_t vol_source; + uint32_t vol_mode; + struct aw_table_info temp_info; + struct aw_table_info vol_info; +}; + +struct aw_monitor_trace { + int32_t pre_val; + int32_t sum_val; + struct aw_table aw_table; +}; + +enum aw_monitor_mode { + AW_MON_KERNEL_MODE = 0, + AW_MON_HAL_MODE, +}; + +/****************************************************************** + * struct aw882xx monitor + *******************************************************************/ +struct aw_monitor_desc { + struct delayed_work delay_work; + struct aw_monitor_cfg monitor_cfg; + + bool mon_start_flag; + uint8_t first_entry; + uint8_t samp_count; + uint8_t db_offset; + uint8_t monitor_mode; + + uint32_t pre_vmax; + struct aw_monitor_trace temp_trace; + struct aw_monitor_trace vol_trace; + + +#ifdef AW_DEBUG + uint16_t test_vol; + int16_t test_temp; +#endif +}; + +/****************************************************************** + * aw882xx monitor functions + *******************************************************************/ +void aw882xx_monitor_start(struct aw_monitor_desc *monitor_desc); +int aw882xx_monitor_stop(struct aw_monitor_desc *monitor_desc); +void aw882xx_monitor_init(struct aw_monitor_desc *monitor_desc); +void aw882xx_monitor_deinit(struct aw_monitor_desc *monitor_desc); +int aw882xx_monitor_parse_fw(struct aw_monitor_desc *monitor_desc, + uint8_t *data, uint32_t data_len); + +void aw882xx_monitor_hal_work(struct aw_monitor_desc *monitor_desc, uint32_t *vmax); +void aw882xx_monitor_hal_get_time(struct aw_monitor_desc *monitor_desc, uint32_t *time); + + +#endif + diff --git a/sound/soc/codecs/aw882xx/aw882xx_pid_1852_reg.h b/sound/soc/codecs/aw882xx/aw882xx_pid_1852_reg.h new file mode 100644 index 000000000000..94af10893b62 --- /dev/null +++ b/sound/soc/codecs/aw882xx/aw882xx_pid_1852_reg.h @@ -0,0 +1,1927 @@ +/* SPDX-License-Identifier: GPL-2.0 + * aw882xx_pid_1852_reg.h + * + * Copyright (c) 2020 AWINIC Technology CO., LTD + * + * Author: Nick Li + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#ifndef __AW882XX_PID_1852_REG_H__ +#define __AW882XX_PID_1852_REG_H__ + +#define AW_PID_1852_MONITOR_FILE "aw882xx_pid_1852_monitor.bin" + +/* registers list */ +#define AW_PID_1852_ID_REG (0x00) +#define AW_PID_1852_SYSST_REG (0x01) +#define AW_PID_1852_SYSINT_REG (0x02) +#define AW_PID_1852_SYSINTM_REG (0x03) +#define AW_PID_1852_SYSCTRL_REG (0x04) +#define AW_PID_1852_SYSCTRL2_REG (0x05) +#define AW_PID_1852_I2SCTRL_REG (0x06) +#define AW_PID_1852_I2SCFG1_REG (0x07) +#define AW_PID_1852_I2SCFG2_REG (0x08) +#define AW_PID_1852_HAGCCFG1_REG (0x09) +#define AW_PID_1852_HAGCCFG2_REG (0x0A) +#define AW_PID_1852_HAGCCFG3_REG (0x0B) +#define AW_PID_1852_HAGCCFG4_REG (0x0C) +#define AW_PID_1852_HAGCCFG5_REG (0x0D) +#define AW_PID_1852_HAGCCFG6_REG (0x0E) +#define AW_PID_1852_HAGCCFG7_REG (0x0F) +#define AW_PID_1852_HAGCST_REG (0x10) +#define AW_PID_1852_PRODID_REG (0x11) +#define AW_PID_1852_VBAT_REG (0x12) +#define AW_PID_1852_TEMP_REG (0x13) +#define AW_PID_1852_PVDD_REG (0x14) +#define AW_PID_1852_DBGCTRL_REG (0x20) +#define AW_PID_1852_I2SINT_REG (0x21) +#define AW_PID_1852_I2SCAPCNT_REG (0x22) +#define AW_PID_1852_CRCIN_REG (0x38) +#define AW_PID_1852_CRCOUT_REG (0x39) +#define AW_PID_1852_VSNCTRL1_REG (0x50) +#define AW_PID_1852_ISNCTRL1_REG (0x52) +#define AW_PID_1852_ISNCTRL2_REG (0x53) +#define AW_PID_1852_VTMCTRL1_REG (0x54) +#define AW_PID_1852_VTMCTRL2_REG (0x55) +#define AW_PID_1852_VTMCTRL3_REG (0x56) +#define AW_PID_1852_ISNDAT_REG (0x57) +#define AW_PID_1852_VSNDAT_REG (0x58) +#define AW_PID_1852_PWMCTRL_REG (0x59) +#define AW_PID_1852_PWMCTRL2_REG (0x5A) +#define AW_PID_1852_BSTCTRL1_REG (0x60) +#define AW_PID_1852_BSTCTRL2_REG (0x61) +#define AW_PID_1852_BSTCTRL3_REG (0x62) +#define AW_PID_1852_BSTDBG1_REG (0x63) +#define AW_PID_1852_BSTDBG2_REG (0x64) +#define AW_PID_1852_BSTDBG3_REG (0x65) +#define AW_PID_1852_PLLCTRL1_REG (0x66) +#define AW_PID_1852_PLLCTRL2_REG (0x67) +#define AW_PID_1852_PLLCTRL3_REG (0x68) +#define AW_PID_1852_CDACTRL1_REG (0x69) +#define AW_PID_1852_CDACTRL2_REG (0x6A) +#define AW_PID_1852_SADCCTRL_REG (0x6B) +#define AW_PID_1852_TESTCTRL1_REG (0x70) +#define AW_PID_1852_TESTCTRL2_REG (0x71) +#define AW_PID_1852_EFCTRL1_REG (0x72) +#define AW_PID_1852_EFCTRL2_REG (0x73) +#define AW_PID_1852_EFWH_REG (0x74) +#define AW_PID_1852_EFWM2_REG (0x75) +#define AW_PID_1852_EFWM1_REG (0x76) +#define AW_PID_1852_EFWL_REG (0x77) +#define AW_PID_1852_EFRH_REG (0x78) +#define AW_PID_1852_EFRM2_REG (0x79) +#define AW_PID_1852_EFRM1_REG (0x7A) +#define AW_PID_1852_EFRL_REG (0x7B) +#define AW_PID_1852_TESTDET_REG (0x7C) + +/******************************************** + * Register Access + *******************************************/ +#define AW_PID_1852_REG_MAX (0x7D) + + +#define AW_PID_1852_REG_NONE_ACCESS (0) +#define AW_PID_1852_REG_RD_ACCESS (1 << 0) +#define AW_PID_1852_REG_WR_ACCESS (1 << 1) + + +static const unsigned char aw_pid_1852_reg_access[AW_PID_1852_REG_MAX] = { + [AW_PID_1852_ID_REG] = (AW_PID_1852_REG_RD_ACCESS), + [AW_PID_1852_SYSST_REG] = (AW_PID_1852_REG_RD_ACCESS), + [AW_PID_1852_SYSINT_REG] = (AW_PID_1852_REG_RD_ACCESS), + [AW_PID_1852_SYSINTM_REG] = (AW_PID_1852_REG_RD_ACCESS | AW_PID_1852_REG_WR_ACCESS), + [AW_PID_1852_SYSCTRL_REG] = (AW_PID_1852_REG_RD_ACCESS | AW_PID_1852_REG_WR_ACCESS), + [AW_PID_1852_SYSCTRL2_REG] = (AW_PID_1852_REG_RD_ACCESS | AW_PID_1852_REG_WR_ACCESS), + [AW_PID_1852_I2SCTRL_REG] = (AW_PID_1852_REG_RD_ACCESS | AW_PID_1852_REG_WR_ACCESS), + [AW_PID_1852_I2SCFG1_REG] = (AW_PID_1852_REG_RD_ACCESS | AW_PID_1852_REG_WR_ACCESS), + [AW_PID_1852_I2SCFG2_REG] = (AW_PID_1852_REG_RD_ACCESS | AW_PID_1852_REG_WR_ACCESS), + [AW_PID_1852_HAGCCFG1_REG] = (AW_PID_1852_REG_RD_ACCESS | AW_PID_1852_REG_WR_ACCESS), + [AW_PID_1852_HAGCCFG2_REG] = (AW_PID_1852_REG_RD_ACCESS | AW_PID_1852_REG_WR_ACCESS), + [AW_PID_1852_HAGCCFG3_REG] = (AW_PID_1852_REG_RD_ACCESS | AW_PID_1852_REG_WR_ACCESS), + [AW_PID_1852_HAGCCFG4_REG] = (AW_PID_1852_REG_RD_ACCESS | AW_PID_1852_REG_WR_ACCESS), + [AW_PID_1852_HAGCCFG5_REG] = (AW_PID_1852_REG_RD_ACCESS | AW_PID_1852_REG_WR_ACCESS), + [AW_PID_1852_HAGCCFG6_REG] = (AW_PID_1852_REG_RD_ACCESS | AW_PID_1852_REG_WR_ACCESS), + [AW_PID_1852_HAGCCFG7_REG] = (AW_PID_1852_REG_RD_ACCESS | AW_PID_1852_REG_WR_ACCESS), + [AW_PID_1852_HAGCST_REG] = (AW_PID_1852_REG_RD_ACCESS), + [AW_PID_1852_PRODID_REG] = (AW_PID_1852_REG_RD_ACCESS), + [AW_PID_1852_VBAT_REG] = (AW_PID_1852_REG_RD_ACCESS), + [AW_PID_1852_TEMP_REG] = (AW_PID_1852_REG_RD_ACCESS), + [AW_PID_1852_PVDD_REG] = (AW_PID_1852_REG_RD_ACCESS), + [AW_PID_1852_DBGCTRL_REG] = (AW_PID_1852_REG_RD_ACCESS | AW_PID_1852_REG_WR_ACCESS), + [AW_PID_1852_I2SINT_REG] = (AW_PID_1852_REG_RD_ACCESS), + [AW_PID_1852_I2SCAPCNT_REG] = (AW_PID_1852_REG_RD_ACCESS), + [AW_PID_1852_CRCIN_REG] = (AW_PID_1852_REG_RD_ACCESS | AW_PID_1852_REG_WR_ACCESS), + [AW_PID_1852_CRCOUT_REG] = (AW_PID_1852_REG_RD_ACCESS), + [AW_PID_1852_VSNCTRL1_REG] = (AW_PID_1852_REG_RD_ACCESS | AW_PID_1852_REG_WR_ACCESS), + [AW_PID_1852_ISNCTRL1_REG] = (AW_PID_1852_REG_RD_ACCESS | AW_PID_1852_REG_WR_ACCESS), + [AW_PID_1852_ISNCTRL2_REG] = (AW_PID_1852_REG_RD_ACCESS | AW_PID_1852_REG_WR_ACCESS), + [AW_PID_1852_VTMCTRL1_REG] = (AW_PID_1852_REG_RD_ACCESS | AW_PID_1852_REG_WR_ACCESS), + [AW_PID_1852_VTMCTRL2_REG] = (AW_PID_1852_REG_RD_ACCESS | AW_PID_1852_REG_WR_ACCESS), + [AW_PID_1852_VTMCTRL3_REG] = (AW_PID_1852_REG_RD_ACCESS | AW_PID_1852_REG_WR_ACCESS), + [AW_PID_1852_ISNDAT_REG] = (AW_PID_1852_REG_RD_ACCESS), + [AW_PID_1852_VSNDAT_REG] = (AW_PID_1852_REG_RD_ACCESS), + [AW_PID_1852_PWMCTRL_REG] = (AW_PID_1852_REG_RD_ACCESS | AW_PID_1852_REG_WR_ACCESS), + [AW_PID_1852_PWMCTRL2_REG] = (AW_PID_1852_REG_RD_ACCESS | AW_PID_1852_REG_WR_ACCESS), + [AW_PID_1852_BSTCTRL1_REG] = (AW_PID_1852_REG_RD_ACCESS | AW_PID_1852_REG_WR_ACCESS), + [AW_PID_1852_BSTCTRL2_REG] = (AW_PID_1852_REG_RD_ACCESS | AW_PID_1852_REG_WR_ACCESS), + [AW_PID_1852_BSTCTRL3_REG] = (AW_PID_1852_REG_RD_ACCESS | AW_PID_1852_REG_WR_ACCESS), + [AW_PID_1852_BSTDBG1_REG] = (AW_PID_1852_REG_RD_ACCESS | AW_PID_1852_REG_WR_ACCESS), + [AW_PID_1852_BSTDBG2_REG] = (AW_PID_1852_REG_RD_ACCESS | AW_PID_1852_REG_WR_ACCESS), + [AW_PID_1852_BSTDBG3_REG] = (AW_PID_1852_REG_RD_ACCESS | AW_PID_1852_REG_WR_ACCESS), + [AW_PID_1852_PLLCTRL1_REG] = (AW_PID_1852_REG_RD_ACCESS | AW_PID_1852_REG_WR_ACCESS), + [AW_PID_1852_PLLCTRL2_REG] = (AW_PID_1852_REG_RD_ACCESS | AW_PID_1852_REG_WR_ACCESS), + [AW_PID_1852_PLLCTRL3_REG] = (AW_PID_1852_REG_RD_ACCESS | AW_PID_1852_REG_WR_ACCESS), + [AW_PID_1852_CDACTRL1_REG] = (AW_PID_1852_REG_RD_ACCESS | AW_PID_1852_REG_WR_ACCESS), + [AW_PID_1852_CDACTRL2_REG] = (AW_PID_1852_REG_RD_ACCESS | AW_PID_1852_REG_WR_ACCESS), + [AW_PID_1852_SADCCTRL_REG] = (AW_PID_1852_REG_RD_ACCESS | AW_PID_1852_REG_WR_ACCESS), + [AW_PID_1852_TESTCTRL1_REG] = (AW_PID_1852_REG_RD_ACCESS | AW_PID_1852_REG_WR_ACCESS), + [AW_PID_1852_TESTCTRL2_REG] = (AW_PID_1852_REG_RD_ACCESS | AW_PID_1852_REG_WR_ACCESS), + [AW_PID_1852_EFCTRL1_REG] = (AW_PID_1852_REG_RD_ACCESS | AW_PID_1852_REG_WR_ACCESS), + [AW_PID_1852_EFCTRL2_REG] = (AW_PID_1852_REG_RD_ACCESS | AW_PID_1852_REG_WR_ACCESS), + [AW_PID_1852_EFWH_REG] = (AW_PID_1852_REG_RD_ACCESS | AW_PID_1852_REG_WR_ACCESS), + [AW_PID_1852_EFWM2_REG] = (AW_PID_1852_REG_RD_ACCESS | AW_PID_1852_REG_WR_ACCESS), + [AW_PID_1852_EFWM1_REG] = (AW_PID_1852_REG_RD_ACCESS | AW_PID_1852_REG_WR_ACCESS), + [AW_PID_1852_EFWL_REG] = (AW_PID_1852_REG_RD_ACCESS | AW_PID_1852_REG_WR_ACCESS), + [AW_PID_1852_EFRH_REG] = (AW_PID_1852_REG_RD_ACCESS), + [AW_PID_1852_EFRM2_REG] = (AW_PID_1852_REG_RD_ACCESS), + [AW_PID_1852_EFRM1_REG] = (AW_PID_1852_REG_RD_ACCESS), + [AW_PID_1852_EFRL_REG] = (AW_PID_1852_REG_RD_ACCESS), + [AW_PID_1852_TESTDET_REG] = (AW_PID_1852_REG_RD_ACCESS), +}; + +/* detail information of registers begin */ +/* ID (0x00) detail */ +/* IDCODE bit 15:0 (ID 0x00) */ +#define AW_PID_1852_IDCODE_START_BIT (0) +#define AW_PID_1852_IDCODE_BITS_LEN (16) +#define AW_PID_1852_IDCODE_MASK \ + (~(((1< + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#ifndef __AW882XX_PID_2013_REG_H__ +#define __AW882XX_PID_2013_REG_H__ + +#define AW_PID_2013_MONITOR_FILE "aw882xx_pid_2013_monitor.bin" + +/* registers list */ +#define AW_PID_2013_ID_REG (0x00) +#define AW_PID_2013_SYSST_REG (0x01) +#define AW_PID_2013_SYSINT_REG (0x02) +#define AW_PID_2013_SYSINTM_REG (0x03) +#define AW_PID_2013_SYSCTRL_REG (0x04) +#define AW_PID_2013_SYSCTRL2_REG (0x05) +#define AW_PID_2013_I2SCTRL1_REG (0x06) +#define AW_PID_2013_I2SCTRL2_REG (0x07) +#define AW_PID_2013_DACCFG1_REG (0x08) +#define AW_PID_2013_DACCFG2_REG (0x09) +#define AW_PID_2013_DACCFG3_REG (0x0A) +#define AW_PID_2013_DACCFG4_REG (0x0B) +#define AW_PID_2013_DACCFG5_REG (0x0C) +#define AW_PID_2013_DACCFG6_REG (0x0D) +#define AW_PID_2013_DACCFG7_REG (0x0E) +#define AW_PID_2013_PWMCTRL_REG (0x10) +#define AW_PID_2013_I2SCFG1_REG (0x11) +#define AW_PID_2013_DBGCTRL_REG (0x12) +#define AW_PID_2013_DACST_REG (0x20) +#define AW_PID_2013_VBAT_REG (0x21) +#define AW_PID_2013_TEMP_REG (0x22) +#define AW_PID_2013_PVDD_REG (0x23) +#define AW_PID_2013_ISNDAT_REG (0x24) +#define AW_PID_2013_VSNDAT_REG (0x25) +#define AW_PID_2013_I2SINT_REG (0x26) +#define AW_PID_2013_I2SCAPCNT_REG (0x27) +#define AW_PID_2013_ANASTA1_REG (0x28) +#define AW_PID_2013_ANASTA2_REG (0x29) +#define AW_PID_2013_ANASTA3_REG (0x2A) +#define AW_PID_2013_TESTDET_REG (0x2B) +#define AW_PID_2013_TESTIN_REG (0x38) +#define AW_PID_2013_TESTOUT_REG (0x39) +#define AW_PID_2013_VSNTM1_REG (0x50) +#define AW_PID_2013_VSNTM2_REG (0x51) +#define AW_PID_2013_ISNCTRL1_REG (0x52) +#define AW_PID_2013_PLLCTRL1_REG (0x53) +#define AW_PID_2013_PLLCTRL2_REG (0x54) +#define AW_PID_2013_PLLCTRL3_REG (0x55) +#define AW_PID_2013_CDACTRL1_REG (0x56) +#define AW_PID_2013_CDACTRL2_REG (0x57) +#define AW_PID_2013_SADCCTRL1_REG (0x58) +#define AW_PID_2013_BSTCTRL1_REG (0x60) +#define AW_PID_2013_BSTCTRL2_REG (0x61) +#define AW_PID_2013_BSTCTRL3_REG (0x62) +#define AW_PID_2013_BSTCTRL4_REG (0x63) +#define AW_PID_2013_BSTCTRL5_REG (0x64) +#define AW_PID_2013_BSTCTRL6_REG (0x65) +#define AW_PID_2013_DSMCFG1_REG (0x66) +#define AW_PID_2013_DSMCFG2_REG (0x67) +#define AW_PID_2013_DSMCFG3_REG (0x68) +#define AW_PID_2013_DSMCFG4_REG (0x69) +#define AW_PID_2013_DSMCFG5_REG (0x6A) +#define AW_PID_2013_DSMCFG6_REG (0x6B) +#define AW_PID_2013_DSMCFG7_REG (0x6C) +#define AW_PID_2013_DSMCFG8_REG (0x6D) +#define AW_PID_2013_TESTCTRL1_REG (0x70) +#define AW_PID_2013_TESTCTRL2_REG (0x71) +#define AW_PID_2013_EFCTRL1_REG (0x72) +#define AW_PID_2013_EFCTRL2_REG (0x73) +#define AW_PID_2013_EFWH_REG (0x74) +#define AW_PID_2013_EFWM2_REG (0x75) +#define AW_PID_2013_EFWM1_REG (0x76) +#define AW_PID_2013_EFWL_REG (0x77) +#define AW_PID_2013_EFRH_REG (0x78) +#define AW_PID_2013_EFRM2_REG (0x79) +#define AW_PID_2013_EFRM1_REG (0x7A) +#define AW_PID_2013_EFRL_REG (0x7B) +#define AW_PID_2013_TM_REG (0x7C) + +/******************************************** + * Register Access + *******************************************/ +#define AW_PID_2013_REG_MAX (0x7D) + +#define AW_PID_2013_REG_NONE_ACCESS (0) +#define AW_PID_2013_REG_RD_ACCESS (1 << 0) +#define AW_PID_2013_REG_WR_ACCESS (1 << 1) + +const unsigned char aw_pid_2013_reg_access[AW_PID_2013_REG_MAX] = { + [AW_PID_2013_ID_REG] = (AW_PID_2013_REG_RD_ACCESS), + [AW_PID_2013_SYSST_REG] = (AW_PID_2013_REG_RD_ACCESS), + [AW_PID_2013_SYSINT_REG] = (AW_PID_2013_REG_RD_ACCESS), + [AW_PID_2013_SYSINTM_REG] = (AW_PID_2013_REG_RD_ACCESS | AW_PID_2013_REG_WR_ACCESS), + [AW_PID_2013_SYSCTRL_REG] = (AW_PID_2013_REG_RD_ACCESS | AW_PID_2013_REG_WR_ACCESS), + [AW_PID_2013_SYSCTRL2_REG] = (AW_PID_2013_REG_RD_ACCESS | AW_PID_2013_REG_WR_ACCESS), + [AW_PID_2013_I2SCTRL1_REG] = (AW_PID_2013_REG_RD_ACCESS | AW_PID_2013_REG_WR_ACCESS), + [AW_PID_2013_I2SCTRL2_REG] = (AW_PID_2013_REG_RD_ACCESS | AW_PID_2013_REG_WR_ACCESS), + [AW_PID_2013_DACCFG1_REG] = (AW_PID_2013_REG_RD_ACCESS | AW_PID_2013_REG_WR_ACCESS), + [AW_PID_2013_DACCFG2_REG] = (AW_PID_2013_REG_RD_ACCESS | AW_PID_2013_REG_WR_ACCESS), + [AW_PID_2013_DACCFG3_REG] = (AW_PID_2013_REG_RD_ACCESS | AW_PID_2013_REG_WR_ACCESS), + [AW_PID_2013_DACCFG4_REG] = (AW_PID_2013_REG_RD_ACCESS | AW_PID_2013_REG_WR_ACCESS), + [AW_PID_2013_DACCFG5_REG] = (AW_PID_2013_REG_RD_ACCESS | AW_PID_2013_REG_WR_ACCESS), + [AW_PID_2013_DACCFG6_REG] = (AW_PID_2013_REG_RD_ACCESS | AW_PID_2013_REG_WR_ACCESS), + [AW_PID_2013_DACCFG7_REG] = (AW_PID_2013_REG_RD_ACCESS | AW_PID_2013_REG_WR_ACCESS), + [AW_PID_2013_PWMCTRL_REG] = (AW_PID_2013_REG_RD_ACCESS | AW_PID_2013_REG_WR_ACCESS), + [AW_PID_2013_I2SCFG1_REG] = (AW_PID_2013_REG_RD_ACCESS | AW_PID_2013_REG_WR_ACCESS), + [AW_PID_2013_DBGCTRL_REG] = (AW_PID_2013_REG_RD_ACCESS | AW_PID_2013_REG_WR_ACCESS), + [AW_PID_2013_DACST_REG] = (AW_PID_2013_REG_RD_ACCESS), + [AW_PID_2013_VBAT_REG] = (AW_PID_2013_REG_RD_ACCESS), + [AW_PID_2013_TEMP_REG] = (AW_PID_2013_REG_RD_ACCESS), + [AW_PID_2013_PVDD_REG] = (AW_PID_2013_REG_RD_ACCESS), + [AW_PID_2013_ISNDAT_REG] = (AW_PID_2013_REG_RD_ACCESS), + [AW_PID_2013_VSNDAT_REG] = (AW_PID_2013_REG_RD_ACCESS), + [AW_PID_2013_I2SINT_REG] = (AW_PID_2013_REG_RD_ACCESS), + [AW_PID_2013_I2SCAPCNT_REG] = (AW_PID_2013_REG_RD_ACCESS), + [AW_PID_2013_ANASTA1_REG] = (AW_PID_2013_REG_RD_ACCESS), + [AW_PID_2013_ANASTA2_REG] = (AW_PID_2013_REG_RD_ACCESS), + [AW_PID_2013_ANASTA3_REG] = (AW_PID_2013_REG_RD_ACCESS), + [AW_PID_2013_TESTDET_REG] = (AW_PID_2013_REG_RD_ACCESS), + [AW_PID_2013_TESTIN_REG] = (AW_PID_2013_REG_RD_ACCESS | AW_PID_2013_REG_WR_ACCESS), + [AW_PID_2013_TESTOUT_REG] = (AW_PID_2013_REG_RD_ACCESS), + [AW_PID_2013_VSNTM1_REG] = (AW_PID_2013_REG_RD_ACCESS | AW_PID_2013_REG_WR_ACCESS), + [AW_PID_2013_VSNTM2_REG] = (AW_PID_2013_REG_RD_ACCESS | AW_PID_2013_REG_WR_ACCESS), + [AW_PID_2013_ISNCTRL1_REG] = (AW_PID_2013_REG_RD_ACCESS | AW_PID_2013_REG_WR_ACCESS), + [AW_PID_2013_PLLCTRL1_REG] = (AW_PID_2013_REG_RD_ACCESS | AW_PID_2013_REG_WR_ACCESS), + [AW_PID_2013_PLLCTRL2_REG] = (AW_PID_2013_REG_RD_ACCESS | AW_PID_2013_REG_WR_ACCESS), + [AW_PID_2013_PLLCTRL3_REG] = (AW_PID_2013_REG_RD_ACCESS | AW_PID_2013_REG_WR_ACCESS), + [AW_PID_2013_CDACTRL1_REG] = (AW_PID_2013_REG_RD_ACCESS | AW_PID_2013_REG_WR_ACCESS), + [AW_PID_2013_CDACTRL2_REG] = (AW_PID_2013_REG_RD_ACCESS | AW_PID_2013_REG_WR_ACCESS), + [AW_PID_2013_SADCCTRL1_REG] = (AW_PID_2013_REG_RD_ACCESS | AW_PID_2013_REG_WR_ACCESS), + [AW_PID_2013_BSTCTRL1_REG] = (AW_PID_2013_REG_RD_ACCESS | AW_PID_2013_REG_WR_ACCESS), + [AW_PID_2013_BSTCTRL2_REG] = (AW_PID_2013_REG_RD_ACCESS | AW_PID_2013_REG_WR_ACCESS), + [AW_PID_2013_BSTCTRL3_REG] = (AW_PID_2013_REG_RD_ACCESS | AW_PID_2013_REG_WR_ACCESS), + [AW_PID_2013_BSTCTRL4_REG] = (AW_PID_2013_REG_RD_ACCESS | AW_PID_2013_REG_WR_ACCESS), + [AW_PID_2013_BSTCTRL5_REG] = (AW_PID_2013_REG_RD_ACCESS | AW_PID_2013_REG_WR_ACCESS), + [AW_PID_2013_BSTCTRL6_REG] = (AW_PID_2013_REG_RD_ACCESS | AW_PID_2013_REG_WR_ACCESS), + [AW_PID_2013_DSMCFG1_REG] = (AW_PID_2013_REG_RD_ACCESS | AW_PID_2013_REG_WR_ACCESS), + [AW_PID_2013_DSMCFG2_REG] = (AW_PID_2013_REG_RD_ACCESS | AW_PID_2013_REG_WR_ACCESS), + [AW_PID_2013_DSMCFG3_REG] = (AW_PID_2013_REG_RD_ACCESS | AW_PID_2013_REG_WR_ACCESS), + [AW_PID_2013_DSMCFG4_REG] = (AW_PID_2013_REG_RD_ACCESS | AW_PID_2013_REG_WR_ACCESS), + [AW_PID_2013_DSMCFG5_REG] = (AW_PID_2013_REG_RD_ACCESS | AW_PID_2013_REG_WR_ACCESS), + [AW_PID_2013_DSMCFG6_REG] = (AW_PID_2013_REG_RD_ACCESS | AW_PID_2013_REG_WR_ACCESS), + [AW_PID_2013_DSMCFG7_REG] = (AW_PID_2013_REG_RD_ACCESS | AW_PID_2013_REG_WR_ACCESS), + [AW_PID_2013_DSMCFG8_REG] = (AW_PID_2013_REG_RD_ACCESS | AW_PID_2013_REG_WR_ACCESS), + [AW_PID_2013_TESTCTRL1_REG] = (AW_PID_2013_REG_RD_ACCESS | AW_PID_2013_REG_WR_ACCESS), + [AW_PID_2013_TESTCTRL2_REG] = (AW_PID_2013_REG_RD_ACCESS | AW_PID_2013_REG_WR_ACCESS), + [AW_PID_2013_EFCTRL1_REG] = (AW_PID_2013_REG_RD_ACCESS | AW_PID_2013_REG_WR_ACCESS), + [AW_PID_2013_EFCTRL2_REG] = (AW_PID_2013_REG_RD_ACCESS | AW_PID_2013_REG_WR_ACCESS), + [AW_PID_2013_EFWH_REG] = (AW_PID_2013_REG_RD_ACCESS | AW_PID_2013_REG_WR_ACCESS), + [AW_PID_2013_EFWM2_REG] = (AW_PID_2013_REG_RD_ACCESS | AW_PID_2013_REG_WR_ACCESS), + [AW_PID_2013_EFWM1_REG] = (AW_PID_2013_REG_RD_ACCESS | AW_PID_2013_REG_WR_ACCESS), + [AW_PID_2013_EFWL_REG] = (AW_PID_2013_REG_RD_ACCESS | AW_PID_2013_REG_WR_ACCESS), + [AW_PID_2013_EFRH_REG] = (AW_PID_2013_REG_RD_ACCESS), + [AW_PID_2013_EFRM2_REG] = (AW_PID_2013_REG_RD_ACCESS), + [AW_PID_2013_EFRM1_REG] = (AW_PID_2013_REG_RD_ACCESS), + [AW_PID_2013_EFRL_REG] = (AW_PID_2013_REG_RD_ACCESS), + [AW_PID_2013_TM_REG] = (AW_PID_2013_REG_NONE_ACCESS), +}; + +/* detail information of registers begin */ +/* ID (0x00) detail */ +/* IDCODE bit 15:0 (ID 0x00) */ +#define AW_PID_2013_IDCODE_START_BIT (0) +#define AW_PID_2013_IDCODE_BITS_LEN (16) +#define AW_PID_2013_IDCODE_MASK \ + (~(((1< + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#ifndef __AW882XX_PID_2032_REG_H__ +#define __AW882XX_PID_2032_REG_H__ + +#define AW_PID_2032_MONITOR_FILE "aw882xx_pid_2032_monitor.bin" + +/* registers list */ +#define AW_PID_2032_ID_REG (0x00) +#define AW_PID_2032_SYSST_REG (0x01) +#define AW_PID_2032_SYSINT_REG (0x02) +#define AW_PID_2032_SYSINTM_REG (0x03) +#define AW_PID_2032_SYSCTRL_REG (0x04) +#define AW_PID_2032_SYSCTRL2_REG (0x05) +#define AW_PID_2032_I2SCTRL_REG (0x06) +#define AW_PID_2032_I2SCFG1_REG (0x07) +#define AW_PID_2032_I2SCFG2_REG (0x08) +#define AW_PID_2032_HAGCCFG1_REG (0x09) +#define AW_PID_2032_HAGCCFG2_REG (0x0A) +#define AW_PID_2032_HAGCCFG3_REG (0x0B) +#define AW_PID_2032_HAGCCFG4_REG (0x0C) +#define AW_PID_2032_HAGCCFG5_REG (0x0D) +#define AW_PID_2032_HAGCCFG6_REG (0x0E) +#define AW_PID_2032_HAGCCFG7_REG (0x0F) +#define AW_PID_2032_HAGCST_REG (0x10) +#define AW_PID_2032_PRODID_REG (0x11) +#define AW_PID_2032_VBAT_REG (0x12) +#define AW_PID_2032_TEMP_REG (0x13) +#define AW_PID_2032_PVDD_REG (0x14) +#define AW_PID_2032_HAGCCFG8_REG (0x15) +#define AW_PID_2032_DBGCTRL_REG (0x20) +#define AW_PID_2032_I2SINT_REG (0x21) +#define AW_PID_2032_I2SCAPCNT_REG (0x22) +#define AW_PID_2032_ANASTA1_REG (0x23) +#define AW_PID_2032_ANASTA2_REG (0x24) +#define AW_PID_2032_ANASTA3_REG (0x25) +#define AW_PID_2032_ANASTA4_REG (0x26) +#define AW_PID_2032_DSMCFG1_REG (0x30) +#define AW_PID_2032_DSMCFG2_REG (0x31) +#define AW_PID_2032_DSMCFG3_REG (0x32) +#define AW_PID_2032_DSMCFG4_REG (0x33) +#define AW_PID_2032_DSMCFG5_REG (0x34) +#define AW_PID_2032_DSMCFG6_REG (0x35) +#define AW_PID_2032_DSMCFG7_REG (0x36) +#define AW_PID_2032_DSMCFG8_REG (0x37) +#define AW_PID_2032_TESTIN_REG (0x38) +#define AW_PID_2032_TESTOUT_REG (0x39) +#define AW_PID_2032_VSNCTRL1_REG (0x50) +#define AW_PID_2032_ISNCTRL1_REG (0x52) +#define AW_PID_2032_ISNCTRL2_REG (0x53) +#define AW_PID_2032_VTMCTRL1_REG (0x54) +#define AW_PID_2032_VTMCTRL2_REG (0x55) +#define AW_PID_2032_VTMCTRL3_REG (0x56) +#define AW_PID_2032_ISNDAT_REG (0x57) +#define AW_PID_2032_VSNDAT_REG (0x58) +#define AW_PID_2032_PWMCTRL_REG (0x59) +#define AW_PID_2032_PWMCTRL2_REG (0x5A) +#define AW_PID_2032_BSTCTRL1_REG (0x60) +#define AW_PID_2032_BSTCTRL2_REG (0x61) +#define AW_PID_2032_BSTCTRL3_REG (0x62) +#define AW_PID_2032_BSTDBG1_REG (0x63) +#define AW_PID_2032_BSTDBG2_REG (0x64) +#define AW_PID_2032_BSTDBG3_REG (0x65) +#define AW_PID_2032_PLLCTRL1_REG (0x66) +#define AW_PID_2032_PLLCTRL2_REG (0x67) +#define AW_PID_2032_PLLCTRL3_REG (0x68) +#define AW_PID_2032_CDACTRL1_REG (0x69) +#define AW_PID_2032_CDACTRL2_REG (0x6A) +#define AW_PID_2032_SADCCTRL_REG (0x6B) +#define AW_PID_2032_BSTCTRL8_REG (0x6C) +#define AW_PID_2032_TESTCTRL1_REG (0x70) +#define AW_PID_2032_TESTCTRL2_REG (0x71) +#define AW_PID_2032_EFCTRL1_REG (0x72) +#define AW_PID_2032_EFCTRL2_REG (0x73) +#define AW_PID_2032_EFWH_REG (0x74) +#define AW_PID_2032_EFWM2_REG (0x75) +#define AW_PID_2032_EFWM1_REG (0x76) +#define AW_PID_2032_EFWL_REG (0x77) +#define AW_PID_2032_EFRH_REG (0x78) +#define AW_PID_2032_EFRM2_REG (0x79) +#define AW_PID_2032_EFRM1_REG (0x7A) +#define AW_PID_2032_EFRL_REG (0x7B) +#define AW_PID_2032_TESTDET_REG (0x7C) +#define AW_PID_2032_TM_REG (0x7D) + +/******************************************** + * Register Access + *******************************************/ +#define AW_PID_2032_REG_MAX (0x7E) + +#define AW_PID_2032_REG_NONE_ACCESS (0) +#define AW_PID_2032_REG_RD_ACCESS (1 << 0) +#define AW_PID_2032_REG_WR_ACCESS (1 << 1) + +const unsigned char aw_pid_2032_reg_access[AW_PID_2032_REG_MAX] = { + [AW_PID_2032_ID_REG] = (AW_PID_2032_REG_RD_ACCESS), + [AW_PID_2032_SYSST_REG] = (AW_PID_2032_REG_RD_ACCESS), + [AW_PID_2032_SYSINT_REG] = (AW_PID_2032_REG_RD_ACCESS), + [AW_PID_2032_SYSINTM_REG] = (AW_PID_2032_REG_RD_ACCESS | AW_PID_2032_REG_WR_ACCESS), + [AW_PID_2032_SYSCTRL_REG] = (AW_PID_2032_REG_RD_ACCESS | AW_PID_2032_REG_WR_ACCESS), + [AW_PID_2032_SYSCTRL2_REG] = (AW_PID_2032_REG_RD_ACCESS | AW_PID_2032_REG_WR_ACCESS), + [AW_PID_2032_I2SCTRL_REG] = (AW_PID_2032_REG_RD_ACCESS | AW_PID_2032_REG_WR_ACCESS), + [AW_PID_2032_I2SCFG1_REG] = (AW_PID_2032_REG_RD_ACCESS | AW_PID_2032_REG_WR_ACCESS), + [AW_PID_2032_I2SCFG2_REG] = (AW_PID_2032_REG_RD_ACCESS | AW_PID_2032_REG_WR_ACCESS), + [AW_PID_2032_HAGCCFG1_REG] = (AW_PID_2032_REG_RD_ACCESS | AW_PID_2032_REG_WR_ACCESS), + [AW_PID_2032_HAGCCFG2_REG] = (AW_PID_2032_REG_RD_ACCESS | AW_PID_2032_REG_WR_ACCESS), + [AW_PID_2032_HAGCCFG3_REG] = (AW_PID_2032_REG_RD_ACCESS | AW_PID_2032_REG_WR_ACCESS), + [AW_PID_2032_HAGCCFG4_REG] = (AW_PID_2032_REG_RD_ACCESS | AW_PID_2032_REG_WR_ACCESS), + [AW_PID_2032_HAGCCFG5_REG] = (AW_PID_2032_REG_RD_ACCESS | AW_PID_2032_REG_WR_ACCESS), + [AW_PID_2032_HAGCCFG6_REG] = (AW_PID_2032_REG_RD_ACCESS | AW_PID_2032_REG_WR_ACCESS), + [AW_PID_2032_HAGCCFG7_REG] = (AW_PID_2032_REG_RD_ACCESS | AW_PID_2032_REG_WR_ACCESS), + [AW_PID_2032_HAGCST_REG] = (AW_PID_2032_REG_RD_ACCESS), + [AW_PID_2032_PRODID_REG] = (AW_PID_2032_REG_RD_ACCESS), + [AW_PID_2032_VBAT_REG] = (AW_PID_2032_REG_RD_ACCESS), + [AW_PID_2032_TEMP_REG] = (AW_PID_2032_REG_RD_ACCESS), + [AW_PID_2032_PVDD_REG] = (AW_PID_2032_REG_RD_ACCESS), + [AW_PID_2032_HAGCCFG8_REG] = (AW_PID_2032_REG_RD_ACCESS | AW_PID_2032_REG_WR_ACCESS), + [AW_PID_2032_DBGCTRL_REG] = (AW_PID_2032_REG_RD_ACCESS | AW_PID_2032_REG_WR_ACCESS), + [AW_PID_2032_I2SINT_REG] = (AW_PID_2032_REG_RD_ACCESS), + [AW_PID_2032_I2SCAPCNT_REG] = (AW_PID_2032_REG_RD_ACCESS), + [AW_PID_2032_ANASTA1_REG] = (AW_PID_2032_REG_RD_ACCESS), + [AW_PID_2032_ANASTA2_REG] = (AW_PID_2032_REG_RD_ACCESS), + [AW_PID_2032_ANASTA3_REG] = (AW_PID_2032_REG_RD_ACCESS), + [AW_PID_2032_ANASTA4_REG] = (AW_PID_2032_REG_RD_ACCESS), + [AW_PID_2032_DSMCFG1_REG] = (AW_PID_2032_REG_RD_ACCESS | AW_PID_2032_REG_WR_ACCESS), + [AW_PID_2032_DSMCFG2_REG] = (AW_PID_2032_REG_RD_ACCESS | AW_PID_2032_REG_WR_ACCESS), + [AW_PID_2032_DSMCFG3_REG] = (AW_PID_2032_REG_RD_ACCESS | AW_PID_2032_REG_WR_ACCESS), + [AW_PID_2032_DSMCFG4_REG] = (AW_PID_2032_REG_RD_ACCESS | AW_PID_2032_REG_WR_ACCESS), + [AW_PID_2032_DSMCFG5_REG] = (AW_PID_2032_REG_RD_ACCESS | AW_PID_2032_REG_WR_ACCESS), + [AW_PID_2032_DSMCFG6_REG] = (AW_PID_2032_REG_RD_ACCESS | AW_PID_2032_REG_WR_ACCESS), + [AW_PID_2032_DSMCFG7_REG] = (AW_PID_2032_REG_RD_ACCESS | AW_PID_2032_REG_WR_ACCESS), + [AW_PID_2032_DSMCFG8_REG] = (AW_PID_2032_REG_RD_ACCESS | AW_PID_2032_REG_WR_ACCESS), + [AW_PID_2032_TESTIN_REG] = (AW_PID_2032_REG_RD_ACCESS | AW_PID_2032_REG_WR_ACCESS), + [AW_PID_2032_TESTOUT_REG] = (AW_PID_2032_REG_RD_ACCESS), + [AW_PID_2032_VSNCTRL1_REG] = (AW_PID_2032_REG_RD_ACCESS | AW_PID_2032_REG_WR_ACCESS), + [AW_PID_2032_ISNCTRL1_REG] = (AW_PID_2032_REG_RD_ACCESS | AW_PID_2032_REG_WR_ACCESS), + [AW_PID_2032_ISNCTRL2_REG] = (AW_PID_2032_REG_RD_ACCESS | AW_PID_2032_REG_WR_ACCESS), + [AW_PID_2032_VTMCTRL1_REG] = (AW_PID_2032_REG_RD_ACCESS | AW_PID_2032_REG_WR_ACCESS), + [AW_PID_2032_VTMCTRL2_REG] = (AW_PID_2032_REG_RD_ACCESS | AW_PID_2032_REG_WR_ACCESS), + [AW_PID_2032_VTMCTRL3_REG] = (AW_PID_2032_REG_RD_ACCESS | AW_PID_2032_REG_WR_ACCESS), + [AW_PID_2032_ISNDAT_REG] = (AW_PID_2032_REG_RD_ACCESS), + [AW_PID_2032_VSNDAT_REG] = (AW_PID_2032_REG_RD_ACCESS), + [AW_PID_2032_PWMCTRL_REG] = (AW_PID_2032_REG_RD_ACCESS | AW_PID_2032_REG_WR_ACCESS), + [AW_PID_2032_PWMCTRL2_REG] = (AW_PID_2032_REG_RD_ACCESS | AW_PID_2032_REG_WR_ACCESS), + [AW_PID_2032_BSTCTRL1_REG] = (AW_PID_2032_REG_RD_ACCESS | AW_PID_2032_REG_WR_ACCESS), + [AW_PID_2032_BSTCTRL2_REG] = (AW_PID_2032_REG_RD_ACCESS | AW_PID_2032_REG_WR_ACCESS), + [AW_PID_2032_BSTCTRL3_REG] = (AW_PID_2032_REG_RD_ACCESS | AW_PID_2032_REG_WR_ACCESS), + [AW_PID_2032_BSTDBG1_REG] = (AW_PID_2032_REG_RD_ACCESS | AW_PID_2032_REG_WR_ACCESS), + [AW_PID_2032_BSTDBG2_REG] = (AW_PID_2032_REG_RD_ACCESS | AW_PID_2032_REG_WR_ACCESS), + [AW_PID_2032_BSTDBG3_REG] = (AW_PID_2032_REG_RD_ACCESS | AW_PID_2032_REG_WR_ACCESS), + [AW_PID_2032_PLLCTRL1_REG] = (AW_PID_2032_REG_RD_ACCESS | AW_PID_2032_REG_WR_ACCESS), + [AW_PID_2032_PLLCTRL2_REG] = (AW_PID_2032_REG_RD_ACCESS | AW_PID_2032_REG_WR_ACCESS), + [AW_PID_2032_PLLCTRL3_REG] = (AW_PID_2032_REG_RD_ACCESS | AW_PID_2032_REG_WR_ACCESS), + [AW_PID_2032_CDACTRL1_REG] = (AW_PID_2032_REG_RD_ACCESS | AW_PID_2032_REG_WR_ACCESS), + [AW_PID_2032_CDACTRL2_REG] = (AW_PID_2032_REG_RD_ACCESS | AW_PID_2032_REG_WR_ACCESS), + [AW_PID_2032_SADCCTRL_REG] = (AW_PID_2032_REG_RD_ACCESS | AW_PID_2032_REG_WR_ACCESS), + [AW_PID_2032_BSTCTRL8_REG] = (AW_PID_2032_REG_RD_ACCESS | AW_PID_2032_REG_WR_ACCESS), + [AW_PID_2032_TESTCTRL1_REG] = (AW_PID_2032_REG_RD_ACCESS | AW_PID_2032_REG_WR_ACCESS), + [AW_PID_2032_TESTCTRL2_REG] = (AW_PID_2032_REG_RD_ACCESS | AW_PID_2032_REG_WR_ACCESS), + [AW_PID_2032_EFCTRL1_REG] = (AW_PID_2032_REG_RD_ACCESS | AW_PID_2032_REG_WR_ACCESS), + [AW_PID_2032_EFCTRL2_REG] = (AW_PID_2032_REG_RD_ACCESS | AW_PID_2032_REG_WR_ACCESS), + [AW_PID_2032_EFWH_REG] = (AW_PID_2032_REG_RD_ACCESS | AW_PID_2032_REG_WR_ACCESS), + [AW_PID_2032_EFWM2_REG] = (AW_PID_2032_REG_RD_ACCESS | AW_PID_2032_REG_WR_ACCESS), + [AW_PID_2032_EFWM1_REG] = (AW_PID_2032_REG_RD_ACCESS | AW_PID_2032_REG_WR_ACCESS), + [AW_PID_2032_EFWL_REG] = (AW_PID_2032_REG_RD_ACCESS | AW_PID_2032_REG_WR_ACCESS), + [AW_PID_2032_EFRH_REG] = (AW_PID_2032_REG_RD_ACCESS), + [AW_PID_2032_EFRM2_REG] = (AW_PID_2032_REG_RD_ACCESS), + [AW_PID_2032_EFRM1_REG] = (AW_PID_2032_REG_RD_ACCESS), + [AW_PID_2032_EFRL_REG] = (AW_PID_2032_REG_RD_ACCESS), + [AW_PID_2032_TESTDET_REG] = (AW_PID_2032_REG_RD_ACCESS), + [AW_PID_2032_TM_REG] = (AW_PID_2032_REG_NONE_ACCESS), +}; + +/* detail information of registers begin */ +/* ID (0x00) detail */ +/* IDCODE bit 15:0 (ID 0x00) */ +#define AW_PID_2032_IDCODE_START_BIT (0) +#define AW_PID_2032_IDCODE_BITS_LEN (16) +#define AW_PID_2032_IDCODE_MASK \ + (~(((1< + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#ifndef __AW882XX_PID_2055_REG_H__ +#define __AW882XX_PID_2055_REG_H__ + +#define AW_PID_2055_MONITOR_FILE "aw882xx_pid_2055_monitor.bin" + +/* registers list */ +#define AW_PID_2055_ID_REG (0x00) +#define AW_PID_2055_SYSST_REG (0x01) +#define AW_PID_2055_SYSINT_REG (0x02) +#define AW_PID_2055_SYSINTM_REG (0x03) +#define AW_PID_2055_SYSCTRL_REG (0x04) +#define AW_PID_2055_SYSCTRL2_REG (0x05) +#define AW_PID_2055_I2SCTRL1_REG (0x06) +#define AW_PID_2055_I2SCTRL2_REG (0x07) +#define AW_PID_2055_I2SCTRL3_REG (0x08) +#define AW_PID_2055_DACCFG1_REG (0x09) +#define AW_PID_2055_DACCFG2_REG (0x0A) +#define AW_PID_2055_DACCFG3_REG (0x0B) +#define AW_PID_2055_DACCFG4_REG (0x0C) +#define AW_PID_2055_DACCFG5_REG (0x0D) +#define AW_PID_2055_DACCFG6_REG (0x0E) +#define AW_PID_2055_DACCFG7_REG (0x0F) +#define AW_PID_2055_DACCFG8_REG (0x10) +#define AW_PID_2055_PWMCTRL1_REG (0x11) +#define AW_PID_2055_PWMCTRL2_REG (0x12) +#define AW_PID_2055_PWMCTRL3_REG (0x13) +#define AW_PID_2055_PWMCTRL4_REG (0x14) +#define AW_PID_2055_PWMCTRL5_REG (0x15) +#define AW_PID_2055_I2SCFG1_REG (0x16) +#define AW_PID_2055_DBGCTRL_REG (0x17) +#define AW_PID_2055_DITHERCFG1_REG (0x18) +#define AW_PID_2055_DACST_REG (0x20) +#define AW_PID_2055_VBAT_REG (0x21) +#define AW_PID_2055_TEMP_REG (0x22) +#define AW_PID_2055_PVDD_REG (0x23) +#define AW_PID_2055_BOPST_REG (0x24) +#define AW_PID_2055_I2SINT_REG (0x25) +#define AW_PID_2055_I2SCAPCNT_REG (0x26) +#define AW_PID_2055_ANASTA1_REG (0x27) +#define AW_PID_2055_ANASTA2_REG (0x28) +#define AW_PID_2055_ANASTA3_REG (0x29) +#define AW_PID_2055_DSMCFG1_REG (0x30) +#define AW_PID_2055_DSMCFG2_REG (0x31) +#define AW_PID_2055_DSMCFG3_REG (0x32) +#define AW_PID_2055_DSMCFG4_REG (0x33) +#define AW_PID_2055_DSMCFG5_REG (0x34) +#define AW_PID_2055_DSMCFG6_REG (0x35) +#define AW_PID_2055_DSMCFG7_REG (0x36) +#define AW_PID_2055_DSMCFG8_REG (0x37) +#define AW_PID_2055_TESTIN_REG (0x38) +#define AW_PID_2055_TESTOUT_REG (0x39) +#define AW_PID_2055_SADCCTRL1_REG (0x3A) +#define AW_PID_2055_SADCCTRL2_REG (0x3B) +#define AW_PID_2055_SADCCTRL3_REG (0x3C) +#define AW_PID_2055_SADCCTRL4_REG (0x3D) +#define AW_PID_2055_SADCCTRL5_REG (0x3E) +#define AW_PID_2055_SADCCTRL6_REG (0x3F) +#define AW_PID_2055_PLLCTRL1_REG (0x50) +#define AW_PID_2055_PLLCTRL2_REG (0x51) +#define AW_PID_2055_PLLCTRL3_REG (0x52) +#define AW_PID_2055_CDACTRL1_REG (0x53) +#define AW_PID_2055_CDACTRL2_REG (0x54) +#define AW_PID_2055_CDACTRL3_REG (0x55) +#define AW_PID_2055_BSTCTRL1_REG (0x60) +#define AW_PID_2055_BSTCTRL2_REG (0x61) +#define AW_PID_2055_BSTCTRL3_REG (0x62) +#define AW_PID_2055_BSTCTRL4_REG (0x63) +#define AW_PID_2055_BSTCTRL5_REG (0x64) +#define AW_PID_2055_BSTCTRL6_REG (0x65) +#define AW_PID_2055_BSTCTRL7_REG (0x66) +#define AW_PID_2055_BSTCTRL8_REG (0x67) +#define AW_PID_2055_CPCTRL1_REG (0x68) +#define AW_PID_2055_TESTCTRL1_REG (0x70) +#define AW_PID_2055_TESTCTRL2_REG (0x71) +#define AW_PID_2055_EFCTRL1_REG (0x72) +#define AW_PID_2055_EFCTRL2_REG (0x73) +#define AW_PID_2055_EFWH_REG (0x74) +#define AW_PID_2055_EFWL_REG (0x75) +#define AW_PID_2055_EFRH2_REG (0x76) +#define AW_PID_2055_EFRL2_REG (0x77) +#define AW_PID_2055_EFRH1_REG (0x78) +#define AW_PID_2055_EFRL1_REG (0x79) +#define AW_PID_2055_TM_REG (0x7C) + +/******************************************** + * Register Access + *******************************************/ +#define AW_PID_2055_REG_MAX (0x7D) + +#define AW_PID_2055_REG_NONE_ACCESS (0) +#define AW_PID_2055_REG_RD_ACCESS (1 << 0) +#define AW_PID_2055_REG_WR_ACCESS (1 << 1) + +const unsigned char aw_pid_2055_reg_access[AW_PID_2055_REG_MAX] = { + [AW_PID_2055_ID_REG] = (AW_PID_2055_REG_RD_ACCESS), + [AW_PID_2055_SYSST_REG] = (AW_PID_2055_REG_RD_ACCESS), + [AW_PID_2055_SYSINT_REG] = (AW_PID_2055_REG_RD_ACCESS), + [AW_PID_2055_SYSINTM_REG] = (AW_PID_2055_REG_RD_ACCESS | AW_PID_2055_REG_WR_ACCESS), + [AW_PID_2055_SYSCTRL_REG] = (AW_PID_2055_REG_RD_ACCESS | AW_PID_2055_REG_WR_ACCESS), + [AW_PID_2055_SYSCTRL2_REG] = (AW_PID_2055_REG_RD_ACCESS | AW_PID_2055_REG_WR_ACCESS), + [AW_PID_2055_I2SCTRL1_REG] = (AW_PID_2055_REG_RD_ACCESS | AW_PID_2055_REG_WR_ACCESS), + [AW_PID_2055_I2SCTRL2_REG] = (AW_PID_2055_REG_RD_ACCESS | AW_PID_2055_REG_WR_ACCESS), + [AW_PID_2055_I2SCTRL3_REG] = (AW_PID_2055_REG_RD_ACCESS | AW_PID_2055_REG_WR_ACCESS), + [AW_PID_2055_DACCFG1_REG] = (AW_PID_2055_REG_RD_ACCESS | AW_PID_2055_REG_WR_ACCESS), + [AW_PID_2055_DACCFG2_REG] = (AW_PID_2055_REG_RD_ACCESS | AW_PID_2055_REG_WR_ACCESS), + [AW_PID_2055_DACCFG3_REG] = (AW_PID_2055_REG_RD_ACCESS | AW_PID_2055_REG_WR_ACCESS), + [AW_PID_2055_DACCFG4_REG] = (AW_PID_2055_REG_RD_ACCESS | AW_PID_2055_REG_WR_ACCESS), + [AW_PID_2055_DACCFG5_REG] = (AW_PID_2055_REG_RD_ACCESS | AW_PID_2055_REG_WR_ACCESS), + [AW_PID_2055_DACCFG6_REG] = (AW_PID_2055_REG_RD_ACCESS | AW_PID_2055_REG_WR_ACCESS), + [AW_PID_2055_DACCFG7_REG] = (AW_PID_2055_REG_RD_ACCESS | AW_PID_2055_REG_WR_ACCESS), + [AW_PID_2055_DACCFG8_REG] = (AW_PID_2055_REG_RD_ACCESS | AW_PID_2055_REG_WR_ACCESS), + [AW_PID_2055_PWMCTRL1_REG] = (AW_PID_2055_REG_RD_ACCESS | AW_PID_2055_REG_WR_ACCESS), + [AW_PID_2055_PWMCTRL2_REG] = (AW_PID_2055_REG_RD_ACCESS | AW_PID_2055_REG_WR_ACCESS), + [AW_PID_2055_PWMCTRL3_REG] = (AW_PID_2055_REG_RD_ACCESS | AW_PID_2055_REG_WR_ACCESS), + [AW_PID_2055_PWMCTRL4_REG] = (AW_PID_2055_REG_RD_ACCESS | AW_PID_2055_REG_WR_ACCESS), + [AW_PID_2055_PWMCTRL5_REG] = (AW_PID_2055_REG_RD_ACCESS | AW_PID_2055_REG_WR_ACCESS), + [AW_PID_2055_I2SCFG1_REG] = (AW_PID_2055_REG_RD_ACCESS | AW_PID_2055_REG_WR_ACCESS), + [AW_PID_2055_DBGCTRL_REG] = (AW_PID_2055_REG_RD_ACCESS | AW_PID_2055_REG_WR_ACCESS), + [AW_PID_2055_DITHERCFG1_REG] = (AW_PID_2055_REG_RD_ACCESS | AW_PID_2055_REG_WR_ACCESS), + [AW_PID_2055_DACST_REG] = (AW_PID_2055_REG_RD_ACCESS), + [AW_PID_2055_VBAT_REG] = (AW_PID_2055_REG_RD_ACCESS), + [AW_PID_2055_TEMP_REG] = (AW_PID_2055_REG_RD_ACCESS), + [AW_PID_2055_PVDD_REG] = (AW_PID_2055_REG_RD_ACCESS), + [AW_PID_2055_BOPST_REG] = (AW_PID_2055_REG_RD_ACCESS), + [AW_PID_2055_I2SINT_REG] = (AW_PID_2055_REG_RD_ACCESS), + [AW_PID_2055_I2SCAPCNT_REG] = (AW_PID_2055_REG_RD_ACCESS), + [AW_PID_2055_ANASTA1_REG] = (AW_PID_2055_REG_RD_ACCESS), + [AW_PID_2055_ANASTA2_REG] = (AW_PID_2055_REG_RD_ACCESS), + [AW_PID_2055_ANASTA3_REG] = (AW_PID_2055_REG_RD_ACCESS), + [AW_PID_2055_DSMCFG1_REG] = (AW_PID_2055_REG_RD_ACCESS | AW_PID_2055_REG_WR_ACCESS), + [AW_PID_2055_DSMCFG2_REG] = (AW_PID_2055_REG_RD_ACCESS | AW_PID_2055_REG_WR_ACCESS), + [AW_PID_2055_DSMCFG3_REG] = (AW_PID_2055_REG_RD_ACCESS | AW_PID_2055_REG_WR_ACCESS), + [AW_PID_2055_DSMCFG4_REG] = (AW_PID_2055_REG_RD_ACCESS | AW_PID_2055_REG_WR_ACCESS), + [AW_PID_2055_DSMCFG5_REG] = (AW_PID_2055_REG_RD_ACCESS | AW_PID_2055_REG_WR_ACCESS), + [AW_PID_2055_DSMCFG6_REG] = (AW_PID_2055_REG_RD_ACCESS | AW_PID_2055_REG_WR_ACCESS), + [AW_PID_2055_DSMCFG7_REG] = (AW_PID_2055_REG_RD_ACCESS | AW_PID_2055_REG_WR_ACCESS), + [AW_PID_2055_DSMCFG8_REG] = (AW_PID_2055_REG_RD_ACCESS | AW_PID_2055_REG_WR_ACCESS), + [AW_PID_2055_TESTIN_REG] = (AW_PID_2055_REG_RD_ACCESS | AW_PID_2055_REG_WR_ACCESS), + [AW_PID_2055_TESTOUT_REG] = (AW_PID_2055_REG_RD_ACCESS), + [AW_PID_2055_SADCCTRL1_REG] = (AW_PID_2055_REG_RD_ACCESS | AW_PID_2055_REG_WR_ACCESS), + [AW_PID_2055_SADCCTRL2_REG] = (AW_PID_2055_REG_RD_ACCESS | AW_PID_2055_REG_WR_ACCESS), + [AW_PID_2055_SADCCTRL3_REG] = (AW_PID_2055_REG_RD_ACCESS | AW_PID_2055_REG_WR_ACCESS), + [AW_PID_2055_SADCCTRL4_REG] = (AW_PID_2055_REG_RD_ACCESS | AW_PID_2055_REG_WR_ACCESS), + [AW_PID_2055_SADCCTRL5_REG] = (AW_PID_2055_REG_RD_ACCESS | AW_PID_2055_REG_WR_ACCESS), + [AW_PID_2055_SADCCTRL6_REG] = (AW_PID_2055_REG_RD_ACCESS | AW_PID_2055_REG_WR_ACCESS), + [AW_PID_2055_PLLCTRL1_REG] = (AW_PID_2055_REG_RD_ACCESS | AW_PID_2055_REG_WR_ACCESS), + [AW_PID_2055_PLLCTRL2_REG] = (AW_PID_2055_REG_RD_ACCESS | AW_PID_2055_REG_WR_ACCESS), + [AW_PID_2055_PLLCTRL3_REG] = (AW_PID_2055_REG_RD_ACCESS | AW_PID_2055_REG_WR_ACCESS), + [AW_PID_2055_CDACTRL1_REG] = (AW_PID_2055_REG_RD_ACCESS | AW_PID_2055_REG_WR_ACCESS), + [AW_PID_2055_CDACTRL2_REG] = (AW_PID_2055_REG_RD_ACCESS | AW_PID_2055_REG_WR_ACCESS), + [AW_PID_2055_CDACTRL3_REG] = (AW_PID_2055_REG_RD_ACCESS | AW_PID_2055_REG_WR_ACCESS), + [AW_PID_2055_BSTCTRL1_REG] = (AW_PID_2055_REG_RD_ACCESS | AW_PID_2055_REG_WR_ACCESS), + [AW_PID_2055_BSTCTRL2_REG] = (AW_PID_2055_REG_RD_ACCESS | AW_PID_2055_REG_WR_ACCESS), + [AW_PID_2055_BSTCTRL3_REG] = (AW_PID_2055_REG_RD_ACCESS | AW_PID_2055_REG_WR_ACCESS), + [AW_PID_2055_BSTCTRL4_REG] = (AW_PID_2055_REG_RD_ACCESS | AW_PID_2055_REG_WR_ACCESS), + [AW_PID_2055_BSTCTRL5_REG] = (AW_PID_2055_REG_RD_ACCESS | AW_PID_2055_REG_WR_ACCESS), + [AW_PID_2055_BSTCTRL6_REG] = (AW_PID_2055_REG_RD_ACCESS | AW_PID_2055_REG_WR_ACCESS), + [AW_PID_2055_BSTCTRL7_REG] = (AW_PID_2055_REG_RD_ACCESS | AW_PID_2055_REG_WR_ACCESS), + [AW_PID_2055_BSTCTRL8_REG] = (AW_PID_2055_REG_RD_ACCESS | AW_PID_2055_REG_WR_ACCESS), + [AW_PID_2055_CPCTRL1_REG] = (AW_PID_2055_REG_RD_ACCESS | AW_PID_2055_REG_WR_ACCESS), + [AW_PID_2055_TESTCTRL1_REG] = (AW_PID_2055_REG_RD_ACCESS | AW_PID_2055_REG_WR_ACCESS), + [AW_PID_2055_TESTCTRL2_REG] = (AW_PID_2055_REG_RD_ACCESS | AW_PID_2055_REG_WR_ACCESS), + [AW_PID_2055_EFCTRL1_REG] = (AW_PID_2055_REG_RD_ACCESS | AW_PID_2055_REG_WR_ACCESS), + [AW_PID_2055_EFCTRL2_REG] = (AW_PID_2055_REG_RD_ACCESS | AW_PID_2055_REG_WR_ACCESS), + [AW_PID_2055_EFWH_REG] = (AW_PID_2055_REG_RD_ACCESS | AW_PID_2055_REG_WR_ACCESS), + [AW_PID_2055_EFWL_REG] = (AW_PID_2055_REG_RD_ACCESS | AW_PID_2055_REG_WR_ACCESS), + [AW_PID_2055_EFRH2_REG] = (AW_PID_2055_REG_RD_ACCESS), + [AW_PID_2055_EFRL2_REG] = (AW_PID_2055_REG_RD_ACCESS), + [AW_PID_2055_EFRH1_REG] = (AW_PID_2055_REG_RD_ACCESS), + [AW_PID_2055_EFRL1_REG] = (AW_PID_2055_REG_RD_ACCESS), + [AW_PID_2055_TM_REG] = (AW_PID_2055_REG_NONE_ACCESS), +}; + +/* detail information of registers begin */ +/* ID (0x00) detail */ +/* IDCODE bit 15:0 (ID 0x00) */ +#define AW_PID_2055_IDCODE_START_BIT (0) +#define AW_PID_2055_IDCODE_BITS_LEN (16) +#define AW_PID_2055_IDCODE_MASK \ + (~(((1< + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#ifndef __AW882XX_PID_2055A_REG_H__ +#define __AW882XX_PID_2055A_REG_H__ + +#define AW_PID_2055A_MONITOR_FILE "aw882xx_pid_2055a_monitor.bin" + +/* registers list */ +#define AW_PID_2055A_ID_REG (0x00) +#define AW_PID_2055A_SYSST_REG (0x01) +#define AW_PID_2055A_SYSINT_REG (0x02) +#define AW_PID_2055A_SYSINTM_REG (0x03) +#define AW_PID_2055A_SYSCTRL_REG (0x04) +#define AW_PID_2055A_SYSCTRL2_REG (0x05) +#define AW_PID_2055A_I2SCTRL1_REG (0x06) +#define AW_PID_2055A_I2SCTRL2_REG (0x07) +#define AW_PID_2055A_DACCFG1_REG (0x08) +#define AW_PID_2055A_DACCFG2_REG (0x09) +#define AW_PID_2055A_DACCFG3_REG (0x0A) +#define AW_PID_2055A_DACCFG4_REG (0x0B) +#define AW_PID_2055A_DACCFG5_REG (0x0C) +#define AW_PID_2055A_DACCFG6_REG (0x0D) +#define AW_PID_2055A_DACCFG7_REG (0x0E) +#define AW_PID_2055A_DACCFG8_REG (0x0F) +#define AW_PID_2055A_PWMCTRL1_REG (0x10) +#define AW_PID_2055A_PWMCTRL2_REG (0x11) +#define AW_PID_2055A_PWMCTRL3_REG (0x12) +#define AW_PID_2055A_I2SCFG1_REG (0x13) +#define AW_PID_2055A_DBGCTRL_REG (0x14) +#define AW_PID_2055A_DITHERCFG1_REG (0x15) +#define AW_PID_2055A_DITHERCFG2_REG (0x16) +#define AW_PID_2055A_DITHERCFG3_REG (0x17) +#define AW_PID_2055A_DACST_REG (0x20) +#define AW_PID_2055A_I2SINT_REG (0x21) +#define AW_PID_2055A_I2SCAPCNT_REG (0x22) +#define AW_PID_2055A_ANASTA1_REG (0x23) +#define AW_PID_2055A_ANASTA2_REG (0x24) +#define AW_PID_2055A_ANASTA3_REG (0x25) +#define AW_PID_2055A_DSMCFG1_REG (0x30) +#define AW_PID_2055A_DSMCFG2_REG (0x31) +#define AW_PID_2055A_DSMCFG3_REG (0x32) +#define AW_PID_2055A_DSMCFG4_REG (0x33) +#define AW_PID_2055A_DSMCFG5_REG (0x34) +#define AW_PID_2055A_DSMCFG6_REG (0x35) +#define AW_PID_2055A_DSMCFG7_REG (0x36) +#define AW_PID_2055A_DSMCFG8_REG (0x37) +#define AW_PID_2055A_TESTIN_REG (0x38) +#define AW_PID_2055A_TESTOUT_REG (0x39) +#define AW_PID_2055A_PLLCTRL1_REG (0x50) +#define AW_PID_2055A_PLLCTRL2_REG (0x51) +#define AW_PID_2055A_PLLCTRL3_REG (0x52) +#define AW_PID_2055A_CDACTRL1_REG (0x53) +#define AW_PID_2055A_CDACTRL2_REG (0x54) +#define AW_PID_2055A_BSTCTRL1_REG (0x60) +#define AW_PID_2055A_BSTCTRL2_REG (0x61) +#define AW_PID_2055A_BSTCTRL3_REG (0x62) +#define AW_PID_2055A_BSTCTRL4_REG (0x63) +#define AW_PID_2055A_BSTCTRL5_REG (0x64) +#define AW_PID_2055A_BSTCTRL6_REG (0x65) +#define AW_PID_2055A_BSTCTRL7_REG (0x66) +#define AW_PID_2055A_BSTCRTL8_REG (0x67) +#define AW_PID_2055A_CPCTRL1_REG (0x68) +#define AW_PID_2055A_TESTCTRL1_REG (0x70) +#define AW_PID_2055A_TESTCTRL2_REG (0x71) +#define AW_PID_2055A_EFCTRL1_REG (0x72) +#define AW_PID_2055A_EFCTRL2_REG (0x73) +#define AW_PID_2055A_EFWH_REG (0x74) +#define AW_PID_2055A_EFWL_REG (0x75) +#define AW_PID_2055A_EFRH1_REG (0x76) +#define AW_PID_2055A_EFRH2_REG (0x77) +#define AW_PID_2055A_EFRL1_REG (0x78) +#define AW_PID_2055A_EFRL2_REG (0x79) +#define AW_PID_2055A_TM_REG (0x7C) + +/******************************************** + * Register Access + *******************************************/ +#define AW_PID_2055A_REG_MAX (0x7D) + +#define AW_PID_2055A_REG_NONE_ACCESS (0) +#define AW_PID_2055A_REG_RD_ACCESS (1 << 0) +#define AW_PID_2055A_REG_WR_ACCESS (1 << 1) + +const unsigned char aw_pid_2055a_reg_access[AW_PID_2055A_REG_MAX] = { + [AW_PID_2055A_ID_REG] = (AW_PID_2055A_REG_RD_ACCESS), + [AW_PID_2055A_SYSST_REG] = (AW_PID_2055A_REG_RD_ACCESS), + [AW_PID_2055A_SYSINT_REG] = (AW_PID_2055A_REG_RD_ACCESS), + [AW_PID_2055A_SYSINTM_REG] = (AW_PID_2055A_REG_RD_ACCESS | AW_PID_2055A_REG_WR_ACCESS), + [AW_PID_2055A_SYSCTRL_REG] = (AW_PID_2055A_REG_RD_ACCESS | AW_PID_2055A_REG_WR_ACCESS), + [AW_PID_2055A_SYSCTRL2_REG] = (AW_PID_2055A_REG_RD_ACCESS | AW_PID_2055A_REG_WR_ACCESS), + [AW_PID_2055A_I2SCTRL1_REG] = (AW_PID_2055A_REG_RD_ACCESS | AW_PID_2055A_REG_WR_ACCESS), + [AW_PID_2055A_I2SCTRL2_REG] = (AW_PID_2055A_REG_RD_ACCESS | AW_PID_2055A_REG_WR_ACCESS), + [AW_PID_2055A_DACCFG1_REG] = (AW_PID_2055A_REG_RD_ACCESS | AW_PID_2055A_REG_WR_ACCESS), + [AW_PID_2055A_DACCFG2_REG] = (AW_PID_2055A_REG_RD_ACCESS | AW_PID_2055A_REG_WR_ACCESS), + [AW_PID_2055A_DACCFG3_REG] = (AW_PID_2055A_REG_RD_ACCESS | AW_PID_2055A_REG_WR_ACCESS), + [AW_PID_2055A_DACCFG4_REG] = (AW_PID_2055A_REG_RD_ACCESS | AW_PID_2055A_REG_WR_ACCESS), + [AW_PID_2055A_DACCFG5_REG] = (AW_PID_2055A_REG_RD_ACCESS | AW_PID_2055A_REG_WR_ACCESS), + [AW_PID_2055A_DACCFG6_REG] = (AW_PID_2055A_REG_RD_ACCESS | AW_PID_2055A_REG_WR_ACCESS), + [AW_PID_2055A_DACCFG7_REG] = (AW_PID_2055A_REG_RD_ACCESS | AW_PID_2055A_REG_WR_ACCESS), + [AW_PID_2055A_DACCFG8_REG] = (AW_PID_2055A_REG_RD_ACCESS | AW_PID_2055A_REG_WR_ACCESS), + [AW_PID_2055A_PWMCTRL1_REG] = (AW_PID_2055A_REG_RD_ACCESS | AW_PID_2055A_REG_WR_ACCESS), + [AW_PID_2055A_PWMCTRL2_REG] = (AW_PID_2055A_REG_RD_ACCESS | AW_PID_2055A_REG_WR_ACCESS), + [AW_PID_2055A_PWMCTRL3_REG] = (AW_PID_2055A_REG_RD_ACCESS | AW_PID_2055A_REG_WR_ACCESS), + [AW_PID_2055A_I2SCFG1_REG] = (AW_PID_2055A_REG_RD_ACCESS | AW_PID_2055A_REG_WR_ACCESS), + [AW_PID_2055A_DBGCTRL_REG] = (AW_PID_2055A_REG_RD_ACCESS | AW_PID_2055A_REG_WR_ACCESS), + [AW_PID_2055A_DITHERCFG1_REG] = (AW_PID_2055A_REG_RD_ACCESS | AW_PID_2055A_REG_WR_ACCESS), + [AW_PID_2055A_DITHERCFG2_REG] = (AW_PID_2055A_REG_RD_ACCESS | AW_PID_2055A_REG_WR_ACCESS), + [AW_PID_2055A_DITHERCFG3_REG] = (AW_PID_2055A_REG_RD_ACCESS | AW_PID_2055A_REG_WR_ACCESS), + [AW_PID_2055A_DACST_REG] = (AW_PID_2055A_REG_RD_ACCESS), + [AW_PID_2055A_I2SINT_REG] = (AW_PID_2055A_REG_RD_ACCESS), + [AW_PID_2055A_I2SCAPCNT_REG] = (AW_PID_2055A_REG_RD_ACCESS), + [AW_PID_2055A_ANASTA1_REG] = (AW_PID_2055A_REG_RD_ACCESS), + [AW_PID_2055A_ANASTA2_REG] = (AW_PID_2055A_REG_RD_ACCESS), + [AW_PID_2055A_ANASTA3_REG] = (AW_PID_2055A_REG_RD_ACCESS), + [AW_PID_2055A_DSMCFG1_REG] = (AW_PID_2055A_REG_RD_ACCESS | AW_PID_2055A_REG_WR_ACCESS), + [AW_PID_2055A_DSMCFG2_REG] = (AW_PID_2055A_REG_RD_ACCESS | AW_PID_2055A_REG_WR_ACCESS), + [AW_PID_2055A_DSMCFG3_REG] = (AW_PID_2055A_REG_RD_ACCESS | AW_PID_2055A_REG_WR_ACCESS), + [AW_PID_2055A_DSMCFG4_REG] = (AW_PID_2055A_REG_RD_ACCESS | AW_PID_2055A_REG_WR_ACCESS), + [AW_PID_2055A_DSMCFG5_REG] = (AW_PID_2055A_REG_RD_ACCESS | AW_PID_2055A_REG_WR_ACCESS), + [AW_PID_2055A_DSMCFG6_REG] = (AW_PID_2055A_REG_RD_ACCESS | AW_PID_2055A_REG_WR_ACCESS), + [AW_PID_2055A_DSMCFG7_REG] = (AW_PID_2055A_REG_RD_ACCESS | AW_PID_2055A_REG_WR_ACCESS), + [AW_PID_2055A_DSMCFG8_REG] = (AW_PID_2055A_REG_RD_ACCESS | AW_PID_2055A_REG_WR_ACCESS), + [AW_PID_2055A_TESTIN_REG] = (AW_PID_2055A_REG_RD_ACCESS | AW_PID_2055A_REG_WR_ACCESS), + [AW_PID_2055A_TESTOUT_REG] = (AW_PID_2055A_REG_RD_ACCESS), + [AW_PID_2055A_PLLCTRL1_REG] = (AW_PID_2055A_REG_RD_ACCESS | AW_PID_2055A_REG_WR_ACCESS), + [AW_PID_2055A_PLLCTRL2_REG] = (AW_PID_2055A_REG_RD_ACCESS | AW_PID_2055A_REG_WR_ACCESS), + [AW_PID_2055A_PLLCTRL3_REG] = (AW_PID_2055A_REG_RD_ACCESS | AW_PID_2055A_REG_WR_ACCESS), + [AW_PID_2055A_CDACTRL1_REG] = (AW_PID_2055A_REG_RD_ACCESS | AW_PID_2055A_REG_WR_ACCESS), + [AW_PID_2055A_CDACTRL2_REG] = (AW_PID_2055A_REG_RD_ACCESS | AW_PID_2055A_REG_WR_ACCESS), + [AW_PID_2055A_BSTCTRL1_REG] = (AW_PID_2055A_REG_RD_ACCESS | AW_PID_2055A_REG_WR_ACCESS), + [AW_PID_2055A_BSTCTRL2_REG] = (AW_PID_2055A_REG_RD_ACCESS | AW_PID_2055A_REG_WR_ACCESS), + [AW_PID_2055A_BSTCTRL3_REG] = (AW_PID_2055A_REG_RD_ACCESS | AW_PID_2055A_REG_WR_ACCESS), + [AW_PID_2055A_BSTCTRL4_REG] = (AW_PID_2055A_REG_RD_ACCESS | AW_PID_2055A_REG_WR_ACCESS), + [AW_PID_2055A_BSTCTRL5_REG] = (AW_PID_2055A_REG_RD_ACCESS | AW_PID_2055A_REG_WR_ACCESS), + [AW_PID_2055A_BSTCTRL6_REG] = (AW_PID_2055A_REG_RD_ACCESS | AW_PID_2055A_REG_WR_ACCESS), + [AW_PID_2055A_BSTCTRL7_REG] = (AW_PID_2055A_REG_RD_ACCESS | AW_PID_2055A_REG_WR_ACCESS), + [AW_PID_2055A_BSTCRTL8_REG] = (AW_PID_2055A_REG_RD_ACCESS | AW_PID_2055A_REG_WR_ACCESS), + [AW_PID_2055A_CPCTRL1_REG] = (AW_PID_2055A_REG_RD_ACCESS | AW_PID_2055A_REG_WR_ACCESS), + [AW_PID_2055A_TESTCTRL1_REG] = (AW_PID_2055A_REG_RD_ACCESS | AW_PID_2055A_REG_WR_ACCESS), + [AW_PID_2055A_TESTCTRL2_REG] = (AW_PID_2055A_REG_RD_ACCESS | AW_PID_2055A_REG_WR_ACCESS), + [AW_PID_2055A_EFCTRL1_REG] = (AW_PID_2055A_REG_RD_ACCESS | AW_PID_2055A_REG_WR_ACCESS), + [AW_PID_2055A_EFCTRL2_REG] = (AW_PID_2055A_REG_RD_ACCESS | AW_PID_2055A_REG_WR_ACCESS), + [AW_PID_2055A_EFWH_REG] = (AW_PID_2055A_REG_RD_ACCESS | AW_PID_2055A_REG_WR_ACCESS), + [AW_PID_2055A_EFWL_REG] = (AW_PID_2055A_REG_RD_ACCESS | AW_PID_2055A_REG_WR_ACCESS), + [AW_PID_2055A_EFRH1_REG] = (AW_PID_2055A_REG_RD_ACCESS), + [AW_PID_2055A_EFRH2_REG] = (AW_PID_2055A_REG_RD_ACCESS), + [AW_PID_2055A_EFRL1_REG] = (AW_PID_2055A_REG_RD_ACCESS), + [AW_PID_2055A_EFRL2_REG] = (AW_PID_2055A_REG_RD_ACCESS), + [AW_PID_2055A_TM_REG] = (AW_PID_2055A_REG_NONE_ACCESS), +}; + +/* detail information of registers begin */ +/* ID (0x00) detail */ +/* IDCODE bit 15:0 (ID 0x00) */ +#define AW_PID_2055A_IDCODE_START_BIT (0) +#define AW_PID_2055A_IDCODE_BITS_LEN (16) +#define AW_PID_2055A_IDCODE_MASK \ + (~(((1< + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#ifndef __AW882XX_PID_2071_REG_H__ +#define __AW882XX_PID_2071_REG_H__ + +#define AW_PID_2071_MONITOR_FILE "aw882xx_pid_2071_monitor.bin" + +/* registers list */ +#define AW_PID_2071_ID_REG (0x00) +#define AW_PID_2071_SYSST_REG (0x01) +#define AW_PID_2071_SYSINT_REG (0x02) +#define AW_PID_2071_SYSINTM_REG (0x03) +#define AW_PID_2071_SYSCTRL_REG (0x04) +#define AW_PID_2071_SYSCTRL2_REG (0x05) +#define AW_PID_2071_I2SCTRL_REG (0x06) +#define AW_PID_2071_I2SCFG1_REG (0x07) +#define AW_PID_2071_I2SCFG2_REG (0x08) +#define AW_PID_2071_HAGCCFG1_REG (0x09) +#define AW_PID_2071_HAGCCFG2_REG (0x0A) +#define AW_PID_2071_HAGCCFG3_REG (0x0B) +#define AW_PID_2071_HAGCCFG4_REG (0x0C) +#define AW_PID_2071_HAGCCFG5_REG (0x0D) +#define AW_PID_2071_HAGCCFG6_REG (0x0E) +#define AW_PID_2071_HAGCCFG7_REG (0x0F) +#define AW_PID_2071_HAGCST_REG (0x10) +#define AW_PID_2071_PRODID_REG (0x11) +#define AW_PID_2071_VBAT_REG (0x12) +#define AW_PID_2071_TEMP_REG (0x13) +#define AW_PID_2071_PVDD_REG (0x14) +#define AW_PID_2071_HAGCCFG8_REG (0x15) +#define AW_PID_2071_DBGCTRL_REG (0x20) +#define AW_PID_2071_I2SINT_REG (0x21) +#define AW_PID_2071_I2SCAPCNT_REG (0x22) +#define AW_PID_2071_ANASTA1_REG (0x23) +#define AW_PID_2071_ANASTA2_REG (0x24) +#define AW_PID_2071_ANASTA3_REG (0x25) +#define AW_PID_2071_ANASTA4_REG (0x26) +#define AW_PID_2071_DSMCFG8_REG (0x37) +#define AW_PID_2071_TESTIN_REG (0x38) +#define AW_PID_2071_TESTOUT_REG (0x39) +#define AW_PID_2071_SADCCTRL2_REG (0x3A) +#define AW_PID_2071_SADCCTRL3_REG (0x3B) +#define AW_PID_2071_SADCCTRL4_REG (0x3C) +#define AW_PID_2071_VSNCTRL1_REG (0x50) +#define AW_PID_2071_ISNCTRL1_REG (0x52) +#define AW_PID_2071_ISNCTRL2_REG (0x53) +#define AW_PID_2071_VTMCTRL1_REG (0x54) +#define AW_PID_2071_VTMCTRL2_REG (0x55) +#define AW_PID_2071_VTMCTRL3_REG (0x56) +#define AW_PID_2071_ISNDAT_REG (0x57) +#define AW_PID_2071_VSNDAT_REG (0x58) +#define AW_PID_2071_PWMCTRL_REG (0x59) +#define AW_PID_2071_PWMCTRL2_REG (0x5A) +#define AW_PID_2071_PWMCTRL3_REG (0x5B) +#define AW_PID_2071_VCALDAT_REG (0x5C) +#define AW_PID_2071_BSTCTRL1_REG (0x60) +#define AW_PID_2071_BSTCTRL2_REG (0x61) +#define AW_PID_2071_BSTCTRL3_REG (0x62) +#define AW_PID_2071_BSTDBG1_REG (0x63) +#define AW_PID_2071_BSTDBG2_REG (0x64) +#define AW_PID_2071_BSTDBG3_REG (0x65) +#define AW_PID_2071_PLLCTRL1_REG (0x66) +#define AW_PID_2071_PLLCTRL2_REG (0x67) +#define AW_PID_2071_PLLCTRL3_REG (0x68) +#define AW_PID_2071_CDACTRL1_REG (0x69) +#define AW_PID_2071_CDACTRL2_REG (0x6A) +#define AW_PID_2071_SADCCTRL_REG (0x6B) +#define AW_PID_2071_BSTCTRL8_REG (0x6C) +#define AW_PID_2071_DITHERCFG1_REG (0x6D) +#define AW_PID_2071_TESTCTRL1_REG (0x70) +#define AW_PID_2071_TESTCTRL2_REG (0x71) +#define AW_PID_2071_EFCTRL1_REG (0x72) +#define AW_PID_2071_EFCTRL2_REG (0x73) +#define AW_PID_2071_EFWH_REG (0x74) +#define AW_PID_2071_EFWM2_REG (0x75) +#define AW_PID_2071_EFWM1_REG (0x76) +#define AW_PID_2071_EFWL_REG (0x77) +#define AW_PID_2071_EFRH_REG (0x78) +#define AW_PID_2071_EFRM2_REG (0x79) +#define AW_PID_2071_EFRM1_REG (0x7A) +#define AW_PID_2071_EFRL_REG (0x7B) +#define AW_PID_2071_TESTDET_REG (0x7C) +#define AW_PID_2071_TM_REG (0x7D) + +/******************************************** + * Register Access + *******************************************/ +#define AW_PID_2071_REG_MAX (0x7E) + +#define AW_PID_2071_REG_NONE_ACCESS (0) +#define AW_PID_2071_REG_RD_ACCESS (1 << 0) +#define AW_PID_2071_REG_WR_ACCESS (1 << 1) + +const unsigned char aw_pid_2071_reg_access[AW_PID_2071_REG_MAX] = { + [AW_PID_2071_ID_REG] = (AW_PID_2071_REG_RD_ACCESS), + [AW_PID_2071_SYSST_REG] = (AW_PID_2071_REG_RD_ACCESS), + [AW_PID_2071_SYSINT_REG] = (AW_PID_2071_REG_RD_ACCESS), + [AW_PID_2071_SYSINTM_REG] = (AW_PID_2071_REG_RD_ACCESS | AW_PID_2071_REG_WR_ACCESS), + [AW_PID_2071_SYSCTRL_REG] = (AW_PID_2071_REG_RD_ACCESS | AW_PID_2071_REG_WR_ACCESS), + [AW_PID_2071_SYSCTRL2_REG] = (AW_PID_2071_REG_RD_ACCESS | AW_PID_2071_REG_WR_ACCESS), + [AW_PID_2071_I2SCTRL_REG] = (AW_PID_2071_REG_RD_ACCESS | AW_PID_2071_REG_WR_ACCESS), + [AW_PID_2071_I2SCFG1_REG] = (AW_PID_2071_REG_RD_ACCESS | AW_PID_2071_REG_WR_ACCESS), + [AW_PID_2071_I2SCFG2_REG] = (AW_PID_2071_REG_RD_ACCESS | AW_PID_2071_REG_WR_ACCESS), + [AW_PID_2071_HAGCCFG1_REG] = (AW_PID_2071_REG_RD_ACCESS | AW_PID_2071_REG_WR_ACCESS), + [AW_PID_2071_HAGCCFG2_REG] = (AW_PID_2071_REG_RD_ACCESS | AW_PID_2071_REG_WR_ACCESS), + [AW_PID_2071_HAGCCFG3_REG] = (AW_PID_2071_REG_RD_ACCESS | AW_PID_2071_REG_WR_ACCESS), + [AW_PID_2071_HAGCCFG4_REG] = (AW_PID_2071_REG_RD_ACCESS | AW_PID_2071_REG_WR_ACCESS), + [AW_PID_2071_HAGCCFG5_REG] = (AW_PID_2071_REG_RD_ACCESS | AW_PID_2071_REG_WR_ACCESS), + [AW_PID_2071_HAGCCFG6_REG] = (AW_PID_2071_REG_RD_ACCESS | AW_PID_2071_REG_WR_ACCESS), + [AW_PID_2071_HAGCCFG7_REG] = (AW_PID_2071_REG_RD_ACCESS | AW_PID_2071_REG_WR_ACCESS), + [AW_PID_2071_HAGCST_REG] = (AW_PID_2071_REG_RD_ACCESS), + [AW_PID_2071_PRODID_REG] = (AW_PID_2071_REG_RD_ACCESS), + [AW_PID_2071_VBAT_REG] = (AW_PID_2071_REG_RD_ACCESS), + [AW_PID_2071_TEMP_REG] = (AW_PID_2071_REG_RD_ACCESS), + [AW_PID_2071_PVDD_REG] = (AW_PID_2071_REG_RD_ACCESS), + [AW_PID_2071_HAGCCFG8_REG] = (AW_PID_2071_REG_RD_ACCESS | AW_PID_2071_REG_WR_ACCESS), + [AW_PID_2071_DBGCTRL_REG] = (AW_PID_2071_REG_RD_ACCESS | AW_PID_2071_REG_WR_ACCESS), + [AW_PID_2071_I2SINT_REG] = (AW_PID_2071_REG_RD_ACCESS), + [AW_PID_2071_I2SCAPCNT_REG] = (AW_PID_2071_REG_RD_ACCESS), + [AW_PID_2071_ANASTA1_REG] = (AW_PID_2071_REG_RD_ACCESS), + [AW_PID_2071_ANASTA2_REG] = (AW_PID_2071_REG_RD_ACCESS), + [AW_PID_2071_ANASTA3_REG] = (AW_PID_2071_REG_RD_ACCESS), + [AW_PID_2071_ANASTA4_REG] = (AW_PID_2071_REG_RD_ACCESS), + [AW_PID_2071_DSMCFG8_REG] = (AW_PID_2071_REG_RD_ACCESS | AW_PID_2071_REG_WR_ACCESS), + [AW_PID_2071_TESTIN_REG] = (AW_PID_2071_REG_RD_ACCESS | AW_PID_2071_REG_WR_ACCESS), + [AW_PID_2071_TESTOUT_REG] = (AW_PID_2071_REG_RD_ACCESS), + [AW_PID_2071_SADCCTRL2_REG] = (AW_PID_2071_REG_RD_ACCESS | AW_PID_2071_REG_WR_ACCESS), + [AW_PID_2071_SADCCTRL3_REG] = (AW_PID_2071_REG_RD_ACCESS | AW_PID_2071_REG_WR_ACCESS), + [AW_PID_2071_SADCCTRL4_REG] = (AW_PID_2071_REG_RD_ACCESS | AW_PID_2071_REG_WR_ACCESS), + [AW_PID_2071_VSNCTRL1_REG] = (AW_PID_2071_REG_RD_ACCESS | AW_PID_2071_REG_WR_ACCESS), + [AW_PID_2071_ISNCTRL1_REG] = (AW_PID_2071_REG_RD_ACCESS | AW_PID_2071_REG_WR_ACCESS), + [AW_PID_2071_ISNCTRL2_REG] = (AW_PID_2071_REG_RD_ACCESS | AW_PID_2071_REG_WR_ACCESS), + [AW_PID_2071_VTMCTRL1_REG] = (AW_PID_2071_REG_RD_ACCESS | AW_PID_2071_REG_WR_ACCESS), + [AW_PID_2071_VTMCTRL2_REG] = (AW_PID_2071_REG_RD_ACCESS | AW_PID_2071_REG_WR_ACCESS), + [AW_PID_2071_VTMCTRL3_REG] = (AW_PID_2071_REG_RD_ACCESS | AW_PID_2071_REG_WR_ACCESS), + [AW_PID_2071_ISNDAT_REG] = (AW_PID_2071_REG_RD_ACCESS), + [AW_PID_2071_VSNDAT_REG] = (AW_PID_2071_REG_RD_ACCESS), + [AW_PID_2071_PWMCTRL_REG] = (AW_PID_2071_REG_RD_ACCESS | AW_PID_2071_REG_WR_ACCESS), + [AW_PID_2071_PWMCTRL2_REG] = (AW_PID_2071_REG_RD_ACCESS | AW_PID_2071_REG_WR_ACCESS), + [AW_PID_2071_PWMCTRL3_REG] = (AW_PID_2071_REG_RD_ACCESS | AW_PID_2071_REG_WR_ACCESS), + [AW_PID_2071_VCALDAT_REG] = (AW_PID_2071_REG_RD_ACCESS), + [AW_PID_2071_BSTCTRL1_REG] = (AW_PID_2071_REG_RD_ACCESS | AW_PID_2071_REG_WR_ACCESS), + [AW_PID_2071_BSTCTRL2_REG] = (AW_PID_2071_REG_RD_ACCESS | AW_PID_2071_REG_WR_ACCESS), + [AW_PID_2071_BSTCTRL3_REG] = (AW_PID_2071_REG_RD_ACCESS | AW_PID_2071_REG_WR_ACCESS), + [AW_PID_2071_BSTDBG1_REG] = (AW_PID_2071_REG_RD_ACCESS | AW_PID_2071_REG_WR_ACCESS), + [AW_PID_2071_BSTDBG2_REG] = (AW_PID_2071_REG_RD_ACCESS | AW_PID_2071_REG_WR_ACCESS), + [AW_PID_2071_BSTDBG3_REG] = (AW_PID_2071_REG_RD_ACCESS | AW_PID_2071_REG_WR_ACCESS), + [AW_PID_2071_PLLCTRL1_REG] = (AW_PID_2071_REG_RD_ACCESS | AW_PID_2071_REG_WR_ACCESS), + [AW_PID_2071_PLLCTRL2_REG] = (AW_PID_2071_REG_RD_ACCESS | AW_PID_2071_REG_WR_ACCESS), + [AW_PID_2071_PLLCTRL3_REG] = (AW_PID_2071_REG_RD_ACCESS | AW_PID_2071_REG_WR_ACCESS), + [AW_PID_2071_CDACTRL1_REG] = (AW_PID_2071_REG_RD_ACCESS | AW_PID_2071_REG_WR_ACCESS), + [AW_PID_2071_CDACTRL2_REG] = (AW_PID_2071_REG_RD_ACCESS | AW_PID_2071_REG_WR_ACCESS), + [AW_PID_2071_SADCCTRL_REG] = (AW_PID_2071_REG_RD_ACCESS | AW_PID_2071_REG_WR_ACCESS), + [AW_PID_2071_BSTCTRL8_REG] = (AW_PID_2071_REG_RD_ACCESS | AW_PID_2071_REG_WR_ACCESS), + [AW_PID_2071_DITHERCFG1_REG] = (AW_PID_2071_REG_RD_ACCESS | AW_PID_2071_REG_WR_ACCESS), + [AW_PID_2071_TESTCTRL1_REG] = (AW_PID_2071_REG_RD_ACCESS | AW_PID_2071_REG_WR_ACCESS), + [AW_PID_2071_TESTCTRL2_REG] = (AW_PID_2071_REG_RD_ACCESS | AW_PID_2071_REG_WR_ACCESS), + [AW_PID_2071_EFCTRL1_REG] = (AW_PID_2071_REG_RD_ACCESS | AW_PID_2071_REG_WR_ACCESS), + [AW_PID_2071_EFCTRL2_REG] = (AW_PID_2071_REG_RD_ACCESS | AW_PID_2071_REG_WR_ACCESS), + [AW_PID_2071_EFWH_REG] = (AW_PID_2071_REG_RD_ACCESS | AW_PID_2071_REG_WR_ACCESS), + [AW_PID_2071_EFWM2_REG] = (AW_PID_2071_REG_RD_ACCESS | AW_PID_2071_REG_WR_ACCESS), + [AW_PID_2071_EFWM1_REG] = (AW_PID_2071_REG_RD_ACCESS | AW_PID_2071_REG_WR_ACCESS), + [AW_PID_2071_EFWL_REG] = (AW_PID_2071_REG_RD_ACCESS | AW_PID_2071_REG_WR_ACCESS), + [AW_PID_2071_EFRH_REG] = (AW_PID_2071_REG_RD_ACCESS), + [AW_PID_2071_EFRM2_REG] = (AW_PID_2071_REG_RD_ACCESS), + [AW_PID_2071_EFRM1_REG] = (AW_PID_2071_REG_RD_ACCESS), + [AW_PID_2071_EFRL_REG] = (AW_PID_2071_REG_RD_ACCESS), + [AW_PID_2071_TESTDET_REG] = (AW_PID_2071_REG_RD_ACCESS), + [AW_PID_2071_TM_REG] = (AW_PID_2071_REG_NONE_ACCESS), +}; + +/* detail information of registers begin */ +/* ID (0x00) detail */ +/* IDCODE bit 15:0 (ID 0x00) */ +#define AW_PID_2071_IDCODE_START_BIT (0) +#define AW_PID_2071_IDCODE_BITS_LEN (16) +#define AW_PID_2071_IDCODE_MASK \ + (~(((1< + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#ifndef __AW882XX_PID_2113_REG_H__ +#define __AW882XX_PID_2113_REG_H__ + +#define AW_PID_2113_MONITOR_FILE "aw882xx_pid_2113_monitor.bin" + +/* registers list */ +#define AW_PID_2113_ID_REG (0x00) +#define AW_PID_2113_SYSST_REG (0x01) +#define AW_PID_2113_SYSINT_REG (0x02) +#define AW_PID_2113_SYSINTM_REG (0x03) +#define AW_PID_2113_SYSCTRL_REG (0x04) +#define AW_PID_2113_SYSCTRL2_REG (0x05) +#define AW_PID_2113_I2SCTRL1_REG (0x06) +#define AW_PID_2113_I2SCTRL2_REG (0x07) +#define AW_PID_2113_I2SCTRL3_REG (0x08) +#define AW_PID_2113_DACCFG1_REG (0x09) +#define AW_PID_2113_DACCFG2_REG (0x0A) +#define AW_PID_2113_DACCFG3_REG (0x0B) +#define AW_PID_2113_DACCFG4_REG (0x0C) +#define AW_PID_2113_DACCFG5_REG (0x0D) +#define AW_PID_2113_DACCFG6_REG (0x0E) +#define AW_PID_2113_DACCFG7_REG (0x0F) +#define AW_PID_2113_DACCFG8_REG (0x10) +#define AW_PID_2113_PWMCTRL1_REG (0x11) +#define AW_PID_2113_PWMCTRL2_REG (0x12) +#define AW_PID_2113_I2SCFG1_REG (0x13) +#define AW_PID_2113_DBGCTRL_REG (0x14) +#define AW_PID_2113_DACCFG9_REG (0x15) +#define AW_PID_2113_DACCFG10_REG (0x16) +#define AW_PID_2113_DACST_REG (0x20) +#define AW_PID_2113_VBAT_REG (0x21) +#define AW_PID_2113_TEMP_REG (0x22) +#define AW_PID_2113_PVDD_REG (0x23) +#define AW_PID_2113_ISNDAT_REG (0x24) +#define AW_PID_2113_VSNDAT_REG (0x25) +#define AW_PID_2113_I2SINT_REG (0x26) +#define AW_PID_2113_I2SCAPCNT_REG (0x27) +#define AW_PID_2113_ANASTA1_REG (0x28) +#define AW_PID_2113_ANASTA2_REG (0x29) +#define AW_PID_2113_ANASTA3_REG (0x2A) +#define AW_PID_2113_TESTDET_REG (0x2B) +#define AW_PID_2113_DSMCFG1_REG (0x30) +#define AW_PID_2113_DSMCFG2_REG (0x31) +#define AW_PID_2113_DSMCFG3_REG (0x32) +#define AW_PID_2113_DSMCFG4_REG (0x33) +#define AW_PID_2113_DSMCFG5_REG (0x34) +#define AW_PID_2113_DSMCFG6_REG (0x35) +#define AW_PID_2113_DSMCFG7_REG (0x36) +#define AW_PID_2113_DSMCFG8_REG (0x37) +#define AW_PID_2113_TESTIN_REG (0x38) +#define AW_PID_2113_TESTOUT_REG (0x39) +#define AW_PID_2113_SADCCTRL1_REG (0x3A) +#define AW_PID_2113_SADCCTRL2_REG (0x3B) +#define AW_PID_2113_SADCCTRL3_REG (0x3C) +#define AW_PID_2113_SADCCTRL4_REG (0x3D) +#define AW_PID_2113_SADCCTRL5_REG (0x3E) +#define AW_PID_2113_SADCCTRL6_REG (0x3F) +#define AW_PID_2113_SADCCTRL7_REG (0x40) +#define AW_PID_2113_VSNTM1_REG (0x50) +#define AW_PID_2113_VSNTM2_REG (0x51) +#define AW_PID_2113_ISNCTRL1_REG (0x52) +#define AW_PID_2113_ISNCTRL2_REG (0x53) +#define AW_PID_2113_PLLCTRL1_REG (0x54) +#define AW_PID_2113_PLLCTRL2_REG (0x55) +#define AW_PID_2113_PLLCTRL3_REG (0x56) +#define AW_PID_2113_CDACTRL1_REG (0x57) +#define AW_PID_2113_CDACTRL2_REG (0x58) +#define AW_PID_2113_DITHERCFG1_REG (0x59) +#define AW_PID_2113_DITHERCFG2_REG (0x5A) +#define AW_PID_2113_DITHERCFG3_REG (0x5B) +#define AW_PID_2113_CPCTRL_REG (0x5C) +#define AW_PID_2113_BSTCTRL1_REG (0x60) +#define AW_PID_2113_BSTCTRL2_REG (0x61) +#define AW_PID_2113_BSTCTRL3_REG (0x62) +#define AW_PID_2113_BSTCTRL4_REG (0x63) +#define AW_PID_2113_BSTCTRL5_REG (0x64) +#define AW_PID_2113_BSTCTRL6_REG (0x65) +#define AW_PID_2113_BSTCTRL7_REG (0x66) +#define AW_PID_2113_BSTCTRL8_REG (0x67) +#define AW_PID_2113_BSTCTRL9_REG (0x68) +#define AW_PID_2113_TM_REG (0x6F) +#define AW_PID_2113_TESTCTRL1_REG (0x70) +#define AW_PID_2113_TESTCTRL2_REG (0x71) +#define AW_PID_2113_EFCTRL1_REG (0x72) +#define AW_PID_2113_EFCTRL2_REG (0x73) +#define AW_PID_2113_EFWH_REG (0x74) +#define AW_PID_2113_EFWM2_REG (0x75) +#define AW_PID_2113_EFWM1_REG (0x76) +#define AW_PID_2113_EFWL_REG (0x77) +#define AW_PID_2113_EFRH4_REG (0x78) +#define AW_PID_2113_EFRH3_REG (0x79) +#define AW_PID_2113_EFRH2_REG (0x7A) +#define AW_PID_2113_EFRH1_REG (0x7B) +#define AW_PID_2113_EFRL4_REG (0x7C) +#define AW_PID_2113_EFRL3_REG (0x7D) +#define AW_PID_2113_EFRL2_REG (0x7E) +#define AW_PID_2113_EFRL1_REG (0x7F) + +/******************************************** + * Register Access + *******************************************/ +#define AW_PID_2113_REG_MAX (0x80) + +#define AW_PID_2113_REG_NONE_ACCESS (0) +#define AW_PID_2113_REG_RD_ACCESS (1 << 0) +#define AW_PID_2113_REG_WR_ACCESS (1 << 1) + +const unsigned char aw_pid_2113_reg_access[AW_PID_2113_REG_MAX] = { + [AW_PID_2113_ID_REG] = (AW_PID_2113_REG_RD_ACCESS), + [AW_PID_2113_SYSST_REG] = (AW_PID_2113_REG_RD_ACCESS), + [AW_PID_2113_SYSINT_REG] = (AW_PID_2113_REG_RD_ACCESS), + [AW_PID_2113_SYSINTM_REG] = (AW_PID_2113_REG_RD_ACCESS | AW_PID_2113_REG_WR_ACCESS), + [AW_PID_2113_SYSCTRL_REG] = (AW_PID_2113_REG_RD_ACCESS | AW_PID_2113_REG_WR_ACCESS), + [AW_PID_2113_SYSCTRL2_REG] = (AW_PID_2113_REG_RD_ACCESS | AW_PID_2113_REG_WR_ACCESS), + [AW_PID_2113_I2SCTRL1_REG] = (AW_PID_2113_REG_RD_ACCESS | AW_PID_2113_REG_WR_ACCESS), + [AW_PID_2113_I2SCTRL2_REG] = (AW_PID_2113_REG_RD_ACCESS | AW_PID_2113_REG_WR_ACCESS), + [AW_PID_2113_I2SCTRL3_REG] = (AW_PID_2113_REG_RD_ACCESS | AW_PID_2113_REG_WR_ACCESS), + [AW_PID_2113_DACCFG1_REG] = (AW_PID_2113_REG_RD_ACCESS | AW_PID_2113_REG_WR_ACCESS), + [AW_PID_2113_DACCFG2_REG] = (AW_PID_2113_REG_RD_ACCESS | AW_PID_2113_REG_WR_ACCESS), + [AW_PID_2113_DACCFG3_REG] = (AW_PID_2113_REG_RD_ACCESS | AW_PID_2113_REG_WR_ACCESS), + [AW_PID_2113_DACCFG4_REG] = (AW_PID_2113_REG_RD_ACCESS | AW_PID_2113_REG_WR_ACCESS), + [AW_PID_2113_DACCFG5_REG] = (AW_PID_2113_REG_RD_ACCESS | AW_PID_2113_REG_WR_ACCESS), + [AW_PID_2113_DACCFG6_REG] = (AW_PID_2113_REG_RD_ACCESS | AW_PID_2113_REG_WR_ACCESS), + [AW_PID_2113_DACCFG7_REG] = (AW_PID_2113_REG_RD_ACCESS | AW_PID_2113_REG_WR_ACCESS), + [AW_PID_2113_DACCFG8_REG] = (AW_PID_2113_REG_RD_ACCESS | AW_PID_2113_REG_WR_ACCESS), + [AW_PID_2113_PWMCTRL1_REG] = (AW_PID_2113_REG_RD_ACCESS | AW_PID_2113_REG_WR_ACCESS), + [AW_PID_2113_PWMCTRL2_REG] = (AW_PID_2113_REG_RD_ACCESS | AW_PID_2113_REG_WR_ACCESS), + [AW_PID_2113_I2SCFG1_REG] = (AW_PID_2113_REG_RD_ACCESS | AW_PID_2113_REG_WR_ACCESS), + [AW_PID_2113_DBGCTRL_REG] = (AW_PID_2113_REG_RD_ACCESS | AW_PID_2113_REG_WR_ACCESS), + [AW_PID_2113_DACCFG9_REG] = (AW_PID_2113_REG_RD_ACCESS | AW_PID_2113_REG_WR_ACCESS), + [AW_PID_2113_DACCFG10_REG] = (AW_PID_2113_REG_RD_ACCESS | AW_PID_2113_REG_WR_ACCESS), + [AW_PID_2113_DACST_REG] = (AW_PID_2113_REG_RD_ACCESS), + [AW_PID_2113_VBAT_REG] = (AW_PID_2113_REG_RD_ACCESS), + [AW_PID_2113_TEMP_REG] = (AW_PID_2113_REG_RD_ACCESS), + [AW_PID_2113_PVDD_REG] = (AW_PID_2113_REG_RD_ACCESS), + [AW_PID_2113_ISNDAT_REG] = (AW_PID_2113_REG_RD_ACCESS), + [AW_PID_2113_VSNDAT_REG] = (AW_PID_2113_REG_RD_ACCESS), + [AW_PID_2113_I2SINT_REG] = (AW_PID_2113_REG_RD_ACCESS), + [AW_PID_2113_I2SCAPCNT_REG] = (AW_PID_2113_REG_RD_ACCESS), + [AW_PID_2113_ANASTA1_REG] = (AW_PID_2113_REG_RD_ACCESS), + [AW_PID_2113_ANASTA2_REG] = (AW_PID_2113_REG_RD_ACCESS), + [AW_PID_2113_ANASTA3_REG] = (AW_PID_2113_REG_RD_ACCESS), + [AW_PID_2113_TESTDET_REG] = (AW_PID_2113_REG_RD_ACCESS), + [AW_PID_2113_DSMCFG1_REG] = (AW_PID_2113_REG_RD_ACCESS | AW_PID_2113_REG_WR_ACCESS), + [AW_PID_2113_DSMCFG2_REG] = (AW_PID_2113_REG_RD_ACCESS | AW_PID_2113_REG_WR_ACCESS), + [AW_PID_2113_DSMCFG3_REG] = (AW_PID_2113_REG_RD_ACCESS | AW_PID_2113_REG_WR_ACCESS), + [AW_PID_2113_DSMCFG4_REG] = (AW_PID_2113_REG_RD_ACCESS | AW_PID_2113_REG_WR_ACCESS), + [AW_PID_2113_DSMCFG5_REG] = (AW_PID_2113_REG_RD_ACCESS | AW_PID_2113_REG_WR_ACCESS), + [AW_PID_2113_DSMCFG6_REG] = (AW_PID_2113_REG_RD_ACCESS | AW_PID_2113_REG_WR_ACCESS), + [AW_PID_2113_DSMCFG7_REG] = (AW_PID_2113_REG_RD_ACCESS | AW_PID_2113_REG_WR_ACCESS), + [AW_PID_2113_DSMCFG8_REG] = (AW_PID_2113_REG_RD_ACCESS | AW_PID_2113_REG_WR_ACCESS), + [AW_PID_2113_TESTIN_REG] = (AW_PID_2113_REG_RD_ACCESS | AW_PID_2113_REG_WR_ACCESS), + [AW_PID_2113_TESTOUT_REG] = (AW_PID_2113_REG_RD_ACCESS), + [AW_PID_2113_SADCCTRL1_REG] = (AW_PID_2113_REG_RD_ACCESS | AW_PID_2113_REG_WR_ACCESS), + [AW_PID_2113_SADCCTRL2_REG] = (AW_PID_2113_REG_RD_ACCESS | AW_PID_2113_REG_WR_ACCESS), + [AW_PID_2113_SADCCTRL3_REG] = (AW_PID_2113_REG_RD_ACCESS | AW_PID_2113_REG_WR_ACCESS), + [AW_PID_2113_SADCCTRL4_REG] = (AW_PID_2113_REG_RD_ACCESS | AW_PID_2113_REG_WR_ACCESS), + [AW_PID_2113_SADCCTRL5_REG] = (AW_PID_2113_REG_RD_ACCESS | AW_PID_2113_REG_WR_ACCESS), + [AW_PID_2113_SADCCTRL6_REG] = (AW_PID_2113_REG_RD_ACCESS | AW_PID_2113_REG_WR_ACCESS), + [AW_PID_2113_SADCCTRL7_REG] = (AW_PID_2113_REG_RD_ACCESS | AW_PID_2113_REG_WR_ACCESS), + [AW_PID_2113_VSNTM1_REG] = (AW_PID_2113_REG_RD_ACCESS | AW_PID_2113_REG_WR_ACCESS), + [AW_PID_2113_VSNTM2_REG] = (AW_PID_2113_REG_RD_ACCESS | AW_PID_2113_REG_WR_ACCESS), + [AW_PID_2113_ISNCTRL1_REG] = (AW_PID_2113_REG_RD_ACCESS | AW_PID_2113_REG_WR_ACCESS), + [AW_PID_2113_ISNCTRL2_REG] = (AW_PID_2113_REG_RD_ACCESS | AW_PID_2113_REG_WR_ACCESS), + [AW_PID_2113_PLLCTRL1_REG] = (AW_PID_2113_REG_RD_ACCESS | AW_PID_2113_REG_WR_ACCESS), + [AW_PID_2113_PLLCTRL2_REG] = (AW_PID_2113_REG_RD_ACCESS | AW_PID_2113_REG_WR_ACCESS), + [AW_PID_2113_PLLCTRL3_REG] = (AW_PID_2113_REG_RD_ACCESS | AW_PID_2113_REG_WR_ACCESS), + [AW_PID_2113_CDACTRL1_REG] = (AW_PID_2113_REG_RD_ACCESS | AW_PID_2113_REG_WR_ACCESS), + [AW_PID_2113_CDACTRL2_REG] = (AW_PID_2113_REG_RD_ACCESS | AW_PID_2113_REG_WR_ACCESS), + [AW_PID_2113_DITHERCFG1_REG] = (AW_PID_2113_REG_RD_ACCESS | AW_PID_2113_REG_WR_ACCESS), + [AW_PID_2113_DITHERCFG2_REG] = (AW_PID_2113_REG_RD_ACCESS | AW_PID_2113_REG_WR_ACCESS), + [AW_PID_2113_DITHERCFG3_REG] = (AW_PID_2113_REG_RD_ACCESS | AW_PID_2113_REG_WR_ACCESS), + [AW_PID_2113_CPCTRL_REG] = (AW_PID_2113_REG_RD_ACCESS | AW_PID_2113_REG_WR_ACCESS), + [AW_PID_2113_BSTCTRL1_REG] = (AW_PID_2113_REG_RD_ACCESS | AW_PID_2113_REG_WR_ACCESS), + [AW_PID_2113_BSTCTRL2_REG] = (AW_PID_2113_REG_RD_ACCESS | AW_PID_2113_REG_WR_ACCESS), + [AW_PID_2113_BSTCTRL3_REG] = (AW_PID_2113_REG_RD_ACCESS | AW_PID_2113_REG_WR_ACCESS), + [AW_PID_2113_BSTCTRL4_REG] = (AW_PID_2113_REG_RD_ACCESS | AW_PID_2113_REG_WR_ACCESS), + [AW_PID_2113_BSTCTRL5_REG] = (AW_PID_2113_REG_RD_ACCESS | AW_PID_2113_REG_WR_ACCESS), + [AW_PID_2113_BSTCTRL6_REG] = (AW_PID_2113_REG_RD_ACCESS | AW_PID_2113_REG_WR_ACCESS), + [AW_PID_2113_BSTCTRL7_REG] = (AW_PID_2113_REG_RD_ACCESS | AW_PID_2113_REG_WR_ACCESS), + [AW_PID_2113_BSTCTRL8_REG] = (AW_PID_2113_REG_RD_ACCESS | AW_PID_2113_REG_WR_ACCESS), + [AW_PID_2113_BSTCTRL9_REG] = (AW_PID_2113_REG_RD_ACCESS | AW_PID_2113_REG_WR_ACCESS), + [AW_PID_2113_TM_REG] = (AW_PID_2113_REG_NONE_ACCESS), + [AW_PID_2113_TESTCTRL1_REG] = (AW_PID_2113_REG_RD_ACCESS | AW_PID_2113_REG_WR_ACCESS), + [AW_PID_2113_TESTCTRL2_REG] = (AW_PID_2113_REG_RD_ACCESS | AW_PID_2113_REG_WR_ACCESS), + [AW_PID_2113_EFCTRL1_REG] = (AW_PID_2113_REG_RD_ACCESS | AW_PID_2113_REG_WR_ACCESS), + [AW_PID_2113_EFCTRL2_REG] = (AW_PID_2113_REG_RD_ACCESS | AW_PID_2113_REG_WR_ACCESS), + [AW_PID_2113_EFWH_REG] = (AW_PID_2113_REG_RD_ACCESS | AW_PID_2113_REG_WR_ACCESS), + [AW_PID_2113_EFWM2_REG] = (AW_PID_2113_REG_RD_ACCESS | AW_PID_2113_REG_WR_ACCESS), + [AW_PID_2113_EFWM1_REG] = (AW_PID_2113_REG_RD_ACCESS | AW_PID_2113_REG_WR_ACCESS), + [AW_PID_2113_EFWL_REG] = (AW_PID_2113_REG_RD_ACCESS | AW_PID_2113_REG_WR_ACCESS), + [AW_PID_2113_EFRH4_REG] = (AW_PID_2113_REG_RD_ACCESS), + [AW_PID_2113_EFRH3_REG] = (AW_PID_2113_REG_RD_ACCESS), + [AW_PID_2113_EFRH2_REG] = (AW_PID_2113_REG_RD_ACCESS), + [AW_PID_2113_EFRH1_REG] = (AW_PID_2113_REG_RD_ACCESS), + [AW_PID_2113_EFRL4_REG] = (AW_PID_2113_REG_RD_ACCESS), + [AW_PID_2113_EFRL3_REG] = (AW_PID_2113_REG_RD_ACCESS), + [AW_PID_2113_EFRL2_REG] = (AW_PID_2113_REG_RD_ACCESS), + [AW_PID_2113_EFRL1_REG] = (AW_PID_2113_REG_RD_ACCESS), +}; + +/* detail information of registers begin */ +/* ID (0x00) detail */ +/* IDCODE bit 15:0 (ID 0x00) */ +#define AW_PID_2113_IDCODE_START_BIT (0) +#define AW_PID_2113_IDCODE_BITS_LEN (16) +#define AW_PID_2113_IDCODE_MASK \ + (~(((1< + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#ifndef __AW882XX_PID_2308_REG_H__ +#define __AW882XX_PID_2308_REG_H__ + +#define AW_PID_2308_MONITOR_FILE "aw882xx_pid_2308_monitor.bin" + +/* registers list */ +#define AW_PID_2308_ID_REG (0x00) +#define AW_PID_2308_SYSST_REG (0x01) +#define AW_PID_2308_SYSINT_REG (0x02) +#define AW_PID_2308_SYSINTM_REG (0x03) +#define AW_PID_2308_SYSCTRL_REG (0x04) +#define AW_PID_2308_SYSCTRL2_REG (0x05) +#define AW_PID_2308_I2SCTRL1_REG (0x06) +#define AW_PID_2308_I2SCTRL2_REG (0x07) +#define AW_PID_2308_I2SCTRL3_REG (0x08) +#define AW_PID_2308_DACCFG1_REG (0x09) +#define AW_PID_2308_DACCFG2_REG (0x0A) +#define AW_PID_2308_DACCFG3_REG (0x0B) +#define AW_PID_2308_DACCFG4_REG (0x0C) +#define AW_PID_2308_DACCFG5_REG (0x0D) +#define AW_PID_2308_DACCFG6_REG (0x0E) +#define AW_PID_2308_DACCFG7_REG (0x0F) +#define AW_PID_2308_DACCFG8_REG (0x10) +#define AW_PID_2308_PWMCTRL1_REG (0x11) +#define AW_PID_2308_PWMCTRL2_REG (0x12) +#define AW_PID_2308_I2SCFG1_REG (0x13) +#define AW_PID_2308_MPDCFG5_REG (0x14) +#define AW_PID_2308_BOPCTRL1_REG (0x15) +#define AW_PID_2308_BOPCTRL2_REG (0x16) +#define AW_PID_2308_BOPCTRL3_REG (0x17) +#define AW_PID_2308_BOPCTRL4_REG (0x18) +#define AW_PID_2308_BOPCTRL5_REG (0x19) +#define AW_PID_2308_BOPCTRL6_REG (0x1A) +#define AW_PID_2308_BOPCTRL7_REG (0x1B) +#define AW_PID_2308_BOPCTRL8_REG (0x1C) +#define AW_PID_2308_BOPCTRL9_REG (0x1D) +#define AW_PID_2308_BOPCTRL10_REG (0x1E) +#define AW_PID_2308_DBGCTRL_REG (0x1F) +#define AW_PID_2308_DACST_REG (0x20) +#define AW_PID_2308_VBAT_REG (0x21) +#define AW_PID_2308_TEMP_REG (0x22) +#define AW_PID_2308_PVDD_REG (0x23) +#define AW_PID_2308_ISNDAT_REG (0x24) +#define AW_PID_2308_VSNDAT_REG (0x25) +#define AW_PID_2308_I2SINT_REG (0x26) +#define AW_PID_2308_I2SCAPCNT_REG (0x27) +#define AW_PID_2308_TESTDET_REG (0x28) +#define AW_PID_2308_ANASTA1_REG (0x29) +#define AW_PID_2308_ANASTA2_REG (0x2A) +#define AW_PID_2308_ANASTA3_REG (0x2B) +#define AW_PID_2308_ANASTA4_REG (0x2C) +#define AW_PID_2308_ANASTA5_REG (0x2D) +#define AW_PID_2308_TESTOUT_REG (0x2E) +#define AW_PID_2308_DC_DOUT_REG (0x2F) +#define AW_PID_2308_DSMCFG1_REG (0x30) +#define AW_PID_2308_DSMCFG2_REG (0x31) +#define AW_PID_2308_DSMCFG3_REG (0x32) +#define AW_PID_2308_DSMCFG4_REG (0x33) +#define AW_PID_2308_DSMCFG5_REG (0x34) +#define AW_PID_2308_DSMCFG6_REG (0x35) +#define AW_PID_2308_DSMCFG7_REG (0x36) +#define AW_PID_2308_DSMCFG8_REG (0x37) +#define AW_PID_2308_TESTIN_REG (0x38) +#define AW_PID_2308_DETCTRL1_REG (0x3A) +#define AW_PID_2308_DETCTRL2_REG (0x3B) +#define AW_PID_2308_MPDCFG1_REG (0x3C) +#define AW_PID_2308_MPDCFG2_REG (0x3D) +#define AW_PID_2308_MPDCFG3_REG (0x3E) +#define AW_PID_2308_MPDCFG4_REG (0x3F) +#define AW_PID_2308_ISNTM1_REG (0x50) +#define AW_PID_2308_ISNCTRL3_REG (0x51) +#define AW_PID_2308_VSNTM1_REG (0x52) +#define AW_PID_2308_VSNTM2_REG (0x53) +#define AW_PID_2308_ISNCTRL1_REG (0x54) +#define AW_PID_2308_ISNCTRL2_REG (0x55) +#define AW_PID_2308_PLLCTRL1_REG (0x56) +#define AW_PID_2308_PLLCTRL2_REG (0x57) +#define AW_PID_2308_PLLCTRL3_REG (0x58) +#define AW_PID_2308_PSMCTRL1_REG (0x59) +#define AW_PID_2308_PSMCTRL2_REG (0x5A) +#define AW_PID_2308_PSMCTRL3_REG (0x5B) +#define AW_PID_2308_NGCTRL1_REG (0x5C) +#define AW_PID_2308_NGCTRL2_REG (0x5D) +#define AW_PID_2308_NGCTRL3_REG (0x5E) +#define AW_PID_2308_CPCTRL_REG (0x5F) +#define AW_PID_2308_BSTCTRL1_REG (0x60) +#define AW_PID_2308_BSTCTRL2_REG (0x61) +#define AW_PID_2308_BSTCTRL3_REG (0x62) +#define AW_PID_2308_BSTCTRL4_REG (0x63) +#define AW_PID_2308_BSTCTRL5_REG (0x64) +#define AW_PID_2308_BSTCTRL6_REG (0x65) +#define AW_PID_2308_BSTCTRL7_REG (0x66) +#define AW_PID_2308_BSTCTRL8_REG (0x67) +#define AW_PID_2308_BSTCTRL9_REG (0x68) +#define AW_PID_2308_CDACTRL1_REG (0x69) +#define AW_PID_2308_CDACTRL2_REG (0x6A) +#define AW_PID_2308_CDACTRL3_REG (0x6B) +#define AW_PID_2308_CDACTRL4_REG (0x6C) +#define AW_PID_2308_CDACTRL5_REG (0x6D) +#define AW_PID_2308_TM2_REG (0x6E) +#define AW_PID_2308_TM_REG (0x6F) +#define AW_PID_2308_TESTCTRL1_REG (0x70) +#define AW_PID_2308_TESTCTRL2_REG (0x71) +#define AW_PID_2308_EFCTRL1_REG (0x72) +#define AW_PID_2308_EFCTRL2_REG (0x73) +#define AW_PID_2308_EFWH_REG (0x74) +#define AW_PID_2308_EFWM2_REG (0x75) +#define AW_PID_2308_EFWM1_REG (0x76) +#define AW_PID_2308_EFWL_REG (0x77) +#define AW_PID_2308_EFRH4_REG (0x78) +#define AW_PID_2308_EFRH3_REG (0x79) +#define AW_PID_2308_EFRH2_REG (0x7A) +#define AW_PID_2308_EFRH1_REG (0x7B) +#define AW_PID_2308_EFRL4_REG (0x7C) +#define AW_PID_2308_EFRL3_REG (0x7D) +#define AW_PID_2308_EFRL2_REG (0x7E) +#define AW_PID_2308_EFRL1_REG (0x7F) + +/******************************************** + * Register Access + *******************************************/ +#define AW_PID_2308_REG_MAX (0x80) + +#define REG_NONE_ACCESS (0) +#define REG_RD_ACCESS (1 << 0) +#define REG_WR_ACCESS (1 << 1) + +const unsigned char aw_pid_2308_reg_access[AW_PID_2308_REG_MAX] = { + [AW_PID_2308_ID_REG] = (REG_RD_ACCESS), + [AW_PID_2308_SYSST_REG] = (REG_RD_ACCESS), + [AW_PID_2308_SYSINT_REG] = (REG_RD_ACCESS), + [AW_PID_2308_SYSINTM_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW_PID_2308_SYSCTRL_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW_PID_2308_SYSCTRL2_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW_PID_2308_I2SCTRL1_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW_PID_2308_I2SCTRL2_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW_PID_2308_I2SCTRL3_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW_PID_2308_DACCFG1_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW_PID_2308_DACCFG2_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW_PID_2308_DACCFG3_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW_PID_2308_DACCFG4_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW_PID_2308_DACCFG5_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW_PID_2308_DACCFG6_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW_PID_2308_DACCFG7_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW_PID_2308_DACCFG8_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW_PID_2308_PWMCTRL1_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW_PID_2308_PWMCTRL2_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW_PID_2308_I2SCFG1_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW_PID_2308_MPDCFG5_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW_PID_2308_BOPCTRL1_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW_PID_2308_BOPCTRL2_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW_PID_2308_BOPCTRL3_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW_PID_2308_BOPCTRL4_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW_PID_2308_BOPCTRL5_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW_PID_2308_BOPCTRL6_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW_PID_2308_BOPCTRL7_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW_PID_2308_BOPCTRL8_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW_PID_2308_BOPCTRL9_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW_PID_2308_BOPCTRL10_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW_PID_2308_DBGCTRL_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW_PID_2308_DACST_REG] = (REG_RD_ACCESS), + [AW_PID_2308_VBAT_REG] = (REG_RD_ACCESS), + [AW_PID_2308_TEMP_REG] = (REG_RD_ACCESS), + [AW_PID_2308_PVDD_REG] = (REG_RD_ACCESS), + [AW_PID_2308_ISNDAT_REG] = (REG_RD_ACCESS), + [AW_PID_2308_VSNDAT_REG] = (REG_RD_ACCESS), + [AW_PID_2308_I2SINT_REG] = (REG_RD_ACCESS), + [AW_PID_2308_I2SCAPCNT_REG] = (REG_RD_ACCESS), + [AW_PID_2308_TESTDET_REG] = (REG_RD_ACCESS), + [AW_PID_2308_ANASTA1_REG] = (REG_RD_ACCESS), + [AW_PID_2308_ANASTA2_REG] = (REG_RD_ACCESS), + [AW_PID_2308_ANASTA3_REG] = (REG_RD_ACCESS), + [AW_PID_2308_ANASTA4_REG] = (REG_RD_ACCESS), + [AW_PID_2308_ANASTA5_REG] = (REG_RD_ACCESS), + [AW_PID_2308_TESTOUT_REG] = (REG_RD_ACCESS), + [AW_PID_2308_DC_DOUT_REG] = (REG_RD_ACCESS), + [AW_PID_2308_DSMCFG1_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW_PID_2308_DSMCFG2_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW_PID_2308_DSMCFG3_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW_PID_2308_DSMCFG4_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW_PID_2308_DSMCFG5_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW_PID_2308_DSMCFG6_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW_PID_2308_DSMCFG7_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW_PID_2308_DSMCFG8_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW_PID_2308_TESTIN_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW_PID_2308_DETCTRL1_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW_PID_2308_DETCTRL2_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW_PID_2308_MPDCFG1_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW_PID_2308_MPDCFG2_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW_PID_2308_MPDCFG3_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW_PID_2308_MPDCFG4_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW_PID_2308_ISNTM1_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW_PID_2308_ISNCTRL3_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW_PID_2308_VSNTM1_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW_PID_2308_VSNTM2_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW_PID_2308_ISNCTRL1_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW_PID_2308_ISNCTRL2_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW_PID_2308_PLLCTRL1_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW_PID_2308_PLLCTRL2_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW_PID_2308_PLLCTRL3_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW_PID_2308_PSMCTRL1_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW_PID_2308_PSMCTRL2_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW_PID_2308_PSMCTRL3_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW_PID_2308_NGCTRL1_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW_PID_2308_NGCTRL2_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW_PID_2308_NGCTRL3_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW_PID_2308_CPCTRL_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW_PID_2308_BSTCTRL1_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW_PID_2308_BSTCTRL2_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW_PID_2308_BSTCTRL3_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW_PID_2308_BSTCTRL4_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW_PID_2308_BSTCTRL5_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW_PID_2308_BSTCTRL6_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW_PID_2308_BSTCTRL7_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW_PID_2308_BSTCTRL8_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW_PID_2308_BSTCTRL9_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW_PID_2308_CDACTRL1_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW_PID_2308_CDACTRL2_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW_PID_2308_CDACTRL3_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW_PID_2308_CDACTRL4_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW_PID_2308_CDACTRL5_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW_PID_2308_TM2_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW_PID_2308_TM_REG] = (REG_NONE_ACCESS), + [AW_PID_2308_TESTCTRL1_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW_PID_2308_TESTCTRL2_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW_PID_2308_EFCTRL1_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW_PID_2308_EFCTRL2_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW_PID_2308_EFWH_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW_PID_2308_EFWM2_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW_PID_2308_EFWM1_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW_PID_2308_EFWL_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW_PID_2308_EFRH4_REG] = (REG_RD_ACCESS), + [AW_PID_2308_EFRH3_REG] = (REG_RD_ACCESS), + [AW_PID_2308_EFRH2_REG] = (REG_RD_ACCESS), + [AW_PID_2308_EFRH1_REG] = (REG_RD_ACCESS), + [AW_PID_2308_EFRL4_REG] = (REG_RD_ACCESS), + [AW_PID_2308_EFRL3_REG] = (REG_RD_ACCESS), + [AW_PID_2308_EFRL2_REG] = (REG_RD_ACCESS), + [AW_PID_2308_EFRL1_REG] = (REG_RD_ACCESS), +}; + +/******************************************** + * Volume Coefficient + *******************************************/ +#define AW_PID_2308_VOL_STEP (64) +#define AW_PID_2308_MUTE_VOL (1023) + +/* detail information of registers begin */ +/* ID (0x00) detail */ +/* IDCODE bit 15:0 (ID 0x00) */ +#define AW_PID_2308_IDCODE_START_BIT (0) +#define AW_PID_2308_IDCODE_BITS_LEN (16) +#define AW_PID_2308_IDCODE_MASK \ + (~(((1< + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "aw882xx_log.h" +#include "aw882xx.h" +#include "aw882xx_spin.h" + +static unsigned int g_spin_mode; +static unsigned int g_spin_value; + +static DEFINE_MUTEX(g_spin_lock); + +static int aw_dev_set_channal_mode(struct aw_device *aw_dev, + struct aw_spin_desc spin_desc, uint32_t spin_val) +{ + int ret; + struct aw_reg_ch *rx_desc = &spin_desc.rx_desc; + + ret = aw_dev->ops.aw_i2c_write_bits(aw_dev, rx_desc->reg, rx_desc->mask, + spin_desc.spin_table[spin_val].rx_val); + if (ret < 0) { + aw_dev_err(aw_dev->dev, "set rx failed"); + return ret; + } + + aw_dev_dbg(aw_dev->dev, "set channel mode done!"); + return 0; +} + +static int aw_reg_write_spin(struct aw_device *aw_dev, + uint32_t spin_val, bool mixer_en) +{ + int ret; + struct aw_device *local_dev = NULL; + struct list_head *pos = NULL; + struct list_head *dev_list = NULL; + + ret = aw882xx_dev_get_list_head(&dev_list); + if (ret) { + aw_dev_err(aw_dev->dev, "get dev list failed"); + return ret; + } + + if ((g_spin_mode == AW_REG_MIXER_SPIN_MODE) && (mixer_en)) { + list_for_each(pos, dev_list) { + local_dev = container_of(pos, struct aw_device, list_node); + ret = aw882xx_dsp_set_mixer_en(local_dev, AW_AUDIO_MIX_ENABLE); + if (ret) + return ret; + } + } + + usleep_range(AW_100000_US, AW_100000_US + 10); + + list_for_each(pos, dev_list) { + local_dev = container_of(pos, struct aw_device, list_node); + ret = aw_dev_set_channal_mode(local_dev, local_dev->spin_desc, spin_val); + if (ret < 0) { + aw_dev_err(local_dev->dev, "set channal mode failed"); + return ret; + } + + if ((g_spin_mode == AW_REG_MIXER_SPIN_MODE) && (mixer_en)) { + ret = aw882xx_dsp_set_mixer_en(aw_dev, AW_AUDIO_MIX_DSIABLE); + if (ret) + return ret; + } + } + + return 0; +} + +int aw882xx_spin_set_record_val(struct aw_device *aw_dev) +{ + int ret = -1; + + mutex_lock(&g_spin_lock); + if (g_spin_mode == AW_ADSP_SPIN_MODE) { + ret = aw882xx_dsp_write_spin(g_spin_value); + if (ret) { + mutex_unlock(&g_spin_lock); + return ret; + } + } else if ((g_spin_mode == AW_REG_SPIN_MODE) || + (g_spin_mode == AW_REG_MIXER_SPIN_MODE)) { + ret = aw_dev_set_channal_mode(aw_dev, aw_dev->spin_desc, g_spin_value); + if (ret) { + mutex_unlock(&g_spin_lock); + return ret; + } + } else { + aw_dev_info(aw_dev->dev, "do nothing"); + } + mutex_unlock(&g_spin_lock); + + aw_dev_info(aw_dev->dev, "set record spin val done"); + return 0; +} + +int aw882xx_spin_value_get(struct aw_device *aw_dev, + uint32_t *spin_val, bool pstream) +{ + int ret = 0; + + if (((g_spin_mode == AW_REG_SPIN_MODE) || + (g_spin_mode == AW_REG_MIXER_SPIN_MODE)) || (!pstream)) + *spin_val = g_spin_value; + else if (g_spin_mode == AW_ADSP_SPIN_MODE) + ret = aw882xx_dsp_read_spin(spin_val); + + return ret; +} + +int aw882xx_spin_value_set(struct aw_device *aw_dev, uint32_t spin_val, bool pstream) +{ + int ret = 0; + + mutex_lock(&g_spin_lock); + if (pstream) { + if ((g_spin_mode == AW_REG_SPIN_MODE) || + (g_spin_mode == AW_REG_MIXER_SPIN_MODE)) + ret = aw_reg_write_spin(aw_dev, spin_val, true); + else if (g_spin_mode == AW_ADSP_SPIN_MODE) + ret = aw882xx_dsp_write_spin(spin_val); + else + aw_dev_info(aw_dev->dev, "can't set spin value"); + } else { + if ((g_spin_mode == AW_REG_SPIN_MODE) || + (g_spin_mode == AW_REG_MIXER_SPIN_MODE)) + ret = aw_reg_write_spin(aw_dev, spin_val, false); + else + aw_dev_info(aw_dev->dev, "stream no start only record spin angle"); + } + g_spin_value = spin_val; + mutex_unlock(&g_spin_lock); + + return ret; +} + +static int aw_parse_spin_table_dt(struct aw_device *aw_dev) +{ + int ret = -1; + const char *str_data = NULL; + char spin_table_str[AW_SPIN_MAX] = { 0 }; + struct aw_spin_desc *spin_desc = &aw_dev->spin_desc; + int i; + + ret = of_property_read_string(aw_dev->dev->of_node, "spin-data", &str_data); + if (ret < 0) { + aw_dev_err(aw_dev->dev, "get spin_data failed, close spin function"); + return ret; + } + + ret = sscanf(str_data, "%c %c %c %c", + &spin_table_str[AW_SPIN_0], &spin_table_str[AW_SPIN_90], + &spin_table_str[AW_SPIN_180], &spin_table_str[AW_SPIN_270]); + if (ret != AW_SPIN_MAX) { + aw_dev_err(aw_dev->dev, "unsupported str:%s, close spin function", str_data); + return -EINVAL; + } + + for (i = 0; i < AW_SPIN_MAX; i++) { + if (spin_table_str[i] == 'l' || spin_table_str[i] == 'L') { + spin_desc->spin_table[i].rx_val = spin_desc->rx_desc.left_val; + } else if (spin_table_str[i] == 'r' || spin_table_str[i] == 'R') { + spin_desc->spin_table[i].rx_val = spin_desc->rx_desc.right_val; + } else { + aw_dev_err(aw_dev->dev, "unsupported str:%s, close spin function", str_data); + return -EINVAL; + } + } + + return 0; +} + +static int aw_parse_spin_dts(struct aw_device *aw_dev) +{ + int ret = -1; + const char *spin_str = NULL; + + ret = of_property_read_string(aw_dev->dev->of_node, "spin-mode", &spin_str); + if (ret < 0) { + g_spin_mode = AW_SPIN_OFF_MODE; + aw_dev_info(aw_dev->dev, "spin-mode get failed, spin switch off, spin_mode:%d", g_spin_mode); + return 0; + } + + if (!strcmp(spin_str, "dsp_spin")) + g_spin_mode = AW_ADSP_SPIN_MODE; + else if (!strcmp(spin_str, "reg_spin")) + g_spin_mode = AW_REG_SPIN_MODE; + else if (!strcmp(spin_str, "reg_mixer_spin")) + g_spin_mode = AW_REG_MIXER_SPIN_MODE; + else + g_spin_mode = AW_SPIN_OFF_MODE; + + if ((g_spin_mode == AW_REG_SPIN_MODE) || + (g_spin_mode == AW_REG_MIXER_SPIN_MODE)) { + ret = aw_parse_spin_table_dt(aw_dev); + if (ret < 0) + return ret; + } + + aw_dev_info(aw_dev->dev, "spin mode is %d", g_spin_mode); + return 0; +} + +int aw882xx_spin_init(struct aw_spin_desc *spin_desc) +{ + int ret = 0; + struct aw_device *aw_dev = + container_of(spin_desc, struct aw_device, spin_desc); + + ret = aw_parse_spin_dts(aw_dev); + + if (g_spin_mode == AW_SPIN_OFF_MODE) + spin_desc->aw_spin_kcontrol_st = AW_SPIN_KCONTROL_DISABLE; + else + spin_desc->aw_spin_kcontrol_st = AW_SPIN_KCONTROL_ENABLE; + + aw_dev_info(aw_dev->dev, "aw_spin_kcontrol_st:%d", spin_desc->aw_spin_kcontrol_st); + + return ret; +} diff --git a/sound/soc/codecs/aw882xx/aw882xx_spin.h b/sound/soc/codecs/aw882xx/aw882xx_spin.h new file mode 100644 index 000000000000..eb303e324e3e --- /dev/null +++ b/sound/soc/codecs/aw882xx/aw882xx_spin.h @@ -0,0 +1,31 @@ +/* SPDX-License-Identifier: GPL-2.0 + * aw882xx_spin.h spin_module + * + * Copyright (c) 2019 AWINIC Technology CO., LTD + * + * Author: Nick Li + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#ifndef __AW882XX_SPIN_H__ +#define __AW882XX_SPIN_H__ + + +enum { + AW_SPIN_OFF_MODE = 0, + AW_ADSP_SPIN_MODE, + AW_REG_SPIN_MODE, + AW_REG_MIXER_SPIN_MODE, + AW_SPIN_MODE_MAX, +}; + +int aw882xx_spin_init(struct aw_spin_desc *spin_desc); +int aw882xx_spin_value_set(struct aw_device *aw_dev, uint32_t spin_val, bool pstream); +int aw882xx_spin_value_get(struct aw_device *aw_dev, uint32_t *spin_val, bool pstream); +int aw882xx_spin_set_record_val(struct aw_device *aw_dev); + +#endif diff --git a/sound/soc/codecs/it6621/Kconfig b/sound/soc/codecs/it6621/Kconfig new file mode 100644 index 000000000000..e64053b7719f --- /dev/null +++ b/sound/soc/codecs/it6621/Kconfig @@ -0,0 +1,10 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +config SND_SOC_IT6621 + tristate "IT6621 driver for HDMI2.1 enhanced audio return channel (eARC)" + depends on (I2C) + help + Say yes here to build support for ITE IT6621 eARC. + + To compile this driver as a module, choose M here: the module + will be called it6621. diff --git a/sound/soc/codecs/it6621/Makefile b/sound/soc/codecs/it6621/Makefile new file mode 100644 index 000000000000..f559bbcc30ef --- /dev/null +++ b/sound/soc/codecs/it6621/Makefile @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +it6621-y := it6621-codec.o it6621-clk.o it6621-earc.o it6621-uapi.o +obj-$(CONFIG_SND_SOC_IT6621) += it6621.o diff --git a/sound/soc/codecs/it6621/it6621-clk.c b/sound/soc/codecs/it6621/it6621-clk.c new file mode 100644 index 000000000000..af6c0cecae20 --- /dev/null +++ b/sound/soc/codecs/it6621/it6621-clk.c @@ -0,0 +1,319 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2024 Rockchip Electronics Co. Ltd. + * Author: Jason Zhang + */ + +#include "it6621.h" +#include "it6621-clk.h" +#include "it6621-earc.h" +#include "it6621-reg-bank0.h" +#include "it6621-reg-bank1.h" + +static int it6621_get_100ms_cnt(struct it6621_priv *priv, u32 *count) +{ + unsigned int val; + + regmap_write(priv->regmap, IT6621_REG_GEN0, IT6621_100MS_CNT_EN); + msleep(99); + regmap_write(priv->regmap, IT6621_REG_GEN0, IT6621_100MS_CNT_DIS); + regmap_read(priv->regmap, IT6621_REG_100MS_CNT_7_0, &val); + *count = (u32)val; + regmap_read(priv->regmap, IT6621_REG_100MS_CNT_15_8, &val); + *count += ((u32)(val) << 8); + regmap_read(priv->regmap, IT6621_REG_100MS_CNT_23_16, &val); + *count += ((u32)(val) << 16); + + return 0; +} + +static int it6621_get_lcf(struct it6621_priv *priv, unsigned int *lcf) +{ + unsigned int timer_1us_flt; + unsigned int lcf_high; + unsigned int lcf_low; + unsigned int tmp; + + if (priv->fixed_lcf) { + *lcf = priv->fixed_lcf; + dev_info(priv->dev, "lcf: %d\n", *lcf); + } else { + regmap_update_bits(priv->regmap, 0xa9, 0x0f, 0x00); + it6621_get_100ms_cnt(priv, &lcf_low); + + regmap_update_bits(priv->regmap, 0xa9, 0x0f, 0x0f); + it6621_get_100ms_cnt(priv, &lcf_high); + + if (!(lcf_high - lcf_low)) { + dev_err(priv->dev, "Invalid LCF"); + return -EINVAL; + } + + /* Get tenths */ + tmp = (1000000 - lcf_low) * 16 * 10 / (lcf_high - lcf_low); + timer_1us_flt = tmp % 10; + tmp = tmp / 10; + if (timer_1us_flt >= 5) + *lcf = tmp + 1; + else + *lcf = tmp; + + dev_info(priv->dev, "lcf low: %d, lcf high: %d, lcf: %d\n", + lcf_low, lcf_high, *lcf); + } + + if (*lcf > 15) + *lcf = 15; + + return 0; +} + +static int it6621_get_refclk(struct it6621_priv *priv, unsigned int *refclk) +{ + if (priv->rclk_sel == IT6621_RCLK_FREQ_REFCLK) + *refclk = priv->rclk / 2; + else if (priv->rclk_sel == IT6621_RCLK_FREQ_REFCLK_DIV_2) + *refclk = priv->rclk; + else if (priv->rclk_sel == IT6621_RCLK_FREQ_REFCLK_DIV_4) + *refclk = priv->rclk * 2; + else if (priv->rclk_sel == IT6621_RCLK_FREQ_REFCLK_DIV_8) + *refclk = priv->rclk * 4; + else + *refclk = 0; + + return 0; +} + +int it6621_calc_rclk(struct it6621_priv *priv) +{ + unsigned int timer_1us; + unsigned int timer_1us_int; + unsigned int timer_1us_flt; + unsigned int lcf; + unsigned int aclk_bnd_num; + unsigned int aclk_valid_num; + unsigned int sum; + int ret; + + ret = it6621_get_lcf(priv, &lcf); + if (ret) + return ret; + + regmap_update_bits(priv->regmap, 0xa9, 0x0f, lcf); + + it6621_get_100ms_cnt(priv, &sum); + priv->rclk = sum / 100; + dev_dbg(priv->dev, "RCLK: %uMHz\n", priv->rclk / 1000); + + /* Update 1us timer */ + timer_1us = sum / 100000; + timer_1us_int = timer_1us; + timer_1us_flt = sum % 100000; + timer_1us_flt <<= 8; + timer_1us_flt /= 100000; + regmap_write(priv->regmap, IT6621_REG_GEN4, timer_1us_int); + regmap_write(priv->regmap, IT6621_REG_1US_TIME_FLT, timer_1us_flt); + + if (priv->rclk_sel == IT6621_RCLK_FREQ_REFCLK) + sum /= 2; + else if (priv->rclk_sel == IT6621_RCLK_FREQ_REFCLK_DIV_4) + sum *= 2; + else if (priv->rclk_sel == IT6621_RCLK_FREQ_REFCLK_DIV_8) + sum *= 4; + + aclk_bnd_num = sum * 128 / 358400; + aclk_valid_num = sum * 128 / 200000; + regmap_write(priv->regmap, IT6621_REG_CLK_DET0, aclk_bnd_num & 0xff); + regmap_write(priv->regmap, IT6621_REG_CLK_DET1, + (aclk_bnd_num & 0x100) >> 8); + regmap_write(priv->regmap, IT6621_REG_CLK_DET2, + aclk_valid_num & 0xff); + regmap_write(priv->regmap, IT6621_REG_CLK_DET3, + (aclk_valid_num & 0x300) >> 8); + + return 0; +} + +/** + * it6621_force_pdiv() - If auto mode error , FW force to correct PLL's setting + * @priv: The priv device + * + * Returns zero if succeed. + */ +int it6621_force_pdiv(struct it6621_priv *priv) +{ + unsigned int tbclk_sel; + unsigned int xp_pdiv; + unsigned int xp_gain; + unsigned int val; + unsigned int expect; + + regmap_read(priv->regmap, IT6621_REG_CLK_CTRL1, &val); + tbclk_sel = val & IT6621_TBCLK_SEL; + + regmap_read(priv->regmap, IT6621_REG_TX_AFE1, &val); + xp_pdiv = val & IT6621_TX_XP_PDIV; + xp_gain = (val & IT6621_TX_XP_GAIN) >> 2; + + dev_dbg(priv->dev, "ACLK: %d\n", priv->aclk); + + expect = 0xff; + switch (tbclk_sel) { + case IT6621_TBCLK_AICLK_MUL_32: + if (xp_pdiv != 0) + expect = 0; + break; + case IT6621_TBCLK_AICLK_MUL_16: + if ((priv->aclk < 3584) && (xp_pdiv != 0)) + expect = 0; + else if ((priv->aclk > 3584) && (priv->aclk < 7168) && + (xp_pdiv != 1)) + expect = 1; + break; + case IT6621_TBCLK_AICLK_MUL_8: + if ((priv->aclk < 3584) && (xp_pdiv != 0)) + expect = 0; + else if ((priv->aclk > 3584) && (priv->aclk < 7168) && + (xp_pdiv != 1)) + expect = 1; + else if ((priv->aclk > 7168) && (priv->aclk < 14336) && + (xp_pdiv != 3)) + expect = 3; + break; + case IT6621_TBCLK_AICLK_MUL_4: + if ((priv->aclk < 7168) && xp_pdiv != 0) + expect = 0; + else if ((priv->aclk > 7168) && (priv->aclk < 14336) && + (xp_pdiv != 1)) + expect = 1; + else if ((priv->aclk > 14336) && (priv->aclk < 28672) && + (xp_pdiv != 3)) + expect = 3; + break; + case IT6621_TBCLK_AICLK_MUL_2: + if ((priv->aclk < 14336) && xp_pdiv != 0) + expect = 0; + else if ((priv->aclk > 14336) && (priv->aclk < 28672) && + (xp_pdiv != 1)) + expect = 1; + else if ((priv->aclk > 28672) && (priv->aclk < 57334) && + (xp_pdiv != 3)) + expect = 3; + break; + case IT6621_TBCLK_AICLK: + if ((priv->aclk < 28672) && (xp_pdiv != 0)) + expect = 0; + else if ((priv->aclk > 28672) && (priv->aclk < 57334) && + (xp_pdiv != 1)) + expect = 1; + else if ((priv->aclk > 57334) && (priv->aclk < 114668) && + (xp_pdiv != 3)) + expect = 3; + break; + default: + break; + } + + if (expect != 0xff) + dev_warn(priv->dev, "Wrong XP PDIV, detect %d, expected %d\n", + xp_pdiv, expect); + + expect = 0xff; + switch (tbclk_sel) { + case IT6621_TBCLK_AICLK: + if ((priv->aclk > 3584) && (priv->aclk < 7168) && + (xp_gain != 0)) + expect = 0; + break; + case IT6621_TBCLK_AICLK_MUL_2: + if ((priv->aclk < 3584) && (xp_gain != 0)) + expect = 0; + break; + default: + if (xp_gain != 1) + expect = 1; + break; + } + + if (expect != 0xff) + dev_warn(priv->dev, "Wrong XP GAIN, detect %d, expected %d\n", + xp_gain, expect); + + regmap_read(priv->regmap, IT6621_REG_TX_AFE1, &val); + xp_pdiv = val & IT6621_TX_XP_PDIV; + xp_gain = (val & IT6621_TX_XP_GAIN) >> 2; + dev_dbg(priv->dev, "TBCLK SEL: 0x%02X, XP PDIV: %d, XP GAIN: %d\n", + tbclk_sel, xp_pdiv, xp_gain); + + usleep_range(10000, 11000); + regmap_update_bits(priv->regmap, IT6621_REG_DMAC_CTRL1, + IT6621_TX_MANUAL_RESET_EN_SEL, + IT6621_TX_MANUAL_RESET_EN); + regmap_update_bits(priv->regmap, IT6621_REG_DMAC_CTRL1, + IT6621_TX_MANUAL_RESET_EN_SEL, + IT6621_TX_MANUAL_RESET_DIS); + + return 0; +} + +void it6621_get_aclk(struct it6621_priv *priv) +{ + unsigned int aclk_avg; + unsigned int aclk_pred2; + unsigned int aclk_pred4; + unsigned int aclk_valid; + unsigned int aclk_stb; + unsigned int refclk; + unsigned int tmp; + + it6621_get_refclk(priv, &refclk); + + regmap_read(priv->regmap, IT6621_REG_CLK_DET8, &aclk_avg); + regmap_read(priv->regmap, IT6621_REG_CLK_DET9, &tmp); + aclk_avg += ((tmp & IT6621_DET_ACLK_AVG_HIGH) << 8); + aclk_pred2 = (tmp & IT6621_DET_ACLK_PRE_DIV_2) >> 4; + aclk_pred4 = (tmp & IT6621_DET_ACLK_PRE_DIV_4) >> 5; + aclk_valid = (tmp & IT6621_DET_ACLK_FREQ_VALID) >> 6; + aclk_stb = (tmp & IT6621_DET_ACLK_FREQ_STB) >> 7; + + priv->aclk = refclk * 128 / aclk_avg; + + if (aclk_pred4) + priv->aclk *= 4; + else if (aclk_pred2) + priv->aclk *= 2; + + dev_dbg(priv->dev, "ACLK: %uMHz, valid: %d, stable: %d\n", + priv->aclk / 1000, aclk_valid, aclk_stb); +} + +void it6621_get_bclk(struct it6621_priv *priv) +{ + unsigned int bclk_avg; + unsigned int bclk_pred2; + unsigned int bclk_pred4; + unsigned int bclk_valid; + unsigned int bclk_stb; + unsigned int refclk; + unsigned int tmp; + + it6621_get_refclk(priv, &refclk); + + regmap_read(priv->regmap, IT6621_REG_CLK_DET10, &bclk_avg); + regmap_read(priv->regmap, IT6621_REG_CLK_DET11, &tmp); + bclk_avg += ((tmp & IT6621_DET_BCLK_AVG_HIGH) << 8); + bclk_pred2 = (tmp & IT6621_DET_BCLK_PRE_DIV_2) >> 4; + bclk_pred4 = (tmp & IT6621_DET_BCLK_PRE_DIV_4) >> 5; + bclk_valid = (tmp & IT6621_DET_BCLK_FREQ_VALID) >> 6; + bclk_stb = (tmp & IT6621_DET_BCLK_FREQ_STB) >> 7; + + priv->bclk = refclk * 128 / bclk_avg; + + if (bclk_pred4) + priv->bclk *= 4; + else if (bclk_pred2) + priv->bclk *= 2; + + dev_dbg(priv->dev, "BCLK: %uMHz, valid: %d, stable: %d\n", + priv->bclk / 1000, bclk_valid, bclk_stb); +} diff --git a/sound/soc/codecs/it6621/it6621-clk.h b/sound/soc/codecs/it6621/it6621-clk.h new file mode 100644 index 000000000000..58d825d806b3 --- /dev/null +++ b/sound/soc/codecs/it6621/it6621-clk.h @@ -0,0 +1,18 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (c) 2024 Rockchip Electronics Co. Ltd. + * Author: Jason Zhang + */ + +#ifndef _IT6621_CLK_H +#define _IT6621_CLK_H + +#include "it6621.h" +#include "it6621-earc.h" + +int it6621_calc_rclk(struct it6621_priv *priv); +int it6621_force_pdiv(struct it6621_priv *priv); +void it6621_get_aclk(struct it6621_priv *priv); +void it6621_get_bclk(struct it6621_priv *priv); + +#endif /* _IT6621_CLK_H */ diff --git a/sound/soc/codecs/it6621/it6621-codec.c b/sound/soc/codecs/it6621/it6621-codec.c new file mode 100644 index 000000000000..58f236510013 --- /dev/null +++ b/sound/soc/codecs/it6621/it6621-codec.c @@ -0,0 +1,894 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * it6621-codec.c -- IT6621 ALSA SoC audio codec driver + * + * Copyright (c) 2024 Rockchip Electronics Co. Ltd. + * Author: Jason Zhang + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "it6621.h" +#include "it6621-clk.h" +#include "it6621-earc.h" +#include "it6621-uapi.h" +#include "it6621-reg-bank0.h" +#include "it6621-reg-bank1.h" +#include "it6621-reg-cec.h" + +#define IT6621_I2C_NAME "it6621" + +static const struct regmap_range_cfg it6621_range = { + .range_min = IT6621_REG_VENDOR_ID_LOW, + .range_max = IT6621_REG_TX_PKT3_PB15, + .selector_reg = IT6621_REG_SYS_CTRL3, + .selector_mask = IT6621_BANK_SEL, + .selector_shift = 0, + .window_start = 0, + .window_len = 256, +}; + +static bool it6621_is_accessible_reg(struct device *dev, unsigned int reg) +{ + if (reg >= IT6621_REG_VENDOR_ID_LOW && reg <= IT6621_REG_TX_PKT3_PB15) + return true; + + return false; +} + +static const struct regmap_config it6621_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .max_register = IT6621_REG_TX_PKT3_PB15, + .readable_reg = it6621_is_accessible_reg, + .writeable_reg = it6621_is_accessible_reg, + .ranges = &it6621_range, + .num_ranges = 1, +}; + +static int it6621_set_audio_src(struct it6621_priv *priv) +{ + unsigned int src; + + if (priv->audio_ch >= 15) + src = IT6621_AUD_SRC7_SRC0_EN; + else if (priv->audio_ch >= 13) + src = IT6621_AUD_SRC6_SRC0_EN; + else if (priv->audio_ch >= 11) + src = IT6621_AUD_SRC5_SRC0_EN; + else if (priv->audio_ch >= 9) + src = IT6621_AUD_SRC4_SRC0_EN; + else if (priv->audio_ch >= 7 || priv->i2s_hbr) + src = IT6621_AUD_SRC3_SRC0_EN; + else if (priv->audio_ch >= 5) + src = IT6621_AUD_SRC2_SRC0_EN; + else if (priv->audio_ch >= 3) + src = IT6621_AUD_SRC1_SRC0_EN; + else + src = IT6621_AUD_SRC0_EN; + + /* Set input audio source */ + regmap_update_bits(priv->regmap, IT6621_REG_TX_AUD_SRC_SEL, + IT6621_TX_AUD_SRC, priv->audio_src); + + /* Update source number */ + regmap_write(priv->regmap, IT6621_REG_TX_AUD_SRC_EN, src); + + /* Update ACLK detect after changing source number */ + regmap_update_bits(priv->regmap, IT6621_REG_CLK_DET7, + IT6621_ACLK_DET_EN_SEL, IT6621_ACLK_DET_DIS); + regmap_update_bits(priv->regmap, IT6621_REG_CLK_DET7, + IT6621_ACLK_DET_EN_SEL, IT6621_ACLK_DET_EN); + + return 0; +} + +static int it6621_set_i2s_tdm_fmt(struct it6621_priv *priv) +{ + unsigned int wl; + + if ((priv->i2s_wl == IEC958_AES4_CON_WORDLEN_24_20) || + (priv->i2s_wl == (IEC958_AES4_CON_WORDLEN_20_16 | + IEC958_AES4_CON_MAX_WORDLEN_24))) + wl = IT6621_I2S_TDM_20BIT; + else if (priv->i2s_wl == (IEC958_AES4_CON_WORDLEN_24_20 | + IEC958_AES4_CON_MAX_WORDLEN_24)) + wl = IT6621_I2S_TDM_24BIT; + else + wl = IT6621_I2S_TDM_16BIT; + + regmap_update_bits(priv->regmap, IT6621_REG_TX_I2S, + IT6621_I2S_TDM_WORD_LEN | IT6621_I2S_FMT, + wl | priv->i2s_fmt); + + regmap_update_bits(priv->regmap, IT6621_REG_TX_AUD_CTRL3, + IT6621_TX_I2S_HBR_EN_SEL | IT6621_TX_TDM_CH_NUM, + priv->i2s_hbr | ((priv->audio_ch / 2) - 1)); + + return 0; +} + +static int it6621_set_spdif_fmt(struct it6621_priv *priv) +{ + if (priv->audio_type == IT6621_AUD_TYPE_NLPCM) + regmap_update_bits(priv->regmap, IT6621_REG_DMAC_CTRL1, + IT6621_TX_V_BIT_VAL, IT6621_TX_V_BIT_NLPCM); + else + regmap_update_bits(priv->regmap, IT6621_REG_DMAC_CTRL1, + IT6621_TX_V_BIT_VAL, IT6621_TX_V_BIT_LPCM); + + return 0; +} + +static int it6621_set_auto_audio_fmt(struct it6621_priv *priv) +{ + unsigned int auto_fmt; + + if ((priv->audio_type == IT6621_AUD_TYPE_NLPCM) && + (priv->audio_ch == 8)) { + auto_fmt = IT6621_TX_AUTO_AUD_FMT_DIS; + } else { + /* NOTE: Disable auto audio format in SPDIF */ + if (priv->audio_src == IT6621_AUD_SRC_SPDIF) + auto_fmt = IT6621_TX_AUTO_AUD_FMT_DIS; + else + auto_fmt = IT6621_TX_AUTO_AUD_FMT_EN; + } + + regmap_update_bits(priv->regmap, IT6621_REG_TX_AUD_CTRL10, + IT6621_TX_AUTO_AUD_FMT_SEL, auto_fmt); + + return 0; +} + +static int it6621_set_audio_fmt(struct it6621_priv *priv) +{ + int ret; + + /* Set audio source */ + ret = it6621_set_audio_src(priv); + if (ret < 0) + return ret; + + /* RX I2S/TDM word length */ + ret = it6621_set_i2s_tdm_fmt(priv); + if (ret < 0) + return ret; + + /* SPDIF V bit */ + ret = it6621_set_spdif_fmt(priv); + if (ret < 0) + return ret; + + /* For Compress audio LayoutB */ + ret = it6621_set_auto_audio_fmt(priv); + if (ret < 0) + return ret; + + /* eARC TX Channel Status */ + ret = it6621_set_channel_status(priv); + if (ret < 0) + return ret; + + return 0; +} + +static int it6621_update_config(struct it6621_priv *priv) +{ + if (priv->force_16ch) + priv->audio_ch = 16; + + if ((priv->audio_fs == IT6621_AES3_CON_FS_256000) || + (priv->audio_fs == IT6621_AES3_CON_FS_352000) || + (priv->audio_fs == IT6621_AES3_CON_FS_384000) || + (priv->audio_fs == IT6621_AES3_CON_FS_512000) || + (priv->audio_fs == IT6621_AES3_CON_FS_705000) || + (priv->audio_fs == IEC958_AES3_CON_FS_768000) || + (priv->audio_fs == IT6621_AES3_CON_FS_1024000) || + (priv->audio_fs == IT6621_AES3_CON_FS_1411000) || + (priv->audio_fs == IT6621_AES3_CON_FS_1536000)) + priv->audio_hbr = 1; + else + priv->audio_hbr = 0; + + if (priv->audio_input_hbr == 1) + priv->audio_hbr = 1; + + if (priv->audio_hbr) + priv->audio_type = IT6621_AUD_TYPE_NLPCM; + + if ((priv->audio_src == IT6621_AUD_SRC_I2S) && + priv->audio_hbr && priv->i2s_hbr_enabled) + priv->i2s_hbr = IT6621_TX_I2S_HBR_EN; + else + priv->i2s_hbr = IT6621_TX_I2S_HBR_DIS; + + if ((priv->audio_src == IT6621_AUD_SRC_I2S) && + (priv->audio_type == IT6621_AUD_TYPE_NLPCM)) + priv->i2s_nlpcm_enabled = IT6621_TX_NLPCM_I2S_EN; + else + priv->i2s_nlpcm_enabled = IT6621_TX_NLPCM_I2S_DIS; + + /* NOTE: For Allion AC3 and Allion Astro VG849C test. */ + if ((priv->audio_ch > 2) && + (priv->audio_type == IT6621_AUD_TYPE_NLPCM)) + priv->audio_ch = 2; + + regmap_update_bits(priv->regmap, IT6621_REG_TX_AUD_CTRL10, + IT6621_TX_2CH_LAYOUT_SEL | IT6621_TX_NLPCM_I2S_SEL | + IT6621_TX_MCH_LPCM_SEL | IT6621_TX_EXT_MUTE_SEL, + IT6621_TX_2CH_LAYOUT_DIS | priv->i2s_nlpcm_enabled | + IT6621_TX_MCH_LPCM_DIS | IT6621_TX_EXT_MUTE_EN); + return 0; +} + +static int it6621_reconfig_aclk(struct it6621_priv *priv) +{ + if (((priv->audio_src == IT6621_AUD_SRC_I2S) && priv->sck_inv_enabled) || + ((priv->audio_src == IT6621_AUD_SRC_TDM) && priv->tck_inv_enabled) || + ((priv->audio_src == IT6621_AUD_SRC_SPDIF) && priv->mclk_inv_enabled) || + ((priv->audio_src == IT6621_AUD_SRC_DSD) && priv->dclk_inv_enabled)) + regmap_update_bits(priv->regmap, IT6621_REG_CLK_CTRL2, + IT6621_ACLK_INV_SEL, IT6621_ACLK_INV_EN); + else + regmap_update_bits(priv->regmap, IT6621_REG_CLK_CTRL2, + IT6621_ACLK_INV_SEL, IT6621_ACLK_INV_DIS); + + return 0; +} + +static int it6621_config_audio(struct it6621_priv *priv) +{ + int ret; + + ret = it6621_update_config(priv); + if (ret < 0) + return ret; + + ret = it6621_reconfig_aclk(priv); + if (ret < 0) + return ret; + + ret = it6621_set_audio_fmt(priv); + if (ret < 0) + return ret; + + return 0; +} + +static int it6621_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct it6621_priv *priv = snd_soc_component_get_drvdata(dai->component); + unsigned int state; + + if (substream->stream != SNDRV_PCM_STREAM_PLAYBACK) + return 0; + + set_bit(IT6621_AUDIO_START, &priv->audio_flag); + clear_bit(IT6621_AUDIO_TO_EN_DMAC, &priv->audio_flag); + + it6621_get_ddfsm_state(priv, &state); + + if ((state != IT6621_TX_EARC_MODE) && (state != IT6621_TX_ARC_MODE)) { + cancel_work_sync(&priv->hpdio_work); + schedule_work(&priv->hpdio_work); + } + + priv->config_audio = true; + + return 0; +} + +static int it6621_mute(struct snd_soc_dai *dai, int mute, int stream) +{ + struct it6621_priv *priv = snd_soc_component_get_drvdata(dai->component); + + if (stream != SNDRV_PCM_STREAM_PLAYBACK) + return 0; + + if (!priv->force_mute) + return 0; + + /* FIXME: Sometimes unmuting stream does not work */ + regmap_update_bits(priv->regmap, IT6621_REG_TX_AUD_CTRL10, + IT6621_TX_FORCE_MUTE_SEL, + mute ? IT6621_TX_FORCE_MUTE_EN : + IT6621_TX_FORCE_MUTE_DIS); + + return 0; +} + +static void it6621_shutdown(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct it6621_priv *priv = snd_soc_component_get_drvdata(dai->component); + + clear_bit(IT6621_AUDIO_START, &priv->audio_flag); + clear_bit(IT6621_AUDIO_TO_EN_DMAC, &priv->audio_flag); +} + +static int it6621_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id, + unsigned int freq, int dir) +{ + struct it6621_priv *priv = snd_soc_dai_get_drvdata(dai); + int ret = 0; + + if (!freq) + return 0; + + ret = clk_set_rate(priv->mclk, freq); + if (ret) + dev_err(priv->dev, "failed to set mclk\n"); + + return ret; +} + +static int it6621_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct it6621_priv *priv = snd_soc_dai_get_drvdata(dai); + unsigned int fs; + unsigned int wl; + unsigned int ch; + int ret; + + switch (snd_pcm_rate_to_rate_bit(params_rate(params))) { + case SNDRV_PCM_RATE_32000: + fs = IEC958_AES3_CON_FS_32000; + break; + case SNDRV_PCM_RATE_44100: + fs = IEC958_AES3_CON_FS_44100; + break; + case SNDRV_PCM_RATE_48000: + fs = IEC958_AES3_CON_FS_48000; + break; + case SNDRV_PCM_RATE_64000: + fs = IT6621_AES3_CON_FS_64000; + break; + case SNDRV_PCM_RATE_88200: + fs = IEC958_AES3_CON_FS_88200; + break; + case SNDRV_PCM_RATE_96000: + fs = IEC958_AES3_CON_FS_96000; + break; + case SNDRV_PCM_RATE_176400: + fs = IEC958_AES3_CON_FS_176400; + break; + case SNDRV_PCM_RATE_192000: + fs = IEC958_AES3_CON_FS_192000; + break; + case SNDRV_PCM_RATE_352800: + fs = IT6621_AES3_CON_FS_352000; + break; + case SNDRV_PCM_RATE_384000: + fs = IT6621_AES3_CON_FS_384000; + break; + default: + dev_err(priv->dev, "invalid rate: %d\n", params_rate(params)); + return -EINVAL; + } + + switch (params_format(params)) { + case SNDRV_PCM_FORMAT_S16_LE: + wl = IEC958_AES4_CON_WORDLEN_20_16; + break; + case SNDRV_PCM_FORMAT_S20_3LE: + wl = IEC958_AES4_CON_WORDLEN_24_20; + break; + case SNDRV_PCM_FORMAT_S24_LE: + wl = IEC958_AES4_CON_WORDLEN_24_20 | + IEC958_AES4_CON_MAX_WORDLEN_24; + break; + default: + dev_err(priv->dev, "invalid format: %d\n", + params_format(params)); + return -EINVAL; + } + + switch (params_channels(params)) { + case 32: + case 16: + case 8: + case 6: + case 2: + ch = params_channels(params); + break; + default: + dev_err(priv->dev, "invalid channel: %d\n", + params_channels(params)); + return -EINVAL; + } + + if (priv->config_audio || (priv->audio_fs != fs) || + (priv->i2s_wl != wl) || (priv->audio_ch != ch)) { + priv->audio_fs = fs; + priv->i2s_wl = wl; + priv->audio_ch = ch; + priv->config_audio = false; + + ret = it6621_config_audio(priv); + if (ret) + return ret; + } + + return 0; +} + +static int it6621_probe(struct snd_soc_component *component) +{ + struct it6621_priv *priv; + + priv = snd_soc_component_get_drvdata(component); + priv->mclk = devm_clk_get_optional(component->dev, "mclk"); + + if (IS_ERR(priv->mclk)) + return PTR_ERR(priv->mclk); + + clk_prepare_enable(priv->mclk); + + return 0; +} + +static int it6621_suspend(struct snd_soc_component *component) +{ + struct it6621_priv *priv = snd_soc_component_get_drvdata(component); + + clear_bit(IT6621_ARC_START, &priv->events); + clear_bit(IT6621_EARC_CAP_CHG, &priv->events); + clear_bit(IT6621_EARC_EDID_OK, &priv->events); + clear_bit(IT6621_EARC_BCLK_OK, &priv->events); + + return 0; +} + +static int it6621_resume(struct snd_soc_component *component) +{ + struct it6621_priv *priv = snd_soc_component_get_drvdata(component); + + return it6621_earc_init(priv); +} + +static int it6621_audio_cap_ctl_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES; + uinfo->count = sizeof_field(struct it6621_priv, rxcap); + + return 0; +} + +static int it6621_audio_cap_ctl_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); + struct it6621_priv *priv = snd_soc_component_get_drvdata(component); + + mutex_lock(&priv->rxcap_lock); + memcpy(ucontrol->value.bytes.data, priv->rxcap, sizeof(priv->rxcap)); + mutex_unlock(&priv->rxcap_lock); + + return 0; +} + +static const char *const it6621_ddfsm_enum[] = { "ARC", "eARC", "unknown" }; + +static int it6621_ddfsm_ctl_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + uinfo->count = 1; + uinfo->value.enumerated.items = ARRAY_SIZE(it6621_ddfsm_enum); + + if (uinfo->value.enumerated.item >= ARRAY_SIZE(it6621_ddfsm_enum)) + uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1; + + strscpy(uinfo->value.enumerated.name, + it6621_ddfsm_enum[uinfo->value.enumerated.item], + sizeof(uinfo->value.enumerated.name)); + + return 0; +} + +static int it6621_ddfsm_ctl_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); + struct it6621_priv *priv = snd_soc_component_get_drvdata(component); + unsigned int state; + + it6621_get_ddfsm_state(priv, &state); + + if (state == IT6621_TX_ARC_MODE) + ucontrol->value.enumerated.item[0] = 0; + else if (state == IT6621_TX_EARC_MODE) + ucontrol->value.enumerated.item[0] = 1; + else + ucontrol->value.enumerated.item[0] = 2; + + return 0; +} + +static int it6621_earc_switch_ctl_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; + uinfo->count = 1; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 1; + + return 0; +} + +static int it6621_earc_switch_ctl_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); + struct it6621_priv *priv = snd_soc_component_get_drvdata(component); + + ucontrol->value.integer.value[0] = (priv->earc_enabled == + IT6621_TX_EARC_EN) ? 1 : 0; + + return 0; +} + +static int it6621_earc_switch_ctl_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); + struct it6621_priv *priv = snd_soc_component_get_drvdata(component); + + return it6621_set_earc_enabled(priv, !!ucontrol->value.integer.value[0]); +} + +static int it6621_arc_switch_ctl_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; + uinfo->count = 1; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 1; + + return 0; +} + +static int it6621_arc_switch_ctl_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); + struct it6621_priv *priv = snd_soc_component_get_drvdata(component); + + ucontrol->value.integer.value[0] = (priv->arc_enabled == + IT6621_TX_ARC_EN) ? 1 : 0; + + return 0; +} + +static int it6621_arc_switch_ctl_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); + struct it6621_priv *priv = snd_soc_component_get_drvdata(component); + + return it6621_set_arc_enabled(priv, !!ucontrol->value.integer.value[0]); +} + +static const struct snd_kcontrol_new it6621_controls[] = { + { + .access = (SNDRV_CTL_ELEM_ACCESS_READ | + SNDRV_CTL_ELEM_ACCESS_VOLATILE), + .iface = SNDRV_CTL_ELEM_IFACE_PCM, + .name = "eARC Audio Capabilities", + .info = it6621_audio_cap_ctl_info, + .get = it6621_audio_cap_ctl_get, + }, + { + .access = (SNDRV_CTL_ELEM_ACCESS_READ | + SNDRV_CTL_ELEM_ACCESS_VOLATILE), + .iface = SNDRV_CTL_ELEM_IFACE_PCM, + .name = "eARC DD FSM", + .info = it6621_ddfsm_ctl_info, + .get = it6621_ddfsm_ctl_get, + }, + { + .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | + SNDRV_CTL_ELEM_ACCESS_VOLATILE), + .iface = SNDRV_CTL_ELEM_IFACE_PCM, + .name = "eARC Switch", + .info = it6621_earc_switch_ctl_info, + .get = it6621_earc_switch_ctl_get, + .put = it6621_earc_switch_ctl_put, + }, + { + .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | + SNDRV_CTL_ELEM_ACCESS_VOLATILE), + .iface = SNDRV_CTL_ELEM_IFACE_PCM, + .name = "ARC Switch", + .info = it6621_arc_switch_ctl_info, + .get = it6621_arc_switch_ctl_get, + .put = it6621_arc_switch_ctl_put, + }, +}; + +static const struct snd_soc_component_driver it6621_component = { + .probe = it6621_probe, + .suspend = it6621_suspend, + .resume = it6621_resume, + .controls = it6621_controls, + .num_controls = ARRAY_SIZE(it6621_controls), +}; + +static const struct snd_soc_dai_ops it6621_dai_ops = { + .startup = it6621_startup, + .set_sysclk = it6621_set_dai_sysclk, + .hw_params = it6621_hw_params, + .mute_stream = it6621_mute, + .shutdown = it6621_shutdown, +}; + +#define IT6621_RATES (SNDRV_PCM_RATE_32000 | \ + SNDRV_PCM_RATE_44100 | \ + SNDRV_PCM_RATE_48000 | \ + SNDRV_PCM_RATE_64000 | \ + SNDRV_PCM_RATE_88200 | \ + SNDRV_PCM_RATE_96000 | \ + SNDRV_PCM_RATE_176400 | \ + SNDRV_PCM_RATE_192000 | \ + SNDRV_PCM_RATE_352800 | \ + SNDRV_PCM_RATE_384000) + +#define IT6621_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \ + SNDRV_PCM_FMTBIT_S20_3LE | \ + SNDRV_PCM_FMTBIT_S24_LE) + +static struct snd_soc_dai_driver it6621_dais[] = { + { + .name = "it6621-i2s", + .playback = { + .stream_name = "IT6621 I2S Playback", + .channels_min = 2, + .channels_max = 16, + .rates = IT6621_RATES, + .formats = IT6621_FORMATS, + }, + .ops = &it6621_dai_ops, + }, { + .name = "it6621-spdif", + .playback = { + .stream_name = "IT6621 SPDIF Playback", + .channels_min = 2, + .channels_max = 2, + .rates = IT6621_RATES, + .formats = IT6621_FORMATS, + }, + .ops = &it6621_dai_ops, + }, { + .name = "it6621-dsd", + .playback = { + .stream_name = "IT6621 DSD Playback", + .channels_min = 2, + .channels_max = 12, + .rates = IT6621_RATES, + .formats = IT6621_FORMATS, + }, + .ops = &it6621_dai_ops, + }, +}; + +static int it6621_check_dev(struct it6621_priv *priv) +{ + unsigned int val; + + regmap_bulk_read(priv->regmap, IT6621_REG_VENDOR_ID_LOW, &val, 2); + priv->vid = le16_to_cpu(val); + if (priv->vid != IT6621_VENDOR_ID) { + dev_err(priv->dev, "invalid vendor id %x\n", priv->vid); + return -ENODEV; + } + + regmap_bulk_read(priv->regmap, IT6621_REG_DEV_ID_LOW, &val, 2); + priv->devid = le16_to_cpu(val); + if (priv->devid != IT6621_DEVICE_ID) { + dev_err(priv->dev, "invalid device id %x\n", priv->devid); + return -ENODEV; + } + + regmap_read(priv->regmap, IT6621_REG_REV_ID, &val); + priv->revid = val; + + if ((priv->revid != IT6621_REVISION_VARIANT_B0) && + (priv->revid != IT6621_REVISION_VARIANT_C0) && + (priv->revid != IT6621_REVISION_VARIANT_D0)) { + dev_err(priv->dev, "invalid revision id %x\n", priv->revid); + return -ENODEV; + } + + return 0; +} + +static void it6621_toggle_hpdio(struct it6621_priv *priv) +{ + mutex_lock(&priv->hpdio_lock); + + dev_dbg(priv->dev, "toggle hpdio\n"); + gpiod_set_value_cansleep(priv->hpdio, 0); + /* + * NOTE: Toggle HPD signal at least 100ms (suggestion time is about + * 1 ~ 1.5 second). + */ + msleep(100); + gpiod_set_value_cansleep(priv->hpdio, 1); + + mutex_unlock(&priv->hpdio_lock); +} + +static void it6621_hpdio_work(struct work_struct *work) +{ + struct it6621_priv *priv = container_of(work, struct it6621_priv, + hpdio_work); + + it6621_toggle_hpdio(priv); +} + +static int it6621_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct it6621_priv *priv; + const char *source; + int ret; + + priv = devm_kzalloc(&client->dev, sizeof(struct it6621_priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + dev_set_drvdata(&client->dev, priv); + + priv->client = client; + priv->dev = &client->dev; + priv->regmap = devm_regmap_init_i2c(client, &it6621_regmap_config); + if (IS_ERR(priv->regmap)) { + dev_err(priv->dev, "failed to initialize regmap\n"); + return PTR_ERR(priv->regmap); + } + + ret = it6621_check_dev(priv); + if (ret < 0) + return ret; + + priv->audio_type = IT6621_AUD_TYPE_LPCM; + priv->audio_ch = 0; + priv->audio_fs = IEC958_AES3_CON_FS_NOTID; + priv->i2s_wl = IEC958_AES4_CON_WORDLEN_NOTID; + priv->mch_lpcm_enabled = IT6621_TX_MCH_LPCM_DIS; + priv->layout_2ch_enabled = IT6621_TX_2CH_LAYOUT_DIS; + priv->vcm_sel = IT6621_TX_VCM0; + priv->i2s_fmt = IT6621_I2S_FMT_32BIT; + priv->rclk_sel = IT6621_RCLK_FREQ_REFCLK_DIV_2; + priv->update_avg_enabled = IT6621_UPDATE_AVG_EN; + priv->sck_inv_enabled = 0; + priv->tck_inv_enabled = 1; + priv->mclk_inv_enabled = 1; + priv->dclk_inv_enabled = 0; + priv->cmo_opt = IT6621_TX_CMO_NORMAL; + priv->force_cmo_enabled = IT6621_TX_FORCE_CMO_EN; + priv->resync_opt = IT6621_TX_RESYNC_NEW; + priv->pkt1_enabled = IT6621_TX_PKT1_DIS; + priv->pkt2_enabled = IT6621_TX_PKT2_DIS; + priv->pkt3_enabled = IT6621_TX_PKT3_DIS; + priv->i2s_hbr_enabled = 1; + priv->ubit_opt = IT6621_TX_U_BIT_1BIT_FRAME; + priv->c_ch_opt = IT6621_TX_C_CH_OPT1; + priv->ecc_opt = IT6621_TX_ECC_U_SWAP; + priv->enc_seed = 0xa5c3; + priv->enc_opt = IT6621_TX_ENC_OPT3; + priv->bclk_inv_enabled = IT6621_BCLK_INV_DIS; + priv->nxt_pkt_to_sel = IT6621_TX_NEXT_PKT_TIMEOUT_50US; + priv->turn_over_sel = IT6621_TX_TURN_OVER_16US; + priv->hb_retry_sel = IT6621_TX_HB_RETRY_0MS; + priv->hb_retry_enabled = IT6621_TX_HB_RETRY_EN; + priv->cmd_to_enabled = 0; + priv->enter_arc_now = IT6621_TX_ARC_NOW_DIS; + priv->arc_enabled = IT6621_TX_ARC_EN; + priv->earc_enabled = IT6621_TX_EARC_EN; + INIT_LIST_HEAD(&priv->fhs); + mutex_init(&priv->fhs_lock); + mutex_init(&priv->hpdio_lock); + mutex_init(&priv->rxcap_lock); + INIT_WORK(&priv->hpdio_work, it6621_hpdio_work); + + ret = it6621_uapi_init(priv); + if (ret) { + dev_err(priv->dev, "failed to initialize uapi\n"); + return ret; + } + + ret = devm_add_action_or_reset(priv->dev, + (void(*)(void *))it6621_uapi_remove, + priv); + if (ret) + return ret; + + ret = device_property_read_string(priv->dev, "ite,audio-source", + &source); + if (ret) { + dev_err(priv->dev, "no input audio source\n"); + return ret; + } + + if (!strcmp(source, "i2s")) + priv->audio_src = IT6621_AUD_SRC_I2S; + else if (!strcmp(source, "spdif")) + priv->audio_src = IT6621_AUD_SRC_SPDIF; + else if (!strcmp(source, "tdm")) + priv->audio_src = IT6621_AUD_SRC_TDM; + else if (!strcmp(source, "dsd")) + priv->audio_src = IT6621_AUD_SRC_DSD; + else + return -EINVAL; + + if (device_property_read_bool(priv->dev, "ite,force-arc")) + priv->force_arc = 1; + + if (device_property_read_bool(priv->dev, "ite,force-earc")) + priv->force_earc = 1; + + if (device_property_read_u32(priv->dev, "ite,fixed-lcf", + &priv->fixed_lcf)) + priv->fixed_lcf = 0x00; + + priv->hpdio = devm_gpiod_get_optional(&client->dev, "hpdio", + GPIOD_OUT_LOW); + + ret = it6621_earc_init(priv); + if (ret) + return ret; + + if (client->irq) { + ret = devm_request_threaded_irq(priv->dev, client->irq, NULL, + it6621_irq, + IRQF_TRIGGER_LOW | IRQF_ONESHOT, + "it6621", priv); + if (ret) + return ret; + } + + return devm_snd_soc_register_component(priv->dev, &it6621_component, + it6621_dais, + ARRAY_SIZE(it6621_dais)); +} + +static const struct i2c_device_id it6621_i2c_id[] = { + { IT6621_I2C_NAME, 0 }, + { /* sentinel */ } +}; + +MODULE_DEVICE_TABLE(i2c, it6621_i2c_id); + +static const struct of_device_id it6621_dt_match[] = { + { .compatible = "ite,it6621" }, + { /* sentinel */ }, +}; + +static struct i2c_driver it6621_i2c_driver = { + .driver = { + .name = IT6621_I2C_NAME, + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(it6621_dt_match), + }, + .probe = it6621_i2c_probe, + .id_table = it6621_i2c_id, +}; + +module_i2c_driver(it6621_i2c_driver); + +MODULE_AUTHOR("Jason Zhang "); +MODULE_DESCRIPTION("ASoC IT6621 eARC Driver"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/it6621/it6621-earc.c b/sound/soc/codecs/it6621/it6621-earc.c new file mode 100644 index 000000000000..56d5227f6dd1 --- /dev/null +++ b/sound/soc/codecs/it6621/it6621-earc.c @@ -0,0 +1,1092 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2024 Rockchip Electronics Co. Ltd. + * Author: Jason Zhang + */ + +#include +#include + +#include "it6621.h" +#include "it6621-clk.h" +#include "it6621-earc.h" +#include "it6621-reg-bank0.h" +#include "it6621-reg-bank1.h" +#include "it6621-reg-cec.h" +#include "it6621-uapi.h" + +int it6621_set_channel_status(struct it6621_priv *priv) +{ + unsigned int layout = 0; + unsigned int ca = 0; + unsigned int fmt = 0; + unsigned int wl = 0; + unsigned int fs = 0; + + /* NOTE: Add for Category code */ + regmap_update_bits(priv->regmap, IT6621_REG_TX_CH_ST1, 0xff, + IEC958_AES1_CON_PCM_CODER); + + /* Refer to HDMI2.1 spec table 9-23 and ICE60958-3 p9 */ + if ((priv->audio_type == IT6621_AUD_TYPE_LPCM) && + (priv->audio_ch == 2) && (priv->audio_enc == 0) && + (priv->mch_lpcm_enabled == IT6621_TX_MCH_LPCM_DIS) && + (priv->i2s_nlpcm_enabled == IT6621_TX_NLPCM_I2S_DIS)) + fmt = HDMI_AUDIO_FMT_UN_2CH_LPCM; + else if ((priv->audio_type == IT6621_AUD_TYPE_LPCM) && + (priv->audio_ch == 2) && (priv->audio_enc == 0) && + (priv->mch_lpcm_enabled == IT6621_TX_MCH_LPCM_EN)) + fmt = HDMI_AUDIO_FMT_UN_MCH_LPCM; + else if ((priv->audio_type == IT6621_AUD_TYPE_LPCM) && + (priv->audio_ch > 2) && (priv->audio_enc == 0)) + fmt = HDMI_AUDIO_FMT_UN_MCH_LPCM; + else if ((priv->audio_type == IT6621_AUD_TYPE_DSD) && + (priv->audio_enc == 0)) + fmt = HDMI_AUDIO_FMT_UN_XCH_DSD; + else if ((priv->audio_type == IT6621_AUD_TYPE_NLPCM) && + (priv->audio_enc == 0)) + fmt = HDMI_AUDIO_FMT_UN_2CH_NLPCM; + else if ((priv->audio_type == IT6621_AUD_TYPE_NLPCM) && + (priv->audio_enc == 1)) + fmt = HDMI_AUDIO_FMT_EN_2CH_NLPCM; + else if ((priv->audio_type == IT6621_AUD_TYPE_LPCM) && + (priv->audio_enc == 1)) + fmt = HDMI_AUDIO_FMT_EN_MCH_NLPCM; + else if ((priv->audio_type == IT6621_AUD_TYPE_DSD) && + (priv->audio_enc == 1)) + fmt = HDMI_AUDIO_FMT_EN_XCH_DSD; + else + dev_err(priv->dev, "invalid audio format\n"); + + /* + * NOTE: Software for which copyright is asserted, Channel status mode + * is set to mode 0, and audio format is set with fmt. + */ + regmap_write(priv->regmap, IT6621_REG_TX_CH_ST0, + ((fmt & 0x1c) << 1) | (fmt & 0x03)); + + /* Refer to IEC60958-3 p12 */ + if (priv->audio_src == IT6621_AUD_SRC_DSD) + wl = IEC958_AES4_CON_WORDLEN_NOTID; + else if (priv->audio_type == IT6621_AUD_TYPE_NLPCM) + wl = IEC958_AES4_CON_WORDLEN_20_16; + else + wl = priv->i2s_wl; + + /* NOTE: Set sample word length */ + regmap_update_bits(priv->regmap, IT6621_REG_TX_CH_ST4, 0x0f, wl); + + /* Refer to HDMI2.1 spec table 9-25 and IEC60958-3 p12 */ + if ((priv->audio_type == IT6621_AUD_TYPE_LPCM) && + (priv->audio_ch <= 2)) + layout = HDMI_AUDIO_LAYOUT_LPCM_2CH; + else if ((priv->audio_type == IT6621_AUD_TYPE_LPCM) && + (priv->audio_ch <= 8)) + layout = HDMI_AUDIO_LAYOUT_LPCM_8CH; + else if ((priv->audio_type == IT6621_AUD_TYPE_LPCM) && + (priv->audio_ch <= 16)) + layout = HDMI_AUDIO_LAYOUT_LPCM_16CH; + else if ((priv->audio_type == IT6621_AUD_TYPE_NLPCM) && + (priv->audio_ch <= 2)) + layout = HDMI_AUDIO_LAYOUT_NLPCM_2CH; + else if ((priv->audio_type == IT6621_AUD_TYPE_NLPCM) && + (priv->audio_ch <= 8)) + layout = HDMI_AUDIO_LAYOUT_NLPCM_8CH; + else if ((priv->audio_type == IT6621_AUD_TYPE_DSD) && + (priv->audio_ch <= 6)) + layout = HDMI_AUDIO_LAYOUT_DSD_6CH; + else if ((priv->audio_type == IT6621_AUD_TYPE_DSD) && + (priv->audio_ch <= 12)) + layout = HDMI_AUDIO_LAYOUT_DSD_12CH; + else + dev_err(priv->dev, "invalid layout\n"); + + regmap_write(priv->regmap, IT6621_REG_TX_CH_ST5, layout << 4); + + /* Refer to HDMI2.0 spec, IEC60958-3 p11 and p12 */ + if ((layout == HDMI_AUDIO_LAYOUT_LPCM_2CH) || + (layout == HDMI_AUDIO_LAYOUT_NLPCM_2CH)) { + fs = priv->audio_fs; + } else if ((layout == HDMI_AUDIO_LAYOUT_LPCM_8CH) || + (layout == HDMI_AUDIO_LAYOUT_NLPCM_8CH)) { + if (priv->audio_fs == IEC958_AES3_CON_FS_32000) + fs = IT6621_AES3_CON_FS_128000; + else if (priv->audio_fs == IEC958_AES3_CON_FS_44100) + fs = IEC958_AES3_CON_FS_176400; + else if (priv->audio_fs == IEC958_AES3_CON_FS_48000) + fs = IEC958_AES3_CON_FS_192000; + else if (priv->audio_fs == IT6621_AES3_CON_FS_64000) + fs = IT6621_AES3_CON_FS_256000; + else if (priv->audio_fs == IEC958_AES3_CON_FS_88200) + fs = IT6621_AES3_CON_FS_352000; + else if (priv->audio_fs == IEC958_AES3_CON_FS_96000) + fs = IT6621_AES3_CON_FS_384000; + else if (priv->audio_fs == IT6621_AES3_CON_FS_128000) + fs = IT6621_AES3_CON_FS_512000; + else if (priv->audio_fs == IEC958_AES3_CON_FS_176400) + fs = IT6621_AES3_CON_FS_705000; + else if (priv->audio_fs == IEC958_AES3_CON_FS_192000) + fs = IEC958_AES3_CON_FS_768000; + else + dev_err(priv->dev, "invalid fs and channel\n"); + } else if ((layout == HDMI_AUDIO_LAYOUT_LPCM_16CH) || + (layout == HDMI_AUDIO_LAYOUT_DSD_6CH)) { + if (priv->audio_fs == IEC958_AES3_CON_FS_32000) + fs = IT6621_AES3_CON_FS_256000; + else if (priv->audio_fs == IEC958_AES3_CON_FS_44100) + fs = IT6621_AES3_CON_FS_352000; + else if (priv->audio_fs == IEC958_AES3_CON_FS_48000) + fs = IT6621_AES3_CON_FS_384000; + else if (priv->audio_fs == IT6621_AES3_CON_FS_64000) + fs = IT6621_AES3_CON_FS_512000; + else if (priv->audio_fs == IEC958_AES3_CON_FS_88200) + fs = IT6621_AES3_CON_FS_705000; + else if (priv->audio_fs == IEC958_AES3_CON_FS_96000) + fs = IEC958_AES3_CON_FS_768000; + else + dev_err(priv->dev, "invalid fs and channel\n"); + } else if (layout == HDMI_AUDIO_LAYOUT_DSD_12CH) { + if (priv->audio_fs == IEC958_AES3_CON_FS_32000) + fs = IT6621_AES3_CON_FS_512000; + else if (priv->audio_fs == IEC958_AES3_CON_FS_44100) + fs = IT6621_AES3_CON_FS_705000; + else if (priv->audio_fs == IEC958_AES3_CON_FS_48000) + fs = IEC958_AES3_CON_FS_768000; + else + dev_err(priv->dev, "invalid fs and channel\n"); + } + + regmap_write(priv->regmap, IT6621_REG_TX_CH_ST3, + ((fs & 0x30) << 2) + (fs & 0x0f)); + + /* Refer to HDMI2.1 spec table 9-28 and CTA861-G table 28~30 */ + /* Audio InfoFrame */ + if (priv->audio_ch > 8) { +#ifdef _1QD980ATC_ // for 5-1-60 + ca = 0x00; +#else + /* + * CTA-861-G spec. Section 6.6.3: Delivery According to the + * Speaker Mask (Byte 4 = 0xFE). + */ + ca = 0xfe; +#endif + } else if ((priv->audio_type == IT6621_AUD_TYPE_NLPCM) || + (priv->mch_lpcm_enabled == IT6621_TX_MCH_LPCM_EN) || + (priv->layout_2ch_enabled == IT6621_TX_2CH_LAYOUT_EN)) { + ca = 0x00; + } else { + /* + * CTA-861-G spec. Table 35 Audio InfoFrame Data Byte 4. + * 0x00: FR/FL + * 0x01: FR/FL/LFE1 + * 0x03: FR/FL/LFE1/FC + * 0x07: FR/FL/LFE1/FC/BC + * 0x0B: FR/FL/LFE1/FC/LS/RS + * 0x0F: FR/FL/LFE1/FC/LS/RS/BC + * 0x13: FR/FL/LFE1/FC/LS/RS/RLC/RRC + * 0xff: Channels delivered according to Channel Index + */ + + switch (priv->audio_ch) { + case 0: + ca = 0xff; + break; // no audio + case 2: + ca = 0x00; + break; + case 3: + ca = 0x01; + break; // 0x01,0x02,0x04 + case 4: + ca = 0x03; + break; // 0x03,0x05,0x06,0x08,0x14 + case 5: + ca = 0x07; + break; // 0x07,0x09,0x0A,0x0C,0x15,0x16,0x18 + case 6: + ca = 0x0B; + break; // 0x0B,0x0D,0x0E,0x10,0x17,0x19,0x1A,0x1C + case 7: + ca = 0x0f; + break; // 0x0F,0x11,0x12,0x1B,0x1D,0x1E + case 8: + ca = 0x13; + break; // 0x13,0x1F + default: + break; + } + } + + /* For allocation test 5-1-34, can't use on normal LPCM test */ + if (priv->force_ca & 0x80) { + switch (priv->force_ca) { + case 0x80: + ca = 0x00; + break; // 2ch + case 0x81: + ca = 0x01; + break; // 4ch + case 0x82: + ca = 0x0B; + break; // 6ch + case 0x83: + ca = 0x13; + break; // 8ch + default: + break; + } + + /* Clear for test */ + priv->force_ca = 0; + } + + /* NOTE: Set channel allocation. */ + regmap_write(priv->regmap, IT6621_REG_TX_CH_ST9, ca); + + /* + * NOTE: DM_INH = 0, permitted or no information about any assertion + * of the down mixed stereo output. + * + * LSV3 = 0, LSV2 = 0, LSV1 = 0, LSV1 = 0, Level Shift Value is 0dB. + * + * LFEPBL1 = 0, LFEPBL0 = 0, unknown or refer to other information for + * LFE playback level comparing with other channel signal. + */ + regmap_write(priv->regmap, IT6621_REG_TX_CH_ST10, 0x00); + + if (priv->audio_ch > 8) { + /* + * CTA-861-G spec. Table 29: Audio InfoFrame Format When Byte 4 + * is 0xFE. + * + * Byte 6: FLW/ RLC/ FLC/ BC BL/ FC LFE1 FL/ + * FRW RRC FRC BR FR + * Byte 7: TpSiL/ SiL/ TpBC LFE2 LS/ TpFC TpC TpFL/ + * TpSiR SiR RS TpFR + * Byte 8: F87=0 F86=0 F85=0 F84=0 TpLS/ BtFL/ BtFC TpBL/ + * TpRS BtFR TpBR + */ + /* Set HDMI2.1 channel status */ + regmap_write(priv->regmap, IT6621_REG_TX_CH_ST11, 0x6f); + regmap_write(priv->regmap, IT6621_REG_TX_CH_ST12, 0x0f); + regmap_write(priv->regmap, IT6621_REG_TX_CH_ST13, 0x0c); + } else { + /* Reserved in CTA-861-G spec when Byte 4 is less than 0x32. */ + regmap_write(priv->regmap, IT6621_REG_TX_CH_ST11, 0x00); + regmap_write(priv->regmap, IT6621_REG_TX_CH_ST12, 0x00); + regmap_write(priv->regmap, IT6621_REG_TX_CH_ST13, 0x00); + } + + /* Reserved in CTA-861-G spec. */ + regmap_write(priv->regmap, IT6621_REG_TX_CH_ST14, 0x00); + regmap_write(priv->regmap, IT6621_REG_TX_CH_ST15, 0x00); + + return 0; +} + +int it6621_set_arc_enabled(struct it6621_priv *priv, bool enabled) +{ + priv->arc_enabled = enabled ? IT6621_TX_ARC_EN : IT6621_TX_ARC_DIS; + + regmap_update_bits(priv->regmap, IT6621_REG_TX_DD0, IT6621_TX_ARC_SEL, + priv->arc_enabled); + + return 0; +} + +int it6621_set_earc_enabled(struct it6621_priv *priv, bool enabled) +{ + priv->earc_enabled = enabled ? IT6621_TX_EARC_EN : IT6621_TX_EARC_DIS; + + regmap_update_bits(priv->regmap, IT6621_REG_TX_DD0, IT6621_TX_EARC_SEL, + priv->earc_enabled); + + return 0; +} + +int it6621_set_enter_arc(struct it6621_priv *priv, bool enabled) +{ + unsigned int state; + + if (enabled) { + regmap_update_bits(priv->regmap, IT6621_REG_TX_DD0, + IT6621_TX_ARC_NOW_SEL, + IT6621_TX_ARC_NOW_EN); + it6621_get_ddfsm_state(priv, &state); + if (state != IT6621_TX_ARC_MODE) { + dev_err(priv->dev, "not in ARC mode\n"); + return -EAGAIN; + } + + /* NOTE: ARC only support SPDIF */ + regmap_update_bits(priv->regmap, IT6621_REG_TX_AUD_SRC_SEL, + IT6621_TX_AUD_SRC, IT6621_AUD_SRC_SPDIF); + /* Common mode ARC */ + regmap_update_bits(priv->regmap, IT6621_REG_TX_AFE3, + IT6621_TX_IN_ARC_MODE_SEL, + IT6621_TX_IN_ARC_COMMON_MODE); + regmap_update_bits(priv->regmap, IT6621_REG_TX_AFE3, + IT6621_TX_DRV_CSW_SEL, IT6621_TX_DRV_CSW_7); + dev_dbg(priv->dev, "ARC now enabled\n"); + } else { + regmap_update_bits(priv->regmap, IT6621_REG_TX_DD0, + IT6621_TX_ARC_NOW_SEL, + IT6621_TX_ARC_NOW_DIS); + /* Signal mode ARC */ + regmap_update_bits(priv->regmap, IT6621_REG_TX_AFE3, + IT6621_TX_IN_ARC_MODE_SEL, + IT6621_TX_IN_ARC_SIGNAL_MODE); + regmap_update_bits(priv->regmap, IT6621_REG_TX_AFE3, + IT6621_TX_DRV_CSW_SEL, IT6621_TX_DRV_CSW_4); + dev_dbg(priv->dev, "ARC now disabled\n"); + } + + return 0; +} + +static int it6621_toggle_real_hpd(struct it6621_priv *priv) +{ + /* toggle real HPD at least 100ms */ + /* Set HPDB low */ + regmap_update_bits(priv->regmap, IT6621_REG_SYS_CTRL1, + IT6621_TX_FORCE_HPDB_LOW_SEL, + IT6621_TX_FORCE_HPDB_LOW_EN); + msleep(120); + /* Set HPDB high */ + regmap_update_bits(priv->regmap, IT6621_REG_SYS_CTRL1, + IT6621_TX_FORCE_HPDB_LOW_SEL, + IT6621_TX_FORCE_HPDB_LOW_DIS); + + return 0; +} + +static int it6621_set_auto_mode(struct it6621_priv *priv) +{ + /* auto mode , eARC auto detect */ + regmap_update_bits(priv->regmap, IT6621_REG_TX_DD3, + IT6621_TX_FORCE_ARC_MODE_SEL, + IT6621_TX_FORCE_ARC_MODE_DIS); + + it6621_set_enter_arc(priv, false); + + return it6621_toggle_real_hpd(priv); +} + +static int it6621_force_arc_mode(struct it6621_priv *priv) +{ + /* + * Force ARC mode , close eARC mode. + * Please recover to this HDMI RX's original EDID. + */ + regmap_update_bits(priv->regmap, IT6621_REG_TX_DD3, + IT6621_TX_FORCE_ARC_MODE_SEL, + IT6621_TX_FORCE_ARC_MODE_EN); + + return it6621_toggle_real_hpd(priv); +} + +int it6621_get_ddfsm_state(struct it6621_priv *priv, unsigned int *state) +{ + int ret; + + ret = regmap_read(priv->regmap, IT6621_REG_TX_DD2, state); + *state &= IT6621_TX_DD_FSM_STATE; + + return ret; +} + +static int it6621_wait_cmdc_bus(struct it6621_priv *priv) +{ + unsigned int status; + unsigned int cmdc_state; + unsigned int dd_state; + unsigned int val; + int ret; + + ret = regmap_read_poll_timeout(priv->regmap, IT6621_REG_INT_STATUS1, + status, status & (IT6621_TX_CMD_FAIL | + IT6621_TX_CMD_DONE), + 1000, 10000); + if (ret) { + it6621_get_ddfsm_state(priv, &dd_state); + regmap_read(priv->regmap, IT6621_REG_CMDC1, &val); + cmdc_state = val & IT6621_TX_CMDC_STATE; + dev_err(priv->dev, "timeout! TXDDFSM: %d, TXCMDFSM: %d\n", + dd_state, cmdc_state); + } + + if (status & IT6621_TX_CMD_DONE) { + /* TX init done interrupt */ + regmap_write(priv->regmap, IT6621_REG_INT_STATUS1, + IT6621_TX_CMD_DONE); + return 0; + } + + if (status & IT6621_TX_CMD_FAIL) { + regmap_write(priv->regmap, IT6621_REG_INT_STATUS1, + IT6621_TX_CMD_FAIL); + dev_err(priv->dev, "TX CMD failed\n"); + + regmap_read(priv->regmap, IT6621_REG_CMDC1, &val); + + if (val & IT6621_TX_FAIL_STATE_NO_RESP) + dev_err(priv->dev, "no response\n"); + + if (val & IT6621_TX_FAIL_STATE_UNEXP_RESP) + dev_err(priv->dev, "unexpected response\n"); + + if (val & IT6621_TX_FAIL_STATE_ECC_ERR) + dev_err(priv->dev, "uncorrectable ECC error\n"); + + if (val & IT6621_TX_FAIL_STATE_TIMEOUT) { + if (priv->cmd_to_enabled) + dev_err(priv->dev, + "NACK/RETRY 256 times timeout\n"); + else + dev_err(priv->dev, "NACK command state\n"); + } + } + + return -EAGAIN; +} + +static int it6621_read_cmdc_cmd(struct it6621_priv *priv, unsigned int devid, + unsigned int offset, unsigned int *cmd) +{ + unsigned int state; + + it6621_get_ddfsm_state(priv, &state); + if (state != IT6621_TX_EARC_MODE) { + dev_err(priv->dev, "abort CMDC read\n"); + return -EAGAIN; + } + + /* Data FIFO Clear */ + regmap_update_bits(priv->regmap, IT6621_REG_CMDC3, + IT6621_TX_DATA_FIFO_CLEAR, + IT6621_TX_DATA_FIFO_CLEAR); + /* TxCmd DevID */ + regmap_write(priv->regmap, IT6621_REG_TX_DEV_ID, devid); + /* TxCmd Offset */ + regmap_write(priv->regmap, IT6621_REG_TX_OFFSET, offset); + /* Read Trigger (1-byte) */ + regmap_write(priv->regmap, IT6621_REG_CMDC2, IT6621_TX_READ_TRIGGER); + + it6621_wait_cmdc_bus(priv); + + return regmap_read(priv->regmap, IT6621_REG_TX_DATA_FIFO, cmd); +} + +static void it6621_write_cmdc_cmd(struct it6621_priv *priv, unsigned int devid, + unsigned int offset, unsigned int data) +{ + unsigned int state; + + it6621_get_ddfsm_state(priv, &state); + if (state != IT6621_TX_EARC_MODE) { + dev_err(priv->dev, "abort CMDC write\n"); + return; + } + + /* Data FIFO Clear */ + regmap_update_bits(priv->regmap, IT6621_REG_CMDC3, + IT6621_TX_DATA_FIFO_CLEAR, + IT6621_TX_DATA_FIFO_CLEAR); + /* TxCmd DevID */ + regmap_write(priv->regmap, IT6621_REG_TX_DEV_ID, devid); + /* TxCmd Offset */ + regmap_write(priv->regmap, IT6621_REG_TX_OFFSET, offset); + /* TxCmd WrData */ + regmap_write(priv->regmap, IT6621_REG_TX_DATA_FIFO, data); + /* Write Trigger (1-byte) */ + regmap_write(priv->regmap, IT6621_REG_CMDC2, IT6621_TX_WRITE_TRIGGER); + + it6621_wait_cmdc_bus(priv); +} + +static int it6621_read_cmdc_bulk(struct it6621_priv *priv, unsigned int devid, + unsigned int offset, size_t len, void *data) +{ + unsigned int state; + int ret; + + it6621_get_ddfsm_state(priv, &state); + if (state != IT6621_TX_EARC_MODE) { + dev_err(priv->dev, "abort CMDC bulk read\n"); + return -EAGAIN; + } + + /* Data FIFO Clear */ + regmap_update_bits(priv->regmap, IT6621_REG_CMDC3, + IT6621_TX_DATA_FIFO_CLEAR, + IT6621_TX_DATA_FIFO_CLEAR); + /* TxCmd DevID */ + regmap_write(priv->regmap, IT6621_REG_TX_DEV_ID, devid); + /* TxCmd Offset */ + regmap_write(priv->regmap, IT6621_REG_TX_OFFSET, offset); + /* Read Trigger & Read ByteNum[4:0] */ + regmap_write(priv->regmap, IT6621_REG_CMDC2, + IT6621_TX_READ_TRIGGER | (len - 1)); + + ret = it6621_wait_cmdc_bus(priv); + if (ret) + return ret; + + regmap_noinc_read(priv->regmap, IT6621_REG_TX_DATA_FIFO, data, len); + + return 0; +} + +/** + * it6621_set_latency - eARC TX Set latency request + * + * @latency: latency in marco second, range from 0 to 250 ms. + */ +static void it6621_set_latency(struct it6621_priv *priv, unsigned int latency) +{ + it6621_write_cmdc_cmd(priv, 0x74, 0xd3, latency); +} + +/** + * it6621_get_latency - Read eARC RX's Latency + * + * @latency: latency in marco second, range from 0 to 250 ms. + */ +static int it6621_get_latency(struct it6621_priv *priv, unsigned int *latency) +{ + return it6621_read_cmdc_cmd(priv, 0x74, 0xd2, latency); +} + +/** + * it6621_reset_driver - should be set power down in ARC mode + * + * @on: power on/down differential mode signal. + */ +static void it6621_reset_driver(struct it6621_priv *priv, bool enabled) +{ + dev_dbg(priv->dev, "set TX driver %s\n", enabled ? "on" : "off"); + + if (enabled) + regmap_update_bits(priv->regmap, IT6621_REG_TX_AFE2, + IT6621_TX_DRV_RESET_SEL, + IT6621_TX_DRV_RESET_DIS); + else + regmap_update_bits(priv->regmap, IT6621_REG_TX_AFE2, + IT6621_TX_DRV_RESET_SEL, + IT6621_TX_DRV_RESET_EN); +} + +static int it6621_check_audio(struct it6621_priv *priv) +{ + unsigned int val; + + if (test_bit(IT6621_AUDIO_TO_EN_DMAC, &priv->audio_flag) && + test_bit(IT6621_AUDIO_START, &priv->audio_flag)) { + if (test_bit(IT6621_EARC_BCLK_OK, &priv->events)) { + /* Need to be finetune at diff platform */ + msleep(50); + it6621_reset_driver(priv, true); + clear_bit(IT6621_EARC_BCLK_OK, &priv->events); + clear_bit(IT6621_AUDIO_TO_EN_DMAC, &priv->audio_flag); + regmap_read(priv->regmap, IT6621_REG_TX_AFE2, &val); + dev_dbg(priv->dev, "A2: 0x%02x\n", val); + } + + if (priv->force_arc) + it6621_set_enter_arc(priv, true); + } + + return 0; +} + +int it6621_earc_init(struct it6621_priv *priv) +{ + priv->state = IT6621_EARC_IDLE; + priv->rclk = 0; + priv->aclk = 0; + priv->bclk = 0; + + /* Enable GRCLK */ + regmap_update_bits(priv->regmap, IT6621_REG_CLK_CTRL0, + IT6621_GATE_RCLK_SEL, IT6621_GATE_RCLK_DIS); + + /* TXAFE PLL Reset */ + regmap_update_bits(priv->regmap, IT6621_REG_TX_AFE0, + IT6621_TX_XP_RESET_SEL, IT6621_TX_XP_RESET_ACTIVE); + + /* eARCTX Reset */ + regmap_update_bits(priv->regmap, IT6621_REG_SYS_RESET, + IT6621_SW_RCLK_RESET_SEL, IT6621_SW_RCLK_RESET_EN); + + regmap_update_bits(priv->regmap, IT6621_REG_CLK_CTRL0, + IT6621_RCLK_FREQ_SEL, priv->rclk_sel); + + regmap_update_bits(priv->regmap, IT6621_REG_CLK_DET7, + IT6621_ACLK_DET_EN_SEL, IT6621_ACLK_DET_DIS); + regmap_update_bits(priv->regmap, IT6621_REG_CLK_DET7, + IT6621_UPDATE_AVG_EN_SEL, priv->update_avg_enabled); + regmap_update_bits(priv->regmap, IT6621_REG_CMDC4, + IT6621_TX_HB_RETRY_TIME_SEL | + IT6621_TX_HB_RETRY_SEL, + priv->hb_retry_sel | priv->hb_retry_enabled); + /* NOTE: Disable to pass SL-870 HFR5-1-35/36/37 */ + regmap_update_bits(priv->regmap, IT6621_REG_CMDC5, + IT6621_TX_AUTO_WRITE_STATE_SEL, + IT6621_TX_AUTO_WRITE_STATE_DIS); + regmap_update_bits(priv->regmap, IT6621_REG_DMAC_CTRL0, + IT6621_TX_ENC_OPT | IT6621_TX_ENC_SEL | + IT6621_TX_ECC_OPT, + priv->enc_opt | (priv->audio_enc << 3) | + priv->ecc_opt); + regmap_write(priv->regmap, IT6621_REG_TX_ENC_SEED_LOW, + priv->enc_seed & 0xff); + regmap_write(priv->regmap, IT6621_REG_TX_ENC_SEED_HIGH, + (priv->enc_seed & 0xff00) >> 8); + regmap_update_bits(priv->regmap, IT6621_REG_DMAC_CTRL1, + IT6621_TX_U_BIT_OPT | IT6621_TX_C_CH_OPT | + IT6621_TX_PKT3_EN_SEL | IT6621_TX_PKT2_EN_SEL | + IT6621_TX_PKT1_EN_SEL, + priv->ubit_opt | priv->c_ch_opt | + priv->pkt3_enabled | priv->pkt2_enabled | + priv->pkt1_enabled); + regmap_update_bits(priv->regmap, IT6621_REG_CMDC6, + IT6621_TX_RESYNC_OPT | IT6621_TX_FORCE_CMO_OPT | + IT6621_TX_CMO_OPT, + priv->resync_opt | priv->force_cmo_enabled | + priv->cmo_opt); + regmap_update_bits(priv->regmap, IT6621_REG_CMDC0, + IT6621_TX_TURN_OVER_SEL | + IT6621_TX_NEXT_PKT_TIMEOUT_SEL, + priv->turn_over_sel | + priv->nxt_pkt_to_sel); + regmap_update_bits(priv->regmap, IT6621_REG_TX_AUD_CTRL10, + IT6621_TX_2CH_LAYOUT_SEL | IT6621_TX_NLPCM_I2S_SEL | + IT6621_TX_MCH_LPCM_SEL | IT6621_TX_EXT_MUTE_SEL, + priv->layout_2ch_enabled | priv->i2s_nlpcm_enabled | + priv->mch_lpcm_enabled | IT6621_TX_EXT_MUTE_DIS); + regmap_update_bits(priv->regmap, IT6621_REG_CLK_CTRL2, + IT6621_BCLK_INV_SEL | IT6621_ACLK_INV_SEL, + priv->bclk_inv_enabled | IT6621_ACLK_INV_DIS); + regmap_update_bits(priv->regmap, IT6621_REG_TX_DD0, + IT6621_TX_ARC_NOW_SEL | IT6621_TX_ARC_SEL | + IT6621_TX_EARC_SEL, + priv->enter_arc_now | priv->arc_enabled | + priv->earc_enabled); + + if (priv->force_arc) + regmap_update_bits(priv->regmap, IT6621_REG_TX_DD3, + IT6621_TX_FORCE_ARC_MODE_SEL, + IT6621_TX_FORCE_ARC_MODE_EN); + else + regmap_update_bits(priv->regmap, IT6621_REG_TX_DD3, + IT6621_TX_FORCE_ARC_MODE_SEL, + IT6621_TX_FORCE_ARC_MODE_DIS); + + /* test to disable TxXPLOCKChgInt */ + regmap_write(priv->regmap, IT6621_REG_INT_EN0, + IT6621_TX_RESYNC_ERR_EN | IT6621_TX_NO_AUD_CHANGE_EN | + IT6621_TX_DISV_TIMEOUT_EN | IT6621_TX_HB_LOST_EN | + IT6621_TX_STATE3_CHANGE_EN | IT6621_TX_HPDIO_OFF_EN | + IT6621_TX_HPDIO_ON_EN); + regmap_write(priv->regmap, IT6621_REG_INT_EN1, + IT6621_TX_CMD_DONE_EN | IT6621_TX_CMD_FAIL_EN | + IT6621_TX_READ_STATE_CHG_EN | IT6621_TX_CMDC_BP_ERR_EN | + IT6621_TX_WRITE_STATE_CHG_EN | IT6621_TX_WRITE_CAP_CHG_EN | + IT6621_TX_HB_FAIL_EN); + regmap_write(priv->regmap, IT6621_REG_INT_EN2, + IT6621_TX_MUTE_CHANGE_EN | IT6621_TX_SPDIF_CHANGE_EN | + IT6621_TX_SPDIF_READY_EN | IT6621_TX_DEC_ERR_EN | + IT6621_TX_FIFO_ERR_EN); + /* enable RX HPD interrupt for HPDB interrupt */ + regmap_write(priv->regmap, IT6621_REG_INT_EN3, + IT6621_TX_HPDB_OFF_EN | IT6621_TX_HPDB_ON_EN); + regmap_write(priv->regmap, IT6621_REG_INT_EN4, + IT6621_DET_NO_BCLK_EN | IT6621_DET_BCLK_VALID_EN | + IT6621_DET_BCLK_STABLE_EN | IT6621_DET_ACLK_VALID_EN | + IT6621_DET_ACLK_STABLE_EN); + regmap_update_bits(priv->regmap, 0xa9, 0xFF, 0xFD); + it6621_calc_rclk(priv); + + /* enable ACLK detection */ + regmap_update_bits(priv->regmap, IT6621_REG_CLK_DET7, + IT6621_ACLK_DET_EN_SEL, IT6621_ACLK_DET_EN); + + /* RTxDbgFifoClr */ + regmap_update_bits(priv->regmap, IT6621_REG_TX_DEBUG_FIFO2, + IT6621_TX_DEBUG_FIFO_CLEAR_SEL, + IT6621_TX_DEBUG_FIFO_CLEAR_EN); + regmap_update_bits(priv->regmap, IT6621_REG_TX_AFE1, + IT6621_TX_XP_ER0_SEL | IT6621_TX_XP_DEI_SEL, + IT6621_TX_XP_ER0_DIS | IT6621_TX_XP_DEI_DIS); + if (priv->revid == IT6621_REVISION_VARIANT_C0) { + /* + * NOTE: In eARC mode, change DMAC back to B0 version, + * DRV_OT_SEL set to 1 for C0,TX_HYS_SEL = 5 for C0 + */ + regmap_update_bits(priv->regmap, IT6621_REG_TX_AFE2, + IT6621_TX_DRV_OT_SEL | + IT6621_TX_DRV_DSW_SEL | + IT6621_TX_DRV_DC, + IT6621_TX_DRV_OT_EN | + IT6621_TX_DRV_DSW_4 | + IT6621_TX_DRV_DC_SEL_DIS | + IT6621_TX_DRV_DC_DIS); + regmap_update_bits(priv->regmap, IT6621_REG_TX_AFE4, + IT6621_TX_HYS_SEL | + IT6621_TX_VCM_SEL | + IT6621_TX_RC_CK_SEL, + IT6621_TX_HYS5 | + priv->vcm_sel | + IT6621_TX_RC_CK_DIS); + } else if (priv->revid == IT6621_REVISION_VARIANT_D0) { + regmap_update_bits(priv->regmap, IT6621_REG_TX_AFE2, + IT6621_TX_DRV_OT_SEL | + IT6621_TX_DRV_DSW_SEL | + IT6621_TX_DRV_DC, + IT6621_TX_DRV_OT_EN | + IT6621_TX_DRV_DSW_7 | + IT6621_TX_DRV_DC_SEL_DIS | + IT6621_TX_DRV_DC_DIS); + regmap_update_bits(priv->regmap, IT6621_REG_TX_AFE4, + IT6621_TX_HYS_SEL | + IT6621_TX_VCM_SEL | + IT6621_TX_RC_CK_SEL, + IT6621_TX_HYS5 | + priv->vcm_sel | + IT6621_TX_RC_CK_DIS); + } else { + /* + * NOTE: DRV_OT_SEL set to 0 force TM tri-state in + * ARC single mode (B0). + */ + regmap_update_bits(priv->regmap, IT6621_REG_TX_AFE2, + IT6621_TX_DRV_OT_SEL | + IT6621_TX_DRV_DSW_SEL, + IT6621_TX_DRV_OT_DIS | + IT6621_TX_DRV_DSW_4); + regmap_update_bits(priv->regmap, IT6621_REG_TX_AFE4, + IT6621_TX_HYS_SEL | + IT6621_TX_VCM_SEL | + IT6621_TX_RC_CK_SEL, + IT6621_TX_HYS6 | + priv->vcm_sel | + IT6621_TX_RC_CK_DIS); + } + + /* For D0 TX_DRV_CSR */ + if (priv->revid == IT6621_REVISION_VARIANT_D0) + regmap_update_bits(priv->regmap, IT6621_REG_TX_AFE3, + IT6621_TX_DRV_CSW_SEL | + IT6621_TX_DRV_CSR_SEL, + IT6621_TX_DRV_CSW_4 | + IT6621_TX_DRV_CSR_2); + else + regmap_update_bits(priv->regmap, IT6621_REG_TX_AFE3, + IT6621_TX_DRV_CSW_SEL | + IT6621_TX_DRV_CSR_SEL, + IT6621_TX_DRV_CSW_4 | + IT6621_TX_DRV_CSR_4); + + regmap_update_bits(priv->regmap, IT6621_REG_SYS_RESET, + IT6621_SW_RCCLK_RESET_SEL | + IT6621_SW_TCCLK_RESET_SEL | + IT6621_SW_BCLK_RESET_SEL | + IT6621_SW_ACLK_RESET_SEL, + IT6621_SW_RCCLK_RESET_DIS | + IT6621_SW_TCCLK_RESET_DIS | + IT6621_SW_BCLK_RESET_DIS | + IT6621_SW_ACLK_RESET_DIS); + + /* Enable eARC TX Discovery and Disconnect FSM */ + regmap_update_bits(priv->regmap, IT6621_REG_TX_DD0, + IT6621_TX_DD_FSM_SEL, IT6621_TX_DD_FSM_EN); + + if (priv->force_arc) { + dev_info(priv->dev, "force ARC mode\n"); + it6621_force_arc_mode(priv); + } + + if (priv->force_earc) { + dev_info(priv->dev, "force eARC mode\n"); + it6621_set_auto_mode(priv); + } + + return 0; +} + +static int it6621_read_rxcap(struct it6621_priv *priv) +{ + u8 rxcap[IT6621_RX_CAP_MAX_LEN]; + int i; + int ret; + + /* Enable eARC TX Command Done/Fail Interrupt */ + regmap_update_bits(priv->regmap, IT6621_REG_INT_EN1, + IT6621_TX_CMD_FAIL_SEL | IT6621_TX_CMD_DONE_SEL, + IT6621_TX_CMD_FAIL_EN | IT6621_TX_CMD_DONE_EN); + + for (i = 0; i < 255; i += IT6621_RXCAP_BULK_LEN) { + ret = it6621_read_cmdc_bulk(priv, 0xa0, i, + IT6621_RXCAP_BULK_LEN, &rxcap[i]); + if (ret) { + dev_err(priv->dev, "failed to read eARC RX Cap\n"); + return ret; + } + } + + mutex_lock(&priv->rxcap_lock); + + if (memcmp(rxcap, priv->rxcap, sizeof(priv->rxcap))) { + memcpy(priv->rxcap, rxcap, sizeof(priv->rxcap)); + set_bit(IT6621_EARC_CAP_CHG, &priv->events); + } + + mutex_unlock(&priv->rxcap_lock); + + return 0; +} + +static void it6621_set_state(struct it6621_priv *priv, unsigned int state) +{ + if (priv->state != state) { + priv->state = state; + it6621_uapi_msg(priv, IT6621_EVENT_STATE_CHANGE, &priv->state, + sizeof(priv->state)); + } +} + +static int it6621_check_rxcap(struct it6621_priv *priv) +{ + if (test_bit(IT6621_EARC_CAP_CHG, &priv->events)) { + clear_bit(IT6621_EARC_CAP_CHG, &priv->events); + it6621_uapi_msg(priv, IT6621_EVENT_AUDIO_CAP_CHANGE, + priv->rxcap, sizeof(priv->rxcap)); + cancel_work_sync(&priv->hpdio_work); + schedule_work(&priv->hpdio_work); + } + + return 0; +} + +static int it6621_earc_irq(struct it6621_priv *priv) +{ + unsigned int status0; + unsigned int status1; + unsigned int status2; + unsigned int status3; + unsigned int status4; + unsigned int state; + unsigned int val; + unsigned int latency = 0; + + regmap_read(priv->regmap, IT6621_REG_INT_STATUS0, &status0); + regmap_read(priv->regmap, IT6621_REG_INT_STATUS1, &status1); + regmap_read(priv->regmap, IT6621_REG_INT_STATUS2, &status2); + regmap_read(priv->regmap, IT6621_REG_INT_STATUS3, &status3); + regmap_read(priv->regmap, IT6621_REG_INT_STATUS4, &status4); + regmap_write(priv->regmap, IT6621_REG_INT_STATUS0, status0); + regmap_write(priv->regmap, IT6621_REG_INT_STATUS1, status1); + regmap_write(priv->regmap, IT6621_REG_INT_STATUS2, status2); + status3 &= IT6621_TX_HPDB_OFF | IT6621_TX_HPDB_ON; + regmap_write(priv->regmap, IT6621_REG_INT_STATUS3, status3); + regmap_write(priv->regmap, IT6621_REG_INT_STATUS4, status4); + + /* Interrupt status0 */ + if (status0 & IT6621_TX_HPDIO_ON) { + dev_dbg(priv->dev, "HPD IO on\n"); + /* Set HPDB low clear */ + regmap_update_bits(priv->regmap, IT6621_REG_SYS_CTRL1, + IT6621_TX_FORCE_HPDB_LOW_SEL, + IT6621_TX_FORCE_HPDB_LOW_DIS); + } + + if (status0 & IT6621_TX_HPDIO_OFF) { + dev_dbg(priv->dev, "HPD IO off\n"); + + if (test_bit(IT6621_ARC_START, &priv->events)) + it6621_set_enter_arc(priv, false); + + /* Set HPDB low */ + if (!priv->toggle_by_edid) + regmap_update_bits(priv->regmap, + IT6621_REG_SYS_CTRL1, + IT6621_TX_FORCE_HPDB_LOW_SEL, + IT6621_TX_FORCE_HPDB_LOW_EN); + else + priv->toggle_by_edid = 0; + + clear_bit(IT6621_ARC_START, &priv->events); + } + + if (status0 & IT6621_TX_STATE3_CHANGE) { + dev_dbg(priv->dev, "eARC enable\n"); + + it6621_get_ddfsm_state(priv, &state); + dev_dbg(priv->dev, "eARC stat3 change to %d\n", + state & IT6621_TX_EARC_MODE ? 1 : 0); + clear_bit(IT6621_ARC_START, &priv->events); + + if (state & IT6621_TX_EARC_MODE) + it6621_set_state(priv, IT6621_EARC_CONNECTED); + else + regmap_update_bits(priv->regmap, IT6621_REG_TX_AFE2, + IT6621_TX_DRV_RESET_SEL, + IT6621_TX_DRV_RESET_EN); + } + + if (status0 & IT6621_TX_HB_LOST) { + dev_dbg(priv->dev, "heartbeat lost\n"); + regmap_update_bits(priv->regmap, IT6621_REG_TX_AFE2, + IT6621_TX_DRV_RESET_SEL, + IT6621_TX_DRV_RESET_EN); + } + + if (status0 & IT6621_TX_DISV_TIMEOUT) { + dev_dbg(priv->dev, "discovery timeout\n"); + + priv->events = 0; + set_bit(IT6621_ARC_START, &priv->events); + it6621_set_state(priv, IT6621_ARC_PENDING); + } + + if (status0 & IT6621_TX_NO_AUD_CHANGE) { + regmap_read(priv->regmap, IT6621_REG_SYS_STATUS, &val); + val &= IT6621_TX_NO_AUDIO; + dev_dbg(priv->dev, "TX has %s audio stream\n", val ? "no" : ""); + } + + if (status0 & IT6621_TX_XP_LOCK_CHANGE) { + regmap_read(priv->regmap, IT6621_REG_SYS_STATUS, &val); + val &= IT6621_TX_XP_LOCK; + dev_dbg(priv->dev, "XP lock: %d\n", val >> 2); + } + + if (status0 & IT6621_TX_RESYNC_ERR) + dev_err(priv->dev, "CMDC resync error\n"); + + /* Interrupt status1 */ + if (status1 & IT6621_TX_CMD_DONE) + dev_dbg(priv->dev, "Cmd Done\n"); + + if (status1 & IT6621_TX_HB_DONE) + dev_dbg(priv->dev, "heartbeat done\n"); + + if (status1 & IT6621_TX_READ_STATE_CHANGE) { + regmap_read(priv->regmap, IT6621_REG_TX_READ_STATE, &val); + dev_dbg(priv->dev, "RX state change to 0x%02X\n", val); + val &= 0x18; + regmap_update_bits(priv->regmap, IT6621_REG_CMDC5, 0x18, val); + } + + if (status1 & IT6621_TX_CMDC_BP_ERR) + dev_err(priv->dev, "CMDC bi-phase error\n"); + + if (status1 & IT6621_TX_WRITE_STATE_CHANGE) { + it6621_get_latency(priv, &latency); + dev_dbg(priv->dev, "auto write STAT_CHNG 1->0 done\n"); + dev_dbg(priv->dev, "latency: 0x%02X ms\n", latency); + } + + if (status1 & IT6621_TX_WRITE_CAP_CHANGE) { + dev_dbg(priv->dev, "auto write CAP_CHNG 1->0 done\n"); + it6621_read_rxcap(priv); + + if (priv->audio_enc) { + it6621_write_cmdc_cmd(priv, 0x9c, 0x10, + priv->enc_opt >> 4); + it6621_write_cmdc_cmd(priv, 0x9c, 0x11, + priv->enc_seed & 0xff); + it6621_write_cmdc_cmd(priv, 0x9c, 0x12, + (priv->enc_seed & 0xff00) >> 8); + } + + /* Write 140ms to ERX_LATENCY_REQ */ + it6621_set_latency(priv, 140); + regmap_read(priv->regmap, IT6621_REG_TX_AFE2, &val); + val &= IT6621_TX_DRV_RESET_SEL; + dev_dbg(priv->dev, "TX driver reset: %d\n", val >> 1); + } + + if (status1 & IT6621_TX_HB_FAIL) + dev_dbg(priv->dev, "heartbeat fail\n"); + + /* Interrupt status2 */ + if (status2 & IT6621_TX_FIFO_ERR) + dev_dbg(priv->dev, "audio FIFO error\n"); + + if (status2 & IT6621_TX_DEC_ERR) + dev_dbg(priv->dev, "audio decode error\n"); + + if (status2 & IT6621_TX_SPDIF_READY) + dev_dbg(priv->dev, "SPDIF channel status is ready\n"); + + if (status2 & IT6621_TX_SPDIF_CHANGE) + dev_dbg(priv->dev, "SPDIF channel status is changed\n"); + + if (status2 & IT6621_TX_MUTE_CHANGE) { + regmap_read(priv->regmap, IT6621_REG_SYS_STATUS, &val); + val &= IT6621_TX_MUTE; + dev_dbg(priv->dev, "input is %s\n", val ? "muted" : "unmuted"); + } + + /* Interrupt status3 */ + if (status3 & IT6621_TX_HPDB_ON) { + dev_dbg(priv->dev, "HPD bus on\n"); + it6621_set_state(priv, IT6621_EARC_PENDING); + } + + if (status3 & IT6621_TX_HPDB_OFF) { + dev_dbg(priv->dev, "HPD bus off\n"); + regmap_update_bits(priv->regmap, IT6621_REG_TX_AFE2, + IT6621_TX_DRV_RESET_SEL, + IT6621_TX_DRV_RESET_EN); + + if (test_bit(IT6621_ARC_START, &priv->events)) + it6621_set_enter_arc(priv, false); + + clear_bit(IT6621_ARC_START, &priv->events); + it6621_set_state(priv, IT6621_EARC_IDLE); + } + + /* Interrupt status4 */ + if (status4 & IT6621_DET_ACLK_STABLE) { + dev_dbg(priv->dev, "ACLK is stable\n"); + it6621_get_aclk(priv); + it6621_force_pdiv(priv); + } + + if (status4 & IT6621_DET_ACLK_VALID) + dev_dbg(priv->dev, "ACLK is valid\n"); + + if (status4 & IT6621_DET_NO_BCLK) { + dev_dbg(priv->dev, "BCLK is not present\n"); + clear_bit(IT6621_EARC_BCLK_OK, &priv->events); + it6621_reset_driver(priv, false); + } + + if (status4 & IT6621_DET_BCLK_STABLE) { + dev_dbg(priv->dev, "BCLK is stable\n"); + it6621_get_bclk(priv); + set_bit(IT6621_EARC_BCLK_OK, &priv->events); + if (test_bit(IT6621_AUDIO_START, &priv->audio_flag)) + set_bit(IT6621_AUDIO_TO_EN_DMAC, &priv->audio_flag); + } + + if (status4 & IT6621_DET_BCLK_VALID) + dev_dbg(priv->dev, "BCLK is valid\n"); + + return 0; +} + +irqreturn_t it6621_irq(int irq, void *data) +{ + struct it6621_priv *priv = data; + + it6621_earc_irq(priv); + + it6621_check_audio(priv); + it6621_check_rxcap(priv); + + return IRQ_HANDLED; +} diff --git a/sound/soc/codecs/it6621/it6621-earc.h b/sound/soc/codecs/it6621/it6621-earc.h new file mode 100644 index 000000000000..c4f0f430e1b0 --- /dev/null +++ b/sound/soc/codecs/it6621/it6621-earc.h @@ -0,0 +1,62 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (c) 2024 Rockchip Electronics Co. Ltd. + * Author: Jason Zhang + */ + +#ifndef _IT6621_EARC_H +#define _IT6621_EARC_H + +#include "it6621.h" + +#define IT6621_AES3_CON_FS_64000 0x0b +#define IT6621_AES3_CON_FS_128000 0x2b +#define IT6621_AES3_CON_FS_256000 0x1b +#define IT6621_AES3_CON_FS_352000 0x0d +#define IT6621_AES3_CON_FS_384000 0x05 +#define IT6621_AES3_CON_FS_512000 0x3b +#define IT6621_AES3_CON_FS_705000 0x2d +#define IT6621_AES3_CON_FS_1024000 0x35 +#define IT6621_AES3_CON_FS_1411000 0x1d +#define IT6621_AES3_CON_FS_1536000 0x15 + +#define IT6621_AUD_TYPE_LPCM 0 +#define IT6621_AUD_TYPE_NLPCM 1 +#define IT6621_AUD_TYPE_HBR 2 +#define IT6621_AUD_TYPE_DSD 3 + +/* HDMI2.1 spec. Table 9-23: Channel Status Bits 0, 1, 3, 4, and 5 */ +#define HDMI_AUDIO_FMT_UN_2CH_LPCM 0x00 /* Unencrypted 2-channel LPCM */ +#define HDMI_AUDIO_FMT_UN_MCH_LPCM 0x10 /* Unencrypted multi-channel LPCM */ +#define HDMI_AUDIO_FMT_UN_XCH_DSD 0x18 /* Unencrypted One Bit Audio */ +#define HDMI_AUDIO_FMT_UN_2CH_NLPCM 0x02 /* Unencrypted IEC 61937 */ +#define HDMI_AUDIO_FMT_EN_2CH_NLPCM 0x06 /* Encrypted IEC 61937 */ +#define HDMI_AUDIO_FMT_EN_MCH_NLPCM 0x16 /* Encrypted multi-channel LPCM */ +#define HDMI_AUDIO_FMT_EN_XCH_DSD 0x1e /* Encrypted One Bit Audio */ + +/* + * HDMI2.1 spec. + * Table 9-25: Channel Status Bits 44 to 47 When Multi-Channel L-PCM is + * Transmitted. + * Table 9-26: Channel Status Bits 44 to 47 When One Bit Audio is Transmitted. + * Table 9-27: Channel Status Bits 44 to 47 When IEC 61937 (Compressed) Audio + * is Transmitted. + */ +#define HDMI_AUDIO_LAYOUT_LPCM_2CH 0x00 +#define HDMI_AUDIO_LAYOUT_LPCM_8CH 0x07 +#define HDMI_AUDIO_LAYOUT_LPCM_16CH 0x0b +#define HDMI_AUDIO_LAYOUT_LPCM_32CH 0x03 +#define HDMI_AUDIO_LAYOUT_NLPCM_2CH 0x00 +#define HDMI_AUDIO_LAYOUT_NLPCM_8CH 0x07 +#define HDMI_AUDIO_LAYOUT_DSD_6CH 0x05 +#define HDMI_AUDIO_LAYOUT_DSD_12CH 0x09 + +int it6621_set_arc_enabled(struct it6621_priv *priv, bool enabled); +int it6621_set_earc_enabled(struct it6621_priv *priv, bool enabled); +int it6621_set_enter_arc(struct it6621_priv *priv, bool enabled); +int it6621_get_ddfsm_state(struct it6621_priv *priv, unsigned int *state); +int it6621_set_channel_status(struct it6621_priv *priv); +int it6621_earc_init(struct it6621_priv *priv); +irqreturn_t it6621_irq(int irq, void *data); + +#endif /* _IT6621_EARC_H */ diff --git a/sound/soc/codecs/it6621/it6621-reg-bank0.h b/sound/soc/codecs/it6621/it6621-reg-bank0.h new file mode 100644 index 000000000000..b447ede66df0 --- /dev/null +++ b/sound/soc/codecs/it6621/it6621-reg-bank0.h @@ -0,0 +1,982 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (c) 2024 Rockchip Electronics Co. Ltd. + * Author: Jason Zhang + */ + +#ifndef _IT6621_REG_BANK0_H +#define _IT6621_REG_BANK0_H + +/* Bank 0 */ + +/* General Registers */ +#define IT6621_REG_VENDOR_ID_LOW 0x00 /* Vendor ID low */ +#define IT6621_REG_VENDOR_ID_HIGH 0x01 /* Vendor ID high */ +#define IT6621_REG_DEV_ID_LOW 0x02 /* Device ID low */ +#define IT6621_REG_DEV_ID_HIGH 0x03 /* Device ID high */ +#define IT6621_REG_REV_ID 0x04 /* Revision ID */ + +/* System Reset */ +#define IT6621_REG_SYS_RESET 0x05 +#define IT6621_SW_ACLK_RESET_SEL BIT(0) /* Software ACLK clock domain reset */ +#define IT6621_SW_ACLK_RESET_DIS (0x00 << 0) +#define IT6621_SW_ACLK_RESET_EN (0x01 << 0) +#define IT6621_SW_BCLK_RESET_SEL BIT(1) /* Software BCLK clock domain reset */ +#define IT6621_SW_BCLK_RESET_DIS (0x00 << 1) +#define IT6621_SW_BCLK_RESET_EN (0x01 << 1) +#define IT6621_SW_TCCLK_RESET_SEL BIT(2) /* Software TCCLK clock domain reset */ +#define IT6621_SW_TCCLK_RESET_DIS (0x00 << 2) +#define IT6621_SW_TCCLK_RESET_EN (0x01 << 2) +#define IT6621_SW_RCCLK_RESET_SEL BIT(3) /* Software RCCLK clock domain reset */ +#define IT6621_SW_RCCLK_RESET_DIS (0x00 << 3) +#define IT6621_SW_RCCLK_RESET_EN (0x01 << 3) +#define IT6621_SW_RCLK_RESET_SEL BIT(7) /* Software RCLK clock domain reset */ +#define IT6621_SW_RCLK_RESET_DIS (0x00 << 7) +#define IT6621_SW_RCLK_RESET_EN (0x01 << 7) + +/* System Status */ +#define IT6621_REG_SYS_STATUS 0x07 +#define IT6621_HPDIO_STATUS BIT(0) /* eARC HPDIO status */ +#define IT6621_HPDB_STATUS BIT(1) /* eARC HPDB status */ +#define IT6621_TX_XP_LOCK BIT(2) /* eARC TX XP lock indicator of PLL, 1: locked */ +#define IT6621_TX_NO_AUDIO BIT(4) /* 1: eARC TX no input audio */ +#define IT6621_TX_MUTE BIT(6) /* eARC TX input mute status */ + +#define IT6621_REG_EARC_TX_AUD_FREQ_NUM 0x0a + +/* System Control Registers */ +#define IT6621_REG_SYS_CTRL0 0x0c +#define IT6621_EXT_INT_EN BIT(1) /* External INT pin, 0: Disable, 1: Enable */ +#define IT6621_INT_IO_MODE BIT(2) /* External INT pin mode selection, + * 0: Push-Pull Mode, + * 1: Open-Drain mode + */ +#define IT6621_INT_IO_POL BIT(3) /* External INT pin active selection, + * 0: INT active low, + * 1: INT active high + */ +#define IT6621_FORCE_WRITE_UPDATE BIT(4) /* 1: force write update in non-idle state */ + +#define IT6621_REG_SYS_CTRL1 0x0d +#define IT6621_TX_AUD_FREQ_OPT BIT(0) /* eARC TX audio sampling frequency option */ +#define IT6621_TX_AUD_FREQ_DIV1 (0x00 << 0) /* div 1 */ +#define IT6621_TX_AUD_FREQ_DIV4 (0x01 << 0) /* div 4 */ +#define IT6621_TX_FORCE_HPDB_LOW_SEL BIT(4) /* eARC TX force HPDB low */ +#define IT6621_TX_FORCE_HPDB_LOW_DIS (0x00 << 4) +#define IT6621_TX_FORCE_HPDB_LOW_EN (0x01 << 4) + +#define IT6621_REG_SYS_CTRL3 0x0f +#define IT6621_BANK_SEL GENMASK(1, 0) /* Bank selection */ +#define IT6621_BANK0 (0x00 << 0) /* Reg00h~ Regffh */ +#define IT6621_BANK1 (0x01 << 0) /* Reg110h ~ Reg1ffh */ +#define IT6621_BANK2 (0x02 << 0) /* Reg210h ~ Reg2ffh */ +#define IT6621_TX_INT_STATUS BIT(2) /* eARC TX interrupt status */ +#define IT6621_CEC_INT_STATUS BIT(4) /* eARC CEC interrupt status */ + +/* Interrupt Status Registers */ +#define IT6621_REG_INT_STATUS0 0x10 +#define IT6621_TX_HPDIO_ON BIT(0) /* eARC TX HPDIO on interrupt */ +#define IT6621_TX_HPDIO_OFF BIT(1) /* eARC TX HPDIO off interrupt */ +#define IT6621_TX_STATE3_CHANGE BIT(2) /* eARC TX state3 change interrupt */ +#define IT6621_TX_HB_LOST BIT(3) /* eARC TX HeartBeat lost interrupt */ +#define IT6621_TX_DISV_TIMEOUT BIT(4) /* eARC TX discovery timeout interrupt */ +#define IT6621_TX_NO_AUD_CHANGE BIT(5) /* eARC TX no audio change interrupt */ +#define IT6621_TX_XP_LOCK_CHANGE BIT(6) /* eARC TX XP_LOCK change interrupt */ +#define IT6621_TX_RESYNC_ERR BIT(7) /* eARC TX ReSync error interrupt */ + +#define IT6621_REG_INT_STATUS1 0x11 +#define IT6621_TX_CMD_DONE BIT(0) /* eARC TX command done interrupt */ +#define IT6621_TX_CMD_FAIL BIT(1) /* eARC TX command fail interrupt */ +#define IT6621_TX_HB_DONE BIT(2) /* eARC TX HeartBeat done interrupt */ +#define IT6621_TX_READ_STATE_CHANGE BIT(3) /* eARC TX read EARC_RX_STAT change interrupt */ +#define IT6621_TX_CMDC_BP_ERR BIT(4) /* eARC TX CMDC bi-phase error interrupt */ +#define IT6621_TX_WRITE_STATE_CHANGE BIT(5) /* eARC TX auto write STAT_CHNG + * from '1' to '0' done + */ +#define IT6621_TX_WRITE_CAP_CHANGE BIT(6) /* eARC TX auto write CAP_CHNG + * from '1' to '0' done + */ +#define IT6621_TX_HB_FAIL BIT(7) /* eARC TX HeartBeat fail interrupt */ + +#define IT6621_REG_INT_STATUS2 0x12 +#define IT6621_TX_FIFO_ERR BIT(0) /* eARC TX FIFO error interrupt */ +#define IT6621_TX_DEC_ERR BIT(1) /* eARC TX input audio decode error interrupt */ +#define IT6621_TX_SPDIF_READY BIT(2) /* eARC TX input SPDIF channel + * status ready interrupt + */ +#define IT6621_TX_SPDIF_CHANGE BIT(3) /* eARC TX input SPDIF channel + * status change interrupt + */ +#define IT6621_TX_MUTE_CHANGE BIT(4) /* eARC TX input MUTE change interrupt */ + +#define IT6621_REG_INT_STATUS3 0x13 +#define IT6621_TX_HPDB_ON BIT(0) /* eARC TX HPDB on interrupt */ +#define IT6621_TX_HPDB_OFF BIT(1) /* eARC TX HPDB off interrupt */ + +#define IT6621_REG_INT_STATUS4 0x19 +#define IT6621_DET_ACLK_STABLE BIT(0) /* Detect ACLK stable interrupt */ +#define IT6621_DET_ACLK_VALID BIT(1) /* Detect ACLK valid interrupt */ +#define IT6621_DET_BCLK_STABLE BIT(2) /* Detect BCLK stable interrupt */ +#define IT6621_DET_BCLK_VALID BIT(3) /* Detect BCLK valid interrupt */ +#define IT6621_DET_NO_BCLK BIT(4) /* Detect no BCLK interrupt */ +#define IT6621_DET_NO_DMAC BIT(5) /* Detect no DMAC interrupt */ + +/* Interrupt Enable Registers */ +#define IT6621_REG_INT_EN0 0x1c +#define IT6621_TX_HPDIO_ON_EN BIT(0) /* Enable eARC TX HPDIO on interrupt */ +#define IT6621_TX_HPDIO_OFF_EN BIT(1) /* Enable eARC TX HPDIO off interrupt */ +#define IT6621_TX_STATE3_CHANGE_EN BIT(2) /* Enable eARC TX state3 change interrupt */ +#define IT6621_TX_HB_LOST_EN BIT(3) /* Enable eARC TX HeartBeat lost interrupt */ +#define IT6621_TX_DISV_TIMEOUT_EN BIT(4) /* Enable eARC TX discovery timeout interrupt */ +#define IT6621_TX_NO_AUD_CHANGE_EN BIT(5) /* Enable eARC TX no audio change interrupt */ +#define IT6621_TX_XP_LOCK_CHANGE_EN BIT(6) /* Enable eARC TX XP_LOCK change interrupt */ +#define IT6621_TX_RESYNC_ERR_EN BIT(7) /* Enable eARC TX ReSync error interrupt */ + +#define IT6621_REG_INT_EN1 0x1d +#define IT6621_TX_CMD_DONE_SEL BIT(0) /* Enable eARC TX command done interrupt */ +#define IT6621_TX_CMD_DONE_DIS (0x00 << 0) +#define IT6621_TX_CMD_DONE_EN (0x01 << 0) +#define IT6621_TX_CMD_FAIL_SEL BIT(1) /* Enable eARC TX command fail interrupt */ +#define IT6621_TX_CMD_FAIL_DIS (0x00 << 1) +#define IT6621_TX_CMD_FAIL_EN (0x01 << 1) +#define IT6621_TX_HB_DONE_SEL BIT(2) /* Enable eARC TX HeartBeat done interrupt */ +#define IT6621_TX_HB_DONE_DIS (0x00 << 2) +#define IT6621_TX_HB_DONE_EN (0x01 << 2) +#define IT6621_TX_READ_STATE_CHG_SEL BIT(3) /* Enable eARC TX read + * EARC_RX_STAT change interrupt + */ +#define IT6621_TX_READ_STATE_CHG_DIS (0x00 << 3) +#define IT6621_TX_READ_STATE_CHG_EN (0x01 << 3) +#define IT6621_TX_CMDC_BP_ERR_SEL BIT(4) /* Enable eARC TX CMDC bi-phase error interrupt */ +#define IT6621_TX_CMDC_BP_ERR_DIS (0x00 << 4) +#define IT6621_TX_CMDC_BP_ERR_EN (0x01 << 4) +#define IT6621_TX_WRITE_STATE_CHG_SEL BIT(5) /* Enable eARC TX auto write + * state change interrupt + */ +#define IT6621_TX_WRITE_STATE_CHG_DIS (0x00 << 5) +#define IT6621_TX_WRITE_STATE_CHG_EN (0x01 << 5) +#define IT6621_TX_WRITE_CAP_CHG_SEL BIT(6) /* Enable eARC TX auto write cap change interrupt */ +#define IT6621_TX_WRITE_CAP_CHG_DIS (0x00 << 6) +#define IT6621_TX_WRITE_CAP_CHG_EN (0x01 << 6) +#define IT6621_TX_HB_FAIL_SEL BIT(7) /* Enable eARC TX HeartBeat fail interrupt */ +#define IT6621_TX_HB_FAIL_DIS (0x00 << 7) +#define IT6621_TX_HB_FAIL_EN (0x01 << 7) + +#define IT6621_REG_INT_EN2 0x1e +#define IT6621_TX_FIFO_ERR_EN BIT(0) /* Enable eARC TX FIFO error interrupt */ +#define IT6621_TX_DEC_ERR_EN BIT(1) /* Enable eARC TX input audio + * decode error interrupt + */ +#define IT6621_TX_SPDIF_READY_EN BIT(2) /* Enable eARC TX input SPDIF + * channel status ready interrupt + */ +#define IT6621_TX_SPDIF_CHANGE_EN BIT(3) /* Enable eARC TX input SPDIF + * channel status change interrupt + */ +#define IT6621_TX_MUTE_CHANGE_EN BIT(4) /* Enable eARC TX input MUTE change interrupt */ + +#define IT6621_REG_INT_EN3 0x1f +#define IT6621_TX_HPDB_ON_EN BIT(0) /* Enable eARC TX HPDB on interrupt */ +#define IT6621_TX_HPDB_OFF_EN BIT(1) /* Enable eARC TX HPDB off interrupt */ + +#define IT6621_REG_INT_EN4 0x25 +#define IT6621_DET_ACLK_STABLE_EN BIT(0) /* Enable detect ACLK stable interrupt */ +#define IT6621_DET_ACLK_VALID_EN BIT(1) /* Enable detect ACLK valid interrupt */ +#define IT6621_DET_BCLK_STABLE_EN BIT(2) /* Enable detect BCLK stable interrupt */ +#define IT6621_DET_BCLK_VALID_EN BIT(3) /* Enable detect BCLK valid interrupt */ +#define IT6621_DET_NO_BCLK_EN BIT(4) /* Enable detect no BCLK interrupt */ +#define IT6621_DET_NO_DMAC_EN BIT(5) /* Enable detect no DMAC interrupt */ + +/* Clock Control Registers */ +#define IT6621_REG_CLK_CTRL0 0x28 +#define IT6621_RCLK_FREQ_SEL GENMASK(1, 0) /* RCLK frequency selection */ +#define IT6621_RCLK_FREQ_REFCLK (0x00 << 0) /* RCLK = REFCLK, 20MHz */ +#define IT6621_RCLK_FREQ_REFCLK_DIV_2 (0x01 << 0) /* RCLK = REFCLK/2, 10Mhz */ +#define IT6621_RCLK_FREQ_REFCLK_DIV_4 (0x02 << 0) /* RCLK = REFCLK/4, 5Mhz */ +#define IT6621_RCLK_FREQ_REFCLK_DIV_8 (0x03 << 0) /* RCLK = REFCLK/8, 2.5Mhz */ +#define IT6621_RCLK_PWD_SEL BIT(2) /* Enable RCLK power-down when IDDQ mode */ +#define IT6621_RCLK_PWD_DIS (0x00 << 2) /* disable */ +#define IT6621_RCLK_PWD_EN (0x01 << 2) /* enable */ +#define IT6621_GATE_RCLK_SEL BIT(4) /* Gating GRCLK clock domain */ +#define IT6621_GATE_RCLK_DIS (0x00 << 4) /* disable */ +#define IT6621_GATE_RCLK_EN (0x01 << 4) /* enable */ +#define IT6621_DMAC_PWD_SEL BIT(6) /* Enable DMAC power-down */ +#define IT6621_DMAC_PWD_DIS (0x00 << 6) /* disable */ +#define IT6621_DMAC_PWD_EN (0x01 << 6) /* enable */ +#define IT6621_CMDC_PWD_SEL BIT(7) /* Enable CMDC power-down */ +#define IT6621_CMDC_PWD_DIS (0x00 << 7) /* disable */ +#define IT6621_CMDC_PWD_EN (0x01 << 7) /* enable */ + +#define IT6621_REG_CLK_CTRL1 0x29 +#define IT6621_TBCLK_SEL GENMASK(2, 0) /* TBCLK selection */ +#define IT6621_TBCLK_AICLK (0x00 << 0) /* TBCLK = AICLK x 1 */ +#define IT6621_TBCLK_AICLK_MUL_2 (0x01 << 0) /* TBCLK = AICLK x 2 */ +#define IT6621_TBCLK_AICLK_MUL_4 (0x02 << 0) /* TBCLK = AICLK x 4 */ +#define IT6621_TBCLK_AICLK_MUL_8 (0x03 << 0) /* TBCLK = AICLK x 8 */ +#define IT6621_TBCLK_AICLK_MUL_16 (0x04 << 0) /* TBCLK = AICLK x 16 */ +#define IT6621_TBCLK_AICLK_MUL_32 (0x05 << 0) /* TBCLK = AICLK x 32 */ +#define IT6621_TBCLK_AUTO BIT(3) /* 1: TBCLK auto mode */ +#define IT6621_AOCLK_SEL GENMASK(6, 4) /* AOCLK selection */ +#define IT6621_AOCLK_RBCLK (0x00 << 4) /* AOCLK = RBCLK / 1 */ +#define IT6621_AOCLK_RBCLK_DIV_2 (0x01 << 4) /* AOCLK = RBCLK / 2 */ +#define IT6621_AOCLK_RBCLK_DIV_4 (0x02 << 4) /* AOCLK = RBCLK / 4 */ +#define IT6621_AOCLK_RBCLK_DIV_8 (0x03 << 4) /* AOCLK = RBCLK / 8 */ +#define IT6621_AOCLK_RBCLK_DIV_16 (0x04 << 4) /* AOCLK = RBCLK / 16 */ +#define IT6621_AOCLK_RBCLK_DIV_32 (0x05 << 4) /* AOCLK = RBCLK / 32 */ +#define IT6621_AOCLK_LCCLK (0x06 << 4) /* AOCLK = LCCLK */ +#define IT6621_AOCLK_AUTO BIT(7) /* 1: AOCLK auto mode */ + +#define IT6621_REG_CLK_CTRL2 0x2a +#define IT6621_ACLK_INV_SEL BIT(0) /* eARC ACLK inversion */ +#define IT6621_ACLK_INV_DIS (0x00 << 0) /* disable */ +#define IT6621_ACLK_INV_EN (0x01 << 0) /* enable */ +#define IT6621_BCLK_INV_SEL BIT(1) /* eARC BCLK inversion */ +#define IT6621_BCLK_INV_DIS (0x00 << 1) /* disable */ +#define IT6621_BCLK_INV_EN (0x01 << 1) /* enable */ +#define IT6621_RCCLK_OPT BIT(2) /* RCCLK option */ +#define IT6621_MCLKX2_SEL GENMASK(6, 4) /* MCLKX2 selection */ +#define IT6621_MCLKX2_RBCLKX2 (0x00 << 4) /* MCLKX2 = RBCLKX2 / 1 */ +#define IT6621_MCLKX2_RBCLKX2_DIV_2 (0x01 << 4) /* MCLKX2 = RBCLKX2 / 2 */ +#define IT6621_MCLKX2_RBCLKX2_DIV_4 (0x02 << 4) /* MCLKX2 = RBCLKX2 / 4 */ +#define IT6621_MCLKX2_RBCLKX2_DIV_8 (0x03 << 4) /* MCLKX2 = RBCLKX2 / 8 */ +#define IT6621_MCLKX2_RBCLKX2_DIV_16 (0x04 << 4) /* MCLKX2 = RBCLKX2 / 16 */ +#define IT6621_MCLKX2_RBCLKX2_DIV_32 (0x05 << 4) /* MCLKX2 = RBCLKX2 / 32 */ +#define IT6621_MCLKX2_LCCLK (0x06 << 4) /* MCLKX2 = LCCLK */ +#define IT6621_MCLKX2_AUTO BIT(7) /* 1: MCLKX2 auto mode */ + +/* eARC TX Discovery and Disconnect Registers */ +#define IT6621_REG_TX_DD0 0x30 +#define IT6621_TX_DD_FSM_SEL BIT(0) /* 1: eARC TX enable discovery and disconnect FSM */ +#define IT6621_TX_DD_FSM_DIS (0x00 << 0) +#define IT6621_TX_DD_FSM_EN (0x01 << 0) +#define IT6621_TX_EARC_SEL BIT(1) /* 1: enable eARC TX function */ +#define IT6621_TX_EARC_DIS (0x00 << 1) +#define IT6621_TX_EARC_EN (0x01 << 1) +#define IT6621_TX_ARC_SEL BIT(2) /* 1: enable ARC TX function */ +#define IT6621_TX_ARC_DIS (0x00 << 2) +#define IT6621_TX_ARC_EN (0x01 << 2) +#define IT6621_TX_ARC_NOW_SEL BIT(3) /* 1: ARC TX function is enabled now */ +#define IT6621_TX_ARC_NOW_DIS (0x00 << 3) +#define IT6621_TX_ARC_NOW_EN (0x01 << 3) +#define IT6621_TX_DISV_TIMEOUT_SEL GENMASK(5, 4) /* eARC TX discovery + * timeout selection + * (No COMMA) + */ +#define IT6621_TX_DISV_TIMEOUT_450MS (0x00 << 4) /* 450ms */ +#define IT6621_TX_DISV_TIMEOUT_475MS (0x01 << 4) /* 475ms */ +#define IT6621_TX_DISV_TIMEOUT_500MS (0x02 << 4) /* 500ms */ +#define IT6621_TX_DISV_TIMEOUT_600MS (0x03 << 4) /* 600ms */ +#define IT6621_TX_HB_POS_SEL GENMASK(7, 6) /* eARC TX HeartBeat position selection */ +#define IT6621_TX_HB_POS_1MS (0x00 << 6) /* 1ms */ +#define IT6621_TX_HB_POS_3MS (0x01 << 6) /* 3ms */ +#define IT6621_TX_HB_POS_5MS (0x02 << 6) /* 5ms */ +#define IT6621_TX_HB_POS_7MS (0x03 << 6) /* 7ms */ + +#define IT6621_REG_TX_DD1 0x31 +#define IT6621_TX_COMMA_SEL GENMASK(1, 0) /* eARC TX valid COMMA selection */ +#define IT6621_TX_COMMA_8_12MS (0x00 << 0) /* 8~12ms */ +#define IT6621_TX_COMMA_7_13MS (0x01 << 0) /* 7~13ms */ +#define IT6621_TX_COMMA_6_14MS (0x02 << 0) /* 6~14ms */ +#define IT6621_TX_COMMA_5_15MS (0x03 << 0) /* 5~15ms */ +#define IT6621_TX_COMMA_OPT BIT(2) /* eARC TX COMMA bit error + * tolerance, 0: no tolerance, + * 1: 1-bit tolerance + */ + +#define IT6621_REG_TX_DD2 0x32 +#define IT6621_TX_DD_FSM_STATE GENMASK(5, 0) /* eARC TX discovery and + * disconnect FSM state + */ +#define IT6621_TX_EARC_MODE (0x08 << 0) +#define IT6621_TX_ARC_MODE (0x20 << 0) + +#define IT6621_REG_TX_DD3 0x33 +#define IT6621_TX_FORCE_ARC_MODE_SEL BIT(0) /* force TX ARC mode */ +#define IT6621_TX_FORCE_ARC_MODE_DIS (0x00 << 0) +#define IT6621_TX_FORCE_ARC_MODE_EN (0x01 << 0) + +/* eARC TX CMDC Registers */ +#define IT6621_REG_CMDC0 0x40 +#define IT6621_TX_CMD_TIMEOUT_EN BIT(0) /* 1: eARC TX enable NACK/RETRY timeout (256-time) */ +#define IT6621_TX_NACK_DELAY_EN BIT(1) /* 1: eARC TX enable NACK delay */ +#define IT6621_TX_DEBUG_FIFO_EN BIT(2) /* 1: eARC TX enable debug FIFO */ +#define IT6621_TX_NEXT_PKT_TIMEOUT_SEL BIT(3) /* eARC TX next packet timeout selection */ +#define IT6621_TX_NEXT_PKT_TIMEOUT_30US (0x00 << 3) /* 30us */ +#define IT6621_TX_NEXT_PKT_TIMEOUT_50US (0x01 << 3) /* 50us */ +#define IT6621_TX_NACK_DELAY_SEL GENMASK(5, 4) /* eARC TX NACK packet delay time selection */ +#define IT6621_TX_NACK_DELAY_500US (0x00 << 4) /* 500us */ +#define IT6621_TX_NACK_DELAY_1MS (0x01 << 4) /* 1ms */ +#define IT6621_TX_NACK_DELAY_2MS (0x02 << 4) /* 2ms */ +#define IT6621_TX_NACK_DELAY_4MS (0x03 << 4) /* 4ms */ +#define IT6621_TX_TURN_OVER_SEL GENMASK(7, 6) /* eARC TX turn-over time + * selection before + * transmitting packet + */ +#define IT6621_TX_TURN_OVER_8US (0x00 << 6) /* 8us */ +#define IT6621_TX_TURN_OVER_16US (0x01 << 6) /* 16us */ +#define IT6621_TX_TURN_OVER_24US (0x02 << 6) /* 24us */ + +#define IT6621_REG_CMDC1 0x41 +#define IT6621_TX_CMDC_STATE GENMASK(3, 0) /* eARC TX CMDC state */ +#define IT6621_TX_CMDC_STATE_IDLE (0x00 << 0) /* IDLE */ +#define IT6621_TX_CMDC_STATE_CMD (0x01 << 0) /* TX Cmd */ +#define IT6621_TX_CMDC_STATE_DEVID (0x02 << 0) /* TX DevID */ +#define IT6621_TX_CMDC_STATE_OFFSET (0x03 << 0) /* TX Offset */ +#define IT6621_TX_CMDC_STATE_CONT1 (0x04 << 0) /* TX Cont1 */ +#define IT6621_TX_CMDC_STATE_CONT2 (0x05 << 0) /* TX Cont2 */ +#define IT6621_TX_CMDC_STATE_RETRY (0x06 << 0) /* TX Retry */ +#define IT6621_TX_CMDC_STATE_DATA1 (0x07 << 0) /* TX Data1 */ +#define IT6621_TX_CMDC_STATE_DATA2 (0x08 << 0) /* TX Data2 */ +#define IT6621_TX_CMDC_STATE_STOP (0x09 << 0) /* TX Stop */ +#define IT6621_TX_FAIL_STATE GENMASK(7, 4) +#define IT6621_TX_FAIL_STATE_NO_RESP BIT(4) /* No response */ +#define IT6621_TX_FAIL_STATE_UNEXP_RESP BIT(5) /* Unexpected response */ +#define IT6621_TX_FAIL_STATE_ECC_ERR BIT(6) /* Uncorrectable ECC error */ +#define IT6621_TX_FAIL_STATE_TIMEOUT BIT(7) /* NACK/RETRY 256 times timeout */ + +#define IT6621_REG_TX_DEV_ID 0x42 /* eARC TX device ID */ +#define IT6621_REG_TX_OFFSET 0x43 /* eARC TX offset value */ + +#define IT6621_REG_CMDC2 0x44 +#define IT6621_TX_BYTE_NO GENMASK(4, 0) /* eARC TX byte number (1~32 bytes) */ +#define IT6621_TX_CMD_BUSY BIT(5) /* 1: eARC TX command busy */ +#define IT6621_TX_WRITE_TRIGGER BIT(6) /* eARC TX write trigger */ +#define IT6621_TX_READ_TRIGGER BIT(7) /* eARC TX read trigger */ + +#define IT6621_REG_TX_DATA_FIFO 0x45 /* eARC TX data FIFO of read/write + * data (32-stage FIFO) + */ + +#define IT6621_REG_CMDC3 0x46 +#define IT6621_TX_DATA_FIFO_STAGE GENMASK(5, 0) /* eARC TX data FIFO stage */ +#define IT6621_TX_DATA_FIFO_EMPTY (0x00 << 0) /* FIFO empty */ +#define IT6621_TX_DATA_FIFO_FULL (0x20 << 0) /* FIFO full */ +#define IT6621_TX_DATA_FIFO_ERR BIT(6) /* eARC TX data FIFO error */ +#define IT6621_TX_DATA_FIFO_CLEAR BIT(7) /* eARC TX data FIFO clear */ + +#define IT6621_REG_CMDC4 0x47 +#define IT6621_TX_AUTO_HB_EN BIT(0) /* eARC TX auto HeartBeat, 0: disable, 1: enable */ +#define IT6621_TX_AUTO_HB_BUSY BIT(1) /* 1: eARC TX auto HeartBeat busy */ +#define IT6621_TX_HB_TIME_SEL GENMASK(3, 2) /* eARC TX auto HeartBeat time selection */ +#define IT6621_TX_HB_TIME_35MS (0x00 << 2) /* 35ms */ +#define IT6621_TX_HB_TIME_40MS (0x01 << 2) /* 40ms */ +#define IT6621_TX_HB_TIME_45MS (0x02 << 2) /* 45ms */ +#define IT6621_TX_HB_TIME_50MS (0x03 << 2) /* 50ms */ +#define IT6621_TX_HB_RETRY_SEL BIT(4) /* eARC TX auto HeartBeat retry, + * 0: disable, 1: enable + */ +#define IT6621_TX_HB_RETRY_DIS (0x00 << 4) +#define IT6621_TX_HB_RETRY_EN (0x01 << 4) +#define IT6621_TX_HB_TRIGGER BIT(5) /* eARC TX HeartBeat trigger */ +#define IT6621_TX_HB_RETRY_TIME_SEL GENMASK(7, 6) /* eARC TX HeartBeat retry time selection */ +#define IT6621_TX_HB_RETRY_0MS (0x00 << 6) /* 0ms */ +#define IT6621_TX_HB_RETRY_4MS (0x01 << 6) /* 4ms */ +#define IT6621_TX_HB_RETRY_8MS (0x02 << 6) /* 8ms */ +#define IT6621_TX_HB_RETRY_16MS (0x03 << 6) /* 16ms */ + +#define IT6621_REG_TX_READ_STATE 0x48 /* eARC TX read back value of EARC_RX_STAT */ +#define IT6621_EARC_RX_STAT_EARC_HPD BIT(0) +#define IT6621_EARC_RX_STAT_CAP_CHNG BIT(3) +#define IT6621_EARC_RX_STAT_STAT_CHNG BIT(4) + +#define IT6621_REG_CMDC5 0x49 +#define IT6621_TX_AUTO_WRITE_STATE_SEL BIT(0) /* 1: eARC TX auto write EARC_TX_STAT[7:1] */ +#define IT6621_TX_AUTO_WRITE_STATE_DIS (0x00 << 0) /* to pass SL-870 HFR5-1-35/36/37 */ +#define IT6621_TX_AUTO_WRITE_STATE_EN (0x01 << 0) +#define IT6621_TX_WRITE_STATE GENMASK(7, 1) /* eARC TX write value of EARC_TX_STAT[7:1] */ + +#define IT6621_REG_CMDC6 0x4a +#define IT6621_TX_CMO_OPT BIT(0) /* eARC TX common mode output enable option */ +#define IT6621_TX_CMO_NORMAL (0x00 << 0) /* normal */ +#define IT6621_TX_CMO_PRE_1BIT (0x01 << 0) /* 1-bit before normal */ +#define IT6621_TX_FORCE_CMO_OPT BIT(1) /* eARC TX common mode output enable option */ +#define IT6621_TX_FORCE_CMO_NORMAL (0x00 << 1) /* normal */ +#define IT6621_TX_FORCE_CMO_EN (0x01 << 1) /* force output enable */ +#define IT6621_TX_RESYNC_OPT BIT(2) /* eARC TX common mode resync option */ +#define IT6621_TX_RESYNC_OLD (0x00 << 2) /* old */ +#define IT6621_TX_RESYNC_NEW (0x01 << 2) /* new */ + +#define IT6621_REG_TX_DEBUG_FIFO0 0x4d /* eARC TX debug FIFO (32-stage + * FIFO), Cmd[7:0]/Data[7:0] + */ + +#define IT6621_REG_TX_DEBUG_FIFO1 0x4e +#define IT6621_TX_DEBUG_FIFO_CD BIT(0) /* C/D */ +#define IT6621_TX_DEBUG_FIFO_DATA (0x00 << 0) /* Data */ +#define IT6621_TX_DEBUG_FIFO_CMD (0x01 << 0) /* Cmd */ +#define IT6621_TX_DEBUG_FIFO_IO BIT(1) /* I/O */ +#define IT6621_TX_DEBUG_FIFO_INPUT_PKT (0x00 << 1) /* input packet */ +#define IT6621_TX_DEBUG_FIFO_OUTPUT_PKT (0x01 << 1) /* output packet */ +#define IT6621_TX_DEBUG_FIFO_ECC_ERR BIT(2) /* 1: ECC error */ + +#define IT6621_REG_TX_DEBUG_FIFO2 0x4f +#define IT6621_TX_DEBUG_FIFO_STAGE GENMASK(5, 0) /* eARC TX debug FIFO stage */ +#define IT6621_TX_DEBUG_FIFO_EMPTY (0x00 << 0) /* FIFO empty */ +#define IT6621_TX_DEBUG_FIFO_FULL (0x20 << 0) /* FIFO full */ +#define IT6621_TX_DEBUG_FIFO_ERR BIT(6) /* eARC TX debug FIFO error */ +#define IT6621_TX_DEBUG_FIFO_CLEAR_SEL BIT(7) /* eARC TX debug FIFO clear */ +#define IT6621_TX_DEBUG_FIFO_CLEAR_DIS (0x00 << 7) /* FIFO empty */ +#define IT6621_TX_DEBUG_FIFO_CLEAR_EN (0x01 << 7) + +/* eARC TX DMAC Control Registers */ +#define IT6621_REG_DMAC_CTRL0 0x60 +#define IT6621_TX_ECC_EN BIT(0) /* eARC TX ECC, 0: disable, 1: enable */ +#define IT6621_TX_AUTO_ECC BIT(1) /* 1: eARC TX auto ECC */ +#define IT6621_TX_ECC_OPT BIT(2) /* eARC TX ECC option */ +#define IT6621_TX_ECC_VC_SWAP (0x00 << 2) /* vc swap */ +#define IT6621_TX_ECC_U_SWAP (0x01 << 2) /* u swap */ +#define IT6621_TX_ENC_SEL BIT(3) /* eARC TX encryption, 0: disable, 1: enable */ +#define IT6621_TX_ENC_DIS (0x00 << 3) /* disable */ +#define IT6621_TX_ENC_EN (0x01 << 3) /* enable */ +#define IT6621_TX_ENC_OPT GENMASK(5, 4) /* eARC TX encryption option */ +#define IT6621_TX_ENC_OPT0 (0x00 << 4) +#define IT6621_TX_ENC_OPT1 (0x01 << 4) +#define IT6621_TX_ENC_OPT2 (0x02 << 4) +#define IT6621_TX_ENC_OPT3 (0x03 << 4) + +#define IT6621_REG_TX_ENC_SEED_LOW 0x61 /* eARC TX encryption seed */ +#define IT6621_REG_TX_ENC_SEED_HIGH 0x62 /* eARC TX encryption seed */ + +#define IT6621_REG_DMAC_CTRL1 0x63 +#define IT6621_TX_MANUAL_RESET_EN_SEL BIT(0) /* 1: enable eARC TX audio FIFO manual reset */ +#define IT6621_TX_MANUAL_RESET_DIS (0x00 << 0) +#define IT6621_TX_MANUAL_RESET_EN (0x01 << 0) +#define IT6621_TX_AUTO_RESET_EN BIT(1) /* 1: enable eARC TX audio FIFO auto reset */ +#define IT6621_TX_PKT1_EN_SEL BIT(2) /* 1: enable eARC TX packet 1 using U-bit */ +#define IT6621_TX_PKT1_DIS (0x00 << 2) +#define IT6621_TX_PKT1_EN (0x01 << 2) +#define IT6621_TX_PKT2_EN_SEL BIT(3) /* 1: enable eARC TX packet 2 using U-bit */ +#define IT6621_TX_PKT2_DIS (0x00 << 3) +#define IT6621_TX_PKT2_EN (0x01 << 3) +#define IT6621_TX_PKT3_EN_SEL BIT(4) /* 1: enable eARC TX packet 3 using U-bit */ +#define IT6621_TX_PKT3_DIS (0x00 << 4) +#define IT6621_TX_PKT3_EN (0x01 << 4) +#define IT6621_TX_C_CH_OPT BIT(5) /* 1: eARC TX U-bit C-Ch option */ +#define IT6621_TX_C_CH_OPT1 (0x00 << 5) /* use RegTxChSt[14:8] for + * C-Ch[14:8] and + * RegTxPktCH[7:0] is for + * CH[7:0] which should be + * set 0x00 + */ +#define IT6621_TX_C_CH_OPT2 (0x01 << 5) /* use RegTxPktCH[6:0] for + * C-Ch[14:8] and CH[7:0] + * is set 0x00 + */ +#define IT6621_TX_U_BIT_OPT BIT(6) /* U-bit option */ +#define IT6621_TX_U_BIT_1BIT_FRAME (0x00 << 6) /* 1-bit/frame */ +#define IT6621_TX_U_BIT_1BIT_SUB_FRAME (0x01 << 6) /* 1-bit/sub-frame */ +#define IT6621_TX_V_BIT_VAL BIT(7) /* V-bit value */ +#define IT6621_TX_V_BIT_LPCM (0x00 << 7) /* LPCM */ +#define IT6621_TX_V_BIT_NLPCM (0x01 << 7) /* NLPCM */ + +/* Input Audio Control Registers */ +#define IT6621_REG_TX_AUD_SRC_EN 0x80 /* Enable input audio source */ +#define IT6621_AUD_SRC0_EN BIT(0) /* for audio source 0 */ +#define IT6621_AUD_SRC1_EN BIT(1) /* for audio source 1 */ +#define IT6621_AUD_SRC2_EN BIT(2) /* for audio source 2 */ +#define IT6621_AUD_SRC3_EN BIT(3) /* for audio source 3 */ +#define IT6621_AUD_SRC4_EN BIT(4) /* for audio source 4 */ +#define IT6621_AUD_SRC5_EN BIT(5) /* for audio source 5 */ +#define IT6621_AUD_SRC6_EN BIT(6) /* for audio source 6 */ +#define IT6621_AUD_SRC7_EN BIT(7) /* for audio source 7 */ +#define IT6621_AUD_SRC7_SRC0_EN (IT6621_AUD_SRC7_EN | \ + IT6621_AUD_SRC6_EN | \ + IT6621_AUD_SRC5_EN | \ + IT6621_AUD_SRC4_EN | \ + IT6621_AUD_SRC3_EN | \ + IT6621_AUD_SRC2_EN | \ + IT6621_AUD_SRC1_EN | \ + IT6621_AUD_SRC0_EN) +#define IT6621_AUD_SRC6_SRC0_EN (IT6621_AUD_SRC6_EN | \ + IT6621_AUD_SRC5_EN | \ + IT6621_AUD_SRC4_EN | \ + IT6621_AUD_SRC3_EN | \ + IT6621_AUD_SRC2_EN | \ + IT6621_AUD_SRC1_EN | \ + IT6621_AUD_SRC0_EN) +#define IT6621_AUD_SRC5_SRC0_EN (IT6621_AUD_SRC5_EN | \ + IT6621_AUD_SRC4_EN | \ + IT6621_AUD_SRC3_EN | \ + IT6621_AUD_SRC2_EN | \ + IT6621_AUD_SRC1_EN | \ + IT6621_AUD_SRC0_EN) +#define IT6621_AUD_SRC4_SRC0_EN (IT6621_AUD_SRC4_EN | \ + IT6621_AUD_SRC3_EN | \ + IT6621_AUD_SRC2_EN | \ + IT6621_AUD_SRC1_EN | \ + IT6621_AUD_SRC0_EN) +#define IT6621_AUD_SRC3_SRC0_EN (IT6621_AUD_SRC3_EN | \ + IT6621_AUD_SRC2_EN | \ + IT6621_AUD_SRC1_EN | \ + IT6621_AUD_SRC0_EN) +#define IT6621_AUD_SRC2_SRC0_EN (IT6621_AUD_SRC2_EN | \ + IT6621_AUD_SRC1_EN | \ + IT6621_AUD_SRC0_EN) +#define IT6621_AUD_SRC1_SRC0_EN (IT6621_AUD_SRC1_EN | \ + IT6621_AUD_SRC0_EN) + +#define IT6621_REG_TX_AUD_SRC_SEL 0x81 /* Input audio source selection */ +#define IT6621_TX_AUD_SRC GENMASK(1, 0) /* eARC TX encryption option */ +#define IT6621_AUD_SRC_I2S (0x00 << 0) /* I2S */ +#define IT6621_AUD_SRC_SPDIF (0x01 << 0) /* SPDIF */ +#define IT6621_AUD_SRC_TDM (0x02 << 0) /* TDM */ +#define IT6621_AUD_SRC_DSD (0x03 << 0) /* DSD */ + +#define IT6621_REG_TX_I2S 0x82 +#define IT6621_I2S_FMT GENMASK(4, 0) /* TX I2S/TDM format */ +#define IT6621_I2S_FMT_STANDARD (0x00 << 0) /* Standard I2S */ +#define IT6621_I2S_FMT_32BIT (0x01 << 0) /* 32-bit I2S */ +#define IT6621_I2S_FMT_LEFT_JUSTIFIED (0x00 << 1) /* Left-justified */ +#define IT6621_I2S_FMT_RIGHT_JUSTIFIED (0x01 << 1) /* Right-justified */ +#define IT6621_I2S_FMT_DATA_DELAY (0x00 << 2) /* Data delay 1T correspond to WS */ +#define IT6621_I2S_FMT_NO_DATA_DELAY (0x01 << 2) /* No data delay correspond to WS */ +#define IT6621_I2S_FMT_WS_0_LEFT_CH (0x00 << 3) /* WS=0 is left channel */ +#define IT6621_I2S_FMT_WS_0_RIGHT_CH (0x01 << 3) /* WS=0 is right channel */ +#define IT6621_I2S_FMT_MSB_FIRST (0x00 << 4) /* MSB shift first */ +#define IT6621_I2S_FMT_LSB_FIRST (0x01 << 4) /* LSB shift first */ +#define IT6621_I2S_TDM_WORD_LEN GENMASK(6, 5) /* TX I2S/TDM word length */ +#define IT6621_I2S_TDM_16BIT (0x00 << 5) /* 16 bits */ +#define IT6621_I2S_TDM_18BIT (0x01 << 5) /* 18 bits */ +#define IT6621_I2S_TDM_20BIT (0x02 << 5) /* 20 bits */ +#define IT6621_I2S_TDM_24BIT (0x03 << 5) /* 24 bits */ + +#define IT6621_REG_TX_AUD_CTRL3 0x83 +#define IT6621_TX_TDM_CH_NUM GENMASK(2, 0) /* TX TDM interface channel number */ +#define IT6621_TX_TDM_2CH (0x00 << 0) /* 2-ch */ +#define IT6621_TX_TDM_4CH (0x01 << 0) /* 4-ch */ +#define IT6621_TX_TDM_8CH (0x03 << 0) /* 8-ch */ +#define IT6621_TX_TDM_16CH (0x07 << 0) /* 16-ch */ +#define IT6621_TX_I2S_HBR_EN_SEL BIT(3) /* enable TX I2S HBR input */ +#define IT6621_TX_I2S_HBR_DIS (0x00 << 3) +#define IT6621_TX_I2S_HBR_EN (0x01 << 3) +#define IT6621_TX_DSD_MODE BIT(4) /* TX DSD mode */ +#define IT6621_TX_DSD_MODE_NORMAL (0x00 << 4) /* normal mode */ +#define IT6621_TX_DSD_MODE_PHASE (0x01 << 4) /* phase mode */ +#define IT6621_TX_DSD_BIT_INV_SEL BIT(5) /* TX DSD data inversion */ +#define IT6621_TX_DSD_BIT_NO_INV (0x00 << 5) /* not inverse */ +#define IT6621_TX_DSD_BIT_INV (0x01 << 5) /* inverse */ +#define IT6621_TX_DSD_LM_SWAP_SEL BIT(6) /* TX DSD LSB/MSB swap */ +#define IT6621_TX_DSD_LM_NO_SWAP (0x00 << 6) /* no swap */ +#define IT6621_TX_DSD_LM_SWAP (0x01 << 6) /* swap */ +#define IT6621_TX_DSD_LR_SWAP_SEL BIT(7) /* TX DSD L/R swap */ +#define IT6621_TX_DSD_LR_NO_SWAP (0x00 << 7) /* no swap */ +#define IT6621_TX_DSD_LR_SWAP (0x01 << 7) /* swap */ + +#define IT6621_REG_TX_AUD_SEL1 0x84 +#define IT6621_TX_AUD0_SEL GENMASK(2, 0) /* TX audio 0 input selection */ +#define IT6621_TX_AUD0_FROM_SRC0 (0x00 << 0) /* from audio source 0 */ +#define IT6621_TX_AUD0_FROM_SRC1 (0x01 << 0) /* from audio source 1 */ +#define IT6621_TX_AUD0_FROM_SRC2 (0x02 << 0) /* from audio source 2 */ +#define IT6621_TX_AUD0_FROM_SRC3 (0x03 << 0) /* from audio source 3 */ +#define IT6621_TX_AUD0_FROM_SRC4 (0x04 << 0) /* from audio source 4 */ +#define IT6621_TX_AUD0_FROM_SRC5 (0x05 << 0) /* from audio source 5 */ +#define IT6621_TX_AUD0_FROM_SRC6 (0x06 << 0) /* from audio source 6 */ +#define IT6621_TX_AUD0_FROM_SRC7 (0x07 << 0) /* from audio source 7 */ +#define IT6621_TX_AUD1_SEL GENMASK(6, 4) /* TX audio 1 input selection */ +#define IT6621_TX_AUD1_FROM_SRC0 (0x00 << 4) /* from audio source 0 */ +#define IT6621_TX_AUD1_FROM_SRC1 (0x01 << 4) /* from audio source 1 */ +#define IT6621_TX_AUD1_FROM_SRC2 (0x02 << 4) /* from audio source 2 */ +#define IT6621_TX_AUD1_FROM_SRC3 (0x03 << 4) /* from audio source 3 */ +#define IT6621_TX_AUD1_FROM_SRC4 (0x04 << 4) /* from audio source 4 */ +#define IT6621_TX_AUD1_FROM_SRC5 (0x05 << 4) /* from audio source 5 */ +#define IT6621_TX_AUD1_FROM_SRC6 (0x06 << 4) /* from audio source 6 */ +#define IT6621_TX_AUD1_FROM_SRC7 (0x07 << 4) /* from audio source 7 */ + +#define IT6621_REG_TX_AUD_SEL2 0x85 +#define IT6621_TX_AUD2_SEL GENMASK(2, 0) /* TX audio 2 input selection */ +#define IT6621_TX_AUD2_FROM_SRC0 (0x00 << 0) /* from audio source 0 */ +#define IT6621_TX_AUD2_FROM_SRC1 (0x01 << 0) /* from audio source 1 */ +#define IT6621_TX_AUD2_FROM_SRC2 (0x02 << 0) /* from audio source 2 */ +#define IT6621_TX_AUD2_FROM_SRC3 (0x03 << 0) /* from audio source 3 */ +#define IT6621_TX_AUD2_FROM_SRC4 (0x04 << 0) /* from audio source 4 */ +#define IT6621_TX_AUD2_FROM_SRC5 (0x05 << 0) /* from audio source 5 */ +#define IT6621_TX_AUD2_FROM_SRC6 (0x06 << 0) /* from audio source 6 */ +#define IT6621_TX_AUD2_FROM_SRC7 (0x07 << 0) /* from audio source 7 */ +#define IT6621_TX_AUD3_SEL GENMASK(6, 4) /* TX audio 3 input selection */ +#define IT6621_TX_AUD3_FROM_SRC0 (0x00 << 4) /* from audio source 0 */ +#define IT6621_TX_AUD3_FROM_SRC1 (0x01 << 4) /* from audio source 1 */ +#define IT6621_TX_AUD3_FROM_SRC2 (0x02 << 4) /* from audio source 2 */ +#define IT6621_TX_AUD3_FROM_SRC3 (0x03 << 4) /* from audio source 3 */ +#define IT6621_TX_AUD3_FROM_SRC4 (0x04 << 4) /* from audio source 4 */ +#define IT6621_TX_AUD3_FROM_SRC5 (0x05 << 4) /* from audio source 5 */ +#define IT6621_TX_AUD3_FROM_SRC6 (0x06 << 4) /* from audio source 6 */ +#define IT6621_TX_AUD3_FROM_SRC7 (0x07 << 4) /* from audio source 7 */ + +#define IT6621_REG_TX_AUD_SEL3 0x86 +#define IT6621_TX_AUD4_SEL GENMASK(2, 0) /* TX audio 4 input selection */ +#define IT6621_TX_AUD4_FROM_SRC0 (0x00 << 0) /* from audio source 0 */ +#define IT6621_TX_AUD4_FROM_SRC1 (0x01 << 0) /* from audio source 1 */ +#define IT6621_TX_AUD4_FROM_SRC2 (0x02 << 0) /* from audio source 2 */ +#define IT6621_TX_AUD4_FROM_SRC3 (0x03 << 0) /* from audio source 3 */ +#define IT6621_TX_AUD4_FROM_SRC4 (0x04 << 0) /* from audio source 4 */ +#define IT6621_TX_AUD4_FROM_SRC5 (0x05 << 0) /* from audio source 5 */ +#define IT6621_TX_AUD4_FROM_SRC6 (0x06 << 0) /* from audio source 6 */ +#define IT6621_TX_AUD4_FROM_SRC7 (0x07 << 0) /* from audio source 7 */ +#define IT6621_TX_AUD5_SEL GENMASK(6, 4) /* TX audio 5 input selection */ +#define IT6621_TX_AUD5_FROM_SRC0 (0x00 << 4) /* from audio source 0 */ +#define IT6621_TX_AUD5_FROM_SRC1 (0x01 << 4) /* from audio source 1 */ +#define IT6621_TX_AUD5_FROM_SRC2 (0x02 << 4) /* from audio source 2 */ +#define IT6621_TX_AUD5_FROM_SRC3 (0x03 << 4) /* from audio source 3 */ +#define IT6621_TX_AUD5_FROM_SRC4 (0x04 << 4) /* from audio source 4 */ +#define IT6621_TX_AUD5_FROM_SRC5 (0x05 << 4) /* from audio source 5 */ +#define IT6621_TX_AUD5_FROM_SRC6 (0x06 << 4) /* from audio source 6 */ +#define IT6621_TX_AUD5_FROM_SRC7 (0x07 << 4) /* from audio source 7 */ + +#define IT6621_REG_TX_AUD_SEL4 0x87 +#define IT6621_TX_AUD6_SEL GENMASK(2, 0) /* TX audio 6 input selection */ +#define IT6621_TX_AUD6_FROM_SRC0 (0x00 << 0) /* from audio source 0 */ +#define IT6621_TX_AUD6_FROM_SRC1 (0x01 << 0) /* from audio source 1 */ +#define IT6621_TX_AUD6_FROM_SRC2 (0x02 << 0) /* from audio source 2 */ +#define IT6621_TX_AUD6_FROM_SRC3 (0x03 << 0) /* from audio source 3 */ +#define IT6621_TX_AUD6_FROM_SRC4 (0x04 << 0) /* from audio source 4 */ +#define IT6621_TX_AUD6_FROM_SRC5 (0x05 << 0) /* from audio source 5 */ +#define IT6621_TX_AUD6_FROM_SRC6 (0x06 << 0) /* from audio source 6 */ +#define IT6621_TX_AUD6_FROM_SRC7 (0x07 << 0) /* from audio source 7 */ +#define IT6621_TX_AUD7_SEL GENMASK(6, 4) /* TX audio 7 input selection */ +#define IT6621_TX_AUD7_FROM_SRC0 (0x00 << 4) /* from audio source 0 */ +#define IT6621_TX_AUD7_FROM_SRC1 (0x01 << 4) /* from audio source 1 */ +#define IT6621_TX_AUD7_FROM_SRC2 (0x02 << 4) /* from audio source 2 */ +#define IT6621_TX_AUD7_FROM_SRC3 (0x03 << 4) /* from audio source 3 */ +#define IT6621_TX_AUD7_FROM_SRC4 (0x04 << 4) /* from audio source 4 */ +#define IT6621_TX_AUD7_FROM_SRC5 (0x05 << 4) /* from audio source 5 */ +#define IT6621_TX_AUD7_FROM_SRC6 (0x06 << 4) /* from audio source 6 */ +#define IT6621_TX_AUD7_FROM_SRC7 (0x07 << 4) /* from audio source 7 */ + +#define IT6621_REG_TX_AUD_FORCE_OUTPUT 0x88 /* 1: force output data to 24-bit '0' */ + +#define IT6621_REG_TX_AUD_CTRL9 0x89 +#define IT6621_TX_SPDIF_REC_EN BIT(0) /* 1: enable SPDIF input record channel status */ +#define IT6621_TX_SPDIF_ERR_DET_EN BIT(1) /* 1: enable SPDIF input channel + * status error detection + */ +#define IT6621_TX_MCLK_FREQ GENMASK(3, 2) /* Input MCLK frequency selection */ +#define IT6621_TX_MCLK_FREQ_128FS (0x00 << 2) /* 128FS */ +#define IT6621_TX_MCLK_FREQ_256FS (0x01 << 2) /* 256FS */ +#define IT6621_TX_MCLK_FREQ_512FS (0x02 << 2) /* 512FS */ +#define IT6621_TX_MCLK_FREQ_1024FS (0x03 << 2) /* 1024FS */ +#define IT6621_TX_MUTE_TO_OFF_EN BIT(4) /* 1: enable TXMUTE to audio off */ +#define IT6621_TX_FIFO_ERR_TO_MUTE_EN BIT(5) /* 1: enable FIFO error to audio mute */ +#define IT6621_TX_NO_CLK_TO_MUTE_EN BIT(6) /* 1: enable no TBCLK to audio mute */ +#define IT6621_TX_UNSTB_CLK_TO_MUTE_EN BIT(7) /* 1: enable TBCLK unstable to audio mute */ + +#define IT6621_REG_TX_AUD_CTRL10 0x8a +#define IT6621_TX_EXT_MUTE_SEL BIT(0) /* external MUTE input + * RegEnTxMute=RegF0[1] at FPGA + * register (SlvAddr=0x88) + */ +#define IT6621_TX_EXT_MUTE_EN (0x00 << 0) /* enable */ +#define IT6621_TX_EXT_MUTE_DIS (0x01 << 0) /* disable */ +#define IT6621_TX_AUTO_CH_STAT_MUTE_SEL BIT(1) /* eARC TX channel status MUTE auto mode */ +#define IT6621_TX_AUTO_CH_STAT_MUTE_DIS (0x00 << 1) /* disable */ +#define IT6621_TX_AUTO_CH_STAT_MUTE_EN (0x01 << 1) /* enable */ +#define IT6621_TX_AUTO_AUD_FMT_SEL BIT(2) /* eARC TX channel status audio format auto mode */ +#define IT6621_TX_AUTO_AUD_FMT_DIS (0x00 << 2) /* disable */ +#define IT6621_TX_AUTO_AUD_FMT_EN (0x01 << 2) /* enable */ +#define IT6621_TX_AUTO_LAYOUT_SEL BIT(3) /* eARC TX channel status layout auto mode */ +#define IT6621_TX_AUTO_LAYOUT_DIS (0x00 << 3) /* disable */ +#define IT6621_TX_AUTO_LAYOUT_EN (0x01 << 3) /* enable */ +#define IT6621_TX_MCH_LPCM_SEL BIT(4) /* eARC TX force multi-channel LPCM */ +#define IT6621_TX_MCH_LPCM_DIS (0x00 << 4) /* disable */ +#define IT6621_TX_MCH_LPCM_EN (0x01 << 4) /* enable */ +#define IT6621_TX_NLPCM_I2S_SEL BIT(5) /* eARC TX force NLPCM from I2S interface */ +#define IT6621_TX_NLPCM_I2S_DIS (0x00 << 5) /* disable */ +#define IT6621_TX_NLPCM_I2S_EN (0x01 << 5) /* enable */ +#define IT6621_TX_2CH_LAYOUT_SEL BIT(6) /* eARC TX force 2-channel layout */ +#define IT6621_TX_2CH_LAYOUT_DIS (0x00 << 6) /* disable */ +#define IT6621_TX_2CH_LAYOUT_EN (0x01 << 6) /* enable */ +#define IT6621_TX_FORCE_MUTE_SEL BIT(7) /* force TXMUTE */ +#define IT6621_TX_FORCE_MUTE_DIS (0x00 << 7) /* disable */ +#define IT6621_TX_FORCE_MUTE_EN (0x01 << 7) /* enable */ + +/* eARC TX AFE Registers */ +#define IT6621_REG_TX_AFE0 0xa0 +#define IT6621_TX_XP_RESET_SEL BIT(0) /* Reset PLL, low active */ +#define IT6621_TX_XP_RESET_ACTIVE (0x00 << 0) /* active */ +#define IT6621_TX_XP_RESET_INACTIVE (0x01 << 0) /* inactive */ +#define IT6621_TX_XP_PWD BIT(1) /* Power down PLL, low active */ +#define IT6621_TX_XP_IPWD BIT(2) /* Power down the bias for PLL and LC, low active */ + +#define IT6621_REG_TX_AFE1 0xa1 +#define IT6621_TX_XP_PDIV GENMASK(1, 0) /* Set PDIV[1:0] by + * TBCLKSEL[2:0] and the + * frequency of AICLK. + * When TBCLKSEL=101, set 00 + * When TBCLKSEL=100 + * 2.048MHz~3.072MHz: set 00 + * 4.096MHz~6.144MHz: set 01 + * When TBCLKSEL=011 + * 2.048MHz~3.072MHz: set 00 + * 4.096MHz~6.144MHz: set 01 + * 8.192MHz~12.288MHz: set 10 or 11 + * When TBCLKSEL=010 + * 4.096MHz~6.144MHz: set 00 + * 8.192MHz~12.288MHz: set 01 + * 16.384MHz~24.576MHz: set 10 or 11 + * When TBCLKSEL=001 + * 2.048MHz~12.288MHz: set 00 + * 16.384MHz~24.576MHz: set 01 + * 32.768MHz~49.152MHz: set 10 or 11 + * When TBCLKSEL=000 + * 4.096MHz~24.576MHz: set 00 + * 32.768MHz~49.152MHz: set 01 + * 65.536MHz~98.304MHz: set 10 or 11 + */ +#define IT6621_TX_XP_GAIN BIT(2) /* Set GAIN by TBCLKSEL[2:0] and + * the frequency of AICLK + * When TBCLK=000, 4.096MHz~6.144MHz: set 0 + * When TBCLK=001, 2.048MHz~3.072MHz: set 0 + * When others set1 + */ +#define IT6621_TX_XP_DEI_SEL BIT(3) +#define IT6621_TX_XP_DEI_DIS (0x00 << 3) +#define IT6621_TX_XP_DEI_EN (0x01 << 3) +#define IT6621_TX_XP_ER0_SEL BIT(4) +#define IT6621_TX_XP_ER0_DIS (0x00 << 4) +#define IT6621_TX_XP_ER0_EN (0x01 << 4) +#define IT6621_TX_AUTO_XP_GAIN_SEL BIT(6) /* 1: XP_GAIN auto mode */ +#define IT6621_TX_AUTO_XP_GAIN_DIS (0x00 << 6) +#define IT6621_TX_AUTO_XP_GAIN_EN (0x01 << 6) +#define IT6621_TX_AUTO_XP_PDIV_SEL BIT(7) /* 1: XP_PDIV[1:0] auto mode */ +#define IT6621_TX_AUTO_XP_PDIV_DIS (0x00 << 7) +#define IT6621_TX_AUTO_XP_PDIV_EN (0x01 << 7) + +#define IT6621_REG_TX_AFE2 0xa2 +#define IT6621_TX_DRV_DPWD BIT(0) /* Power down the differential + * mode driver, high active. + * NOTE: Set 1 in ARC mode. + */ +#define IT6621_TX_DRV_RESET_SEL BIT(1) /* Reset the differential mode + * driver, high active. + * NOTE: Set 1 in ARC mode. + */ +#define IT6621_TX_DRV_RESET_DIS (0x00 << 1) +#define IT6621_TX_DRV_RESET_EN (0x01 << 1) +#define IT6621_TX_DRV_DC GENMASK(3, 2) +#define IT6621_TX_DRV_DC_DIS (0x00 << 2) +#define IT6621_TX_DRV_DC_EN (0x01 << 2) +#define IT6621_TX_DRV_DC_SEL_DIS (0x00 << 3) +#define IT6621_TX_DRV_DC_SEL_EN (0x01 << 3) +#define IT6621_TX_DRV_DSW_SEL GENMASK(6, 4) +#define IT6621_TX_DRV_DSW_4 (0x04 << 4) +#define IT6621_TX_DRV_DSW_7 (0x07 << 4) +#define IT6621_TX_DRV_OT_SEL BIT(7) +#define IT6621_TX_DRV_OT_DIS (0x00 << 7) +#define IT6621_TX_DRV_OT_EN (0x01 << 7) + +#define IT6621_REG_TX_AFE3 0xa3 +#define IT6621_TX_DRV_CPWD BIT(0) /* Power down the common mode driver, high active */ +#define IT6621_TX_DRV_CSR_SEL GENMASK(3, 1) /* 0: fastest, 7: slowest */ +#define IT6621_TX_DRV_CSR_2 (0x02 << 1) +#define IT6621_TX_DRV_CSR_4 (0x04 << 1) +#define IT6621_TX_DRV_CSW_SEL GENMASK(6, 4) /* 0: minimum, 7: maximum */ +#define IT6621_TX_DRV_CSW_4 (0x04 << 4) +#define IT6621_TX_DRV_CSW_7 (0x07 << 4) +#define IT6621_TX_IN_ARC_MODE_SEL BIT(7) /* In ARC mode */ +#define IT6621_TX_IN_ARC_SIGNAL_MODE (0x00 << 7) /* signal mode */ +#define IT6621_TX_IN_ARC_COMMON_MODE (0x01 << 7) /* common mode */ + +#define IT6621_REG_TX_AFE4 0xa4 +#define IT6621_TX_RC_PWD BIT(0) /* Power down common receiver, + * high active. + * NOTE: Set 1 in ARC mode. + */ +#define IT6621_TX_RC_CK_SEL BIT(1) +#define IT6621_TX_RC_CK_DIS (0x00 << 1) +#define IT6621_TX_RC_CK_EN (0x01 << 1) +#define IT6621_TX_VCM_SEL GENMASK(3, 2) +#define IT6621_TX_VCM0 (0x00 << 2) +#define IT6621_TX_VCM1 (0x01 << 2) +#define IT6621_TX_VCM2 (0x02 << 2) +#define IT6621_TX_VCM3 (0x03 << 2) +#define IT6621_TX_HYS_SEL GENMASK(6, 4) +#define IT6621_TX_HYS5 (0x05 << 4) +#define IT6621_TX_HYS6 (0x06 << 4) + +#define IT6621_REG_TX_AFE5 0xa5 +#define IT6621_TX_LC_PWD BIT(4) /* PWD=0, LCVCO is at power down */ +#define IT6621_TX_LC_ICTP_PWD BIT(5) /* ICTP_PWD=0, ICTP block is at power down */ +#define IT6621_TX_LC_RESET BIT(6) /* RESET=0, LCVCO is at reset */ + +#define IT6621_REG_TX_AFE15 0xaf +#define IT6621_TX_AUTO_DPWD_SEL BIT(0) /* 1: enable auto power down + * differential mode TX AFE + */ +#define IT6621_TX_AUTO_DPWD_DIS (0x00 << 0) +#define IT6621_TX_AUTO_DPWD_EN (0x01 << 0) +#define IT6621_TX_AUTO_DRST_SEL BIT(1) /* 1: enable auto reset differential mode TX AFE */ +#define IT6621_TX_AUTO_DRST_DIS (0x00 << 1) +#define IT6621_TX_AUTO_DRST_EN (0x01 << 1) +#define IT6621_TX_AUTO_CPWD_SEL BIT(2) /* 1: enable auto power down common mode TX AFE */ +#define IT6621_TX_AUTO_CPWD_DIS (0x00 << 2) +#define IT6621_TX_AUTO_CPWD_EN (0x01 << 2) + +/* eARC Clock Detection Registers */ +#define IT6621_REG_CLK_DET0 0xc0 +#define IT6621_ACLK_BND_NUM_LOW GENMASK(7, 0) /* ACLK frequency boundary + * for XP_PDIV auto setting. + * 128T@3.584MHz count by 10MHz RCLK. + */ + +#define IT6621_REG_CLK_DET1 0xc1 +#define IT6621_ACLK_BND_NUM_HIGH BIT(0) + +#define IT6621_REG_CLK_DET2 0xc2 +#define IT6621_ACLK_VALID_NUM_LOW GENMASK(7, 0) /* ACLK frequency valid for + * XP_PDIV auto setting. + * 128T@2MHz count by 10MHz RCLK. + */ + +#define IT6621_REG_CLK_DET3 0xc3 +#define IT6621_ACLK_VALID_NUM_HIGH GENMASK(1, 0) + +#define IT6621_REG_CLK_DET4 0xc4 +#define IT6621_BCLK_BND_NUM GENMASK(7, 0) /* BCLK frequency boundary + * for FSEL auto setting. + * 128T@6.25MHz count by 10MHz RCLK. + */ + +#define IT6621_REG_CLK_DET5 0xc5 +#define IT6621_BCLK_VALID_NUM_LOW GENMASK(7, 0) /* BCLK frequency valid for + * FSEL auto setting. + * 128T@4MHz count by 10MHz RCLK. + */ + +#define IT6621_REG_CLK_DET6 0xc6 +#define IT6621_BCLK_VALID_NUM_HIGH BIT(0) + +#define IT6621_REG_CLK_DET7 0xc7 +#define IT6621_ACLK_DET_EN_SEL BIT(0) /* enable ACLK clock detection */ +#define IT6621_ACLK_DET_DIS (0x00 << 0) +#define IT6621_ACLK_DET_EN (0x01 << 0) +#define IT6621_BCLK_DET_EN_SEL BIT(1) /* 1: enable BCLK clock detection */ +#define IT6621_UPDATE_AVG_EN_SEL BIT(4) /* enable update average clock detection value */ +#define IT6621_UPDATE_AVG_DIS (0x00 << 4) +#define IT6621_UPDATE_AVG_EN (0x01 << 4) +#define IT6621_CLK_DIFF_MIN_EN BIT(5) +#define IT6621_CLK_ORG_DELTA_EN (0x00 << 5) /* 0: Original delta */ +#define IT6621_CLK_FIX_MIN_DELTA_EN (0x01 << 5) /* 1: Fix minimum delta */ +#define IT6621_RCLK_DELTA_SEL GENMASK(7, 6) /* RCLK deviation selection */ +#define IT6621_RCLK_DELTA1 (0x00 << 6) /* +/-1% */ +#define IT6621_RCLK_DELTA2 (0x01 << 6) /* +/-2% */ +#define IT6621_RCLK_DELTA3 (0x02 << 6) /* +/-3% */ +#define IT6621_RCLK_DELTA5 (0x03 << 6) /* +/-5% */ + +#define IT6621_REG_CLK_DET8 0xc8 +#define IT6621_DET_ACLK_AVG_LOW GENMASK(7, 0) /* ACLK frequency detection */ + +#define IT6621_REG_CLK_DET9 0xc9 +#define IT6621_DET_ACLK_AVG_HIGH GENMASK(3, 0) +#define IT6621_DET_ACLK_PRE_DIV_2 BIT(4) /* 1: ACLK is pre-divided by 2 */ +#define IT6621_DET_ACLK_PRE_DIV_4 BIT(5) /* 1: ACLK is pre-divided by 4 */ +#define IT6621_DET_ACLK_FREQ_VALID BIT(6) /* 1: ACLK frequency is valid */ +#define IT6621_DET_ACLK_FREQ_STB BIT(7) /* 1: ACLK frequency detection */ + +#define IT6621_REG_CLK_DET10 0xca +#define IT6621_DET_BCLK_AVG_LOW GENMASK(7, 0) /* BCLK frequency detection */ + +#define IT6621_REG_CLK_DET11 0xcb +#define IT6621_DET_BCLK_AVG_HIGH GENMASK(2, 0) +#define IT6621_DET_BCLK_PRE_DIV_2 BIT(4) /* 1: BCLK is pre-divided by 2 */ +#define IT6621_DET_BCLK_PRE_DIV_4 BIT(5) /* 1: BCLK is pre-divided by 4 */ +#define IT6621_DET_BCLK_FREQ_VALID BIT(6) /* 1: BCLK frequency is valid */ +#define IT6621_DET_BCLK_FREQ_STB BIT(7) /* 1: BCLK frequency detection */ + +/* GPIO Control Registers */ +#define IT6621_REG_GPIO_CTRL0 0xe8 +#define IT6621_I2S0_GPIO_MODE_EN BIT(0) /* 1: enable I2S0 GPIO mode */ +#define IT6621_I2S0_GPIO_OUTPUT_EN BIT(1) /* 1: enable I2S0 output enable */ +#define IT6621_I2S0_GPIO_OUTPUT_VAL BIT(2) /* I2S0 GPIO output value */ +#define IT6621_I2S0_GPIO_INPUT_VAL BIT(3) /* I2S0 GPIO input value */ +#define IT6621_I2S1_GPIO_MODE_EN BIT(4) /* 1: enable I2S1 GPIO mode */ +#define IT6621_I2S1_GPIO_OUTPUT_EN BIT(5) /* 1: enable I2S1 output enable */ +#define IT6621_I2S1_GPIO_OUTPUT_VAL BIT(6) /* I2S1 GPIO output value */ +#define IT6621_I2S1_GPIO_INPUT_VAL BIT(7) /* I2S1 GPIO input value */ + +#define IT6621_REG_GPIO_CTRL1 0xe9 +#define IT6621_I2S2_GPIO_MODE_EN BIT(0) /* 1: enable I2S2 GPIO mode */ +#define IT6621_I2S2_GPIO_OUTPUT_EN BIT(1) /* 1: enable I2S2 output enable */ +#define IT6621_I2S2_GPIO_OUTPUT_VAL BIT(2) /* I2S2 GPIO output value */ +#define IT6621_I2S2_GPIO_INPUT_VAL BIT(3) /* I2S2 GPIO input value */ +#define IT6621_I2S3_GPIO_MODE_EN BIT(4) /* 1: enable I2S3 GPIO mode */ +#define IT6621_I2S3_GPIO_OUTPUT_EN BIT(5) /* 1: enable I2S3 output enable */ +#define IT6621_I2S3_GPIO_OUTPUT_VAL BIT(6) /* I2S3 GPIO output value */ +#define IT6621_I2S3_GPIO_INPUT_VAL BIT(7) /* I2S3 GPIO input value */ + +#define IT6621_REG_GPIO_CTRL2 0xea +#define IT6621_I2S4_GPIO_MODE_EN BIT(0) /* 1: enable I2S4 GPIO mode */ +#define IT6621_I2S4_GPIO_OUTPUT_EN BIT(1) /* 1: enable I2S4 output enable */ +#define IT6621_I2S4_GPIO_OUTPUT_VAL BIT(2) /* I2S4 GPIO output value */ +#define IT6621_I2S4_GPIO_INPUT_VAL BIT(3) /* I2S4 GPIO input value */ +#define IT6621_I2S5_GPIO_MODE_EN BIT(4) /* 1: enable I2S5 GPIO mode */ +#define IT6621_I2S5_GPIO_OUTPUT_EN BIT(5) /* 1: enable I2S5 output enable */ +#define IT6621_I2S5_GPIO_OUTPUT_VAL BIT(6) /* I2S5 GPIO output value */ +#define IT6621_I2S5_GPIO_INPUT_VAL BIT(7) /* I2S5 GPIO input value */ + +#define IT6621_REG_GPIO_CTRL3 0xeb +#define IT6621_I2S6_GPIO_MODE_EN BIT(0) /* 1: enable I2S6 GPIO mode */ +#define IT6621_I2S6_GPIO_OUTPUT_EN BIT(1) /* 1: enable I2S6 output enable */ +#define IT6621_I2S6_GPIO_OUTPUT_VAL BIT(2) /* I2S6 GPIO output value */ +#define IT6621_I2S6_GPIO_INPUT_VAL BIT(3) /* I2S6 GPIO input value */ +#define IT6621_I2S7_GPIO_MODE_EN BIT(4) /* 1: enable I2S7 GPIO mode */ +#define IT6621_I2S7_GPIO_OUTPUT_EN BIT(5) /* 1: enable I2S7 output enable */ +#define IT6621_I2S7_GPIO_OUTPUT_VAL BIT(6) /* I2S7 GPIO output value */ +#define IT6621_I2S7_GPIO_INPUT_VAL BIT(7) /* I2S7 GPIO input value */ + +#define IT6621_REG_GPIO_CTRL4 0xec +#define IT6621_MCLK_GPIO_MODE_EN BIT(0) /* 1: enable MCLK GPIO mode */ +#define IT6621_MCLK_GPIO_OUTPUT_EN BIT(1) /* 1: enable MCLK output enable */ +#define IT6621_MCLK_GPIO_OUTPUT_VAL BIT(2) /* MCLK GPIO output value */ +#define IT6621_MCLK_GPIO_INPUT_VAL BIT(3) /* MCLK GPIO input value */ +#define IT6621_SPDIF_GPIO_MODE_EN BIT(4) /* 1: enable SPDIF GPIO mode */ +#define IT6621_SPDIF_GPIO_OUTPUT_EN BIT(5) /* 1: enable SPDIF output enable */ +#define IT6621_SPDIF_GPIO_OUTPUT_VAL BIT(6) /* SPDIF GPIO output value */ +#define IT6621_SPDIF_GPIO_INPUT_VAL BIT(7) /* SPDIF GPIO input value */ + +#define IT6621_REG_GPIO_CTRL5 0xed +#define IT6621_MUTE_GPIO_MODE_EN BIT(0) /* 1: enable MUTE GPIO mode */ +#define IT6621_MUTE_GPIO_OUTPUT_EN BIT(1) /* 1: enable MUTE output enable */ +#define IT6621_MUTE_GPIO_OUTPUT_VAL BIT(2) /* MUTE GPIO output value */ +#define IT6621_MUTE_GPIO_INPUT_VAL BIT(3) /* MUTE GPIO input value */ +#define IT6621_HPDB_GPIO_MODE_EN BIT(4) /* 1: enable HPDB GPIO mode */ +#define IT6621_HPDB_GPIO_OUTPUT_EN BIT(5) /* 1: enable HPDB output enable */ +#define IT6621_HPDB_GPIO_OUTPUT_VAL BIT(6) /* HPDB GPIO output value */ +#define IT6621_HPDB_GPIO_INPUT_VAL BIT(7) /* HPDB GPIO input value */ + +/* Misc Registers */ +#define IT6621_REG_MISC0 0xf0 +#define IT6621_DEBUG_SEL GENMASK(2, 0) /* Select one of the 8 debug groups */ +#define IT6621_DEBUG_EN BIT(3) /* 1: enable debug output */ +#define IT6621_AUD_DEBUG_EN BIT(5) /* 1: Enable audio signal debug output */ + +#define IT6621_REG_MISC1 0xf1 +#define IT6621_HPD_DG_TIME_SEL GENMASK(1, 0) /* HPD de-glitch time selection */ +#define IT6621_HPD_DG_TIME_10US (0x00 << 0) /* 10us */ +#define IT6621_HPD_DG_TIME_100US (0x01 << 0) /* 100us */ +#define IT6621_HPD_DG_TIME_1MS (0x02 << 0) /* 1ms */ +#define IT6621_HPD_DG_TIME_10MS (0x03 << 0) /* 10ms */ +#define IT6621_CMD_HOLD_TIME GENMASK(7, 4) /* PCI2C hold time */ + +#define IT6621_REG_MISC2 0xf2 +#define IT6621_CMD_DRV GENMASK(1, 0) /* Driving setting for PCSCL and PCSDA */ +#define IT6621_HPD_DRV GENMASK(3, 2) /* Driving setting for HPD signals */ +#define IT6621_I2S_DRV GENMASK(5, 4) /* Driving setting for I2S signals */ +#define IT6621_SPDIF_DRV GENMASK(7, 6) /* Driving setting for SPDIF signals */ + +#define IT6621_REG_MISC3 0xf3 +#define IT6621_CMD_SMT BIT(0) /* PCSCL/PCSDA Schmitt trigger option */ +#define IT6621_SCK_SMT BIT(2) /* SCK/DCLK Schmitt trigger option */ +#define IT6621_MCLK_SMT BIT(3) /* MCLK Schmitt trigger option */ +#define IT6621_SPDIFSMT BIT(4) /* SPDIF Schmitt trigger option */ + +#define IT6621_REG_MISC12 0xfc +#define IT6621_CRCLK_SEL_EN BIT(0) +#define IT6621_PWD_CRCLK (0x00 << 0) /* power-down CRCLK and disable CEC function */ +#define IT6621_CRCLK_EN (0x01 << 0) /* enable CRCLK for CEC function */ +#define IT6621_CEC_SLAVE_ADDR GENMASK(7, 1) /* CEC slave address */ + +#define IT6621_REG_PASS_WORD 0xff /* 0xC3/0xA5 on, 0xFF off */ +#define IT6621_PASS_WORD_ON1 0xc3 +#define IT6621_PASS_WORD_ON2 0xa5 +#define IT6621_PASS_WORD_OFF 0xff + +#endif /* _IT6621_REG_BANK0_H */ diff --git a/sound/soc/codecs/it6621/it6621-reg-bank1.h b/sound/soc/codecs/it6621/it6621-reg-bank1.h new file mode 100644 index 000000000000..f75174ff0e36 --- /dev/null +++ b/sound/soc/codecs/it6621/it6621-reg-bank1.h @@ -0,0 +1,147 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (c) 2024 Rockchip Electronics Co. Ltd. + * Author: Jason Zhang + */ + +#ifndef _IT6621_REG_BANK1_H +#define _IT6621_REG_BANK1_H + +/* Bank 1 */ + +/* General Registers */ +#define IT6621_REG_GEN0 0x110 +#define IT6621_100MS_CNT_SEL BIT(7) /* Enable 100ms calibration counter */ +#define IT6621_100MS_CNT_DIS (0x00 << 7) +#define IT6621_100MS_CNT_EN (0x01 << 7) + +#define IT6621_REG_100MS_CNT_7_0 0x111 /* 100ms counter value */ +#define IT6621_REG_100MS_CNT_15_8 0x112 +#define IT6621_REG_100MS_CNT_23_16 0x113 + +#define IT6621_REG_GEN4 0x114 +#define IT6621_1US_TIME_INT GENMASK(5, 0) /* 1us time base integer number. + * Note: default value is + * calculated by 10MHz RCLK. + */ + +#define IT6621_REG_1US_TIME_FLT 0x115 /* 1us time base floating number */ + +#define IT6621_REG_GEN6 0x116 +#define IT6621_TIMER_INT_NUM GENMASK(6, 0) /* User defined timer + * interrupt count number + */ +#define IT6621_TIMER_INT_UNIT BIT(7) +#define IT6621_TIMER_INT_UNIT_10MS (0x00 << 7) /* unit=10ms */ +#define IT6621_TIMER_INT_UNIT_100MS (0x01 << 7) /* unit=100ms */ + +#define IT6621_REG_GEN7 0x117 +#define IT6621_TIME_STAMP_EN_SEL GENMASK(6, 0) /* Time stamp for firmware */ +#define IT6621_TIME_STAMP_EN BIT(7) /* 1: Enable time stamp */ + +/* Input SPDIF Channel Status Registers */ +#define IT6621_REG_AI_TX_CH_ST_7_0 0x120 +#define IT6621_REG_AI_TX_CH_ST_15_8 0x121 +#define IT6621_REG_AI_TX_CH_ST_23_16 0x122 +#define IT6621_REG_AI_TX_CH_ST_31_24 0x123 +#define IT6621_REG_AI_TX_CH_ST_39_32 0x124 + +/* eARC TX Channel Status Registers */ +#define IT6621_REG_TX_CH_ST0 0x130 +#define IT6621_REG_TX_CH_ST1 0x131 +#define IT6621_REG_TX_CH_ST2 0x132 +#define IT6621_REG_TX_CH_ST3 0x133 +#define IT6621_REG_TX_CH_ST4 0x134 +#define IT6621_REG_TX_CH_ST5 0x135 +#define IT6621_REG_TX_CH_ST9 0x139 +#define IT6621_REG_TX_CH_ST10 0x13a +#define IT6621_REG_TX_CH_ST11 0x13b +#define IT6621_REG_TX_CH_ST12 0x13c +#define IT6621_REG_TX_CH_ST13 0x13d +#define IT6621_REG_TX_CH_ST14 0x13e +#define IT6621_REG_TX_CH_ST15 0x13f + +/* eARC TX U-bit Packet Registers */ + +/* Packet Type 1 */ +#define IT6621_REG_TX_PKT1_CRC 0x150 /* eARC TX packet CRC */ +#define IT6621_REG_TX_PKT1_CH 0x151 /* eARC TX packet CH */ +#define IT6621_REG_TX_PKT1_HB0 0x152 /* eARC TX packet HB0 */ +#define IT6621_REG_TX_PKT1_HB1 0x153 /* eARC TX packet HB1 */ +#define IT6621_REG_TX_PKT1_HB2 0x154 /* eARC TX packet HB2 */ +#define IT6621_REG_TX_PKT1_PB0 0x155 /* eARC TX packet PB0 */ +#define IT6621_REG_TX_PKT1_PB1 0x156 /* eARC TX packet PB1 */ +#define IT6621_REG_TX_PKT1_PB2 0x157 /* eARC TX packet PB2 */ +#define IT6621_REG_TX_PKT1_PB3 0x158 /* eARC TX packet PB3 */ +#define IT6621_REG_TX_PKT1_PB4 0x159 /* eARC TX packet PB4 */ +#define IT6621_REG_TX_PKT1_PB5 0x15a /* eARC TX packet PB5 */ +#define IT6621_REG_TX_PKT1_PB6 0x15b /* eARC TX packet PB6 */ +#define IT6621_REG_TX_PKT1_PB7 0x15c /* eARC TX packet PB7 */ +#define IT6621_REG_TX_PKT1_PB8 0x15d /* eARC TX packet PB8 */ +#define IT6621_REG_TX_PKT1_PB9 0x15e /* eARC TX packet PB9 */ +#define IT6621_REG_TX_PKT1_PB10 0x15f /* eARC TX packet PB10 */ +#define IT6621_REG_TX_PKT1_PB11 0x160 /* eARC TX packet PB11 */ +#define IT6621_REG_TX_PKT1_PB12 0x161 /* eARC TX packet PB12 */ +#define IT6621_REG_TX_PKT1_PB13 0x162 /* eARC TX packet PB13 */ +#define IT6621_REG_TX_PKT1_PB14 0x163 /* eARC TX packet PB14 */ +#define IT6621_REG_TX_PKT1_PB15 0x164 /* eARC TX packet PB15 */ +#define IT6621_REG_TX_PKT1_PB16 0x165 /* eARC TX packet PB16 */ +#define IT6621_REG_TX_PKT1_PB17 0x166 /* eARC TX packet PB17 */ +#define IT6621_REG_TX_PKT1_PB18 0x167 /* eARC TX packet PB18 */ +#define IT6621_REG_TX_PKT1_PB19 0x168 /* eARC TX packet PB19 */ +#define IT6621_REG_TX_PKT1_PB20 0x169 /* eARC TX packet PB20 */ +#define IT6621_REG_TX_PKT1_PB21 0x16a /* eARC TX packet PB21 */ +#define IT6621_REG_TX_PKT1_PB22 0x16b /* eARC TX packet PB22 */ +#define IT6621_REG_TX_PKT1_PB23 0x16c /* eARC TX packet PB23 */ +#define IT6621_REG_TX_PKT1_PB24 0x16d /* eARC TX packet PB24 */ +#define IT6621_REG_TX_PKT1_PB25 0x16e /* eARC TX packet PB25 */ +#define IT6621_REG_TX_PKT1_PB26 0x16f /* eARC TX packet PB26 */ +#define IT6621_REG_TX_PKT1_PB27 0x170 /* eARC TX packet PB27 */ + +/* Packet Type 2 */ +#define IT6621_REG_TX_PKT2_CRC 0x171 /* eARC TX packet CRC */ +#define IT6621_REG_TX_PKT2_CH 0x172 /* eARC TX packet CH */ +#define IT6621_REG_TX_PKT2_HB0 0x173 /* eARC TX packet HB0 */ +#define IT6621_REG_TX_PKT2_HB1 0x174 /* eARC TX packet HB1 */ +#define IT6621_REG_TX_PKT2_HB2 0x175 /* eARC TX packet HB2 */ +#define IT6621_REG_TX_PKT2_PB0 0x176 /* eARC TX packet PB0 */ +#define IT6621_REG_TX_PKT2_PB1 0x177 /* eARC TX packet PB1 */ +#define IT6621_REG_TX_PKT2_PB2 0x178 /* eARC TX packet PB2 */ +#define IT6621_REG_TX_PKT2_PB3 0x179 /* eARC TX packet PB3 */ +#define IT6621_REG_TX_PKT2_PB4 0x17a /* eARC TX packet PB4 */ +#define IT6621_REG_TX_PKT2_PB5 0x17b /* eARC TX packet PB5 */ +#define IT6621_REG_TX_PKT2_PB6 0x17c /* eARC TX packet PB6 */ +#define IT6621_REG_TX_PKT2_PB7 0x17d /* eARC TX packet PB7 */ +#define IT6621_REG_TX_PKT2_PB8 0x17e /* eARC TX packet PB8 */ +#define IT6621_REG_TX_PKT2_PB9 0x17f /* eARC TX packet PB9 */ +#define IT6621_REG_TX_PKT2_PB10 0x180 /* eARC TX packet PB10 */ +#define IT6621_REG_TX_PKT2_PB11 0x181 /* eARC TX packet PB11 */ +#define IT6621_REG_TX_PKT2_PB12 0x182 /* eARC TX packet PB12 */ +#define IT6621_REG_TX_PKT2_PB13 0x183 /* eARC TX packet PB13 */ +#define IT6621_REG_TX_PKT2_PB14 0x184 /* eARC TX packet PB14 */ +#define IT6621_REG_TX_PKT2_PB15 0x185 /* eARC TX packet PB15 */ + +/* Packet Type 3 */ +#define IT6621_REG_TX_PKT3_CRC 0x186 /* eARC TX packet CRC */ +#define IT6621_REG_TX_PKT3_CH 0x187 /* eARC TX packet CH */ +#define IT6621_REG_TX_PKT3_HB0 0x188 /* eARC TX packet HB0 */ +#define IT6621_REG_TX_PKT3_HB1 0x189 /* eARC TX packet HB1 */ +#define IT6621_REG_TX_PKT3_HB2 0x18a /* eARC TX packet HB2 */ +#define IT6621_REG_TX_PKT3_PB0 0x18b /* eARC TX packet PB0 */ +#define IT6621_REG_TX_PKT3_PB1 0x18c /* eARC TX packet PB1 */ +#define IT6621_REG_TX_PKT3_PB2 0x18d /* eARC TX packet PB2 */ +#define IT6621_REG_TX_PKT3_PB3 0x18e /* eARC TX packet PB3 */ +#define IT6621_REG_TX_PKT3_PB4 0x18f /* eARC TX packet PB4 */ +#define IT6621_REG_TX_PKT3_PB5 0x190 /* eARC TX packet PB5 */ +#define IT6621_REG_TX_PKT3_PB6 0x191 /* eARC TX packet PB6 */ +#define IT6621_REG_TX_PKT3_PB7 0x192 /* eARC TX packet PB7 */ +#define IT6621_REG_TX_PKT3_PB8 0x193 /* eARC TX packet PB8 */ +#define IT6621_REG_TX_PKT3_PB9 0x194 /* eARC TX packet PB9 */ +#define IT6621_REG_TX_PKT3_PB10 0x195 /* eARC TX packet PB10 */ +#define IT6621_REG_TX_PKT3_PB11 0x196 /* eARC TX packet PB11 */ +#define IT6621_REG_TX_PKT3_PB12 0x197 /* eARC TX packet PB12 */ +#define IT6621_REG_TX_PKT3_PB13 0x198 /* eARC TX packet PB13 */ +#define IT6621_REG_TX_PKT3_PB14 0x199 /* eARC TX packet PB14 */ +#define IT6621_REG_TX_PKT3_PB15 0x19a /* eARC TX packet PB15 */ + +#endif /* _IT6621_REG_BANK1_H */ diff --git a/sound/soc/codecs/it6621/it6621-reg-cec.h b/sound/soc/codecs/it6621/it6621-reg-cec.h new file mode 100644 index 000000000000..4ce8865bdc6b --- /dev/null +++ b/sound/soc/codecs/it6621/it6621-reg-cec.h @@ -0,0 +1,246 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (c) 2024 Rockchip Electronics Co. Ltd. + * Author: Jason Zhang + */ + +#ifndef _IT6621_REG_CEC_H +#define _IT6621_REG_CEC_H + +/* CEC Control Registers */ +#define IT6621_REG_CEC_CTRL6 0x06 /* 0: Interrupt Enable, 1: Interrupt Mask */ +#define IT6621_TX_INT_MASK BIT(0) +#define IT6621_RX_INT_MASK BIT(1) +#define IT6621_RX_FAIL_INT_MASK BIT(2) +#define IT6621_TX_DONE_INT_MASK BIT(3) +#define IT6621_RX_DONE_INT_MASK BIT(4) +#define IT6621_TX_FAIL_INT_MASK BIT(5) +#define IT6621_CMD_OVERFLOW_INT_MASK BIT(6) +#define IT6621_DATA_OVERFLOW_INT_MASK BIT(7) + +#define IT6621_REG_CEC_CTRL7 0x07 +#define IT6621_DBG_CEC_SEL GENMASK(4, 2) +#define IT6621_CEC_INT_STS_SEL BIT(5) + +#define IT6621_REG_CEC_CTRL8 0x08 +#define IT6621_CEC_INT_SEL BIT(0) /* CEC interrupt enable, + * 1: Enable, 0: Disable + */ +#define IT6621_CEC_INT_DIS (0x00 << 0) +#define IT6621_CEC_INT_EN (0x01 << 0) +#define IT6621_CEC_RESET_SEL BIT(2) /* Reset CEC block, + * 1: Enable, 0: Disable + */ +#define IT6621_CEC_RESET_DIS (0x00 << 2) +#define IT6621_CEC_RESET_EN (0x01 << 2) +#define IT6621_CEC_SMT BIT(3) /* Schmitt trigger of CEC IO, + * 1: Enable, 0: Disable + */ +#define IT6621_CEC_FORCE BIT(4) /* Force CEC output regardless of normal function */ +#define IT6621_CEC_OE BIT(5) /* Force CEC output value */ +#define IT6621_DBG_CEC_CLR BIT(6) /* For debug only */ +#define IT6621_FIRE_FRAME BIT(7) /* 1: Fire CEC command out */ + +#define IT6621_REG_CEC_CTRL9 0x09 +#define IT6621_EN_100MS_CNT BIT(0) /* Used as a reference 100ms + * time interval for CEC calibration + */ +#define IT6621_NACK_SEL BIT(1) /* Acknowledge from follower to initiator */ +#define IT6621_ACK_EN (0x00 << 1) /* ACK */ +#define IT6621_NACK_EN (0x01 << 1) /* NACK */ +#define IT6621_PULSE_SEL BIT(2) /* Select illegal bit as error bit */ +#define IT6621_PULSE_DIS (0x00 << 2) /* Disable */ +#define IT6621_PULSE_EN (0x01 << 2) /* Enable */ +#define IT6621_ACK_TRIG_SEL BIT(3) /* Acknowledge for broadcast mode */ +#define IT6621_ACK_TRIG_NACK (0x00 << 3) /* NACK */ +#define IT6621_ACK_TRIG_ACK (0x01 << 3) /* ACK */ +#define IT6621_REFIRE_SEL BIT(4) /* Retry to fire CEC command */ +#define IT6621_REFIRE_DIS (0x00 << 4) /* Disable */ +#define IT6621_REFIRE_EN (0x01 << 4) /* Enable */ +#define IT6621_RX_SELF_SEL BIT(5) /* Initiator received CEC bus data */ +#define IT6621_RX_SELF_EN (0x00 << 5) /* Enable */ +#define IT6621_RX_SELF_DIS (0x01 << 5) /* Disable */ +#define IT6621_REGION_SEL BIT(6) /* Select region for error bit */ +#define IT6621_REGION_START_TO_IDLE (0x00 << 6) /* Region form state Start to IDLE */ +#define IT6621_REGION_WHOLE (0x01 << 6) /* Whole region */ +#define IT6621_DATA_BIT_SEL BIT(7) /* Select data bit */ +#define IT6621_DATA_BIT_NORMAL (0x00 << 7) /* Normal */ +#define IT6621_DATA_BIT_INC_0P1MS (0x01 << 7) /* Increase 0.1ms */ + +#define IT6621_REG_CEC_CTRL10 0x0a +#define IT6621_BUS_FREE_SEL GENMASK(1, 0) /* Select bus free bit time */ +#define IT6621_BUS_FREE_AUTO (0x00 << 0) /* Automatic */ +#define IT6621_BUS_FREE_3BIT_TIME (0x01 << 0) /* 3 bit time */ +#define IT6621_BUS_FREE_5BIT_TIME (0x02 << 0) /* 5 bit time */ +#define IT6621_BUS_FREE_7BIT_TIME (0x03 << 0) /* 7 bit time */ +#define IT6621_BIT_END_SEL GENMASK(3, 2) /* Select logic 0 and + * logic 1 output bit time + */ +#define IT6621_BIT_END_STD (0x00 << 2) /* Standard */ +#define IT6621_BIT_END_MAX0_MIN1 (0x01 << 2) /* Logic 0 maximum and logic 1 minimum */ +#define IT6621_BIT_END_MAX1_MIN0 (0x02 << 2) /* Logic 1 maximum and logic 0 minimum */ +#define IT6621_AR_BIT_SEL BIT(4) /* Select bit time for arbitration lose */ +#define IT6621_AR_BIT_5BIT_TIME (0x00 << 4) /* 5 bit time */ +#define IT6621_AR_BIT_3BIT_TIME (0x01 << 4) /* 3 bit time */ +#define IT6621_HW_RTY_SEL BIT(5) /* HW 5 times Retry of TX */ +#define IT6621_HW_RTY_EN (0x00 << 5) +#define IT6621_HW_RTY_DIS (0x01 << 5) +#define IT6621_CEC_RX_EN_SEL BIT(6) /* CEC RX function */ +#define IT6621_CEC_RX_DIS (0x00 << 6) +#define IT6621_CEC_RX_EN (0x01 << 6) + +#define IT6621_REG_DATA_MIN 0x0b /* Minimum data bit time */ +#define IT6621_REG_TIMER_UNIT 0x0c /* CEC timer unit, nominally + * 100us. This value should be + * decided from MS_Count. + */ + +#define IT6621_REG_CEC_CTRL13 0x0d +#define IT6621_CEC_IO_PU_SEL BIT(4) +#define IT6621_CEC_IO_NORMAL (0x00 << 4) /* Normal */ +#define IT6621_CEC_IO_PU (0x01 << 4) /* Pull-up */ +#define IT6621_CEC_IO_SR BIT(5) /* CEC IO slew rate control */ +#define IT6621_CEC_IO_DRV GENMASK(7, 6) +#define IT6621_CEC_IO_DRV_2P5MA (0x00 << 6) /* 2.5mA */ +#define IT6621_CEC_IO_DRV_5MA (0x01 << 6) /* 5mA */ +#define IT6621_CEC_IO_DRV_7P5MA (0x02 << 6) /* 7.5mA */ +#define IT6621_CEC_IO_DRV_10MA (0x03 << 6) /* 10mA */ + +/* CEC Initiator Registers */ +#define IT6621_REG_TX_HEADER 0x10 /* CEC initiator command header */ +#define IT6621_REG_TX_OPCODE 0x11 /* CEC initiator command Opcode */ +#define IT6621_REG_TX_OPERAND1 0x12 /* CEC initiator command Operand1 */ +#define IT6621_REG_TX_OPERAND2 0x13 /* CEC initiator command Operand2 */ +#define IT6621_REG_TX_OPERAND3 0x14 /* CEC initiator command Operand3 */ +#define IT6621_REG_TX_OPERAND4 0x15 /* CEC initiator command Operand4 */ +#define IT6621_REG_TX_OPERAND5 0x16 /* CEC initiator command Operand5 */ +#define IT6621_REG_TX_OPERAND6 0x17 /* CEC initiator command Operand6 */ +#define IT6621_REG_TX_OPERAND7 0x18 /* CEC initiator command Operand7 */ +#define IT6621_REG_TX_OPERAND8 0x19 /* CEC initiator command Operand8 */ +#define IT6621_REG_TX_OPERAND9 0x1a /* CEC initiator command Operand9 */ +#define IT6621_REG_TX_OPERAND10 0x1b /* CEC initiator command Operand10 */ +#define IT6621_REG_TX_OPERAND11 0x1c /* CEC initiator command Operand11 */ +#define IT6621_REG_TX_OPERAND12 0x1d /* CEC initiator command Operand12 */ +#define IT6621_REG_TX_OPERAND13 0x1e /* CEC initiator command Operand13 */ +#define IT6621_REG_TX_OPERAND14 0x1f /* CEC initiator command Operand14 */ +#define IT6621_REG_TX_OPERAND15 0x20 /* CEC initiator command Operand15 */ +#define IT6621_REG_TX_OPERAND16 0x21 /* CEC initiator command Operand16 */ + +#define IT6621_REG_CEC_INIT22 0x22 +#define IT6621_LOG_ADDR GENMASK(3, 0) /* CEC target logical address */ + +#define IT6621_REG_CEC_INIT23 0x23 +#define IT6621_OUT_NUM GENMASK(4, 0) /* CEC output byte size in a frame */ + +/* CEC Follower Registers */ +#define IT6621_REG_RX_HEADER 0x30 /* CEC Follower command header */ +#define IT6621_REG_RX_OPCODE 0x31 /* CEC Follower command Opcode */ +#define IT6621_REG_RX_OPERAND1 0x32 /* CEC Follower command Operand1 */ +#define IT6621_REG_RX_OPERAND2 0x33 /* CEC Follower command Operand2 */ +#define IT6621_REG_RX_OPERAND3 0x34 /* CEC Follower command Operand3 */ +#define IT6621_REG_RX_OPERAND4 0x35 /* CEC Follower command Operand4 */ +#define IT6621_REG_RX_OPERAND5 0x36 /* CEC Follower command Operand5 */ +#define IT6621_REG_RX_OPERAND6 0x37 /* CEC Follower command Operand6 */ +#define IT6621_REG_RX_OPERAND7 0x38 /* CEC Follower command Operand7 */ +#define IT6621_REG_RX_OPERAND8 0x39 /* CEC Follower command Operand8 */ +#define IT6621_REG_RX_OPERAND9 0x3a /* CEC Follower command Operand9 */ +#define IT6621_REG_RX_OPERAND10 0x3b /* CEC Follower command Operand10 */ +#define IT6621_REG_RX_OPERAND11 0x3c /* CEC Follower command Operand11 */ +#define IT6621_REG_RX_OPERAND12 0x3d /* CEC Follower command Operand12 */ +#define IT6621_REG_RX_OPERAND13 0x3e /* CEC Follower command Operand13 */ +#define IT6621_REG_RX_OPERAND14 0x3f /* CEC Follower command Operand14 */ +#define IT6621_REG_RX_OPERAND15 0x40 /* CEC Follower command Operand15 */ +#define IT6621_REG_RX_OPERAND16 0x41 /* CEC Follower command Operand16 */ + +#define IT6621_REG_CEC_FOL22 0x42 +#define IT6621_IN_CNT GENMASK(4, 0) /* CEC follower received bytes */ + +/* CEC Misc. Registers */ +#define IT6621_REG_CEC_MSIC0 0x43 +#define IT6621_OUT_CNT GENMASK(4, 0) /* CEC initiator output bytes */ + +#define IT6621_REG_CEC_MSIC1 0x44 +#define IT6621_BUS_STATUS BIT(1) +#define IT6621_BUS_STATUS_BUSY (0x00 << 1) /* Busy */ +#define IT6621_BUS_STATUS_FREE (0x01 << 1) /* Busy */ +#define IT6621_OUT_STATUS GENMASK(3, 2) /* Output status */ +#define IT6621_OUT_STATUS_RCV_ACK (0x00 << 2) /* Received ACK */ +#define IT6621_OUT_STATUS_RCV_NACK (0x01 << 2) /* Received NACK */ +#define IT6621_OUT_STATUS_RTY (0x02 << 2) /* Retry, if no ACK, NACK + * or arbitration lose + */ +#define IT6621_OUT_STATUS_FAIL (0x03 << 2) /* Fail */ +#define IT6621_ERR_STATUS GENMASK(5, 4) /* Output status */ +#define IT6621_ERR_STATUS_NO_ERR (0x00 << 4) /* No error occurs */ +#define IT6621_ERR_STATUS_MDBP (0x01 << 4) /* Received data period < minimum + * data bit period + */ +#define IT6621_ERR_STATUS_IHLP (0x02 << 4) /* Illegal high-low period */ +#define IT6621_ERR_STATUS_BOTH (0x03 << 4) /* Both */ +#define IT6621_READY_FIRE BIT(6) /* Bus ready for firing a CEC command */ + +#define IT6621_REG_CEC_MS_COUNT_7_0 0x45 +#define IT6621_REG_CEC_MS_COUNT_15_8 0x46 +#define IT6621_REG_CEC_MS_COUNT_19_16 0x47 + +#define IT6621_REG_CEC_MSIC5 0x48 +#define IT6621_DBG_STATE GENMASK(3, 0) /* Debug CEC error state */ +#define IT6621_DBG_INT BIT(4) /* CEC interrupt for debug */ +#define IT6621_CEC_INT BIT(5) /* CEC interrupt status */ + +#define IT6621_REG_CEC_MSIC6 0x49 +#define IT6621_DBG_BLOCK GENMASK(4, 0) /* Debug CEC error block number */ + +#define IT6621_REG_CEC_MSIC7 0x4a +#define IT6621_DBG_BIT GENMASK(3, 0) /* Debug CEC error bit number */ + +#define IT6621_REG_DBG_TIMING 0x4b /* Debug CEC error data bit time */ + +#define IT6621_REG_CEC_MSIC8 0x4c +#define IT6621_TX_INT BIT(0) /* CEC initiator output byte interrupt */ +#define IT6621_RX_INT BIT(1) /* CEC follower received byte interrupt */ +#define IT6621_RX_FAIL_INT BIT(2) /* CEC received fail interrupt */ +#define IT6621_TX_DONE_INT BIT(3) /* CEC output finish interrupt */ +#define IT6621_RX_DONE_INT BIT(4) /* CEC received finish interrupt */ +#define IT6621_TX_FAIL_INT BIT(5) /* CEC initiator output fail interrupt */ +#define IT6621_CMD_OVERFLOW_INT BIT(6) /* CEC command FIFO over flow interrupt */ +#define IT6621_DATA_OVERFLOW_INT BIT(7) /* CEC data FIFO over flow interrupt */ + +#define IT6621_REG_RX_CMD_RX_HEADER 0x4d /* Command FIFO Rx_Header */ +#define IT6621_REG_RX_CMD_RX_OPCODE 0x4e /* Command FIFO Rx_Opcode */ + +#define IT6621_REG_RX_CMD_BYTE2 0x4f +#define IT6621_RX_CMD_IN_CNT GENMASK(4, 0) /* Command FIFO In_Cnt */ +#define IT6621_RX_CMD_ERR_STATUS GENMASK(6, 5) /* Command FIFO Error_Status */ +#define IT6621_RX_CMD_CEC_RX_FAIL BIT(7) /* Command FIFO CEC Rx_Fail */ + +#define IT6621_REG_RX_DATA 0x50 /* Data FIFO Rx_Operand */ + +#define IT6621_REG_CEC_MSIC12 0x51 +#define IT6621_RX_CMD_VALID BIT(0) /* Read command FIFO valid */ +#define IT6621_RX_CMD_FULL BIT(1) /* Command FIFO full */ +#define IT6621_RX_CMD_WRITE_OVERFLOW BIT(2) /* Write command FIFO over flow */ +#define IT6621_RX_CMD_READ_OVERFLOW BIT(3) /* Read command FIFO over flow */ +#define IT6621_RX_DATA_VALID BIT(4) /* Read data FIFO valid */ +#define IT6621_RX_DATA_FULL BIT(5) /* Data FIFO full */ +#define IT6621_RX_DATA_WRITE_OVERFLOW BIT(6) /* Write data FIFO over flow */ +#define IT6621_RX_DATA_READ_OVERFLOW BIT(7) /* Read data FIFO over flow */ + +#define IT6621_REG_CEC_MSIC13 0x52 +#define IT6621_RX_CMD_STG GENMASK(3, 0) /* Rx command FIFO stage */ +#define IT6621_RX_CMD_FIFO_RST BIT(5) /* CEC command FIFO reset 1:Reset */ +#define IT6621_RX_DATA_FIFO_RST BIT(6) /* CEC data FIFO reset 1:Reset */ +#define IT6621_RX_CEC_FIFO_EN_SEL BIT(7) /* CEC FIFO enable */ +#define IT6621_RX_CEC_FIFO_DIS (0x00 << 7) /* Disable */ +#define IT6621_RX_CEC_FIFO_EN (0x01 << 7) /* Enable */ + +#define IT6621_REG_CEC_MSIC14 0x53 +#define IT6621_RX_DATA_STG GENMASK(3, 0) /* Rx data FIFO stage */ + +#define IT6621_REG_CEC_MSIC15 0x54 +#define IT6621_TX_FAIL_STATUS GENMASK(2, 0) +#define IT6621_TX_FAIL_STATUS_RCV_ACK BIT(0) /* receive ACK */ +#define IT6621_TX_FAIL_STATUS_RCV_NACK BIT(1) /* receive NACK */ +#define IT6621_TX_FAIL_STATUS_RTY BIT(2) /* retry */ + +#endif /* _IT6621_REG_CEC_H */ diff --git a/sound/soc/codecs/it6621/it6621-uapi.c b/sound/soc/codecs/it6621/it6621-uapi.c new file mode 100644 index 000000000000..27ef368f50e8 --- /dev/null +++ b/sound/soc/codecs/it6621/it6621-uapi.c @@ -0,0 +1,364 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2024 Rockchip Electronics Co. Ltd. + * Author: Jason Zhang + */ + +#include +#include +#include + +#include "it6621.h" +#include "it6621-earc.h" +#include "it6621-uapi.h" + +#define IT6621_MAX_MSGS 18 +#define IT6621_MAX_MSG_LEN 256 + +struct it6621_msg { + u8 event; + u8 data[IT6621_MAX_MSG_LEN]; +} __packed; + +/* Command */ +#define IT6621_EARC_SET_ENABLED _IOW('a', 0x01, unsigned int) +#define IT6621_EARC_GET_STATE _IOR('a', 0x02, unsigned int) +#define IT6621_EARC_GET_AUDIO_CAP _IOR('a', 0x03, u8[IT6621_MAX_MSG_LEN]) +#define IT6621_EARC_GET_EVENT _IOR('a', 0x04, struct it6621_msg) +#define IT6621_EARC_SET_ENTER_ARC _IOW('a', 0x05, unsigned int) + +struct it6621_msg_entry { + struct list_head list; + struct it6621_msg msg; +}; + +struct it6621_fh { + struct list_head list; + struct list_head msgs; + unsigned int msgs_num; + struct mutex msgs_lock; + wait_queue_head_t wait; + struct it6621_priv *priv; + struct mutex valid_lock; + bool valid; +}; + +static int minor; + +static bool it6621_fh_get_valid(struct it6621_fh *fh) +{ + bool valid; + + mutex_lock(&fh->valid_lock); + valid = fh->valid; + mutex_unlock(&fh->valid_lock); + + return valid; +} + +static void it6621_fh_set_valid(struct it6621_fh *fh, bool valid) +{ + mutex_lock(&fh->valid_lock); + fh->valid = valid; + mutex_unlock(&fh->valid_lock); +} + +static int it6621_fh_set_earc_enabled(struct it6621_fh *fh, + unsigned int __user *argp) +{ + struct it6621_priv *priv = fh->priv; + unsigned int enabled; + int ret; + + ret = copy_from_user(&enabled, argp, sizeof(enabled)); + if (ret) + return -EFAULT; + + return it6621_set_earc_enabled(priv, !!enabled); +} + +static int it6621_fh_get_earc_state(struct it6621_fh *fh, + unsigned int __user *argp) +{ + struct it6621_priv *priv = fh->priv; + int ret; + + ret = copy_to_user(argp, &priv->state, sizeof(priv->state)); + if (ret) + return -EFAULT; + + return 0; +} + +static int it6621_fh_get_earc_audio_cap(struct it6621_fh *fh, u8 __user *argp) +{ + struct it6621_priv *priv = fh->priv; + int ret; + + mutex_lock(&priv->rxcap_lock); + ret = copy_to_user(argp, priv->rxcap, sizeof(priv->rxcap)); + mutex_unlock(&priv->rxcap_lock); + + if (ret) + return -EFAULT; + + return 0; +} + +static int it6621_fh_get_msg(struct it6621_fh *fh, + struct it6621_msg __user *argp, + bool block) +{ + struct it6621_msg_entry *entry; + int ret = 0; + + do { + mutex_lock(&fh->msgs_lock); + + if (fh->msgs_num) { + entry = list_first_entry(&fh->msgs, + struct it6621_msg_entry, + list); + list_del(&entry->list); + ret = copy_to_user(argp, &entry->msg, sizeof(entry->msg)); + kfree(entry); + fh->msgs_num--; + mutex_unlock(&fh->msgs_lock); + + if (ret) + return -EFAULT; + + return 0; + } + + mutex_unlock(&fh->msgs_lock); + + if (!block) + return -EAGAIN; + + ret = wait_event_interruptible(fh->wait, fh->msgs_num); + + if (!it6621_fh_get_valid(fh)) + return -ENXIO; + /* Exit on error, otherwise loop to get the new message */ + } while (!ret); + + return ret; +} + +static int it6621_fh_push_msg(struct it6621_fh *fh, u8 event, void *data, + size_t len) +{ + struct it6621_msg_entry *entry; + + mutex_lock(&fh->msgs_lock); + + if (fh->msgs_num <= IT6621_MAX_MSGS) { + entry = kzalloc(sizeof(*entry), GFP_KERNEL); + if (!entry) { + mutex_unlock(&fh->msgs_lock); + return -ENOMEM; + } + + entry->msg.event = event; + memcpy(entry->msg.data, data, len); + list_add_tail(&entry->list, &fh->msgs); + fh->msgs_num++; + } else { + dev_warn(fh->priv->dev, "queue is full for fh: %p", fh); + } + + mutex_unlock(&fh->msgs_lock); + + wake_up_interruptible(&fh->wait); + + return 0; +} + +static int it6621_fh_set_enter_arc(struct it6621_fh *fh, + unsigned int __user *argp) +{ + struct it6621_priv *priv = fh->priv; + int enabled; + int ret; + + ret = copy_from_user(&enabled, argp, sizeof(enabled)); + if (ret) + return -EFAULT; + + return it6621_set_enter_arc(priv, !!enabled); +} + +static int it6621_uapi_open(struct inode *inode, struct file *file) +{ + struct miscdevice *mdev = file->private_data; + struct it6621_priv *priv = container_of(mdev, struct it6621_priv, mdev); + struct it6621_fh *fh; + + if (!priv->uapi_registered) + return -ENXIO; + + fh = kzalloc(sizeof(*fh), GFP_KERNEL); + if (!fh) + return -ENOMEM; + + fh->priv = priv; + fh->valid = true; + fh->msgs_num = 0; + INIT_LIST_HEAD(&fh->msgs); + mutex_init(&fh->msgs_lock); + mutex_init(&fh->valid_lock); + init_waitqueue_head(&fh->wait); + + mutex_lock(&priv->fhs_lock); + list_add(&fh->list, &priv->fhs); + mutex_unlock(&priv->fhs_lock); + + file->private_data = fh; + + return 0; +} + +static long it6621_uapi_ioctl(struct file *file, unsigned int cmd, + unsigned long arg) +{ + struct it6621_fh *fh = file->private_data; + bool block = !(file->f_flags & O_NONBLOCK); + void __user *argp = (void __user *)arg; + + if (!it6621_fh_get_valid(fh)) + return -ENODEV; + + switch (cmd) { + case IT6621_EARC_SET_ENABLED: + return it6621_fh_set_earc_enabled(fh, argp); + case IT6621_EARC_GET_STATE: + return it6621_fh_get_earc_state(fh, argp); + case IT6621_EARC_GET_AUDIO_CAP: + return it6621_fh_get_earc_audio_cap(fh, argp); + case IT6621_EARC_GET_EVENT: + return it6621_fh_get_msg(fh, argp, block); + case IT6621_EARC_SET_ENTER_ARC: + return it6621_fh_set_enter_arc(fh, argp); + default: + return -ENOTTY; + } +} + +static int it6621_uapi_release(struct inode *inode, struct file *file) +{ + struct it6621_fh *fh = file->private_data; + struct it6621_priv *priv = fh->priv; + struct it6621_msg_entry *entry; + + if (it6621_fh_get_valid(fh)) { + mutex_lock(&priv->fhs_lock); + list_del(&fh->list); + mutex_unlock(&priv->fhs_lock); + } + + mutex_lock(&fh->msgs_lock); + + while (!list_empty(&fh->msgs)) { + entry = list_first_entry(&fh->msgs, struct it6621_msg_entry, + list); + list_del(&entry->list); + kfree(entry); + } + + mutex_unlock(&fh->msgs_lock); + + kfree(fh); + file->private_data = NULL; + + return 0; +} + +static __poll_t it6621_uapi_poll(struct file *file, + struct poll_table_struct *poll) +{ + struct it6621_fh *fh = file->private_data; + __poll_t ret = 0; + + poll_wait(file, &fh->wait, poll); + if (!it6621_fh_get_valid(fh)) + ret = EPOLLERR | EPOLLHUP; + else + ret = EPOLLIN | EPOLLRDNORM; + + return ret; +} + +const struct file_operations it6621_uapi_fops = { + .owner = THIS_MODULE, + .open = it6621_uapi_open, + .unlocked_ioctl = it6621_uapi_ioctl, + .compat_ioctl = it6621_uapi_ioctl, + .release = it6621_uapi_release, + .poll = it6621_uapi_poll, + .llseek = no_llseek, +}; + +int it6621_uapi_init(struct it6621_priv *priv) +{ + char *name; + int ret; + + name = kzalloc(NAME_MAX, GFP_KERNEL); + if (!name) + return -ENOMEM; + + snprintf(name, NAME_MAX, "ite-earc%d", minor++); + priv->mdev.minor = MISC_DYNAMIC_MINOR; + priv->mdev.name = name; + priv->mdev.fops = &it6621_uapi_fops; + + ret = misc_register(&priv->mdev); + if (ret) + return ret; + + priv->uapi_registered = true; + + return 0; +} + +void it6621_uapi_remove(struct it6621_priv *priv) +{ + struct it6621_fh *fh; + + mutex_lock(&priv->fhs_lock); + + priv->uapi_registered = false; + + list_for_each_entry(fh, &priv->fhs, list) + it6621_fh_set_valid(fh, false); + + list_for_each_entry(fh, &priv->fhs, list) + wake_up_interruptible(&fh->wait); + + mutex_unlock(&priv->fhs_lock); + + misc_deregister(&priv->mdev); + kfree(priv->mdev.name); +} + +int it6621_uapi_msg(struct it6621_priv *priv, u8 event, void *data, size_t len) +{ + struct it6621_fh *fh; + int ret = 0; + + if (!priv->uapi_registered) + return 0; + + mutex_lock(&priv->fhs_lock); + + list_for_each_entry(fh, &priv->fhs, list) { + ret = it6621_fh_push_msg(fh, event, data, len); + if (ret) + break; + } + + mutex_unlock(&priv->fhs_lock); + + return ret; +} diff --git a/sound/soc/codecs/it6621/it6621-uapi.h b/sound/soc/codecs/it6621/it6621-uapi.h new file mode 100644 index 000000000000..daf6f67eff3d --- /dev/null +++ b/sound/soc/codecs/it6621/it6621-uapi.h @@ -0,0 +1,30 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (c) 2024 Rockchip Electronics Co. Ltd. + * Author: Jason Zhang + */ + +#ifndef _IT6621_UAPI_H +#define _IT6621_UAPI_H + +/* States */ +#define IT6621_EARC_IDLE 0x01 +#define IT6621_EARC_PENDING 0x02 +#define IT6621_ARC_PENDING 0x03 +#define IT6621_EARC_CONNECTED 0x04 + +/* Events */ +#define IT6621_EVENT_STATE_CHANGE 0x01 /* Event of state change, with a + * state following up. + */ + +#define IT6621_EVENT_AUDIO_CAP_CHANGE 0x02 /* Event of capabilities change, + * with a audio capabilities + * following up. + */ + +int it6621_uapi_init(struct it6621_priv *priv); +void it6621_uapi_remove(struct it6621_priv *priv); +int it6621_uapi_msg(struct it6621_priv *priv, u8 event, void *data, size_t len); + +#endif /* _IT6621_UAPI_H */ diff --git a/sound/soc/codecs/it6621/it6621.h b/sound/soc/codecs/it6621/it6621.h new file mode 100644 index 000000000000..bb902ebeabc4 --- /dev/null +++ b/sound/soc/codecs/it6621/it6621.h @@ -0,0 +1,210 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (c) 2024 Rockchip Electronics Co. Ltd. + * Author: Jason Zhang + */ + +#ifndef _IT6621_H +#define _IT6621_H + +#include +#include +#include +#include +#include +#include +#include + +#define IT6621_VENDOR_ID 0x4954 +#define IT6621_DEVICE_ID 0x6621 +#define IT6621_REVISION_VARIANT_B0 0xb0 +#define IT6621_REVISION_VARIANT_C0 0xc0 +#define IT6621_REVISION_VARIANT_D0 0xd0 + +#define IT6621_ARC_START 0 +#define IT6621_EARC_CAP_CHG 1 +#define IT6621_EARC_EDID_OK 2 +#define IT6621_EARC_BCLK_OK 3 + +#define IT6621_AUDIO_START 0 +#define IT6621_AUDIO_TO_EN_DMAC 7 + +#define IT6621_CMD_WAIT_TIME_MS 1 +#define IT6621_CMD_WAIT_COUNT 10 +#define IT6621_RXCAP_BULK_LEN 16 +#define IT6621_RX_CAP_MAX_LEN 256 +#define IT6621_ADB_MAX_LEN 32 + +/** + * struct it6621_priv - IT6621 device + * @client: the i2c client used by the driver. + * @dev: i2c device. + * @mclk: master clock. + * @hpdio: Input Hot Plus Detection. + * @hpdio_lock: hpdio lock to protect hpdio access. + * @rxcap_lock: rxcap lock to protect rxcap access. + * @state: the state of IT6621 device. + * @vid: vendor ID. + * @devid: device ID. + * @revid: revision ID. + * @audio_enc: LPCM 2-ch do not support encryption. + * @audio_src: I2S, SPDIF, TDM, DSD (DSD: EnAudGen must be TRUE for + * Internal AudGen). + * @audio_ch: channel number. + * @audio_fs: sample frequency. + * @audio_type: LPCM, NLPCM. + * @audio_hbr: HBR. + * @audio_input_hbr: input audio HBR. + * @i2s_wl: 0 for 16-bit, 1 for 18-bit, 2 for 20-bit, 3 for 24-bit. + * @i2s_hbr: I2S HBR. + * @i2s_fmt: I2S format. + * @i2s_nlpcm_enabled: auto by input setting. + * @i2s_hbr_enabled: enable eARC TX I2S hbr. + * @hbr_layb_enabled: QD980 HFR5-1-40. + * @mch_lpcm_enabled: SL-870 5-1-30 [Multi-channel 2-ch layout] has audio output + * @layout_2ch_enabled: use for SL-870 5-1-29 [Multi-channel 2-ch layout] => + * fixed by SL-870 @ FW Ver1.11 => (always FALSE) + * @vcm_sel: tx VCM selection. + * @force_ca: force channel allocation. + * @force_16ch: force to 16 channels. + * @toggle_by_edid: indicate whether HPD is toggled by EDID. + * @rclk: RCLK frequency. + * @aclk: ACLK frequency. + * @bclk: BCLK frequency. + * @rclk_sel: RCLK frequency selection. + * @update_avg_enabled: enable update average clock detection value. + * @cmo_opt: eARC TX common mode output enable option. + * @force_cmo_enabled: force eARC TX common mode enable. + * @resync_opt: eARC TX common mode resync option. + * @ubit_opt: U-bit option. + * @c_ch_opt: eARC TX U-bit C-Ch option. + * @ecc_opt: eARC TX ECC option. + * @enc_seed: eARC TX encryption seed. + * @enc_opt: eARC TX encryption option. + * @fixed_lcf: fixed LC frequency. + * @bclk_inv_enabled: enable eARC BCLK inversion. + * @sck_inv_enabled: enable I2S serial clock inversion. + * @tck_inv_enabled: enable TDM clock inversion. + * @mclk_inv_enabled: enable SPDIF master clock inversion. + * @dclk_inv_enabled: enable DSD clock inversion. + * @nxt_pkt_to_sel: eARC TX next packet timeout selection. + * @turn_over_sel: eARC TX turn-over time selection before + * transmitting packet, set 24 us for QD980 HFR5-1-21. + * @hb_retry_sel: eARC TX HeartBeat retry time selection. + * @hb_retry_enabled: enable eARC TX auto HeartBeat retry. + * @cmd_to_enabled: indicate whether command timeout is enabled. + * @force_arc: force TX ARC mode. + * @enter_arc_now: enter ARC mode when initiate IT6621 device, + * enable for standalone ARC mode. + * @arc_enabled: enable ARC mode. + * @earc_enabled: enable eARC mode, disable for standalone ARC mode. + * @pkt1_enabled: enable eARC TX packet 1 using U-bit. + * @pkt2_enabled: enable eARC TX packet 2 using U-bit. + * @pkt3_enabled: enable eARC TX packet 3 using U-bit. + * @events: eARC events. + * @audio_flag: upstream's audio state, if upstream is audio on, set to 1 at + * upstream, extern to upstream's function. + * @hpdio_work: work to toggle hpdio. + * @config_audio: indicate whether audio is need to be configured. + * @force_mute: force mute. + * @uapi_registered: indicate whether uapi is registered. + * @rxcap: capabilities from the ARC device. + * @adb: audio data block. + */ +struct it6621_priv { + struct i2c_client *client; + struct device *dev; + struct regmap *regmap; + struct miscdevice mdev; + struct clk *mclk; + struct gpio_desc *hpdio; + struct list_head fhs; + struct mutex fhs_lock; + struct mutex hpdio_lock; + struct mutex rxcap_lock; + unsigned int state; + unsigned int vid; + unsigned int devid; + unsigned int revid; + + /* Tx Audio Option */ + unsigned int audio_enc; + unsigned int audio_src; + unsigned int audio_ch; + unsigned int audio_fs; + unsigned int audio_type; + unsigned int audio_hbr; + unsigned int audio_input_hbr; + unsigned int i2s_wl; + unsigned int i2s_hbr; + unsigned int i2s_fmt; + unsigned int i2s_nlpcm_enabled; + unsigned int i2s_hbr_enabled; + unsigned int hbr_layb_enabled; + unsigned int mch_lpcm_enabled; + unsigned int layout_2ch_enabled; + unsigned int vcm_sel; + unsigned int force_ca; + unsigned int force_16ch; + + /* FIXME: Need to toggle by edid? */ + unsigned int toggle_by_edid; + unsigned int rclk; + unsigned int aclk; + unsigned int bclk; + + /* Clock configurations */ + unsigned int rclk_sel; + unsigned int update_avg_enabled; + + unsigned int cmo_opt; + unsigned int force_cmo_enabled; + unsigned int resync_opt; + unsigned int ubit_opt; + unsigned int c_ch_opt; + unsigned int ecc_opt; + unsigned int enc_seed; + unsigned int enc_opt; + unsigned int fixed_lcf; + + /* Clock inversion option */ + unsigned int bclk_inv_enabled; + unsigned int sck_inv_enabled; + unsigned int tck_inv_enabled; + unsigned int mclk_inv_enabled; + unsigned int dclk_inv_enabled; + + /* DMCD option */ + unsigned int nxt_pkt_to_sel; + unsigned int turn_over_sel; + + /* TX CMDC option */ + unsigned int hb_retry_sel; + unsigned int hb_retry_enabled; + unsigned int cmd_to_enabled; + + /* Discovery option */ + unsigned int force_arc; + unsigned int force_earc; + unsigned int enter_arc_now; + unsigned int arc_enabled; + unsigned int earc_enabled; + + /* Loop Test option */ + unsigned int pkt1_enabled; + unsigned int pkt2_enabled; + unsigned int pkt3_enabled; + + unsigned long events; + unsigned long audio_flag; + + struct work_struct hpdio_work; + struct class class; + bool config_audio; + bool force_mute; + bool uapi_registered; + u8 rxcap[IT6621_RX_CAP_MAX_LEN]; + u8 adb[IT6621_ADB_MAX_LEN]; +}; + +#endif /* _IT6621_H */