[alsa-devel] [PATCH] ASoC: Add support for NAU8824 codec to ASoC

Wan ZongShun linux at mcuos.com
Sat Feb 21 15:39:54 CET 2015


The NAU88L24 is an ultra-low power high performance audio codec designed
for tablet PC, ultra portable laptops by Nuvoton, now add linux driver
support for it.

Signed-off-by: Wan ZongShun <linux at mcuos.com>
---
 sound/soc/codecs/Kconfig   |   5 +
 sound/soc/codecs/Makefile  |   2 +
 sound/soc/codecs/nau8824.c | 770 +++++++++++++++++++++++++++++++++++++++++++++
 sound/soc/codecs/nau8824.h | 379 ++++++++++++++++++++++
 4 files changed, 1156 insertions(+)
 create mode 100644 sound/soc/codecs/nau8824.c
 create mode 100644 sound/soc/codecs/nau8824.h

diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index 064e6c1..862b7bd 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -75,6 +75,7 @@ config SND_SOC_ALL_CODECS
 	select SND_SOC_MAX9877 if I2C
 	select SND_SOC_MC13783 if MFD_MC13XXX
 	select SND_SOC_ML26124 if I2C
+	select SND_SOC_NAU8824 if I2C
 	select SND_SOC_HDMI_CODEC
 	select SND_SOC_PCM1681 if I2C
 	select SND_SOC_PCM1792A if SPI_MASTER
@@ -463,6 +464,10 @@ config SND_SOC_MAX98357A
 config SND_SOC_MAX9850
 	tristate
 
+config SND_SOC_NAU8824
+	tristate "Nuvoton NAU8824 CODEC"
+	depends on I2C
+
 config SND_SOC_PCM1681
 	tristate "Texas Instruments PCM1681 CODEC"
 	depends on I2C
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index 69b8666..acb7bda 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -68,6 +68,7 @@ snd-soc-max98357a-objs := max98357a.o
 snd-soc-max9850-objs := max9850.o
 snd-soc-mc13783-objs := mc13783.o
 snd-soc-ml26124-objs := ml26124.o
+snd-soc-nau8824-objs := nau8824.o
 snd-soc-hdmi-codec-objs := hdmi.o
 snd-soc-pcm1681-objs := pcm1681.o
 snd-soc-pcm1792a-codec-objs := pcm1792a.o
@@ -250,6 +251,7 @@ obj-$(CONFIG_SND_SOC_MAX98357A)	+= snd-soc-max98357a.o
 obj-$(CONFIG_SND_SOC_MAX9850)	+= snd-soc-max9850.o
 obj-$(CONFIG_SND_SOC_MC13783)	+= snd-soc-mc13783.o
 obj-$(CONFIG_SND_SOC_ML26124)	+= snd-soc-ml26124.o
+obj-$(CONFIG_SND_SOC_NAU8824)	+= snd-soc-nau8824.o
 obj-$(CONFIG_SND_SOC_HDMI_CODEC) += snd-soc-hdmi-codec.o
 obj-$(CONFIG_SND_SOC_PCM1681)	+= snd-soc-pcm1681.o
 obj-$(CONFIG_SND_SOC_PCM1792A)	+= snd-soc-pcm1792a-codec.o
