kernel: sound: Adding TI codec support
Vinod G [Wed, 30 Nov 2011 01:32:11 +0000 (17:32 -0800)]
Adding the code for supporting TI AIC3262 codec.
bug 816608

Change-Id: I19c3e03e8fd442c0c19a72a7efeddcd0ca05a7e1
Reviewed-on: http://git-master/r/67279
Reviewed-by: Vinod Gopalakrishnakurup <vinodg@nvidia.com>
Tested-by: Vinod Gopalakrishnakurup <vinodg@nvidia.com>
Reviewed-by: Scott Peterson <speterson@nvidia.com>

include/sound/tlv320aic326x.h [new file with mode: 0644]
sound/soc/codecs/Kconfig
sound/soc/codecs/Makefile
sound/soc/codecs/tlv320aic326x.c [new file with mode: 0755]
sound/soc/codecs/tlv320aic326x.h [new file with mode: 0755]
sound/soc/codecs/tlv320aic326x_mini-dsp.c [new file with mode: 0755]
sound/soc/codecs/tlv320aic326x_minidsp_config.c [new file with mode: 0755]

diff --git a/include/sound/tlv320aic326x.h b/include/sound/tlv320aic326x.h
new file mode 100644 (file)
index 0000000..97e5841
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ * Platform data for Texas Instruments TLV320AIC326x codec
+ *
+ * Copyright 2010 TI Products
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ *
+ */
+#ifndef __LINUX_SND_TLV320AIC326x_H__
+#define __LINUX_SND_TLV320AIC326x_H__
+
+/* codec platform data */
+struct aic326x_pdata {
+
+       /* has to be one of 16,32,64,128,256,512 ms
+       as per the data sheet */
+       unsigned int debounce_time_ms;
+};
+
+#endif
index 665d924..f14d61e 100644 (file)
@@ -48,6 +48,7 @@ config SND_SOC_ALL_CODECS
        select SND_SOC_TLV320AIC23 if I2C
        select SND_SOC_TLV320AIC26 if SPI_MASTER
        select SND_SOC_TVL320AIC32X4 if I2C
+       select SND_SOC_TLV320AIC326X if I2C
        select SND_SOC_TLV320AIC3X if I2C
        select SND_SOC_TPA6130A2 if I2C
        select SND_SOC_TLV320DAC33 if I2C
@@ -246,6 +247,9 @@ config SND_SOC_TVL320AIC32X4
 config SND_SOC_TLV320AIC3X
        tristate
 
+config SND_SOC_TLV320AIC326X
+       tristate "TI AIC326x Codec"
+
 config SND_SOC_TLV320DAC33
        tristate
 
index 5119a7e..e866eee 100644 (file)
@@ -35,6 +35,8 @@ snd-soc-stac9766-objs := stac9766.o
 snd-soc-tlv320aic23-objs := tlv320aic23.o
 snd-soc-tlv320aic26-objs := tlv320aic26.o
 snd-soc-tlv320aic3x-objs := tlv320aic3x.o
+snd-soc-tlv320aic326x-objs := tlv320aic326x.o tlv320aic326x_minidsp_config.o
+snd-soc-tlv320aic326x-objs += tlv320aic326x_mini-dsp.o
 snd-soc-tlv320aic32x4-objs := tlv320aic32x4.o
 snd-soc-tlv320dac33-objs := tlv320dac33.o
 snd-soc-twl4030-objs := twl4030.o
@@ -133,6 +135,7 @@ obj-$(CONFIG_SND_SOC_TLV320AIC23)   += snd-soc-tlv320aic23.o
 obj-$(CONFIG_SND_SOC_TLV320AIC26)      += snd-soc-tlv320aic26.o
 obj-$(CONFIG_SND_SOC_TLV320AIC3X)      += snd-soc-tlv320aic3x.o
 obj-$(CONFIG_SND_SOC_TVL320AIC32X4)     += snd-soc-tlv320aic32x4.o
+obj-$(CONFIG_SND_SOC_TLV320AIC326X)    += snd-soc-tlv320aic326x.o
 obj-$(CONFIG_SND_SOC_TLV320DAC33)      += snd-soc-tlv320dac33.o
 obj-$(CONFIG_SND_SOC_TWL4030)  += snd-soc-twl4030.o
 obj-$(CONFIG_SND_SOC_TWL6040)  += snd-soc-twl6040.o
