Browse Source

Merge "asoc: codecs: codec driver support for CSRA66X0"

Linux Build Service Account 6 years ago
parent
commit
029bb3d3aa
3 changed files with 1102 additions and 0 deletions
  1. 105 0
      asoc/codecs/csra66x0/Kbuild
  2. 767 0
      asoc/codecs/csra66x0/csra66x0.c
  3. 230 0
      asoc/codecs/csra66x0/csra66x0.h

+ 105 - 0
asoc/codecs/csra66x0/Kbuild

@@ -0,0 +1,105 @@
+# We can build either as part of a standalone Kernel build or as
+# an external module.  Determine which mechanism is being used
+ifeq ($(MODNAME),)
+	KERNEL_BUILD := 1
+else
+	KERNEL_BUILD := 0
+endif
+
+
+ifeq ($(KERNEL_BUILD), 1)
+	# These are configurable via Kconfig for kernel-based builds
+	# Need to explicitly configure for Android-based builds
+	AUDIO_BLD_DIR := $(ANDROID_BUILD_TOP)/kernel/msm-4.14
+	AUDIO_ROOT := $(AUDIO_BLD_DIR)/techpack/audio
+endif
+
+ifeq ($(KERNEL_BUILD), 0)
+	ifeq ($(CONFIG_ARCH_QCS405), y)
+		include $(AUDIO_ROOT)/config/qcs405auto.conf
+		export
+		INCS    +=  -include $(AUDIO_ROOT)/config/qcs405autoconf.h
+	endif
+endif
+
+# As per target team, build is done as follows:
+# Defconfig : build with default flags
+# Slub      : defconfig  + CONFIG_SLUB_DEBUG := y +
+#	      CONFIG_SLUB_DEBUG_ON := y + CONFIG_PAGE_POISONING := y
+# Perf      : Using appropriate msmXXXX-perf_defconfig
+#
+# Shipment builds (user variants) should not have any debug feature
+# enabled. This is identified using 'TARGET_BUILD_VARIANT'. Slub builds
+# are identified using the CONFIG_SLUB_DEBUG_ON configuration. Since
+# there is no other way to identify defconfig builds, QTI internal
+# representation of perf builds (identified using the string 'perf'),
+# is used to identify if the build is a slub or defconfig one. This
+# way no critical debug feature will be enabled for perf and shipment
+# builds. Other OEMs are also protected using the TARGET_BUILD_VARIANT
+# config.
+
+############ UAPI ############
+UAPI_DIR :=	uapi
+UAPI_INC :=	-I$(AUDIO_ROOT)/include/$(UAPI_DIR)
+
+############ COMMON ############
+COMMON_DIR :=	include
+COMMON_INC :=	-I$(AUDIO_ROOT)/$(COMMON_DIR)
+
+############ CSRA66X0 ############
+
+# for CSRA66X0 Codec
+ifdef CONFIG_SND_SOC_CSRA66X0
+	CSRA66X0_OBJS += csra66x0.o
+endif
+
+LINUX_INC +=	-Iinclude/linux
+
+INCS +=		$(COMMON_INC) \
+		$(UAPI_INC)
+
+#EXTRA_CFLAGS += $(INCS)
+ccflags-y += $(INCS)
+
+
+CDEFINES +=	-DANI_LITTLE_BYTE_ENDIAN \
+		-DANI_LITTLE_BIT_ENDIAN \
+		-DDOT11F_LITTLE_ENDIAN_HOST \
+		-DANI_COMPILER_TYPE_GCC \
+		-DANI_OS_TYPE_ANDROID=6 \
+		-DPTT_SOCK_SVC_ENABLE \
+		-Wall\
+		-Werror\
+		-D__linux__
+
+KBUILD_CPPFLAGS += $(CDEFINES)
+
+# Currently, for versions of gcc which support it, the kernel Makefile
+# is disabling the maybe-uninitialized warning.  Re-enable it for the
+# AUDIO driver.  Note that we must use EXTRA_CFLAGS here so that it
+# will override the kernel settings.
+ifeq ($(call cc-option-yn, -Wmaybe-uninitialized),y)
+#EXTRA_CFLAGS += -Wmaybe-uninitialized
+ccflags-y += -Wmaybe-uninitialized
+endif
+#EXTRA_CFLAGS += -Wmissing-prototypes
+
+ifeq ($(call cc-option-yn, -Wheader-guard),y)
+#EXTRA_CFLAGS += -Wheader-guard
+ccflags-y += -Wheader-guard
+endif
+
+ifeq ($(KERNEL_BUILD), 0)
+KBUILD_EXTRA_SYMBOLS +=$(OUT)/obj/vendor/qcom/opensource/audio-kernel/ipc/Module.symvers
+KBUILD_EXTRA_SYMBOLS +=$(OUT)/obj/vendor/qcom/opensource/audio-kernel/dsp/Module.symvers
+KBUILD_EXTRA_SYMBOLS +=$(OUT)/obj/vendor/qcom/opensource/audio-kernel/asoc/Module.symvers
+KBUILD_EXTRA_SYMBOLS +=$(OUT)/obj/vendor/qcom/opensource/audio-kernel/asoc/codecs/Module.symvers
+KBUILD_EXTRA_SYMBOLS +=$(OUT)/obj/vendor/qcom/opensource/audio-kernel/soc/Module.symvers
+endif
+
+# Module information used by KBuild framework
+obj-$(CONFIG_SND_SOC_CSRA66X0) += csra66x0_dlkm.o
+csra66x0_dlkm-y := $(CSRA66X0_OBJS)
+
+# inject some build related information
+DEFINES += -DBUILD_TIMESTAMP=\"$(shell date -u +'%Y-%m-%dT%H:%M:%SZ')\"

+ 767 - 0
asoc/codecs/csra66x0/csra66x0.c