diff --git a/sound/soc/codecs/nau8824.c b/sound/soc/codecs/nau8824.c
new file mode 100644
index 0000000..80c2283
--- /dev/null
+++ b/sound/soc/codecs/nau8824.c
@@ -0,0 +1,770 @@
+/*
+ * linux/sound/soc/codecs/nau8824.c
+ *
+ * Copyright 2015 Nuvoton Technology Corp.
+ * Author: Meng-Huang Kuo <mhkuo at nuvoton.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/gpio.h>
+#include <linux/device.h>
+#include <linux/clk.h>
+#include <linux/regmap.h>
+#include <linux/acpi.h>
+#include <asm/div64.h>
+#include <sound/jack.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+#include <linux/delay.h>
+
+#include "nau8824.h"
+
+static int nau8824_hw_params(struct snd_pcm_substream *substream,
+				struct snd_pcm_hw_params *params,
+				struct snd_soc_dai *dai);
+static int nau8824_set_dai_fmt(struct snd_soc_dai *codec_dai,
+				unsigned int fmt);
+static int nau8824_set_bias_level(struct snd_soc_codec *codec,
+				enum snd_soc_bias_level level);
+static int nau8824_set_sysclk(struct snd_soc_codec *codec, int clk_id,
+				int source, unsigned int freq, int dir);
+static const DECLARE_TLV_DB_SCALE(out_spk_vol_tlv, 0, 100, 0);
+static const DECLARE_TLV_DB_SCALE(out_hp_vol_tlv, -3000, 100, 0);
+static const DECLARE_TLV_DB_SCALE(dac_vol_tlv, -12800, 50, 0);
+static const DECLARE_TLV_DB_SCALE(in_vol_tlv, -3450, 150, 0);
+static const DECLARE_TLV_DB_SCALE(adc_vol_tlv, -12800, 50, 0);
+static const DECLARE_TLV_DB_SCALE(adc_left_vol_tlv, -12750, 50, 1);
+static const DECLARE_TLV_DB_SCALE(adc_right_vol_tlv, -12750, 50, 1);
+
+static const struct snd_kcontrol_new nau8824_snd_controls[] = {
+	/* SP Class-D mute control */
+	SOC_DOUBLE("SP Playback Switch", NAU8824_CLASS_D_GAIN1,
+				NAU8824_CLASS_D_SFT, NAU8824_CLASS_D_SFT, 1, 0),
+	/* SP Class-D driver output stage gain control */
+	SOC_SINGLE_TLV("SP Left Volume", NAU8824_CLASS_D_GAIN2,
+				NAU8824_CLASS_D_GAIN_L_SFT,
+				NAU8824_SPK_VOL_RSCL_RANGE, 0, out_spk_vol_tlv),
+	SOC_SINGLE_TLV("SP Right Volume", NAU8824_CLASS_D_GAIN1,
+				NAU8824_CLASS_D_GAIN_R_SFT,
+				NAU8824_SPK_VOL_RSCL_RANGE,	0,
+				out_spk_vol_tlv),
+	/* SP Class-D mute control */
+	SOC_DOUBLE("HP Playback Switch", NAU8824_HP_MUTE, NAU8824_L_MUTE_SFT,
+				NAU8824_R_MUTE_SFT, 1, 1),
+	SOC_SINGLE_TLV("HP Left Volume", NAU8824_HP_VOL, NAU8824_L_VOL_SFT,
+				NAU8824_VOL_RSCL_RANGE, 1, out_hp_vol_tlv),
+	SOC_SINGLE_TLV("HP Right Volume", NAU8824_HP_VOL, NAU8824_R_VOL_SFT,
+				NAU8824_VOL_RSCL_RANGE, 1, out_hp_vol_tlv),
+	/* DMIC control */
+	SOC_DOUBLE("DMIC L R Switch", NAU8824_ENA_CTRL, NAU8824_DMIC_CH0_SFT,
+				NAU8824_DMIC_CH1_SFT, 1, 0),
+	SOC_SINGLE("DMIC Enable", NAU8824_BIAS_ADJ, NAU8824_DMIC1_SFT, 1, 0),
+	SOC_SINGLE("VMID Switch", NAU8824_BIAS_ADJ, NAU8824_VMID_SFT, 1, 0),
+	SOC_SINGLE("BIAS Switch", NAU8824_BOOST, NAU8824_G_BIAS_SFT, 1, 0),
+	SOC_DOUBLE_R_TLV("MIC L R Gain", NAU8824_ADC_CH0_DGAIN_CTRL,
+				NAU8824_ADC_CH1_DGAIN_CTRL, 0,
+				NAU8824_ADC_VOL_RSCL_RANGE,	0, adc_vol_tlv),
+};
+
+static int set_dmic_clk(struct snd_soc_dapm_widget *w,
+				struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_codec *codec = w->codec;
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		snd_soc_update_bits(codec, NAU8824_CLK_DIVIDER,
+				NAU8824_CLK_DMIC_SRC_MASK,
+				NAU8824_CLK_DMIC_DIV_4);
+		break;
+	default:
+		break;
+	}
+	return 0;
+}
+
+static const struct snd_kcontrol_new nau8824_rec_l_mix[] = {
+				SOC_DAPM_SINGLE("BST1 Switch", SND_SOC_NOPM,
+				0, 0, 0),
+};
+
+static const struct snd_kcontrol_new nau8824_rec_r_mix[] = {
+				SOC_DAPM_SINGLE("BST2 Switch", SND_SOC_NOPM,
+				0, 0, 0),
+};
+
+static const struct snd_kcontrol_new nau8824_spo_mix[] = {
+				SOC_DAPM_SINGLE("SP L Switch", SND_SOC_NOPM,
+				0, 0, 0),
+				SOC_DAPM_SINGLE("SP R Switch", SND_SOC_NOPM,
+				0, 0, 0),
+};
+
+static const struct snd_kcontrol_new nau8824_hpo_mix[] = {
+				SOC_DAPM_SINGLE("HP L Switch",
+				NAU8824_HPO_MIXER, NAU8824_M_HPVOL_L_HM_SFT,
+				1, 0),
+				SOC_DAPM_SINGLE("HP R Switch",
+				NAU8824_HPO_MIXER, NAU8824_M_HPVOL_R_HM_SFT,
+				1, 0),
+};
+
+static const char * const nau8824_stereo_adc1_src[] = { "ADC", "DMIC" };
+
+static const SOC_ENUM_SINGLE_DECL(nau8824_stereo_adc_l1_enum, NAU8824_ENA_CTRL,
+				NAU8824_DMIC_CH0_SFT, nau8824_stereo_adc1_src);
+
+static const SOC_ENUM_SINGLE_DECL(nau8824_stereo_adc_r1_enum, NAU8824_ENA_CTRL,
+				NAU8824_DMIC_CH1_SFT, nau8824_stereo_adc1_src);
+
+static const struct snd_kcontrol_new nau8824_sto_adc_l1_mux =
+				SOC_DAPM_ENUM("Stereo ADC L1 source",
+				nau8824_stereo_adc_l1_enum);
+
+static const struct snd_kcontrol_new nau8824_sto_adc_r1_mux =
+				SOC_DAPM_ENUM("Stereo ADC R1 source",
+				nau8824_stereo_adc_r1_enum);
+
+static int nau8824_spk_event(struct snd_soc_dapm_widget *w,
+			    struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_codec *codec = w->codec;
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		snd_soc_update_bits(codec, NAU8824_ANALOG_CTRL2,
+				NAU8824_CLASS_D_CLAMP_MSK,
+				NAU8824_CLASS_D_CLAMP_BETTER);
+		break;
+	case SND_SOC_DAPM_PRE_PMD:
+		snd_soc_update_bits(codec, NAU8824_CLASS_D_GAIN1,
+				NAU8824_CLASS_D_MASK, NAU8824_CLASS_D_DIS);
+	default:
+		break;
+	}
+	return 0;
+}
+
+static int nau8824_hp_event(struct snd_soc_dapm_widget *w,
+				struct snd_kcontrol *kcontrol, int event)
+{
+	return 0;
+}
+
+static int nau8824_dac1_event(struct snd_soc_dapm_widget *w,
+				struct snd_kcontrol *kcontrol, int event)
+{
+	return 0;
+}
+
+static int micbias_power_on_event(struct snd_soc_dapm_widget *w,
+				struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_codec *codec = w->codec;
+
+	if (SND_SOC_DAPM_EVENT_ON(event))
+		snd_soc_update_bits(codec, NAU8824_BOOST, NAU8824_G_BIAS_MASK,
+				NAU8824_G_BIAS_EN);
+	else if (SND_SOC_DAPM_EVENT_OFF(event))
+		snd_soc_update_bits(codec, NAU8824_BOOST, NAU8824_G_BIAS_MASK,
+				NAU8824_G_BIAS_DIS);
+	return 0;
+}
+
+static int vmid_power_on_event(struct snd_soc_dapm_widget *w,
+				struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_codec *codec = w->codec;
+
+	if (SND_SOC_DAPM_EVENT_ON(event))
+		snd_soc_update_bits(codec, NAU8824_BIAS_ADJ,
+				NAU8824_VMID_MASK, NAU8824_VMID_EN);
+	else if (SND_SOC_DAPM_EVENT_OFF(event))
+		snd_soc_update_bits(codec, NAU8824_BIAS_ADJ,
+				NAU8824_VMID_MASK, NAU8824_VMID_DIS);
+	return 0;
+}
+
+static const struct snd_soc_dapm_widget nau8824_dapm_widgets[] = {
+
+	SND_SOC_DAPM_INPUT("DMIC1"),
+	SND_SOC_DAPM_INPUT("IN1P"),
+	SND_SOC_DAPM_INPUT("IN1N"),
+	SND_SOC_DAPM_INPUT("IN2P"),
+	SND_SOC_DAPM_INPUT("IN2N"),
+
+	SND_SOC_DAPM_SUPPLY("micbias", SND_SOC_NOPM, 0, 0,
+				micbias_power_on_event, SND_SOC_DAPM_PRE_PMU
+				| SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_SUPPLY("vmid", SND_SOC_NOPM, 0, 0, vmid_power_on_event,
+				SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_PGA("DMIC L1", NAU8824_ENA_CTRL, NAU8824_DMIC_CH0_SFT,
+				0, NULL, 0),
+	SND_SOC_DAPM_PGA("DMIC R1", NAU8824_ENA_CTRL, NAU8824_DMIC_CH1_SFT,
+				0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("DMIC CLK", SND_SOC_NOPM, 0, 0, set_dmic_clk,
+				SND_SOC_DAPM_PRE_PMU),
+
+	/* REC Mixer */
+	SND_SOC_DAPM_MIXER("RECMIXL", SND_SOC_NOPM, 0, 0, nau8824_rec_l_mix,
+				ARRAY_SIZE(nau8824_rec_l_mix)),
+	SND_SOC_DAPM_MIXER("RECMIXR", SND_SOC_NOPM, 0, 0, nau8824_rec_r_mix,
+				ARRAY_SIZE(nau8824_rec_r_mix)),
+
+	/* ADCs */
+	SND_SOC_DAPM_ADC("ADC L", NULL, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_ADC("ADC R", NULL, SND_SOC_NOPM, 0, 0),
+
+	/* ADC Mux */
+	SND_SOC_DAPM_MUX("Stereo ADC L1 Mux", SND_SOC_NOPM, 0, 0,
+				&nau8824_sto_adc_l1_mux),
+	SND_SOC_DAPM_MUX("Stereo ADC R1 Mux", SND_SOC_NOPM, 0, 0,
+				&nau8824_sto_adc_r1_mux),
+	/* ADC IF1  */
+	SND_SOC_DAPM_PGA("IF1 ADC", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+	/* Audio Interface */
+	SND_SOC_DAPM_AIF_IN("AIF1RX", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("AIF1TX", "AIF1 Capture", 0, SND_SOC_NOPM, 0, 0),
+
+	/* DACs */
+	SND_SOC_DAPM_DAC_E("DAC L1", NULL, NAU8824_DAC_CTRL,
+				NAU8824_DAC_L_SFT, 0, nau8824_dac1_event,
+				SND_SOC_DAPM_PRE_PMD),
+	SND_SOC_DAPM_DAC_E("DAC R1", NULL, NAU8824_DAC_CTRL,
+				NAU8824_DAC_R_SFT, 0, nau8824_dac1_event,
+				SND_SOC_DAPM_PRE_PMD),
+
+	/* SPO/HPO/LOUT/Mono Mixer */
+	SND_SOC_DAPM_MIXER("SPO MIX", SND_SOC_NOPM, 0, 0, nau8824_spo_mix,
+				ARRAY_SIZE(nau8824_spo_mix)),
+	SND_SOC_DAPM_MIXER("HPO MIX", SND_SOC_NOPM, 0, 0, nau8824_hpo_mix,
+				ARRAY_SIZE(nau8824_hpo_mix)),
+
+	SND_SOC_DAPM_PGA_S("HP amp", 1, NAU8824_CLASS_G_CTRL,
+	NAU8824_CLASS_G_SHIFT, 0, nau8824_hp_event,
+				SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+	SND_SOC_DAPM_PGA_S("SPK amp", 1, NAU8824_CLASS_D_GAIN1,
+				NAU8824_CLASS_D_SFT, 0, nau8824_spk_event,
+				SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+
+	/* Output Lines */
+	SND_SOC_DAPM_OUTPUT("SPK"),
+	SND_SOC_DAPM_OUTPUT("HPOL"),
+	SND_SOC_DAPM_OUTPUT("HPOR"),
+};
+
+static const struct snd_soc_dapm_route nau8824_dapm_routes[] = {
+
+	{"DMIC L1", NULL, "DMIC1"},
+	{"DMIC R1", NULL, "DMIC1"},
+
+	{"BST1", NULL, "IN1P"},
+	{"BST1", NULL, "IN1N"},
+	{"BST2", NULL, "IN2P"},
+	{"BST2", NULL, "IN2N"},
+	{"IN2P", NULL, "micbias"},
+	{"IN2P", NULL, "vmid"},
+
+	{"RECMIXL", "BST1 Switch", "BST1"},
+	{"RECMIXR", "BST2 Switch", "BST2"},
+
+	{"ADC L", NULL, "RECMIXL"},
+	{"ADC R", NULL, "RECMIXR"},
+	{"DMIC L1", NULL, "DMIC CLK"},
+	{"DMIC R1", NULL, "DMIC CLK"},
+
+	{"Stereo ADC L1 Mux", "ADC", "ADC L"},
+	{"Stereo ADC L1 Mux", "DMIC", "DMIC L1"},
+	{"Stereo ADC R1 Mux", "ADC", "ADC R"},
+	{"Stereo ADC R1 Mux", "DMIC", "DMIC R1"},
+	{"AIF1TX", NULL, "IF1 ADC"},
+
+	{"DAC L1", NULL, "AIF1RX"},
+	{"DAC R1", NULL, "AIF1RX"},
+	{"SPO MIX", "SP L Switch", "DAC L1"},
+	{"SPO MIX", "SP R Switch", "DAC R1"},
+	{"SPK amp", NULL, "SPO MIX"},
+	{"SPK", NULL, "SPK amp"},
+
+	{"HPO MIX", "HP L Switch", "DAC L1"},
+	{"HPO MIX", "HP R Switch", "DAC R1"},
+	{"HP amp", NULL, "HPO MIX"},
+	{"HPOL", NULL, "HP amp"},
+	{"HPOR", NULL, "HP amp"},
+};
+
+static int nau8824_hw_params(struct snd_pcm_substream *substream,
+				struct snd_pcm_hw_params *params,
+				struct snd_soc_dai *tmp)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_codec *codec = rtd->codec;
+	unsigned int val_len = 0;
+
+	dev_dbg(codec->dev, "%s\n", __func__);
+	dev_dbg(codec->dev, "##- Data length: %d\n", params_format(params));
+
+	switch (params_format(params)) {
+	case SNDRV_PCM_FORMAT_S16_LE:
+		break;
+	case SNDRV_PCM_FORMAT_S20_3LE:
+		val_len |= NAU8824_I2S_DL_20;
+		break;
+	case SNDRV_PCM_FORMAT_S24_LE:
+		val_len |= NAU8824_I2S_DL_24;
+		break;
+	case SNDRV_PCM_FORMAT_S8:
+	case SNDRV_PCM_FORMAT_S32_LE:
+		val_len |= NAU8824_I2S_DL_32;
+		break;
+	default:
+		return -EINVAL;
+	}
+	snd_soc_update_bits(codec, NAU8824_I2S_PCM_CTRL_1, NAU8824_I2S_DL_MASK,
+				val_len);
+	return 0;
+}
+
+static int nau8824_dac_mute(struct snd_soc_dai *codec_dai, int mute)
+{
+	struct snd_soc_codec *codec = codec_dai->codec;
+
+	if (mute)
+		snd_soc_update_bits(codec, NAU8824_DAC_MUTE_CTRL,
+				NAU8824_SOFT_MUTE_MASK, NAU8824_SOFT_MUTE_EN);
+	else
+		snd_soc_update_bits(codec, NAU8824_DAC_MUTE_CTRL,
+				NAU8824_SOFT_MUTE_MASK, NAU8824_SOFT_MUTE_DIS);
+	return 0;
+}
+
+static int nau8824_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
+{
+	struct snd_soc_codec *codec = codec_dai->codec;
+	unsigned int reg_val = 0, reg_val_2 = 0;
+
+	dev_dbg(codec->dev, "%s: Entered\n", __func__);
+	dev_dbg(codec->dev, "###nau8824_set_dai_fmt %x\n", fmt);
+	dev_dbg(codec->dev, "##+ nau8824_set_dai_fmt (%x)\n", fmt);
+
+	/* set master/slave audio interface */
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBM_CFM:
+		reg_val_2 |= NAU8824_I2S_MS_M;
+		break;
+	case SND_SOC_DAIFMT_CBS_CFS:
+		break;
+	case SND_SOC_DAIFMT_CBS_CFM:
+		break;
+	default:
+		dev_alert(codec->dev, "Invalid DAI master/slave interface\n");
+		return -EINVAL;
+	}
+
+	/* interface format */
+	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+	case SND_SOC_DAIFMT_NB_NF:
+		break;
+	case SND_SOC_DAIFMT_IB_NF:
+		reg_val |= NAU8824_I2S_BP_INV;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		reg_val |= NAU8824_I2S_DF_I2S;
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		reg_val |= NAU8824_I2S_DF_LEFT;
+		break;
+	case SND_SOC_DAIFMT_RIGHT_J:
+		reg_val |= NAU8824_I2S_DF_RIGHT;
+		break;
+	case SND_SOC_DAIFMT_DSP_A:
+		reg_val |= NAU8824_I2S_DF_PCM_A;
+		break;
+	case SND_SOC_DAIFMT_DSP_B:
+		reg_val |= NAU8824_I2S_DF_PCM_B;
+		reg_val |= NAU8824_I2S_PCMB_EN;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	snd_soc_update_bits(codec, NAU8824_I2S_PCM_CTRL_1,
+				NAU8824_I2S_DL_MASK | NAU8824_I2S_DF_MASK
+				| NAU8824_I2S_BP_MASK | NAU8824_I2S_PCMB_MASK,
+				reg_val);
+	snd_soc_update_bits(codec, NAU8824_I2S_PCM_CTRL_2, NAU8824_I2S_MS_MASK,
+				reg_val_2);
+
+	dev_dbg(codec->dev, "##-nau8824_set_dai_fmt Master\n");
+	dev_dbg(codec->dev, "%s: Exiting\n", __func__);
+	return 0;
+}
+
+static int nau8824_FLL_freerun_mode(struct snd_soc_codec *codec, int IsEnable)
+{
+	if (IsEnable == true) {
+		snd_soc_write(codec, 0x03, 0x0853);
+		snd_soc_write(codec, 0x09, 0xE000);
+		snd_soc_write(codec, 0x03, 0x8853);
+	} else {
+		snd_soc_write(codec, 0x03, 0x0853);
+		snd_soc_write(codec, 0x09, 0x6000);
+		snd_soc_write(codec, 0x03, 0x8853);
+	}
+	return 0;
+}
+
+void set_sys_clk(struct snd_soc_codec *codec, int sys_clk)
+{
+	pr_debug("%s sys_clk=%x\n", __func__, sys_clk);
+	switch (sys_clk) {
+	case NAU8824_INTERNALCLOCK:
+		nau8824_FLL_freerun_mode(codec, true);
+		break;
+
+	case NAU8824_MCLK:
+	default:
+		nau8824_FLL_freerun_mode(codec, false);
+		break;
+	}
+}
+
+static int nau8824_set_dai_pll(struct snd_soc_dai *dai,
+		int pll_id, int source, unsigned int freq_in,
+		unsigned int freq_out)
+{
+	struct snd_soc_codec *codec = dai->codec;
+
+	dev_dbg(codec->dev, "In nau8824: dai_set_pll\n");
+	return 0;
+}
+
+static int nau8824_set_sysclk(struct snd_soc_codec *codec,
+		int clk_id, int source, unsigned int freq, int dir)
+{
+	int divider = 1;
+
+	if (clk_id == NAU8824_MCLK) {
+		set_sys_clk(codec, NAU8824_MCLK);
+		dev_dbg(codec->dev, "%s: input freq = %d divider = %d",
+		__func__, freq, divider);
+
+	} else if (clk_id == NAU8824_INTERNALCLOCK) {
+		set_sys_clk(codec, NAU8824_INTERNALCLOCK);
+	} else {
+		dev_err(codec->dev, "Wrong clock src\n");
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int nau8824_set_bias_level(struct snd_soc_codec *codec,
+				enum snd_soc_bias_level level)
+{
+	dev_dbg(codec->dev, "## nau8824_set_bias_level %d\n", level);
+	if (level == codec->dapm.bias_level) {
+		dev_dbg(codec->dev, "##set_bias_level: level returning...\r\n");
+		return -EINVAL;
+	}
+
+	switch (level) {
+	case SND_SOC_BIAS_ON:
+		/* All power is driven by DAPM system*/
+		dev_dbg(codec->dev, "###nau8824_set_bias_level BIAS_ON\n");
+		snd_soc_update_bits(codec, NAU8824_BIAS_ADJ,
+			NAU8824_VMID_MASK, NAU8824_VMID_EN);
+		snd_soc_update_bits(codec, NAU8824_BOOST,
+				NAU8824_G_BIAS_MASK, NAU8824_G_BIAS_EN);
+		break;
+
+	case SND_SOC_BIAS_PREPARE:
+		dev_dbg(codec->dev, "###nau8824_set_bias_level BIAS_PREPARE\n");
+		break;
+
+	case SND_SOC_BIAS_STANDBY:
+		dev_dbg(codec->dev, "###nau8824_set_bias_level STANDBY\n");
+		break;
+
+	case SND_SOC_BIAS_OFF:
+		dev_dbg(codec->dev, "###nau8824_set_bias_level OFF\n");
+		set_sys_clk(codec, NAU8824_INTERNALCLOCK);
+		snd_soc_update_bits(codec, NAU8824_BIAS_ADJ, NAU8824_VMID_MASK,
+				NAU8824_VMID_DIS);
+		snd_soc_update_bits(codec, NAU8824_BOOST,
+				NAU8824_G_BIAS_MASK, NAU8824_G_BIAS_DIS);
+		break;
+	default:
+		break;
+	}
+	codec->dapm.bias_level = level;
+	dev_dbg(codec->dev, "## nau8824_set_bias_level %d\n", level);
+
+	return 0;
+}
+
+static int nau8824_suspend(struct snd_soc_codec *codec)
+{
+	dev_dbg(codec->dev, "%s: Entered\n", __func__);
+	nau8824_set_bias_level(codec, SND_SOC_BIAS_OFF);
+	dev_dbg(codec->dev, "%s: Exiting\n", __func__);
+	return 0;
+}
+
+static int nau8824_resume(struct snd_soc_codec *codec)
+{
+	dev_dbg(codec->dev, "%s: Entered\n", __func__);
+	nau8824_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+	dev_dbg(codec->dev, "%s: Exiting\n", __func__);
+	return 0;
+}
+
+struct nau8824_init_reg {
+	u8 reg;
+	u16 val;
+};
+
+static struct nau8824_init_reg init_list[] = {
+	{0x0000, 0x0001},
+	{0x0000, 0x0000},
+	{0x0066, 0x0060},
+	{0x0076, 0x3000},
+	{0x0004, 0x0002},
+	{0x0005, 0xDD44},
+	{0x0006, 0x0007},
+	{0x0007, 0x0810},
+	{0x0008, 0xC000},
+	{0x0074, 0x1106},
+	{0x0073, 0x330C},
+	{0x0080, 0x0000},
+	{0x006D, 0x0100},
+	{0x006E, 0x0001},
+	{0x006A, 0x0008},
+	{0x006D, 0x0180},
+	{0x006D, 0x1480},
+	{0x006E, 0x0014},
+	{0x0050, 0x2007},
+	{0x0080, 0x3020},
+	{0x006B, 0xC000},
+	{0x007B, 0x1E1E},
+	{0x006B, 0xC005},
+	{0x0068, 0x8000},
+	{0x0076, 0x300F},
+	{0x007F, 0x000F},
+	{0x0080, 0x0020},
+	{0x006B, 0x0005},
+	{0x007B, 0x0000},
+	{0x0002, 0x0800},
+	{0x0025, 0x1000},
+	{0x0024, 0x0002},
+	{0x0002, 0x0AA5},
+	{0x0020, 0x0000},
+	{0x0025, 0x1082},
+	{0x0031, 0x0800},
+	{0x0032, 0x0100},
+	{0x0033, 0x0300},
+	{0x0034, 0x0000},
+	{0x001C, 0x000A},
+	{0x001F, 0x2000},
+	{0x0001, 0x0030},
+	{0x0002, 0x3AA5},
+	{0x0067, 0x4040},
+	{0x007F, 0x300F},
+	{0x0077, 0x0010},
+	{0x0078, 0x3C00},
+	{0x0076, 0x380F},
+	{0x0076, 0x300F},
+	{0x007A, 0x0202},
+	{0x0067, 0x0000},
+	{0x0072, 0x40A0},
+	{0x0079, 0x0300},
+	{0x0023, 0x1010},
+	{0x0024, 0x0002},
+	{0x0038, 0x1486},
+	{0x003C, 0x1486},
+	{0x0066, 0x0064},
+	{0x0001, 0x40F0},
+	{0x0001, 0x48F0},
+	{0x0025, 0x3082},
+	{0x0020, 0x0003},
+	{0x0024, 0x8102},
+	{0x002D, 0x0108},
+	{0x002E, 0x0308},
+	{0x002F, 0x0500},
+	{0x0030, 0x0700},
+	{0x001C, 0x000A},
+	{0x001F, 0x2000},
+	{0x0002, 0x3BA5},
+	{0x0001, 0x48F3},
+	{0x0002, 0xFBA5},
+	{0x0014, 0x2210},
+	{0x007c, 0x1e1e},
+};
+
+#define NAU8824_INIT_REG_LEN ARRAY_SIZE(init_list)
+static int nau8824_reg_init(struct snd_soc_codec *codec)
+{
+	int i;
+
+	mdelay(1);
+	for (i = 0; i < NAU8824_INIT_REG_LEN; i++) {
+		if (init_list[i].reg == 0xFFFF)
+			mdelay(1);
+		else
+			snd_soc_write(codec, init_list[i].reg,
+			init_list[i].val);
+	}
+	return 0;
+}
+
+static int nau8824_codec_probe(struct snd_soc_codec *codec)
+{
+	int ret = 0;
+	struct nau8824_priv *nau8824;
+
+	nau8824 = snd_soc_codec_get_drvdata(codec);
+	codec->control_data = nau8824->regmap;
+	mutex_init(&nau8824->mutex);
+	nau8824_reg_init(codec);
+
+	/* Dynamic Headset detection enabled */
+	snd_soc_update_bits(codec, 0x01, 0x400, 0x400);
+	snd_soc_update_bits(codec, 0x02, 0x0008, 0x0008);
+	snd_soc_update_bits(codec, 0x0f, 0x0300, 0x0100);
+	snd_soc_write(codec, 0x09, 0xE000);
+	snd_soc_write(codec, NAU8824_IRQ_SETTING, 0x1006);
+	snd_soc_write(codec, 0x13, 0x1615);
+	snd_soc_write(codec, 0x15, 0x0414);
+	snd_soc_update_bits(codec, 0x16, 0xFF00, 0x5900);
+	snd_soc_update_bits(codec, 0x66, 0x0070, 0x0060);
+
+	/* Program codec to use internal clock */
+	nau8824_FLL_freerun_mode(codec, true);
+	return ret;
+}
+
+static int nau8824_codec_remove(struct snd_soc_codec *codec)
+{
+	nau8824_set_bias_level(codec, SND_SOC_BIAS_OFF);
+	return 0;
+}
+
+static struct snd_soc_codec_driver soc_codec_driver_nau8824 = {
+	.probe			= nau8824_codec_probe,
+	.remove			= nau8824_codec_remove,
+	.suspend		= nau8824_suspend,
+	.resume			= nau8824_resume,
+	.set_bias_level		= nau8824_set_bias_level,
+	.controls		= nau8824_snd_controls,
+	.num_controls		= ARRAY_SIZE(nau8824_snd_controls),
+	.dapm_widgets		= nau8824_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(nau8824_dapm_widgets),
+	.dapm_routes		= nau8824_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(nau8824_dapm_routes),
+	.reg_word_size		= sizeof(u16),
+	.reg_cache_default	= init_list,
+	.set_sysclk		= nau8824_set_sysclk,
+};
+
+static struct snd_soc_dai_ops nau8824_dai_ops = {
+	.hw_params	= nau8824_hw_params,
+	.set_pll	= nau8824_set_dai_pll,
+	.set_fmt	= nau8824_set_dai_fmt,
+	.digital_mute	= nau8824_dac_mute,
+};
+
+static struct snd_soc_dai_driver nau8824_dai_driver[] = {
+{
+	.name = "nau8824-aif1",
+		.playback = {
+			.stream_name	 = "AIF1 Playback",
+			.channels_min	 = 1,
+			.channels_max	 = 2,
+			.rates		 = NAU8824_RATES,
+			.formats	 = NAU8824_FORMATS,
+		},
+		.capture = {
+			.stream_name	 = "AIF1 Capture",
+			.channels_min	 = 1,
+			.channels_max	 = 2,
+			.rates		 = NAU8824_RATES,
+			.formats	 = NAU8824_FORMATS,
+		},
+	.ops = &nau8824_dai_ops,
+}
+};
+
+static int nau8824_i2c_probe(struct i2c_client *i2c,
+					const struct i2c_device_id *id)
+{
+	struct nau8824_priv *nau8824;
+	int ret;
+
+	pr_debug("%s enter", __func__);
+	nau8824 = kzalloc(sizeof(*nau8824), GFP_KERNEL);
+	if (nau8824 == NULL)
+		return -ENOMEM;
+
+	i2c_set_clientdata(i2c, nau8824);
+	ret = snd_soc_register_codec(&i2c->dev, &soc_codec_driver_nau8824,
+				nau8824_dai_driver,
+				ARRAY_SIZE(nau8824_dai_driver));
+	if (ret < 0)
+		kfree(nau8824);
+
+	return ret;
+}
+
+static int nau8824_i2c_remove(struct i2c_client *i2c)
+{
+	struct nau8824_priv *nau8824 = dev_get_drvdata(&i2c->dev);
+
+	snd_soc_unregister_codec(nau8824->dev);
+
+	return 0;
+}
+
+static const struct i2c_device_id nau8824_i2c_id[] = {
+	{ "nau8824", 0},
+	{"10508824:00", 0},
+	{"10508824", 0},
+	{ }
+};
+
+MODULE_DEVICE_TABLE(i2c, nau8824_i2c_id);
+static struct i2c_driver nau8824_i2c_driver = {
+	.driver = {
+		.name	= "nau8824",
+		.owner	= THIS_MODULE,
+	},
+	.probe		= nau8824_i2c_probe,
+	.remove		= (nau8824_i2c_remove),
+	.id_table	= nau8824_i2c_id,
+};
+module_i2c_driver(nau8824_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC NAU8824 codec driver");
+MODULE_AUTHOR("Nuvoton");
+MODULE_LICENSE("GPL");
+
diff --git a/sound/soc/codecs/nau8824.h b/sound/soc/codecs/nau8824.h
new file mode 100644
index 0000000..1745dac
--- /dev/null
+++ b/sound/soc/codecs/nau8824.h
@@ -0,0 +1,379 @@
+/*
+ * linux/sound/soc/codecs/nau8824.h
+ *
+ * Copyright 2015 Nuvoton Technology Corp.
+ * Author: Meng-Huang Kuo <mhkuo at nuvoton.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _NAU8824_H
+#define _NAU8824_H
+
+#define NAU8824_RESET						0x00
+#define NAU8824_ENA_CTRL					0x01
+#define NAU8824_CLK_EN						0x02
+#define NAU8824_CLK_DIVIDER					0x03
+#define NAU8824_FL_1						0x04
+#define NAU8824_FL_2						0x05
+#define NAU8824_FL_3						0x06
+#define NAU8824_FL_4						0x07
+#define NAU8824_FL_5						0x08
+#define NAU8824_FL_6						0x09
+#define NAU8824_IRQ_STATUS					0x10
+#define NAU8824_IRQ_CLEAR					0x11
+#define NAU8824_IRQ_SETTING					0x12
+#define NAU8824_SAR_ADC						0x13
+#define NAU8824_VDET_COEFFICIENT			0x14
+#define NAU8824_I2S_PCM_CTRL_1				0x1C
+#define NAU8824_I2S_PCM_CTRL_2				0x1D
+#define NAU8824_ADC_CH0_DGAIN_CTRL			0x2D
+#define NAU8824_ADC_CH1_DGAIN_CTRL			0x2E
+#define NAU8824_DAC_MUTE_CTRL				0x31
+#define NAU8824_DAC0_DIG_VOL				0x32
+#define NAU8824_DAC1_DIG_VOL				0x33
+#define NAU8824_CLASS_G_CTRL				0x50
+#define NAU8824_SAR_ADC_OUTPUT				0x59
+#define NAU8824_BIAS_ADJ					0x66
+#define NAU8824_ANALOG_CTRL2				0x6A
+#define NAU8824_HPO_MIXER					0x6B
+#define NAU8824_CLASS_D_GAIN1				0x6D
+#define NAU8824_CLASS_D_GAIN2				0x6E
+#define NAU8824_DAC_CTRL					0x73
+#define NAU8824_MIC_BIAS					0x74
+#define NAU8824_HP_MUTE						0x75
+#define NAU8824_BOOST						0x76
+#define	NAU8824_HP_VOL						0x7B
+
+/* reg. NAU8824_ENA_CTRL (0x01) */
+#define NAU8824_DMIC_EDGE_CH23_MASK			(0x01 << 15)
+#define NAU8824_DMIC_EDGE_CH23_SFT			15
+#define NAU8824_DMIC_EDGE_CH01_MASK			(0x01 << 14)
+#define NAU8824_DMIC_EDGE_CH01_SFT			14
+#define NAU8824_ADC_OP_EN_MASK				(0x01 << 11)
+#define NAU8824_ADC_OP_EN_SFT				11
+#define NAU8824_ADC_OP_EN					(0x01 << 11)
+#define NAU8824_ADC_OP_DIS					(0x00 << 11)
+#define NAU8824_INT_SLEEP_MASK				(0x01 << 10)
+#define NAU8824_INT_SLEEP_SFT				10
+#define NAU8824_INT_SLEEP_ON				(0x01 << 10)
+#define NAU8824_INT_SLEEP_OFF				(0x00 << 10)
+#define NAU8824_DMIC_CH3_MASK				(0x01 << 9)
+#define NAU8824_DMIC_CH3_SFT				9
+#define NAU8824_DMIC_CH3_ON					(0x01 << 9)
+#define NAU8824_DMIC_CH3_OFF				(0x00 << 9)
+#define NAU8824_DMIC_CH2_MASK				(0x01 << 8)
+#define NAU8824_DMIC_CH2_SFT				8
+#define NAU8824_DMIC_CH2_ON					(0x01 << 8)
+#define NAU8824_DMIC_CH2_OFF				(0x00 << 8)
+#define NAU8824_DMIC_CH1_MASK				(0x01 << 7)
+#define NAU8824_DMIC_CH1_SFT				7
+#define NAU8824_DMIC_CH1_ON					(0x01 << 7)
+#define NAU8824_DMIC_CH1_OFF				(0x00 << 7)
+#define NAU8824_DMIC_CH0_MASK				(0x01 << 6)
+#define NAU8824_DMIC_CH0_SFT				6
+#define NAU8824_DMIC_CH0_ON					(0x01 << 6)
+#define NAU8824_DMIC_CH0_OFF				(0x00 << 6)
+#define NAU8824_DAC_CH1_EN_MASK				(0x01 << 5)
+#define NAU8824_DAC_CH1_EN_SFT				5
+#define NAU8824_DAC_CH1_EN					(0x01 << 5)
+#define NAU8824_DAC_CH1_DIS					(0x00 << 5)
+#define NAU8824_DAC_CH0_EN_MASK				(0x01 << 4)
+#define NAU8824_DAC_CH0_EN_SFT				4
+#define NAU8824_DAC_CH0_EN					(0x01 << 4)
+#define NAU8824_DAC_CH0_DIS					(0x00 << 4)
+#define NAU8824_ADC_CH3_EN_MASK				(0x01 << 3)
+#define NAU8824_ADC_CH3_EN_SFT				3
+#define NAU8824_ADC_CH3_EN					(0x01 << 3)
+#define NAU8824_ADC_CH3_DIS					(0x00 << 3)
+#define NAU8824_ADC_CH2_EN_MASK				(0x01 << 2)
+#define NAU8824_ADC_CH2_EN_SFT				2
+#define NAU8824_ADC_CH2_EN					(0x01 << 2)
+#define NAU8824_ADC_CH2_DIS					(0x00 << 2)
+#define NAU8824_ADC_CH1_EN_MASK				(0x01 << 1)
+#define NAU8824_ADC_CH1_EN_SFT				1
+#define NAU8824_ADC_CH1_EN					(0x01 << 1)
+#define NAU8824_ADC_CH1_DIS					(0x00 << 1)
+#define NAU8824_ADC_CH0_EN_MASK				(0x01 << 0)
+#define NAU8824_ADC_CH0_EN_SFT				0
+#define NAU8824_ADC_CH0_EN					(0x01 << 0)
+#define NAU8824_ADC_CH0_DIS					(0x00 << 0)
+
+/* reg. NAU8824_CLK_EN (0x02) */
+#define NAU8824_CLK_SAR_EN_MASK				(0x1 << 3)
+#define NAU8824_CLK_SAR_EN_SFT				3
+#define NAU8824_CLK_SAR_EN					(0x1 << 3)
+#define NAU8824_CLK_SAR_DIS					(0x0 << 3)
+
+/* reg. NAU8824_CLK_DIVIDER (0x03) */
+#define NAU8824_SYSCLK_SRC_MASK				(0x1 << 15)
+#define NAU8824_SYSCLK_SRC_SFT				15
+#define NAU8824_SYSCLK_SRC_VCO				(0x1 << 15)
+#define NAU8824_SYSCLK_SRC_MCLK				(0x0 << 15)
+#define NAU8824_CLK_CODEC_SRC_MASK			(0x1 << 13)
+#define NAU8824_CLK_CODEC_SRC_SFT			13
+#define NAU8824_CODEC_SRC_SYSCLK			(0x1 << 13)
+#define NAU8824_CODEC_SRC_MCLK				(0x0 << 13)
+#define NAU8824_CLK_DMIC_SRC_MASK			(0x7 << 10)
+#define NAU8824_CLK_DMIC_SRC_SFT			10
+#define NAU8824_CLK_DMIC_DIV_4				(0x2 << 10)
+
+/* reg. NAU8824_IRQ_STATUS (0x10) */
+#define NAU8824_IRQ_KEY_RELEASE				(0x1 << 5)
+#define NAU8824_IRQ_LONGKEY					(0x1 << 4)
+#define NAU8824_IRQ_SHORTKEY				(0x1 << 3)
+#define NAU8824_IRQ_MIC_INSERTED			(0x1 << 2)
+#define NAU8824_IRQ_JACK_EJECTED			(0x1 << 1)
+#define NAU8824_IRQ_JACK_INSERTED			(0x1 << 0)
+
+/* reg. NAU8824_IRQ_CLEAR (0x11) */
+#define NAU8824_IRQ_KEY_RELEASE_CLR			(0x1 << 5)
+#define NAU8824_IRQ_LONGKEY_CLR				(0x1 << 4)
+#define NAU8824_IRQ_SHORTKEY_CLR			(0x1 << 3)
+#define NAU8824_IRQ_MIC_INSERTED_CLR		(0x1 << 2)
+#define NAU8824_IRQ_JACK_EJECTED_CLR		(0x1 << 1)
+#define NAU8824_IRQ_JACK_INSERTED_CLR		(0x1 << 0)
+
+/* reg NAU8824_SAR_ADC (0x13) */
+#define NAU8824_SAR_EN_MASK					(0x1 << 12)
+#define NAU8824_SAR_EN_SFT					12
+#define NAU8824_SAR_EN						(0x1 << 12)
+#define NAU8824_SAR_DIS						(0x0 << 12)
+
+/* reg. NAU8824_I2S_PCM_CTRL_1 (0x1C) */
+#define NAU8824_I2S_BP_MASK					(0x1 << 7)
+#define NAU8824_I2S_BP_SFT					7
+#define NAU8824_I2S_BP_NOR					(0x0 << 7)
+#define NAU8824_I2S_BP_INV					(0x1 << 7)
+#define NAU8824_I2S_PCMB_MASK				(0x1 << 6)
+#define NAU8824_I2S_PCMB_SFT				6
+#define NAU8824_I2S_PCMB_EN					(0x1 << 6)
+#define NAU8824_I2S_PCMB_DIS				(0x0 << 6)
+#define NAU8824_I2S_DL_MASK					(0x3 << 2)
+#define NAU8824_I2S_DL_SFT					2
+#define NAU8824_I2S_DF_MASK					(0x3)
+#define NAU8824_I2S_DF_SFT					0
+#define NAU8824_I2S_DF_RIGHT				(0x0)
+#define NAU8824_I2S_DF_LEFT					(0x1)
+#define NAU8824_I2S_DF_I2S					(0x2)
+#define NAU8824_I2S_DF_PCM_A				(0x3)
+#define NAU8824_I2S_DF_PCM_B				(0x3)
+
+/* reg. NAU8824_I2S_PCM_CTRL_2 (0x1D) */
+#define NAU8824_I2S_BCLKDIV_MASK			7
+#define NAU8824_I2S_BCLKDIV_SFT				0
+
+#define NAU8824_I2S_MS_MASK					(0x1 << 3)
+#define NAU8824_I2S_MS_SFT					3
+#define NAU8824_I2S_MS_M					(0x1 << 3)
+#define NAU8824_I2S_MS_S					(0x0 << 3)
+
+/* reg. NAU8824_DAC_MUTE_CTRL (0x31) */
+#define NAU8824_SOFT_MUTE_MASK				(0x1 << 13)
+#define NAU8824_SOFT_MUTE_SFT				13
+#define NAU8824_SOFT_MUTE_EN				(0x1 << 13)
+#define NAU8824_SOFT_MUTE_DIS				(0x0 << 13)
+
+/* reg NAU8824_DAC0_DIG_VOL (0x32) */
+#define NAU8824_DAC0_GAIN_MASK				(0x1FF << 0)
+
+/* reg NAU8824_DAC1_DIG_VOL (0x33) */
+#define NAU8824_DAC1_GAIN_MASK				(0x1FF << 0)
+
+/* reg. NAU8824_CLASS_G_CTRL (0x50) */
+#define NAU8824_CLASS_G_CLK_SRC_MSK			(0x3 << 14)
+#define NAU8824_CLASS_G_CLK_DIS				(0x3 << 14)
+#define NAU8824_CLASS_G_CLK_SRC_MCLK		(0x2 << 14)
+#define NAU8824_CLASS_G_CLK_SRC_660K		(0x1 << 14)
+#define NAU8824_CLASS_G_CLK_SRC_2M			(0x0 << 14)
+#define NAU8824_CLASS_G_TIMER_MSK			(0x3F << 8)
+#define NAU8824_CLASS_G_TIMER_SFT			8
+#define NAU8824_CLASS_G_THRSLD_MSK			(0x3 << 4)
+#define NAU8824_CLASS_G_THRSLD_SFT			4
+#define NAU8824_CLASS_G_RIGHT_EN_MSK		(0x1 << 2)
+#define NAU8824_CLASS_G_RIGHT_EN			(0x1 << 2)
+#define	NAU8824_CLASS_G_RIGHT_DIS			(0x0 << 2)
+#define NAU8824_CLASS_G_LEFT_EN_MSK			(0x1 << 1)
+#define NAU8824_CLASS_G_LEFT_EN				(0x1 << 1)
+#define NAU8824_CLASS_G_LEFT_DIS			(0x0 << 1)
+#define NAU8824_CLASS_G_EN_MSK				(0x1 << 0)
+#define NAU8824_CLASS_G_SHIFT				0
+#define NAU8824_CLASS_G_EN					(0x1 << 0)
+#define NAU8824_CLASS_G_DIS					(0x0 << 0)
+
+/* reg NAU8824_SAR_ADC_OUTPUT (0x59) */
+#define NAU8824_ADC_OUTPUT_MASK				(0xFF << 0)
+#define NAU8824_ADC_OUTPUT_SFT				0
+
+/* reg. NAU8824_BIAS_ADJ_2 (0x66) */
+#define NAU8824_VMID_MASK					(0x1 << 6)
+#define NAU8824_VMID_SFT					6
+#define NAU8824_VMID_EN						(0x1 << 6)
+#define NAU8824_VMID_DIS					(0x0 << 6)
+#define NAU8824_VMID_OPTION_MASK			(0x1 << 4)
+#define NAU8824_VMID_OPTION_SFT				4
+#define NAU8824_DMIC2_MASK					(0x1 << 3)
+#define NAU8824_DMIC2_SFT					3
+#define NAU8824_DMIC2_EN					(0x1 << 3)
+#define NAU8824_DMIC2_DIS					(0x0 << 3)
+#define NAU8824_DMIC1_MASK					(0x1 << 2)
+#define NAU8824_DMIC1_SFT					2
+#define NAU8824_DMIC1_EN					(0x1 << 2)
+#define NAU8824_DMIC1_DIS					(0x0 << 2)
+
+/* reg. NAU8824_ANALOG_CTRL2 (0x6A) */
+#define NAU8824_CLASS_D_CLAMP_MSK			(0x1 << 3)
+#define NAU8824_CLASS_D_CLAMP_SFT			3
+#define NAU8824_CLASS_D_CLAMP_BETTER		(0x1 << 3)
+#define NAU8824_CLASS_D_CLAMP_DEFAULT		(0x0 << 3)
+
+/* reg. NAU8824_HPO_MIXER (0x6B) */
+#define NAU8824_M_HPVOL_R_HM				(0x1 << 2)
+#define NAU8824_M_HPVOL_R_HM_SFT			2
+#define NAU8824_M_HPVOL_L_HM				(0x1 << 0)
+#define NAU8824_M_HPVOL_L_HM_SFT			0
+
+/* reg. NAU8824_CLASS_D_GAIN1 (0x6D) */
+#define NAU8824_CLASS_D_GAIN_R_MSK			(0x1F << 8)
+#define NAU8824_CLASS_D_GAIN_R_SFT			8
+#define NAU8824_CLASS_D_MASK				(0x1 << 7)
+#define NAU8824_CLASS_D_SFT					7
+#define NAU8824_CLASS_D_EN_MSK				(0x1 << 7)
+#define NAU8824_CLASS_D_EN					(0x1 << 7)
+#define NAU8824_CLASS_D_DIS					(0x0 << 7)
+
+/* reg. NAU8824_CLASS_D_GAIN2 (0x6E) */
+#define NAU8824_CLASS_D_GAIN_L_MSK			(0x1F << 0)
+#define NAU8824_CLASS_D_GAIN_L_SFT			0
+
+/* reg. NAU8824_DAC_CTRL (0x73) */
+#define NAU8824_DAC_R_MASK					(0x1 << 13)
+#define NAU8824_DAC_R_SFT					13
+#define NAU8824_DAC_R_EN			        (0x1 << 13)
+#define NAU8824_DAC_R_DIS					(0x0 << 13)
+#define NAU8824_DAC_L_MASK					(0x1 << 12)
+#define NAU8824_DAC_L_SFT					12
+#define NAU8824_DAC_L_EN					(0x1 << 12)
+#define NAU8824_DAC_L_DIS					(0x0 << 12)
+
+/* reg. NAU8824_MIC_BIAS (0x74) */
+#define NAU8824_BIAS_POWER_MASK				(0x1 << 8)
+#define NAU8824_BIAS_POWER_SFT				8
+#define NAU8824_BIAS_POWER_ON				(0x1 << 8)
+#define NAU8824_BIAS_POWER_DOWN				(0x0 << 8)
+#define NAU8824_BIAS_LEVEL_MASK				(0x7 << 0)
+#define NAU8824_BIAS_LEVEL_SFT				0
+#define NAU8824_BIAS_LEVEL_VDDA				(0x0 << 0)
+
+/* reg. NAU8824_HP_MUTE	(0x75) */
+#define NAU8824_R_MUTE						(0x1 << 14)
+#define NAU8824_R_MUTE_SFT					14
+#define NAU8824_L_MUTE						(0x1 << 6)
+#define NAU8824_L_MUTE_SFT					6
+
+/* reg. NAU8824_BOOST (0x76) */
+#define NAU8824_VMID_PRECHARGE_MASK			(0x1 << 13)
+#define NAU8824_VMID_PRECHARGE_SFT			13
+#define NAU8824_VMID_PRECHARGE_DIS			(0x1 << 13)
+#define NAU8824_VMID_PRECHARGE_EN			(0x0 << 13)
+#define NAU8824_G_BIAS_MASK					(0x1 << 12)
+#define NAU8824_G_BIAS_SFT					12
+#define NAU8824_G_BIAS_EN					(0x1 << 12)
+#define NAU8824_G_BIAS_DIS					(0x0 << 12)
+
+/* reg. NAU8824_HP_VOL (0x7B) */
+#define NAU8824_R_VOL_MASK					(0x1f << 8)
+#define NAU8824_R_VOL_SFT					8
+#define NAU8824_SPK_L_VOL_MASK				(0x1f)
+#define NAU8824_SPK_R_VOL_MASK				(0x1f << 8)
+#define NAU8824_L_VOL_MASK					(0x1f)
+#define NAU8824_L_VOL_SFT					0
+
+/* Volume Rescale */
+#define NAU8824_VOL_RSCL_MAX				0x1E
+#define NAU8824_VOL_RSCL_RANGE				0x1E
+#define NAU8824_SPK_VOL_RSCL_MAX			0x19
+#define NAU8824_SPK_VOL_RSCL_RANGE			0x19
+#define NAU8824_DAC_VOL_RSCL_RANGE			0x164
+#define NAU8824_ADC_VOL_RSCL_RANGE			0x164
+
+/* Data Format */
+#define NAU8824_I2S_DL_32					(0x3 << 2)
+#define NAU8824_I2S_DL_24					(0x2 << 2)
+#define NAU8824_I2S_DL_20					(0x1 << 2)
+#define NAU8824_I2S_DL_16					(0x0 << 2)
+
+#define NAU8824_FREQ_25000000				25000000
+#define NAU8824_PLL_CLKIN_MCLK				0
+#define NAU8824_BUTTONPRESS_MASK			0x20
+#define NAU8824_HSPLUG_MASK					0x10
+
+enum {
+	NAU8824_INTERNALCLOCK = 0,
+	NAU8824_MCLK,
+};
+
+enum {
+	NAU8824_J_IN_EVENT,
+	NAU8824_J_OUT_EVENT,
+	NAU8824_BP_EVENT,
+	NAU8824_BR_EVENT,
+	NAU8824_UN_EVENT,
+};
+
+enum {
+	S_NAU8824_J_OUT,
+	S_NAU8824_J_IN_TEMP,
+	S_NAU8824_J_IN,
+	S_NAU8824_BUTTON_DECT,
+	S_NAU8824_NO_BUTTON_DECT,
+};
+
+#define NAU8824_RATES	SNDRV_PCM_RATE_8000_192000
+#define NAU8824_FORMATS	(SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE \
+			 | SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S32_LE)
+
+struct nau8824_jack_data {
+	struct snd_soc_jack *jack;
+	int report;
+};
+
+struct nau8824_gpio_setup {
+	unsigned int reg;
+	u8 value;
+};
+
+struct nau8824_pdata {
+	unsigned int audio_mclk1;
+	unsigned int gpio_irq;
+	int naudint_irq;
+	int headset_detect;
+	int button_press_detect;
+};
+
+struct nau8824_priv {
+	struct nau8824_jack_data hs_jack;
+	struct workqueue_struct *workqueue;
+	struct delayed_work delayed_work;
+	struct snd_soc_codec *codec;
+	u8 i2c_regs_status;
+	struct device *dev;
+	struct regmap *regmap;
+	struct mutex mutex;
+	struct nau8824_pdata pdata;
+	unsigned int irq;
+	bool jd_status;
+	bool bp_status;
+	int	jack_type;
+};
+
+int nau8824_device_init(struct nau8824_priv *nau8824);
+void nau8824_device_exit(struct nau8824_priv *nau8824);
+void nau8824_enable_mic_bias(struct snd_soc_codec *codec, int enable);
+int nau8824_query_jack_status(struct snd_soc_codec *codec);
+int nau8824_query_btn_press(struct snd_soc_codec *codec);
+void nau8824_btn_press_intr_enable(struct snd_soc_codec *codec,	int enable);
+
+#endif				/* _NAU8824_H */
-- 
1.9.1


---
此电子邮件没有病毒和恶意软件,因为 avast! 防病毒保护处于活动状态。
http://www.avast.com



More information about the Alsa-devel mailing list