Merge commit '1feee0d9c0b20750eef52b06b9211a4a3a353895'

* commit '1feee0d9c0b20750eef52b06b9211a4a3a353895':
  ASoC: codecs: add aw882xx amp
  ASoC: codecs: add support for IT6621
  drm/rockchip: drv: Fix ROCKCHIP_BO_CACHABLE flag Invalid

Change-Id: I6c69d064fc0b72fff4ddc93b876ab4c23ad47dfe
This commit is contained in:
Tao Huang
2024-02-06 17:08:06 +08:00
43 changed files with 36440 additions and 5 deletions

View File

@@ -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) {

View File

@@ -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

View File

@@ -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

View File

@@ -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.

View File

@@ -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

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,223 @@
/* SPDX-License-Identifier: GPL-2.0
* aw882xx.h
*
* Copyright (c) 2020 AWINIC Technology CO., LTD
*
* Author: Nick Li <liweilei@awinic.com.cn>
*
* 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 <linux/version.h>
#include <linux/kernel.h>
#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

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,102 @@
/* SPDX-License-Identifier: GPL-2.0
* aw882xx_bin_parse.h
*
* Copyright (c) 2020 AWINIC Technology CO., LTD
*
* Author: Nick Li <liweilei@awinic.com.cn>
*
* 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

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,193 @@
/* SPDX-License-Identifier: GPL-2.0
* aw882xx_calib.h
*
* Copyright (c) 2020 AWINIC Technology CO., LTD
*
* Author: Nick Li <liweilei@awinic.com.cn>
*
* 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

View File

@@ -0,0 +1,165 @@
/* SPDX-License-Identifier: GPL-2.0
* aw882xx_data_type.h
*
* Copyright (c) 2020 AWINIC Technology CO., LTD
*
* Author: Nick Li <liweilei@awinic.com.cn>
*
* 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

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,463 @@
/* SPDX-License-Identifier: GPL-2.0
* aw882xx_device.h
*
* Copyright (c) 2020 AWINIC Technology CO., LTD
*
* Author: Nick Li <liweilei@awinic.com.cn>
*
* 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

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,109 @@
/* SPDX-License-Identifier: GPL-2.0
* aw882xx_dsp.h
*
* Copyright (c) 2020 AWINIC Technology CO., LTD
*
* Author: Nick Li <liweilei@awinic.com.cn>
*
* 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

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,35 @@
/* SPDX-License-Identifier: GPL-2.0
* aw882xx_log.h
*
* Copyright (c) 2020 AWINIC Technology CO., LTD
*
* Author: Nick Li <liweilei@awinic.com.cn>
*
* 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

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,234 @@
/* SPDX-License-Identifier: GPL-2.0
* aw882xx_monitor.h
*
* Copyright (c) 2020 AWINIC Technology CO., LTD
*
* Author: Nick Li <liweilei@awinic.com.cn>
*
* 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

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,247 @@
// SPDX-License-Identifier: GPL-2.0
/* aw882xx_spin.c spin_module
*
* Copyright (c) 2019 AWINIC Technology CO., LTD
*
* Author: Nick Li <liweilei@awinic.com.cn>
*
* 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 <linux/module.h>
#include <linux/i2c.h>
#include <sound/core.h>
#include <sound/soc.h>
#include <linux/of_gpio.h>
#include <linux/device.h>
#include <linux/firmware.h>
#include <linux/of.h>
#include <linux/timer.h>
#include <linux/delay.h>
#include <linux/version.h>
#include <linux/input.h>
#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;
}

View File

@@ -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 <liweilei@awinic.com.cn>
*
* 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

View File

@@ -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.

View File

@@ -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

View File

@@ -0,0 +1,319 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (c) 2024 Rockchip Electronics Co. Ltd.
* Author: Jason Zhang <jason.zhang@rock-chips.com>
*/
#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);
}

View File

@@ -0,0 +1,18 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* Copyright (c) 2024 Rockchip Electronics Co. Ltd.
* Author: Jason Zhang <jason.zhang@rock-chips.com>
*/
#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 */

View File

@@ -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 <jason.zhang@rock-chips.com>
*/
#include <linux/module.h>
#include <linux/irq.h>
#include <linux/interrupt.h>
#include <linux/clk.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
#include <sound/asoundef.h>
#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 <jason.zhang@rock-chips.com>");
MODULE_DESCRIPTION("ASoC IT6621 eARC Driver");
MODULE_LICENSE("GPL");

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,62 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* Copyright (c) 2024 Rockchip Electronics Co. Ltd.
* Author: Jason Zhang <jason.zhang@rock-chips.com>
*/
#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 */

View File

@@ -0,0 +1,982 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* Copyright (c) 2024 Rockchip Electronics Co. Ltd.
* Author: Jason Zhang <jason.zhang@rock-chips.com>
*/
#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 */

View File

@@ -0,0 +1,147 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* Copyright (c) 2024 Rockchip Electronics Co. Ltd.
* Author: Jason Zhang <jason.zhang@rock-chips.com>
*/
#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 */

View File

@@ -0,0 +1,246 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* Copyright (c) 2024 Rockchip Electronics Co. Ltd.
* Author: Jason Zhang <jason.zhang@rock-chips.com>
*/
#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 */

View File

@@ -0,0 +1,364 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (c) 2024 Rockchip Electronics Co. Ltd.
* Author: Jason Zhang <jason.zhang@rock-chips.com>
*/
#include <linux/kernel.h>
#include <linux/device.h>
#include <linux/poll.h>
#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;
}

View File

@@ -0,0 +1,30 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* Copyright (c) 2024 Rockchip Electronics Co. Ltd.
* Author: Jason Zhang <jason.zhang@rock-chips.com>
*/
#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 */

View File

@@ -0,0 +1,210 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* Copyright (c) 2024 Rockchip Electronics Co. Ltd.
* Author: Jason Zhang <jason.zhang@rock-chips.com>
*/
#ifndef _IT6621_H
#define _IT6621_H
#include <linux/delay.h>
#include <linux/gpio.h>
#include <linux/i2c.h>
#include <linux/miscdevice.h>
#include <linux/of_gpio.h>
#include <linux/regmap.h>
#include <sound/asoundef.h>
#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 */