@@ -0,0 +1,767 @@
+/*
+ * Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/tlv.h>
+#include <sound/soc.h>
+#include <linux/gpio.h>
+#include <linux/of_gpio.h>
+#include "csra66x0.h"
+
+/* CSRA66X0 register default values */
+static struct reg_default csra66x0_reg_defaults[] = {
+	{CSRA66X0_AUDIO_IF_RX_CONFIG1,           0x00},
+	{CSRA66X0_AUDIO_IF_RX_CONFIG2,           0x0B},
+	{CSRA66X0_AUDIO_IF_RX_CONFIG3,           0x0F},
+	{CSRA66X0_AUDIO_IF_TX_EN,                0x00},
+	{CSRA66X0_AUDIO_IF_TX_CONFIG1,           0x6B},
+	{CSRA66X0_AUDIO_IF_TX_CONFIG2,           0x02},
+	{CSRA66X0_I2C_DEVICE_ADDRESS,            0x0D},
+	{CSRA66X0_CHIP_ID_FA,                    0x39},
+	{CSRA66X0_ROM_VER_FA,                    0x08},
+	{CSRA66X0_CHIP_REV_0_FA,                 0x05},
+	{CSRA66X0_CHIP_REV_1_FA,                 0x03},
+	{CSRA66X0_CH1_MIX_SEL,                   0x01},
+	{CSRA66X0_CH2_MIX_SEL,                   0x10},
+	{CSRA66X0_CH1_SAMPLE1_SCALE_0,           0x00},
+	{CSRA66X0_CH1_SAMPLE1_SCALE_1,           0x20},
+	{CSRA66X0_CH1_SAMPLE3_SCALE_0,           0x00},
+	{CSRA66X0_CH1_SAMPLE3_SCALE_1,           0x20},
+	{CSRA66X0_CH1_SAMPLE5_SCALE_0,           0x00},
+	{CSRA66X0_CH1_SAMPLE5_SCALE_1,           0x20},
+	{CSRA66X0_CH1_SAMPLE7_SCALE_0,           0x00},
+	{CSRA66X0_CH1_SAMPLE7_SCALE_1,           0x20},
+	{CSRA66X0_CH1_SAMPLE2_SCALE_0,           0x00},
+	{CSRA66X0_CH1_SAMPLE2_SCALE_1,           0x20},
+	{CSRA66X0_CH1_SAMPLE4_SCALE_0,           0x00},
+	{CSRA66X0_CH1_SAMPLE4_SCALE_1,           0x20},
+	{CSRA66X0_CH1_SAMPLE6_SCALE_0,           0x00},
+	{CSRA66X0_CH1_SAMPLE6_SCALE_1,           0x20},
+	{CSRA66X0_CH1_SAMPLE8_SCALE_0,           0x00},
+	{CSRA66X0_CH1_SAMPLE8_SCALE_1,           0x20},
+	{CSRA66X0_CH2_SAMPLE1_SCALE_0,           0x00},
+	{CSRA66X0_CH2_SAMPLE1_SCALE_1,           0x20},
+	{CSRA66X0_CH2_SAMPLE3_SCALE_0,           0x00},
+	{CSRA66X0_CH2_SAMPLE3_SCALE_1,           0x20},
+	{CSRA66X0_CH2_SAMPLE5_SCALE_0,           0x00},
+	{CSRA66X0_CH2_SAMPLE5_SCALE_1,           0x20},
+	{CSRA66X0_CH2_SAMPLE7_SCALE_0,           0x00},
+	{CSRA66X0_CH2_SAMPLE7_SCALE_1,           0x20},
+	{CSRA66X0_CH2_SAMPLE2_SCALE_0,           0x00},
+	{CSRA66X0_CH2_SAMPLE2_SCALE_1,           0x20},
+	{CSRA66X0_CH2_SAMPLE4_SCALE_0,           0x00},
+	{CSRA66X0_CH2_SAMPLE4_SCALE_1,           0x20},
+	{CSRA66X0_CH2_SAMPLE6_SCALE_0,           0x00},
+	{CSRA66X0_CH2_SAMPLE6_SCALE_1,           0x20},
+	{CSRA66X0_CH2_SAMPLE8_SCALE_0,           0x00},
+	{CSRA66X0_CH2_SAMPLE8_SCALE_1,           0x20},
+	{CSRA66X0_VOLUME_CONFIG_FA,              0x26},
+	{CSRA66X0_STARTUP_DELAY_FA,              0x00},
+	{CSRA66X0_CH1_VOLUME_0_FA,               0x19},
+	{CSRA66X0_CH1_VOLUME_1_FA,               0x01},
+	{CSRA66X0_CH2_VOLUME_0_FA,               0x19},
+	{CSRA66X0_CH2_VOLUME_1_FA,               0x01},
+	{CSRA66X0_QUAD_ENC_COUNT_0_FA,           0x00},
+	{CSRA66X0_QUAD_ENC_COUNT_1_FA,           0x00},
+	{CSRA66X0_SOFT_CLIP_CONFIG,              0x00},
+	{CSRA66X0_CH1_HARD_CLIP_THRESH,          0x00},
+	{CSRA66X0_CH2_HARD_CLIP_THRESH,          0x00},
+	{CSRA66X0_SOFT_CLIP_THRESH,              0x00},
+	{CSRA66X0_DS_ENABLE_THRESH_0,            0x05},
+	{CSRA66X0_DS_ENABLE_THRESH_1,            0x00},
+	{CSRA66X0_DS_TARGET_COUNT_0,             0x00},
+	{CSRA66X0_DS_TARGET_COUNT_1,             0xFF},
+	{CSRA66X0_DS_TARGET_COUNT_2,             0xFF},
+	{CSRA66X0_DS_DISABLE_THRESH_0,           0x0F},
+	{CSRA66X0_DS_DISABLE_THRESH_1,           0x00},
+	{CSRA66X0_DCA_CTRL,                      0x07},
+	{CSRA66X0_CH1_DCA_THRESH,                0x40},
+	{CSRA66X0_CH2_DCA_THRESH,                0x40},
+	{CSRA66X0_DCA_ATTACK_RATE,               0x00},
+	{CSRA66X0_DCA_RELEASE_RATE,              0x00},
+	{CSRA66X0_CH1_OUTPUT_INVERT_EN,          0x00},
+	{CSRA66X0_CH2_OUTPUT_INVERT_EN,          0x00},
+	{CSRA66X0_CH1_176P4K_DELAY,              0x00},
+	{CSRA66X0_CH2_176P4K_DELAY,              0x00},
+	{CSRA66X0_CH1_192K_DELAY,                0x00},
+	{CSRA66X0_CH2_192K_DELAY,                0x00},
+	{CSRA66X0_DEEMP_CONFIG_FA,               0x00},
+	{CSRA66X0_CH1_TREBLE_GAIN_CTRL_FA,       0x00},
+	{CSRA66X0_CH2_TREBLE_GAIN_CTRL_FA,       0x00},
+	{CSRA66X0_CH1_TREBLE_FC_CTRL_FA,         0x00},
+	{CSRA66X0_CH2_TREBLE_FC_CTRL_FA,         0x00},
+	{CSRA66X0_CH1_BASS_GAIN_CTRL_FA,         0x00},
+	{CSRA66X0_CH2_BASS_GAIN_CTRL_FA,         0x00},
+	{CSRA66X0_CH1_BASS_FC_CTRL_FA,           0x00},
+	{CSRA66X0_CH2_BASS_FC_CTRL_FA,           0x00},
+	{CSRA66X0_FILTER_SEL_8K,                 0x00},
+	{CSRA66X0_FILTER_SEL_11P025K,            0x00},
+	{CSRA66X0_FILTER_SEL_16K,                0x00},
+	{CSRA66X0_FILTER_SEL_22P05K,             0x00},
+	{CSRA66X0_FILTER_SEL_32K,                0x00},
+	{CSRA66X0_FILTER_SEL_44P1K_48K,          0x00},
+	{CSRA66X0_FILTER_SEL_88P2K_96K,          0x00},
+	{CSRA66X0_FILTER_SEL_176P4K_192K,        0x00},
+	/* RESERVED */
+	{CSRA66X0_USER_DSP_CTRL,                 0x00},
+	{CSRA66X0_TEST_TONE_CTRL,                0x00},
+	{CSRA66X0_TEST_TONE_FREQ_0,              0x00},
+	{CSRA66X0_TEST_TONE_FREQ_1,              0x00},
+	{CSRA66X0_TEST_TONE_FREQ_2,              0x00},
+	{CSRA66X0_AUDIO_RATE_CTRL_FA,            0x08},
+	{CSRA66X0_MODULATION_INDEX_CTRL,         0x3F},
+	{CSRA66X0_MODULATION_INDEX_COUNT,        0x10},
+	{CSRA66X0_MIN_MODULATION_PULSE_WIDTH,    0x7A},
+	{CSRA66X0_DEAD_TIME_CTRL,                0x00},
+	{CSRA66X0_DEAD_TIME_THRESHOLD_0,         0xE7},
+	{CSRA66X0_DEAD_TIME_THRESHOLD_1,         0x26},
+	{CSRA66X0_DEAD_TIME_THRESHOLD_2,         0x40},
+	{CSRA66X0_CH1_LOW_SIDE_DLY,              0x00},
+	{CSRA66X0_CH2_LOW_SIDE_DLY,              0x00},
+	{CSRA66X0_SPECTRUM_CTRL,                 0x00},
+	/* RESERVED */
+	{CSRA66X0_SPECTRUM_SPREAD_CTRL,          0x0C},
+	/* RESERVED */
+	{CSRA66X0_EXT_PA_PROTECT_POLARITY,       0x03},
+	{CSRA66X0_TEMP0_BACKOFF_COMP_VALUE,      0x98},
+	{CSRA66X0_TEMP0_SHUTDOWN_COMP_VALUE,     0xA3},
+	{CSRA66X0_TEMP1_BACKOFF_COMP_VALUE,      0x98},
+	{CSRA66X0_TEMP1_SHUTDOWN_COMP_VALUE,     0xA3},
+	{CSRA66X0_TEMP_PROT_BACKOFF,             0x00},
+	{CSRA66X0_TEMP_READ0_FA,                 0x00},
+	{CSRA66X0_TEMP_READ1_FA,                 0x00},
+	{CSRA66X0_CHIP_STATE_CTRL_FA,            0x02},
+	/* RESERVED */
+	{CSRA66X0_PWM_OUTPUT_CONFIG,             0x00},
+	{CSRA66X0_MISC_CONTROL_STATUS_0,         0x08},
+	{CSRA66X0_MISC_CONTROL_STATUS_1_FA,      0x40},
+	{CSRA66X0_PIO0_SELECT,                   0x00},
+	{CSRA66X0_PIO1_SELECT,                   0x00},
+	{CSRA66X0_PIO2_SELECT,                   0x00},
+	{CSRA66X0_PIO3_SELECT,                   0x00},
+	{CSRA66X0_PIO4_SELECT,                   0x00},
+	{CSRA66X0_PIO5_SELECT,                   0x00},
+	{CSRA66X0_PIO6_SELECT,                   0x00},
+	{CSRA66X0_PIO7_SELECT,                   0x00},
+	{CSRA66X0_PIO8_SELECT,                   0x00},
+	{CSRA66X0_PIO_DIRN0,                     0xFF},
+	{CSRA66X0_PIO_DIRN1,                     0x01},
+	{CSRA66X0_PIO_PULL_EN0,                  0xFF},
+	{CSRA66X0_PIO_PULL_EN1,                  0x01},
+	{CSRA66X0_PIO_PULL_DIR0,                 0x00},
+	{CSRA66X0_PIO_PULL_DIR1,                 0x00},
+	{CSRA66X0_PIO_DRIVE_OUT0_FA,             0x00},
+	{CSRA66X0_PIO_DRIVE_OUT1_FA,             0x00},
+	{CSRA66X0_PIO_STATUS_IN0_FA,             0x00},
+	{CSRA66X0_PIO_STATUS_IN1_FA,             0x00},
+	/* RESERVED */
+	{CSRA66X0_IRQ_OUTPUT_ENABLE,             0x00},
+	{CSRA66X0_IRQ_OUTPUT_POLARITY,           0x01},
+	{CSRA66X0_IRQ_OUTPUT_STATUS_FA,          0x00},
+	{CSRA66X0_CLIP_DCA_STATUS_FA,            0x00},
+	{CSRA66X0_CHIP_STATE_STATUS_FA,          0x02},
+	{CSRA66X0_FAULT_STATUS_FA,               0x00},
+	{CSRA66X0_OTP_STATUS_FA,                 0x00},
+	{CSRA66X0_AUDIO_IF_STATUS_FA,            0x00},
+	/* RESERVED */
+	{CSRA66X0_DSP_SATURATION_STATUS_FA,      0x00},
+	{CSRA66X0_AUDIO_RATE_STATUS_FA,          0x00},
+	/* RESERVED */
+	{CSRA66X0_DISABLE_PWM_OUTPUT,            0x00},
+	/* RESERVED */
+	{CSRA66X0_OTP_VER_FA,                    0x03},
+	{CSRA66X0_RAM_VER_FA,                    0x02},
+	/* RESERVED */
+	{CSRA66X0_AUDIO_SATURATION_FLAGS_FA,     0x00},
+	{CSRA66X0_DCOFFSET_CHAN_1_01_FA,         0x00},
+	{CSRA66X0_DCOFFSET_CHAN_1_02_FA,         0x00},
+	{CSRA66X0_DCOFFSET_CHAN_1_03_FA,         0x00},
+	{CSRA66X0_DCOFFSET_CHAN_2_01_FA,         0x00},
+	{CSRA66X0_DCOFFSET_CHAN_2_02_FA,         0x00},
+	{CSRA66X0_DCOFFSET_CHAN_2_03_FA,         0x00},
+	{CSRA66X0_FORCED_PA_SWITCHING_CTRL,      0x90},
+	{CSRA66X0_PA_FORCE_PULSE_WIDTH,          0x07},
+	{CSRA66X0_PA_HIGH_MODULATION_CTRL_CH1,   0x00},
+	/* RESERVED */
+	{CSRA66X0_HIGH_MODULATION_THRESHOLD_LOW, 0xD4},
+	{CSRA66X0_HIGH_MODULATION_THRESHOLD_HIGH, 0x78},
+	/* RESERVED */
+	{CSRA66X0_PA_FREEZE_CTRL,                0x00},
+	{CSRA66X0_DCA_FREEZE_CTRL,               0x3C},
+	/* RESERVED */
+};
+
+static bool csra66x0_volatile_register(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case CSRA66X0_CHIP_ID_FA:
+	case CSRA66X0_TEMP_READ0_FA:
+	case CSRA66X0_TEMP_READ1_FA:
+	case CSRA66X0_MISC_CONTROL_STATUS_1_FA:
+	case CSRA66X0_IRQ_OUTPUT_STATUS_FA:
+	case CSRA66X0_CLIP_DCA_STATUS_FA:
+	case CSRA66X0_CHIP_STATE_STATUS_FA:
+	case CSRA66X0_FAULT_STATUS_FA:
+	case CSRA66X0_OTP_STATUS_FA:
+	case CSRA66X0_AUDIO_IF_STATUS_FA:
+	case CSRA66X0_DSP_SATURATION_STATUS_FA:
+	case CSRA66X0_AUDIO_RATE_STATUS_FA:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static bool csra66x0_writeable_registers(struct device *dev, unsigned int reg)
+{
+	if ((reg >= CSRA66X0_AUDIO_IF_RX_CONFIG1)
+			&& (reg <= CSRA66X0_MAX_REGISTER_ADDR))
+		return true;
+
+	return false;
+}
+
+static bool csra66x0_readable_registers(struct device *dev, unsigned int reg)
+{
+	if ((reg >= CSRA66X0_AUDIO_IF_RX_CONFIG1)
+			&& (reg <= CSRA66X0_MAX_REGISTER_ADDR))
+		return true;
+
+	return false;
+}
+
+/* codec private data */
+struct csra66x0_priv {
+	struct regmap *regmap;
+	struct snd_soc_codec *codec;
+	int spk_volume_ch1;
+	int spk_volume_ch2;
+	int irq;
+	int vreg_gpio;
+	u32 irq_active_low;
+	u32 in_cluster;
+	u32 is_master;
+};
+
+/*
+ * CSRA66X0 Controls
+ */
+static const DECLARE_TLV_DB_SCALE(csra66x0_volume_tlv, -9000, 25, 0);
+static const DECLARE_TLV_DB_RANGE(csra66x0_bass_treble_tlv,
+		0,  0, TLV_DB_SCALE_ITEM(0,   0, 0),
+		1, 15, TLV_DB_SCALE_ITEM(-1500, 100, 0),
+		16, 30, TLV_DB_SCALE_ITEM(100, 100, 0)
+);
+
+static int csra66x0_get_volume(struct snd_kcontrol *kcontrol,
+			struct snd_ctl_elem_value *ucontrol)
+{
+	struct soc_mixer_control *mc =
+			(struct soc_mixer_control *)kcontrol->private_value;
+	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	unsigned int reg_l = mc->reg;
+	unsigned int reg_r = mc->rreg;
+	unsigned int val_l, val_r;
+
+	val_l = (snd_soc_read(codec, reg_l) & 0xff) |
+			((snd_soc_read(codec,
+			CSRA66X0_CH1_VOLUME_1_FA) & (0x01)) << 8);
+	val_r = (snd_soc_read(codec, reg_r) & 0xff) |
+			((snd_soc_read(codec,
+			CSRA66X0_CH2_VOLUME_1_FA) & (0x01)) << 8);
+	ucontrol->value.integer.value[0] = val_l;
+	ucontrol->value.integer.value[1] = val_r;
+	return 0;
+}
+
+static int csra66x0_set_volume(struct snd_kcontrol *kcontrol,
+			struct snd_ctl_elem_value *ucontrol)
+{
+	struct soc_mixer_control *mc =
+			(struct soc_mixer_control *)kcontrol->private_value;
+	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	struct csra66x0_priv *csra66x0 = snd_soc_codec_get_drvdata(codec);
+	unsigned int reg_l = mc->reg;
+	unsigned int reg_r = mc->rreg;
+	unsigned int val_l[2];
+	unsigned int val_r[2];
+
+	csra66x0->spk_volume_ch1 = (ucontrol->value.integer.value[0]);
+	csra66x0->spk_volume_ch2 = (ucontrol->value.integer.value[1]);
+	val_l[0] = csra66x0->spk_volume_ch1 & SPK_VOLUME_LSB_MSK;
+	val_l[1] = (csra66x0->spk_volume_ch1 & SPK_VOLUME_MSB_MSK) ? 1 : 0;
+	val_r[0] = csra66x0->spk_volume_ch2 & SPK_VOLUME_LSB_MSK;
+	val_r[1] = (csra66x0->spk_volume_ch2 & SPK_VOLUME_MSB_MSK) ? 1 : 0;
+	snd_soc_write(codec, reg_l, val_l[0]);
+	snd_soc_write(codec, reg_r, val_r[0]);
+	snd_soc_write(codec, CSRA66X0_CH1_VOLUME_1_FA, val_l[1]);
+	snd_soc_write(codec, CSRA66X0_CH2_VOLUME_1_FA, val_r[1]);
+	return 0;
+}
+
+/* enumerated controls */
+static const char * const csra66x0_mute_output_text[] = {"PLAY", "MUTE"};
+static const char * const csra66x0_output_invert_text[] = {
+		"UNCHANGED", "INVERTED"};
+static const char * const csra66x0_deemp_config_text[] = {
+		"DISABLED", "ENABLED"};
+
+SOC_ENUM_SINGLE_DECL(csra66x0_mute_output_enum,
+			CSRA66X0_MISC_CONTROL_STATUS_1_FA, 2,
+			csra66x0_mute_output_text);
+SOC_ENUM_SINGLE_DECL(csra66x0_ch1_output_invert_enum,
+			CSRA66X0_CH1_OUTPUT_INVERT_EN, 0,
+			csra66x0_output_invert_text);
+SOC_ENUM_SINGLE_DECL(csra66x0_ch2_output_invert_enum,
+			CSRA66X0_CH2_OUTPUT_INVERT_EN, 0,
+			csra66x0_output_invert_text);
+SOC_ENUM_DOUBLE_DECL(csra66x0_deemp_config_enum,
+			CSRA66X0_DEEMP_CONFIG_FA, 0, 1,
+			csra66x0_deemp_config_text);
+
+static const struct snd_kcontrol_new csra66x0_snd_controls[] = {
+	/* volume */
+	SOC_DOUBLE_R_EXT_TLV("PA VOLUME", CSRA66X0_CH1_VOLUME_0_FA,
+			CSRA66X0_CH2_VOLUME_0_FA, 0, 0x1C9, 0,
+			csra66x0_get_volume, csra66x0_set_volume,
+			csra66x0_volume_tlv),
+
+	/* bass treble */
+	SOC_DOUBLE_R_TLV("PA BASS GAIN", CSRA66X0_CH1_BASS_GAIN_CTRL_FA,
+			CSRA66X0_CH2_BASS_GAIN_CTRL_FA, 0, 0x1E, 0,
+			csra66x0_bass_treble_tlv),
+	SOC_DOUBLE_R_TLV("PA TREBLE GAIN", CSRA66X0_CH1_TREBLE_GAIN_CTRL_FA,
+			CSRA66X0_CH2_TREBLE_GAIN_CTRL_FA, 0, 0x1E, 0,
+			csra66x0_bass_treble_tlv),
+	SOC_DOUBLE_R("PA BASS_XOVER FREQ", CSRA66X0_CH1_BASS_FC_CTRL_FA,
+			CSRA66X0_CH2_BASS_FC_CTRL_FA, 0, 2, 0),
+	SOC_DOUBLE_R("PA TREBLE_XOVER FREQ", CSRA66X0_CH1_TREBLE_FC_CTRL_FA,
+			CSRA66X0_CH2_TREBLE_FC_CTRL_FA, 0, 2, 0),
+
+	/* switch */
+	SOC_ENUM("PA MUTE_OUTPUT SWITCH", csra66x0_mute_output_enum),
+	SOC_ENUM("PA DE-EMPHASIS SWITCH", csra66x0_deemp_config_enum),
+};
+
+static const struct snd_kcontrol_new csra_mix_switch[] = {
+	SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0)
+};
+
+static const struct snd_soc_dapm_widget csra66x0_dapm_widgets[] = {
+	SND_SOC_DAPM_INPUT("IN"),
+	SND_SOC_DAPM_MIXER("MIXER", SND_SOC_NOPM, 0, 0,
+			csra_mix_switch, ARRAY_SIZE(csra_mix_switch)),
+	SND_SOC_DAPM_DAC("DAC", NULL, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_PGA("PGA", CSRA66X0_CHIP_STATE_CTRL_FA, 0, 0, NULL, 0),
+	SND_SOC_DAPM_OUTPUT("SPKR"),
+
+	SND_SOC_DAPM_SUPPLY("POWER", CSRA66X0_CHIP_STATE_CTRL_FA,
+			1, 1, NULL, 0),
+};
+
+static const struct snd_soc_dapm_route csra66x0_dapm_routes[] = {
+	{"MIXER", "Switch", "IN"},
+	{"DAC", NULL, "MIXER"},
+	{"PGA", NULL, "DAC"},
+	{"SPKR", NULL, "PGA"},
+	{"SPKR", NULL, "POWER"},
+};
+
+static int csra66x0_init(struct snd_soc_codec *codec,
+			struct csra66x0_priv *csra66x0)
+{
+	/* config */
+	snd_soc_write(codec, CSRA66X0_CHIP_STATE_CTRL_FA, CONFIG_STATE);
+	/* settle time in HW is min. 500ms before proceeding */
+	msleep(500);
+
+	/* setup */
+	snd_soc_write(codec, CSRA66X0_MISC_CONTROL_STATUS_0, 0x09);
+	snd_soc_write(codec, CSRA66X0_TEMP_PROT_BACKOFF, 0x0C);
+	snd_soc_write(codec, CSRA66X0_EXT_PA_PROTECT_POLARITY, 0x03);
+	snd_soc_write(codec, CSRA66X0_PWM_OUTPUT_CONFIG, 0xC8);
+	csra66x0->spk_volume_ch1 = SPK_VOLUME_M20DB;
+	csra66x0->spk_volume_ch2 = SPK_VOLUME_M20DB;
+	snd_soc_write(codec, CSRA66X0_CH1_VOLUME_0_FA, SPK_VOLUME_M20DB_LSB);
+	snd_soc_write(codec, CSRA66X0_CH2_VOLUME_0_FA, SPK_VOLUME_M20DB_LSB);
+	snd_soc_write(codec, CSRA66X0_CH1_VOLUME_1_FA, SPK_VOLUME_M20DB_MSB);
+	snd_soc_write(codec, CSRA66X0_CH2_VOLUME_1_FA, SPK_VOLUME_M20DB_MSB);
+
+	snd_soc_write(codec, CSRA66X0_DEAD_TIME_CTRL, 0x0);
+	snd_soc_write(codec, CSRA66X0_DEAD_TIME_THRESHOLD_0, 0xE7);
+	snd_soc_write(codec, CSRA66X0_DEAD_TIME_THRESHOLD_1, 0x26);
+	snd_soc_write(codec, CSRA66X0_DEAD_TIME_THRESHOLD_2, 0x40);
+
+	snd_soc_write(codec, CSRA66X0_MIN_MODULATION_PULSE_WIDTH, 0x7A);
+	snd_soc_write(codec, CSRA66X0_CH1_HARD_CLIP_THRESH, 0x00);
+	snd_soc_write(codec, CSRA66X0_CH2_HARD_CLIP_THRESH, 0x00);
+
+	snd_soc_write(codec, CSRA66X0_CH1_DCA_THRESH, 0x40);
+	snd_soc_write(codec, CSRA66X0_CH2_DCA_THRESH, 0x40);
+	snd_soc_write(codec, CSRA66X0_DCA_ATTACK_RATE, 0x00);
+	snd_soc_write(codec, CSRA66X0_DCA_RELEASE_RATE, 0x00);
+
+	if (csra66x0->irq) {
+		snd_soc_write(codec, CSRA66X0_PIO0_SELECT, 0x1);
+		if (csra66x0->irq_active_low)
+			snd_soc_write(codec, CSRA66X0_IRQ_OUTPUT_POLARITY, 0x0);
+		else
+			snd_soc_write(codec, CSRA66X0_IRQ_OUTPUT_POLARITY, 0x1);
+
+		snd_soc_write(codec, CSRA66X0_IRQ_OUTPUT_ENABLE, 0x01);
+	} else {
+		snd_soc_write(codec, CSRA66X0_IRQ_OUTPUT_ENABLE, 0x00);
+	}
+	/* settle time in HW is min. 500ms before slave initializing */
+	msleep(500);
+	return 0;
+}
+
+static int csra66x0_soc_probe(struct snd_soc_codec *codec)
+{
+	struct csra66x0_priv *csra66x0 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_dapm_context *dapm;
+	char name[50];
+
+	if (csra66x0->in_cluster) {
+		dapm = snd_soc_codec_get_dapm(codec);
+		dev_dbg(codec->dev, "%s: setting %s to codec %s\n",
+			__func__, codec->component.name_prefix,
+			codec->component.name);
+		snd_soc_write(codec, CSRA66X0_CHIP_STATE_CTRL_FA,
+			CONFIG_STATE);
+		/* settle time in HW is min. 500ms before proceeding */
+		msleep(500);
+		snd_soc_write(codec, CSRA66X0_PIO7_SELECT, 0x04);
+		snd_soc_write(codec, CSRA66X0_PIO8_SELECT, 0x04);
+		if (csra66x0->is_master) {
+			/* Master specific config */
+			snd_soc_write(codec, CSRA66X0_PIO_PULL_EN0, 0xFF);
+			snd_soc_write(codec, CSRA66X0_PIO_PULL_DIR0, 0x80);
+			snd_soc_write(codec, CSRA66X0_PIO_PULL_EN1, 0x01);
+			snd_soc_write(codec, CSRA66X0_PIO_PULL_DIR1, 0x01);
+		} else {
+			/* Slave specific config */
+			snd_soc_write(codec, CSRA66X0_PIO_PULL_EN0, 0x7F);
+			snd_soc_write(codec, CSRA66X0_PIO_PULL_EN1, 0x00);
+		}
+		snd_soc_write(codec, CSRA66X0_DCA_CTRL, 0x05);
+		if (dapm->component) {
+			strlcpy(name, dapm->component->name_prefix,
+				sizeof(name));
+			strlcat(name, " IN", sizeof(name));
+			snd_soc_dapm_ignore_suspend(dapm, name);
+			strlcpy(name, dapm->component->name_prefix,
+				sizeof(name));
+			strlcat(name, " SPKR", sizeof(name));
+			snd_soc_dapm_ignore_suspend(dapm, name);
+		}
+	}
+
+	csra66x0->codec = codec;
+
+	/* common configuration */
+	csra66x0_init(codec, csra66x0);
+	return 0;
+}
+
+static int csra66x0_soc_remove(struct snd_soc_codec *codec)
+{
+	snd_soc_write(codec, CSRA66X0_CHIP_STATE_CTRL_FA, STDBY_STATE);
+	return 0;
+}
+
+static int csra66x0_soc_suspend(struct snd_soc_codec *codec)
+{
+	u16 state_reg = snd_soc_read(codec, CSRA66X0_CHIP_STATE_CTRL_FA) & 0xFC;
+
+	snd_soc_write(codec, CSRA66X0_CHIP_STATE_CTRL_FA, state_reg |
+			STDBY_STATE);
+	return 0;
+}
+
+static int csra66x0_soc_resume(struct snd_soc_codec *codec)
+{
+	u16 state_reg = snd_soc_read(codec, CSRA66X0_CHIP_STATE_CTRL_FA) & 0xFC;
+
+	snd_soc_write(codec, CSRA66X0_CHIP_STATE_CTRL_FA, state_reg |
+			RUN_STATE);
+	return 0;
+}
+
+static struct regmap *csra66x0_get_regmap(struct device *dev)
+{
+	struct csra66x0_priv *csra66x0_ctrl = dev_get_drvdata(dev);
+
+	if (!csra66x0_ctrl)
+		return NULL;
+	return csra66x0_ctrl->regmap;
+}
+
+static struct snd_soc_codec_driver soc_codec_drv_csra66x0 = {
+	.probe  = csra66x0_soc_probe,
+	.remove = csra66x0_soc_remove,
+	.suspend = csra66x0_soc_suspend,
+	.resume = csra66x0_soc_resume,
+	.get_regmap = csra66x0_get_regmap,
+	.component_driver = {
+		.controls = csra66x0_snd_controls,
+		.num_controls = ARRAY_SIZE(csra66x0_snd_controls),
+		.dapm_widgets = csra66x0_dapm_widgets,
+		.num_dapm_widgets = ARRAY_SIZE(csra66x0_dapm_widgets),
+		.dapm_routes = csra66x0_dapm_routes,
+		.num_dapm_routes = ARRAY_SIZE(csra66x0_dapm_routes),
+	},
+};
+
+static struct regmap_config csra66x0_regmap_config = {
+	.reg_bits = 16,
+	.val_bits = 8,
+	.cache_type = REGCACHE_RBTREE,
+	.reg_defaults = csra66x0_reg_defaults,
+	.num_reg_defaults = ARRAY_SIZE(csra66x0_reg_defaults),
+	.max_register = CSRA66X0_MAX_REGISTER_ADDR,
+	.volatile_reg = csra66x0_volatile_register,
+	.writeable_reg = csra66x0_writeable_registers,
+	.readable_reg = csra66x0_readable_registers,
+};
+
+static irqreturn_t csra66x0_irq(int irq, void *data)
+{
+	struct csra66x0_priv *csra66x0 = (struct csra66x0_priv *) data;
+	struct snd_soc_codec  *codec = csra66x0->codec;
+	u16    val;
+
+	/* Treat interrupt before codec is initialized as spurious */
+	if (codec == NULL)
+		return IRQ_NONE;
+
+	dev_dbg(codec->dev, "%s: csra66x0_interrupt\n", __func__);
+
+	/* fault  indication */
+	val = snd_soc_read(codec, CSRA66X0_IRQ_OUTPUT_STATUS_FA) & 0x1;
+	if (val) {
+		val = snd_soc_read(codec, CSRA66X0_FAULT_STATUS_FA);
+		if (val & FAULT_STATUS_INTERNAL)
+			dev_dbg(codec->dev, "%s: FAULT_STATUS_INTERNAL 0x%X\n",
+				__func__, val);
+		if (val & FAULT_STATUS_OTP_INTEGRITY)
+			dev_dbg(codec->dev, "%s: FAULT_STATUS_OTP_INTEGRITY 0x%X\n",
+				__func__, val);
+		if (val & FAULT_STATUS_PADS2)
+			dev_dbg(codec->dev, "%s: FAULT_STATUS_PADS2 0x%X\n",
+				__func__, val);
+		if (val & FAULT_STATUS_SMPS)
+			dev_dbg(codec->dev, "%s: FAULT_STATUS_SMPS 0x%X\n",
+				__func__, val);
+		if (val & FAULT_STATUS_TEMP)
+			dev_dbg(codec->dev, "%s: FAULT_STATUS_TEMP 0x%X\n",
+				__func__, val);
+		if (val & FAULT_STATUS_PROTECT)
+			dev_dbg(codec->dev, "%s: FAULT_STATUS_PROTECT 0x%X\n",
+				__func__, val);
+
+		/* clear fault state and re-init */
+		snd_soc_write(codec, CSRA66X0_FAULT_STATUS_FA, 0x00);
+		csra66x0_init(codec, csra66x0);
+	} else {
+		return IRQ_NONE;
+	}
+	return IRQ_HANDLED;
+};
+
+static const struct of_device_id csra66x0_of_match[] = {
+	{ .compatible = "qcom,csra66x0", },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, csra66x0_of_match);
+
+#if IS_ENABLED(CONFIG_I2C)
+static int csra66x0_i2c_probe(struct i2c_client *client_i2c,
+			const struct i2c_device_id *id)
+{
+	struct csra66x0_priv *csra66x0;
+	int ret, irq_trigger;
+
+	csra66x0 = devm_kzalloc(&client_i2c->dev, sizeof(struct csra66x0_priv),
+			GFP_KERNEL);
+	if (csra66x0 == NULL)
+		return -ENOMEM;
+
+	csra66x0->regmap = devm_regmap_init_i2c(client_i2c,
+			&csra66x0_regmap_config);
+	if (IS_ERR(csra66x0->regmap)) {
+		ret = PTR_ERR(csra66x0->regmap);
+		dev_err(&client_i2c->dev,
+				"%s %d: Failed to allocate register map for I2C device: %d\n",
+				__func__, __LINE__, ret);
+		return ret;
+	}
+
+	i2c_set_clientdata(client_i2c, csra66x0);
+
+	/* get data from device tree */
+	if (client_i2c->dev.of_node) {
+		/* cluster of multiple devices */
+		ret = of_property_read_u32(
+			client_i2c->dev.of_node, "qcom,csra-cluster",
+			&csra66x0->in_cluster);
+		if (ret) {
+			dev_info(&client_i2c->dev,
+			"%s: qcom,csra-cluster property not defined in DT\n", __func__);
+			csra66x0->in_cluster = 0;
+		}
+		/* master or slave device */
+		ret = of_property_read_u32(
+			client_i2c->dev.of_node, "qcom,csra-cluster-master",
+			&csra66x0->is_master);
+		if (ret) {
+			dev_info(&client_i2c->dev,
+			"%s: qcom,csra-cluster-master property not defined in DT\n", __func__);
+			csra66x0->is_master = 0;
+		}
+
+		/* gpio setup for vreg */
+		csra66x0->vreg_gpio = of_get_named_gpio(client_i2c->dev.of_node,
+			"qcom,csra-vreg-en-gpio", 0);
+		if (!gpio_is_valid(csra66x0->vreg_gpio)) {
+			dev_err(&client_i2c->dev, "%s: %s property is not found %d\n",
+					__func__, "qcom,csra-vreg-en-gpio",
+					csra66x0->vreg_gpio);
+			return -ENODEV;
+		}
+		dev_dbg(&client_i2c->dev, "%s: vreg_en gpio %d\n", __func__,
+			csra66x0->vreg_gpio);
+		ret = gpio_request(csra66x0->vreg_gpio, dev_name(&client_i2c->dev));
+		if (ret) {
+			if (ret == -EBUSY) {
+				/* GPIO was already requested */
+				dev_dbg(&client_i2c->dev,
+				"%s: gpio %d is already set\n",
+				__func__, csra66x0->vreg_gpio);
+			} else {
+				dev_err(&client_i2c->dev, "%s: Failed to request gpio %d, err: %d\n",
+					__func__, csra66x0->vreg_gpio, ret);
+			}
+		} else {
+			gpio_direction_output(csra66x0->vreg_gpio, 1);
+			gpio_set_value(csra66x0->vreg_gpio, 1);
+		}
+
+		/* register interrupt handle */
+		if (client_i2c->irq) {
+			csra66x0->irq = client_i2c->irq;
+			/* interrupt polarity */
+			ret = of_property_read_u32(
+				client_i2c->dev.of_node, "irq-active-low",
+				&csra66x0->irq_active_low);
+			if (ret) {
+				dev_info(&client_i2c->dev,
+				"%s: irq-active-low property not defined in DT\n", __func__);
+				csra66x0->irq_active_low = 0;
+			}
+			if (csra66x0->irq_active_low)
+				irq_trigger = IRQF_TRIGGER_LOW;
+			else
+				irq_trigger = IRQF_TRIGGER_HIGH;
+
+			ret = devm_request_threaded_irq(&client_i2c->dev,
+					csra66x0->irq, NULL, csra66x0_irq,
+					irq_trigger | IRQF_ONESHOT,
+					"csra66x0_irq", csra66x0);
+			if (ret) {
+				dev_err(&client_i2c->dev,
+				"%s: Failed to request IRQ %d: %d\n",
+				__func__, csra66x0->irq, ret);
+				csra66x0->irq = 0;
+			}
+		}
+	}
+
+	/* register codec */
+	ret = snd_soc_register_codec(&client_i2c->dev,
+			&soc_codec_drv_csra66x0, NULL, 0);
+	if (ret != 0) {
+		dev_err(&client_i2c->dev, "%s %d: Failed to register CODEC: %d\n",
+			__func__,  __LINE__, ret);
+		if (gpio_is_valid(csra66x0->vreg_gpio)) {
+			gpio_set_value(csra66x0->vreg_gpio, 0);
+			gpio_free(csra66x0->vreg_gpio);
+		}
+		return ret;
+	}
+	return 0;
+}
+
+static int csra66x0_i2c_remove(struct i2c_client *i2c_client)
+{
+	struct csra66x0_priv *csra66x0 = i2c_get_clientdata(i2c_client);
+
+	if (csra66x0) {
+		if (gpio_is_valid(csra66x0->vreg_gpio)) {
+			gpio_set_value(csra66x0->vreg_gpio, 0);
+			gpio_free(csra66x0->vreg_gpio);
+		}
+	}
+	snd_soc_unregister_codec(&i2c_client->dev);
+	return 0;
+}
+
+static const struct i2c_device_id csra66x0_i2c_id[] = {
+	{ "csra66x0", 0},
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, csra66x0_i2c_id);
+
+static struct i2c_driver csra66x0_i2c_driver = {
+	.probe =    csra66x0_i2c_probe,
+	.remove =   csra66x0_i2c_remove,
+	.id_table = csra66x0_i2c_id,
+	.driver = {
+		.name = "csra66x0",
+		.owner = THIS_MODULE,
+		.of_match_table = csra66x0_of_match
+	},
+};
+#endif
+
+static int __init csra66x0_codec_init(void)
+{
+	int ret = 0;
+#if IS_ENABLED(CONFIG_I2C)
+	ret = i2c_add_driver(&csra66x0_i2c_driver);
+	if (ret != 0)
+		pr_err("%s: Failed to register CSRA66X0 I2C driver, ret = %d\n",
+			__func__, ret);
+#endif
+	return ret;
+}
+module_init(csra66x0_codec_init);
+
+static void __exit csra66x0_codec_exit(void)
+{
+#if IS_ENABLED(CONFIG_I2C)
+	i2c_del_driver(&csra66x0_i2c_driver);
+#endif
+}
+module_exit(csra66x0_codec_exit);
+
+MODULE_DESCRIPTION("CSRA66X0 Codec driver");
+MODULE_LICENSE("GPL v2");

+ 230 - 0
asoc/codecs/csra66x0/csra66x0.h

@@ -0,0 +1,230 @@
+/*
+ * Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _CSRA66X0_H
+#define _CSRA66X0_H
+
+/* CSRA66X0 register addresses */
+#define CSRA66X0_BASE 0x7000
+
+#define CSRA66X0_AUDIO_IF_RX_CONFIG1            (CSRA66X0_BASE+0x0000)
+#define CSRA66X0_AUDIO_IF_RX_CONFIG2            (CSRA66X0_BASE+0x0001)
+#define CSRA66X0_AUDIO_IF_RX_CONFIG3            (CSRA66X0_BASE+0x0002)
+#define CSRA66X0_AUDIO_IF_TX_EN                 (CSRA66X0_BASE+0x0003)
+#define CSRA66X0_AUDIO_IF_TX_CONFIG1            (CSRA66X0_BASE+0x0004)
+#define CSRA66X0_AUDIO_IF_TX_CONFIG2            (CSRA66X0_BASE+0x0005)
+#define CSRA66X0_I2C_DEVICE_ADDRESS             (CSRA66X0_BASE+0x0006)
+#define CSRA66X0_CHIP_ID_FA                     (CSRA66X0_BASE+0x0007)
+#define CSRA66X0_ROM_VER_FA                     (CSRA66X0_BASE+0x0008)
+#define CSRA66X0_CHIP_REV_0_FA                  (CSRA66X0_BASE+0x0009)
+#define CSRA66X0_CHIP_REV_1_FA                  (CSRA66X0_BASE+0x000A)
+#define CSRA66X0_CH1_MIX_SEL                    (CSRA66X0_BASE+0x000B)
+#define CSRA66X0_CH2_MIX_SEL                    (CSRA66X0_BASE+0x000C)
+#define CSRA66X0_CH1_SAMPLE1_SCALE_0            (CSRA66X0_BASE+0x000D)
+#define CSRA66X0_CH1_SAMPLE1_SCALE_1            (CSRA66X0_BASE+0x000E)
+#define CSRA66X0_CH1_SAMPLE3_SCALE_0            (CSRA66X0_BASE+0x000F)
+#define CSRA66X0_CH1_SAMPLE3_SCALE_1            (CSRA66X0_BASE+0x0010)
+#define CSRA66X0_CH1_SAMPLE5_SCALE_0            (CSRA66X0_BASE+0x0011)
+#define CSRA66X0_CH1_SAMPLE5_SCALE_1            (CSRA66X0_BASE+0x0012)
+#define CSRA66X0_CH1_SAMPLE7_SCALE_0            (CSRA66X0_BASE+0x0013)
+#define CSRA66X0_CH1_SAMPLE7_SCALE_1            (CSRA66X0_BASE+0x0014)
+#define CSRA66X0_CH1_SAMPLE2_SCALE_0            (CSRA66X0_BASE+0x0015)
+#define CSRA66X0_CH1_SAMPLE2_SCALE_1            (CSRA66X0_BASE+0x0016)
+#define CSRA66X0_CH1_SAMPLE4_SCALE_0            (CSRA66X0_BASE+0x0017)
+#define CSRA66X0_CH1_SAMPLE4_SCALE_1            (CSRA66X0_BASE+0x0018)
+#define CSRA66X0_CH1_SAMPLE6_SCALE_0            (CSRA66X0_BASE+0x0019)
+#define CSRA66X0_CH1_SAMPLE6_SCALE_1            (CSRA66X0_BASE+0x001A)
+#define CSRA66X0_CH1_SAMPLE8_SCALE_0            (CSRA66X0_BASE+0x001B)
+#define CSRA66X0_CH1_SAMPLE8_SCALE_1            (CSRA66X0_BASE+0x001C)
+#define CSRA66X0_CH2_SAMPLE1_SCALE_0            (CSRA66X0_BASE+0x001D)
+#define CSRA66X0_CH2_SAMPLE1_SCALE_1            (CSRA66X0_BASE+0x001E)
+#define CSRA66X0_CH2_SAMPLE3_SCALE_0            (CSRA66X0_BASE+0x001F)
+#define CSRA66X0_CH2_SAMPLE3_SCALE_1            (CSRA66X0_BASE+0x0020)
+#define CSRA66X0_CH2_SAMPLE5_SCALE_0            (CSRA66X0_BASE+0x0021)
+#define CSRA66X0_CH2_SAMPLE5_SCALE_1            (CSRA66X0_BASE+0x0022)
+#define CSRA66X0_CH2_SAMPLE7_SCALE_0            (CSRA66X0_BASE+0x0023)
+#define CSRA66X0_CH2_SAMPLE7_SCALE_1            (CSRA66X0_BASE+0x0024)
+#define CSRA66X0_CH2_SAMPLE2_SCALE_0            (CSRA66X0_BASE+0x0025)
+#define CSRA66X0_CH2_SAMPLE2_SCALE_1            (CSRA66X0_BASE+0x0026)
+#define CSRA66X0_CH2_SAMPLE4_SCALE_0            (CSRA66X0_BASE+0x0027)
+#define CSRA66X0_CH2_SAMPLE4_SCALE_1            (CSRA66X0_BASE+0x0028)
+#define CSRA66X0_CH2_SAMPLE6_SCALE_0            (CSRA66X0_BASE+0x0029)
+#define CSRA66X0_CH2_SAMPLE6_SCALE_1            (CSRA66X0_BASE+0x002A)
+#define CSRA66X0_CH2_SAMPLE8_SCALE_0            (CSRA66X0_BASE+0x002B)
+#define CSRA66X0_CH2_SAMPLE8_SCALE_1            (CSRA66X0_BASE+0x002C)
+#define CSRA66X0_VOLUME_CONFIG_FA               (CSRA66X0_BASE+0x002D)
+#define CSRA66X0_STARTUP_DELAY_FA               (CSRA66X0_BASE+0x002E)
+#define CSRA66X0_CH1_VOLUME_0_FA                (CSRA66X0_BASE+0x002F)
+#define CSRA66X0_CH1_VOLUME_1_FA                (CSRA66X0_BASE+0x0030)
+#define CSRA66X0_CH2_VOLUME_0_FA                (CSRA66X0_BASE+0x0031)
+#define CSRA66X0_CH2_VOLUME_1_FA                (CSRA66X0_BASE+0x0032)
+#define CSRA66X0_QUAD_ENC_COUNT_0_FA            (CSRA66X0_BASE+0x0033)
+#define CSRA66X0_QUAD_ENC_COUNT_1_FA            (CSRA66X0_BASE+0x0034)
+#define CSRA66X0_SOFT_CLIP_CONFIG               (CSRA66X0_BASE+0x0035)
+#define CSRA66X0_CH1_HARD_CLIP_THRESH           (CSRA66X0_BASE+0x0036)
+#define CSRA66X0_CH2_HARD_CLIP_THRESH           (CSRA66X0_BASE+0x0037)
+#define CSRA66X0_SOFT_CLIP_THRESH               (CSRA66X0_BASE+0x0038)
+#define CSRA66X0_DS_ENABLE_THRESH_0             (CSRA66X0_BASE+0x0039)
+#define CSRA66X0_DS_ENABLE_THRESH_1             (CSRA66X0_BASE+0x003A)
+#define CSRA66X0_DS_TARGET_COUNT_0              (CSRA66X0_BASE+0x003B)
+#define CSRA66X0_DS_TARGET_COUNT_1              (CSRA66X0_BASE+0x003C)
+#define CSRA66X0_DS_TARGET_COUNT_2              (CSRA66X0_BASE+0x003D)
+#define CSRA66X0_DS_DISABLE_THRESH_0            (CSRA66X0_BASE+0x003E)
+#define CSRA66X0_DS_DISABLE_THRESH_1            (CSRA66X0_BASE+0x003F)
+#define CSRA66X0_DCA_CTRL                       (CSRA66X0_BASE+0x0040)
+#define CSRA66X0_CH1_DCA_THRESH                 (CSRA66X0_BASE+0x0041)
+#define CSRA66X0_CH2_DCA_THRESH                 (CSRA66X0_BASE+0x0042)
+#define CSRA66X0_DCA_ATTACK_RATE                (CSRA66X0_BASE+0x0043)
+#define CSRA66X0_DCA_RELEASE_RATE               (CSRA66X0_BASE+0x0044)
+#define CSRA66X0_CH1_OUTPUT_INVERT_EN           (CSRA66X0_BASE+0x0045)
+#define CSRA66X0_CH2_OUTPUT_INVERT_EN           (CSRA66X0_BASE+0x0046)
+#define CSRA66X0_CH1_176P4K_DELAY               (CSRA66X0_BASE+0x0047)
+#define CSRA66X0_CH2_176P4K_DELAY               (CSRA66X0_BASE+0x0048)
+#define CSRA66X0_CH1_192K_DELAY                 (CSRA66X0_BASE+0x0049)
+#define CSRA66X0_CH2_192K_DELAY                 (CSRA66X0_BASE+0x004A)
+#define CSRA66X0_DEEMP_CONFIG_FA                (CSRA66X0_BASE+0x004B)
+#define CSRA66X0_CH1_TREBLE_GAIN_CTRL_FA        (CSRA66X0_BASE+0x004C)
+#define CSRA66X0_CH2_TREBLE_GAIN_CTRL_FA        (CSRA66X0_BASE+0x004D)
+#define CSRA66X0_CH1_TREBLE_FC_CTRL_FA          (CSRA66X0_BASE+0x004E)
+#define CSRA66X0_CH2_TREBLE_FC_CTRL_FA          (CSRA66X0_BASE+0x004F)
+#define CSRA66X0_CH1_BASS_GAIN_CTRL_FA          (CSRA66X0_BASE+0x0050)
+#define CSRA66X0_CH2_BASS_GAIN_CTRL_FA          (CSRA66X0_BASE+0x0051)
+#define CSRA66X0_CH1_BASS_FC_CTRL_FA            (CSRA66X0_BASE+0x0052)
+#define CSRA66X0_CH2_BASS_FC_CTRL_FA            (CSRA66X0_BASE+0x0053)
+#define CSRA66X0_FILTER_SEL_8K                  (CSRA66X0_BASE+0x0054)
+#define CSRA66X0_FILTER_SEL_11P025K             (CSRA66X0_BASE+0x0055)
+#define CSRA66X0_FILTER_SEL_16K                 (CSRA66X0_BASE+0x0056)
+#define CSRA66X0_FILTER_SEL_22P05K              (CSRA66X0_BASE+0x0057)
+#define CSRA66X0_FILTER_SEL_32K                 (CSRA66X0_BASE+0x0058)
+#define CSRA66X0_FILTER_SEL_44P1K_48K           (CSRA66X0_BASE+0x0059)
+#define CSRA66X0_FILTER_SEL_88P2K_96K           (CSRA66X0_BASE+0x005A)
+#define CSRA66X0_FILTER_SEL_176P4K_192K         (CSRA66X0_BASE+0x005B)
+/* RESERVED (CSRA66X0_BASE+0x005C) */
+#define CSRA66X0_USER_DSP_CTRL                  (CSRA66X0_BASE+0x005D)
+#define CSRA66X0_TEST_TONE_CTRL                 (CSRA66X0_BASE+0x005E)
+#define CSRA66X0_TEST_TONE_FREQ_0               (CSRA66X0_BASE+0x005F)
+#define CSRA66X0_TEST_TONE_FREQ_1               (CSRA66X0_BASE+0x0060)
+#define CSRA66X0_TEST_TONE_FREQ_2               (CSRA66X0_BASE+0x0061)
+#define CSRA66X0_AUDIO_RATE_CTRL_FA             (CSRA66X0_BASE+0x0062)
+#define CSRA66X0_MODULATION_INDEX_CTRL          (CSRA66X0_BASE+0x0063)
+#define CSRA66X0_MODULATION_INDEX_COUNT         (CSRA66X0_BASE+0x0064)
+#define CSRA66X0_MIN_MODULATION_PULSE_WIDTH     (CSRA66X0_BASE+0x0065)
+#define CSRA66X0_DEAD_TIME_CTRL                 (CSRA66X0_BASE+0x0066)
+#define CSRA66X0_DEAD_TIME_THRESHOLD_0          (CSRA66X0_BASE+0x0067)
+#define CSRA66X0_DEAD_TIME_THRESHOLD_1          (CSRA66X0_BASE+0x0068)
+#define CSRA66X0_DEAD_TIME_THRESHOLD_2          (CSRA66X0_BASE+0x0069)
+#define CSRA66X0_CH1_LOW_SIDE_DLY               (CSRA66X0_BASE+0x006A)
+#define CSRA66X0_CH2_LOW_SIDE_DLY               (CSRA66X0_BASE+0x006B)
+#define CSRA66X0_SPECTRUM_CTRL                  (CSRA66X0_BASE+0x006C)
+/* RESERVED (CSRA66X0_BASE+0x006D) */
+#define CSRA66X0_SPECTRUM_SPREAD_CTRL           (CSRA66X0_BASE+0x006E)
+/* RESERVED (CSRA66X0_BASE+0x006F) */
+/* ... */
+/* RESERVED (CSRA66X0_BASE+0x007C) */
+#define CSRA66X0_EXT_PA_PROTECT_POLARITY        (CSRA66X0_BASE+0x007D)
+#define CSRA66X0_TEMP0_BACKOFF_COMP_VALUE       (CSRA66X0_BASE+0x007E)
+#define CSRA66X0_TEMP0_SHUTDOWN_COMP_VALUE      (CSRA66X0_BASE+0x007F)
+#define CSRA66X0_TEMP1_BACKOFF_COMP_VALUE       (CSRA66X0_BASE+0x0080)
+#define CSRA66X0_TEMP1_SHUTDOWN_COMP_VALUE      (CSRA66X0_BASE+0x0081)
+#define CSRA66X0_TEMP_PROT_BACKOFF              (CSRA66X0_BASE+0x0082)
+#define CSRA66X0_TEMP_READ0_FA                  (CSRA66X0_BASE+0x0083)
+#define CSRA66X0_TEMP_READ1_FA                  (CSRA66X0_BASE+0x0084)
+#define CSRA66X0_CHIP_STATE_CTRL_FA             (CSRA66X0_BASE+0x0085)
+/* RESERVED (CSRA66X0_BASE+0x0086) */
+#define CSRA66X0_PWM_OUTPUT_CONFIG              (CSRA66X0_BASE+0x0087)
+#define CSRA66X0_MISC_CONTROL_STATUS_0          (CSRA66X0_BASE+0x0088)
+#define CSRA66X0_MISC_CONTROL_STATUS_1_FA       (CSRA66X0_BASE+0x0089)
+#define CSRA66X0_PIO0_SELECT                    (CSRA66X0_BASE+0x008A)
+#define CSRA66X0_PIO1_SELECT                    (CSRA66X0_BASE+0x008B)
+#define CSRA66X0_PIO2_SELECT                    (CSRA66X0_BASE+0x008C)
+#define CSRA66X0_PIO3_SELECT                    (CSRA66X0_BASE+0x008D)
+#define CSRA66X0_PIO4_SELECT                    (CSRA66X0_BASE+0x008E)
+#define CSRA66X0_PIO5_SELECT                    (CSRA66X0_BASE+0x008F)
+#define CSRA66X0_PIO6_SELECT                    (CSRA66X0_BASE+0x0090)
+#define CSRA66X0_PIO7_SELECT                    (CSRA66X0_BASE+0x0091)
+#define CSRA66X0_PIO8_SELECT                    (CSRA66X0_BASE+0x0092)
+#define CSRA66X0_PIO_DIRN0                      (CSRA66X0_BASE+0x0093)
+#define CSRA66X0_PIO_DIRN1                      (CSRA66X0_BASE+0x0094)
+#define CSRA66X0_PIO_PULL_EN0                   (CSRA66X0_BASE+0x0095)
+#define CSRA66X0_PIO_PULL_EN1                   (CSRA66X0_BASE+0x0096)
+#define CSRA66X0_PIO_PULL_DIR0                  (CSRA66X0_BASE+0x0097)
+#define CSRA66X0_PIO_PULL_DIR1                  (CSRA66X0_BASE+0x0098)
+#define CSRA66X0_PIO_DRIVE_OUT0_FA              (CSRA66X0_BASE+0x0099)
+#define CSRA66X0_PIO_DRIVE_OUT1_FA              (CSRA66X0_BASE+0x009A)
+#define CSRA66X0_PIO_STATUS_IN0_FA              (CSRA66X0_BASE+0x009B)
+#define CSRA66X0_PIO_STATUS_IN1_FA              (CSRA66X0_BASE+0x009C)
+/* RESERVED (CSRA66X0_BASE+0x009D) */
+#define CSRA66X0_IRQ_OUTPUT_ENABLE              (CSRA66X0_BASE+0x009E)
+#define CSRA66X0_IRQ_OUTPUT_POLARITY            (CSRA66X0_BASE+0x009F)
+#define CSRA66X0_IRQ_OUTPUT_STATUS_FA           (CSRA66X0_BASE+0x00A0)
+#define CSRA66X0_CLIP_DCA_STATUS_FA             (CSRA66X0_BASE+0x00A1)
+#define CSRA66X0_CHIP_STATE_STATUS_FA           (CSRA66X0_BASE+0x00A2)
+#define CSRA66X0_FAULT_STATUS_FA                (CSRA66X0_BASE+0x00A3)
+#define CSRA66X0_OTP_STATUS_FA                  (CSRA66X0_BASE+0x00A4)
+#define CSRA66X0_AUDIO_IF_STATUS_FA             (CSRA66X0_BASE+0x00A5)
+/* RESERVED (CSRA66X0_BASE+0x00A6) */
+#define CSRA66X0_DSP_SATURATION_STATUS_FA       (CSRA66X0_BASE+0x00A7)
+#define CSRA66X0_AUDIO_RATE_STATUS_FA           (CSRA66X0_BASE+0x00A8)
+/* RESERVED (CSRA66X0_BASE+0x00A9) */
+/* ... */
+/* RESERVED (CSRA66X0_BASE+0x00AB) */
+#define CSRA66X0_DISABLE_PWM_OUTPUT             (CSRA66X0_BASE+0x00AC)
+/* RESERVED (CSRA66X0_BASE+0x00AD) */
+/* ... */
+/* RESERVED (CSRA66X0_BASE+0x00B0) */
+#define CSRA66X0_OTP_VER_FA                     (CSRA66X0_BASE+0x00B1)
+#define CSRA66X0_RAM_VER_FA                     (CSRA66X0_BASE+0x00B2)
+/* RESERVED (CSRA66X0_BASE+0x00B3) */
+#define CSRA66X0_AUDIO_SATURATION_FLAGS_FA      (CSRA66X0_BASE+0x00B4)
+#define CSRA66X0_DCOFFSET_CHAN_1_01_FA          (CSRA66X0_BASE+0x00B5)
+#define CSRA66X0_DCOFFSET_CHAN_1_02_FA          (CSRA66X0_BASE+0x00B6)
+#define CSRA66X0_DCOFFSET_CHAN_1_03_FA          (CSRA66X0_BASE+0x00B7)
+#define CSRA66X0_DCOFFSET_CHAN_2_01_FA          (CSRA66X0_BASE+0x00B8)
+#define CSRA66X0_DCOFFSET_CHAN_2_02_FA          (CSRA66X0_BASE+0x00B9)
+#define CSRA66X0_DCOFFSET_CHAN_2_03_FA          (CSRA66X0_BASE+0x00BA)
+#define CSRA66X0_FORCED_PA_SWITCHING_CTRL       (CSRA66X0_BASE+0x00BB)
+#define CSRA66X0_PA_FORCE_PULSE_WIDTH           (CSRA66X0_BASE+0x00BC)
+#define CSRA66X0_PA_HIGH_MODULATION_CTRL_CH1    (CSRA66X0_BASE+0x00BD)
+/* RESERVED (CSRA66X0_BASE+0x00BE) */
+/* RESERVED (CSRA66X0_BASE+0x00BF) */
+#define CSRA66X0_HIGH_MODULATION_THRESHOLD_LOW  (CSRA66X0_BASE+0x00C0)
+#define CSRA66X0_HIGH_MODULATION_THRESHOLD_HIGH (CSRA66X0_BASE+0x00C1)
+/* RESERVED (CSRA66X0_BASE+0x00C2) */
+/* RESERVED (CSRA66X0_BASE+0x00C3) */
+#define CSRA66X0_PA_FREEZE_CTRL                 (CSRA66X0_BASE+0x00C4)
+#define CSRA66X0_DCA_FREEZE_CTRL                (CSRA66X0_BASE+0x00C5)
+/* RESERVED (CSRA66X0_BASE+0x00C6) */
+/* ... */
+/* RESERVED (CSRA66X0_BASE+0x00FF) */
+#define CSRA66X0_MAX_REGISTER_ADDR  CSRA66X0_DCA_FREEZE_CTRL
+
+#define EXPECTED_CSRA66X0_CHIP_ID 0x39
+
+#define SPK_VOLUME_M20DB 0x119
+#define SPK_VOLUME_M20DB_LSB (SPK_VOLUME_M20DB & 0x0FF)
+#define SPK_VOLUME_M20DB_MSB ((SPK_VOLUME_M20DB & 0x100)>>8)
+#define SPK_VOLUME_LSB_MSK 0x00FF
+#define SPK_VOLUME_MSB_MSK 0x0100
+
+#define CONFIG_STATE    0x0
+#define RUN_STATE       0x1
+#define STDBY_STATE     0x2
+
+#define FAULT_STATUS_INTERNAL       0x01
+#define FAULT_STATUS_OTP_INTEGRITY  0x02
+#define FAULT_STATUS_PADS2          0x04
+#define FAULT_STATUS_SMPS           0x08
+#define FAULT_STATUS_TEMP           0x10
+#define FAULT_STATUS_PROTECT        0x20
+
+#endif /* _CSRA66X0_H */