diff --git a/sound/soc/codecs/tlv320aic326x.c b/sound/soc/codecs/tlv320aic326x.c
new file mode 100755 (executable)
index 0000000..40b6093
--- /dev/null
@@ -0,0 +1,3896 @@
+/*
+* linux/sound/soc/codecs/tlv320aic3262.c
+*
+* Copyright (C) 2011 Mistral Solutions Pvt Ltd.
+*
+* Based on sound/soc/codecs/tlv320aic3262.c
+*
+* This package 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.
+*
+* THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+*
+* The TLV320AIC3262 is a flexible, low-power, low-voltage stereo audio
+* codec with digital microphone inputs and programmable outputs.
+*
+* History:
+*
+* Rev 0.1   ASoC driver support    Mistral         20-01-2011
+*
+*              The AIC325x ASoC driver is ported for the codec AIC3262.
+* Rev 0.2   ASoC driver support    Mistral         21-03-2011
+*              The AIC326x ASoC driver is updated abe changes.
+*
+* Rev 0.3   ASoC driver support    Mistral         12.09.2011
+*              fixed the compilation issues for Whistler support
+*
+* Rev 0.4   ASoC driver support    Mistral         27.09.2011
+*              The AIC326x driver ported for Nvidia cardhu.
+*
+* Rev 0.5   Modified to support Multiple ASI Ports  08-Nov-2011
+*              Driver updated to support ASI Ports of AIC3262
+*
+* Modified by Nvidia 23-Nov-2011 for K39 ASoC changes.
+*/
+
+/*
+ *****************************************************************************
+ * INCLUDES
+ *****************************************************************************
+ */
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/platform_device.h>
+#include <linux/spi/spi.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+#include <asm/div64.h>
+#include <sound/tlv320aic326x.h>
+#include <sound/jack.h>
+
+#include "tlv320aic326x.h"
+
+/*
+ *****************************************************************************
+ * Global Variable
+ *****************************************************************************
+ */
+static u8 aic3262_reg_ctl;
+
+u8 dac_reg = 0, adc_gain = 0, hpl = 0, hpr = 0;
+u8 rec_amp = 0, rampr = 0, spk_amp = 0;
+/* whenever aplay/arecord is run, aic3262_hw_params() function gets called.
+ * This function reprograms the clock dividers etc. this flag can be used to
+ * disable this when the clock dividers are programmed by pps config file
+ */
+static int soc_static_freq_config = 1;
+
+/*
+ *****************************************************************************
+ * Macros
+ *****************************************************************************
+ */
+
+/* ASoC Widget Control definition for a single Register based Control */
+#define SOC_SINGLE_AIC3262(xname) \
+{\
+       .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
+       .info = __new_control_info, .get = __new_control_get,\
+       .put = __new_control_put, \
+       .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, \
+}
+#define SOC_SINGLE_N(xname, xreg, xshift, xmax, xinvert) \
+{\
+       .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
+       .info = n_control_info, .get = n_control_get,\
+       .put = n_control_put, \
+       .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, \
+       .private_value =  ((unsigned long)&(struct soc_mixer_control)) \
+       {.reg = xreg, .shift = xshift, .rshift = xshift, .max = xmax, \
+       .invert = xinvert} }
+
+/* ASoC Widget Control definition for a Double Register based Control */
+
+#define SOC_DOUBLE_R_N(xname, reg_left, reg_right, xshift, xmax, xinvert) \
+{      .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
+       .info = snd_soc_info_volsw_2r_n, \
+       .get = snd_soc_get_volsw_2r_n, .put = snd_soc_put_volsw_2r_n, \
+       .private_value = (unsigned long)&(struct soc_mixer_control) \
+               {.reg = reg_left, .rreg = reg_right, .shift = xshift, \
+               .max = xmax, .invert = xinvert} }
+
+#define SND_SOC_DAPM_SWITCH_N(wname, wreg, wshift, winvert) \
+{      .id = snd_soc_dapm_switch, .name = wname, .reg = wreg, .shift = wshift,\
+       .invert = winvert, .kcontrols = NULL, .num_kcontrols = 0}
+/*
+ *****************************************************************************
+ * Function Prototype
+ *****************************************************************************
+ */
+static int aic3262_hw_params(struct snd_pcm_substream *substream,
+                            struct snd_pcm_hw_params *params,
+                            struct snd_soc_dai *dai);
+
+static int aic3262_mute(struct snd_soc_dai *dai, int mute);
+
+static int aic3262_set_dai_sysclk(struct snd_soc_dai *codec_dai,
+                                 int clk_id, unsigned int freq, int dir);
+
+static int aic3262_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt);
+
+static int aic3262_set_bias_level(struct snd_soc_codec *codec,
+                                               enum snd_soc_bias_level level);
+
+static int __new_control_info(struct snd_kcontrol *kcontrol,
+                             struct snd_ctl_elem_info *uinfo);
+
+static int __new_control_get(struct snd_kcontrol *kcontrol,
+                            struct snd_ctl_elem_value *ucontrol);
+
+static int __new_control_put(struct snd_kcontrol *kcontrol,
+                            struct snd_ctl_elem_value *ucontrol);
+
+static inline int aic3262_get_divs(int mclk, int rate);
+
+static int aic3262_multi_i2s_hw_params(struct snd_pcm_substream *substream,
+                               struct snd_pcm_hw_params *params,
+                               struct snd_soc_dai *dai);
+
+static int aic3262_multi_i2s_set_dai_sysclk(struct snd_soc_dai *codec_dai,
+               int clk_id, unsigned int freq, int dir);
+static int aic3262_multi_i2s_set_dai_pll(struct snd_soc_dai *codec_dai,
+               int pll_id, int source, unsigned int freq_in,
+               unsigned int freq_out);
+
+static int aic3262_multi_i2s_asi1_set_dai_fmt(struct snd_soc_dai *codec_dai,
+               unsigned int fmt);
+
+static int aic3262_multi_i2s_asi2_set_dai_fmt(struct snd_soc_dai *codec_dai,
+               unsigned int fmt);
+
+static int aic3262_multi_i2s_asi3_set_dai_fmt(struct snd_soc_dai *codec_dai,
+               unsigned int fmt);
+
+static int aic3262_multi_i2s_asi1_mute(struct snd_soc_dai *dai, int mute);
+
+static int aic3262_multi_i2s_asi2_mute(struct snd_soc_dai *dai, int mute);
+
+static int aic3262_multi_i2s_asi3_mute(struct snd_soc_dai *dai, int mute);
+
+static const char *wclk1_pincontrol[] = {
+       "ASI1 Word Clock Input/Output", "CLKOUT output"};
+static const char *dout1_pincontrol[] = {
+       "disabled", "ASI1 data output", "gpio", "clock out",
+       "INT1", "INT2", "SAR ADC interrupt"};
+
+static const char *din1_pincontrol[] = {"disabled", "enabled"};
+
+static const char *wclk2_pincontrol[] = {
+       "diabled", "ASI1 secondary wclk", "general purpose input",
+       "general purpose output", "clkout", "INT1 interrupt",
+       "IN2 interrupt", "output digital microphone",
+       "SAR ADC interrupt", "data output for ASI1"};
+
+static const char *bclk2_pincontrol[] = {
+       "diabled", "ASI1 secondary wclk", "general purpose input",
+       "general purpose output", "clkout", "INT1 interrupt",
+       "IN2 interrupt", "output digital microphone",
+       "SAR ADC interrupt", "data output for ASI1"};
+
+static const char *dout2_pincontrol[] = {
+       "disabled", "ASI2 Data Output", "General Purpose Output",
+       "INT1 Interrupt", "INT2 Interrupt", "SAR ADC interrupt",
+       "Output for digital microphone", "Data Output for ASI1"};
+
+static const char *din2_pincontrol[] = {"disabled", "enabled"};
+
+static const char *wclk3_pincontrol[] = {
+       "Disabled", "ASI3 WCLK", "General Purpose Input",
+       "General Purpose output", "Data Output for ASI1"};
+
+static const char *bclk3_pincontrol[] = {
+       "Disabled", "ASI3 BCLK", "General Purpose Input",
+       "General Purpose output", "Data Output for ASI1"};
+
+static const char *dout3_pincontrol[] = {
+       "disabled", "ASI3 data ooutput", "General Purpose Output",
+       "ASI1 Word Clock Output", "Data Output for ASI1"};
+
+static const char *din3_pincontrol[] = {"disabled", "enabled"};
+
+static const char *clkin[] = {
+       "mclk1", "bclk1", "gpio1", "pll_clk", "bclk2", "gpi1",
+       "hf_ref_clk", "hf_osc_clk", "mclk2", "gpio2", "gpi2"};
+
+/* List of SOC_ENUM structures for the AIC3262 PIN Control Amixer Controls */
+static const struct soc_enum aic326x_enum[] = {
+       SOC_ENUM_SINGLE(WCLK1_PIN_CNTL_REG, 2, 2, wclk1_pincontrol),
+       SOC_ENUM_SINGLE(DOUT1_PIN_CNTL_REG, 1, 7, dout1_pincontrol),
+       SOC_ENUM_SINGLE(DIN1_PIN_CNTL_REG,  5, 2, din1_pincontrol),
+       SOC_ENUM_SINGLE(WCLK2_PIN_CNTL_REG, 2, 10, wclk2_pincontrol),
+       SOC_ENUM_SINGLE(BCLK2_PIN_CNTL_REG, 2, 10, bclk2_pincontrol),
+       SOC_ENUM_SINGLE(DOUT2_PIN_CNTL_REG, 1, 8, dout2_pincontrol),
+       SOC_ENUM_SINGLE(DIN2_PIN_CNTL_REG,  5, 2, din2_pincontrol),
+       SOC_ENUM_SINGLE(WCLK3_PIN_CNTL_REG, 2, 5, wclk3_pincontrol),
+       SOC_ENUM_SINGLE(BCLK3_PIN_CNTL_REG, 2, 5, bclk3_pincontrol),
+       SOC_ENUM_SINGLE(DOUT3_PIN_CNTL_REG, 1, 5, dout3_pincontrol),
+       SOC_ENUM_SINGLE(DIN3_PIN_CNTL_REG,  5, 2, din3_pincontrol),
+       SOC_ENUM_DOUBLE(DAC_ADC_CLKIN_REG,  0, 4, 11, clkin),
+};
+
+#ifdef DAC_INDEPENDENT_VOL
+/*
+ *----------------------------------------------------------------------------
+ * Function : n_control_info
+ * Purpose  : This function is to initialize data for new control required to
+ *            program the AIC3262 registers.
+ *
+ *----------------------------------------------------------------------------
+ */
+static int n_control_info(struct snd_kcontrol *kcontrol,
+                             struct snd_ctl_elem_info *uinfo)
+{
+       struct soc_mixer_control *mc =
+               (struct soc_mixer_control *)kcontrol->private_value;
+       int max = mc->max;
+       unsigned int shift = mc->shift;
+       unsigned int rshift = mc->rshift;
+
+       if (max == 1)
+               uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+       else
+               uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+
+       uinfo->count = shift == rshift ? 1 : 2;
+       uinfo->value.integer.min = 0;
+       uinfo->value.integer.max = max;
+       return 0;
+}
+
+/*
+ *----------------------------------------------------------------------------
+ * Function : n_control_get
+ * Purpose  : This function is to read data of new control for
+ *            program the AIC3262 registers.
+ *
+ *----------------------------------------------------------------------------
+ */
+static int n_control_get(struct snd_kcontrol *kcontrol,
+                            struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       u32 val;
+       unsigned short mask, shift;
+       struct soc_mixer_control *mc =
+               (struct soc_mixer_control *)kcontrol->private_value;
+       if (!strcmp(kcontrol->id.name, "Left DAC Volume")) {
+               mask = AIC3262_8BITS_MASK;
+               shift = 0;
+               val = aic3262_read(codec, mc->reg);
+               ucontrol->value.integer.value[0] =
+                   (val <= 48) ? (val + 127) : (val - 129);
+       }
+       if (!strcmp(kcontrol->id.name, "Right DAC Volume")) {
+               mask = AIC3262_8BITS_MASK;
+               shift = 0;
+               val = aic3262_read(codec, mc->reg);
+               ucontrol->value.integer.value[0] =
+                   (val <= 48) ? (val + 127) : (val - 129);
+       }
+
+       return 0;
+}
+
+/*
+ *----------------------------------------------------------------------------
+ * Function : __new_control_put
+ * Purpose  : new_control_put is called to pass data from user/application to
+ *            the driver.
+ *
+ *----------------------------------------------------------------------------
+ */
+static int n_control_put(struct snd_kcontrol *kcontrol,
+                            struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct soc_mixer_control *mc =
+               (struct soc_mixer_control *)kcontrol->private_value;
+       u8 val, val_mask;
+       int reg, err;
+       unsigned int invert = mc->invert;
+       int max = mc->max;
+       DBG("n_control_put\n");
+       reg = mc->reg;
+       val = ucontrol->value.integer.value[0];
+       if (invert)
+               val = max - val;
+       if (!strcmp(kcontrol->id.name, "Left DAC Volume")) {
+               DBG("LDAC\n");
+               val = (val >= 127) ? (val - 127) : (val + 129);
+               val_mask = AIC3262_8BITS_MASK;
+       }
+       if (!strcmp(kcontrol->id.name, "Right DAC Volume")) {
+               DBG("RDAC\n");
+               val = (val >= 127) ? (val - 127) : (val + 129);
+               val_mask = AIC3262_8BITS_MASK;
+       }
+
+       err = snd_soc_update_bits_locked(codec, reg, val_mask, val);
+       if (err < 0) {
+               printk(KERN_ERR "Error while updating bits\n");
+               return err;
+       }
+
+       return 0;
+}
+#endif /*#ifdef DAC_INDEPENDENT_VOL*/
+/*
+ *------------------------------------------------------------------------------
+ * snd_soc_info_volsw_2r_n - double mixer info callback
+ * @kcontrol: mixer control
+ * @uinfo: control element information
+ *
+ * Callback to provide information about a double mixer control that
+ * spans 2 codec registers.
+ *
+ * Returns 0 for success.
+ *------------------------------------------------------------------------------
+ */
+int snd_soc_info_volsw_2r_n(struct snd_kcontrol *kcontrol,
+       struct snd_ctl_elem_info *uinfo)
+{
+       struct soc_mixer_control *mc =
+               (struct soc_mixer_control *)kcontrol->private_value;
+       int max = mc->max;
+
+       if (max == 1)
+               uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+       else
+               uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+
+       uinfo->count = 2;
+       uinfo->value.integer.min = 0;
+       uinfo->value.integer.max = max;
+       return 0;
+}
+
+/*
+ *------------------------------------------------------------------------------
+ * snd_soc_get_volsw_2r_n - double mixer get callback
+ * @kcontrol: mixer control
+ * @ucontrol: control element information
+ *
+ * Callback to get the value of a double mixer control that spans 2 registers.
+ *
+ * Returns 0 for success.
+ *------------------------------------------------------------------------------
+ */
+int snd_soc_get_volsw_2r_n(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_kcontrol_chip(kcontrol);
+       unsigned int reg = mc->reg;
+       unsigned int reg2 = mc->rreg;
+       unsigned int shift = mc->shift;
+       int max = mc->max;
+       unsigned int mask;
+       unsigned int invert = mc->invert;
+       unsigned short val, val2;
+
+       if (!strcmp(kcontrol->id.name, "PCM Playback Volume")) {
+               mask = AIC3262_8BITS_MASK;
+               shift = 0;
+       } else if (!strcmp(kcontrol->id.name, "HP Driver Gain")) {
+               mask = 0x3F;
+               shift = 0;
+       } else if (!strcmp(kcontrol->id.name, "PGA Capture Volume")) {
+               mask = 0x7F;
+               shift = 0;
+       } else if (!strcmp(kcontrol->id.name, "REC Driver Volume")) {
+               mask = 0x3F;
+               shift = 0;
+       } else if (!strcmp(kcontrol->id.name, "LO to HP Volume")) {
+               mask = 0x7F;
+               shift = 0;
+       } else if (!strcmp(kcontrol->id.name, "MA Volume")) {
+               mask = 0x7F;
+               shift = 0;
+       } else {
+               printk(KERN_ERR "Invalid kcontrol name\n");
+               return -1;
+       }
+
+       /* Read, update the corresponding Registers */
+       val = (snd_soc_read(codec, reg) >> shift) & mask;
+       val2 = (snd_soc_read(codec, reg2) >> shift) & mask;
+
+       if (!strcmp(kcontrol->id.name, "PCM Playback Volume")) {
+               ucontrol->value.integer.value[0] =
+                   (val <= 48) ? (val + 127) : (val - 129);
+               ucontrol->value.integer.value[1] =
+                   (val2 <= 48) ? (val2 + 127) : (val2 - 129);
+       } else if (!strcmp(kcontrol->id.name, "HP Driver Gain")) {
+               ucontrol->value.integer.value[0] =
+                   (val >= 57) ? (val - 57) : (val + 7);
+               ucontrol->value.integer.value[1] =
+                   (val2 >= 57) ? (val2 - 57) : (val2 + 7);
+       } else if (!strcmp(kcontrol->id.name, "PGA Capture Volume")) {
+               ucontrol->value.integer.value[0] =
+                   (val <= 40) ? (val + 24) : (val - 104);
+               ucontrol->value.integer.value[1] =
+                   (val2 <= 40) ? (val2 + 24) : (val2 - 104);
+       } else if (!strcmp(kcontrol->id.name, "REC Driver Volume")) {
+               ucontrol->value.integer.value[0] = ((val >= 0) & (val <= 29)) ?
+                                                (val + 7) : (val - 57);
+               ucontrol->value.integer.value[1] = ((val2 >= 0) &
+                   (val2 <= 29)) ? (val2 + 7) : (val2 - 57);
+
+       } else if (!strcmp(kcontrol->id.name, "LO to HP Volume")) {
+               ucontrol->value.integer.value[0] = ((val >= 0) & (val <= 116)) ?
+                                (val + 1) : ((val == 127) ? (0) : (117));
+               ucontrol->value.integer.value[1] = ((val2 >= 0) & (val2 <= 116))
+                                ? (val2 + 1) : ((val2 == 127) ? (0) : (117));
+
+       } else if (!strcmp(kcontrol->id.name, "MA Volume")) {
+               ucontrol->value.integer.value[0] = (val <= 40) ?
+                                        (41 - val) : (val = 0);
+               ucontrol->value.integer.value[1] = (val2 <= 40) ?
+                                        (41 - val2) : (val2 = 0);
+       }
+
+       if (invert) {
+               ucontrol->value.integer.value[0] =
+                       max - ucontrol->value.integer.value[0];
+               ucontrol->value.integer.value[1] =
+                       max - ucontrol->value.integer.value[1];
+       }
+
+       return 0;
+}
+/*
+*-------------------------------------------------------------------------------
+* snd_soc_put_volsw_2r_n - double mixer set callback
+* @kcontrol: mixer control
+* @ucontrol: control element information
+*
+* Callback to set the value of a double mixer control that spans 2 registers.
+*
+* Returns 0 for success.
+*-------------------------------------------------------------------------------
+*/
+int snd_soc_put_volsw_2r_n(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_kcontrol_chip(kcontrol);
+       unsigned int reg = mc->reg;
+       unsigned int reg2 = mc->rreg;
+       unsigned int shift = mc->shift;
+       int max = mc->max;
+       unsigned int mask;
+       unsigned int invert = mc->invert;
+       int err;
+       unsigned short val, val2, val_mask;
+
+       mask = 0x00FF;
+
+       val = (ucontrol->value.integer.value[0] & mask);
+       val2 = (ucontrol->value.integer.value[1] & mask);
+       if (invert) {
+               val = max - val;
+               val2 = max - val2;
+       }
+
+       /* Check for the string name of the kcontrol */
+       if (!strcmp(kcontrol->id.name, "PCM Playback Volume")) {
+               val = (val >= 127) ? (val - 127) : (val + 129);
+               val2 = (val2 >= 127) ? (val2 - 127) : (val2 + 129);
+               val_mask = AIC3262_8BITS_MASK;  /* 8 bits */
+       } else if ((!strcmp(kcontrol->id.name, "HP Driver Gain")) ||
+                  (!strcmp(kcontrol->id.name, "LO Driver Gain"))) {
+               val = (val <= 6) ? (val + 57) : (val - 7);
+               val2 = (val2 <= 6) ? (val2 + 57) : (val2 - 7);
+               val_mask = 0x3F;        /* 6 bits */
+               DBG("val=%d, val2=%d", val, val2);
+       } else if (!strcmp(kcontrol->id.name, "PGA Capture Volume")) {
+               val = (val >= 24) ? ((val <= 64) ?
+                       (val-24) : (40)) : (val + 104);
+               val2 = (val2 >= 24) ?
+                       ((val2 <= 64) ? (val2 - 24) : (40)) : (val2 + 104);
+               val_mask = 0x7F;        /* 7 bits */
+       } else if (!strcmp(kcontrol->id.name, "LO to REC Volume")) {
+
+               val = (val <= 116) ?
+                        (val % 116) : ((val == 117) ? (127) : (117));
+               val2 = (val2 <= 116) ?
+                       (val2 % 116) : ((val2 == 117) ? (127) : (117));
+               val_mask = 0x7F;
+       } else if (!strcmp(kcontrol->id.name, "REC Driver Volume")) {
+
+               val = (val <= 7) ? (val + 57) : ((val < 36) ? (val - 7) : (29));
+               val2 = (val2 <= 7) ?
+                               (val2 + 57) : ((val2 < 36) ? (val2 - 7) : (29));
+               val_mask = 0x3F;
+       } else if (!strcmp(kcontrol->id.name, "LO to HP Volume")) {
+
+               val = ((val > 0) & (val <= 117)) ?
+                        (val - 1) : ((val == 0) ? (127) : (116));
+               val2 = ((val2 > 0) & (val2 <= 117)) ?
+                        (val2 - 1) : ((val2 == 0) ? (127) : (116));
+               val_mask = 0x7F;
+       } else if (!strcmp(kcontrol->id.name, "MA Volume")) {
+
+               val = ((val <= 41) & (val > 0)) ?
+                        (41 - val) : ((val > 41) ? (val = 41) : (63));
+               val2 = ((val2 <= 41) & (val2 > 0)) ?
+                        (41 - val2) : ((val2 > 41) ? (val2 = 41) : (63));
+               val_mask = 0x7F;
+       } else {
+               printk(KERN_ERR "Invalid control name\n");
+               return -1;
+       }
+
+       val = val << shift;
+       val2 = val2 << shift;
+
+       err = snd_soc_update_bits_locked(codec, reg, val_mask, val);
+       if (err < 0)
+               return err;
+
+       err = snd_soc_update_bits_locked(codec, reg2, val_mask, val2);
+       return err;
+}
+
+static int __new_control_info(struct snd_kcontrol *kcontrol,
+                             struct snd_ctl_elem_info *uinfo)
+{
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+       uinfo->count = 1;
+       uinfo->value.integer.min = 0;
+       uinfo->value.integer.max = 65535;
+
+       return 0;
+}
+
+/*
+ *----------------------------------------------------------------------------
+ * Function : __new_control_get
+ * Purpose  : This function is to read data of new control for
+ *            program the AIC3262 registers.
+ *
+ *----------------------------------------------------------------------------
+ */
+static int __new_control_get(struct snd_kcontrol *kcontrol,
+                            struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       u32 val;
+       val = aic3262_read(codec, aic3262_reg_ctl);
+       ucontrol->value.integer.value[0] = val;
+       return 0;
+}
+
+/*
+ *----------------------------------------------------------------------------
+ * Function : __new_control_put
+ * Purpose  : new_control_put is called to pass data from user/application to
+ *            the driver.
+ *
+ *----------------------------------------------------------------------------
+ */
+static int __new_control_put(struct snd_kcontrol *kcontrol,
+                            struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct aic3262_priv *aic3262 = snd_soc_codec_get_drvdata(codec);
+       u8 data[2];
+       int ret = 0;
+
+       u32 data_from_user = ucontrol->value.integer.value[0];
+
+       aic3262_change_book(codec, 0);
+       aic3262_reg_ctl = data[0] = (u8) ((data_from_user & 0xFF00) >> 8);
+       data[1] = (u8) ((data_from_user & 0x00FF));
+
+       if (!data[0])
+               aic3262->page_no = data[1];
+
+       DBG("reg = %d val = %x\n", data[0], data[1]);
+
+       ret = snd_soc_write(codec, data[0], data[1]);
+       if (ret)
+               printk(KERN_ERR "Error in i2c write\n");
+
+       return ret;
+}
+
+
+/*
+ *****************************************************************************
+ * Structure Initialization
+ *****************************************************************************
+ */
+static const struct snd_kcontrol_new aic3262_snd_controls[] = {
+       /* Output */
+       #ifndef DAC_INDEPENDENT_VOL
+       /* sound new kcontrol for PCM Playback volume control */
+       SOC_DOUBLE_R_N("PCM Playback Volume", DAC_LVOL, DAC_RVOL, 0, 0xAf, 0),
+       #endif
+       /* sound new kcontrol for HP driver gain */
+       SOC_DOUBLE_R_N("HP Driver Gain", HPL_VOL, HPR_VOL, 0, 21, 0),
+       /* sound new kcontrol for SPK driver gain*/
+       SOC_DOUBLE("SPK Driver Gain", SPK_AMP_CNTL_R4, 0, 4, 5, 0),
+       /* Reveiver driver Gain volume*/
+       SOC_DOUBLE_R_N("REC Driver Volume",
+                       REC_AMP_CNTL_R5, RAMPR_VOL, 0, 36, 0),
+       /* sound new kcontrol for PGA capture volume */
+       SOC_DOUBLE_R_N("PGA Capture Volume", LADC_VOL, RADC_VOL, 0, 0x3F,
+                            0),
+       SOC_DOUBLE("ADC Fine Gain ", ADC_FINE_GAIN, 4, 0, 4, 1),
+       SOC_DOUBLE_R("PGA MIC Volume", MICL_PGA, MICR_PGA, 0, 95, 0),
+
+       SOC_DOUBLE_R("LO to REC Volume", RAMP_CNTL_R1, RAMP_CNTL_R2, 0, 116, 1),
+       SOC_DOUBLE_R_N("LO to HP Volume",
+                HP_AMP_CNTL_R2, HP_AMP_CNTL_R3, 0, 117, 0),
+       SOC_DOUBLE_R("LO to SPK Volume",
+                SPK_AMP_CNTL_R2, SPK_AMP_CNTL_R3, 0, 116, 1),
+       SOC_DOUBLE("ADC channel mute", ADC_FINE_GAIN, 7, 3, 1, 0),
+
+       SOC_DOUBLE("DAC MUTE", DAC_MVOL_CONF, 2, 3, 1, 1),
+
+       /* sound new kcontrol for Programming the registers from user space */
+       SOC_SINGLE_AIC3262("Program Registers"),
+
+       SOC_SINGLE("RESET", RESET_REG, 0 , 1, 0),
+
+       SOC_SINGLE("DAC VOL SOFT STEPPING", DAC_MVOL_CONF, 0, 2, 0),
+
+       #ifdef DAC_INDEPENDENT_VOL
+       SOC_SINGLE_N("Left DAC Volume", DAC_LVOL, 0, 0xAF, 0),
+       SOC_SINGLE_N("Right DAC Volume", DAC_RVOL, 0, 0xAF, 0),
+       #endif
+
+       SOC_SINGLE("DAC AUTO MUTE CONTROL", DAC_MVOL_CONF, 4, 7, 0),
+       SOC_SINGLE("RIGHT MODULATOR SETUP", DAC_MVOL_CONF, 7, 1, 0),
+
+       SOC_SINGLE("ADC Volume soft stepping", ADC_CHANNEL_POW, 0, 3, 0),
+
+       SOC_DOUBLE_R_N("MA Volume",
+                LADC_PGA_MAL_VOL, RADC_PGA_MAR_VOL, 0, 42, 0),
+
+       SOC_SINGLE("Mic Bias ext independent enable", MIC_BIAS_CNTL, 7, 1, 0),
+       SOC_SINGLE("MICBIAS_EXT ON", MIC_BIAS_CNTL, 6, 1, 0),
+       SOC_SINGLE("MICBIAS EXT Power Level", MIC_BIAS_CNTL, 4, 3, 0),
+
+       SOC_SINGLE("MICBIAS_INT ON", MIC_BIAS_CNTL, 2, 1, 0),
+       SOC_SINGLE("MICBIAS INT Power Level", MIC_BIAS_CNTL, 0, 3, 0),
+
+       SOC_DOUBLE("DRC_EN_CTL", DRC_CNTL_R1, 6, 5, 1, 0),
+       SOC_SINGLE("DRC_THRESHOLD_LEVEL", DRC_CNTL_R1, 2, 7, 1),
+       SOC_SINGLE("DRC_HYSTERISIS_LEVEL", DRC_CNTL_R1, 0, 7, 0),
+
+       SOC_SINGLE("DRC_HOLD_LEVEL", DRC_CNTL_R2, 3, 0x0F, 0),
+       SOC_SINGLE("DRC_GAIN_RATE", DRC_CNTL_R2, 0, 4, 0),
+       SOC_SINGLE("DRC_ATTACK_RATE", DRC_CNTL_R3, 4, 0x0F, 1),
+       SOC_SINGLE("DRC_DECAY_RATE", DRC_CNTL_R3, 0, 0x0F, 1),
+
+       SOC_SINGLE("BEEP_GEN_EN", BEEP_CNTL_R1, 7, 1, 0),
+       SOC_DOUBLE_R("BEEP_VOL_CNTL", BEEP_CNTL_R1, BEEP_CNTL_R2, 0, 0x0F, 1),
+       SOC_SINGLE("BEEP_MAS_VOL", BEEP_CNTL_R2, 6, 3, 0),
+
+       SOC_DOUBLE_R("AGC_EN", LAGC_CNTL, RAGC_CNTL, 7, 1, 0),
+       SOC_DOUBLE_R("AGC_TARGET_LEVEL", LAGC_CNTL, RAGC_CNTL, 4, 7, 1),
+
+       SOC_DOUBLE_R("AGC_GAIN_HYSTERESIS", LAGC_CNTL, RAGC_CNTL, 0, 3, 0),
+       SOC_DOUBLE_R("AGC_HYSTERESIS", LAGC_CNTL_R2, RAGC_CNTL_R2, 6, 3, 0),
+       SOC_DOUBLE_R("AGC_NOISE_THRESHOLD",
+                LAGC_CNTL_R2, RAGC_CNTL_R2, 1, 31, 1),
+
+       SOC_DOUBLE_R("AGC_MAX_GAIN", LAGC_CNTL_R3, RAGC_CNTL_R3, 0, 116, 0),
+       SOC_DOUBLE_R("AGC_ATCK_TIME", LAGC_CNTL_R4, RAGC_CNTL_R4, 3, 31, 0),
+       SOC_DOUBLE_R("AGC_ATCK_SCALE_FACTOR",
+                LAGC_CNTL_R4, RAGC_CNTL_R4, 0, 7, 0),
+
+       SOC_DOUBLE_R("AGC_DECAY_TIME", LAGC_CNTL_R5, RAGC_CNTL_R5, 3, 31, 0),
+       SOC_DOUBLE_R("AGC_DECAY_SCALE_FACTOR",
+                LAGC_CNTL_R5, RAGC_CNTL_R5, 0, 7, 0),
+       SOC_DOUBLE_R("AGC_NOISE_DEB_TIME",
+                LAGC_CNTL_R6, RAGC_CNTL_R6, 0, 31, 0),
+
+       SOC_DOUBLE_R("AGC_SGL_DEB_TIME",
+                LAGC_CNTL_R7, RAGC_CNTL_R7, 0, 0x0F, 0),
+       SOC_SINGLE("DAC PRB Selection", DAC_PRB, 0, 25, 0),
+
+       SOC_SINGLE("INTERRUPT FLAG - Read only", 46, 0, 255, 0),
+       SOC_SINGLE("INTERRUPT STICKY FLAG - Read only", 44, 0, 255, 0),
+       SOC_SINGLE("INT1 CONTROL", 48, 0, 255, 0),
+       SOC_SINGLE("GPIO1 CONTROL", (PAGE_4 + 86), 0, 255, 0),
+       SOC_SINGLE("HP_DEPOP", HP_DEPOP, 0, 255, 0),
+
+       #if defined(FULL_IN_CNTL)
+
+       SOC_SINGLE("IN1L_2_LMPGA_P_CTL", LMIC_PGA_PIN, 6, 3, 0),
+       SOC_SINGLE("IN2L_2_LMPGA_P_CTL", LMIC_PGA_PIN, 4, 3, 0),
+       SOC_SINGLE("IN3L_2_LMPGA_P_CTL", LMIC_PGA_PIN, 2, 3, 0),
+       SOC_SINGLE("IN1R_2_LMPGA_P_CTL", LMIC_PGA_PIN, 0, 3, 0),
+
+       SOC_SINGLE("IN4L_2_LMPGA_P_CTL", LMIC_PGA_PM_IN4, 5, 1, 0),
+       SOC_SINGLE("IN4R_2_LMPGA_M_CTL", LMIC_PGA_PM_IN4, 4, 1, 0),
+
+       SOC_SINGLE("CM1_2_LMPGA_M_CTL", LMIC_PGA_MIN, 6, 3, 0),
+       SOC_SINGLE("IN2R_2_LMPGA_M_CTL", LMIC_PGA_MIN, 4, 3, 0),
+       SOC_SINGLE("IN3R_2_LMPGA_M_CTL", LMIC_PGA_MIN, 2, 3, 0),
+       SOC_SINGLE("CM2_2_LMPGA_M_CTL", LMIC_PGA_MIN, 0, 3, 0),
+
+       SOC_SINGLE("IN1R_2_RMPGA_P_CTL", RMIC_PGA_PIN, 6, 3, 0),
+       SOC_SINGLE("IN2R_2_RMPGA_P_CTL", RMIC_PGA_PIN, 4, 3, 0),
+       SOC_SINGLE("IN3R_2_RMPGA_P_CTL", RMIC_PGA_PIN, 2, 3, 0),
+       SOC_SINGLE("IN2L_2_RMPGA_P_CTL", RMIC_PGA_PIN, 0, 3, 0),
+
+       SOC_SINGLE("IN4R_2_RMPGA_P_CTL", RMIC_PGA_PM_IN4, 5, 1, 0),
+       SOC_SINGLE("IN4L_2_RMPGA_M_CTL", RMIC_PGA_PM_IN4, 4, 1, 0),
+
+       SOC_SINGLE("CM1_2_RMPGA_M_CTL", RMIC_PGA_MIN, 6, 3, 0),
+       SOC_SINGLE("IN1L_2_RMPGA_M_CTL", RMIC_PGA_MIN, 4, 3, 0),
+       SOC_SINGLE("IN3L_2_RMPGA_M_CTL", RMIC_PGA_MIN, 2, 3, 0),
+       SOC_SINGLE("CM2_2_RMPGA_M_CTL", RMIC_PGA_MIN, 0, 3, 0),
+
+       #endif
+
+       SOC_DOUBLE("MA_EN_CNTL", MA_CNTL, 3, 2, 1, 0),
+       SOC_DOUBLE("IN1 LO DIRECT BYPASS", MA_CNTL, 5, 4, 1, 0),
+       SOC_DOUBLE("IN1 LO BYPASS VOLUME" , LINE_AMP_CNTL_R2, 3, 0, 3, 1),
+       SOC_DOUBLE("MA LO BYPASS EN",  LINE_AMP_CNTL_R2, 7, 6, 1, 0),
+
+       /* Pin control Macros */
+       SOC_ENUM("DOUT1 Pin Control", aic326x_enum[DOUT1_ENUM]),
+       SOC_ENUM("DIN1 Pin Control",  aic326x_enum[DIN1_ENUM]),
+       SOC_ENUM("WCLK2 Pin Control", aic326x_enum[WCLK2_ENUM]),
+       SOC_ENUM("BCLK2 Pin Control", aic326x_enum[BCLK2_ENUM]),
+       SOC_ENUM("DOUT2 Pin Control", aic326x_enum[DOUT2_ENUM]),
+       SOC_ENUM("DIN2 Pin Control",  aic326x_enum[DIN2_ENUM]),
+       SOC_ENUM("WCLK3 Pin Control", aic326x_enum[WCLK3_ENUM]),
+       SOC_ENUM("BCLK3 Pin Control", aic326x_enum[BCLK3_ENUM]),
+       SOC_ENUM("DOUT3 Pin Control", aic326x_enum[DOUT3_ENUM]),
+       SOC_ENUM("DIN3 Pin Control",  aic326x_enum[DIN3_ENUM]),
+       SOC_ENUM("DAC CLK IN", aic326x_enum[CLKIN_ENUM]),
+       SOC_ENUM("ADC CLK IN", aic326x_enum[CLKIN_ENUM]),
+
+};
+
+/* the sturcture contains the different values for mclk */
+static const struct aic3262_rate_divs aic3262_divs[] = {
+/*
+ * mclk, rate, p_val, pll_j, pll_d, dosr, ndac, mdac, aosr, nadc, madc, blck_N,
+ * codec_speficic_initializations
+ */
+       /* 8k rate */
+#ifdef CONFIG_MINI_DSP
+       {12000000, 8000, 1, 8, 1920, 768, 8, 2, 128, 8, 12, 4,
+               {{0, 60, 0}, {0, 61, 0} } },
+#else
+       {12000000, 8000, 1, 8, 1920, 128, 12, 8, 128, 8, 6, 4,
+               {{0, 60, 1}, {0, 61, 1} } },
+       {12288000, 8000, 1, 1, 3333, 128, 12, 8, 128, 8, 6, 4,
+               {{0, 60, 1}, {0, 61, 1} } },
+       {24000000, 8000, 1, 4, 96, 128, 12, 8, 128, 12, 8, 4,
+               {{0, 60, 1}, {0, 61, 1} } },
+#endif
+       /* 11.025k rate */
+       {12000000, 11025, 1, 1, 8816, 1024, 8, 2, 128, 8, 2, 48,
+               {{0, 60, 1}, {0, 61, 1} } },
+       {12288000, 11025, 1, 1, 8375, 1024, 8, 2, 128, 8, 2, 48,
+               {{0, 60, 1}, {0, 61, 1} } },
+       {24000000, 11025, 1, 3, 7632, 128, 8, 8, 128, 8, 8, 4,
+               {{0, 60, 1}, {0, 61, 1} } },
+
+       /* 16k rate */
+#ifdef CONFIG_MINI_DSP
+       {12000000, 16000, 1, 8, 1920, 384, 4, 4, 128, 4, 12, 12,
+               {{0, 60, 0}, {0, 61, 0} } },
+#else
+       {12000000, 16000, 1, 8, 1920, 128, 8, 6, 128, 8, 6, 4,
+               {{0, 60, 1}, {0, 61, 1} } },
+       {12288000, 16000, 1, 2, 6667, 128, 8, 6, 128, 8, 6, 4,
+               {{0, 60, 1}, {0, 61, 1} } },
+       {24000000, 16000, 1, 4, 96, 128, 8, 6, 128, 8, 6, 4,
+               {{0, 60, 1}, {0, 61, 1} } },
+#endif
+       /* 22.05k rate */
+       {12000000, 22050, 1, 3, 7632, 128, 8, 2, 128, 8, 2, 4,
+               {{0, 60, 1}, {0, 61, 1} } },
+       {12288000, 22050, 1, 3, 675, 128, 8, 2, 128, 8, 2, 4,
+               {{0, 60, 1}, {0, 61, 1} } },
+       {24000000, 22050, 1, 3, 7632, 128, 8, 3, 128, 8, 3, 4,
+               {{0, 60, 1}, {0, 61, 1} } },
+       /* 32k rate */
+       {12000000, 32000, 1, 5, 4613, 128, 8, 2, 128, 8, 2, 4,
+               {{0, 60, 1}, {0, 61, 1} } },
+       {12288000, 32000, 1, 5, 3333, 128, 8, 2, 128, 8, 2, 4,
+               {{0, 60, 1}, {0, 61, 1} } },
+       {24000000, 32000, 1, 4, 96, 128, 6, 4, 128, 6, 4, 4,
+               {{0, 60, 1}, {0, 61, 1} } },
+
+#ifdef CONFIG_MINI_DSP
+       {12000000, 44100, 1, 7, 5264, 128, 2, 8, 128, 2, 8, 4,
+               {{0, 60, 0}, {0, 61, 0} } },
+       {12288000, 44100, 1, 7, 3548, 128, 2, 8, 128, 8, 2, 4,
+               {{0, 60, 0}, {0, 61, 0} } },
+#else
+       /* 44.1k rate */
+       {12000000, 44100, 1, 7, 5264, 128, 8, 2, 128, 8, 2, 4,
+               {{0, 60, 1}, {0, 61, 1} } },
+       {12288000, 44100, 1, 7, 3548, 128, 8, 2, 128, 8, 2, 4,
+               {{0, 60, 1}, {0, 61, 1} } },
+       {24000000, 44100, 1, 3, 7632, 128, 4, 4, 64, 4, 4, 4,
+               {{0, 60, 1}, {0, 61, 1} } },
+#endif
+
+#ifdef CONFIG_MINI_DSP
+       {12288000, 48000, 1, 8, 52, 128, 2, 8, 128, 2, 8, 4,
+               {{0, 60, 0}, {0, 61, 0} } },
+#else
+       /* 48k rate */
+       {12000000, 48000, 1, 8, 1920, 128, 8, 2, 128, 8, 2, 4,
+               {{0, 60, 1}, {0, 61, 1} } },
+       {12288000, 48000, 1, 8, 52, 128, 8, 2, 128, 8, 2, 4,
+               {{0, 60, 1}, {0, 61, 1} } },
+       {24000000, 48000, 1, 4, 960, 128, 4, 4, 128, 4, 4, 4,
+               {{0, 60, 1}, {0, 61, 1} } },
+#endif
+
+       /*96k rate */
+       {12000000, 96000, 1, 16, 3840, 128, 8, 2, 128, 8, 2 , 4,
+               {{0, 60, 7}, {0, 61, 7} } },
+       {24000000, 96000, 1, 4, 960, 128, 4, 2, 128, 4, 2, 2,
+               {{0, 60, 7}, {0, 61, 7} } },
+       /*192k */
+       {12000000, 192000, 1, 32, 7680, 128, 8, 2, 128, 8, 2, 4,
+               {{0, 60, 17}, {0, 61, 13} } },
+       {24000000, 192000, 1, 4, 960, 128, 2, 2, 128, 2, 2, 4,
+               {{0, 60, 17}, {0, 61, 13} } },
+};
+
+
+
+/*
+*----------------------------------------------------------------------------
+* Function : aic3262_multi_i2s_dump_regs
+* Purpose  : This function is to mute or unmute the left and right DAC
+*
+*----------------------------------------------------------------------------
+*/
+static void aic3262_multi_i2s_dump_regs(struct snd_soc_dai *dai)
+{
+       struct snd_soc_codec *codec = dai->codec;
+       struct aic3262_priv *aic3262 = snd_soc_codec_get_drvdata(codec);
+       unsigned int counter;
+
+       DBG(KERN_INFO "#%s: Dai Active %d ASI%d REGS DUMP\n",
+               __func__, aic3262->active_count, dai->id);
+
+       aic3262_change_page(codec, 0);
+       aic3262_change_book(codec, 0);
+
+       DBG(KERN_INFO "#Page0 REGS..\n");
+       for (counter = 0; counter < 85; counter++) {
+               DBG(KERN_INFO "#%2d -> 0x%x\n", counter,
+                       aic3262_read(codec, counter));
+       }
+
+       /*DBG(KERN_INFO "#Page1 REGS..\n");
+       for (counter = 128; counter < 176; counter++) {
+               DBG(KERN_INFO "#%2d -> 0x%x\n", (counter % 128),
+                       aic3262_read(codec, counter));
+       }*/
+
+       DBG(KERN_INFO "#Page4 REGS..\n");
+       for (counter = 512; counter < 631; counter++) {
+               DBG(KERN_INFO "#%2d -> 0x%x\n",
+                       (counter % 128), aic3262_read(codec, counter));
+       }
+
+       for (counter = 0; counter < MAX_ASI_COUNT; counter++) {
+               DBG(KERN_INFO "#ASI%d Frame %s @ %dHz Playback %d Record %d\n",
+               (counter + 1),
+               (aic3262->asiCtxt[counter].master == 1) ? "Master" : "Slave",
+               aic3262->asiCtxt[counter].sampling_rate,
+               aic3262->asiCtxt[counter].playback_mode,
+               aic3262->asiCtxt[counter].capture_mode);
+               DBG(KERN_INFO "#DAC Option [%d,%d] ADC Option %d WLEN %d\n\n",
+               aic3262->asiCtxt[counter].left_dac_output,
+               aic3262->asiCtxt[counter].right_dac_output,
+               aic3262->asiCtxt[counter].adc_input,
+               aic3262->asiCtxt[counter].word_len);
+       }
+       return;
+}
+
+/*
+ *----------------------------------------------------------------------------
+ * Function : aic3262_multi_i2s_mute
+ * Purpose  : This function is to mute or unmute the left and right DAC
+ *
+ *----------------------------------------------------------------------------
+ */
+static int aic3262_multi_i2s_mute(struct snd_soc_dai *dai, int mute)
+{
+       struct snd_soc_codec *codec = dai->codec;
+       struct aic3262_priv *aic3262 = snd_soc_codec_get_drvdata(codec);
+
+       DBG(KERN_INFO "#%s : mute entered with %d\n", __func__, mute);
+
+       /* If we are doing both Recording and Playback on this DAI interface,
+       * do not MUTE the Codec.
+       */
+       if (mute && (aic3262->asiCtxt[dai->id - 1].asi_active > 1)) {
+               DBG("#%s Cannot Mute the ASI%d Now..\n",
+                       __func__, dai->id);
+       } else {
+               switch (dai->id) {
+               case 1:
+                       aic3262_multi_i2s_asi1_mute(dai, mute);
+               break;
+               case 2:
+                       aic3262_multi_i2s_asi2_mute(dai, mute);
+               break;
+               case 3:
+                       aic3262_multi_i2s_asi3_mute(dai, mute);
+               break;
+               default:
+                       printk(KERN_ERR "#%s: Invalid DAI id\n", __func__);
+                       return -EINVAL;
+               }
+       }
+       DBG(KERN_INFO "#%s : mute ended\n", __func__);
+       return 0;
+}
+
+
+/*
+*----------------------------------------------------------------------------
+* Function : aic3262_multi_i2s_asi1_mute
+* Purpose  : This function is to mute or unmute the left and right DAC
+*
+*----------------------------------------------------------------------------
+*/
+static int aic3262_multi_i2s_asi1_mute(struct snd_soc_dai *dai, int mute)
+{
+       struct snd_soc_codec *codec = dai->codec;
+       struct aic3262_priv *aic3262 = snd_soc_codec_get_drvdata(codec);
+
+       DBG(KERN_INFO "#%s : mute %d started\n", __func__, mute);
+
+       if (mute) {
+               DBG(KERN_INFO "Mute if part\n");
+
+               if (!aic3262->asiCtxt[0].port_muted) {
+                       dac_reg = aic3262_read(codec, DAC_MVOL_CONF);
+                       adc_gain = aic3262_read(codec, ADC_FINE_GAIN);
+                       hpl = aic3262_read(codec, HPL_VOL);
+                       hpr = aic3262_read(codec, HPR_VOL);
+                       rec_amp = aic3262_read(codec, REC_AMP_CNTL_R5);
+                       rampr = aic3262_read(codec, RAMPR_VOL);
+                       spk_amp = aic3262_read(codec, SPK_AMP_CNTL_R4);
+               }
+               DBG(KERN_INFO "spk_reg = %2x\n\n", spk_amp);
+
+               /* First check if both Playback and Recording is going on
+               * this interface.
+               */
+               if (aic3262->asiCtxt[0].asi_active > 1) {
+                       DBG("#%s Cannot Mute the ASI Now..\n", __func__);
+               } else if (!(aic3262->asiCtxt[1].playback_mode) &&
+                           !(aic3262->asiCtxt[2].playback_mode)) {
+                       /* Before Muting, please check if any other
+                       * ASI is active. if so, we cannot simply mute the
+                       * DAC and ADC Registers.
+                       */
+                       aic3262_write(codec, DAC_MVOL_CONF,
+                               ((dac_reg & 0xF3) | 0x0C));
+                       aic3262_write(codec, ADC_FINE_GAIN,
+                               ((adc_gain & 0x77) | 0x88));
+                       aic3262_write(codec, HPL_VOL, 0xB9);
+                       aic3262_write(codec, HPR_VOL, 0xB9);
+                       aic3262_write(codec, REC_AMP_CNTL_R5, 0x39);
+                       aic3262_write(codec, RAMPR_VOL, 0x39);
+                       aic3262_write(codec, SPK_AMP_CNTL_R4, 0x00);
+                       aic3262->asiCtxt[0].port_muted = 1;
+               } else {
+                       DBG(KERN_INFO
+                       "#%s: Other ASI Active. Cannot MUTE Codec..\n",
+                               __func__);
+               }
+       } else {
+               DBG(KERN_INFO "Mute else part\n");
+               aic3262_write(codec, DAC_MVOL_CONF, (dac_reg & 0xF3));
+               mdelay(5);
+               aic3262_write(codec, ADC_FINE_GAIN, (adc_gain & 0x77));
+               mdelay(5);
+               aic3262_write(codec, HPL_VOL, hpl);
+               mdelay(5);
+               aic3262_write(codec, HPR_VOL, hpr);
+               mdelay(5);
+               aic3262_write(codec, REC_AMP_CNTL_R5, rec_amp);
+               mdelay(5);
+               aic3262_write(codec, RAMPR_VOL, rampr);
+               mdelay(5);
+               aic3262_write(codec, SPK_AMP_CNTL_R4, spk_amp);
+               mdelay(5);
+
+               /* Basic hack */
+               aic3262_write(codec, LINE_AMP_CNTL_R1, 0xc3);
+               aic3262_write(codec, HP_AMP_CNTL_R1, 0x33);
+
+               aic3262->asiCtxt[0].port_muted = 0;
+               aic3262_multi_i2s_dump_regs(dai);
+       }
+
+       DBG(KERN_INFO "#%s : mute %d ended\n", __func__, mute);
+
+       return 0;
+}
+
+/*
+*----------------------------------------------------------------------------
+* Function : aic3262_multi_i2s_asi2_maic3262_asi3_clk_configute
+* Purpose  : This function is to mute or unmute the left and right DAC
+*
+*----------------------------------------------------------------------------
+*/
+static int aic3262_multi_i2s_asi2_mute(struct snd_soc_dai *dai, int mute)
+{
+       struct snd_soc_codec *codec = dai->codec;
+       struct aic3262_priv *aic3262 = snd_soc_codec_get_drvdata(codec);
+
+       DBG(KERN_INFO "#%s : mute %d started\n", __func__, mute);
+
+       if (mute) {
+               DBG(KERN_INFO "Mute if part\n");
+
+               if (!aic3262->asiCtxt[1].port_muted) {
+                       dac_reg = aic3262_read(codec, DAC_MVOL_CONF);
+                       adc_gain = aic3262_read(codec, ADC_FINE_GAIN);
+                       hpl = aic3262_read(codec, HPL_VOL);
+                       hpr = aic3262_read(codec, HPR_VOL);
+                       rec_amp = aic3262_read(codec, REC_AMP_CNTL_R5);
+                       rampr = aic3262_read(codec, RAMPR_VOL);
+                       spk_amp = aic3262_read(codec, SPK_AMP_CNTL_R4);
+                       DBG(KERN_INFO "spk_reg = %2x\n\n", spk_amp);
+               }
+
+               /* First check if both Playback and Recording is going on
+               * this interface.
+               */
+               if (aic3262->asiCtxt[1].asi_active > 1) {
+                       DBG("#%s Cannot Mute the ASI Now..\n", __func__);
+               } else if (!(aic3262->asiCtxt[0].playback_mode) &&
+                           !(aic3262->asiCtxt[2].playback_mode)) {
+                       /* Before Muting, please check if any other
+                       * ASI is active. if so, we cannot simply mute the
+                       * DAC and ADC Registers.
+                       */
+                       aic3262_write(codec, DAC_MVOL_CONF,
+                               ((dac_reg & 0xF3) | 0x0C));
+                       aic3262_write(codec, ADC_FINE_GAIN,
+                               ((adc_gain & 0x77) | 0x88));
+                       aic3262_write(codec, HPL_VOL, 0xB9);
+                       aic3262_write(codec, HPR_VOL, 0xB9);
+                       aic3262_write(codec, REC_AMP_CNTL_R5, 0x39);
+                       aic3262_write(codec, RAMPR_VOL, 0x39);
+                       aic3262_write(codec, SPK_AMP_CNTL_R4, 0x00);
+                       aic3262->asiCtxt[1].port_muted = 1;
+               } else {
+                       DBG("#%s: Other ASI Active. Cannot MUTE Codec..\n",
+                               __func__);
+               }
+       } else {
+               DBG(KERN_INFO "Mute else part\n");
+               aic3262_write(codec, DAC_MVOL_CONF, (dac_reg & 0xF3));
+               mdelay(5);
+               aic3262_write(codec, ADC_FINE_GAIN, (adc_gain & 0x77));
+               mdelay(5);
+               aic3262_write(codec, HPL_VOL, hpl);
+               mdelay(5);
+               aic3262_write(codec, HPR_VOL, hpr);
+               mdelay(5);
+               aic3262_write(codec, REC_AMP_CNTL_R5, rec_amp);
+               mdelay(5);
+               aic3262_write(codec, RAMPR_VOL, rampr);
+               mdelay(5);
+               aic3262_write(codec, SPK_AMP_CNTL_R4, spk_amp);
+               mdelay(5);
+
+               /* Basic hack */
+               aic3262_write(codec, LINE_AMP_CNTL_R1, 0xc3);
+               aic3262_write(codec, HP_AMP_CNTL_R1, 0x33);
+
+               aic3262->asiCtxt[1].port_muted = 0;
+               aic3262_multi_i2s_dump_regs(dai);
+       }
+
+       DBG(KERN_INFO "#%s : mute %d ended\n", __func__, mute);
+
+       return 0;
+}
+/*
+*----------------------------------------------------------------------------
+* Function : aic3262_multi_i2s_asi3_mute
+* Purpose  : This function is to mute or unmute the left and right DAC
+*
+*----------------------------------------------------------------------------
+*/
+static int aic3262_multi_i2s_asi3_mute(struct snd_soc_dai *dai, int mute)
+{
+       struct snd_soc_codec *codec = dai->codec;
+       struct aic3262_priv *aic3262 = snd_soc_codec_get_drvdata(codec);
+
+       DBG(KERN_INFO "#%s : mute %d started\n", __func__, mute);
+
+       if (mute) {
+               DBG("Mute if part\n");
+
+               if (!aic3262->asiCtxt[2].port_muted) {
+                       dac_reg = aic3262_read(codec, DAC_MVOL_CONF);
+                       adc_gain = aic3262_read(codec, ADC_FINE_GAIN);
+                       hpl = aic3262_read(codec, HPL_VOL);
+                       hpr = aic3262_read(codec, HPR_VOL);
+                       rec_amp = aic3262_read(codec, REC_AMP_CNTL_R5);
+                       rampr = aic3262_read(codec, RAMPR_VOL);
+                       spk_amp = aic3262_read(codec, SPK_AMP_CNTL_R4);
+               }
+               DBG("spk_reg = %2x\n\n", spk_amp);
+
+               /* First check if both Playback and Recording is going on
+               * this interface.
+               */
+               if (aic3262->asiCtxt[2].asi_active > 1) {
+                       DBG("#%s Cannot Mute the ASI Now..\n", __func__);
+               } else if (!(aic3262->asiCtxt[0].playback_mode) &&
+                           !(aic3262->asiCtxt[1].playback_mode)) {
+                       /* Before Muting, please check if any other
+                       * ASI is active. if so, we cannot simply mute the
+                       * DAC and ADC Registers.
+                       */
+                       aic3262_write(codec, DAC_MVOL_CONF,
+                               ((dac_reg & 0xF3) | 0x0C));
+                       aic3262_write(codec, ADC_FINE_GAIN,
+                               ((adc_gain & 0x77) | 0x88));
+                       aic3262_write(codec, HPL_VOL, 0xB9);
+                       aic3262_write(codec, HPR_VOL, 0xB9);
+                       aic3262_write(codec, REC_AMP_CNTL_R5, 0x39);
+                       aic3262_write(codec, RAMPR_VOL, 0x39);
+                       aic3262_write(codec, SPK_AMP_CNTL_R4, 0x00);
+                       aic3262->asiCtxt[2].port_muted = 1;
+               } else {
+                       DBG("#%s: Other ASI Active. Cannot MUTE Codec..\n",
+                               __func__);
+               }
+       } else {
+               DBG("Mute else part\n");
+               aic3262_write(codec, DAC_MVOL_CONF, (dac_reg & 0xF3));
+               mdelay(5);
+               aic3262_write(codec, ADC_FINE_GAIN, (adc_gain & 0x77));
+               mdelay(5);
+               aic3262_write(codec, HPL_VOL, hpl);
+               mdelay(5);
+               aic3262_write(codec, HPR_VOL, hpr);
+               mdelay(5);
+               aic3262_write(codec, REC_AMP_CNTL_R5, rec_amp);
+               mdelay(5);
+               aic3262_write(codec, RAMPR_VOL, rampr);
+               mdelay(5);
+               aic3262_write(codec, SPK_AMP_CNTL_R4, spk_amp);
+               mdelay(5);
+
+               /* Basic hack */
+               aic3262_write(codec, LINE_AMP_CNTL_R1, 0xc3);
+               aic3262_write(codec, HP_AMP_CNTL_R1, 0x33);
+
+               aic3262->asiCtxt[2].port_muted = 0;
+               aic3262_multi_i2s_dump_regs(dai);
+       }
+
+       DBG(KERN_INFO "#%s : mute %d ended\n", __func__, mute);
+
+       return 0;
+}
+
+/*
+ *----------------------------------------------------------------------------
+ * Function : aic3262_multi_i2s_set_dai_fmt
+ * Purpose  : This function is to set the DAI format
+ *
+ *----------------------------------------------------------------------------
+ */
+static int aic3262_multi_i2s_set_dai_fmt(struct snd_soc_dai *codec_dai,
+               unsigned int fmt)
+{
+       /* Check the DAI Id and based on that switch the configuration for
+       * the Individual ASI Port.
+       */
+       switch (codec_dai->id) {
+       case 1:
+               aic3262_multi_i2s_asi1_set_dai_fmt(codec_dai, fmt);
+       break;
+       case 2:
+               aic3262_multi_i2s_asi2_set_dai_fmt(codec_dai, fmt);
+       break;
+       case 3:
+               aic3262_multi_i2s_asi3_set_dai_fmt(codec_dai, fmt);
+       break;
+       default:
+               printk(KERN_ERR
+                       "#%s: Invalid DAI interface format\n", __func__);
+               return -EINVAL;
+       }
+       return 0;
+}
+
+
+
+/*
+*----------------------------------------------------------------------------
+* Function : aic3262_multi_i2s_asi1_set_dai_fmt
+* Purpose  : This function is to set the DAI format for ASI1 Port
+*
+*----------------------------------------------------------------------------
+*/
+static int aic3262_multi_i2s_asi1_set_dai_fmt(struct snd_soc_dai *codec_dai,
+               unsigned int fmt)
+{
+       struct snd_soc_codec *codec = codec_dai->codec;
+       struct aic3262_priv *aic3262 = snd_soc_codec_get_drvdata(codec);
+       u8 iface_reg, clk_reg;
+       u8 regvalue;
+
+       DBG(KERN_INFO "%s: DAI_ID %d fmt %d\n",
+               __func__, codec_dai->id, fmt);
+
+       /* Read the B0_P4_R4 and B0_P4_R10 Registers to configure the
+       * ASI1 Bus and Clock Formats depending on the PCM Format.
+       */
+       iface_reg = aic3262_read(codec, ASI1_BUS_FMT);
+       clk_reg   = aic3262_read(codec, ASI1_BWCLK_CNTL_REG);
+
+       /* set master/slave audio interface */
+       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+       case SND_SOC_DAIFMT_CBM_CFM:
+               DBG(KERN_INFO "#%s: Configuring ASI%d as Frame Master..\n",
+                       __func__, codec_dai->id);
+               aic3262->asiCtxt[0].master = 1;
+               clk_reg |= (BIT5 | BIT2);       /* Codec Interface as Master */
+       break;
+       case SND_SOC_DAIFMT_CBS_CFS:
+               DBG(KERN_INFO "#%s: Configuring ASI%d as Frame Slave..\n",
+                       __func__, codec_dai->id);
+               clk_reg &= ~0xFC; /* Reset bits D[7:5] and D[4:2] to zero */
+               aic3262->asiCtxt[0].master = 0;
+       break;
+       case SND_SOC_DAIFMT_CBS_CFM:
+               /* new case..just for debugging */
+               DBG(KERN_INFO "%s: SND_SOC_DAIFMT_CBS_CFM\n", __func__);
+               aic3262->asiCtxt[0].master = 0;
+               clk_reg |= BIT5;        /* Only WCLK1 Output from Codec */
+               clk_reg &= ~0x1C;       /* BCLK1 Input to Codec */
+       break;
+       default:
+               printk(KERN_ERR "#%s: Invalid DAI master/slave interface\n",
+                       __func__);
+               return -EINVAL;
+       }
+       aic3262->asiCtxt[0].pcm_format = (fmt & SND_SOC_DAIFMT_FORMAT_MASK);
+       /* interface format */
+       switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+       case SND_SOC_DAIFMT_I2S:
+               DBG(KERN_INFO "#%s: Configuring ASI%d for I2s Mode..\n",
+                       __func__, codec_dai->id);
+               iface_reg = (iface_reg & 0x1f);
+       break;
+       case SND_SOC_DAIFMT_DSP_A:
+               DBG(KERN_INFO "#%s: Configuring ASI%d for DSP_A Mode..\n",
+                       __func__, codec_dai->id);
+               iface_reg = (iface_reg & 0x1f) | 0x20;
+       break;
+       case SND_SOC_DAIFMT_RIGHT_J:
+               iface_reg = (iface_reg & 0x1f) | 0x40;
+       break;
+       case SND_SOC_DAIFMT_LEFT_J:
+               iface_reg = (iface_reg & 0x1f) | 0x60;
+       break;
+       case SND_SOC_DAIFMT_DSP_B:
+               DBG(KERN_INFO "#%s: Configuring ASI%d for DSP_B Mode..\n",
+                       __func__, codec_dai->id);
+               iface_reg = (iface_reg & 0x1f) | 0x80;
+               /* voice call need data offset in 1 bitclock */
+               aic3262_write(codec, ASI1_LCH_OFFSET, 1);
+       break;
+       default:
+               printk(KERN_ERR
+                       "#%s: Invalid DAI interface format\n", __func__);
+               return -EINVAL;
+       }
+       /* Also Configure the Pin Control Registers before writing into
+       * the ASI specific Clock Control and Format Registers
+       */
+
+       /* Configure B0_P4_R65_D[5:2] to 001 This configures the
+       * WCLK1 Pin to ASI1
+       */
+       regvalue = aic3262_read(codec, WCLK1_PIN_CNTL_REG);
+       aic3262_write(codec, WCLK1_PIN_CNTL_REG, (regvalue | BIT2));
+
+       /* Configure B0_P4_R68_d[6:5] = 01 and B0_P4_R67_D[4:1] to 0001
+       * to ensure that the DIN1 and DOUT1 Pins are configured
+       * correctly
+       */
+       regvalue = aic3262_read(codec, DIN1_PIN_CNTL_REG);
+       aic3262_write(codec, DIN1_PIN_CNTL_REG, (regvalue | BIT5));
+       regvalue = aic3262_read(codec, DOUT1_PIN_CNTL_REG);
+       aic3262_write(codec, DOUT1_PIN_CNTL_REG, (regvalue | BIT1));
+
+       aic3262_write(codec, ASI1_BWCLK_CNTL_REG, clk_reg);
+
+       aic3262_write(codec, ASI1_BUS_FMT, iface_reg);
+
+       return 0;
+}
+
+
+/*
+*----------------------------------------------------------------------------
+* Function : aic3262_multi_i2s_asi2_set_dai_fmt
+* Purpose  : This function is to set the DAI format for ASI2 Port
+*
+*----------------------------------------------------------------------------
+*/
+static int aic3262_multi_i2s_asi2_set_dai_fmt(struct snd_soc_dai *codec_dai,
+                       unsigned int fmt)
+{
+       struct snd_soc_codec *codec = codec_dai->codec;
+       struct aic3262_priv *aic3262 = snd_soc_codec_get_drvdata(codec);
+       u8 iface_reg, clk_reg;
+       u8 regvalue;
+
+       DBG(KERN_INFO "%s: DAI_ID %d fmt %d\n",
+               __func__, codec_dai->id, fmt);
+
+       /* Read the B0_P4_R17 and B0_P4_R26 Registers to configure the
+       * ASI1 Bus and Clock Formats depending on the PCM Format.
+       */
+       iface_reg = aic3262_read(codec, ASI2_BUS_FMT);
+       clk_reg   = aic3262_read(codec, ASI2_BWCLK_CNTL_REG);
+       /*
+       iface_reg = ifce_reg & ~(3 << 6 | 3 << 2);
+       */
+
+       /* set master/slave audio interface */
+       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+       case SND_SOC_DAIFMT_CBM_CFM:
+               DBG(KERN_INFO "#%s: Configuring ASI%d as Frame Master..\n",
+                       __func__, codec_dai->id);
+               aic3262->asiCtxt[1].master = 1;
+               clk_reg |= (BIT5 | BIT2);
+       break;
+       case SND_SOC_DAIFMT_CBS_CFS:
+               DBG(KERN_INFO "#%s: Configuring ASI%d as Frame Slave..\n",
+                       __func__, codec_dai->id);
+
+               clk_reg &= ~0xFC;
+               aic3262->asiCtxt[1].master = 0;
+       break;
+       case SND_SOC_DAIFMT_CBS_CFM:
+               /*new case..just for debugging */
+               DBG(KERN_INFO "%s: SND_SOC_DAIFMT_CBS_CFM\n", __func__);
+               aic3262->asiCtxt[1].master = 0;
+               clk_reg |= BIT5;
+               clk_reg &= ~0x1C;
+       break;
+       default:
+               printk(KERN_ERR "#%s:Invalid DAI master/slave interface\n",
+                       __func__);
+               return -EINVAL;
+       }
+       aic3262->asiCtxt[1].pcm_format = (fmt & SND_SOC_DAIFMT_FORMAT_MASK);
+       /* interface format */
+       switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+       case SND_SOC_DAIFMT_I2S:
+               DBG(KERN_INFO "#%s: Configuring ASI%d for I2S Mode..\n",
+                               __func__, codec_dai->id);
+               iface_reg = (iface_reg & 0x1f);
+       break;
+       case SND_SOC_DAIFMT_DSP_A:
+               DBG(KERN_INFO "#%s: Configuring ASI%d for DSP_A Mode..\n",
+                       __func__, codec_dai->id);
+               iface_reg = (iface_reg & 0x1f) | 0x20;
+       break;
+       case SND_SOC_DAIFMT_RIGHT_J:
+               iface_reg = (iface_reg & 0x1f) | 0x40;
+       break;
+       case SND_SOC_DAIFMT_LEFT_J:
+               iface_reg = (iface_reg & 0x1f) | 0x60;
+       break;
+       case SND_SOC_DAIFMT_DSP_B:
+               DBG(KERN_INFO "#%s: Configuring ASI%d for DSP Mode..\n",
+                       __func__, codec_dai->id);
+               iface_reg = (iface_reg & 0x1f) | 0x80;
+               /* voice call need data offset in 1 bitclock */
+               aic3262_write(codec, ASI2_LCH_OFFSET, 1);
+       break;
+       default:
+               printk(KERN_ERR "#%s:Invalid DAI interface format\n", __func__);
+               return -EINVAL;
+       }
+
+       /* Also Configure the Pin Control Registers before writing into
+       * the ASI2 specific Clock Control and Format Registers
+       */
+
+       /* Configure B0_P4_R69_D[5:2] to 001 This configures the
+       * WCLK2 Pin to ASI2
+       */
+
+       regvalue = aic3262_read(codec, WCLK2_PIN_CNTL_REG);
+       aic3262_write(codec, WCLK2_PIN_CNTL_REG, (regvalue | BIT2));
+
+       regvalue = aic3262_read(codec, BCLK2_PIN_CNTL_REG);
+       aic3262_write(codec, BCLK2_PIN_CNTL_REG, (regvalue | BIT2));
+
+       /* Configure B0_P4_R72_d[6:5] = 01 and B0_P4_R71_D[4:1] to 0001
+        * to ensure that the DIN2 and DOUT2 Pins are configured
+        * correctly
+        */
+       regvalue = aic3262_read(codec, DIN2_PIN_CNTL_REG);
+       aic3262_write(codec, DIN2_PIN_CNTL_REG, (regvalue | BIT5));
+
+       regvalue = aic3262_read(codec, DOUT2_PIN_CNTL_REG);
+       aic3262_write(codec, DOUT2_PIN_CNTL_REG, (regvalue | BIT5 | BIT1));
+
+       aic3262_write(codec, ASI2_BWCLK_CNTL_REG, clk_reg);
+
+       aic3262_write(codec, ASI2_BUS_FMT, iface_reg);
+
+       return 0;
+}
+
+/*
+*----------------------------------------------------------------------------
+* Function : aic3262_multi_i2s_asi3_set_dai_fmt
+* Purpose  : This function is to set the DAI format for ASI3 Port
+*
+*----------------------------------------------------------------------------
+*/
+static int aic3262_multi_i2s_asi3_set_dai_fmt(struct snd_soc_dai *codec_dai,
+                       unsigned int fmt)
+{
+       struct snd_soc_codec *codec = codec_dai->codec;
+       struct aic3262_priv *aic3262 = snd_soc_codec_get_drvdata(codec);
+       u8 iface_reg, clk_reg;
+       u8 regvalue;
+
+       DBG(KERN_INFO "%s: DAI_ID %d fmt %d\n",
+               __func__, codec_dai->id, fmt);
+
+       /* Read the B0_P4_R33 and B0_P4_R42 Registers to configure the
+       * ASI1 Bus and Clock Formats depending on the PCM Format.
+       */
+       iface_reg = aic3262_read(codec, ASI3_BUS_FMT);
+       clk_reg   = aic3262_read(codec, ASI3_BWCLK_CNTL_REG);
+
+       /* set master/slave audio interface */
+       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+       case SND_SOC_DAIFMT_CBM_CFM:
+               DBG(KERN_INFO "#%s: Configuring ASI%d as Frame Master..\n",
+                       __func__, codec_dai->id);
+               aic3262->asiCtxt[2].master = 1;
+               clk_reg |= (BIT5 | BIT2);
+       break;
+       case SND_SOC_DAIFMT_CBS_CFS:
+               DBG(KERN_INFO "#%s: Configuring ASI%d as Frame Slave..\n",
+                       __func__, codec_dai->id);
+               clk_reg &= ~0xFC;
+               aic3262->asiCtxt[2].master = 0;
+       break;
+       case SND_SOC_DAIFMT_CBS_CFM:
+               /* new case..just for debugging */
+               DBG(KERN_INFO "%s: SND_SOC_DAIFMT_CBS_CFM\n", __func__);
+               aic3262->asiCtxt[2].master = 0;
+               clk_reg |= BIT5;
+               clk_reg &= ~0x1C;
+       break;
+       default:
+               printk(KERN_ERR "Invalid DAI master/slave interface\n");
+               return -EINVAL;
+       }
+       aic3262->asiCtxt[2].pcm_format = (fmt & SND_SOC_DAIFMT_FORMAT_MASK);
+       /* interface format */
+       switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+       case SND_SOC_DAIFMT_I2S:
+               DBG(KERN_INFO "#%s: Configuring ASI%d for I2S Mode..\n",
+                       __func__, codec_dai->id);
+               iface_reg = (iface_reg & 0x1f);
+       break;
+       case SND_SOC_DAIFMT_DSP_A:
+               DBG(KERN_INFO "#%s: Configuring ASI%d for DSP_A Mode..\n",
+                       __func__, codec_dai->id);
+               iface_reg = (iface_reg & 0x1f) | 0x20;
+       break;
+       case SND_SOC_DAIFMT_RIGHT_J:
+               iface_reg = (iface_reg & 0x1f) | 0x40;
+       break;
+       case SND_SOC_DAIFMT_LEFT_J:
+               iface_reg = (iface_reg & 0x1f) | 0x60;
+       break;
+       case SND_SOC_DAIFMT_DSP_B:
+               DBG(KERN_INFO "#%s: Configuring ASI%d for DSP Mode..\n",
+                       __func__, codec_dai->id);
+               iface_reg = (iface_reg & 0x1f) | 0x80;
+               /* voice call need data offset in 1 bitclock */
+               aic3262_write(codec, ASI3_LCH_OFFSET, 1);
+       break;
+       default:
+               printk(KERN_ERR
+                       "#%s: Invalid DAI interface format\n", __func__);
+               return -EINVAL;
+       }
+
+       /* Also Configure the Pin Control Registers before writing into
+       * the ASI specific Clock Control and Format Registers
+       */
+       /* Configure B0_P4_R73_D[5:2] to 0001 This configures the
+       * WCLK1 Pin to ASI1
+       */
+       regvalue = aic3262_read(codec, WCLK3_PIN_CNTL_REG);
+       aic3262_write(codec, WCLK3_PIN_CNTL_REG, (regvalue | BIT2));
+
+       regvalue = aic3262_read(codec, BCLK3_PIN_CNTL_REG);
+       aic3262_write(codec, BCLK3_PIN_CNTL_REG, (regvalue | BIT2));
+
+       /* Configure B0_P4_R76_d[6:5] = 01 and B0_P4_R75_D[4:1] to 0001
+       * to ensure that the DIN1 and DOUT1 Pins are configured
+       * correctly
+       */
+       regvalue = aic3262_read(codec, DIN3_PIN_CNTL_REG);
+       aic3262_write(codec, DIN3_PIN_CNTL_REG, (regvalue | BIT5));
+       regvalue = aic3262_read(codec, DOUT3_PIN_CNTL_REG);
+       aic3262_write(codec, DOUT3_PIN_CNTL_REG, (regvalue | BIT1));
+
+       aic3262_write(codec, ASI3_BWCLK_CNTL_REG, clk_reg);
+
+       aic3262_write(codec, ASI3_BUS_FMT, iface_reg);
+
+       return 0;
+}
+
+/*
+ * Clock after PLL and dividers
+ */
+static int aic3262_multi_i2s_set_dai_sysclk(struct snd_soc_dai *codec_dai,
+               int clk_id, unsigned int freq, int dir)
+{
+       struct snd_soc_codec *codec = codec_dai->codec;
+       struct aic3262_priv *aic3262 = snd_soc_codec_get_drvdata(codec);
+
+       DBG(KERN_INFO "#%s: DAI ID %d Freq %d Direction %d\n",
+                       __func__, codec_dai->id, freq, dir);
+       switch (freq) {
+       case AIC3262_FREQ_12000000:
+       case AIC3262_FREQ_12288000:
+               aic3262->sysclk = freq;
+               return 0;
+       case AIC3262_FREQ_24000000:
+               aic3262->sysclk = freq;
+               return 0;
+               break;
+       }
+       printk(KERN_ERR "Invalid frequency to set DAI system clock\n");
+       return -EINVAL;
+}
+
+/*
+* aic3262_multi_i2s_set_pll
+*
+* This function is invoked as part of the PLL call-back
+* handler from the ALSA layer.
+*/
+static int aic3262_multi_i2s_set_dai_pll(struct snd_soc_dai *codec_dai,
+               int pll_id, int source, unsigned int freq_in,
+               unsigned int freq_out)
+{
+       /*u16 reg, enable;
+       int offset;
+       struct snd_soc_codec *codec = codec_dai->codec;*/
+
+       printk(KERN_INFO "%s: DAI ID %d PLL_ID %d InFreq %d OutFreq %d\n",
+               __func__, pll_id, codec_dai->id, freq_in, freq_out);
+
+       return 0;
+}
+
+/*
+* aic3262_asi1_clk_config
+*
+* This function is used to configure the BCLK1, WCLK1 pins which
+* are specific to ASI1 Interface. This function just enables the
+* BCLk and WCLK  along with the miniDSP Port Control Registers.
+* However, depending on the user requirement, this function can also be
+* extended to configure the sourc for the BCLK and WCLK on a ASI basis.
+*/
+static int aic3262_asi1_clk_config(struct snd_soc_codec *codec,
+               struct snd_pcm_hw_params *params)
+{
+       u8 bclk_N_value, wclk_N_value;
+       u8 minidspD_data, minidspA_data;
+       u8 regval;
+
+       struct aic3262_priv *aic3262 = snd_soc_codec_get_drvdata(codec);
+
+       DBG(KERN_INFO "%s: Invoked\n",  __func__);
+
+       if (aic3262->asiCtxt[0].master == 1) {
+               DBG(KERN_INFO
+               "#%s: Codec Master on ASI1 Port. Enabling BCLK WCLK Divider.\n",
+                       __func__);
+               bclk_N_value = aic3262->asiCtxt[0].bclk_div;
+               aic3262_write(codec, ASI1_BCLK_N, (bclk_N_value | 0x80));
+
+               wclk_N_value = aic3262_read(codec, ASI1_WCLK_N);
+               aic3262_write(codec, ASI1_WCLK_N, (wclk_N_value | 0xA0));
+       }
+       /* Configure the BCLK and WCLK Output Mux Options */
+       regval = aic3262_read(codec, ASI1_BWCLK_OUT_CNTL);
+       regval &= ~(AIC3262_ASI_BCLK_MUX_MASK | AIC3262_ASI_WCLK_MUX_MASK);
+
+       regval |= (aic3262->asiCtxt[0].bclk_output <<
+                       AIC3262_ASI_BCLK_MUX_SHIFT);
+       regval |= aic3262->asiCtxt[0].wclk_output;
+       aic3262_write(codec, ASI1_BWCLK_OUT_CNTL, regval);
+
+       /* Configure the corresponding miniDSP Data Ports */
+       minidspD_data = aic3262_read(codec, MINIDSP_PORT_CNTL_REG);
+       minidspD_data &= ~(BIT5 | BIT4);
+       aic3262_write(codec, MINIDSP_PORT_CNTL_REG, minidspD_data);
+
+       minidspA_data = aic3262_read(codec, ASI1_ADC_INPUT_CNTL);
+       minidspA_data &= ~(BIT2 | BIT1 | BIT0);
+       minidspA_data |= aic3262->asiCtxt[0].adc_input;
+       aic3262_write(codec, ASI1_ADC_INPUT_CNTL, minidspA_data);
+
+       return 0;
+
+}
+
+/*
+* aic3262_asi2_clk_config
+*
+* This function is used to configure the BCLK2, WCLK2 pins which
+* are specific to ASI2 Interface. This function just enables the
+* BCLk and WCLK  along with the miniDSP Port Control Registers.
+* However, depending on the user requirement, this function can also be
+* extended to configure the sourc for the BCLK and WCLK on a ASI basis.
+*/
+static int aic3262_asi2_clk_config(struct snd_soc_codec *codec,
+               struct snd_pcm_hw_params *params)
+{
+       u8 bclk_N_value, wclk_N_value, minidspD_data, minidspA_data;
+       u8 regval;
+
+       struct aic3262_priv *aic3262 = snd_soc_codec_get_drvdata(codec);
+
+       DBG(KERN_INFO "%s: Invoked\n",  __func__);
+
+       if (aic3262->asiCtxt[1].master == 1) {
+               DBG(KERN_INFO
+               "#%s: Codec Master on ASI2 Port. Enabling BCLK WCLK Divider.\n",
+                       __func__);
+               bclk_N_value = aic3262->asiCtxt[1].bclk_div;
+               aic3262_write(codec, ASI2_BCLK_N, (bclk_N_value | 0x80));
+
+               wclk_N_value = aic3262_read(codec, ASI2_WCLK_N);
+               aic3262_write(codec, ASI2_WCLK_N, (wclk_N_value | 0xA0));
+       }
+       /* Configure the BCLK and WCLK Output Mux Options */
+       regval = aic3262_read(codec, ASI2_BWCLK_OUT_CNTL);
+       regval &= ~(AIC3262_ASI_BCLK_MUX_MASK | AIC3262_ASI_WCLK_MUX_MASK);
+       regval |= (aic3262->asiCtxt[1].bclk_output <<
+                       AIC3262_ASI_BCLK_MUX_SHIFT);
+       regval |= aic3262->asiCtxt[1].wclk_output;
+
+       aic3262_write(codec, ASI2_BWCLK_OUT_CNTL, regval);
+       /* Configure the corresponding miniDSP Data Ports */
+       minidspD_data = aic3262_read(codec, MINIDSP_PORT_CNTL_REG);
+       minidspD_data |= (BIT2);
+       aic3262_write(codec, MINIDSP_PORT_CNTL_REG, minidspD_data);
+
+       minidspA_data = aic3262_read(codec, ASI2_ADC_INPUT_CNTL);
+       minidspA_data &= ~(BIT2 | BIT1 | BIT0);
+       minidspA_data |= aic3262->asiCtxt[1].adc_input;
+       aic3262_write(codec, ASI2_ADC_INPUT_CNTL, minidspA_data);
+
+       return 0;
+
+}
+
+/*
+* aic3262_asi3_clk_config
+*
+* This function is used to configure the BCLK3, WCLK3 pins which
+* are specific to ASI3 Interface. This function just enables the
+* BCLk and WCLK  along with the miniDSP Port Control Registers.
+* However, depending on the user requirement, this function can also be
+* extended to configure the sourc for the BCLK and WCLK on a ASI basis.
+*/
+static int aic3262_asi3_clk_config(struct snd_soc_codec *codec,
+               struct snd_pcm_hw_params *params)
+{
+       u8 bclk_N_value, wclk_N_value, minidspD_data, minidspA_data;
+       u8 regval;
+
+       struct aic3262_priv *aic3262 = snd_soc_codec_get_drvdata(codec);
+
+       DBG(KERN_INFO "%s:\n",  __func__);
+
+       if (aic3262->asiCtxt[2].master == 1) {
+               DBG(KERN_INFO
+               "#%s: Codec Master on ASI3 Port. Enabling BCLK WCLK Divider.\n",
+                       __func__);
+               bclk_N_value = aic3262->asiCtxt[2].bclk_div;
+               aic3262_write(codec, ASI2_BCLK_N, (bclk_N_value | 0x80));
+
+               wclk_N_value = aic3262_read(codec, ASI3_WCLK_N);
+               aic3262_write(codec, ASI3_WCLK_N, (wclk_N_value | 0xA0));
+       }
+
+       /* Configure the BCLK and WCLK Output Mux Options */
+       regval = aic3262_read(codec, ASI3_BWCLK_OUT_CNTL);
+       regval &= ~(AIC3262_ASI_BCLK_MUX_MASK | AIC3262_ASI_WCLK_MUX_MASK);
+       regval |= (aic3262->asiCtxt[2].bclk_output <<
+                       AIC3262_ASI_BCLK_MUX_SHIFT);
+       regval |= aic3262->asiCtxt[2].wclk_output;
+       aic3262_write(codec, ASI3_BWCLK_OUT_CNTL, regval);
+
+       minidspD_data = aic3262_read(codec, MINIDSP_PORT_CNTL_REG);
+       minidspD_data |= (BIT1);
+       aic3262_write(codec, MINIDSP_PORT_CNTL_REG, minidspD_data);
+
+       minidspA_data = aic3262_read(codec, ASI3_ADC_INPUT_CNTL);
+       minidspA_data &= ~(BIT2 | BIT1 | BIT0);
+       minidspA_data |= aic3262->asiCtxt[2].adc_input;
+       aic3262_write(codec, ASI3_ADC_INPUT_CNTL, minidspA_data);
+
+       return 0;
+
+}
+
+/*
+* aic3262_multi_i2s_hw_params
+*
+* This function is used to configure the individual ASI port registers
+* depending on the configuration passed on by the snd_pcm_hw_params
+* structure.
+* This function internally configures the ASI specific pins and clock
+* Control Registers.
+*/
+static int aic3262_multi_i2s_hw_params(struct snd_pcm_substream *substream,
+                       struct snd_pcm_hw_params *params,
+                       struct snd_soc_dai *dai)
+{
+       int i, j;
+       u8 data;
+       u16 regoffset = 0;
+       u8 dacpath = 0;
+       u8 adcpath = 0;
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_codec *codec = rtd->codec;
+       struct aic3262_priv *aic3262 = snd_soc_codec_get_drvdata(codec);
+
+       DBG(KERN_INFO "#%s: Invoked for ASI%d Port for %s Mode\n",
+               __func__, dai->id,
+               (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+               ? "Playback" : "Record");
+
+       i = aic3262_get_divs(aic3262->sysclk, params_rate(params));
+
+       i2c_verify_book0(codec);
+
+       if (i < 0) {
+               printk(KERN_ERR "#%s: Sampling rate %d not supported\n",
+                       __func__, params_rate(params));
+               return i;
+       }
+
+       aic3262_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+
+       /* Configure the PLL J, R D values only if none of the ASI
+       * Interfaces are Active.
+       */
+       /*if (!(AIC3262_MULTI_ASI_ACTIVE(aic3262))) {*/
+       if (1) {
+               DBG(KERN_INFO "#%s: None of the ASIs active yet...\n",
+                       __func__);
+               /*We will fix R value to 1 and make P & J=K.D as variable */
+               /* Setting P & R values are set to 1 and 1 at init*/
+
+               /* J value */
+               aic3262_write(codec, PLL_J_REG, aic3262_divs[i].pll_j);
+
+               /* MSB & LSB for D value */
+
+               aic3262_write(codec, PLL_D_MSB, (aic3262_divs[i].pll_d >> 8));
+               aic3262_write(codec, PLL_D_LSB,
+                             (aic3262_divs[i].pll_d & AIC3262_8BITS_MASK));
+
+               /* NDAC divider value */
+               data = aic3262_read(codec, NDAC_DIV_POW_REG);
+               DBG(KERN_INFO "# reading NDAC = %d , NDAC_DIV_POW_REG = %x\n",
+                       aic3262_divs[i].ndac, data);
+               aic3262_write(codec, NDAC_DIV_POW_REG,
+                        ((data & 0x80)|(aic3262_divs[i].ndac)));
+               DBG(KERN_INFO "# writing NDAC = %d , NDAC_DIV_POW_REG = %x\n",
+                       aic3262_divs[i].ndac,
+                       ((data & 0x80)|(aic3262_divs[i].ndac)));
+
+               /* MDAC divider value */
+               data = aic3262_read(codec, MDAC_DIV_POW_REG);
+               DBG(KERN_INFO "# reading MDAC = %d , MDAC_DIV_POW_REG = %x\n",
+                       aic3262_divs[i].mdac, data);
+               aic3262_write(codec, MDAC_DIV_POW_REG,
+                       ((data & 0x80)|(aic3262_divs[i].mdac)));
+               DBG(KERN_INFO "# writing MDAC = %d , MDAC_DIV_POW_REG = %x\n",
+               aic3262_divs[i].mdac, ((data & 0x80)|(aic3262_divs[i].mdac)));
+
+               /* DOSR MSB & LSB values */
+               aic3262_write(codec, DOSR_MSB_REG, aic3262_divs[i].dosr >> 8);
+               DBG(KERN_INFO "# writing DOSR_MSB_REG = %d\n",
+                       (aic3262_divs[i].dosr >> 8));
+               aic3262_write(codec, DOSR_LSB_REG,
+                       aic3262_divs[i].dosr & AIC3262_8BITS_MASK);
+               DBG(KERN_INFO "# writing DOSR_LSB_REG = %d\n",
+                       (aic3262_divs[i].dosr & AIC3262_8BITS_MASK));
+
+               /* NADC divider value */
+               data = aic3262_read(codec, NADC_DIV_POW_REG);
+               aic3262_write(codec, NADC_DIV_POW_REG,
+                       ((data & 0x80)|(aic3262_divs[i].nadc)));
+               DBG(KERN_INFO "# writing NADC_DIV_POW_REG = %d\n",
+                       aic3262_divs[i].nadc);
+
+               /* MADC divider value */
+               data = aic3262_read(codec, MADC_DIV_POW_REG);
+               aic3262_write(codec, MADC_DIV_POW_REG,
+                       ((data & 0x80)|(aic3262_divs[i].madc)));
+               DBG(KERN_INFO "# writing MADC_DIV_POW_REG = %d\n",
+                       aic3262_divs[i].madc);
+
+               /* AOSR value */
+               aic3262_write(codec, AOSR_REG, aic3262_divs[i].aosr);
+               DBG(KERN_INFO "# writing AOSR = %d\n", aic3262_divs[i].aosr);
+       } else {
+               DBG(KERN_INFO "#Atleast 1 ASI Active. Cannot Program PLL..\n");
+       }
+       /* Check for the DAI ID to know which ASI needs
+       * Configuration.
+       */
+       switch (dai->id) {
+       case 1:
+               regoffset = ASI1_BUS_FMT;
+
+               if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+                       DBG(KERN_INFO "#%s: ASI1 DAC Inputs enabled..\n",
+                                       __func__);
+                       /* Read the DAC Control Register and configure it
+                       * as per the ASIContext Structure Settings.
+                       */
+                       dacpath = aic3262_read(codec, ASI1_DAC_OUT_CNTL);
+                       dacpath &= ~(AIC3262_ASI_LDAC_PATH_MASK |
+                               AIC3262_ASI_RDAC_PATH_MASK);
+                       dacpath |= (aic3262->asiCtxt[0].left_dac_output
+                               << AIC3262_ASI_LDAC_PATH_SHIFT);
+
+                       dacpath |= (aic3262->asiCtxt[0].right_dac_output
+                               << AIC3262_ASI_RDAC_PATH_SHIFT);
+                       aic3262_write(codec, ASI1_DAC_OUT_CNTL, dacpath);
+
+                       aic3262->asiCtxt[0].playback_mode = 1;
+                       aic3262->asiCtxt[0].bclk_div =
+                               aic3262_divs[i].blck_N;
+               } else {
+                       /* For Recording, Configure the DOUT Pin as per
+                        * ASIContext Structure Settings.
+                        */
+                       adcpath = aic3262_read(codec, ASI1_DATA_OUT);
+                       adcpath &= ~(AIC3262_ASI_DOUT_MASK);
+
+                       adcpath |= aic3262->asiCtxt[0].dout_option;
+                       aic3262_write(codec, ASI1_DATA_OUT, adcpath);
+
+                       aic3262->asiCtxt[0].capture_mode = 1;
+               }
+       break;
+       case 2:
+               regoffset = ASI2_BUS_FMT;
+
+               /* Since we are configuring ASI2, please check if Playback
+                * is expected. If so, enable ASI2 Inputs to Left and
+                * Right DACs
+                */
+               if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+                       DBG(KERN_INFO "#%s: ASI2 DAC Inputs enabled..\n",
+                                       __func__);
+                       /* Read the DAC Control Register and configure it
+                        * as per theASIContext Structure Settings.
+                        */
+                       dacpath = aic3262_read(codec, ASI2_DAC_OUT_CNTL);
+                       dacpath &= ~(AIC3262_ASI_LDAC_PATH_MASK |
+                               AIC3262_ASI_RDAC_PATH_MASK);
+                       dacpath |= (aic3262->asiCtxt[1].left_dac_output
+                               << AIC3262_ASI_LDAC_PATH_SHIFT);
+
+                       dacpath |= (aic3262->asiCtxt[1].right_dac_output
+                               << AIC3262_ASI_RDAC_PATH_SHIFT);
+                       aic3262_write(codec, ASI2_DAC_OUT_CNTL, dacpath);
+                       aic3262->asiCtxt[1].playback_mode = 1;
+
+                       aic3262->asiCtxt[1].bclk_div =
+                               aic3262_divs[i].blck_N;
+               } else {
+                       /* For Recording, Configure the DOUT Pin as per
+                        * ASIContext Structure Settings.
+                        */
+                       adcpath = aic3262_read(codec, ASI2_DATA_OUT);
+                       adcpath &= ~(AIC3262_ASI_DOUT_MASK);
+                       adcpath |= aic3262->asiCtxt[1].dout_option;
+                       aic3262_write(codec, ASI2_DATA_OUT, adcpath);
+
+                       aic3262->asiCtxt[1].capture_mode = 1;
+               }
+       break;
+       case 3:
+               regoffset = ASI3_BUS_FMT;
+               /* Since we are configuring ASI3, please check if Playback
+               * is expected. If so, enable ASI3 Inputs to Left and
+               * Right DACs
+               */
+               if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+                       DBG(KERN_INFO "#%s:ASI3 DAC Inputs enabled.\n",
+                               __func__);
+                       /* Read the DAC Control Register and configure
+                       * it as per the ASIContext Structure Settings.
+                       */
+                       dacpath = aic3262_read(codec, ASI3_DAC_OUT_CNTL);
+                       dacpath &= ~(AIC3262_ASI_LDAC_PATH_MASK |
+                                       AIC3262_ASI_RDAC_PATH_MASK);
+                       dacpath |= (aic3262->asiCtxt[2].left_dac_output
+                                       << AIC3262_ASI_LDAC_PATH_SHIFT);
+                       dacpath |= (aic3262->asiCtxt[2].right_dac_output
+                               << AIC3262_ASI_RDAC_PATH_SHIFT);
+                       aic3262_write(codec,
+                               ASI3_DAC_OUT_CNTL, dacpath);
+
+                       aic3262->asiCtxt[2].playback_mode = 1;
+
+                       aic3262->asiCtxt[2].bclk_div =
+                               aic3262_divs[i].blck_N;
+               } else {
+                       /* For Recording, Configure the DOUT Pin as per
+                        * ASIContext Structure Settings.
+                        */
+                       adcpath &= ~(AIC3262_ASI_DOUT_MASK);
+                       adcpath |= aic3262->asiCtxt[2].dout_option;
+                       aic3262_write(codec, ASI3_DATA_OUT, adcpath);
+
+                       aic3262->asiCtxt[2].capture_mode = 1;
+               }
+       break;
+       default:
+               printk(KERN_ERR "Invalid Dai ID %d in %s",
+                       dai->id, __func__);
+       break;
+       }
+       DBG(KERN_INFO "#%s: Reading Pg %d Reg %d for Bus Format Control.\n",
+               __func__, (regoffset/128),  (regoffset % 128));
+
+       /* Read the correspondig ASI DAI Interface Register */
+       data = aic3262_read(codec, regoffset);
+
+       data = data & 0xe7;
+
+       switch (params_format(params)) {
+       case SNDRV_PCM_FORMAT_S16_LE:
+               DBG(KERN_INFO "#%s: Configuring ASI%d S16_LE Fmt..\n",
+                       __func__, dai->id);
+               data = data | 0x00;
+               aic3262->asiCtxt[dai->id - 1].word_len = 16;
+       break;
+       case SNDRV_PCM_FORMAT_S20_3LE:
+               data |= (0x08);
+               aic3262->asiCtxt[dai->id - 1].word_len = 20;
+       break;
+       case SNDRV_PCM_FORMAT_S24_LE:
+               DBG(KERN_INFO "#%s: Configuring ASI%d S24_LE Fmt..\n",
+                       __func__, dai->id);
+               data |= (0x10);
+               aic3262->asiCtxt[dai->id - 1].word_len = 24;
+       break;
+       case SNDRV_PCM_FORMAT_S32_LE:
+               DBG(KERN_INFO "#%s: Configuring ASI%d S32_LE Fmt..\n",
+                       __func__, dai->id);
+               data |= (0x18);
+               aic3262->asiCtxt[dai->id - 1].word_len = 32;
+       break;
+       }
+
+       /* configure the respective Registers for the above configuration */
+       aic3262_write(codec, regoffset, data);
+
+       for (j = 0; j < NO_FEATURE_REGS; j++) {
+               aic3262_write(codec,
+                       aic3262_divs[i].codec_specific_regs[j].reg_offset,
+                       aic3262_divs[i].codec_specific_regs[j].reg_val);
+       }
+
+       /* Enable the PLL, MDAC, NDAC, NADC, MADC and BCLK Dividers */
+       aic3262_set_bias_level(codec, SND_SOC_BIAS_ON);
+
+       /* Based on the DAI ID we enable the corresponding pins related to the
+       * ASI Port.
+       */
+       switch (dai->id) {
+       case 1:
+               aic3262_asi1_clk_config(codec, params);
+       break;
+       case 2:
+               aic3262_asi2_clk_config(codec, params);
+       break;
+       case 3:
+               aic3262_asi3_clk_config(codec, params);
+       break;
+       default:
+               printk(KERN_ERR "Invalid Dai ID %d in %s",
+                       dai->id, __func__);
+       break;
+       }
+       /* Depending on the DAI->ID update the local Flags */
+       aic3262->asiCtxt[dai->id - 1].asi_active++;
+       aic3262->asiCtxt[dai->id - 1].sampling_rate = params_rate(params);
+       /* Update the active_count flag */
+       aic3262->active_count++;
+
+       return 0;
+}
+
+/*
+*
+* aic3262_multi_i2s_hw_free
+*
+* This function is used to configure the Codec after the usage is completed.
+* We can use this function to disable the DAC and ADC specific inputs from the
+* individual ASI Ports of the Audio Codec.
+*/
+static int aic3262_multi_i2s_hw_free(struct snd_pcm_substream *substream,
+                       struct snd_soc_dai *dai)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_codec *codec = rtd->codec;
+       struct aic3262_priv *aic3262 = snd_soc_codec_get_drvdata(codec);
+
+       u8 value;
+       u8 dacpath;
+       u8 adcpath;
+       u16 dacregoffset = 0;
+       u16 adcregoffset = 0;
+
+       DBG(KERN_INFO "#%s: ASI%d Port for %s Mode\n",
+               __func__, dai->id,
+               (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ?
+               "Playback" : "Record");
+
+       /* Check if this function was already executed earlier for the same
+       * ASI Port
+       */
+       if ((substream->stream == SNDRV_PCM_STREAM_PLAYBACK) &&
+               (aic3262->asiCtxt[dai->id - 1].playback_mode == 0)) {
+               DBG(KERN_INFO "#%s: Function Already Executed. Exiting..\n",
+                       __func__);
+               goto err;
+       } else if ((substream->stream != SNDRV_PCM_STREAM_PLAYBACK) &&
+               (aic3262->asiCtxt[dai->id - 1].capture_mode == 0)) {
+               DBG(KERN_INFO "#%s: Function Already Executed. Exiting..\n",
+                       __func__);
+               goto err;
+       }
+
+       switch (dai->id) {
+       case 1:
+               /* In case we are Frame Master on this Interface, Switch off
+               * the Bit Clock Divider and Word Clock Dividers
+               */
+               if (aic3262->asiCtxt[0].master == 1) {
+                       /* Also check if either Playback or Recording is still
+                       * going on this ASI Interface
+                       */
+
+                       value = aic3262_read(codec, ASI1_BCLK_N);
+                       aic3262_write(codec, ASI1_BCLK_N, (value & 0x7f));
+
+                       value = aic3262_read(codec, ASI1_WCLK_N);
+                       aic3262_write(codec, ASI1_WCLK_N, (value & 0x7f));
+               }
+
+               dacregoffset = ASI1_DAC_OUT_CNTL;
+               adcregoffset = ASI1_ADC_INPUT_CNTL;
+       break;
+       case 2:
+               /* In case we are Frame Master on this Interface, Switch off
+               * the Bit Clock Divider and Word Clock Dividers
+               */
+               if (aic3262->asiCtxt[1].master == 1) {
+                       value = aic3262_read(codec, ASI2_BCLK_N);
+                       aic3262_write(codec, ASI2_BCLK_N, (value & 0x7f));
+
+                       value = aic3262_read(codec, ASI2_WCLK_N);
+                       aic3262_write(codec, ASI2_WCLK_N, (value & 0x7f));
+               }
+               dacregoffset = ASI2_DAC_OUT_CNTL;
+               adcregoffset = ASI2_ADC_INPUT_CNTL;
+       break;
+       case 3:
+               /* In case we are Frame Master on this Interface, Switch off
+               * the Bit Clock Divider and Word Clock Dividers
+               */
+               if (aic3262->asiCtxt[2].master == 1) {
+                       value = aic3262_read(codec, ASI3_BCLK_N);
+                       aic3262_write(codec, ASI3_BCLK_N, (value & 0x7f));
+
+                       value = aic3262_read(codec, ASI3_WCLK_N);
+                       aic3262_write(codec, ASI3_WCLK_N, (value & 0x7f));
+               }
+               dacregoffset = ASI3_DAC_OUT_CNTL;
+               adcregoffset = ASI3_ADC_INPUT_CNTL;
+       break;
+       default:
+               printk(KERN_ERR "#%s: Invalid dai id\n", __func__);
+       }
+       /* If this was a Playback Stream Stop, then only
+       * switch off the DAC Inputs
+       */
+       if ((substream->stream == SNDRV_PCM_STREAM_PLAYBACK) &&
+               (dacregoffset != 0)) {
+               printk(KERN_INFO "#%s: Disabling Pg %d Reg %d DAC Inputs ..\n",
+                       __func__, (dacregoffset/128), (dacregoffset % 128));
+
+               dacpath = aic3262_read(codec, dacregoffset);
+               aic3262_write(codec, dacregoffset, (dacpath & ~(BIT6 | BIT4)));
+
+               aic3262->asiCtxt[dai->id - 1].playback_mode = 0;
+       } else {
+               /* Switch off the ADC Input Control Registers here */
+               DBG(KERN_INFO "#%s: Disabling Pg %d Reg %d for ADC Inputs..\n",
+                       __func__, (adcregoffset/128), (adcregoffset % 128));
+
+               adcpath =  aic3262_read(codec, adcregoffset);
+               aic3262_write(codec, adcregoffset,
+                       (adcpath & ~(BIT2 | BIT1 | BIT0)));
+
+               aic3262->asiCtxt[dai->id - 1].capture_mode = 0;
+       }
+
+       /* If we were configured in mono PCM Mode earlier, then reset the
+       * Left Channel and Right Channel offset Registers here.
+       */
+       switch (dai->id) {
+       case 1:
+               if (aic3262->asiCtxt[0].pcm_format == SND_SOC_DAIFMT_DSP_B) {
+                       aic3262_write(codec, ASI1_LCH_OFFSET, 0x00);
+                       aic3262_write(codec, ASI1_RCH_OFFSET, 0x00);
+               }
+       break;
+       case 2:
+               if (aic3262->asiCtxt[1].pcm_format == SND_SOC_DAIFMT_DSP_B) {
+                       aic3262_write(codec, ASI2_LCH_OFFSET, 0x00);
+                       aic3262_write(codec, ASI2_RCH_OFFSET, 0x00);
+               }
+
+       break;
+       case 3:
+               if (aic3262->asiCtxt[2].pcm_format == SND_SOC_DAIFMT_DSP_B) {
+                       aic3262_write(codec, ASI3_LCH_OFFSET, 0x00);
+                       aic3262_write(codec, ASI3_RCH_OFFSET, 0x00);
+               }
+       break;
+       }
+       /* Depending on the DAI->ID update the asi_active Flags */
+       if (aic3262->asiCtxt[dai->id - 1].asi_active) {
+               aic3262->asiCtxt[dai->id - 1].asi_active--;
+
+               /* Update the active_count flag */
+               if (aic3262->active_count)
+                       aic3262->active_count--;
+       }
+err:
+       return 0;
+}
+
+/*
+ *----------------------------------------------------------------------------
+ * @struct  snd_soc_codec_dai |
+ *          It is SoC Codec DAI structure which has DAI capabilities viz.,
+ *          playback and capture, DAI runtime information viz. state of DAI
+ *                     and pop wait state, and DAI private data.
+ *          The AIC3262 rates ranges from 8k to 192k
+ *          The PCM bit format supported are 16, 20, 24 and 32 bits
+ *----------------------------------------------------------------------------
+ */
+struct snd_soc_dai_ops aic3262_dai_ops = {
+       .hw_params = aic3262_hw_params,
+       .digital_mute = aic3262_mute,
+       .set_sysclk = aic3262_set_dai_sysclk,
+       .set_fmt = aic3262_set_dai_fmt,
+};
+
+struct snd_soc_dai_ops aic3262_multi_i2s_dai_ops = {
+       .hw_params      = aic3262_multi_i2s_hw_params,
+       .digital_mute   = aic3262_multi_i2s_mute,
+       .set_fmt        = aic3262_multi_i2s_set_dai_fmt,
+       .set_pll        = aic3262_multi_i2s_set_dai_pll,
+       .set_sysclk     = aic3262_multi_i2s_set_dai_sysclk,
+       .hw_free        = aic3262_multi_i2s_hw_free,
+};
+
+
+static struct snd_soc_dai_driver tlv320aic3262_dai[] = {
+/* AIC3262 ASI1 DAI */
+{
+       .name = "aic3262-asi1",
+       .id = 1,
+       .playback = {
+               .stream_name = "Playback",
+               .channels_min = 1,
+               .channels_max = 2,
+               .rates = AIC3262_RATES,
+               .formats = AIC3262_FORMATS},
+       .capture = { /* dummy for fast DAI switching */
+               .stream_name = "Capture",
+               .channels_min = 1,
+               .channels_max = 2,
+               .rates = AIC3262_RATES,
+               .formats = AIC3262_FORMATS},
+       .ops = &aic3262_multi_i2s_dai_ops,
+},
+/* AIC3262 ASI2 DAI */
+{
+       .name = "aic3262-asi2",
+       .id = 2,
+       .playback = {
+               .stream_name = "Playback",
+               .channels_min = 1,
+               .channels_max = 2,
+               .rates = AIC3262_RATES,
+               .formats = AIC3262_FORMATS,},
+       .capture = {
+               .stream_name = "Capture",
+               .channels_min = 1,
+               .channels_max = 2,
+               .rates = AIC3262_RATES,
+               .formats = AIC3262_FORMATS,},
+       .ops = &aic3262_multi_i2s_dai_ops,
+
+},
+/* AIC3262 ASI3 DAI  */
+{
+       .name = "aic3262-asi3",
+       .id = 3,
+       .playback = {
+               .stream_name = "Playback",
+               .channels_min = 1,
+               .channels_max = 2,
+               .rates = AIC3262_RATES,
+               .formats = AIC3262_FORMATS, },
+       .capture = {
+               .stream_name = "Capture",
+               .channels_min = 1,
+               .channels_max = 2,
+               .rates = AIC3262_RATES,
+               .formats = AIC3262_FORMATS, },
+       .ops = &aic3262_multi_i2s_dai_ops,
+
+},
+};
+
+/*
+ *****************************************************************************
+ * Initializations
+ *****************************************************************************
+ */
+/*
+ * AIC3262 register cache
+ * We are caching the registers here.
+ * There is no point in caching the reset register.
+ *
+ * NOTE: In AIC3262, there are 127 registers supported in both page0 and page1
+ *       The following table contains the page0 and page 1 and page 3
+ *       registers values.
+ */
+static const u8 aic3262_reg[AIC3262_CACHEREGNUM] = {
+       0x00, 0x00, 0x10, 0x00, /* 0 */
+       0x03, 0x40, 0x11, 0x08, /* 4 */
+       0x00, 0x00, 0x00, 0x82, /* 8 */
+       0x88, 0x00, 0x80, 0x02, /* 12 */
+       0x00, 0x08, 0x01, 0x01, /* 16 */
+       0x80, 0x01, 0x00, 0x04, /* 20 */
+       0x00, 0x00, 0x01, 0x00, /* 24 */
+       0x00, 0x00, 0x01, 0x00, /* 28 */
+       0x00, 0x00, 0x00, 0x00, /* 32 */
+       0x00, 0x00, 0x00, 0x00, /* 36 */
+       0x00, 0x00, 0x00, 0x00, /* 40 */
+       0x00, 0x00, 0x00, 0x00, /* 44 */
+       0x00, 0x00, 0x00, 0x00, /* 48 */
+       0x00, 0x42, 0x02, 0x02, /* 52 */
+       0x42, 0x02, 0x02, 0x02, /* 56 */
+       0x00, 0x00, 0x00, 0x01, /* 60 */
+       0x01, 0x00, 0x14, 0x00, /* 64 */
+       0x0C, 0x00, 0x00, 0x00, /* 68 */
+       0x00, 0x00, 0x00, 0xEE, /* 72 */
+       0x10, 0xD8, 0x10, 0xD8, /* 76 */
+       0x00, 0x00, 0x88, 0x00, /* 80 */
+       0x00, 0x00, 0x00, 0x00, /* 84 */
+       0x7F, 0x00, 0x00, 0x00, /* 88 */
+       0x00, 0x00, 0x00, 0x00, /* 92 */
+       0x7F, 0x00, 0x00, 0x00, /* 96 */
+       0x00, 0x00, 0x00, 0x00, /* 100 */
+       0x00, 0x00, 0x00, 0x00, /* 104 */
+       0x00, 0x00, 0x00, 0x00, /* 108 */
+       0x00, 0x00, 0x00, 0x00, /* 112 */
+       0x00, 0x00, 0x00, 0x00, /* 116 */
+       0x00, 0x00, 0x00, 0x00, /* 120 */
+       0x00, 0x00, 0x00, 0x00, /* 124 - PAGE0 Registers(127) ends here */
+       0x01, 0x00, 0x08, 0x00, /* 128, PAGE1-0 */
+       0x00, 0x00, 0x00, 0x00, /* 132, PAGE1-4 */
+       0x00, 0x00, 0x00, 0x10, /* 136, PAGE1-8 */
+       0x00, 0x00, 0x00, 0x00, /* 140, PAGE1-12 */
+       0x40, 0x40, 0x40, 0x40, /* 144, PAGE1-16 */
+       0x00, 0x00, 0x00, 0x00, /* 148, PAGE1-20 */
+       0x00, 0x00, 0x00, 0x00, /* 152, PAGE1-24 */
+       0x00, 0x00, 0x00, 0x00, /* 156, PAGE1-28 */
+       0x00, 0x00, 0x00, 0x00, /* 160, PAGE1-32 */
+       0x00, 0x00, 0x00, 0x00, /* 164, PAGE1-36 */
+       0x00, 0x00, 0x00, 0x00, /* 168, PAGE1-40 */
+       0x00, 0x00, 0x00, 0x00, /* 172, PAGE1-44 */
+       0x00, 0x00, 0x00, 0x00, /* 176, PAGE1-48 */
+       0x00, 0x00, 0x00, 0x00, /* 180, PAGE1-52 */
+       0x00, 0x00, 0x00, 0x80, /* 184, PAGE1-56 */
+       0x80, 0x00, 0x00, 0x00, /* 188, PAGE1-60 */
+       0x00, 0x00, 0x00, 0x00, /* 192, PAGE1-64 */
+       0x00, 0x00, 0x00, 0x00, /* 196, PAGE1-68 */
+       0x00, 0x00, 0x00, 0x00, /* 200, PAGE1-72 */
+       0x00, 0x00, 0x00, 0x00, /* 204, PAGE1-76 */
+       0x00, 0x00, 0x00, 0x00, /* 208, PAGE1-80 */
+       0x00, 0x00, 0x00, 0x00, /* 212, PAGE1-84 */
+       0x00, 0x00, 0x00, 0x00, /* 216, PAGE1-88 */
+       0x00, 0x00, 0x00, 0x00, /* 220, PAGE1-92 */
+       0x00, 0x00, 0x00, 0x00, /* 224, PAGE1-96 */
+       0x00, 0x00, 0x00, 0x00, /* 228, PAGE1-100 */
+       0x00, 0x00, 0x00, 0x00, /* 232, PAGE1-104 */
+       0x00, 0x00, 0x00, 0x00, /* 236, PAGE1-108 */
+       0x00, 0x00, 0x00, 0x00, /* 240, PAGE1-112 */
+       0x00, 0x00, 0x00, 0x00, /* 244, PAGE1-116 */
+       0x00, 0x00, 0x00, 0x00, /* 248, PAGE1-120 */
+       0x00, 0x00, 0x00, 0x00, /* 252, PAGE1-124 Page 1 Registers Ends Here */
+       0x00, 0x00, 0x00, 0x00, /* 256, PAGE2-0  */
+       0x00, 0x00, 0x00, 0x00, /* 260, PAGE2-4  */
+       0x00, 0x00, 0x00, 0x00, /* 264, PAGE2-8  */
+       0x00, 0x00, 0x00, 0x00, /* 268, PAGE2-12 */
+       0x00, 0x00, 0x00, 0x00, /* 272, PAGE2-16 */
+       0x00, 0x00, 0x00, 0x00, /* 276, PAGE2-20 */
+       0x00, 0x00, 0x00, 0x00, /* 280, PAGE2-24 */
+       0x00, 0x00, 0x00, 0x00, /* 284, PAGE2-28 */
+       0x00, 0x00, 0x00, 0x00, /* 288, PAGE2-32 */
+       0x00, 0x00, 0x00, 0x00, /* 292, PAGE2-36 */
+       0x00, 0x00, 0x00, 0x00, /* 296, PAGE2-40 */
+       0x00, 0x00, 0x00, 0x00, /* 300, PAGE2-44 */
+       0x00, 0x00, 0x00, 0x00, /* 304, PAGE2-48 */
+       0x00, 0x00, 0x00, 0x00, /* 308, PAGE2-52 */
+       0x00, 0x00, 0x00, 0x00, /* 312, PAGE2-56 */
+       0x00, 0x00, 0x00, 0x00, /* 316, PAGE2-60 */
+       0x00, 0x00, 0x00, 0x00, /* 320, PAGE2-64 */
+       0x00, 0x00, 0x00, 0x00, /* 324, PAGE2-68 */
+       0x00, 0x00, 0x00, 0x00, /* 328, PAGE2-72 */
+       0x00, 0x00, 0x00, 0x00, /* 332, PAGE2-76 */
+       0x00, 0x00, 0x00, 0x00, /* 336, PAGE2-80 */
+       0x00, 0x00, 0x00, 0x00, /* 340, PAGE2-84 */
+       0x00, 0x00, 0x00, 0x00, /* 344, PAGE2-88 */
+       0x00, 0x00, 0x00, 0x00, /* 348, PAGE2-92 */
+       0x00, 0x00, 0x00, 0x00, /* 352, PAGE2-96 */
+       0x00, 0x00, 0x00, 0x00, /* 356, PAGE2-100 */
+       0x00, 0x00, 0x00, 0x00, /* 360, PAGE2-104 */
+       0x00, 0x00, 0x00, 0x00, /* 364, PAGE2-108 */
+       0x00, 0x00, 0x00, 0x00, /* 368, PAGE2-112*/
+       0x00, 0x00, 0x00, 0x00, /* 372, PAGE2-116*/
+       0x00, 0x00, 0x00, 0x00, /* 376, PAGE2-120*/
+       0x00, 0x00, 0x00, 0x00, /* 380, PAGE2-124 Page 2 Registers Ends Here */
+       0x00, 0x00, 0x00, 0x00, /* 384, PAGE3-0  */
+       0x00, 0x00, 0x00, 0x00, /* 388, PAGE3-4  */
+       0x00, 0x00, 0x00, 0x00, /* 392, PAGE3-8  */
+       0x00, 0x00, 0x00, 0x00, /* 392, PAGE3-12  */
+       0x00, 0x00, 0x00, 0x00, /* 392, PAGE3-16  */
+       0x00, 0x00, 0x00, 0x00, /* 392, PAGE3-20  */
+       0x00, 0x00, 0x00, 0x00, /* 392, PAGE3-24  */
+       0x00, 0x00, 0x00, 0x00, /* 392, PAGE3-28  */
+       0x00, 0x00, 0x00, 0x00, /* 392, PAGE3-32  */
+       0x00, 0x00, 0x00, 0x00, /* 392, PAGE3-36  */
+       0x00, 0x00, 0x00, 0x00, /* 392, PAGE3-40  */
+       0x00, 0x00, 0x00, 0x00, /* 392, PAGE3-44  */
+       0x00, 0x00, 0x00, 0x00, /* 392, PAGE3-48  */
+       0x00, 0x00, 0x00, 0x00, /* 392, PAGE3-52  */
+       0x00, 0x00, 0x00, 0x00, /* 392, PAGE3-56  */
+       0x00, 0x00, 0x00, 0x00, /* 392, PAGE3-60  */
+       0x00, 0x00, 0x00, 0x00, /* 392, PAGE3-64  */
+       0x00, 0x00, 0x00, 0x00, /* 392, PAGE3-68  */
+       0x00, 0x00, 0x00, 0x00, /* 328, PAGE3-72 */
+       0x00, 0x00, 0x00, 0x00, /* 332, PAGE3-76 */
+       0x00, 0x00, 0x00, 0x00, /* 336, PAGE3-80 */
+       0x00, 0x00, 0x00, 0x00, /* 340, PAGE3-84 */
+       0x00, 0x00, 0x00, 0x00, /* 344, PAGE3-88 */
+       0x00, 0x00, 0x00, 0x00, /* 348, PAGE3-92 */
+       0x00, 0x00, 0x00, 0x00, /* 352, PAGE3-96 */
+       0x00, 0x00, 0x00, 0x00, /* 356, PAGE3-100 */
+       0x00, 0x00, 0x00, 0x00, /* 360, PAGE3-104 */
+       0x00, 0x00, 0x00, 0x00, /* 364, PAGE3-108 */
+       0x00, 0x00, 0x00, 0x00, /* 368, PAGE3-112*/
+       0x00, 0x00, 0x00, 0x00, /* 372, PAGE3-116*/
+       0x00, 0x00, 0x00, 0x00, /* 376, PAGE3-120*/
+       0x00, 0x00, 0x00, 0x00, /* 380, PAGE3-124 Page 3 Registers Ends Here */
+       0x00, 0x00, 0x00, 0x00, /* 384, PAGE4-0  */
+       0x00, 0x00, 0x00, 0x00, /* 388, PAGE4-4  */
+       0x00, 0x00, 0x00, 0x00, /* 392, PAGE4-8  */
+       0x00, 0x00, 0x00, 0x00, /* 392, PAGE4-12  */
+       0x00, 0x00, 0x00, 0x00, /* 392, PAGE4-16  */
+       0x00, 0x00, 0x00, 0x00, /* 392, PAGE4-20  */
+       0x00, 0x00, 0x00, 0x00, /* 392, PAGE4-24  */
+       0x00, 0x00, 0x00, 0x00, /* 392, PAGE4-28  */
+       0x00, 0x00, 0x00, 0x00, /* 392, PAGE4-32  */
+       0x00, 0x00, 0x00, 0x00, /* 392, PAGE4-36  */
+       0x00, 0x00, 0x00, 0x00, /* 392, PAGE4-40  */
+       0x00, 0x00, 0x00, 0x00, /* 392, PAGE4-44  */
+       0x00, 0x00, 0x00, 0x00, /* 392, PAGE4-48  */
+       0x00, 0x00, 0x00, 0x00, /* 392, PAGE4-52  */
+       0x00, 0x00, 0x00, 0x00, /* 392, PAGE4-56  */
+       0x00, 0x00, 0x00, 0x00, /* 392, PAGE4-60  */
+       0x00, 0x00, 0x00, 0x00, /* 392, PAGE4-64  */
+       0x00, 0x00, 0x00, 0x00, /* 392, PAGE4-68  */
+       0x00, 0x00, 0x00, 0x00, /* 328, PAGE4-72 */
+       0x00, 0x00, 0x00, 0x00, /* 332, PAGE4-76 */
+       0x00, 0x00, 0x00, 0x00, /* 336, PAGE4-80 */
+       0x00, 0x00, 0x00, 0x00, /* 340, PAGE4-84 */
+       0x00, 0x00, 0x00, 0x00, /* 344, PAGE4-88 */
+       0x00, 0x00, 0x00, 0x00, /* 348, PAGE4-92 */
+       0x00, 0x00, 0x00, 0x00, /* 352, PAGE4-96 */
+       0x00, 0x00, 0x00, 0x00, /* 356, PAGE4-100 */
+       0x00, 0x00, 0x00, 0x00, /* 360, PAGE4-104 */
+       0x00, 0x00, 0x00, 0x00, /* 364, PAGE4-108 */
+       0x00, 0x00, 0x00, 0x00, /* 368, PAGE4-112*/
+       0x00, 0x00, 0x00, 0x00, /* 372, PAGE4-116*/
+       0x00, 0x00, 0x00, 0x00, /* 376, PAGE4-120*/
+       0x00, 0x00, 0x00, 0x00, /* 380, PAGE4-124 Page 2 Registers Ends Here */
+
+};
+
+/*
+ *------------------------------------------------------------------------------
+ * aic3262 initialization data
+ * This structure initialization contains the initialization required for
+ * AIC326x.
+ * These registers values (reg_val) are written into the respective AIC3262
+ * register offset (reg_offset) to  initialize AIC326x.
+ * These values are used in aic3262_init() function only.
+ *------------------------------------------------------------------------------
+ */
+static const struct aic3262_configs aic3262_reg_init[] = {
+       /* CLOCKING */
+
+       {0, RESET_REG, 1},
+       {0, RESET_REG, 0},
+
+       {0, PASI_DAC_DP_SETUP,  0xc0},  /*DAC */
+       {0, DAC_MVOL_CONF,  0x00},      /*DAC un-muted*/
+       /* set default volumes */
+       {0, DAC_LVOL, 0x01},
+       {0, DAC_RVOL, 0x01},
+       {0, HPL_VOL,  0x3a},
+       {0, HPR_VOL,  0x3a},
+       {0, SPK_AMP_CNTL_R2, 0x14},
+       {0, SPK_AMP_CNTL_R3, 0x14},
+       {0, SPK_AMP_CNTL_R4, 0x33},
+       {0, REC_AMP_CNTL_R5, 0x82},
+       {0, RAMPR_VOL, 20},
+       {0, RAMP_CNTL_R1, 70},
+       {0, RAMP_CNTL_R2, 70},
+
+       /* DRC Defaults */
+       {0, DRC_CNTL_R1, 0x6c},
+       {0, DRC_CNTL_R2, 16},
+
+       /* DEPOP SETTINGS */
+       {0, HP_DEPOP, 0x14},
+       {0, RECV_DEPOP, 0x14},
+
+       {0, POWER_CONF, 0x00},   /* Disconnecting AVDD-DVD weak link*/
+       {0, REF_PWR_DLY, 0x01},
+       {0, CM_REG, 0x00},      /*CM - default*/
+       {0, LDAC_PTM, 0},       /*LDAC_PTM - default*/
+       {0, RDAC_PTM, 0},       /*RDAC_PTM - default*/
+       {0, HP_CTL, 0x30},      /*HP output percentage - at 75%*/
+       {0, LADC_VOL, 0x01},    /*LADC volume*/
+       {0, RADC_VOL, 0x01},    /*RADC volume*/
+
+       {0, DAC_ADC_CLKIN_REG, 0x33},   /*DAC ADC CLKIN*/
+       {0, PLL_CLKIN_REG, 0x00},       /*PLL CLKIN*/
+       {0, PLL_PR_POW_REG, 0x11},      /*PLL Power=0-down, P=1, R=1 vals*/
+       {0, 0x3d, 1},
+
+       {0, LMIC_PGA_PIN, 0x55},        /*IN1_L select - - 10k -LMICPGA_P*/
+       {0, LMIC_PGA_MIN, 0x40},        /*CM to LMICPGA-M*/
+       {0, RMIC_PGA_PIN, 0x55},        /*IN1_R select - - 10k -RMIC_PGA_P*/
+       {0, RMIC_PGA_MIN, 0x40},        /*CM to RMICPGA_M*/
+       {0, (PAGE_1 + 0x79), 33},       /*LMIC-PGA-POWERUP-DELAY - default*/
+       {0, (PAGE_1 + 0x7a), 1},        /*FIXMELATER*/
+
+
+       {0, ADC_CHANNEL_POW, 0xc2}, /*ladc, radc ON , SOFT STEP disabled*/
+       {0, ADC_FINE_GAIN, 0x00},   /*ladc - unmute, radc - unmute*/
+       {0, MICL_PGA, 0x4f},
+       {0, MICR_PGA, 0x4f},
+       {0, MIC_BIAS_CNTL, 0xFC},
+       /*   ASI1 Configuration */
+       {0, ASI1_BUS_FMT, 0},
+       {0, ASI1_BWCLK_CNTL_REG, 0x00},         /* originaly 0x24*/
+       {0, ASI1_BCLK_N_CNTL, 1},
+       {0, ASI1_BCLK_N, 0x84},
+
+       {0, MA_CNTL, 0},                        /* Mixer Amp disabled */
+       {0, LINE_AMP_CNTL_R2, 0x00},            /* Line Amp Cntl disabled */
+
+       /* ASI2 Configuration */
+       {0, ASI2_BUS_FMT, 0},
+       {0, ASI2_BCLK_N_CNTL, 1},
+       {0, ASI2_BCLK_N, 0x84},
+       {0, ASI2_BWCLK_OUT_CNTL, 0x20},
+
+       {0, BEEP_CNTL_R1, 0x05},
+       {0, BEEP_CNTL_R2, 0x04},
+
+       /* Interrupt config for headset detection */
+       {0, INT1_CNTL, 0x80},
+       {0, INT_FMT, 0x40},
+       {0, GPIO1_IO_CNTL, 0x14},
+       {0, HP_DETECT, 0x94},
+
+#if defined(CONFIG_MINI_DSP)
+       {0, 60, 0},
+       {0, 61, 0},
+       /* Added the below set of values after consulting the miniDSP
+        * Program Section Array
+        */
+       {0, MINIDSP_ACCESS_CTRL, 0x00},
+#endif
+
+
+};
+
+static int reg_init_size =
+       sizeof(aic3262_reg_init) / sizeof(struct aic3262_configs);
+
+static const struct snd_kcontrol_new aic3262_snd_controls2[] = {
+
+       SOC_DOUBLE_R("IN1 MPGA Route", LMIC_PGA_PIN, RMIC_PGA_PIN, 6, 3, 0),
+       SOC_DOUBLE_R("IN2 MPGA Route", LMIC_PGA_PIN, RMIC_PGA_PIN, 4, 3, 0),
+       SOC_DOUBLE_R("IN3 MPGA Route", LMIC_PGA_PIN, RMIC_PGA_PIN, 2, 3, 0),
+       SOC_DOUBLE_R("IN4 MPGA Route",
+                LMIC_PGA_PM_IN4, RMIC_PGA_PM_IN4, 5, 1, 0),
+};
+static const struct snd_soc_dapm_widget aic3262_dapm_widgets[] = {
+       SND_SOC_DAPM_DAC("Left DAC", "Playback", PASI_DAC_DP_SETUP, 7, 0),
+       SND_SOC_DAPM_DAC("Right DAC", "Playback", PASI_DAC_DP_SETUP, 6, 0),
+
+       SND_SOC_DAPM_SWITCH_N("LDAC_2_HPL", HP_AMP_CNTL_R1, 5, 0),
+       SND_SOC_DAPM_SWITCH_N("RDAC_2_HPR", HP_AMP_CNTL_R1, 4, 0),
+
+       SND_SOC_DAPM_PGA("HPL Driver", HP_AMP_CNTL_R1, 1, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("HPR Driver", HP_AMP_CNTL_R1, 0, 0, NULL, 0),
+
+       SND_SOC_DAPM_SWITCH_N("LDAC_2_LOL", LINE_AMP_CNTL_R1, 7, 0),
+       SND_SOC_DAPM_SWITCH_N("RDAC_2_LOR", LINE_AMP_CNTL_R1, 6, 0),
+
+       SND_SOC_DAPM_PGA("LOL Driver", LINE_AMP_CNTL_R1, 1, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("LOR Driver", LINE_AMP_CNTL_R1, 0, 0, NULL, 0),
+
+       SND_SOC_DAPM_PGA("SPKL Driver", SPK_AMP_CNTL_R1, 1, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("SPKR Driver", SPK_AMP_CNTL_R1, 0, 0, NULL, 0),
+
+       SND_SOC_DAPM_PGA("RECL Driver", REC_AMP_CNTL_R5, 7, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("RECR Driver", REC_AMP_CNTL_R5, 6, 0, NULL, 0),
+
+       SND_SOC_DAPM_ADC("Left ADC", "Capture", ADC_CHANNEL_POW, 7, 0),
+       SND_SOC_DAPM_ADC("Right ADC", "Capture", ADC_CHANNEL_POW, 6, 0),
+
+       SND_SOC_DAPM_SWITCH("IN1L Route",
+                LMIC_PGA_PIN, 6, 0, &aic3262_snd_controls2[0]),
+       SND_SOC_DAPM_SWITCH("IN2L Route",
+                LMIC_PGA_PIN, 4, 0, &aic3262_snd_controls2[1]),
+       SND_SOC_DAPM_SWITCH("IN3L Route",
+                LMIC_PGA_PIN, 2, 0, &aic3262_snd_controls2[2]),
+       SND_SOC_DAPM_SWITCH("IN4L Route",
+                LMIC_PGA_PM_IN4, 5, 0, &aic3262_snd_controls2[3]),
+       SND_SOC_DAPM_SWITCH("IN1R Route",
+                RMIC_PGA_PIN, 6, 0, &aic3262_snd_controls2[4]),
+       SND_SOC_DAPM_SWITCH("IN2R Route",
+                RMIC_PGA_PIN, 4, 0, &aic3262_snd_controls2[5]),
+       SND_SOC_DAPM_SWITCH("IN3R Route",
+                RMIC_PGA_PIN, 2, 0, &aic3262_snd_controls2[6]),
+       SND_SOC_DAPM_SWITCH("IN4R Route",
+                RMIC_PGA_PM_IN4, 5, 0, &aic3262_snd_controls2[7]),
+
+       SND_SOC_DAPM_OUTPUT("HPL"),
+       SND_SOC_DAPM_OUTPUT("HPR"),
+       SND_SOC_DAPM_OUTPUT("LOL"),
+       SND_SOC_DAPM_OUTPUT("LOR"),
+       SND_SOC_DAPM_OUTPUT("SPKL"),
+       SND_SOC_DAPM_OUTPUT("SPKR"),
+       SND_SOC_DAPM_OUTPUT("RECL"),
+       SND_SOC_DAPM_OUTPUT("RECR"),
+
+       SND_SOC_DAPM_INPUT("IN1L"),
+       SND_SOC_DAPM_INPUT("IN2L"),
+       SND_SOC_DAPM_INPUT("IN3L"),
+       SND_SOC_DAPM_INPUT("IN4L"),
+
+       SND_SOC_DAPM_INPUT("IN1R"),
+       SND_SOC_DAPM_INPUT("IN2R"),
+       SND_SOC_DAPM_INPUT("IN3R"),
+       SND_SOC_DAPM_INPUT("IN4R"),
+};
+
+static const struct snd_soc_dapm_route aic3262_dapm_routes[] = {
+       {"LDAC_2_HPL", NULL, "Left DAC"},
+       {"HPL Driver", NULL, "LDAC_2_HPL"},
+       {"HPL", NULL, "HPL Driver"},
+       {"RDAC_2_HPR", NULL, "Right DAC"},
+       {"HPR Driver", NULL, "RDAC_2_HPR"},
+       {"HPR", NULL, "HPR Driver"},
+
+       {"LDAC_2_LOL", NULL, "Left DAC"},
+       {"LOL Driver", NULL, "LDAC_2_LOL"},
+       {"LOL", NULL, "LOL Driver"},
+       {"RDAC_2_LOR", NULL, "Right DAC"},
+       {"LOR Driver", NULL, "RDAC_2_LOR"},
+       {"LOR", NULL, "LOR Driver"},
+
+       {"SPKL Driver", NULL, "LOL"},
+       {"SPKL", NULL, "SPKL Driver"},
+       {"SPKR Driver", NULL, "LOR"},
+       {"SPKR", NULL, "SPKR Driver"},
+
+       {"RECL Driver", NULL, "LOL"},
+       {"RECL", NULL, "RECL Driver"},
+       {"RECR Driver", NULL, "LOR"},
+       {"RECR", NULL, "RECR Driver"},
+
+       {"Left ADC", "IN1L Route", "IN1L"},
+       {"Left ADC", "IN2L Route", "IN2L"},
+       {"Left ADC", "IN3L Route", "IN3L"},
+       {"Left ADC", "IN4L Route", "IN4L"},
+
+       {"Right ADC", "IN1R Route", "IN1R"},
+       {"Right ADC", "IN2R Route", "IN2R"},
+       {"Right ADC", "IN3R Route", "IN3R"},
+       {"Right ADC", "IN4R Route", "IN4R"},
+/*
+       {"LOL Driver", NULL, "IN1L"},
+       {"LOR Driver", NULL, "IN1R"},
+*/
+};
+
+/*
+ *****************************************************************************
+ * Function Definitions
+ *****************************************************************************
+ */
+
+
+/*
+ *----------------------------------------------------------------------------
+ * Function : aic3262_change_page
+ * Purpose  : This function is to switch between page 0 and page 1.
+ *
+ *----------------------------------------------------------------------------
+ */
+int aic3262_change_page(struct snd_soc_codec *codec, u8 new_page)
+{
+       struct aic3262_priv *aic3262 = snd_soc_codec_get_drvdata(codec);
+       u8 data[2];
+       int ret = 0;
+
+       data[0] = 0;
+       data[1] = new_page;
+       aic3262->page_no = new_page;
+
+       ret = snd_soc_write(codec, data[0], data[1]);
+       if (ret)
+               printk(KERN_ERR "Error in changing page to %d\n", new_page);
+
+       DBG("# Changing page to %d\r\n", new_page);
+
+       return ret;
+}
+/*
+ *----------------------------------------------------------------------------
+ * Function : aic3262_change_book
+ * Purpose  : This function is to switch between books
+ *
+ *----------------------------------------------------------------------------
+ */
+int aic3262_change_book(struct snd_soc_codec *codec, u8 new_book)
+{
+       struct aic3262_priv *aic3262 = snd_soc_codec_get_drvdata(codec);
+       u8 data[2];
+       int ret = 0;
+
+       data[0] = 0x7F;
+       data[1] = new_book;
+       aic3262->book_no = new_book;
+
+       ret = aic3262_change_page(codec, 0);
+       if (ret)
+               return ret;
+
+       ret = snd_soc_write(codec, data[0], data[1]);
+       if (ret)
+               printk(KERN_ERR "Error in changing Book\n");
+
+       DBG("# Changing book to %d\r\n", new_book);
+
+       return ret;
+}
+/*
+ *----------------------------------------------------------------------------
+ * Function : aic3262_write_reg_cache
+ * Purpose  : This function is to write aic3262 register cache
+ *
+ *----------------------------------------------------------------------------
+ */
+void aic3262_write_reg_cache(struct snd_soc_codec *codec,
+                                          u16 reg, u8 value)
+{
+       u8 *cache = codec->reg_cache;
+
+       if (reg >= AIC3262_CACHEREGNUM)
+               return;
+
+       if (cache)
+               cache[reg] = value;
+}
+
+/*
+ *----------------------------------------------------------------------------
+ * Function : aic3262_read
+ * Purpose  : This function is to read the aic3262 register space.
+ *
+ *----------------------------------------------------------------------------
+ */
+u8 aic3262_read(struct snd_soc_codec *codec, u16 reg)
+{
+       struct aic3262_priv *aic3262 = snd_soc_codec_get_drvdata(codec);
+       u8 value;
+       u8 page = reg / 128;
+
+       reg = reg % 128;
+
+       if (aic3262->page_no != page)
+               aic3262_change_page(codec, page);
+
+       value = snd_soc_read(codec, reg);
+       /*DBG("r %2x %02x\r\n", reg, value);*/
+       return value;
+}
+
+/*
+ *----------------------------------------------------------------------------
+ * Function : aic3262_write
+ * Purpose  : This function is to write to the aic3262 register space.
+ *
+ *----------------------------------------------------------------------------
+ */
+int aic3262_write(struct snd_soc_codec *codec, u16 reg, u8 value)
+{
+       struct aic3262_priv *aic3262 = snd_soc_codec_get_drvdata(codec);
+       u8 data[2];
+       u8 page;
+       int ret = 0;
+
+       page = reg / 128;
+       data[AIC3262_REG_OFFSET_INDEX] = reg % 128;
+       if (aic3262->page_no != page)
+               aic3262_change_page(codec, page);
+
+       /* data is
+        *   D15..D8 aic3262 register offset
+        *   D7...D0 register data
+        */
+       data[AIC3262_REG_DATA_INDEX] = value & AIC3262_8BITS_MASK;
+#if defined(EN_REG_CACHE)
+       if ((page >= 0) & (page <= 4))
+               aic3262_write_reg_cache(codec, reg, value);
+
+#endif
+       if (!data[AIC3262_REG_OFFSET_INDEX]) {
+               /* if the write is to reg0 update aic3262->page_no */
+               aic3262->page_no = value;
+       }
+
+       /*DBG("w %2x %02x\r\n",
+               data[AIC3262_REG_OFFSET_INDEX], data[AIC3262_REG_DATA_INDEX]);*/
+       ret = snd_soc_write(codec, data[AIC3262_REG_OFFSET_INDEX],
+                       data[AIC3262_REG_DATA_INDEX]);
+       if (ret)
+               printk(KERN_ERR "Error in i2c write\n");
+
+       return ret;
+}
+
+/*
+ *------------------------------------------------------------------------------
+ * Function : aic3262_write__
+ * Purpose  : This function is to write to the aic3262 register space.
+ *            (low level).
+ *------------------------------------------------------------------------------
+ */
+
+int aic3262_write__(struct i2c_client *client, const char *buf, int count)
+{
+       u8 data[3];
+       int ret;
+       data[0] = *buf;
+       data[1] = *(buf+1);
+       data[2] = *(buf+2);
+       /*DBG("w %2x %02x\r\n",
+               data[AIC3262_REG_OFFSET_INDEX], data[AIC3262_REG_DATA_INDEX]);*/
+       ret = i2c_master_send(client, data, 2);
+       if (ret < 2) {
+               printk(
+               KERN_ERR"I2C write Error : bytes written = %d\n\n", ret);
+               return -EIO;
+       }
+
+       return ret;
+}
+/*
+ *----------------------------------------------------------------------------
+ * Function : aic3262_reset_cache
+ * Purpose  : This function is to reset the cache.
+ *----------------------------------------------------------------------------
+ */
+int aic3262_reset_cache(struct snd_soc_codec *codec)
+{
+#if defined(EN_REG_CACHE)
+       if (codec->reg_cache) {
+               memcpy(codec->reg_cache, aic3262_reg, sizeof(aic3262_reg));
+               return 0;
+       }
+#endif
+       return 0;
+}
+
+/*
+ *----------------------------------------------------------------------------
+ * Function : aic3262_get_divs
+ * Purpose  : This function is to get required divisor from the "aic3262_divs"
+ *            table.
+ *
+ *----------------------------------------------------------------------------
+ */
+static inline int aic3262_get_divs(int mclk, int rate)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(aic3262_divs); i++) {
+               if ((aic3262_divs[i].rate == rate)
+                   && (aic3262_divs[i].mclk == mclk)) {
+                       DBG(KERN_INFO "#%s: Found Entry %d in Clock_Array\n",
+                               __func__, i);
+                       return i;
+               }
+       }
+       printk(KERN_ERR "Master clock and sample rate is not supported\n");
+       return -EINVAL;
+}
+
+/*
+ *----------------------------------------------------------------------------
+ * Function : aic3262_add_controls
+ * Purpose  : This function is to add non dapm kcontrols.  The different
+ *            controls are in "aic3262_snd_controls" table.
+ *            The following different controls are supported
+ *                # PCM Playback volume control
+ *                               # PCM Playback Volume
+ *                               # HP Driver Gain
+ *                               # HP DAC Playback Switch
+ *                               # PGA Capture Volume
+ *                               # Program Registers
+ *
+ *----------------------------------------------------------------------------
+ */
+static int aic3262_add_controls(struct snd_soc_codec *codec)
+{
+       int err;
+
+       err = snd_soc_add_controls(codec, aic3262_snd_controls,
+               ARRAY_SIZE(aic3262_snd_controls));
+       if (err < 0) {
+               printk(KERN_ERR "Invalid control\n");
+               return err;
+       }
+
+       err = snd_soc_add_controls(codec, aic3262_snd_controls2,
+               ARRAY_SIZE(aic3262_snd_controls2));
+       if (err < 0) {
+               printk(KERN_ERR "Invalid control\n");
+               return err;
+       }
+
+       return 0;
+}
+
+/*
+ *----------------------------------------------------------------------------
+ * Function : aic3262_add_widgets
+ * Purpose  : This function is to add the dapm widgets
+ *            The following are the main widgets supported
+ *                # Left DAC to Left Outputs
+ *                # Right DAC to Right Outputs
+ *               # Left Inputs to Left ADC
+ *               # Right Inputs to Right ADC
+ *
+ *----------------------------------------------------------------------------
+ */
+static int aic3262_add_widgets(struct snd_soc_codec *codec)
+{
+       int ret;
+       struct snd_soc_dapm_context *dapm = &codec->dapm;
+#ifndef AIC3262_MULTI_I2S
+       int i;
+       for (i = 0; i < ARRAY_SIZE(aic3262_dapm_widgets); i++)
+               ret = snd_soc_dapm_new_control(dapm, &aic3262_dapm_widgets[i]);
+#else
+       ret = snd_soc_dapm_new_controls(dapm, aic3262_dapm_widgets,
+                       ARRAY_SIZE(aic3262_dapm_widgets));
+       if (ret != 0) {
+               printk(KERN_ERR "#%s: Unable to add DAPM Controls. Err %d\n",
+                                __func__, ret);
+       }
+#endif
+       /* set up audio path interconnects */
+       DBG("#Completed adding new dapm widget controls size=%d\n",
+               ARRAY_SIZE(aic3262_dapm_widgets));
+       snd_soc_dapm_add_routes(dapm, aic3262_dapm_routes,
+                               ARRAY_SIZE(aic3262_dapm_routes));
+       DBG("#Completed adding DAPM routes\n");
+       /*snd_soc_dapm_new_widgets(codec);*/
+       DBG("#Completed updating dapm\n");
+       return 0;
+}
+/*
+ *----------------------------------------------------------------------------
+ * Function : reg_def_conf
+ * Purpose  : This function is to reset the codec book 0 registers
+ *
+ *----------------------------------------------------------------------------
+ */
+int reg_def_conf(struct snd_soc_codec *codec)
+{
+       int i = 0, ret;
+
+       aic3262_change_page(codec, 0);
+       aic3262_change_book(codec, 0);
+
+       /* Configure the Codec with the default Initialization Values */
+       for (i = 0; i < reg_init_size; i++) {
+               ret = aic3262_write(codec, aic3262_reg_init[i].reg_offset,
+                       aic3262_reg_init[i].reg_val);
+               if (ret)
+                       break;
+       }
+       return ret;
+}
+
+/*
+ * i2c_verify_book0
+ *
+ * This function is used to dump the values of the Book 0 Pages.
+ */
+int i2c_verify_book0(struct snd_soc_codec *codec)
+{
+       int i, j, k = 0;
+       u8 val1;
+
+       DBG("starting i2c_verify\n");
+       DBG("Resetting page to 0\n");
+       aic3262_change_book(codec, 0);
+       for (j = 0; j < 3; j++) {
+               if (j == 0) {
+                       aic3262_change_page(codec, 0);
+                       k = 0;
+               }
+               if (j == 1) {
+                       aic3262_change_page(codec, 1);
+                       k = 1;
+               }
+               /*
+               if (j == 2) {
+                       aic3262_change_page(codec, 4);
+                       k = 4;
+               }*/
+               for (i = 0; i <= 127; i++) {
+                       val1 = snd_soc_read(codec, i);
+                       /* printk("[%d][%d]=[0x%2x]\n",k,i,val1); */
+               }
+       }
+       return 0;
+}
+
+
+
+/*
+ *----------------------------------------------------------------------------
+ * Function : aic3262_hw_params
+ * Purpose  : This function is to set the hardware parameters for AIC3262.
+ *            The functions set the sample rate and audio serial data word
+ *            length.
+ *
+ *----------------------------------------------------------------------------
+ */
+static int aic3262_hw_params(struct snd_pcm_substream *substream,
+                            struct snd_pcm_hw_params *params,
+                            struct snd_soc_dai *dai)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_codec *codec = rtd->codec;
+       struct aic3262_priv *aic3262 = snd_soc_codec_get_drvdata(codec);
+       int i, j;
+       u8 data;
+
+       aic3262_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+
+       i = aic3262_get_divs(aic3262->sysclk, params_rate(params));
+
+       i2c_verify_book0(codec);
+
+       if (i < 0) {
+               printk(KERN_ERR "sampling rate not supported\n");
+               return i;
+       }
+
+       if (soc_static_freq_config) {
+               /*We will fix R value to 1 and make P & J=K.D as varialble */
+
+               /* Setting P & R values are set to 1 and 1 at init*/
+
+               /* J value */
+               aic3262_write(codec, PLL_J_REG, aic3262_divs[i].pll_j);
+
+               /* MSB & LSB for D value */
+
+               aic3262_write(codec, PLL_D_MSB, (aic3262_divs[i].pll_d >> 8));
+               aic3262_write(codec, PLL_D_LSB,
+                             (aic3262_divs[i].pll_d & AIC3262_8BITS_MASK));
+
+               /* NDAC divider value */
+               data = aic3262_read(codec, NDAC_DIV_POW_REG);
+               DBG(KERN_INFO "# reading NDAC = %d , NDAC_DIV_POW_REG = %x\n",
+                       aic3262_divs[i].ndac, data);
+               aic3262_write(codec, NDAC_DIV_POW_REG,
+                        ((data & 0x80)|(aic3262_divs[i].ndac)));
+               DBG(KERN_INFO "# writing NDAC = %d , NDAC_DIV_POW_REG = %x\n",
+                       aic3262_divs[i].ndac,
+                       ((data & 0x80)|(aic3262_divs[i].ndac)));
+
+               /* MDAC divider value */
+               data = aic3262_read(codec, MDAC_DIV_POW_REG);
+               DBG(KERN_INFO "# reading MDAC = %d , MDAC_DIV_POW_REG = %x\n",
+                       aic3262_divs[i].mdac, data);
+               aic3262_write(codec, MDAC_DIV_POW_REG,
+                        ((data & 0x80)|(aic3262_divs[i].mdac)));
+               DBG(KERN_INFO "# writing MDAC = %d , MDAC_DIV_POW_REG = %x\n",
+               aic3262_divs[i].mdac, ((data & 0x80)|(aic3262_divs[i].mdac)));
+
+               /* DOSR MSB & LSB values */
+               aic3262_write(codec, DOSR_MSB_REG, aic3262_divs[i].dosr >> 8);
+               DBG(KERN_INFO "# writing DOSR_MSB_REG = %d\n",
+                       (aic3262_divs[i].dosr >> 8));
+               aic3262_write(codec, DOSR_LSB_REG,
+                             aic3262_divs[i].dosr & AIC3262_8BITS_MASK);
+               DBG(KERN_INFO "# writing DOSR_LSB_REG = %d\n",
+                       (aic3262_divs[i].dosr & AIC3262_8BITS_MASK));
+
+               /* NADC divider value */
+               data = aic3262_read(codec, NADC_DIV_POW_REG);
+               aic3262_write(codec, NADC_DIV_POW_REG,
+                        ((data & 0x80)|(aic3262_divs[i].nadc)));
+               DBG(KERN_INFO "# writing NADC_DIV_POW_REG = %d\n",
+                       aic3262_divs[i].nadc);
+
+               /* MADC divider value */
+               data = aic3262_read(codec, MADC_DIV_POW_REG);
+               aic3262_write(codec, MADC_DIV_POW_REG,
+                       ((data & 0x80)|(aic3262_divs[i].madc)));
+               DBG(KERN_INFO "# writing MADC_DIV_POW_REG = %d\n",
+                       aic3262_divs[i].madc);
+
+               /* AOSR value */
+               aic3262_write(codec, AOSR_REG, aic3262_divs[i].aosr);
+               DBG(KERN_INFO "# writing AOSR = %d\n", aic3262_divs[i].aosr);
+       }
+
+
+       data = aic3262_read(codec, ASI1_BUS_FMT);
+
+       data = data & 0xe7;
+
+       switch (params_format(params)) {
+       case SNDRV_PCM_FORMAT_S16_LE:
+               data = data | 0x00;
+               break;
+       case SNDRV_PCM_FORMAT_S20_3LE:
+               data |= (0x08);
+               break;
+       case SNDRV_PCM_FORMAT_S24_LE:
+               data |= (0x10);
+               break;
+       case SNDRV_PCM_FORMAT_S32_LE:
+               data |= (0x18);
+               break;
+       }
+
+       /* configure the respective Registers for the above configuration */
+       aic3262_write(codec, ASI1_BUS_FMT, data);
+
+       for (j = 0; j < NO_FEATURE_REGS; j++) {
+               aic3262_write(codec,
+                             aic3262_divs[i].codec_specific_regs[j].reg_offset,
+                             aic3262_divs[i].codec_specific_regs[j].reg_val);
+       }
+
+       aic3262_set_bias_level(codec, SND_SOC_BIAS_ON);
+       return 0;
+}
+
+/*
+ *----------------------------------------------------------------------------
+ * Function : aic3262_mute
+ * Purpose  : This function is to mute or unmute the left and right DAC
+ *
+ *----------------------------------------------------------------------------
+ */
+static int aic3262_mute(struct snd_soc_dai *dai, int mute)
+{
+       struct snd_soc_codec *codec = dai->codec;
+       struct aic3262_priv *aic3262 = snd_soc_codec_get_drvdata(codec);
+
+       DBG(KERN_INFO "#aic3262 codec : mute started\n");
+       if (mute) {
+               DBG("Mute if part\n");
+
+               if (!aic3262->mute_codec) {
+                       dac_reg = aic3262_read(codec, DAC_MVOL_CONF);
+                       adc_gain = aic3262_read(codec, ADC_FINE_GAIN);
+                       hpl = aic3262_read(codec, HPL_VOL);
+                       hpr = aic3262_read(codec, HPR_VOL);
+                       rec_amp = aic3262_read(codec, REC_AMP_CNTL_R5);
+                       rampr = aic3262_read(codec, RAMPR_VOL);
+                       spk_amp = aic3262_read(codec, SPK_AMP_CNTL_R4);
+               }
+               DBG("spk_reg = %2x\n\n", spk_amp);
+
+               aic3262_write(codec, DAC_MVOL_CONF, ((dac_reg & 0xF3) | 0x0C));
+               aic3262_write(codec, ADC_FINE_GAIN, ((adc_gain & 0x77) | 0x88));
+               aic3262_write(codec, HPL_VOL, 0xB9);
+               aic3262_write(codec, HPR_VOL, 0xB9);
+               aic3262_write(codec, REC_AMP_CNTL_R5, 0x39);
+               aic3262_write(codec, RAMPR_VOL, 0x39);
+               aic3262_write(codec, SPK_AMP_CNTL_R4, 0x00);
+               aic3262->mute_codec = 1;
+       } else {
+               DBG("Mute else part\n");
+               aic3262_write(codec, DAC_MVOL_CONF, (dac_reg & 0xF3));
+               mdelay(5);
+               aic3262_write(codec, ADC_FINE_GAIN, (adc_gain & 0x77));
+               mdelay(5);
+               aic3262_write(codec, HPL_VOL, hpl);
+               mdelay(5);
+               aic3262_write(codec, HPR_VOL, hpr);
+               mdelay(5);
+               aic3262_write(codec, REC_AMP_CNTL_R5, rec_amp);
+               mdelay(5);
+               aic3262_write(codec, RAMPR_VOL, rampr);
+               mdelay(5);
+               aic3262_write(codec, SPK_AMP_CNTL_R4, spk_amp);
+               mdelay(5);
+               aic3262->mute_codec = 0;
+       }
+       DBG(KERN_INFO "#aic3262 codec : mute ended\n");
+       return 0;
+}
+
+/*
+ *----------------------------------------------------------------------------
+ * Function : aic3262_set_dai_sysclk
+ * Purpose  : This function is to set the DAI system clock
+ *
+ *----------------------------------------------------------------------------
+ */
+static int aic3262_set_dai_sysclk(struct snd_soc_dai *codec_dai,
+                                 int clk_id, unsigned int freq, int dir)
+{
+       struct snd_soc_codec *codec = codec_dai->codec;
+       struct aic3262_priv *aic3262 = snd_soc_codec_get_drvdata(codec);
+
+       switch (freq) {
+       case AIC3262_FREQ_12000000:
+       case AIC3262_FREQ_12288000:
+               aic3262->sysclk = freq;
+               return 0;
+       case AIC3262_FREQ_24000000:
+               aic3262->sysclk = freq;
+               return 0;
+               break;
+       }
+       printk(KERN_ERR "Invalid frequency to set DAI system clock\n");
+       return -EINVAL;
+}
+
+/*
+ *----------------------------------------------------------------------------
+ * Function : aic3262_set_dai_fmt
+ * Purpose  : This function is to set the DAI format
+ *
+ *----------------------------------------------------------------------------
+ */
+static int aic3262_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
+{
+       struct snd_soc_codec *codec = codec_dai->codec;
+       struct aic3262_priv *aic3262 = snd_soc_codec_get_drvdata(codec);
+       u8 iface_reg, clk_reg;
+
+       iface_reg = aic3262_read(codec, ASI1_BUS_FMT);
+
+       /* set master/slave audio interface */
+       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+       case SND_SOC_DAIFMT_CBM_CFM:
+               DBG("setdai_fmt : SND_SOC_DAIFMT_CBM_CFM : master=1\n");
+               aic3262->master = 1;
+               /*Test added */
+               clk_reg = aic3262_read(codec, ASI1_BWCLK_CNTL_REG);
+               clk_reg = (clk_reg & 0x03);
+               aic3262_write(codec, ASI1_BWCLK_CNTL_REG,
+                                     (clk_reg | 0x24));
+               break;
+       case SND_SOC_DAIFMT_CBS_CFS:
+               DBG("setdai_fmt : SND_SOC_DAIFMT_CBS_CFS : master=0\n");
+               aic3262->master = 0;
+               /*Test added */
+               clk_reg = aic3262_read(codec, ASI1_BWCLK_CNTL_REG);
+               aic3262_write(codec, ASI1_BWCLK_CNTL_REG,
+                                     (clk_reg & 0x03));
+               break;
+       case SND_SOC_DAIFMT_CBS_CFM: /*new case..just for debugging*/
+               DBG("SND_SOC_DAIFMT_CBS_CFM\n");
+               aic3262->master = 0;
+               break;
+       default:
+               printk(KERN_ERR "Invalid DAI master/slave interface\n");
+               return -EINVAL;
+       }
+
+       /* interface format */
+       switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+       case SND_SOC_DAIFMT_I2S:
+               iface_reg = (iface_reg & 0x1f);
+               break;
+       case SND_SOC_DAIFMT_DSP_A:
+               iface_reg = (iface_reg & 0x1f) | 0x20;
+               break;
+       case SND_SOC_DAIFMT_RIGHT_J:
+               iface_reg = (iface_reg & 0x1f) | 0x40;
+               break;
+       case SND_SOC_DAIFMT_LEFT_J:
+               iface_reg = (iface_reg & 0x1f) | 0x60;
+               break;
+       case SND_SOC_DAIFMT_DSP_B:
+               iface_reg = (iface_reg & 0x1f) | 0x80;
+               /* voice call need data offset in 1 bitclock */
+               aic3262_write(codec, ASI1_LCH_OFFSET, 1);
+               break;
+       default:
+               printk(KERN_ERR "Invalid DAI interface format\n");
+               return -EINVAL;
+       }
+
+       aic3262_write(codec, ASI1_BUS_FMT, iface_reg);
+
+       return 0;
+}
+
+/*
+ *----------------------------------------------------------------------------
+ * Function : aic3262_set_bias_level
+ * Purpose  : This function is to get triggered when dapm events occurs.
+ *
+ *----------------------------------------------------------------------------
+ */
+static int aic3262_set_bias_level(struct snd_soc_codec *codec,
+                                 enum snd_soc_bias_level level)
+{
+       u8 value;
+       struct aic3262_priv *aic3262 = snd_soc_codec_get_drvdata(codec);
+
+       DBG(KERN_INFO "#%s: Codec Active %d[%d]\n",
+               __func__, codec->active, aic3262->active_count);
+       switch (level) {
+               /* full On */
+       case SND_SOC_BIAS_ON:
+               DBG(KERN_INFO "#aic3262 codec : set_bias_on started\n");
+       case SND_SOC_BIAS_PREPARE:
+               /* all power is driven by DAPM system */
+               DBG(KERN_INFO "#aic3262 codec : set_bias_prepare started\n");
+
+               /* Switch on PLL */
+               value = aic3262_read(codec, PLL_PR_POW_REG);
+               aic3262_write(codec, PLL_PR_POW_REG, ((value | 0x80)));
+
+               /* Switch on NDAC Divider */
+               value = aic3262_read(codec, NDAC_DIV_POW_REG);
+               aic3262_write(codec, NDAC_DIV_POW_REG,
+                       ((value & 0x7f) | (0x80)));
+
+               /* Switch on MDAC Divider */
+               value = aic3262_read(codec, MDAC_DIV_POW_REG);
+               aic3262_write(codec, MDAC_DIV_POW_REG,
+                       ((value & 0x7f) | (0x80)));
+
+               /* Switch on NADC Divider */
+               value = aic3262_read(codec, NADC_DIV_POW_REG);
+               aic3262_write(codec, NADC_DIV_POW_REG,
+                       ((value & 0x7f) | (0x80)));
+
+               /* Switch on MADC Divider */
+               value = aic3262_read(codec, MADC_DIV_POW_REG);
+               aic3262_write(codec, MADC_DIV_POW_REG,
+                       ((value & 0x7f) | (0x80)));
+
+
+               aic3262_write(codec, ADC_CHANNEL_POW, 0xc2);
+               aic3262_write(codec, ADC_FINE_GAIN, 0x00);
+
+               DBG("#aic3262 codec : set_bias_on complete\n");
+
+               break;
+
+
+               /* Off, with power */
+       case SND_SOC_BIAS_STANDBY:
+               /*
+                * all power is driven by DAPM system,
+                * so output power is safe if bypass was set
+                */
+
+               DBG("#aic3262 codec : set_bias_stby inside if condn\n");
+
+               if (!aic3262->active_count) {
+                       /* Switch off NDAC Divider */
+                       value = aic3262_read(codec, NDAC_DIV_POW_REG);
+                       aic3262_write(codec, NDAC_DIV_POW_REG,
+                               (value & 0x7f));
+
+                       /* Switch off MDAC Divider */
+                       value = aic3262_read(codec, MDAC_DIV_POW_REG);
+                       aic3262_write(codec, MDAC_DIV_POW_REG,
+                               (value & 0x7f));
+
+                       /* Switch off NADC Divider */
+                       value = aic3262_read(codec, NADC_DIV_POW_REG);
+                       aic3262_write(codec, NADC_DIV_POW_REG,
+                               (value & 0x7f));
+
+                       /* Switch off MADC Divider */
+                       value = aic3262_read(codec, MADC_DIV_POW_REG);
+                       aic3262_write(codec, MADC_DIV_POW_REG,
+                               (value & 0x7f));
+
+                       /* Switch off PLL */
+                       value = aic3262_read(codec, PLL_PR_POW_REG);
+                       aic3262_write(codec, PLL_PR_POW_REG, (value & 0x7f));
+
+                       DBG("#%s: set_bias_stby complete\n", __func__);
+               } else
+                       DBG(KERN_INFO
+                       "#%s: Another Stream Active. No STANDBY\n", __func__);
+               break;
+
+               /* Off, without power */
+       case SND_SOC_BIAS_OFF:
+               /* force all power off */
+
+               /* Switch off PLL */
+               value = aic3262_read(codec, PLL_PR_POW_REG);
+               aic3262_write(codec,
+                       PLL_PR_POW_REG, (value & ~(0x01 << 7)));
+
+               /* Switch off NDAC Divider */
+               value = aic3262_read(codec, NDAC_DIV_POW_REG);
+               aic3262_write(codec, NDAC_DIV_POW_REG,
+                       (value & ~(0x01 << 7)));
+
+               /* Switch off MDAC Divider */
+               value = aic3262_read(codec, MDAC_DIV_POW_REG);
+               aic3262_write(codec, MDAC_DIV_POW_REG,
+                       (value & ~(0x01 << 7)));
+
+               /* Switch off NADC Divider */
+               value = aic3262_read(codec, NADC_DIV_POW_REG);
+               aic3262_write(codec, NADC_DIV_POW_REG,
+                       (value & ~(0x01 << 7)));
+
+               /* Switch off MADC Divider */
+               value = aic3262_read(codec, MADC_DIV_POW_REG);
+               aic3262_write(codec, MADC_DIV_POW_REG,
+                       (value & ~(0x01 << 7)));
+               value = aic3262_read(codec, ASI1_BCLK_N);
+
+               break;
+       }
+       codec->dapm.bias_level = level;
+       DBG(KERN_INFO "#aic3262 codec : set_bias exiting\n");
+       return 0;
+}
+
+/*
+ *----------------------------------------------------------------------------
+ * Function : aic3262_suspend
+ * Purpose  : This function is to suspend the AIC3262 driver.
+ *
+ *----------------------------------------------------------------------------
+ */
+static int aic3262_suspend(struct snd_soc_codec *codec, pm_message_t state)
+{
+       struct aic3262_priv *aic3262 = snd_soc_codec_get_drvdata(codec);
+
+       if (aic3262)
+               disable_irq(aic3262->irq);
+
+       aic3262_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+
+       return 0;
+}
+
+/*
+ *----------------------------------------------------------------------------
+ * Function : aic3262_resume
+ * Purpose  : This function is to resume the AIC3262 driver
+ *
+ *----------------------------------------------------------------------------
+ */
+static int aic3262_resume(struct snd_soc_codec *codec)
+{
+       int i;
+       u8 data[2];
+       int ret = 0;
+       struct aic3262_priv *aic3262 = snd_soc_codec_get_drvdata(codec);
+       u8 *cache = codec->reg_cache;
+
+       ret = aic3262_change_page(codec, 0);
+       if (ret)
+               return ret;
+
+       /* Sync reg_cache with the hardware */
+       for (i = 0; i < ARRAY_SIZE(aic3262_reg); i++) {
+               data[0] = i % 128;
+               data[1] = cache[i];
+
+               ret = snd_soc_write(codec, data[0], data[1]);
+               if (ret)
+                       break;
+       }
+
+       if (!ret) {
+               aic3262_change_page(codec, 0);
+               aic3262_set_bias_level(codec, SND_SOC_BIAS_ON);
+
+               if (aic3262)
+                       enable_irq(aic3262->irq);
+       }
+       return ret;
+}
+
+/*
+* aic3262_jack_handler
+*
+* This function is called from the Interrupt Handler
+* to check the status of the AIC3262 Registers related to Headset Detection
+*/
+static irqreturn_t aic3262_jack_handler(int irq, void *data)
+{
+       struct snd_soc_codec *codec = data;
+       struct aic3262_priv *aic3262 = snd_soc_codec_get_drvdata(codec);
+       unsigned int value;
+       unsigned int micbits, hsbits = 0;
+
+       DBG("%s++\n", __func__);
+
+       /* Read the Jack Status Register*/
+       value = snd_soc_read(codec, STICKY_FLAG2);
+       DBG(KERN_INFO "reg44 0x%x\n", value);
+
+       value = snd_soc_read(codec, INT_FLAG2);
+       DBG("reg46 0x%x\n", value);
+
+       value = snd_soc_read(codec, DAC_FLAG_R1);
+       DBG("reg37 0x%x\n", value);
+
+       micbits = value & DAC_FLAG_MIC_MASKBITS;
+       DBG("micbits 0x%x\n", micbits);
+
+       hsbits = value & DAC_FLAG_HS_MASKBITS;
+       DBG("hsbits 0x%x\n", hsbits);
+
+       /* sleep for debounce time */
+       msleep(aic3262->pdata->debounce_time_ms);
+
+       /* No Headphone or Headset*/
+       if (!micbits && !hsbits) {
+               snd_soc_jack_report(aic3262->headset_jack,
+                               0, SND_JACK_HEADSET);
+       }
+
+       /* Headphone Detected */
+       if ((micbits == DAC_FLAG_R1_NOMIC) || (hsbits)) {
+               snd_soc_jack_report(aic3262->headset_jack,
+                               SND_JACK_HEADPHONE, SND_JACK_HEADSET);
+       }
+
+       /* Headset Detected - only with capless */
+       if (micbits == DAC_FLAG_R1_MIC) {
+               snd_soc_jack_report(aic3262->headset_jack,
+                               SND_JACK_HEADSET, SND_JACK_HEADSET);
+       }
+
+       return IRQ_HANDLED;
+}
+
+/*
+* aic326x_headset_detect
+*
+* Call-back function called to check the status of Headset Pin.
+*/
+int aic326x_headset_detect(struct snd_soc_codec *codec,
+       struct snd_soc_jack *jack, int jack_type)
+{
+       struct aic3262_priv *aic3262 = snd_soc_codec_get_drvdata(codec);
+       aic3262->headset_jack = jack;
+
+       /*TODO*/
+       aic3262_jack_handler(aic3262->irq, codec);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(aic326x_headset_detect);
+
+
+#ifdef AIC3262_MULTI_I2S
+/*
+* aic3262_asi_default_config
+*
+* This function is used to perform the default pin configurations for
+* the functionalities which are specific to each ASI Port of the AIC3262
+* Audio Codec Chipset. The user is encouraged to change these values
+* if required on their platforms.
+*/
+static void aic3262_asi_default_config(struct snd_soc_codec *codec)
+{
+       struct aic3262_priv *aic3262 = snd_soc_codec_get_drvdata(codec);
+       u16 counter;
+
+       DBG(KERN_INFO
+               "#%s: Invoked. Will Config ASI Registers to Defaults..\n",
+                       __func__);
+       for (counter = 0; counter < MAX_ASI_COUNT; counter++) {
+               aic3262->asiCtxt[counter].asi_active = 0;
+               aic3262->asiCtxt[counter].bclk_div = 1;
+               aic3262->asiCtxt[counter].wclk_div = 1;
+               aic3262->asiCtxt[counter].port_muted = 1;
+               aic3262->asiCtxt[counter].bclk_div_option =
+                       BDIV_CLKIN_DAC_MOD_CLK;
+               aic3262->asiCtxt[counter].offset1 = 0;
+               aic3262->asiCtxt[counter].offset2 = 0;
+       }
+       /* ASI1 Defaults */
+       aic3262->asiCtxt[0].bclk_output = ASI1_BCLK_DIVIDER_OUTPUT;
+       aic3262->asiCtxt[0].wclk_output = GENERATED_DAC_FS;
+       aic3262->asiCtxt[0].left_dac_output  = DAC_PATH_LEFT;
+       aic3262->asiCtxt[0].right_dac_output = DAC_PATH_LEFT;
+       aic3262->asiCtxt[0].adc_input        = ADC_PATH_MINIDSP_1;
+       aic3262->asiCtxt[0].dout_option      = ASI_OUTPUT;
+
+       /* ASI2 Defaults */
+       aic3262->asiCtxt[1].bclk_output = ASI2_BCLK_DIVIDER_OUTPUT;
+       aic3262->asiCtxt[1].wclk_output = GENERATED_DAC_FS;
+       aic3262->asiCtxt[1].left_dac_output  = DAC_PATH_LEFT;
+       aic3262->asiCtxt[1].right_dac_output = DAC_PATH_LEFT;
+       aic3262->asiCtxt[1].adc_input        = ADC_PATH_MINIDSP_2;
+       aic3262->asiCtxt[1].dout_option      = ASI_OUTPUT;
+
+       /* ASI3 Defaults */
+       aic3262->asiCtxt[2].bclk_output = ASI3_BCLK_DIVIDER_OUTPUT;
+       aic3262->asiCtxt[2].wclk_output = GENERATED_DAC_FS;
+       aic3262->asiCtxt[2].left_dac_output  = DAC_PATH_LEFT;
+       aic3262->asiCtxt[2].right_dac_output = DAC_PATH_LEFT;
+       aic3262->asiCtxt[2].adc_input        = ADC_PATH_MINIDSP_3;
+       aic3262->asiCtxt[2].dout_option      = ASI2_INPUT;
+
+       return;
+}
+
+#endif /* #ifdef AIC3262_MULTI_I2S */
+
+/*
+ *----------------------------------------------------------------------------
+ * Function : aic3262_probe
+ * Purpose  : This is first driver function called by the SoC core driver.
+ *
+ *----------------------------------------------------------------------------
+ */
+static int aic3262_probe(struct snd_soc_codec *codec)
+{
+       struct aic3262_priv *aic3262 = snd_soc_codec_get_drvdata(codec);
+       int ret = 0;
+
+       DBG(KERN_INFO "#%s: Invoked..\n", __func__);
+
+       /* Setting cache bypass - not to overwrite the cache registers,
+       Codec registers have 4 pages which is not handled in the common
+       cache code properly - bypass it in write value and save it
+       using separate call*/
+       codec->cache_bypass = 1;
+
+       ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_I2C);
+       if (ret != 0) {
+               dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
+               return ret;
+       }
+
+       ret = reg_def_conf(codec);
+       if (ret != 0) {
+               printk(KERN_ERR "Failed to init TI codec: %d\n", ret);
+               return ret;
+       }
+
+       if (aic3262->irq) {
+               /* audio interrupt */
+               ret = request_threaded_irq(aic3262->irq, NULL,
+                               aic3262_jack_handler,
+                               IRQF_TRIGGER_FALLING,
+                               "tlv320aic3262", codec);
+               if (ret) {
+                       printk(KERN_INFO "#%s: IRQ Registration failed..[%d]",
+                                       __func__, ret);
+                       dev_err(codec->dev, "Failed to request IRQ: %d\n", ret);
+                       return ret;
+               } else
+                       printk(KERN_INFO
+                               "#%s: irq Registration for IRQ %d done..\n",
+                                       __func__, aic3262->irq);
+       } else {
+               printk(KERN_INFO "#%s: I2C IRQ Configuration is Wrong. \
+                       Please check it..\n", __func__);
+       }
+
+       aic3262_asi_default_config(codec);
+
+       /* off, with power on */
+       aic3262_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+
+       aic3262_add_controls(codec);
+       aic3262_add_widgets(codec);
+       /*TODO*/
+       aic3262_write(codec, MIC_BIAS_CNTL, 0x66);
+
+#ifdef CONFIG_MINI_DSP
+       /* Program MINI DSP for ADC and DAC */
+       aic3262_minidsp_program(codec);
+       aic3262_add_minidsp_controls(codec);
+       aic3262_change_book(codec, 0x0);
+#endif
+
+#ifdef MULTIBYTE_CONFIG_SUPPORT
+       aic3262_add_multiconfig_controls(codec);
+#endif
+
+       return ret;
+}
+
+/*
+ *----------------------------------------------------------------------------
+ * Function : aic3262_remove
+ * Purpose  : to remove aic3262 soc device
+ *
+ *----------------------------------------------------------------------------
+ */
+static int aic3262_remove(struct snd_soc_codec *codec)
+{
+
+       /* power down chip */
+       aic3262_set_bias_level(codec, SND_SOC_BIAS_OFF);
+
+       return 0;
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ * @struct  snd_soc_codec_device |
+ *          This structure is soc audio codec device sturecute which pointer
+ *          to basic functions aic3262_probe(), aic3262_remove(),
+ *          aic3262_suspend() and aic3262_resume()
+ *----------------------------------------------------------------------------
+ */
+static struct snd_soc_codec_driver soc_codec_dev_aic3262 = {
+       .probe = aic3262_probe,
+       .remove = aic3262_remove,
+       .suspend = aic3262_suspend,
+       .resume = aic3262_resume,
+       .set_bias_level = aic3262_set_bias_level,
+       .reg_cache_size = ARRAY_SIZE(aic3262_reg),
+       .reg_word_size = sizeof(u16),
+       .reg_cache_default = aic3262_reg,
+       .compress_type = SND_SOC_FLAT_COMPRESSION,
+};
+
+
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+/*
+ *----------------------------------------------------------------------------
+ * Function : aic3262_codec_probe
+ * Purpose  : This function attaches the i2c client and initializes
+ *                             AIC3262 CODEC.
+ *            NOTE:
+ *            This function is called from i2c core when the I2C address is
+ *            valid.
+ *            If the i2c layer weren't so broken, we could pass this kind of
+ *            data around
+ *
+ *----------------------------------------------------------------------------
+ */
+static __devinit int aic3262_codec_probe(struct i2c_client *i2c,
+                       const struct i2c_device_id *id)
+{
+       int ret;
+
+       struct aic3262_priv *aic3262;
+
+       DBG(KERN_INFO "#%s: Entered\n", __func__);
+
+       aic3262 = kzalloc(sizeof(struct aic3262_priv), GFP_KERNEL);
+
+       if (!aic3262) {
+               printk(KERN_ERR "#%s: Unable to Allocate Priv struct..\n",
+                       __func__);
+               return -ENOMEM;
+       }
+
+       i2c_set_clientdata(i2c, aic3262);
+       aic3262->control_type = SND_SOC_I2C;
+       aic3262->irq = i2c->irq;
+       aic3262->pdata = i2c->dev.platform_data;
+
+       /* The Configuration Support will be by default to 3 which
+       * holds the MAIN Patch Configuration.
+       */
+       aic3262->current_dac_config[0] = -1;
+       aic3262->current_dac_config[1] = -1;
+       aic3262->current_adc_config[0] = -1;
+       aic3262->current_adc_config[1] = -1;
+
+       aic3262->mute_codec = 1;
+
+       aic3262->page_no = 0;
+       aic3262->book_no = 0;
+       aic3262->active_count = 0;
+       aic3262->dac_clkin_option = 3;
+       aic3262->adc_clkin_option = 3;
+
+       ret = snd_soc_register_codec(&i2c->dev,
+               &soc_codec_dev_aic3262,
+               tlv320aic3262_dai, ARRAY_SIZE(tlv320aic3262_dai));
+
+       if (ret < 0)
+               kfree(aic3262);
+
+       return ret;
+}
+
+/*
+ *----------------------------------------------------------------------------
+ * Function : aic3262_i2c_remove
+ * Purpose  : This function removes the i2c client and uninitializes
+ *                              AIC3262 CODEC.
+ *            NOTE:
+ *            This function is called from i2c core
+ *            If the i2c layer weren't so broken, we could pass this kind of
+ *            data around
+ *
+ *----------------------------------------------------------------------------
+ */
+static __devexit int aic3262_i2c_remove(struct i2c_client *i2c)
+{
+       snd_soc_unregister_codec(&i2c->dev);
+       kfree(i2c_get_clientdata(i2c));
+       return 0;
+}
+
+static const struct i2c_device_id tlv320aic3262_id[] = {
+       {"tlv320aic3262", 0},
+       {}
+};
+MODULE_DEVICE_TABLE(i2c, tlv320aic3262_id);
+
+static struct i2c_driver tlv320aic3262_i2c_driver = {
+       .driver = {
+               .name = "tlv320aic3262",
+               .owner = THIS_MODULE,
+       },
+       .probe = aic3262_codec_probe,
+       .remove = __devexit_p(aic3262_i2c_remove),
+       .id_table = tlv320aic3262_id,
+};
+#endif /*#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)*/
+
+static int __init tlv320aic3262_modinit(void)
+{
+       int ret = 0;
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+       ret = i2c_add_driver(&tlv320aic3262_i2c_driver);
+       if (ret != 0)
+               printk(KERN_ERR "Failed to register aic326x i2c driver %d\n",
+                       ret);
+#endif
+       return ret;
+
+}
+module_init(tlv320aic3262_modinit);
+
+static void __exit tlv320aic3262_exit(void)
+{
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+       i2c_del_driver(&tlv320aic3262_i2c_driver);
+#endif
+}
+module_exit(tlv320aic3262_exit);
+
+MODULE_DESCRIPTION("ASoC TLV320AIC3262 codec driver");
+MODULE_AUTHOR("Barani Prashanth<gvbarani@mistralsolutions.com>");
+MODULE_AUTHOR("Ravindra<ravindra@mistralsolutions.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/tlv320aic326x.h b/sound/soc/codecs/tlv320aic326x.h
new file mode 100755 (executable)
index 0000000..e6e6735
--- /dev/null
@@ -0,0 +1,629 @@
+/*
+ * linux/sound/soc/codecs/tlv320aic3262.h
+ *
+ *
+ * Copyright (C) 2011 Mistral Solutions Pvt Ltd.
+ *
+ * This package 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.
+ *
+ * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * History:
+ *  Rev 0.1   ASoC driver support    Mistral         20-01-2011
+ *
+ * The AIC3262 ASoC driver is ported for the codec AIC3262.
+ *
+ */
+
+#ifndef _TLV320AIC3262_H
+#define _TLV320AIC3262_H
+
+#define AUDIO_NAME "aic3262"
+#define AIC3262_VERSION "1.1"
+
+/* Enable this macro allow for different ASI formats */
+/*#define ASI_MULTI_FMT*/
+#undef ASI_MULTI_FMT
+/* Enable register caching on write */
+#define EN_REG_CACHE
+
+#define MULTIBYTE_CONFIG_SUPPORT
+
+
+/* Macro enables or disables support for miniDSP in the driver */
+/* Enable the AIC3262_TiLoad macro first before enabling these macros */
+#define CONFIG_MINI_DSP
+/*#undef CONFIG_MINI_DSP*/
+
+/* Enable or disable controls to have Input routing*/
+/*#define FULL_IN_CNTL */
+#undef FULL_IN_CNTL
+/* AIC3262 supported sample rate are 8k to 192k */
+#define AIC3262_RATES  SNDRV_PCM_RATE_8000_192000
+
+/* AIC3262 supports the word formats 16bits, 20bits, 24bits and 32 bits */
+#define AIC3262_FORMATS        (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE \
+                        | SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S32_LE)
+
+#define AIC3262_FREQ_12000000 12000000
+#define AIC3262_FREQ_12288000 12288000
+#define AIC3262_FREQ_24000000 24000000
+
+/* Macro for enabling the Multi_I2S Support in Driver */
+#define AIC3262_MULTI_I2S      1
+
+/* Driver Debug Messages Enabled */
+#define DEBUG
+
+#ifdef DEBUG
+       #define DBG(x...)       printk(x)
+#else
+       #define DBG(x...)
+#endif
+
+/*Select the below macro to decide on the DAC master volume controls.
+ *2 independent or one combined
+ */
+/*#define DAC_INDEPENDENT_VOL*/
+#undef DAC_INDEPENDENT_VOL
+
+/* Audio data word length = 16-bits (default setting) */
+#define AIC3262_WORD_LEN_16BITS                0x00
+#define AIC3262_WORD_LEN_20BITS                0x01
+#define AIC3262_WORD_LEN_24BITS                0x02
+#define AIC3262_WORD_LEN_32BITS                0x03
+
+/* sink: name of target widget */
+#define AIC3262_WIDGET_NAME    0
+/* control: mixer control name */
+#define AIC3262_CONTROL_NAME
+/* source: name of source name */
+#define AIC3262_SOURCE_NAME    2
+
+/* D15..D8 aic3262 register offset */
+#define AIC3262_REG_OFFSET_INDEX    0
+/* D7...D0 register data */
+#define AIC3262_REG_DATA_INDEX      1
+
+/* Serial data bus uses I2S mode (Default mode) */
+#define AIC3262_I2S_MODE               0x00
+#define AIC3262_DSP_MODE               0x01
+#define AIC3262_RIGHT_JUSTIFIED_MODE   0x02
+#define AIC3262_LEFT_JUSTIFIED_MODE    0x03
+
+/* 8 bit mask value */
+#define AIC3262_8BITS_MASK           0xFF
+
+/* shift value for CLK_REG_3 register */
+#define CLK_REG_3_SHIFT                        6
+/* shift value for DAC_OSR_MSB register */
+#define DAC_OSR_MSB_SHIFT              4
+
+/* number of codec specific register for configuration */
+#define NO_FEATURE_REGS                        2
+
+/* Total number of ASI Ports */
+#define MAX_ASI_COUNT                  3
+
+/* AIC3262 register space */
+/* Updated from 256 to support Page 3 registers */
+#define        AIC3262_CACHEREGNUM             1024
+#define BIT7             (0x01 << 7)
+#define BIT6             (0x01 << 6)
+#define BIT5             (0x01 << 5)
+#define BIT4             (0x01 << 4)
+#define BIT3             (0x01 << 3)
+#define BIT2             (0x01 << 2)
+#define BIT1             (0x01 << 1)
+#define BIT0             (0x01 << 0)
+
+#define DAC_FLAG_MIC_MASKBITS  0x30
+#define DAC_FLAG_HS_MASKBITS   0x03
+#define DAC_FLAG_R1_NOJACK     0
+#define DAC_FLAG_R1_NOMIC      (0x1 << 4)
+#define DAC_FLAG_R1_MIC                (0x3 << 4)
+#define DAC_FLAG_R1_NOHS       0
+#define DAC_FLAG_R1_MONOHS     1
+#define DAC_FLAG_R1_STEREOHS   2
+/* ****************** Book 0 Registers **************************************/
+
+/* ****************** Page 0 Registers **************************************/
+
+#define PAGE_SEL_REG           0
+#define RESET_REG              1
+#define DAC_ADC_CLKIN_REG      4
+#define PLL_CLKIN_REG          5
+#define PLL_CLK_RANGE_REG      5
+#define PLL_PR_POW_REG         6
+#define PLL_J_REG              7
+#define PLL_D_MSB              8
+#define PLL_D_LSB              9
+#define PLL_CKIN_DIV           10
+
+#define NDAC_DIV_POW_REG       11
+#define MDAC_DIV_POW_REG       12
+#define DOSR_MSB_REG           13
+#define DOSR_LSB_REG           14
+
+#define NADC_DIV_POW_REG       18
+#define MADC_DIV_POW_REG       19
+#define AOSR_REG               20
+#define CLKOUT_MUX             21
+#define CLKOUT_MDIV_VAL                22
+#define TIMER_REG              23
+
+#define LF_CLK_CNTL            24
+#define HF_CLK_CNTL_R1         25
+#define HF_CLK_CNTL_R2         26
+#define HF_CLK_CNTL_R3         27
+#define HF_CLK_CNTL_R4         28
+#define HF_CLK_TRIM_R1         29
+#define HF_CLK_TRIM_R2         30
+#define HF_CLK_TRIM_R3         31
+#define HF_CLK_TRIM_R4         32
+#define DAC_FLAG_R1            37
+#define DAC_FLAG_R2            38
+
+#define STICKY_FLAG1           42
+#define INT_FLAG1              43
+#define STICKY_FLAG2           44
+#define INT_FLAG2              46
+#define INT1_CNTL              48
+#define INT2_CNTL              49
+#define INT_FMT                        51
+
+#define DAC_PRB                        60
+#define ADC_PRB                        61
+#define PASI_DAC_DP_SETUP      63
+#define DAC_MVOL_CONF          64
+#define DAC_LVOL               65
+#define DAC_RVOL               66
+#define HP_DETECT              67
+#define DRC_CNTL_R1            68
+#define DRC_CNTL_R2            69
+#define DRC_CNTL_R3            70
+#define BEEP_CNTL_R1           71
+#define BEEP_CNTL_R2           72
+
+#define ADC_CHANNEL_POW                81
+#define ADC_FINE_GAIN          82
+#define LADC_VOL               83
+#define RADC_VOL               84
+#define ADC_PHASE              85
+
+#define LAGC_CNTL              86
+#define LAGC_CNTL_R2           87
+#define LAGC_CNTL_R3           88
+#define LAGC_CNTL_R4           89
+#define LAGC_CNTL_R5           90
+#define LAGC_CNTL_R6           91
+#define LAGC_CNTL_R7           92
+#define LAGC_CNTL_R8           93
+
+#define RAGC_CNTL              94
+#define RAGC_CNTL_R2           95
+#define RAGC_CNTL_R3           96
+#define RAGC_CNTL_R4           97
+#define RAGC_CNTL_R5           98
+#define RAGC_CNTL_R6           99
+#define RAGC_CNTL_R7           100
+#define RAGC_CNTL_R8           101
+#define MINIDSP_ACCESS_CTRL    121
+/* ****************** Page 1 Registers **************************************/
+#define PAGE_1                 128
+
+#define POWER_CONF             (PAGE_1 + 1)
+#define LDAC_PTM               (PAGE_1 + 3)
+#define RDAC_PTM               (PAGE_1 + 4)
+#define CM_REG                 (PAGE_1 + 8)
+#define HP_CTL                 (PAGE_1 + 9)
+#define HP_DEPOP               (PAGE_1 + 11)
+#define RECV_DEPOP             (PAGE_1 + 12)
+#define MA_CNTL                        (PAGE_1 + 17)
+#define LADC_PGA_MAL_VOL       (PAGE_1 + 18)
+#define RADC_PGA_MAR_VOL       (PAGE_1 + 19)
+
+
+#define LINE_AMP_CNTL_R1       (PAGE_1 + 22)
+#define LINE_AMP_CNTL_R2       (PAGE_1 + 23)
+
+#define HP_AMP_CNTL_R1         (PAGE_1 + 27)
+#define HP_AMP_CNTL_R2         (PAGE_1 + 28)
+#define HP_AMP_CNTL_R3         (PAGE_1 + 29)
+
+#define HPL_VOL                        (PAGE_1 + 31)
+#define HPR_VOL                        (PAGE_1 + 32)
+#define INT1_SEL_L             (PAGE_1 + 34)
+#define RAMP_CNTL_R1           (PAGE_1 + 36)
+#define RAMP_CNTL_R2           (PAGE_1 + 37)
+#define INT1_SEL_RM            (PAGE_1 + 39)
+#define REC_AMP_CNTL_R5                (PAGE_1 + 40)
+#define RAMPR_VOL              (PAGE_1 + 41)
+#define RAMP_TIME_CNTL         (PAGE_1 + 42)
+#define SPK_AMP_CNTL_R1                (PAGE_1 + 45)
+#define SPK_AMP_CNTL_R2                (PAGE_1 + 46)
+#define SPK_AMP_CNTL_R3                (PAGE_1 + 47)
+#define SPK_AMP_CNTL_R4                (PAGE_1 + 48)
+#define MIC_BIAS_CNTL          (PAGE_1 + 51)
+
+#define LMIC_PGA_PIN           (PAGE_1 + 52)
+#define LMIC_PGA_PM_IN4                (PAGE_1 + 53)
+#define LMIC_PGA_MIN           (PAGE_1 + 54)
+#define RMIC_PGA_PIN           (PAGE_1 + 55)
+#define RMIC_PGA_PM_IN4                (PAGE_1 + 56)
+#define RMIC_PGA_MIN           (PAGE_1 + 57)
+/* MIC PGA Gain Registers */
+#define MICL_PGA               (PAGE_1 + 59)
+#define MICR_PGA               (PAGE_1 + 60)
+#define HEADSET_TUNING1_REG    (PAGE_1 + 119)
+#define HEADSET_TUNING2_REG    (PAGE_1 + 120)
+#define MIC_PWR_DLY            (PAGE_1 + 121)
+#define REF_PWR_DLY            (PAGE_1 + 122)
+
+/* ****************** Page 4 Registers **************************************/
+#define PAGE_4                 512
+#define ASI1_BUS_FMT           (PAGE_4 + 1)
+#define ASI1_LCH_OFFSET                (PAGE_4 + 2)
+#define ASI1_RCH_OFFSET                (PAGE_4 + 3)
+#define ASI1_CHNL_SETUP                (PAGE_4 + 4)
+#define ASI1_MULTI_CH_SETUP_R1 (PAGE_4 + 5)
+#define ASI1_MULTI_CH_SETUP_R2 (PAGE_4 + 6)
+#define ASI1_ADC_INPUT_CNTL    (PAGE_4 + 7)
+#define ASI1_DAC_OUT_CNTL      (PAGE_4 + 8)
+#define ASI1_ADC_OUT_TRISTATE  (PAGE_4 + 9)
+#define ASI1_BWCLK_CNTL_REG    (PAGE_4 + 10)
+#define ASI1_BCLK_N_CNTL       (PAGE_4 + 11)
+#define ASI1_BCLK_N            (PAGE_4 + 12)
+#define ASI1_WCLK_N            (PAGE_4 + 13)
+#define ASI1_BWCLK_OUT_CNTL    (PAGE_4 + 14)
+#define ASI1_DATA_OUT           (PAGE_4 + 15)
+#define ASI2_BUS_FMT           (PAGE_4 + 17)
+#define ASI2_LCH_OFFSET                (PAGE_4 + 18)
+#define ASI2_RCH_OFFSET                (PAGE_4 + 19)
+#define ASI2_ADC_INPUT_CNTL    (PAGE_4 + 23)
+#define ASI2_DAC_OUT_CNTL       (PAGE_4 + 24)
+#define ASI2_BWCLK_CNTL_REG    (PAGE_4 + 26)
+#define ASI2_BCLK_N_CNTL       (PAGE_4 + 27)
+#define ASI2_BCLK_N            (PAGE_4 + 28)
+#define ASI2_WCLK_N            (PAGE_4 + 29)
+#define ASI2_BWCLK_OUT_CNTL    (PAGE_4 + 30)
+#define ASI2_DATA_OUT          (PAGE_4 + 31)
+#define ASI3_BUS_FMT            (PAGE_4 + 33)
+#define ASI3_LCH_OFFSET                (PAGE_4 + 34)
+#define ASI3_RCH_OFFSET                (PAGE_4 + 35)
+#define ASI3_ADC_INPUT_CNTL    (PAGE_4 + 39)
+#define ASI3_DAC_OUT_CNTL      (PAGE_4 + 40)
+#define ASI3_BWCLK_CNTL_REG    (PAGE_4 + 42)
+#define ASI3_BCLK_N             (PAGE_4 + 44)
+#define ASI3_WCLK_N             (PAGE_4 + 45)
+#define ASI3_BWCLK_OUT_CNTL    (PAGE_4 + 46)
+#define ASI3_DATA_OUT          (PAGE_4 + 47)
+#define WCLK1_PIN_CNTL_REG     (PAGE_4 + 65)
+#define DOUT1_PIN_CNTL_REG     (PAGE_4 + 67)
+#define DIN1_PIN_CNTL_REG      (PAGE_4 + 68)
+#define WCLK2_PIN_CNTL_REG     (PAGE_4 + 69)
+#define BCLK2_PIN_CNTL_REG     (PAGE_4 + 70)
+#define DOUT2_PIN_CNTL_REG     (PAGE_4 + 71)
+#define DIN2_PIN_CNTL_REG      (PAGE_4 + 72)
+#define WCLK3_PIN_CNTL_REG     (PAGE_4 + 73)
+#define BCLK3_PIN_CNTL_REG     (PAGE_4 + 74)
+#define DOUT3_PIN_CNTL_REG     (PAGE_4 + 75)
+#define DIN3_PIN_CNTL_REG      (PAGE_4 + 76)
+#define MCLK2_PIN_CNTL_REG     (PAGE_4 + 82)
+#define GPIO1_IO_CNTL          (PAGE_4 + 86)
+#define GPIO2_IO_CNTL          (PAGE_4 + 87)
+#define GPI1_EN                        (PAGE_4 + 91)
+#define GPO2_EN                        (PAGE_4 + 92)
+#define GPO1_PIN_CNTL          (PAGE_4 + 96)
+#define MINIDSP_PORT_CNTL_REG  (PAGE_4 + 118)
+
+/****************************************************************************
+* Mixer control  related #defines
+***************************************************************************
+*/
+#define WCLK1_ENUM            0
+#define DOUT1_ENUM            1
+#define DIN1_ENUM             2
+#define WCLK2_ENUM            3
+#define BCLK2_ENUM            4
+#define DOUT2_ENUM            5
+#define DIN2_ENUM             6
+#define WCLK3_ENUM            7
+#define BCLK3_ENUM            8
+#define DOUT3_ENUM            9
+#define DIN3_ENUM             10
+#define CLKIN_ENUM            11
+/*
+*****************************************************************************
+* Enumeration Definitions
+*****************************************************************************
+*/
+/* The below enumeration lists down all the possible inputs to the
+* the PLL of the AIC3262. The Private structure will hold a member
+* of this Enumeration Type.
+*/
+enum AIC3262_PLL_OPTION {
+       PLL_CLKIN_MCLK1 = 0,    /* 0000: (Device Pin) */
+       PLL_CLKIN_BLKC1,        /* 0001: (Device Pin) */
+       PLL_CLKIN_GPIO1,        /* 0010: (Device Pin)*/
+       PLL_CLKIN_DIN1,         /* 0011: (Device Pin)*/
+       PLL_CLKIN_BCLK2,        /* 0100: (Device Pin)*/
+       PLL_CLKIN_GPI1,         /* 0101: (Device Pin)*/
+       PLL_CLKIN_HF_REF_CLK,   /* 0110: (Device Pin)*/
+       PLL_CLKIN_GPIO2,        /* 0111: (Device Pin)*/
+       PLL_CLKIN_GPI2,         /* 1000: (Device Pin)*/
+       PLL_CLKIN_MCLK2         /* 1001: (Device Pin)*/
+};
+
+/* ASI Specific Bit Clock Divider Input Options.
+* Please refer to Page 4 Reg 11, Reg 27 and Reg 43
+*/
+enum ASI_BDIV_CLKIN_OPTION {
+       BDIV_CLKIN_DAC_CLK = 0,         /* 00 DAC_CLK     */
+       BDIV_CLKIN_DAC_MOD_CLK,         /* 01 DAC_MOD_CLK */
+       BDIV_CLKIN_ADC_CLK,             /* 02 ADC_CLK     */
+       BDIV_CLKIN_ADC_MOD_CLK          /* 03 ADC_MOD_CLK */
+};
+
+/* ASI Specific Bit Clock Output Mux Options.
+* Please refer to Page 4 Reg 14, Reg 30 and Reg 46
+* Please note that we are not handling the Reserved
+* cases here.
+*/
+enum ASI_BCLK_OPTION {
+       ASI1_BCLK_DIVIDER_OUTPUT = 0,   /* 00 ASI1 Bit Clock Divider Output */
+       ASI1_BCLK_INPUT,                /* 01 ASI1 Bit Clock Input */
+       ASI2_BCLK_DIVIDER_OUTPUT,       /* 02 ASI2 Bit Clock Divider Output  */
+       ASI2_BCLK_INPUT,                /* 03 ASI2 Bit Clock Input */
+       ASI3_BCLK_DIVIDER_OUTPUT,       /* 04 ASI3 Bit Clock Divider Output  */
+       ASI3_BBCLK_INPUT                /* 05 ASi3 Bit Clock Input */
+};
+
+/* Above bits are to be configured after Shifting 4 bits */
+#define AIC3262_ASI_BCLK_MUX_SHIFT     4
+#define AIC3262_ASI_BCLK_MUX_MASK      (BIT6 | BIT5 | BIT4)
+#define AIC3262_ASI_WCLK_MUX_MASK      (BIT2 | BIT1 | BIT0)
+
+/* ASI Specific Word Clock Output Mux Options */
+enum ASI_WCLK_OPTION {
+       GENERATED_DAC_FS = 0,           /* 00 WCLK = DAC_FS */
+       GENERATED_ADC_FS = 1,           /* 01 WCLK = ADC_FS */
+       ASI1_WCLK_DIV_OUTPUT = 2,       /* 02 WCLK = ASI1 WCLK_DIV_OUT */
+       ASI1_WCLK_INPUT      = 3,       /* 03 WCLK = ASI1 WCLK Input   */
+       ASI2_WCLK_DIV_OUTPUT = 4,       /* 04 WCLK = ASI2 WCLK_DIV_OUT */
+       ASI2_WCLK_INPUT      = 5,       /* 05 WCLK = ASI2 WCLK Input   */
+       ASI3_WCLK_DIV_OUTPUT = 6,       /* 06 WCLK = ASI3 WCLK_DIV_OUT */
+       ASI3_WCLK_INPUT      = 7        /* 07 WCLK = ASI3 WCLK Input   */
+};
+
+/* ASI DAC Output Control Options */
+enum ASI_DAC_OUTPUT_OPTION {
+       DAC_PATH_OFF = 0,       /* 00 DAC Datapath Off */
+       DAC_PATH_LEFT,          /* 01 DAC Datapath left Data */
+       DAC_PATH_RIGHT,         /* 02 DAC Datapath Right Data */
+};
+
+/* Shift the above options by so many bits */
+#define AIC3262_ASI_LDAC_PATH_SHIFT    6
+#define AIC3262_ASI_LDAC_PATH_MASK     (BIT5 | BIT4)
+#define AIC3262_ASI_RDAC_PATH_SHIFT    4
+#define AIC3262_ASI_RDAC_PATH_MASK     (BIT7 | BIT6)
+
+/* ASI specific ADC Input Control Options */
+enum ASI_ADC_INPUT_OPTION {
+       ADC_PATH_OFF = 0,       /* 00 ASI Digital Output Disabled */
+       ADC_PATH_MINIDSP_1,     /* 01 ASI Digital O/P from miniDSP_A(L1,R1) */
+       ADC_PATH_ASI1,          /* 02 ASI Digital Output from ASI1 */
+       ADC_PATH_ASI2,          /* 03 ASI Digital Output from ASI2 */
+       ADC_PATH_ASI3,          /* 04 ASI Digital Output from ASI3 */
+       ADC_PATH_MINIDSP_2,     /* 05 ASI Digital O/P from miniDSP_A(L2,R2) */
+       ADC_PATH_MINIDSP_3      /* 05 ASI Digital O/P from miniDSP_A(L3,R3) */
+};
+
+/* ASI Specific DOUT Pin Options */
+enum ASI_DOUT_OPTION {
+       ASI_OUTPUT = 0,         /* 00 Default ASI Output */
+       ASI1_INPUT,             /* 01 ASI1 Data Input    */
+       ASI2_INPUT,             /* 02 ASI2 Data Input    */
+       ASI3_INPUT              /* 03 ASI3 Data Input    */
+};
+
+#define AIC3262_ASI_DOUT_MASK  (BIT1 | BIT0)
+
+/*
+ *****************************************************************************
+ * Structures Definitions
+ *****************************************************************************
+ */
+#define AIC3262_MULTI_ASI_ACTIVE(x) (((x)->asiCtxt[0].asi_active) || \
+                       ((x)->asiCtxt[1].asi_active) || \
+                       ((x)->asiCtxt[2].asi_active))
+
+/*
+*----------------------------------------------------------------------------
+* @struct  aic3262_setup_data |
+*          i2c specific data setup for AIC3262.
+* @field   unsigned short |i2c_address |
+*          Unsigned short for i2c address.
+*----------------------------------------------------------------------------
+*/
+       struct aic3262_setup_data {
+       unsigned short i2c_address;
+};
+
+/*
+*----------------------------------------------------------------------------
+* @struct aic3262_asi_data
+*      ASI specific data stored for each ASI Interface
+*
+*
+*---------------------------------------------------------------------------
+*/
+struct aic3262_asi_data {
+       u8 asi_active;                                  /* ASI Active Flag */
+       u8 master;                                      /* Frame Master */
+       u32 sampling_rate;                              /* Sampling Rate */
+       enum ASI_BDIV_CLKIN_OPTION bclk_div_option;     /* BCLK DIV Mux Option*/
+       enum ASI_BCLK_OPTION    bclk_output;            /* BCLK Output Option*/
+       enum ASI_WCLK_OPTION    wclk_output;            /* WCLK Output Option*/
+       u8                      bclk_div;               /* BCLK Divider */
+       u8                      wclk_div;               /* WCLK Divider */
+       enum ASI_DAC_OUTPUT_OPTION left_dac_output;     /* LDAC Path */
+       enum ASI_DAC_OUTPUT_OPTION right_dac_output;    /* RDAC Path */
+       enum ASI_ADC_INPUT_OPTION  adc_input;           /* ADC Input Control */
+       enum ASI_DOUT_OPTION    dout_option;            /* DOUT Option */
+       u8                      playback_mode;          /* Playback Selected */
+       u8                      capture_mode;           /* Record Selected */
+       u8                      port_muted;             /* ASI Muted */
+       u8                      pcm_format;             /* PCM Format */
+       u8                      word_len;               /* Word Length */
+       u8                      offset1;                /* Left Ch offset */
+       u8                      offset2;                /* Right Ch Offset */
+};
+
+/*
+*----------------------------------------------------------------------------
+* @struct  aic3262_priv |
+*          AIC3262 priviate data structure to set the system clock, mode and
+*          page number.
+* @field   u32 | sysclk |
+*          system clock
+* @field   s32 | master |
+*          master/slave mode setting for AIC3262
+* @field   u8 | book_no |
+*          book number.
+* @field   u8 | page_no |
+*          page number. Here, page 0 and page 1 are used.
+*----------------------------------------------------------------------------
+*/
+struct aic3262_priv {
+       enum snd_soc_control_type control_type;
+       struct aic326x_pdata *pdata;
+       u32 sysclk;
+       s32 master;
+       u8 book_no;
+       u8 page_no;
+       u8 process_flow;
+       u8 mute_codec;
+       u8 stream_status;
+       u32 active_count;
+       int current_dac_config[MAX_ASI_COUNT];
+       int current_adc_config[MAX_ASI_COUNT];
+       struct aic3262_asi_data asiCtxt[MAX_ASI_COUNT];
+       enum AIC3262_PLL_OPTION aic3262_pllclkin_option;
+       u8 dac_clkin_option;
+       u8 adc_clkin_option;
+       int irq;
+       struct snd_soc_jack *headset_jack;
+};
+
+/*
+ *----------------------------------------------------------------------------
+ * @struct  aic3262_configs |
+ *          AIC3262 initialization data which has register offset and register
+ *          value.
+ * @field   u8 | book_no |
+ *          AIC3262 Book Number Offsets required for initialization..
+ * @field   u16 | reg_offset |
+ *          AIC3262 Register offsets required for initialization..
+ * @field   u8 | reg_val |
+ *          value to set the AIC3262 register to initialize the AIC3262.
+ *----------------------------------------------------------------------------
+ */
+struct aic3262_configs {
+       u8 book_no;
+       u16 reg_offset;
+       u8  reg_val;
+};
+
+/*
+ *----------------------------------------------------------------------------
+ * @struct  aic3262_rate_divs |
+ *          Setting up the values to get different freqencies
+ * @field   u32 | mclk |
+ *          Master clock
+ * @field   u32 | rate |
+ *          sample rate
+ * @field   u8 | p_val |
+ *          value of p in PLL
+ * @field   u32 | pll_j |
+ *          value for pll_j
+ * @field   u32 | pll_d |
+ *          value for pll_d
+ * @field   u32 | dosr |
+ *          value to store dosr
+ * @field   u32 | ndac |
+ *          value for ndac
+ * @field   u32 | mdac |
+ *          value for mdac
+ * @field   u32 | aosr |
+ *          value for aosr
+ * @field   u32 | nadc |
+ *          value for nadc
+ * @field   u32 | madc |
+ *          value for madc
+ * @field   u32 | blck_N |
+ *          value for block N
+ * @field   u32 | aic3262_configs |
+ *          configurations for aic3262 register value
+ *----------------------------------------------------------------------------
+ */
+struct aic3262_rate_divs {
+       u32 mclk;
+       u32 rate;
+       u8 p_val;
+       u8 pll_j;
+       u16 pll_d;
+       u16 dosr;
+       u8 ndac;
+       u8 mdac;
+       u8 aosr;
+       u8 nadc;
+       u8 madc;
+       u8 blck_N;
+       struct aic3262_configs codec_specific_regs[NO_FEATURE_REGS];
+};
+
+/*
+*****************************************************************************
+* EXTERN DECLARATIONS
+*****************************************************************************
+*/
+/*
+ *----------------------------------------------------------------------------
+ * @func  aic326x_headset_detect
+ *      This function help to setup the needed registers to
+ *      enable the headset detection
+ *
+ */
+extern int aic326x_headset_detect(struct snd_soc_codec *codec,
+       struct snd_soc_jack *jack, int jack_type);
+
+
+extern u8 aic3262_read(struct snd_soc_codec *codec, u16 reg);
+extern u16 aic3262_read_2byte(struct snd_soc_codec *codec, u16 reg);
+extern int aic3262_reset_cache(struct snd_soc_codec *codec);
+extern int aic3262_change_page(struct snd_soc_codec *codec, u8 new_page);
+extern int aic3262_write(struct snd_soc_codec *codec, u16 reg, u8 value);
+extern void aic3262_write_reg_cache(struct snd_soc_codec *codec,
+                                   u16 reg, u8 value);
+extern int aic3262_change_book(struct snd_soc_codec *codec, u8 new_book);
+extern int reg_def_conf(struct snd_soc_codec *codec);
+extern int i2c_verify_book0(struct snd_soc_codec *codec);
+
+#ifdef CONFIG_MINI_DSP
+extern int aic3262_minidsp_program(struct snd_soc_codec *codec);
+extern int aic3262_add_minidsp_controls(struct snd_soc_codec *codec);
+#endif
+
+
+#ifdef MULTIBYTE_CONFIG_SUPPORT
+extern int aic3262_add_multiconfig_controls(struct snd_soc_codec *codec);
+#endif
+
+#endif                         /* _TLV320AIC3262_H */
+
diff --git a/sound/soc/codecs/tlv320aic326x_mini-dsp.c b/sound/soc/codecs/tlv320aic326x_mini-dsp.c
new file mode 100755 (executable)
index 0000000..4d9c4de
--- /dev/null
@@ -0,0 +1,1587 @@
+/*
+ * linux/sound/soc/codecs/tlv320aic326x_mini-dsp.c
+ *
+ * Copyright (C) 2011 Mistral Solutions Pvt Ltd.
+ *
+ * This package 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.
+ *
+ * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * The TLV320AIC3262 is a flexible, low-power, low-voltage stereo audio
+ * codec with digital microphone inputs and programmable outputs.
+ *
+ * History:
+ *
+ * Rev 0.1   Added the miniDSP Support     Mistral         01-03-2011
+ *
+ * Rev 0.2   Updated the code-base for miniDSP switching and
+ *     mux control update.    Mistral         21-03-2011
+ *
+ * Rev 0.3   Updated the code-base to support Multi-Configuration feature
+ *           of PPS GDE
+ */
+
+/*
+ *****************************************************************************
+ * INCLUDES
+ *****************************************************************************
+ */
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/fs.h>
+#include <linux/types.h>
+#include <linux/kdev_t.h>
+#include <linux/cdev.h>
+#include <linux/device.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/platform_device.h>
+#include <sound/soc.h>
+#include <sound/core.h>
+#include <sound/soc-dapm.h>
+#include <sound/control.h>
+#include <linux/time.h>                /* For timing computations */
+#include "tlv320aic326x.h"
+#include "tlv320aic326x_mini-dsp.h"
+
+#include "first_rate_pps_driver.h"
+#include "second_rate_pps_driver.h"
+
+#ifdef CONFIG_MINI_DSP
+
+#ifdef REG_DUMP_MINIDSP
+static void aic3262_dump_page(struct i2c_client *i2c, u8 page);
+#endif
+
+/*
+ *****************************************************************************
+ * LOCAL STATIC DECLARATIONS
+ *****************************************************************************
+ */
+static int m_control_info(struct snd_kcontrol *kcontrol,
+                             struct snd_ctl_elem_info *uinfo);
+static int m_control_get(struct snd_kcontrol *kcontrol,
+                            struct snd_ctl_elem_value *ucontrol);
+static int m_control_put(struct snd_kcontrol *kcontrol,
+                            struct snd_ctl_elem_value *ucontrol);
+
+/*
+ *****************************************************************************
+ * MINIDSP RELATED GLOBALS
+ *****************************************************************************
+ */
+/* The below variable is used to maintain the I2C Transactions
+ * to be carried out during miniDSP switching.
+ */
+minidsp_parser_data dsp_parse_data[MINIDSP_PARSER_ARRAY_SIZE*2];
+
+struct i2c_msg i2c_transaction[MINIDSP_PARSER_ARRAY_SIZE * 2];
+/* Total count of I2C Messages are stored in the i2c_count */
+int i2c_count;
+
+/* The below array is used to store the burst array for I2C Multibyte
+ * Operations
+ */
+minidsp_i2c_page i2c_page_array[MINIDSP_PARSER_ARRAY_SIZE];
+int i2c_page_count;
+
+/* kcontrol structure used to register with ALSA Core layer */
+static struct snd_kcontrol_new snd_mux_controls[MAX_MUX_CONTROLS];
+
+/* mode variables */
+static int amode;
+static int dmode;
+
+/* k-control macros used for miniDSP related Kcontrols */
+#define SOC_SINGLE_VALUE_M(xmax, xinvert) \
+       ((unsigned long)&(struct soc_mixer_control) \
+       {.max = xmax, \
+       .invert = xinvert})
+#define SOC_SINGLE_M(xname, max, invert) \
+{\
+       .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
+       .info = m_control_info, .get = m_control_get,\
+       .put = m_control_put, \
+       .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, \
+       .private_value = SOC_SINGLE_VALUE_M(max, invert) }
+#define SOC_SINGLE_AIC3262_M(xname) \
+{\
+       .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
+       .info = m_control_info, .get = m_control_get,\
+       .put = m_control_put, \
+       .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, \
+}
+
+/*
+ * aic3262_minidsp_controls
+ *
+ * Contains the list of the Kcontrol macros required for modifying the
+ * miniDSP behavior at run-time.
+ */
+static const struct snd_kcontrol_new aic3262_minidsp_controls[] = {
+       SOC_SINGLE_AIC3262_M("Minidsp mode") ,
+       SOC_SINGLE_AIC3262_M("ADC Adaptive mode Enable") ,
+       SOC_SINGLE_AIC3262_M("DAC Adaptive mode Enable") ,
+       SOC_SINGLE_AIC3262_M("Dump Regs Book0") ,
+       SOC_SINGLE_AIC3262_M("Verify minidsp program") ,
+};
+
+#ifdef REG_DUMP_MINIDSP
+/*
+ *----------------------------------------------------------------------------
+ * Function : aic3262_dump_page
+ * Purpose  : Read and display one codec register page, for debugging purpose
+ *----------------------------------------------------------------------------
+ */
+static void aic3262_dump_page(struct i2c_client *i2c, u8 page)
+{
+       int i;
+       u8 data;
+       u8 test_page_array[256];
+
+       aic3262_change_page(codec, page);
+
+       data = 0x0;
+
+       i2c_master_send(i2c, data, 1);
+       i2c_master_recv(i2c, test_page_array, 128);
+
+       DBG("\n------- MINI_DSP PAGE %d DUMP --------\n", page);
+       for (i = 0; i < 128; i++)
+               DBG(KERN_INFO " [ %d ] = 0x%x\n", i, test_page_array[i]);
+
+}
+#endif
+
+/*
+ *----------------------------------------------------------------------------
+ * Function : update_kcontrols
+ * Purpose  : Given the miniDSP process flow, this function reads the
+ *            corresponding Page Numbers and then performs I2C Read for those
+ *            Pages.
+ *----------------------------------------------------------------------------
+ */
+void update_kcontrols(struct snd_soc_codec *codec, int process_flow)
+{
+       int i, val1, array_size;
+       char **knames;
+       control *cntl;
+
+       if (process_flow == 1) {
+               knames = Second_Rate_MUX_control_names;
+               cntl = Second_Rate_MUX_controls;
+               array_size = ARRAY_SIZE(Second_Rate_MUX_controls);
+       } else {
+               knames = main44_MUX_control_names;
+               cntl = main44_MUX_controls;
+               array_size = ARRAY_SIZE(main44_MUX_controls);
+       }
+
+       DBG(KERN_INFO "%s: ARRAY_SIZE = %d\tmode=%d\n", __func__,
+                       array_size, process_flow);
+       for (i = 0; i < array_size; i++) {
+               aic3262_change_book(codec, cntl[i].control_book);
+               aic3262_change_page(codec, cntl[i].control_page);
+               val1 = i2c_smbus_read_byte_data(codec->control_data,
+                               cntl[i].control_base);
+               snd_mux_controls[i].private_value = 0;
+       }
+}
+
+/*
+ *----------------------------------------------------------------------------
+ * Function : byte_i2c_array_transfer
+ * Purpose  : Function used only for debugging purpose. This function will
+ *            be used while switching miniDSP Modes register by register.
+ *            This needs to be used only during development.
+ *-----------------------------------------------------------------------------
+ */
+int byte_i2c_array_transfer(struct snd_soc_codec *codec,
+                               reg_value *program_ptr,
+                               int size)
+{
+       int j;
+       u8 buf[3];
+
+       for (j = 0; j < size; j++) {
+               /* Check if current Reg offset is zero */
+               if (program_ptr[j].reg_off == 0) {
+                       /* Check for the Book Change Request */
+                       if ((j < (size - 1)) &&
+                               (program_ptr[j+1].reg_off == 127)) {
+                               aic3262_change_book(codec,
+                                       program_ptr[j+1].reg_val);
+                       /* Increment for loop counter across Book Change */
+                               j++;
+                               continue;
+               }
+               /* Check for the Page Change Request in Current book */
+               aic3262_change_page(codec, program_ptr[j].reg_val);
+               continue;
+               }
+
+               buf[AIC3262_REG_OFFSET_INDEX] = program_ptr[j].reg_off % 128;
+               buf[AIC3262_REG_DATA_INDEX] =
+                               program_ptr[j].reg_val & AIC3262_8BITS_MASK;
+
+               if (codec->hw_write(codec->control_data, buf, 2) != 2) {
+                       printk(KERN_ERR "Error in i2c write\n");
+                       return -EIO;
+               }
+       }
+       return 0;
+}
+
+/*
+ *----------------------------------------------------------------------------
+ * Function : byte_i2c_array_read
+ * Purpose  : This function is used to perform Byte I2C Read. This is used
+ *            only for debugging purposes to read back the Codec Page
+ *            Registers after miniDSP Configuration.
+ *----------------------------------------------------------------------------
+ */
+int byte_i2c_array_read(struct snd_soc_codec *codec,
+                       reg_value *program_ptr, int size)
+{
+       int j;
+       u8 val1;
+       u8 cur_page = 0;
+       u8 cur_book = 0;
+       for (j = 0; j < size; j++) {
+               /* Check if current Reg offset is zero */
+               if (program_ptr[j].reg_off == 0) {
+                       /* Check for the Book Change Request */
+                       if ((j < (size - 1)) &&
+                               (program_ptr[j+1].reg_off == 127)) {
+                               aic3262_change_book(codec,
+                                       program_ptr[j+1].reg_val);
+                               cur_book = program_ptr[j+1].reg_val;
+                       /* Increment for loop counter across Book Change */
+                               j++;
+                               continue;
+                       }
+                       /* Check for the Page Change Request in Current book */
+                       aic3262_change_page(codec, program_ptr[j].reg_val);
+                       cur_page = program_ptr[j].reg_val;
+                       continue;
+               }
+
+               val1 = i2c_smbus_read_byte_data(codec->control_data,
+                               program_ptr[j].reg_off);
+               if (val1 < 0)
+                       printk(KERN_ERR "Error in smbus read\n");
+
+               DBG(KERN_INFO "[%d][%d][%d]= %x\n",
+                       cur_book, cur_page, program_ptr[j].reg_off, val1);
+       }
+       return 0;
+}
+
+/*
+ *----------------------------------------------------------------------------
+ * Function : minidsp_get_burst
+ * Purpose  : Format one I2C burst for transfer from mini dsp program array.
+ *            This function will parse the program array and get next burst
+ *            data for doing an I2C bulk transfer.
+ *----------------------------------------------------------------------------
+ */
+static void
+minidsp_get_burst(reg_value *program_ptr,
+                               int program_size,
+                               minidsp_parser_data *parse_data)
+{
+       int index = parse_data->current_loc;
+       int burst_write_count = 0;
+
+       /*DBG("GET_BURST: start\n");*/
+       /* check if first location is page register, and populate page addr */
+       if (program_ptr[index].reg_off == 0) {
+               if ((index < (program_size - 1)) &&
+                       (program_ptr[index+1].reg_off == 127)) {
+                       parse_data->book_change = 1;
+                       parse_data->book_no = program_ptr[index+1].reg_val;
+                       index += 2;
+                       goto finish_out;
+
+               }
+               parse_data->page_num = program_ptr[index].reg_val;
+               parse_data->burst_array[burst_write_count++] =
+                       program_ptr[index].reg_off;
+               parse_data->burst_array[burst_write_count++] =
+                       program_ptr[index].reg_val;
+               index++;
+               goto finish_out;
+       }
+
+       parse_data->burst_array[burst_write_count++] =
+                       program_ptr[index].reg_off;
+       parse_data->burst_array[burst_write_count++] =
+                       program_ptr[index].reg_val;
+       index++;
+
+       for (; index < program_size; index++) {
+               if (program_ptr[index].reg_off !=
+                               (program_ptr[index - 1].reg_off + 1))
+                       break;
+               else
+                       parse_data->burst_array[burst_write_count++] =
+                               program_ptr[index].reg_val;
+
+       }
+finish_out:
+       parse_data->burst_size = burst_write_count;
+       if (index == program_size)
+               /* parsing completed */
+               parse_data->current_loc = MINIDSP_PARSING_END;
+       else
+               parse_data->current_loc = index;
+       /*DBG("GET_BURST: end\n");*/
+}
+/*
+ *----------------------------------------------------------------------------
+ * Function : minidsp_i2c_multibyte_transfer
+ * Purpose  : Function used to perform multi-byte I2C Writes. Used to configure
+ *            the miniDSP Pages.
+ *----------------------------------------------------------------------------
+ */
+int
+minidsp_i2c_multibyte_transfer(struct snd_soc_codec *codec,
+                                       reg_value *program_ptr,
+                                       int program_size)
+{
+       struct i2c_client *client = codec->control_data;
+
+       minidsp_parser_data parse_data;
+       int count = 0;
+
+#ifdef DEBUG_MINIDSP_LOADING
+       int i = 0, j = 0;
+#endif
+       /* point the current location to start of program array */
+       parse_data.current_loc = 0;
+       parse_data.page_num = 0;
+       parse_data.book_change = 0;
+       parse_data.book_no = 0;
+
+       DBG(KERN_INFO "size is : %d", program_size);
+       do {
+               do {
+                       /* Get first burst data */
+                       minidsp_get_burst(program_ptr, program_size,
+                                       &parse_data);
+                       if (parse_data.book_change == 1)
+                               break;
+                       dsp_parse_data[count] = parse_data;
+
+                       i2c_transaction[count].addr = client->addr;
+                       i2c_transaction[count].flags =
+                               client->flags & I2C_M_TEN;
+                       i2c_transaction[count].len =
+                               dsp_parse_data[count].burst_size;
+                       i2c_transaction[count].buf =
+                               dsp_parse_data[count].burst_array;
+
+#ifdef DEBUG_MINIDSP_LOADING
+                       DBG(KERN_INFO
+                       "i: %d\taddr: %d\tflags: %d\tlen: %d\tbuf:",
+                       i, client->addr, client->flags & I2C_M_TEN,
+                       dsp_parse_data[count].burst_size);
+
+                       for (j = 0; j <= dsp_parse_data[count].burst_size; j++)
+                               DBG(KERN_INFO "%x ",
+                                       dsp_parse_data[i].burst_array[j]);
+
+                       DBG(KERN_INFO "\n\n");
+                       i++;
+#endif
+
+                       count++;
+                       /* Proceed to the next burst reg_addr_incruence */
+               } while (parse_data.current_loc != MINIDSP_PARSING_END);
+
+               if (count > 0) {
+                       if (i2c_transfer(client->adapter,
+                               i2c_transaction, count) != count) {
+                               printk(KERN_ERR "Write burst i2c data error!\n");
+                       }
+               }
+               if (parse_data.book_change == 1) {
+                       aic3262_change_book(codec, parse_data.book_no);
+                       parse_data.book_change = 0;
+               }
+       } while (parse_data.current_loc != MINIDSP_PARSING_END);
+
+       return 0;
+}
+
+/*
+ *----------------------------------------------------------------------------
+ * Function : set_minidsp_mode
+ * Purpose  : Switch to the first minidsp mode.
+ *----------------------------------------------------------------------------
+ */
+int
+set_minidsp_mode(struct snd_soc_codec *codec, int new_mode)
+{
+       struct aic3262_priv *aic326x = snd_soc_codec_get_drvdata(codec);
+
+       DBG("%s: switch  mode start\n", __func__);
+       aic3262_reset_cache(codec);
+       reg_def_conf(codec);
+
+       if (new_mode == 0) {
+
+               /*      General Programming     */
+               DBG(KERN_INFO "$Writing reg_section_init_program\n");
+               if (ARRAY_SIZE(main44_REG_Section_init_program) > 0) {
+#ifndef MULTIBYTE_I2C
+                       byte_i2c_array_transfer(codec,
+                               main44_REG_Section_init_program,
+                               ARRAY_SIZE(main44_REG_Section_init_program));
+#else
+                       minidsp_i2c_multibyte_transfer(codec,
+                               main44_REG_Section_init_program,
+                               ARRAY_SIZE(main44_REG_Section_init_program));
+#endif
+
+               } else {
+                       printk(KERN_ERR
+                       "_CODEC_REGS: Insufficient data for programming\n");
+               }
+
+               /*      minidsp A programming   */
+               DBG(KERN_INFO "#Writing minidsp_A_reg_values\n");
+
+               if ((main44_miniDSP_A_reg_values_COEFF_SIZE +
+                       main44_miniDSP_A_reg_values_INST_SIZE) > 0) {
+#ifndef MULTIBYTE_I2C
+                       byte_i2c_array_transfer(codec,
+                               main44_miniDSP_A_reg_values,
+                               (main44_miniDSP_A_reg_values_COEFF_SIZE +
+                               main44_miniDSP_A_reg_values_INST_SIZE));
+#else
+                       minidsp_i2c_multibyte_transfer(codec,
+                               main44_miniDSP_A_reg_values,
+                               (main44_miniDSP_A_reg_values_COEFF_SIZE +
+                               main44_miniDSP_A_reg_values_INST_SIZE));
+#endif
+               } else {
+                       printk(KERN_ERR
+               "MINI_DSP_A_second: Insufficient data for programming\n");
+               }
+               /*      minidsp D programming   */
+               DBG(KERN_INFO "#Writing minidsp_D_reg_values\n");
+               if ((main44_miniDSP_D_reg_values_COEFF_SIZE +
+                       main44_miniDSP_D_reg_values_INST_SIZE) > 0) {
+
+#ifdef MULTIBYTE_CONFIG_SUPPORT
+                       /*Multibyte for DAC */
+#endif
+
+#ifndef MULTIBYTE_I2C
+                       byte_i2c_array_transfer(codec,
+                               main44_miniDSP_D_reg_values,
+                               (main44_miniDSP_D_reg_values_COEFF_SIZE +
+                               main44_miniDSP_D_reg_values_INST_SIZE));
+#else
+                       minidsp_i2c_multibyte_transfer(codec,
+                               main44_miniDSP_D_reg_values,
+                               (main44_miniDSP_D_reg_values_COEFF_SIZE +
+                               main44_miniDSP_D_reg_values_INST_SIZE));
+#endif
+
+               } else {
+                       printk(KERN_ERR
+               "MINI_DSP_D_second: Insufficient data for programming\n");
+               }
+               DBG(KERN_INFO "#Writing reg_section_post_program\n");
+               if (ARRAY_SIZE(main44_REG_Section_post_program) > 0) {
+                       #ifndef MULTIBYTE_I2C
+                       byte_i2c_array_transfer(codec,
+                               main44_REG_Section_post_program,
+                               ARRAY_SIZE(REG_Section_post_program));
+                       #else
+                       minidsp_i2c_multibyte_transfer(codec,
+                               main44_REG_Section_post_program,
+                               ARRAY_SIZE(main44_REG_Section_post_program));
+                       #endif
+               } else {
+                       printk(KERN_ERR
+               "second_CODEC_REGS: Insufficient data for programming\n");
+               }
+       }
+
+       if (new_mode == 1) {
+               /*      General Programming     */
+               DBG(KERN_INFO "#Writing reg_section_init_program\n");
+               if (ARRAY_SIZE(Second_Rate_REG_Section_init_program) > 0) {
+#ifndef MULTIBYTE_I2C
+                       byte_i2c_array_transfer(codec,
+                       Second_Rate_REG_Section_init_program,
+                       ARRAY_SIZE(Second_Rate_REG_Section_init_program));
+#else
+                       minidsp_i2c_multibyte_transfer(codec,
+                       Second_Rate_REG_Section_init_program,
+                       ARRAY_SIZE(Second_Rate_REG_Section_init_program));
+#endif
+
+               } else {
+                       printk(KERN_ERR
+                        "_CODEC_REGS: Insufficient data for programming\n");
+               }
+               /*      minidsp A programming   */
+               DBG(KERN_INFO "#Writing minidsp_A_reg_values\n");
+
+               if ((Second_Rate_miniDSP_A_reg_values_COEFF_SIZE +
+                       Second_Rate_miniDSP_A_reg_values_INST_SIZE) > 0) {
+#ifndef MULTIBYTE_I2C
+                       byte_i2c_array_transfer(codec,
+                               Second_Rate_miniDSP_A_reg_values,
+                               (Second_Rate_miniDSP_A_reg_values_COEFF_SIZE +
+                               Second_Rate_miniDSP_A_reg_values_INST_SIZE));
+#else
+                       minidsp_i2c_multibyte_transfer(codec,
+                               Second_Rate_miniDSP_A_reg_values,
+                               (Second_Rate_miniDSP_A_reg_values_COEFF_SIZE +
+                               Second_Rate_miniDSP_A_reg_values_INST_SIZE));
+#endif
+               } else {
+                       printk(KERN_ERR
+               "MINI_DSP_A_second: Insufficient data for programming\n");
+               }
+
+               /*      minidsp D programming   */
+               DBG(KERN_INFO "#Writing minidsp_D_reg_values\n");
+
+               if ((Second_Rate_miniDSP_D_reg_values_COEFF_SIZE +
+                       Second_Rate_miniDSP_D_reg_values_INST_SIZE) > 0) {
+#ifndef MULTIBYTE_I2C
+                       byte_i2c_array_transfer(codec,
+                               Second_Rate_miniDSP_D_reg_values,
+                               (Second_Rate_miniDSP_D_reg_values_COEFF_SIZE +
+                               Second_Rate_miniDSP_D_reg_values_INST_SIZE));
+#else
+                       minidsp_i2c_multibyte_transfer(codec,
+                               Second_Rate_miniDSP_D_reg_values,
+                               (Second_Rate_miniDSP_D_reg_values_COEFF_SIZE +
+                               Second_Rate_miniDSP_D_reg_values_INST_SIZE));
+#endif
+               } else {
+                       printk(KERN_ERR
+               "MINI_DSP_D_second: Insufficient data for programming\n");
+               }
+               DBG(KERN_INFO "Writing reg_section_post_program\n");
+               if (ARRAY_SIZE(Second_Rate_REG_Section_post_program) > 0) {
+#ifndef MULTIBYTE_I2C
+                       byte_i2c_array_transfer(codec,
+                               Second_Rate_REG_Section_post_program,
+                               ARRAY_SIZE(REG_Section_post_program));
+#else
+                       minidsp_i2c_multibyte_transfer(codec,
+                       Second_Rate_REG_Section_post_program,
+                       ARRAY_SIZE(Second_Rate_REG_Section_post_program));
+#endif
+               } else {
+                       printk(KERN_ERR
+                "second_CODEC_REGS: Insufficient data for programming\n");
+               }
+       }
+
+#ifdef MULTIBYTE_CONFIG_SUPPORT
+       /*Multibyte for DAC */
+       aic326x->process_flow = new_mode;
+       config_multibyte_for_mode(codec, new_mode);
+#endif
+       DBG("%s: switch mode finished\n", __func__);
+       return 0;
+}
+
+/*
+ * i2c_verify
+ *
+ * Function used to validate the contents written into the miniDSP
+ * pages after miniDSP Configuration.
+*/
+int i2c_verify(struct snd_soc_codec *codec)
+{
+
+       DBG(KERN_INFO "#%s: Invoked.. Resetting to page 0\n", __func__);
+
+       aic3262_change_book(codec, 0);
+       DBG(KERN_INFO "#Reading reg_section_init_program\n");
+
+       byte_i2c_array_read(codec, main44_REG_Section_init_program,
+               ARRAY_SIZE(main44_REG_Section_init_program));
+
+       DBG(KERN_INFO "#Reading minidsp_A_reg_values\n");
+       byte_i2c_array_read(codec, main44_miniDSP_A_reg_values,
+               (main44_miniDSP_A_reg_values_COEFF_SIZE +
+                main44_miniDSP_A_reg_values_INST_SIZE));
+
+       DBG(KERN_INFO "#Reading minidsp_D_reg_values\n");
+       byte_i2c_array_read(codec, main44_miniDSP_D_reg_values,
+               (main44_miniDSP_D_reg_values_COEFF_SIZE +
+                main44_miniDSP_D_reg_values_INST_SIZE));
+
+       DBG(KERN_INFO "#Reading reg_section_post_program\n");
+       byte_i2c_array_read(codec, main44_REG_Section_post_program,
+               ARRAY_SIZE(main44_REG_Section_post_program));
+
+       DBG(KERN_INFO "i2c_verify completed\n");
+       return 0;
+}
+
+/*
+ *----------------------------------------------------------------------------
+ * Function : set_minidsp_mode1
+ * Purpose  : for laoding the default minidsp mode for the first time .
+ *----------------------------------------------------------------------------
+ */
+int
+set_minidsp_mode1(struct snd_soc_codec *codec, int new_mode)
+{
+       DBG("#%s: switch  mode start\n", __func__);
+       aic3262_reset_cache(codec);
+
+       if (new_mode == 0) {
+               /*      General Programming     */
+               DBG(KERN_INFO "#Writing reg_section_init_program\n");
+               if (ARRAY_SIZE(main44_REG_Section_init_program) > 0) {
+#ifndef MULTIBYTE_I2C
+                       byte_i2c_array_transfer(codec,
+                               main44_REG_Section_init_program,
+                               ARRAY_SIZE(main44_REG_Section_init_program));
+#else
+                       minidsp_i2c_multibyte_transfer(codec,
+                               main44_REG_Section_init_program,
+                               ARRAY_SIZE(main44_REG_Section_init_program));
+#endif
+
+               } else {
+                       printk(KERN_ERR
+                       "_CODEC_REGS: Insufficient data for programming\n");
+               }
+               /*      minidsp A programming   */
+               DBG(KERN_INFO "#Writing minidsp_A_reg_values\n");
+               if ((main44_miniDSP_A_reg_values_COEFF_SIZE +
+                    main44_miniDSP_A_reg_values_INST_SIZE) > 0) {
+#ifndef MULTIBYTE_I2C
+                       byte_i2c_array_transfer(codec,
+                               main44_miniDSP_A_reg_values,
+                               (main44_miniDSP_A_reg_values_COEFF_SIZE +
+                               main44_miniDSP_A_reg_values_INST_SIZE));
+#else
+                       minidsp_i2c_multibyte_transfer(codec,
+                               main44_miniDSP_A_reg_values,
+                               (main44_miniDSP_A_reg_values_COEFF_SIZE +
+                               main44_miniDSP_A_reg_values_INST_SIZE));
+#endif
+               } else {
+                       printk(KERN_ERR
+               "MINI_DSP_A_second: Insufficient data for programming\n");
+               }
+
+               /*      minidsp D programming   */
+               DBG(KERN_INFO "#Writing minidsp_D_reg_values\n");
+               if ((main44_miniDSP_D_reg_values_COEFF_SIZE +
+                    main44_miniDSP_D_reg_values_INST_SIZE) > 0) {
+#ifndef MULTIBYTE_I2C
+                       byte_i2c_array_transfer(codec,
+                               main44_miniDSP_D_reg_values,
+                               (main44_miniDSP_D_reg_values_COEFF_SIZE +
+                               main44_miniDSP_D_reg_values_INST_SIZE));
+#else
+                       minidsp_i2c_multibyte_transfer(codec,
+                               main44_miniDSP_D_reg_values,
+                               (main44_miniDSP_D_reg_values_COEFF_SIZE +
+                               main44_miniDSP_D_reg_values_INST_SIZE));
+#endif
+               } else {
+                       printk(KERN_ERR
+               "MINI_DSP_D_second: Insufficient data for programming\n");
+               }
+
+               DBG(KERN_INFO "#Writing reg_section_post_program\n");
+               if (ARRAY_SIZE(main44_REG_Section_post_program) > 0) {
+#ifndef MULTIBYTE_I2C
+                       byte_i2c_array_transfer(codec,
+                       main44_REG_Section_post_program,
+                       ARRAY_SIZE(REG_Section_post_program));
+#else
+                       minidsp_i2c_multibyte_transfer(codec,
+                       main44_REG_Section_post_program,
+                       ARRAY_SIZE(main44_REG_Section_post_program));
+#endif
+               } else {
+                       printk(KERN_ERR
+               "second_CODEC_REGS: Insufficient data for programming\n");
+               }
+       }
+
+       if (new_mode == 1) {
+               /*      General Programming     */
+               DBG(KERN_INFO "#Writing reg_section_init_program\n");
+               if (ARRAY_SIZE(Second_Rate_REG_Section_init_program) > 0) {
+#ifndef MULTIBYTE_I2C
+                       byte_i2c_array_transfer(codec,
+                       second_Rate_REG_Section_init_program,
+                       ARRAY_SIZE(Second_Rate_REG_Section_init_program));
+#else
+                       minidsp_i2c_multibyte_transfer(codec,
+                       Second_Rate_REG_Section_init_program,
+                       ARRAY_SIZE(Second_Rate_REG_Section_init_program));
+#endif
+               } else {
+                       printk(KERN_ERR
+                       "_CODEC_REGS: Insufficient data for programming\n");
+               }
+               /*      minidsp A programming   */
+               DBG(KERN_INFO "#Writing minidsp_A_reg_values\n");
+               if ((Second_Rate_miniDSP_A_reg_values_COEFF_SIZE +
+                       Second_Rate_miniDSP_A_reg_values_INST_SIZE) > 0) {
+#ifndef MULTIBYTE_I2C
+                       byte_i2c_array_transfer(codec,
+                       Second_Rate_miniDSP_A_reg_values,
+                       (Second_Rate_miniDSP_A_reg_values_COEFF_SIZE +
+                       Second_Rate_miniDSP_A_reg_values_INST_SIZE));
+#else
+                       minidsp_i2c_multibyte_transfer(codec,
+                       Second_Rate_miniDSP_A_reg_values,
+                       (Second_Rate_miniDSP_A_reg_values_COEFF_SIZE +
+                       Second_Rate_miniDSP_A_reg_values_INST_SIZE));
+#endif
+               } else {
+                       printk(KERN_ERR\
+               "MINI_DSP_A_second: Insufficient data for programming\n");
+               }
+               /*      minidsp D programming   */
+               DBG(KERN_INFO "#Writing minidsp_D_reg_values\n");
+               if ((Second_Rate_miniDSP_D_reg_values_COEFF_SIZE +
+                       Second_Rate_miniDSP_D_reg_values_INST_SIZE) > 0) {
+#ifndef MULTIBYTE_I2C
+                       byte_i2c_array_transfer(codec,
+                       Second_Rate_miniDSP_D_reg_values,
+                       (Second_Rate_miniDSP_D_reg_values_COEFF_SIZE +
+                       Second_Rate_miniDSP_D_reg_values_INST_SIZE));
+#else
+                       minidsp_i2c_multibyte_transfer(codec,
+                       Second_Rate_miniDSP_D_reg_values,
+                       (Second_Rate_miniDSP_D_reg_values_COEFF_SIZE +
+                       Second_Rate_miniDSP_D_reg_values_INST_SIZE));
+#endif
+               } else
+                       printk(KERN_ERR "MINI_DSP_D_second: Insufficient data for programming\n");
+
+               DBG(KERN_INFO "#Writing reg_section_post_program\n");
+               if (ARRAY_SIZE(Second_Rate_REG_Section_post_program) > 0) {
+#ifndef MULTIBYTE_I2C
+                       byte_i2c_array_transfer(codec,
+                       Second_Rate_REG_Section_post_program,
+                       ARRAY_SIZE(REG_Section_post_program));
+#else
+                       minidsp_i2c_multibyte_transfer(codec,
+                       Second_Rate_REG_Section_post_program,
+                       ARRAY_SIZE(Second_Rate_REG_Section_post_program));
+#endif
+               } else
+                       printk(KERN_ERR\
+               "second_CODEC_REGS: Insufficient data for programming\n");
+
+       }
+
+       DBG("#%s: switch mode completed\n", __func__);
+       return 0;
+}
+
+/*
+ *----------------------------------------------------------------------------
+ * Function : aic3262_minidsp_program
+ * Purpose  : Program mini dsp for AIC3262 codec chip. This routine is
+ *             called from the aic3262 codec driver, if mini dsp programming
+ *             is enabled.
+ *----------------------------------------------------------------------------
+ */
+int aic3262_minidsp_program(struct snd_soc_codec *codec)
+{
+       DBG(KERN_INFO "#AIC3262: programming mini dsp\n");
+
+#if defined(PROGRAM_MINI_DSP_first)
+       #ifdef DEBUG
+       DBG("#Verifying book 0\n");
+       i2c_verify_book0(codec);
+#endif
+       aic3262_change_book(codec, 0);
+       set_minidsp_mode1(codec, 0);
+       aic3262_change_book(codec, 0);
+#ifdef DEBUG
+       DBG("#verifying book 0\n");
+       i2c_verify_book0(codec);
+#endif
+#endif
+#if defined(PROGRAM_MINI_DSP_second)
+#ifdef DEBUG
+       DBG("#Verifying book 0\n");
+       i2c_verify_book0(codec);
+#endif
+       set_minidsp_mode1(codec, 1);
+#ifdef DEBUG
+       DBG("#verifying book 0\n");
+       i2c_verify_book0(codec);
+#endif
+#endif
+       return 0;
+}
+/*
+ *----------------------------------------------------------------------------
+ * Function : m_control_info
+ * Purpose  : This function is to initialize data for new control required to
+ *            program the AIC3262 registers.
+ *
+ *----------------------------------------------------------------------------
+ */
+static int m_control_info(struct snd_kcontrol *kcontrol,
+                             struct snd_ctl_elem_info *uinfo)
+{
+       uinfo->count = 1;
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+       uinfo->value.integer.min = 0;
+       uinfo->value.integer.max = 1;
+       return 0;
+}
+
+/*
+ *----------------------------------------------------------------------------
+ * Function : m_control_get
+ * Purpose  : This function is to read data of new control for
+ *            program the AIC3262 registers.
+ *
+ *----------------------------------------------------------------------------
+ */
+static int m_control_get(struct snd_kcontrol *kcontrol,
+                            struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct aic3262_priv *aic3262 = snd_soc_codec_get_drvdata(codec);
+       u32 val;
+       u8 val1;
+
+       if (!strcmp(kcontrol->id.name, "Minidsp mode")) {
+               val = aic3262->process_flow;
+               ucontrol->value.integer.value[0] = val;
+               DBG(KERN_INFO "control get : mode=%d\n", aic3262->process_flow);
+       }
+       if (!strcmp(kcontrol->id.name, "DAC Adaptive mode Enable")) {
+               aic3262_change_book(codec, 80);
+               val1 = i2c_smbus_read_byte_data(codec->control_data, 1);
+               ucontrol->value.integer.value[0] = ((val1>>1)&0x01);
+               DBG(KERN_INFO "control get : mode=%d\n", aic3262->process_flow);
+       }
+       if (!strcmp(kcontrol->id.name, "ADC Adaptive mode Enable")) {
+               aic3262_change_book(codec, 40);
+               val1 = i2c_smbus_read_byte_data(codec->control_data, 1);
+               ucontrol->value.integer.value[0] = ((val1>>1)&0x01);
+               DBG(KERN_INFO "control get : mode=%d\n", dmode);
+       }
+
+       return 0;
+}
+
+/*
+ *----------------------------------------------------------------------------
+ * Function : m_new_control_put
+ * Purpose  : new_control_put is called to pass data from user/application to
+ *            the driver.
+ *
+ *----------------------------------------------------------------------------
+ */
+static int m_control_put(struct snd_kcontrol *kcontrol,
+                            struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct aic3262_priv *aic3262 = snd_soc_codec_get_drvdata(codec);
+
+       u32 val;
+       u8 val1;
+       int mode = aic3262->process_flow;
+
+       DBG("n_control_put\n");
+       val = ucontrol->value.integer.value[0];
+       if (!strcmp(kcontrol->id.name, "Minidsp mode")) {
+               DBG(KERN_INFO "\nMini dsp put\n mode = %d, val=%d\n",
+                       aic3262->process_flow, val);
+               if (val != mode) {
+                       if (aic3262->mute_codec == 1) {
+                               i2c_verify_book0(codec);
+                               aic3262_change_book(codec, 0);
+                               set_minidsp_mode(codec, val);
+
+                               aic3262_change_book(codec, 0);
+                               i2c_verify_book0(codec);
+       /*                      update_kcontrols(codec, val);*/
+                       } else {
+                               printk(KERN_ERR
+                       " Cant Switch Processflows, Playback in progress");
+                       }
+               }
+       }
+
+       if (!strcmp(kcontrol->id.name, "DAC Adaptive mode Enable")) {
+               DBG(KERN_INFO "\nMini dsp put\n mode = %d, val=%d\n",
+                       aic3262->process_flow, val);
+               if (val != amode) {
+                       aic3262_change_book(codec, 80);
+                       val1 = i2c_smbus_read_byte_data(codec->control_data, 1);
+                       aic3262_write(codec, 1, (val1&0xfb)|(val<<1));
+               }
+               amode = val;
+       }
+
+       if (!strcmp(kcontrol->id.name, "ADC Adaptive mode Enable")) {
+               DBG(KERN_INFO "\nMini dsp put\n mode = %d, val=%d\n",
+                       aic3262->process_flow, val);
+               if (val != dmode) {
+                       aic3262_change_book(codec, 40);
+                       val1 = i2c_smbus_read_byte_data(codec->control_data, 1);
+                       aic3262_write(codec, 1, (val1&0xfb)|(val<<1));
+               }
+               dmode = val;
+       }
+
+       if (!strcmp(kcontrol->id.name, "Dump Regs Book0"))
+               i2c_verify_book0(codec);
+
+
+       if (!strcmp(kcontrol->id.name, "Verify minidsp program")) {
+               if (mode == 0) {
+                       DBG("Current mod=%d\nVerifying minidsp_D_regs", mode);
+                       byte_i2c_array_read(codec,  main44_miniDSP_D_reg_values,
+                               (main44_miniDSP_D_reg_values_COEFF_SIZE +
+                               main44_miniDSP_D_reg_values_INST_SIZE));
+               } else {
+                       byte_i2c_array_read(codec,
+                               Second_Rate_miniDSP_D_reg_values,
+                               (Second_Rate_miniDSP_D_reg_values_COEFF_SIZE +
+                               Second_Rate_miniDSP_D_reg_values_INST_SIZE));
+               }
+       }
+       DBG("\nmode = %d\n", mode);
+       return mode;
+}
+
+/************************** MUX CONTROL section *****************************/
+/*
+ *----------------------------------------------------------------------------
+ * Function : __new_control_info_minidsp_mux
+ * Purpose  : info routine for mini dsp mux control amixer kcontrols
+ *----------------------------------------------------------------------------
+ */
+static int __new_control_info_minidsp_mux(struct snd_kcontrol *kcontrol,
+                                         struct snd_ctl_elem_info *uinfo)
+{
+       int index;
+       int ret_val = -1;
+
+       for (index = 0; index < ARRAY_SIZE(main44_MUX_controls); index++) {
+               if (strstr(kcontrol->id.name, main44_MUX_control_names[index]))
+                       break;
+       }
+
+       if (index < ARRAY_SIZE(main44_MUX_controls)) {
+               uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+               uinfo->count = 1;
+               uinfo->value.integer.min = MIN_MUX_CTRL;
+               uinfo->value.integer.max = MAX_MUX_CTRL;
+               ret_val = 0;
+       }
+       return ret_val;
+}
+
+/*
+ *----------------------------------------------------------------------------
+ * Function : __new_control_get_minidsp_mux
+ *
+ * Purpose  : get routine for  mux control amixer kcontrols,
+ *   read current register values to user.
+ *   Used for for mini dsp 'MUX control' amixer controls.
+ *----------------------------------------------------------------------------
+ */
+static int __new_control_get_minidsp_mux(struct snd_kcontrol *kcontrol,
+                                        struct snd_ctl_elem_value *ucontrol)
+{
+       ucontrol->value.integer.value[0] = kcontrol->private_value;
+       return 0;
+}
+
+/*
+ *----------------------------------------------------------------------------
+ * Function : __new_control_put_minidsp_mux
+ *
+ * Purpose  : put routine for amixer kcontrols, write user values to registers
+ *            values. Used for for mini dsp 'MUX control' amixer controls.
+ *----------------------------------------------------------------------------
+ */
+static int __new_control_put_minidsp_mux(struct snd_kcontrol *kcontrol,
+                                       struct snd_ctl_elem_value *ucontrol)
+{
+       u8 data[MUX_CTRL_REG_SIZE + 1];
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       int index = 1;
+       int user_value = ucontrol->value.integer.value[0];
+       struct i2c_client *i2c;
+       u8 value[2], swap_reg_pre, swap_reg_post;
+       u8 page;
+       int ret_val = -1, array_size;
+       control *array;
+       char **array_names;
+       char *control_name, *control_name1;
+       struct aic3262_priv *aic326x = snd_soc_codec_get_drvdata(codec);
+       i2c = codec->control_data;
+
+       if (aic326x->process_flow == 0) {
+               DBG("#the current process flow is %d", aic326x->process_flow);
+               array = main44_MUX_controls;
+               array_size = ARRAY_SIZE(main44_MUX_controls);
+               array_names = main44_MUX_control_names;
+               control_name = "Stereo_Mux_TwoToOne_1";
+               control_name1 = "Mono_Mux_1_1";
+
+               /* Configure only for process flow  1 controls */
+               if (strcmp(kcontrol->id.name, control_name) &&
+                   strcmp(kcontrol->id.name, control_name1))
+                       return 0;
+       } else {
+               array = Second_Rate_MUX_controls;
+               array_size = ARRAY_SIZE(Second_Rate_MUX_controls);
+               array_names = Second_Rate_MUX_control_names;
+               control_name = "Stereo_Mux_TwoToOne_1_Second";
+               control_name1 = "Mono_Mux_1_1_Second";
+
+               /* Configure only for process flow 2 controls */
+               if (strcmp(kcontrol->id.name, control_name) &&
+                   strcmp(kcontrol->id.name, control_name1))
+                       return 0;
+       }
+
+       page = array[index].control_page;
+
+       DBG("#user value = 0x%x\n", user_value);
+       for (index = 0; index < array_size; index++) {
+               if (strstr(kcontrol->id.name, array_names[index]))
+                       break;
+       }
+       if (index < array_size) {
+               DBG(KERN_INFO "#Index %d Changing to Page %d\n", index,
+                       array[index].control_page);
+
+               aic3262_change_book(codec,
+                                   array[index].control_book);
+               aic3262_change_page(codec,
+                                   array[index].control_page);
+
+               if (!strcmp(array_names[index], control_name)) {
+                       if (user_value > 0) {
+                               data[1] = 0x00;
+                               data[2] = 0x00;
+                               data[3] = 0x00;
+                       } else {
+                               data[1] = 0xFF;
+                               data[2] = 0xFf;
+                               data[3] = 0xFF;
+                       }
+               } else {
+                       if (user_value > 0) {
+                               data[1] =
+                                       (u8) ((user_value >> 16) &
+                                             AIC3262_8BITS_MASK);
+                               data[2] =
+                                       (u8) ((user_value >> 8) &
+                                             AIC3262_8BITS_MASK);
+                               data[3] =
+                                       (u8)((user_value) & AIC3262_8BITS_MASK);
+                       }
+               }
+               /* start register address */
+               data[0] = array[index].control_base;
+
+               DBG(KERN_INFO
+               "#Writing %d %d %d \r\n", data[0], data[1], data[2]);
+
+               ret_val = i2c_master_send(i2c, data, MUX_CTRL_REG_SIZE + 1);
+
+               if (ret_val != MUX_CTRL_REG_SIZE + 1)
+                       printk(KERN_ERR "i2c_master_send transfer failed\n");
+               else {
+                       /* store the current level */
+                       kcontrol->private_value = user_value;
+                       ret_val = 0;
+                       /* Enable adaptive filtering for ADC/DAC */
+               }
+
+               /* Perform a BUFFER SWAP Command. Check if we are currently not
+                * in Page 8, if so, swap to Page 8 first
+                */
+
+               value[0] = 1;
+
+               if (i2c_master_send(i2c, value, 1) != 1)
+                       printk(KERN_ERR "Can not write register address\n");
+
+               /* Read the Value of the Page 8 Register 1 which controls the
+                  Adaptive Switching Mode */
+               if (i2c_master_recv(i2c, value, 1) != 1)
+                       printk(KERN_ERR "Can not read codec registers\n");
+
+               swap_reg_pre = value[0];
+               /* Write the Register bit updates */
+               value[1] = value[0] | 1;
+               value[0] = 1;
+
+               if (i2c_master_send(i2c, value, 2) != 2)
+                       printk(KERN_ERR "Can not write register address\n");
+
+               value[0] = 1;
+               /* verify buffer swap */
+               if (i2c_master_send(i2c, value, 1) != 1)
+                       printk(KERN_ERR "Can not write register address\n");
+
+               /* Read the Value of the Page 8 Register 1 which controls the
+                  Adaptive Switching Mode */
+               if (i2c_master_recv(i2c, &swap_reg_post, 1) != 1)
+                       printk(KERN_ERR "Can not read codec registers\n");
+
+               if ((swap_reg_pre == 4 && swap_reg_post == 6)
+                   || (swap_reg_pre == 6 && swap_reg_post == 4))
+                       DBG("Buffer swap success\n");
+               else
+                       printk(KERN_ERR
+                       "Buffer swap...FAILED\nswap_reg_pre=%x, \
+                       swap_reg_post=%x\n", swap_reg_pre, swap_reg_post);
+
+       }
+       /* update the new buffer value in the old, just swapped out buffer */
+       aic3262_change_book(codec, array[index].control_book);
+       aic3262_change_page(codec, array[index].control_page);
+       ret_val = i2c_master_send(i2c, data, MUX_CTRL_REG_SIZE + 1);
+       ret_val = 0;
+
+       aic3262_change_book(codec, 0);
+       return ret_val;
+}
+
+/*
+ *----------------------------------------------------------------------------
+ * Function : minidsp_mux_ctrl_mixer_controls
+ *
+ * Purpose  : Add amixer kcontrols for mini dsp mux controls,
+ *----------------------------------------------------------------------------
+ */
+static int minidsp_mux_ctrl_mixer_controls(struct snd_soc_codec *codec,
+                                               int size, control *cntl,
+                                               char **name)
+{
+       int i, err;
+       int val1;
+
+       /* DBG("%d mixer controls for mini dsp MUX\n", no_mux_controls);*/
+
+       if (size) {
+               for (i = 0; i < size; i++) {
+
+                       snd_mux_controls[i].name = name[i];
+                       snd_mux_controls[i].iface = SNDRV_CTL_ELEM_IFACE_MIXER;
+                       snd_mux_controls[i].access =
+                               SNDRV_CTL_ELEM_ACCESS_READWRITE;
+                       snd_mux_controls[i].info =
+                               __new_control_info_minidsp_mux;
+                       snd_mux_controls[i].get = __new_control_get_minidsp_mux;
+                       snd_mux_controls[i].put = __new_control_put_minidsp_mux;
+                       /*
+                        *  TBD: read volume reg and update the index number
+                        */
+                       aic3262_change_book(codec, cntl[i].control_book);
+                       aic3262_change_page(codec, cntl[i].control_page);
+                       val1 = i2c_smbus_read_byte_data(codec->control_data,
+                                       cntl[i].control_base);
+                       DBG(KERN_INFO "Control data %x\n", val1);
+                       /*
+                       if( val1 >= 0 )
+                               snd_mux_controls[i].private_value = val1;
+                       else
+                               snd_mux_controls[i].private_value = 0;
+                       */
+                       DBG(KERN_INFO
+                               "the value of amixer control mux=%d", val1);
+                       if (val1 >= 0 && val1 != 255)
+                               snd_mux_controls[i].private_value = val1;
+                       else
+                               snd_mux_controls[i].private_value = 0;
+
+                       snd_mux_controls[i].count = 0;
+
+                       err = snd_ctl_add(codec->card->snd_card,
+                               snd_ctl_new1(&snd_mux_controls[i],
+                                              codec));
+                       if (err < 0)
+                               printk(KERN_ERR
+                                       "%s:Invalid control %s\n", __FILE__,
+                                       snd_mux_controls[i].name);
+               }
+       }
+       return 0;
+}
+
+/*-------------------------  Volume Controls  -----------------------*/
+static int volume_lite_table[] = {
+
+       0x00000D, 0x00000E, 0x00000E, 0x00000F,
+       0x000010, 0x000011, 0x000012, 0x000013,
+       0x000015, 0x000016, 0x000017, 0x000018,
+       0x00001A, 0x00001C, 0x00001D, 0x00001F,
+       0x000021, 0x000023, 0x000025, 0x000027,
+       0x000029, 0x00002C, 0x00002F, 0x000031,
+       0x000034, 0x000037, 0x00003B, 0x00003E,
+       0x000042, 0x000046, 0x00004A, 0x00004F,
+       0x000053, 0x000058, 0x00005D, 0x000063,
+       0x000069, 0x00006F, 0x000076, 0x00007D,
+       0x000084, 0x00008C, 0x000094, 0x00009D,
+       0x0000A6, 0x0000B0, 0x0000BB, 0x0000C6,
+       0x0000D2, 0x0000DE, 0x0000EB, 0x0000F9,
+       0x000108, 0x000118, 0x000128, 0x00013A,
+       0x00014D, 0x000160, 0x000175, 0x00018B,
+       0x0001A3, 0x0001BC, 0x0001D6, 0x0001F2,
+       0x000210, 0x00022F, 0x000250, 0x000273,
+       0x000298, 0x0002C0, 0x0002E9, 0x000316,
+       0x000344, 0x000376, 0x0003AA, 0x0003E2,
+       0x00041D, 0x00045B, 0x00049E, 0x0004E4,
+       0x00052E, 0x00057C, 0x0005D0, 0x000628,
+       0x000685, 0x0006E8, 0x000751, 0x0007C0,
+       0x000836, 0x0008B2, 0x000936, 0x0009C2,
+       0x000A56, 0x000AF3, 0x000B99, 0x000C49,
+       0x000D03, 0x000DC9, 0x000E9A, 0x000F77,
+       0x001062, 0x00115A, 0x001262, 0x001378,
+       0x0014A0, 0x0015D9, 0x001724, 0x001883,
+       0x0019F7, 0x001B81, 0x001D22, 0x001EDC,
+       0x0020B0, 0x0022A0, 0x0024AD, 0x0026DA,
+       0x002927, 0x002B97, 0x002E2D, 0x0030E9,
+       0x0033CF, 0x0036E1, 0x003A21, 0x003D93,
+       0x004139, 0x004517, 0x00492F, 0x004D85,
+       0x00521D, 0x0056FA, 0x005C22, 0x006197,
+       0x006760, 0x006D80, 0x0073FD, 0x007ADC,
+       0x008224, 0x0089DA, 0x009205, 0x009AAC,
+       0x00A3D7, 0x00B7D4, 0x00AD8C, 0x00C2B9,
+       0x00CE43, 0x00DA7B, 0x00E76E, 0x00F524,
+       0x0103AB, 0x01130E, 0x01235A, 0x01349D,
+       0x0146E7, 0x015A46, 0x016ECA, 0x018486,
+       0x019B8C, 0x01B3EE, 0x01CDC3, 0x01E920,
+       0x02061B, 0x0224CE, 0x024553, 0x0267C5,
+       0x028C42, 0x02B2E8, 0x02DBD8, 0x030736,
+       0x033525, 0x0365CD, 0x039957, 0x03CFEE,
+       0x0409C2, 0x044703, 0x0487E5, 0x04CCA0,
+       0x05156D, 0x05628A, 0x05B439, 0x060ABF,
+       0x066666, 0x06C77B, 0x072E50, 0x079B3D,
+       0x080E9F, 0x0888D7, 0x090A4D, 0x09936E,
+       0x0A24B0, 0x0ABE8D, 0x0B6188, 0x0C0E2B,
+       0x0CC509, 0x0D86BD, 0x0E53EB, 0x0F2D42,
+       0x101379, 0x110754, 0x1209A3, 0x131B40,
+       0x143D13, 0x157012, 0x16B543, 0x180DB8,
+       0x197A96, 0x1AFD13, 0x1C9676, 0x1E481C,
+       0x201373, 0x21FA02, 0x23FD66, 0x261F54,
+       0x28619A, 0x2AC625, 0x2D4EFB, 0x2FFE44,
+       0x32D646, 0x35D96B, 0x390A41, 0x3C6B7E,
+       0x400000, 0x43CAD0, 0x47CF26, 0x4C106B,
+       0x50923B, 0x55586A, 0x5A6703, 0x5FC253,
+       0x656EE3, 0x6B7186, 0x71CF54, 0x788DB4,
+       0x7FB260,
+};
+
+static struct snd_kcontrol_new snd_vol_controls[MAX_VOLUME_CONTROLS];
+/*
+ *----------------------------------------------------------------------------
+ * Function : __new_control_info_main44_minidsp_volume
+ * Purpose  : info routine for volumeLite amixer kcontrols
+ *----------------------------------------------------------------------------
+ */
+
+static int
+__new_control_info_minidsp_volume(struct snd_kcontrol *kcontrol,
+                                 struct snd_ctl_elem_info *uinfo)
+{
+       int index, index8;
+       int ret_val = -1;
+
+       for (index = 0; index < ARRAY_SIZE(main44_VOLUME_controls); index++) {
+               if (strstr
+                   (kcontrol->id.name, main44_VOLUME_control_names[index]))
+                       break;
+       }
+       for (index8 = 0; index8 < ARRAY_SIZE(Second_Rate_VOLUME_controls);
+                       index8++) {
+               if (strstr
+                   (kcontrol->id.name,
+                   Second_Rate_VOLUME_control_names[index]))
+                       break;
+       }
+       if ((index < ARRAY_SIZE(main44_VOLUME_controls))
+           || (index8 < ARRAY_SIZE(Second_Rate_VOLUME_controls))) {
+               uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+               uinfo->count = 1;
+               uinfo->value.integer.min = MIN_VOLUME;
+               uinfo->value.integer.max = MAX_VOLUME;
+               ret_val = 0;
+       }
+       return ret_val;
+}
+
+/*
+ *----------------------------------------------------------------------------
+ * Function : __new_control_get_main44_minidsp_vol
+ * Purpose  : get routine for amixer kcontrols, read current register
+ *         values. Used for for mini dsp 'VolumeLite' amixer controls.
+ *----------------------------------------------------------------------------
+ */
+static int
+__new_control_get_minidsp_volume(struct snd_kcontrol *kcontrol,
+                                struct snd_ctl_elem_value *ucontrol)
+{
+       ucontrol->value.integer.value[0] = kcontrol->private_value;
+       return 0;
+}
+
+/*
+ *----------------------------------------------------------------------------
+ * Function : __new_control_put_main44_minidsp_volume
+ * Purpose  : put routine for amixer kcontrols, write user values to registers
+ *        values. Used for for mini dsp 'VolumeLite' amixer controls.
+ *----------------------------------------------------------------------------
+ */
+static int
+__new_control_put_minidsp_volume(struct snd_kcontrol *kcontrol,
+                                struct snd_ctl_elem_value *ucontrol)
+{
+       u8 data[4];
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       int user_value = ucontrol->value.integer.value[0];
+       struct i2c_client *i2c = codec->control_data;
+       int ret_val = -1;
+       int coeff;
+       u8 value[2], swap_reg_pre, swap_reg_post;
+       struct aic3262_priv *aic3262 = snd_soc_codec_get_drvdata(codec);
+
+       control *volume_controls = NULL;
+       printk(KERN_INFO "user value = 0x%x\n", user_value);
+
+       if (aic3262->process_flow == 0)
+               volume_controls = main44_VOLUME_controls;
+       else
+               volume_controls = Second_Rate_VOLUME_controls;
+
+       aic3262_change_book(codec, volume_controls->control_book);
+       aic3262_change_page(codec, volume_controls->control_page);
+
+       coeff = volume_lite_table[user_value << 1];
+
+       data[1] = (u8) ((coeff >> 16) & AIC3262_8BITS_MASK);
+       data[2] = (u8) ((coeff >> 8) & AIC3262_8BITS_MASK);
+       data[3] = (u8) ((coeff) & AIC3262_8BITS_MASK);
+
+       /* Start register address */
+       data[0] = volume_controls->control_base;
+       ret_val = i2c_master_send(i2c, data, VOLUME_REG_SIZE + 1);
+       if (ret_val != VOLUME_REG_SIZE + 1)
+               printk(KERN_ERR "i2c_master_send transfer failed\n");
+       else {
+               /* store the current level */
+               kcontrol->private_value = user_value;
+               ret_val = 0;
+       }
+       /* Initiate buffer swap */
+       value[0] = 1;
+
+       if (i2c_master_send(i2c, value, 1) != 1)
+               printk(KERN_ERR "Can not write register address\n");
+
+       /* Read the Value of the Page 8 Register 1 which controls the
+          Adaptive Switching Mode */
+       if (i2c_master_recv(i2c, value, 1) != 1)
+               printk(KERN_ERR "Can not read codec registers\n");
+
+       swap_reg_pre = value[0];
+       /* Write the Register bit updates */
+       value[1] = value[0] | 1;
+       value[0] = 1;
+       if (i2c_master_send(i2c, value, 2) != 2)
+               printk(KERN_ERR "Can not write register address\n");
+
+       value[0] = 1;
+       /* verify buffer swap */
+       if (i2c_master_send(i2c, value, 1) != 1)
+               printk(KERN_ERR "Can not write register address\n");
+
+       /* Read the Value of the Page 8 Register 1 which controls the
+          Adaptive Switching Mode */
+       if (i2c_master_recv(i2c, &swap_reg_post, 1) != 1)
+               printk(KERN_ERR "Can not read codec registers\n");
+
+       if ((swap_reg_pre == 4 && swap_reg_post == 6)
+           || (swap_reg_pre == 6 && swap_reg_post == 4))
+               DBG("Buffer swap success\n");
+       else
+               DBG("Buffer swap...FAILED\nswap_reg_pre=%x, swap_reg_post=%x\n",
+                        swap_reg_pre, swap_reg_post);
+
+       /* update the new buffer value in the old, just swapped out buffer */
+       aic3262_change_book(codec, volume_controls->control_book);
+       aic3262_change_page(codec, volume_controls->control_page);
+       i2c_master_send(i2c, data, MUX_CTRL_REG_SIZE + 1);
+
+       aic3262_change_book(codec, 0);
+
+       return 0;
+}
+
+/*
+ *----------------------------------------------------------------------------
+ * Function : minidsp_volume_main44_mixer_controls
+ * Purpose  : Add amixer kcontrols for mini dsp volume Lite controls,
+ *----------------------------------------------------------------------------
+ */
+static int minidsp_volume_mixer_controls(struct snd_soc_codec *codec)
+{
+       int i, err, no_volume_controls;
+       static char volume_control_name[MAX_VOLUME_CONTROLS][40];
+
+       /*      ADD first process volume controls       */
+       no_volume_controls = ARRAY_SIZE(main44_VOLUME_controls);
+
+       printk(KERN_INFO " %d mixer controls for mini dsp 'volumeLite'\n",
+               no_volume_controls);
+
+       if (no_volume_controls) {
+
+               for (i = 0; i < no_volume_controls; i++) {
+                       strcpy(volume_control_name[i],
+                              main44_VOLUME_control_names[i]);
+                       strcat(volume_control_name[i], VOLUME_KCONTROL_NAME);
+
+                       printk(KERN_ERR "Volume controls: %s\n",
+                               volume_control_name[i]);
+
+                       snd_vol_controls[i].name = volume_control_name[i];
+                       snd_vol_controls[i].iface = SNDRV_CTL_ELEM_IFACE_MIXER;
+                       snd_vol_controls[i].access =
+                               SNDRV_CTL_ELEM_ACCESS_READWRITE;
+                       snd_vol_controls[i].info =
+                               __new_control_info_minidsp_volume;
+                       snd_vol_controls[i].get =
+                               __new_control_get_minidsp_volume;
+                       snd_vol_controls[i].put =
+                               __new_control_put_minidsp_volume;
+                       /*
+                        *      TBD: read volume reg and update the index number
+                        */
+                       snd_vol_controls[i].private_value = 0;
+                       snd_vol_controls[i].count = 0;
+
+                       err = snd_ctl_add(codec->card->snd_card,
+                                         snd_ctl_new1(&snd_vol_controls[i],
+                                                      codec));
+                       if (err < 0) {
+                               printk(KERN_ERR
+                                       "%s:Invalid control %s\n", __FILE__,
+                                       snd_vol_controls[i].name);
+                       }
+               }
+       }
+       /*      ADD second process volume controls      */
+       no_volume_controls = ARRAY_SIZE(Second_Rate_VOLUME_controls);
+
+       printk(KERN_ERR " %d mixer controls for mini dsp 'volumeLite'\n",
+               no_volume_controls);
+
+       if (no_volume_controls) {
+
+               for (i = 0; i < no_volume_controls; i++) {
+                       strcpy(volume_control_name[i],
+                              Second_Rate_VOLUME_control_names[i]);
+                       strcat(volume_control_name[i], VOLUME_KCONTROL_NAME);
+
+                       printk(KERN_ERR "Volume controls: %s\n",
+                               volume_control_name[i]);
+
+                       snd_vol_controls[i].name = volume_control_name[i];
+                       snd_vol_controls[i].iface = SNDRV_CTL_ELEM_IFACE_MIXER;
+                       snd_vol_controls[i].access =
+                               SNDRV_CTL_ELEM_ACCESS_READWRITE;
+                       snd_vol_controls[i].info =
+                               __new_control_info_minidsp_volume;
+                       snd_vol_controls[i].get =
+                               __new_control_get_minidsp_volume;
+                       snd_vol_controls[i].put =
+                               __new_control_put_minidsp_volume;
+                       /*
+                        *      TBD: read volume reg and update the index number
+                        */
+                       snd_vol_controls[i].private_value = 0;
+                       snd_vol_controls[i].count = 0;
+
+                       err = snd_ctl_add(codec->card->snd_card,
+                                         snd_ctl_new1(&snd_vol_controls[i],
+                                                      codec));
+                       if (err < 0) {
+                               printk(KERN_ERR
+                                       "%s:Invalid control %s\n", __FILE__,
+                                      snd_vol_controls[i].name);
+                       }
+               }
+       }
+       return 0;
+}
+
+/*
+ *--------------------------------------------------------------------------
+ * Function : aic3262_add_minidsp_controls
+ * Purpose :  Configures the AMIXER Control Interfaces that can be exercised by
+ *            the user at run-time. Utilizes the  the snd_adaptive_controls[]
+ *            array to specify two run-time controls.
+ *---------------------------------------------------------------------------
+ */
+int aic3262_add_minidsp_controls(struct snd_soc_codec *codec)
+{
+#ifdef ADD_MINI_DSP_CONTROLS
+       int i, err, no_mux_controls;
+       /* add mode k control */
+       for (i = 0; i < ARRAY_SIZE(aic3262_minidsp_controls); i++) {
+               err = snd_ctl_add(codec->card->snd_card,
+               snd_ctl_new1(&aic3262_minidsp_controls[i], codec));
+               if (err < 0) {
+                       printk(KERN_ERR "Invalid control\n");
+                       return err;
+               }
+       }
+
+       /* add mux controls */
+       no_mux_controls = ARRAY_SIZE(main44_MUX_controls);
+       minidsp_mux_ctrl_mixer_controls(codec, no_mux_controls,
+               main44_MUX_controls, main44_MUX_control_names);
+
+       no_mux_controls = ARRAY_SIZE(Second_Rate_MUX_controls);
+       minidsp_mux_ctrl_mixer_controls(codec, no_mux_controls,
+               Second_Rate_MUX_controls, Second_Rate_MUX_control_names);
+
+       /* add volume controls*/
+       minidsp_volume_mixer_controls(codec);
+#endif /* ADD_MINI_DSP_CONTROLS */
+       return 0;
+}
+
+MODULE_DESCRIPTION("ASoC TLV320AIC3262 miniDSP driver");
+MODULE_AUTHOR("Y Preetam Sashank Reddy <preetam@mistralsolutions.com>");
+MODULE_LICENSE("GPL");
+#endif /* End of CONFIG_MINI_DSP */
diff --git a/sound/soc/codecs/tlv320aic326x_minidsp_config.c b/sound/soc/codecs/tlv320aic326x_minidsp_config.c
new file mode 100755 (executable)
index 0000000..07b762a
--- /dev/null
@@ -0,0 +1,410 @@
+/*
+ * linux/sound/soc/codecs/tlv320aic326x_minidsp_config.c
+ *
+ * Copyright (C) 2011 Mistral Solutions Pvt Ltd.
+ *
+ * This package 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.
+ *
+ * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * The TLV320AIC3262 is a flexible, low-power, low-voltage stereo audio
+ * codec with digital microphone inputs and programmable outputs.
+ *
+ * History:
+ *
+ * Rev 0.1   Added the multiconfig support      Mistral         17-08-2011
+ *
+ * Rev 0.2   Migrated for aic3262 nVidia
+ *     Mistral         21-10-2011
+ */
+
+/*
+ *****************************************************************************
+ * INCLUDES
+ *****************************************************************************
+ */
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/fs.h>
+#include <linux/types.h>
+#include <linux/kdev_t.h>
+#include <linux/cdev.h>
+#include <linux/device.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/platform_device.h>
+#include <sound/soc.h>
+#include <sound/core.h>
+#include <sound/soc-dapm.h>
+#include <sound/control.h>
+#include <linux/time.h>                /* For timing computations */
+#include "tlv320aic326x.h"
+#include "tlv320aic326x_mini-dsp.h"
+
+#include "Patch_base_jazz_Rate48_pps_driver.h"
+#include "Patch_base_main_Rate48_pps_driver.h"
+#include "Patch_base_pop_Rate48_pps_driver.h"
+#include "Patch_base_rock_Rate48_pps_driver.h"
+
+#ifdef CONFIG_MINI_DSP
+
+#define MAX_CONFIG_D_ARRAYS 4
+#define MAX_CONFIG_A_ARRAYS 0
+#define MAX_CONFIG_ARRAYS   4
+#define MINIDSP_DMODE 0
+#define MINIDSP_AMODE 1
+
+/*
+ *****************************************************************************
+ * LOCAL STATIC DECLARATIONS
+ *****************************************************************************
+ */
+static int multibyte_coeff_change(struct snd_soc_codec *codec, int);
+
+static int m_control_get(struct snd_kcontrol *kcontrol,
+                       struct snd_ctl_elem_value *ucontrol);
+static int m_control_put(struct snd_kcontrol *kcontrol,
+                       struct snd_ctl_elem_value *ucontrol);
+
+/* k-control macros used for miniDSP related Kcontrols */
+#define SOC_SINGLE_VALUE_M(xmax, xinvert) \
+       ((unsigned long)&(struct soc_mixer_control) \
+       {.max = xmax, \
+       .invert = xinvert})
+#define SOC_SINGLE_M(xname, max, invert) \
+{\
+       .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
+       .info = m_control_info, .get = m_control_get,\
+       .put = m_control_put, \
+       .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, \
+       .private_value = SOC_SINGLE_VALUE_M(max, invert) }
+#define SOC_SINGLE_AIC3262_M(xname) \
+{\
+       .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
+       .info = m_control_info, .get = m_control_get,\
+       .put = m_control_put, \
+       .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, \
+}
+
+
+/* The Multi-Configurations generated through PPS GDE has been
+ * named as Rock, Pop, Jazz and Main. These were the Configurations
+ * that were used while testing this AUdio Driver. If the user
+ * creates Process-flow with different names, it is advised to
+ * modify the names present in the below array.
+ */
+static const char *multi_config_support_DAC[] = {
+       "ROCK",
+       "POP",
+       "JAZZ",
+       "MAIN",
+};
+
+/* SOC_ENUM Declaration and kControl for switching Configurations
+ * at run-time.
+ */
+static const struct soc_enum aic3262_enum =
+       SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(multi_config_support_DAC),
+                       multi_config_support_DAC);
+
+static const struct snd_kcontrol_new aic3262_minidsp_controls1[] = {
+
+       SOC_ENUM_EXT("Multiconfig support for DAC",
+               aic3262_enum, m_control_get, m_control_put),
+
+};
+
+
+/*
+ * multibyte_config
+ *
+ * This structure has been devised to maintain information about each
+ * configuration provided with the PPS GDE Processflow. For each
+ * configuration, the Driver needs to know where the starting offset
+ * of the Coefficient change, Total Size of Coefficients being affected,
+ * and the Instruction Sizes.
+ * This has to be replicated for both miniDSP_A and miniDSP_D
+ */
+struct multibyte_config {
+       reg_value *regs;
+       unsigned int d_coeff_start;
+       unsigned int d_coeff_size;
+       unsigned int d_inst_start;
+       unsigned int d_inst_size;
+       unsigned int a_coeff_start;
+       unsigned int a_coeff_size;
+       unsigned int a_inst_start;
+       unsigned int a_inst_size;
+} config_array[][2][MAX_CONFIG_ARRAYS] = {
+       /* Process flow 1 */
+       {
+               {
+                       /* DAC */
+                       {rock_D_reg_values, 0, 67, 67, 0, 0, 0, 0, 0},
+                       {pop_D_reg_values, 0, 67, 67, 0, 0, 0, 0, 0},
+                       {jazz_D_reg_values, 0, 67, 67, 0, 0, 0, 0, 0},
+                       {main_D_reg_values, 0, 67, 67, 0, 0, 0, 0, 0},
+               },
+               /* ADC */
+               {},
+       },
+
+       /* Process flow 2 */
+       {
+#if 0
+               {
+                       {main, 0, 0, 0, 0, 0, 0, 0, 0},
+                       {pop, 0, 0, 0, 0, 0, 0, 0, 0},
+                       {jazz, 0, 0, 0, 0, 0, 0, 0, 0},
+                       {rock, 0, 0, 0, 0, 0, 0, 0, 0},
+               },
+               /* ADC */
+               {},
+#endif
+       },
+};
+
+/*
+ *----------------------------------------------------------------------------
+ * Function : m_control_get
+ * Purpose  : This function is to read data of new control for
+ *            program the AIC3262 registers.
+ *
+ *----------------------------------------------------------------------------
+ */
+static int m_control_get(struct snd_kcontrol *kcontrol,
+                        struct snd_ctl_elem_value *ucontrol)
+{
+
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct aic3262_priv *aic326x = snd_soc_codec_get_drvdata(codec);
+       u32 val = 0;
+       u32 mode = aic326x->process_flow;
+
+
+       if (!strcmp(kcontrol->id.name, "Multiconfig support for DAC"))
+               val = aic326x->current_dac_config[mode];
+       else if (!strcmp(kcontrol->id.name, "Multiconfig support for ADC"))
+               val = aic326x->current_adc_config[mode];
+
+
+       ucontrol->value.integer.value[0] = val;
+       return 0;
+}
+
+/*
+ *----------------------------------------------------------------------------
+ * Function : m_new_control_put
+ * Purpose  : new_control_put is called to pass data from user/application to
+ *            the driver.
+ *
+ *----------------------------------------------------------------------------
+ */
+static int m_control_put(struct snd_kcontrol *kcontrol,
+                        struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct aic3262_priv *aic326x = snd_soc_codec_get_drvdata(codec);
+       u32 val;
+       u8 value;
+       int pf = aic326x->process_flow;
+       struct multibyte_config *array;
+
+       val = ucontrol->value.integer.value[0];
+       if (!strcmp(kcontrol->id.name, "Multiconfig support for DAC")) {
+               if (aic326x->process_flow == MINIDSP_DMODE) {
+                       if (val > MAX_CONFIG_D_ARRAYS) {
+                               dev_err(codec->dev, "Value not in range\n");
+                               return -1;
+                       }
+
+                       value = aic3262_read(codec, ADC_CHANNEL_POW);
+                       value = aic3262_read(codec, PASI_DAC_DP_SETUP);
+
+                       array = &config_array[pf][MINIDSP_DMODE][val];
+                       minidsp_i2c_multibyte_transfer(codec,
+                               array->regs,
+                               (array->d_inst_size + array->d_coeff_size));
+
+
+                       /*coefficent buffer change*/
+                       multibyte_coeff_change(codec, 0x50);
+
+                       minidsp_i2c_multibyte_transfer(codec,
+                               array->regs,
+                               (array->d_inst_size + array->d_coeff_size));
+
+
+
+                       value = aic3262_read(codec, ADC_CHANNEL_POW);
+                       value = aic3262_read(codec, PASI_DAC_DP_SETUP);
+               }
+               aic326x->current_dac_config[pf] = val;
+
+       } else {
+               if (aic326x->process_flow == MINIDSP_AMODE) {
+                       if (val > MAX_CONFIG_A_ARRAYS) {
+                               dev_err(codec->dev, "Value not in range\n");
+                               return -1;
+                       }
+                       array = &config_array[pf][MINIDSP_AMODE][val];
+                       minidsp_i2c_multibyte_transfer(codec,
+                               array->regs,
+                               (array->a_inst_size + array->a_coeff_size));
+               }
+               aic326x->current_adc_config[pf] = val;
+       }
+       return val;
+}
+
+
+/*
+ *--------------------------------------------------------------------------
+ * Function : aic3262_add_multiconfig_controls
+ * Purpose :  Configures the AMIXER Control Interfaces that can be exercised by
+ *            the user at run-time. Utilizes the  the snd_adaptive_controls[]
+ *            array to specify two run-time controls.
+ *---------------------------------------------------------------------------
+ */
+int aic3262_add_multiconfig_controls(struct snd_soc_codec *codec)
+{
+       int i, err;
+
+       DBG(KERN_INFO
+               "#%s: Invoked to add controls for Multi-Configuration\n",
+               __func__);
+
+       /* add mode k control */
+       for (i = 0; i < ARRAY_SIZE(aic3262_minidsp_controls1); i++) {
+               err = snd_ctl_add(codec->card->snd_card,
+                               snd_ctl_new1(&aic3262_minidsp_controls1[i],
+                               codec));
+               if (err < 0) {
+                       printk(KERN_ERR
+                       "Cannot add controls for mulibyte configuration\n");
+                       return err;
+               }
+       }
+       DBG(KERN_INFO "#%s: Completed control addition.\n", __func__);
+       return 0;
+}
+
+/*
+ *--------------------------------------------------------------------------
+ * Function : config_multibyte_for_mode
+ * Purpose :  Function which is invoked when user changes the configuration
+ *            at run-time. Internally configures/switches both
+ *            miniDSP_D and miniDSP_A Coefficient arrays.
+ *---------------------------------------------------------------------------
+ */
+void config_multibyte_for_mode(struct snd_soc_codec *codec, int mode)
+{
+       int val;
+       int pf = mode;
+       struct aic3262_priv *aic326x = snd_soc_codec_get_drvdata(codec);
+       struct multibyte_config *array;
+
+       DBG(KERN_INFO "#%s: Invoked for miniDSP Mode %d\n", __func__, mode);
+
+       array = config_array[pf][MINIDSP_DMODE];
+         if ((aic326x->current_dac_config[pf] >= 0) &&
+               (aic326x->current_dac_config[pf] < MAX_CONFIG_ARRAYS)) {
+                       val = aic326x->current_dac_config[pf];
+                       array = &config_array[pf][MINIDSP_DMODE][val];
+                       byte_i2c_array_transfer(codec,
+                               array->regs,
+                               (array->d_inst_size +
+                               array->d_coeff_size));
+       } else {
+               DBG(KERN_INFO "#%s: Invalid Configuration ID %d specified.\n",
+                       __func__, aic326x->current_dac_config[pf]);
+       }
+
+       array = config_array[pf][MINIDSP_AMODE];
+       if ((aic326x->current_adc_config[pf] >= 0) &&
+               (aic326x->current_adc_config[pf] < MAX_CONFIG_ARRAYS)) {
+               val = aic326x->current_adc_config[pf];
+               minidsp_i2c_multibyte_transfer(codec,
+                               array[val].regs,
+                               array[val].a_inst_size +
+                               array[val].a_coeff_size);
+       } else {
+               DBG(KERN_INFO "#%s: Invalid Configuration ID %d specified.\n",
+                       __func__, aic326x->current_dac_config[pf]);
+       }
+       return;
+}
+
+/*
+ *--------------------------------------------------------------------------
+ * Function : config_multibyte_for_mode
+ * Purpose :  Function which is invoked when user changes the configuration
+ *            at run-time. Internally configures/switches both
+ *            miniDSP_D and miniDSP_A Coefficient arrays.
+ *---------------------------------------------------------------------------
+ */
+static int multibyte_coeff_change(struct snd_soc_codec *codec, int bk)
+{
+
+       u8 value[2], swap_reg_pre, swap_reg_post;
+       struct i2c_client *i2c;
+       i2c = codec->control_data;
+
+       aic3262_change_book(codec, bk);
+
+       value[0] = 1;
+
+       if (i2c_master_send(i2c, value, 1) != 1)
+               printk(KERN_ERR "Can not write register address\n");
+       else {
+               /* Read the Value of the Page 8 Register 1 which controls the
+                  Adaptive Switching Mode */
+               if (i2c_master_recv(i2c, value, 1) != 1) {
+                       printk(KERN_ERR "Can not read codec registers\n");
+                       goto err;
+               }
+               swap_reg_pre = value[0];
+
+               /* Write the Register bit updates */
+               value[1] = value[0] | 1;
+               value[0] = 1;
+
+               if (i2c_master_send(i2c, value, 2) != 2) {
+                       printk(KERN_ERR "Can not write register address\n");
+                       goto err;
+               }
+               value[0] = 1;
+               /* verify buffer swap */
+               if (i2c_master_send(i2c, value, 1) != 1)
+                       printk(KERN_ERR "Can not write register address\n");
+
+               /* Read the Value of the Page 8 Register 1 which controls the
+                  Adaptive Switching Mode */
+               if (i2c_master_recv(i2c, &swap_reg_post, 1) != 1)
+                       printk(KERN_ERR "Can not read codec registers\n");
+
+               if ((swap_reg_pre == 4 && swap_reg_post == 6)
+                       || (swap_reg_pre == 6 && swap_reg_post == 4))
+                       DBG(KERN_INFO "Buffer swap success\n");
+               else
+                       printk(KERN_ERR
+                       "Buffer swap...FAILED\nswap_reg_pre=%x, swap_reg_post=%x\n",
+                       swap_reg_pre, swap_reg_post);
+       }
+
+err:
+       return 0;
+}
+
+#endif
+
+MODULE_DESCRIPTION("ASoC AIC3262 miniDSP multi-configuration");
+MODULE_AUTHOR("Barani Prashanth <gvbarani@mistralsolutions.com>");
+MODULE_LICENSE("GPL");