Signed-off-by: Wan Zongshun <mcuos....@gmail.com>
Signed-off-by: Chih-Chiang Chang <ccchan...@nuvoton.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 <mh...@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 <mh...@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.8.1.2

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to