rk30 phone: add TI aic3262 codec driver
author宋秀杰 <sxj@rock-chips.com>
Wed, 2 May 2012 10:21:14 +0000 (18:21 +0800)
committer宋秀杰 <sxj@rock-chips.com>
Wed, 2 May 2012 10:21:14 +0000 (18:21 +0800)
25 files changed:
arch/arm/configs/rk30_phone_loquat_defconfig
arch/arm/mach-rk30/board-rk30-phone-loquat.c
drivers/mfd/Kconfig
drivers/mfd/Makefile
drivers/mfd/tlv320aic3262-core.c [new file with mode: 0644]
drivers/mfd/tlv320aic3262-irq.c [new file with mode: 0644]
include/linux/mfd/tlv320aic3262-core.h [new file with mode: 0644]
include/linux/mfd/tlv320aic3262-registers.h [new file with mode: 0644]
sound/soc/codecs/Kconfig
sound/soc/codecs/Makefile
sound/soc/codecs/aic3262_codec_ops.c [new file with mode: 0644]
sound/soc/codecs/aic3262_codec_ops.h [new file with mode: 0644]
sound/soc/codecs/aic326x_tiload.c [new file with mode: 0644]
sound/soc/codecs/aic326x_tiload.h [new file with mode: 0644]
sound/soc/codecs/aic3xxx_cfw.h [new file with mode: 0644]
sound/soc/codecs/aic3xxx_cfw_ops.c [new file with mode: 0644]
sound/soc/codecs/aic3xxx_cfw_ops.h [new file with mode: 0644]
sound/soc/codecs/pickle.h [new file with mode: 0644]
sound/soc/codecs/tlv320aic3262_default_fw.h [new file with mode: 0644]
sound/soc/codecs/tlv320aic326x.c [new file with mode: 0644]
sound/soc/codecs/tlv320aic326x.h [new file with mode: 0644]
sound/soc/rk29/Kconfig
sound/soc/rk29/Makefile
sound/soc/rk29/rk29_aic3262.c [new file with mode: 0644]
sound/soc/soc-core.c

index d3f4bf7c53d07f72d47e9402841d7f32f24e2641..9df0fa18f812906024378651d34734bb25321dbd 100755 (executable)
@@ -262,6 +262,7 @@ CONFIG_SPI_FPGA_GPIO_IRQ_NUM=0
 CONFIG_POWER_SUPPLY=y
 CONFIG_TEST_POWER=y
 # CONFIG_HWMON is not set
+CONFIG_AIC3262_CODEC=y
 CONFIG_REGULATOR=y
 CONFIG_MEDIA_SUPPORT=y
 CONFIG_VIDEO_DEV=y
@@ -294,8 +295,10 @@ CONFIG_SND=y
 CONFIG_SND_SOC=y
 CONFIG_SND_RK29_SOC=y
 CONFIG_SND_I2S_DMA_EVENT_STATIC=y
-CONFIG_SND_RK29_SOC_RT5631=y
+
+CONFIG_SND_RK29_SOC_AIC3262=y
 CONFIG_SND_RK29_CODEC_SOC_SLAVE=y
+CONFIG_SND_SOC_TLV320AIC326X=y
 CONFIG_HID_A4TECH=y
 CONFIG_HID_ACRUX=y
 CONFIG_HID_ACRUX_FF=y
index fd4b44f71931a2d56df0ec57ed965373d3486959..7ba270c835ddc7c434345c2c56e82952cfc6ecc3 100755 (executable)
@@ -1319,6 +1319,15 @@ static struct i2c_board_info __initdata i2c0_info[] = {
                .flags         = 0,
        },
 #endif
+
+#if defined (CONFIG_SND_SOC_TLV320AIC326X)
+       {
+               .type                   = "tlv320aic3262",
+               .addr           = 0x18,
+               .flags                  = 0,
+       },
+#endif
+
 #if defined (CONFIG_SND_SOC_RT5631)
         {
                 .type                   = "rt5631",
index af404a902e2f7f02828790b17a6d8c573d8536cf..2f102d7632f3f013e1570ac369a084a55e8c73d6 100755 (executable)
@@ -233,6 +233,11 @@ config TWL6030_PWM
          Say yes here if you want support for TWL6030 PWM.
          This is used to control charging LED brightness.
 
+config AIC3262_CODEC
+       bool "Support TI Codec Aic3262"
+       select MFD_CORE
+       default n
+
 config MFD_STMPE
        bool "Support STMicroelectronics STMPE"
        depends on I2C=y && GENERIC_HARDIRQS
index d0188cbcf8d3e1d9837f9e14bd128fa7fd22aa7f..829bbf1b42fadd8ad82ea9e3c57fb1139ea8eb9c 100755 (executable)
@@ -43,6 +43,7 @@ obj-$(CONFIG_TWL4030_MADC)      += twl4030-madc.o
 obj-$(CONFIG_TWL4030_POWER)    += twl4030-power.o
 obj-$(CONFIG_TWL4030_CODEC)    += twl4030-codec.o
 obj-$(CONFIG_TWL6030_PWM)      += twl6030-pwm.o
+obj-$(CONFIG_AIC3262_CODEC)    += tlv320aic3262-core.o tlv320aic3262-irq.o
 
 obj-$(CONFIG_MFD_MC13XXX)      += mc13xxx-core.o
 
diff --git a/drivers/mfd/tlv320aic3262-core.c b/drivers/mfd/tlv320aic3262-core.c
new file mode 100644 (file)
index 0000000..4e058ac
--- /dev/null
@@ -0,0 +1,680 @@
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/delay.h>
+#include <linux/mfd/core.h>
+#include <linux/pm_runtime.h>
+#include <linux/regulator/consumer.h>
+#include <linux/regulator/machine.h>
+#include <linux/gpio.h>
+
+#include <linux/mfd/tlv320aic3262-core.h>
+#include <linux/mfd/tlv320aic3262-registers.h>
+#define DEBUG 1
+struct aic3262_gpio
+{
+       unsigned int reg;
+       u8 mask;
+       u8 shift;
+};
+struct aic3262_gpio  aic3262_gpio_control[] = {
+       {
+               .reg = AIC3262_GPIO1_IO_CNTL,
+               .mask = AIC3262_GPIO_D6_D2,
+               .shift = AIC3262_GPIO_D2_SHIFT,
+       },
+       {
+               .reg = AIC3262_GPIO2_IO_CNTL,
+               .mask = AIC3262_GPIO_D6_D2, 
+               .shift = AIC3262_GPIO_D2_SHIFT,
+       },
+       {
+               .reg = AIC3262_GPI1_EN,
+               .mask = AIC3262_GPI1_D2_D1,
+               .shift = AIC3262_GPIO_D1_SHIFT,
+       },
+       {
+               .reg = AIC3262_GPI2_EN,         
+               .mask = AIC3262_GPI2_D5_D4,
+               .shift = AIC3262_GPIO_D4_SHIFT,
+       },
+       {
+               .reg = AIC3262_GPO1_OUT_CNTL,
+               .mask = AIC3262_GPO1_D4_D1,
+               .shift = AIC3262_GPIO_D1_SHIFT,
+       },
+};
+static int aic3262_read(struct aic3262 *aic3262, unsigned int reg,
+                      int bytes, void *dest)
+{
+       int ret;
+       //u8 *buf = dest;
+
+//     BUG_ON(bytes % 2);
+       BUG_ON(bytes <= 0);
+
+       ret = aic3262->read_dev(aic3262, reg, bytes, dest);
+       if (ret < 0)
+               return ret;
+
+/*     for (i = 0; i < bytes / 2; i++) {
+               dev_vdbg(aic3262->dev, "Read %04x from R%d(0x%x)\n",
+                        buf[i], reg + i, reg + i);
+       }*/
+
+       return ret;
+}
+
+/**
+ * aic3262_reg_read: Read a single TLV320AIC3262 register.
+ *
+ * @aic3262: Device to read from.
+ * @reg: Register to read.
+ */
+int aic3262_reg_read(struct aic3262 *aic3262, unsigned int reg)
+{
+       unsigned char val;
+       int ret;
+
+       mutex_lock(&aic3262->io_lock);
+
+       ret = aic3262_read(aic3262, reg, 1, &val);
+
+       mutex_unlock(&aic3262->io_lock);
+
+       if (ret < 0)
+               return ret;
+       else
+               return val;
+}
+EXPORT_SYMBOL_GPL(aic3262_reg_read);
+
+/**
+ * aic3262_bulk_read: Read multiple TLV320AIC3262 registers
+ *
+ * @aic3262: Device to read from
+ * @reg: First register
+ * @count: Number of registers
+ * @buf: Buffer to fill.  The data will be returned big endian.
+ */
+int aic3262_bulk_read(struct aic3262 *aic3262, unsigned int reg,
+                    int count, u8 *buf)
+{
+       int ret;
+
+       mutex_lock(&aic3262->io_lock);
+
+       ret = aic3262_read(aic3262, reg, count, buf);
+
+       mutex_unlock(&aic3262->io_lock);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(aic3262_bulk_read);
+
+static int aic3262_write(struct aic3262 *aic3262, unsigned int reg,
+                       int bytes, const void *src)
+{
+       //const u8 *buf = src;
+       
+
+//     BUG_ON(bytes % 2);
+       BUG_ON(bytes <= 0);
+
+/*     for (i = 0; i < bytes / 2; i++) {
+               dev_vdbg(aic3262->dev, "Write %04x to R%d(0x%x)\n",
+                       buf[i], reg + i, reg + i);
+       }*/
+
+       return aic3262->write_dev(aic3262, reg, bytes, src);
+}
+
+/**
+ * aic3262_reg_write: Write a single TLV320AIC3262 register.
+ *
+ * @aic3262: Device to write to.
+ * @reg: Register to write to.
+ * @val: Value to write.
+ */
+int aic3262_reg_write(struct aic3262 *aic3262, unsigned int reg,
+                    unsigned char val)
+{
+       int ret;
+
+//     val = cpu_to_be16(val);
+
+       mutex_lock(&aic3262->io_lock);
+
+       ret = aic3262_write(aic3262, reg, 1, &val);
+
+       mutex_unlock(&aic3262->io_lock);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(aic3262_reg_write);
+
+/**
+ * aic3262_bulk_write: Write multiple TLV320AIC3262 registers
+ *
+ * @aic3262: Device to write to
+ * @reg: First register
+ * @count: Number of registers
+ * @buf: Buffer to write from.  Data must be big-endian formatted.
+ */
+int aic3262_bulk_write(struct aic3262 *aic3262, unsigned int reg,
+                     int count, const u8 *buf)
+{
+       int ret;
+
+       mutex_lock(&aic3262->io_lock);
+
+       ret = aic3262_write(aic3262, reg, count, buf);
+
+       mutex_unlock(&aic3262->io_lock);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(aic3262_bulk_write);
+
+/**
+ * aic3262_set_bits: Set the value of a bitfield in a TLV320AIC3262 register
+ *
+ * @aic3262: Device to write to.
+ * @reg: Register to write to.
+ * @mask: Mask of bits to set.
+ * @val: Value to set (unshifted)
+ */
+int aic3262_set_bits(struct aic3262 *aic3262, unsigned int reg,
+                   unsigned char mask, unsigned char val)
+{
+       int ret;
+       u8 r;
+
+       mutex_lock(&aic3262->io_lock);
+
+       ret = aic3262_read(aic3262, reg, 1, &r);
+       if (ret < 0)
+               goto out;
+
+
+       r &= ~mask;
+       r |= (val & mask);
+
+       ret = aic3262_write(aic3262, reg, 1, &r);
+
+out:
+       mutex_unlock(&aic3262->io_lock);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(aic3262_set_bits);
+/* to be changed -- Mukund*/ 
+static struct resource aic3262_codec_resources[] = {
+       {
+               .start = AIC3262_IRQ_HEADSET_DETECT,
+               .end   = AIC3262_IRQ_SPEAKER_OVER_TEMP,
+               .flags = IORESOURCE_IRQ,
+       },
+};
+
+static struct resource aic3262_gpio_resources[] = {
+       {
+               .start = AIC3262_GPIO1,
+               .end   = AIC3262_GPO1,
+               .flags = IORESOURCE_IRQ,
+       },
+};
+
+static struct mfd_cell aic3262_devs[] = {
+       {
+               .name = "tlv320aic3262-codec",
+               .num_resources = ARRAY_SIZE(aic3262_codec_resources),
+               .resources = aic3262_codec_resources,
+       },
+
+       {
+               .name = "tlv320aic3262-gpio",
+               .num_resources = ARRAY_SIZE(aic3262_gpio_resources),
+               .resources = aic3262_gpio_resources,
+               .pm_runtime_no_callbacks = true,
+       },
+};
+
+
+#ifdef CONFIG_PM
+static int aic3262_suspend(struct device *dev)
+{
+       struct aic3262 *aic3262 = dev_get_drvdata(dev);
+       
+
+       /* Don't actually go through with the suspend if the CODEC is
+        * still active (eg, for audio passthrough from CP. */
+//     ret = aic3262_reg_read(aic3262, 20AIC3262_POWER_MANAGEMENT_1);
+/*     if (ret < 0) {
+               dev_err(dev, "Failed to read power status: %d\n", ret);
+       } else if (ret & TLV320AIC3262_VMID_SEL_MASK) {
+               dev_dbg(dev, "CODEC still active, ignoring suspend\n");
+               return 0;
+       }
+*/
+       /* GPIO configuration state is saved here since we may be configuring
+        * the GPIO alternate functions even if we're not using the gpiolib
+        * driver for them.
+        */
+//     ret = aic3262_read(aic3262, TLV320AIC3262_GPIO_1, TLV320AIC3262_NUM_GPIO_REGS * 2,
+//                       &aic3262->gpio_regs);
+/*     if (ret < 0)
+               dev_err(dev, "Failed to save GPIO registers: %d\n", ret);*/
+
+
+       /* Explicitly put the device into reset in case regulators
+        * don't get disabled in order to ensure consistent restart.
+        */
+//     aic3262_reg_write(aic3262, TLV320AIC3262_SOFTWARE_RESET, 0x8994);
+
+       aic3262->suspended = true;
+
+       return 0;
+}
+
+static int aic3262_resume(struct device *dev)
+{
+       struct aic3262 *aic3262 = dev_get_drvdata(dev);
+
+
+       /* We may have lied to the PM core about suspending */
+/*     if (!aic3262->suspended)
+               return 0;
+
+       ret = aic3262_write(aic3262, TLV320AIC3262_INTERRUPT_STATUS_1_MASK,
+                          TLV320AIC3262_NUM_IRQ_REGS * 2, &aic3262->irq_masks_cur);
+       if (ret < 0)
+               dev_err(dev, "Failed to restore interrupt masks: %d\n", ret);
+
+
+       ret = aic3262_write(aic3262, TLV320AIC3262_GPIO_1, TLV320AIC3262_NUM_GPIO_REGS * 2,
+                          &aic3262->gpio_regs);
+       if (ret < 0)
+               dev_err(dev, "Failed to restore GPIO registers: %d\n", ret);
+*/
+       aic3262->suspended = false;
+
+       return 0;
+}
+#endif
+
+
+/*
+ * Instantiate the generic non-control parts of the device.
+ */
+static int aic3262_device_init(struct aic3262 *aic3262, int irq)
+{
+       struct aic3262_pdata *pdata = aic3262->dev->platform_data;
+       const char *devname;
+       int ret, i;
+       u8 revID, pgID;
+       unsigned int naudint = 0;
+       u8 resetVal = 1;
+       printk("aic3262_device_init beginning\n");
+
+       mutex_init(&aic3262->io_lock);
+       dev_set_drvdata(aic3262->dev, aic3262);
+       if(pdata){
+               if(pdata->gpio_reset){
+                       ret = gpio_request(pdata->gpio_reset,"aic3262-reset-pin");
+                       if(ret != 0){
+                               dev_err(aic3262->dev,"not able to acquire gpio %d for reseting the AIC3262 \n", pdata->gpio_reset);
+                               goto err_return;
+                       }
+                       gpio_direction_output(pdata->gpio_reset, 1);
+                       msleep(5);
+                       gpio_direction_output(pdata->gpio_reset, 0);
+                       msleep(5);
+                       gpio_direction_output(pdata->gpio_reset, 1);
+//                     gpio_set_value(pdata->gpio_reset, 0);
+                       msleep(5);
+                       
+                       
+               }       
+       }
+
+
+       /* run the codec through software reset */      
+       ret = aic3262_reg_write(aic3262, AIC3262_RESET_REG, resetVal);
+       if (ret < 0) {
+               dev_err(aic3262->dev, "Could not write to AIC3262 register\n");
+               goto err_return;
+       }
+               
+       msleep(10);
+               
+
+       ret = aic3262_reg_read(aic3262, AIC3262_REV_PG_ID);
+       if (ret < 0) {
+               dev_err(aic3262->dev, "Failed to read ID register\n");
+               goto err_return;
+       }
+       revID = (ret & AIC3262_REV_MASK) >> AIC3262_REV_SHIFT;
+       pgID = (ret & AIC3262_PG_MASK) >> AIC3262_PG_SHIFT;
+       switch (revID ) {
+       case 3:
+               devname = "TLV320AIC3262";
+               if (aic3262->type != TLV320AIC3262)
+                       dev_warn(aic3262->dev, "Device registered as type %d\n",
+                                aic3262->type);
+               aic3262->type = TLV320AIC3262;
+               break;
+       default:
+               dev_err(aic3262->dev, "Device is not a TLV320AIC3262, ID is %x\n",
+                       ret);
+               ret = -EINVAL;
+               goto err_return;
+       
+       }
+
+       dev_info(aic3262->dev, "%s revision %c\n", devname, 'D' + ret);
+
+       printk("aic3262_device_init %s revision %c\n", devname, 'D' + ret);
+
+       if (pdata) {
+               if(pdata->gpio_irq == 1) {
+                       naudint = gpio_to_irq(pdata->naudint_irq);
+                       gpio_request(pdata->naudint_irq,"aic3262-gpio-irq");
+                       gpio_direction_input(pdata->naudint_irq);
+               }
+               else {
+                       naudint = pdata->naudint_irq;
+               }
+               aic3262->irq = naudint;
+               aic3262->irq_base = pdata->irq_base;
+               for(i = 0; i < AIC3262_NUM_GPIO;i++)
+               {       
+                       if(pdata->gpio[i].used)
+                       {
+                               if(pdata->gpio[i].in) // direction is input
+                               {       
+                                       // set direction to input for GPIO, and enable for GPI 
+                                       aic3262_set_bits(aic3262, aic3262_gpio_control[i].reg, 
+                                               aic3262_gpio_control[i].mask, 0x1 << aic3262_gpio_control[i].shift); 
+                                       if(pdata->gpio[i].in_reg) // Some input modes, does not need extra registers to be written
+                                               aic3262_set_bits(aic3262, pdata->gpio[i].in_reg, 
+                                               pdata->gpio[i].in_reg_bitmask, 
+                                               pdata->gpio[i].value << pdata->gpio[i].in_reg_shift);   
+                               }
+                               else    // direction is output
+                               {
+                                       
+                                       aic3262_set_bits(aic3262, aic3262_gpio_control[i].reg, 
+                                               aic3262_gpio_control[i].mask, pdata->gpio[i].value << aic3262_gpio_control[i].shift);
+                               }
+                       }
+                       else // Disable the gpio/gpi/gpo
+                               aic3262_set_bits(aic3262, aic3262_gpio_control[i].reg, aic3262_gpio_control[i].mask, 0x0);
+               }       
+               
+
+       }
+
+
+       if(naudint) {
+               /* codec interrupt */
+               ret = aic3262_irq_init(aic3262);
+               if(ret)
+                       goto err_irq;
+       }
+
+       ret = mfd_add_devices(aic3262->dev, -1,
+                             aic3262_devs, ARRAY_SIZE(aic3262_devs),
+                             NULL, 0);
+       if (ret != 0) {
+               dev_err(aic3262->dev, "Failed to add children: %d\n", ret);
+               goto err_irq;
+       }
+
+       printk("aic3262_device_init added mfd devices \n");
+       pm_runtime_enable(aic3262->dev);
+       pm_runtime_resume(aic3262->dev);
+
+       return 0;
+
+err_irq:
+       aic3262_irq_exit(aic3262);
+//err:
+//     mfd_remove_devices(aic3262->dev);
+err_return:
+       kfree(aic3262);
+       return ret;
+}
+
+static void aic3262_device_exit(struct aic3262 *aic3262)
+{
+       pm_runtime_disable(aic3262->dev);
+       mfd_remove_devices(aic3262->dev);
+       aic3262_irq_exit(aic3262);
+       kfree(aic3262);
+}
+
+static int aic3262_i2c_read_device(struct aic3262 *aic3262, unsigned int reg,
+                                 int bytes, void *dest)
+{
+       struct i2c_client *i2c = aic3262->control_data;
+       aic326x_reg_union *aic_reg = (aic326x_reg_union *) &reg;        
+       char *value;
+       int ret;
+       u8 buf[2];
+       u8 page, book, offset;
+       page = aic_reg->aic326x_register.page;
+       book = aic_reg->aic326x_register.book;
+       offset = aic_reg->aic326x_register.offset;
+       if(aic3262->book_no != book) // change in book required.
+       {
+               // We should change to page 0.
+               // Change the book by writing to offset 127 of page 0
+               // Change the page back to whatever was set before change page
+               buf[0] = 0x0;
+               buf[1] = 0x0;
+               ret = i2c_master_send(i2c, (unsigned char *)buf, 2);
+               if (ret < 0)
+                       return ret;
+               if (ret != 2)
+                       return -EIO;
+               buf[0] = 127;
+               buf[1] = book;
+               ret = i2c_master_send(i2c, (unsigned char *)buf, 2);
+               if (ret < 0)
+                       return ret;
+               if (ret != 2)
+                       return -EIO;
+               aic3262->book_no = book;
+               aic3262->page_no = 0x0;// To force a page change in the following if
+       }
+
+       if (aic3262->page_no != page) {
+               buf[0] = 0x0;
+               buf[1] = page;
+               ret = i2c_master_send(i2c, (unsigned char *) buf, 2);
+
+               if (ret < 0)
+                       return ret;
+               if (ret != 2)
+                       return -EIO;
+               aic3262->page_no = page;
+       }
+       // Send the required offset 
+       buf[0] = offset ;
+       ret = i2c_master_send(i2c, (unsigned char *)buf, 1);
+       if (ret < 0)
+               return ret;
+       if (ret != 1)
+               return -EIO;
+
+       ret = i2c_master_recv(i2c, dest, bytes);
+       value = dest; 
+       if (ret < 0)
+               return ret;
+       if (ret != bytes)
+               return -EIO;
+       return ret;
+}
+
+static int aic3262_i2c_write_device(struct aic3262 *aic3262, unsigned int reg,
+                                  int bytes, const void *src)
+{
+       struct i2c_client *i2c = aic3262->control_data;
+       int ret;
+       
+       //char *value;
+       aic326x_reg_union *aic_reg = (aic326x_reg_union *) &reg;        
+       
+       //struct i2c_msg xfer[2];
+       u8 buf[2];
+       u8 write_buf[bytes + 1];
+       u8 page, book, offset;
+       page = aic_reg->aic326x_register.page;
+       book = aic_reg->aic326x_register.book;
+       offset = aic_reg->aic326x_register.offset;
+       if(aic3262->book_no != book) // change in book required.
+       {
+               // We should change to page 0.
+               // Change the book by writing to offset 127 of page 0
+               // Change the page back to whatever was set before change page
+               buf[0] = 0x0;
+               buf[1] = 0x0;
+               ret = i2c_master_send(i2c, (unsigned char *)buf, 2);
+               
+               if (ret < 0)
+                       return ret;
+               if (ret != 2)
+                       return -EIO;
+               buf[0] = 127;
+               buf[1] = book;
+               ret = i2c_master_send(i2c, (unsigned char *)buf, 2);
+               if (ret < 0)
+                       return ret;
+               if (ret != 2)
+                       return -EIO;
+               aic3262->book_no = book;
+               aic3262->page_no = 0x0;// To force a page change in the following if
+       }
+
+       if (aic3262->page_no != page) {
+               buf[0] = 0x0;
+               buf[1] = page;
+               ret = i2c_master_send(i2c, (unsigned char *) buf, 2);
+               if (ret < 0)
+                       return ret;
+               if (ret != 2)
+                       return -EIO;
+               aic3262->page_no = page;
+       }
+//     value = (char *) src;
+       //ret = i2c_transfer(i2c->adapter, xfer, 2);
+       //printk("%s:write  ret = %d\n",__func__, ret);
+       // send the offset as first message
+/*     xfer[0].addr = i2c->addr;
+       xfer[0].flags = i2c->flags & I2C_M_TEN;
+       xfer[0].len = 1;
+       xfer[0].buf = (char *)&offset;
+       // Send the values in bulk
+       xfer[1].addr = i2c->addr;
+       xfer[1].flags = i2c->flags & I2C_M_TEN;
+       xfer[1].len = bytes;
+       xfer[1].buf = (char *)src;
+
+       ret = i2c_transfer(i2c->adapter, xfer, 2);*/
+/*     buf[0] = offset;
+       memcpy(&buf[1], src, bytes);*/
+//     ret = i2c_master_send(i2c, (unsigned char *)buf, 1);
+//     printk("%s:write offset ret = %d\n",__func__, ret);
+//     ret = i2c_master_send(i2c, (unsigned char *)src, bytes); 
+/*     value = (char *) src;
+       buf[0] = offset;
+       buf[1] = *value; 
+       ret = i2c_master_send(i2c, buf, 2); */
+       write_buf[0] = offset;
+       memcpy(&write_buf[1], src, bytes);
+       ret = i2c_master_send(i2c, write_buf, bytes + 1);
+       if (ret < 0)
+               return ret;
+       if (ret != (bytes + 1) )
+               return -EIO;
+
+       return 0;
+}
+
+static int aic3262_i2c_probe(struct i2c_client *i2c,
+                           const struct i2c_device_id *id)
+{
+       struct aic3262 *aic3262;
+
+       printk("%s: entered \n", __FUNCTION__);
+       aic3262 = kzalloc(sizeof(struct aic3262), GFP_KERNEL);
+       if (aic3262 == NULL)
+               return -ENOMEM;
+
+       printk("%s: allocated memory \n", __FUNCTION__);
+       i2c_set_clientdata(i2c, aic3262);
+       aic3262->dev = &i2c->dev;
+       aic3262->control_data = i2c;
+       aic3262->read_dev = aic3262_i2c_read_device;
+       aic3262->write_dev = aic3262_i2c_write_device;
+//     aic3262->irq = i2c->irq;
+       aic3262->type = id->driver_data;
+       aic3262->book_no = 255;
+       aic3262->page_no = 255;
+
+       return aic3262_device_init(aic3262, i2c->irq);
+}
+
+static int aic3262_i2c_remove(struct i2c_client *i2c)
+{
+       struct aic3262 *aic3262 = i2c_get_clientdata(i2c);
+
+       aic3262_device_exit(aic3262);
+
+       return 0;
+}
+
+static const struct i2c_device_id aic3262_i2c_id[] = {
+       { "tlv320aic3262", TLV320AIC3262 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, aic3262_i2c_id);
+
+static UNIVERSAL_DEV_PM_OPS(aic3262_pm_ops, aic3262_suspend, aic3262_resume,
+                           NULL);
+
+static struct i2c_driver aic3262_i2c_driver = {
+       .driver = {
+               .name = "tlv320aic3262",
+               .owner = THIS_MODULE,
+               .pm = &aic3262_pm_ops,
+       },
+       .probe = aic3262_i2c_probe,
+       .remove = aic3262_i2c_remove,
+       .id_table = aic3262_i2c_id,
+};
+
+static int __init aic3262_i2c_init(void)
+{
+       int ret;
+       printk("aic3262_mfd i2c_init \n");      
+       ret = i2c_add_driver(&aic3262_i2c_driver);
+       if (ret != 0)
+               pr_err("Failed to register aic3262 I2C driver: %d\n", ret);
+
+       return ret;
+}
+module_init(aic3262_i2c_init);
+
+static void __exit aic3262_i2c_exit(void)
+{
+       i2c_del_driver(&aic3262_i2c_driver);
+}
+module_exit(aic3262_i2c_exit);
+
+MODULE_DESCRIPTION("Core support for the TLV320AIC3262 audio CODEC");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Mukund Navada <navada@ti.comm>");
diff --git a/drivers/mfd/tlv320aic3262-irq.c b/drivers/mfd/tlv320aic3262-irq.c
new file mode 100644 (file)
index 0000000..9a76f0f
--- /dev/null
@@ -0,0 +1,204 @@
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/irq.h>
+#include <linux/mfd/core.h>
+#include <linux/interrupt.h>
+
+#include <linux/mfd/tlv320aic3262-core.h>
+#include <linux/mfd/tlv320aic3262-registers.h>
+
+#include <linux/delay.h>
+struct aic3262_irq_data {
+       int mask;
+       int status;
+};
+
+static struct aic3262_irq_data aic3262_irqs[] = {
+       {
+               .mask = AIC3262_HEADSET_IN_MASK,
+               .status = AIC3262_HEADSET_PLUG_UNPLUG_INT,
+       },
+       {
+               .mask = AIC3262_BUTTON_PRESS_MASK,
+               .status = AIC3262_BUTTON_PRESS_INT,
+       },
+       {
+               .mask = AIC3262_DAC_DRC_THRES_MASK,
+               .status = AIC3262_LEFT_DRC_THRES_INT | AIC3262_RIGHT_DRC_THRES_INT,
+       },
+       {
+               .mask = AIC3262_AGC_NOISE_MASK,
+               .status = AIC3262_LEFT_AGC_NOISE_INT | AIC3262_RIGHT_AGC_NOISE_INT,
+       },
+       {
+               .mask = AIC3262_OVER_CURRENT_MASK,
+               .status = AIC3262_LEFT_OUTPUT_DRIVER_OVERCURRENT_INT 
+                       | AIC3262_RIGHT_OUTPUT_DRIVER_OVERCURRENT_INT,
+       },
+       {
+               .mask = AIC3262_OVERFLOW_MASK,
+               .status = AIC3262_LEFT_DAC_OVERFLOW_INT | AIC3262_RIGHT_DAC_OVERFLOW_INT
+                       | AIC3262_MINIDSP_D_BARREL_SHIFT_OVERFLOW_INT | AIC3262_LEFT_ADC_OVERFLOW_INT
+                       | AIC3262_RIGHT_ADC_OVERFLOW_INT | AIC3262_MINIDSP_D_BARREL_SHIFT_OVERFLOW_INT,
+       },
+       {
+               .mask = AIC3262_SPK_OVERCURRENT_MASK,
+               .status = AIC3262_SPK_OVER_CURRENT_INT,
+       },
+
+};
+
+struct aic3262_gpio_data {
+
+};
+
+static inline struct aic3262_irq_data *irq_to_aic3262_irq(struct aic3262 *aic3262,
+               int irq)
+{
+       return &aic3262_irqs[irq - aic3262->irq_base];
+}
+
+static void aic3262_irq_lock(struct irq_data *data)
+{
+       struct aic3262 *aic3262 = irq_data_get_irq_chip_data(data);
+
+       mutex_lock(&aic3262->irq_lock);
+}
+
+static void aic3262_irq_sync_unlock(struct irq_data *data)
+{
+       struct aic3262 *aic3262 = irq_data_get_irq_chip_data(data);
+
+       /* write back to hardware any change in irq mask */
+       if (aic3262->irq_masks_cur != aic3262->irq_masks_cache) {
+               aic3262->irq_masks_cache = aic3262->irq_masks_cur;
+               aic3262_reg_write(aic3262, AIC3262_INT1_CNTL,
+                               aic3262->irq_masks_cur);
+       }
+
+       mutex_unlock(&aic3262->irq_lock);
+}
+
+static void aic3262_irq_unmask(struct irq_data *data)
+{
+       struct aic3262 *aic3262 = irq_data_get_irq_chip_data(data);
+       struct aic3262_irq_data *irq_data = irq_to_aic3262_irq(aic3262, data->irq);
+
+       aic3262->irq_masks_cur |= irq_data->mask;
+}
+
+static void aic3262_irq_mask(struct irq_data *data)
+{
+       struct aic3262 *aic3262 = irq_data_get_irq_chip_data(data);
+       struct aic3262_irq_data *irq_data = irq_to_aic3262_irq(aic3262, data->irq);
+
+       aic3262->irq_masks_cur &= ~irq_data->mask;
+}
+
+static struct irq_chip aic3262_irq_chip = {
+       .name = "tlv320aic3262",
+       .irq_bus_lock = aic3262_irq_lock,
+       .irq_bus_sync_unlock = aic3262_irq_sync_unlock,
+       .irq_mask = aic3262_irq_mask,
+       .irq_unmask = aic3262_irq_unmask,
+};
+
+static irqreturn_t aic3262_irq_thread(int irq, void *data)
+{
+       struct aic3262 *aic3262 = data;
+       u8 status[4]; 
+       int i=0;
+       // Reading the sticky bit registers acknowledges the interrupt to the device */
+       aic3262_bulk_read(aic3262, AIC3262_INT_STICKY_FLAG1, 4, status);
+       
+       /* report  */
+       if(status[2] & aic3262_irqs[AIC3262_IRQ_HEADSET_DETECT].status) // 0    
+       {
+                       handle_nested_irq(aic3262->irq_base);
+                       
+       }
+       if(status[2] & aic3262_irqs[AIC3262_IRQ_BUTTON_PRESS].status)   // 1            
+                       handle_nested_irq(aic3262->irq_base + 1);
+       if(status[2] & aic3262_irqs[AIC3262_IRQ_DAC_DRC].status)        // 2            
+                       handle_nested_irq(aic3262->irq_base + 2);
+       if(status[3] & aic3262_irqs[AIC3262_IRQ_AGC_NOISE].status)      // 3            
+                       handle_nested_irq(aic3262->irq_base + 3);
+       if(status[2] & aic3262_irqs[AIC3262_IRQ_OVER_CURRENT].status)   // 4            
+                       handle_nested_irq(aic3262->irq_base + 4);
+       if(status[0] & aic3262_irqs[AIC3262_IRQ_OVERFLOW_EVENT].status) // 5            
+                       handle_nested_irq(aic3262->irq_base + 5);
+       if(status[3] & aic3262_irqs[AIC3262_IRQ_SPEAKER_OVER_TEMP].status)      // 6            
+                       handle_nested_irq(aic3262->irq_base + 6);
+
+       /* ack unmasked irqs */
+       /* No need to acknowledge the interrupt on AIC3262 */
+
+       return IRQ_HANDLED;
+}
+
+
+
+int aic3262_irq_init(struct aic3262 *aic3262)
+{
+       int cur_irq, ret;
+
+       mutex_init(&aic3262->irq_lock);
+
+       /* mask the individual interrupt sources */
+       aic3262->irq_masks_cur = 0x0; 
+       aic3262->irq_masks_cache = 0x0;
+       aic3262_reg_write(aic3262, AIC3262_INT1_CNTL, 0x0);
+
+       if (!aic3262->irq) {
+               dev_warn(aic3262->dev,
+                               "no interrupt specified, no interrupts\n");
+               aic3262->irq_base = 0;
+               return 0;
+       }
+
+       if (!aic3262->irq_base) {
+               dev_err(aic3262->dev,
+                               "no interrupt base specified, no interrupts\n");
+               return 0;
+       }
+
+
+       /* Register them with genirq */
+       for (cur_irq = aic3262->irq_base;
+               cur_irq < aic3262->irq_base + ARRAY_SIZE(aic3262_irqs);
+               cur_irq++) {
+               irq_set_chip_data(cur_irq, aic3262);
+               irq_set_chip_and_handler(cur_irq, &aic3262_irq_chip,
+                               handle_edge_irq);
+               irq_set_nested_thread(cur_irq, 1);
+
+               /* ARM needs us to explicitly flag the IRQ as valid
+                * and will set them noprobe when we do so. */
+#ifdef CONFIG_ARM
+               set_irq_flags(cur_irq, IRQF_VALID);
+#else
+               set_irq_noprobe(cur_irq);
+#endif
+       }
+
+       ret = request_threaded_irq(aic3262->irq, NULL, aic3262_irq_thread,
+                               IRQF_TRIGGER_RISING,
+                                  "tlv320aic3262", aic3262);
+       if (ret) {
+               dev_err(aic3262->dev, "failed to request IRQ %d: %d\n",
+                       aic3262->irq, ret);
+               return ret;
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL(aic3262_irq_init);
+
+void aic3262_irq_exit(struct aic3262 *aic3262)
+{
+       if (aic3262->irq)
+               free_irq(aic3262->irq, aic3262);
+}
+EXPORT_SYMBOL(aic3262_irq_exit);
diff --git a/include/linux/mfd/tlv320aic3262-core.h b/include/linux/mfd/tlv320aic3262-core.h
new file mode 100644 (file)
index 0000000..165f5e4
--- /dev/null
@@ -0,0 +1,256 @@
+#ifndef __MFD_AIC3262_CORE_H__
+#define __MFD_AIC3262_CORE_H__
+
+#include <linux/interrupt.h>
+#include <linux/mfd/core.h>
+enum aic3262_type {
+       TLV320AIC3262 = 0,
+};
+
+
+#define AIC3262_IRQ_HEADSET_DETECT     0
+#define AIC3262_IRQ_BUTTON_PRESS       1
+#define AIC3262_IRQ_DAC_DRC            2
+#define AIC3262_IRQ_AGC_NOISE          3
+#define AIC3262_IRQ_OVER_CURRENT       4
+#define AIC3262_IRQ_OVERFLOW_EVENT     5
+#define AIC3262_IRQ_SPEAKER_OVER_TEMP  6
+
+#define AIC3262_GPIO1                  7
+#define AIC3262_GPIO2                  8
+#define AIC3262_GPI1                   9
+#define AIC3262_GPI2                   10
+#define AIC3262_GPO1                   11
+
+typedef union aic326x_reg_union {
+       struct aic326x_reg{
+       u8 offset;
+       u8 page;
+       u8 book;
+       u8 reserved;
+       }aic326x_register;
+       unsigned int aic326x_register_int;
+}aic326x_reg_union;
+
+
+/****************************             ************************************/
+
+/*
+ *****************************************************************************
+ * Structures Definitions
+ *****************************************************************************
+ */
+/*
+ *----------------------------------------------------------------------------
+ * @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;
+};
+
+/* GPIO API */                                                                                                                                              
+#define AIC3262_NUM_GPIO 5 // include 2 GPI and 1 GPO pins
+enum {                                                                                                                                                      
+        AIC3262_GPIO1_FUNC_DISABLED             = 0,                                                                                                        
+        AIC3262_GPIO1_FUNC_INPUT               = 1,                                                                                                        
+        AIC3262_GPIO1_FUNC_OUTPUT              = 3,                                                                                                        
+        AIC3262_GPIO1_FUNC_CLOCK_OUTPUT                = 4,
+        AIC3262_GPIO1_FUNC_INT1_OUTPUT         = 5,
+        AIC3262_GPIO1_FUNC_INT2_OUTPUT         = 6,
+        AIC3262_GPIO1_FUNC_ADC_MOD_CLK_OUTPUT   = 10,
+        AIC3262_GPIO1_FUNC_SAR_ADC_INTERRUPT    = 12,
+        AIC3262_GPIO1_FUNC_ASI1_DATA_OUTPUT     = 15,
+        AIC3262_GPIO1_FUNC_ASI1_WCLK           = 16,
+        AIC3262_GPIO1_FUNC_ASI1_BCLK           = 17,
+        AIC3262_GPIO1_FUNC_ASI2_WCLK           = 18,
+        AIC3262_GPIO1_FUNC_ASI2_BCLK           = 19,
+        AIC3262_GPIO1_FUNC_ASI3_WCLK           = 20,
+        AIC3262_GPIO1_FUNC_ASI3_BCLK           = 21
+
+};                                                                                                                                                          
+                                                                                                                                                            
+enum {                                                                                                                                                      
+        AIC3262_GPIO2_FUNC_DISABLED             = 0,                                                                                                        
+        AIC3262_GPIO2_FUNC_INPUT               = 1,                                                                                                        
+        AIC3262_GPIO2_FUNC_OUTPUT              = 3,                                                                                                        
+        AIC3262_GPIO2_FUNC_CLOCK_OUTPUT                = 4,
+        AIC3262_GPIO2_FUNC_INT1_OUTPUT         = 5,
+        AIC3262_GPIO2_FUNC_INT2_OUTPUT         = 6,
+        AIC3262_GPIO2_FUNC_ADC_MOD_CLK_OUTPUT   = 10,
+        AIC3262_GPIO2_FUNC_SAR_ADC_INTERRUPT    = 12,
+        AIC3262_GPIO2_FUNC_ASI1_DATA_OUTPUT     = 15,
+        AIC3262_GPIO2_FUNC_ASI1_WCLK           = 16,
+        AIC3262_GPIO2_FUNC_ASI1_BCLK           = 17,
+        AIC3262_GPIO2_FUNC_ASI2_WCLK           = 18,
+        AIC3262_GPIO2_FUNC_ASI2_BCLK           = 19,
+        AIC3262_GPIO2_FUNC_ASI3_WCLK           = 20,
+        AIC3262_GPIO2_FUNC_ASI3_BCLK           = 21
+};                                   
+enum {                                                                                                                                                      
+        AIC3262_GPO1_FUNC_DISABLED                     = 0,                                                                                                        
+        AIC3262_GPO1_FUNC_MSO_OUTPUT_FOR_SPI   = 1,                                                                                                        
+        AIC3262_GPO1_FUNC_GENERAL_PURPOSE_OUTPUT= 2,
+        AIC3262_GPO1_FUNC_CLOCK_OUTPUT         = 3,
+        AIC3262_GPO1_FUNC_INT1_OUTPUT          = 4,
+        AIC3262_GPO1_FUNC_INT2_OUTPUT          = 5,
+               AIC3262_GPO1_FUNC_ADC_MOD_CLK_OUTPUT   = 7,
+        AIC3262_GPO1_FUNC_SAR_ADC_INTERRUPT    = 12,
+        AIC3262_GPO1_FUNC_ASI1_DATA_OUTPUT     = 15,
+};                                   
+/*
+ *----------------------------------------------------------------------------
+ * @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
+ */
+struct aic3262 {
+       struct mutex io_lock;
+       struct mutex irq_lock;
+
+       enum aic3262_type type;
+
+       struct device *dev;
+       int (*read_dev)(struct aic3262 *aic3262, unsigned int reg,
+                       int bytes, void *dest);
+       int (*write_dev)(struct aic3262 *aic3262, unsigned int reg,
+                        int bytes, const void *src);
+
+       void *control_data;
+
+//     int gpio_base;
+       
+       unsigned int irq;
+       unsigned int irq_base;
+
+       u8 irq_masks_cur;
+       u8 irq_masks_cache;
+
+       /* Used over suspend/resume */
+       bool suspended;
+               
+       u8 book_no;
+       u8 page_no;
+};
+
+struct aic3262_gpio_setup 
+{
+       u8 used; // GPIO, GPI and GPO is used in the board, used = 1 else 0
+       u8 in; // GPIO is used as input, in = 1 else in = 0. GPI in = 1, GPO in = 0
+       unsigned int in_reg; // if GPIO is input, register to write the mask to.
+       u8 in_reg_bitmask; // bitmask for 'value' to be written into in_reg
+       u8 in_reg_shift; // bits to shift to write 'value' into in_reg
+       u8 value; // value to be written gpio_control_reg if GPIO is output, in_reg if its input        
+}; 
+struct aic3262_pdata {
+       unsigned int audio_mclk1; 
+       unsigned int audio_mclk2; 
+       unsigned int gpio_irq; /* whether AIC3262 interrupts the host AP on a GPIO pin of AP */ 
+       unsigned int gpio_reset; /* is the codec being reset by a gpio [host] pin, if yes provide the number. */
+       struct aic3262_gpio_setup *gpio;/* all gpio configuration */
+       int naudint_irq; /* audio interrupt */
+       unsigned int irq_base;
+};
+               
+
+
+static inline int aic3262_request_irq(struct aic3262 *aic3262, int irq,
+                                     irq_handler_t handler, unsigned long irqflags,const char *name,
+                                     void *data)
+{
+       if (!aic3262->irq_base)
+               return -EINVAL;
+
+       return request_threaded_irq(aic3262->irq_base + irq, NULL, handler,
+                                   irqflags, name, data);
+}
+
+static inline void aic3262_free_irq(struct aic3262 *aic3262, int irq,
+                                   void *data)
+{
+       if (!aic3262->irq_base)
+               return;
+
+       free_irq(aic3262->irq_base + irq, data);
+}
+
+/* Device I/O API */
+int aic3262_reg_read(struct aic3262 *aic3262, unsigned int reg);
+int aic3262_reg_write(struct aic3262 *aic3262, unsigned int reg,
+                unsigned char val);
+int aic3262_set_bits(struct aic3262 *aic3262, unsigned int reg,
+                   unsigned char mask, unsigned char val);
+int aic3262_bulk_read(struct aic3262 *aic3262, unsigned int reg,
+                    int count, u8 *buf);
+int aic3262_bulk_write(struct aic3262 *aic3262, unsigned int reg,
+                    int count, const u8 *buf);
+
+
+/* Helper to save on boilerplate */
+/*static inline int aic3262_request_irq(struct aic3262 *aic3262, int irq,
+                                    irq_handler_t handler, const char *name,
+                                    void *data)
+{
+       if (!aic3262->irq_base)
+               return -EINVAL;
+       return request_threaded_irq(aic3262->irq_base + irq, NULL, handler,
+                                   IRQF_TRIGGER_RISING, name,
+                                   data);
+}
+static inline void aic3262_free_irq(struct aic3262 *aic3262, int irq, void *data)
+{
+       if (!aic3262->irq_base)
+               return;
+       free_irq(aic3262->irq_base + irq, data);
+}
+*/
+int aic3262_irq_init(struct aic3262 *aic3262);
+void aic3262_irq_exit(struct aic3262 *aic3262);
+
+#endif
diff --git a/include/linux/mfd/tlv320aic3262-registers.h b/include/linux/mfd/tlv320aic3262-registers.h
new file mode 100644 (file)
index 0000000..3c26834
--- /dev/null
@@ -0,0 +1,301 @@
+
+#ifndef __MFD_AIC3262_REGISTERS_H__
+#define __MFD_AIC3262_REGISTERS_H__
+/*typedef union aic326x_reg_union {
+       struct aic326x_reg{
+       u8 reserved;
+       u8 book;
+       u8 page;
+       u8 offset;
+       }aic326x_register;
+       unsigned int aic326x_register_int;
+}aic326x_reg_union;*/
+#define MAKE_REG(book, page, offset)   (unsigned int)((book << 16)|(page << 8)|offset)         
+
+/* ****************** Book 0 Registers **************************************/
+
+/* ****************** Page 0 Registers **************************************/
+#define AIC3262_PAGE_SEL_REG           MAKE_REG(0,0,0)
+#define AIC3262_RESET_REG              MAKE_REG(0,0,1)
+#define AIC3262_REV_PG_ID              MAKE_REG(0,0,2)
+#define AIC3262_REV_MASK               (0b01110000)
+#define AIC3262_REV_SHIFT              4       
+#define AIC3262_PG_MASK                        (0b00000111)
+#define AIC3262_PG_SHIFT               0       
+#define AIC3262_DAC_ADC_CLKIN_REG      MAKE_REG(0,0,4)
+#define AIC3262_PLL_CLKIN_REG          MAKE_REG(0,0,5)
+#define AIC3262_PLL_CLKIN_MASK         (0b00111100)
+#define AIC3262_PLL_CLKIN_SHIFT                2       
+#define AIC3262_PLL_CLKIN_MCLK1                0
+#define AIC3262_PLL_CLKIN_BCLK1                1       
+#define AIC3262_PLL_CLKIN_GPIO1                2
+#define AIC3262_PLL_CLKIN_DIN1         3
+#define AIC3262_PLL_CLKIN_BCLK2                4
+#define AIC3262_PLL_CLKIN_GPI1         5
+#define AIC3262_PLL_CLKIN_HF_REF_CLK   6
+#define AIC3262_PLL_CLKIN_GPIO2                7
+#define AIC3262_PLL_CLKIN_GPI2         8
+#define AIC3262_PLL_CLKIN_MCLK2                9
+#define AIC3262_CLK_VAL_MASK           0x7f
+#define AIC3262_PLL_CLK_RANGE_REG      MAKE_REG(0,0,5)
+#define AIC3262_PLL_PR_POW_REG         MAKE_REG(0,0,6)
+#define AIC3262_PLL_PVAL_MASK          0x70
+#define AIC3262_PLL_RVAL_MASK          0x0F
+
+#define AIC3262_ENABLE_CLK_MASK                0x80
+#define AIC3262_ENABLE_CLK             0x80
+
+
+#define AIC3262_PLL_J_REG              MAKE_REG(0,0,7)
+#define AIC3262_JVAL_MASK              0x3f
+#define AIC3262_PLL_D_MSB              MAKE_REG(0,0,8)
+#define AIC3262_DVAL_MSB_MASK          0xf
+#define AIC3262_DVAL_LSB_MASK          0xff
+#define AIC3262_PLL_D_LSB              MAKE_REG(0,0,9)
+#define AIC3262_PLL_CKIN_DIV           MAKE_REG(0,0,10)
+
+#define AIC3262_NDAC_DIV_POW_REG       MAKE_REG(0,0,11)
+#define AIC3262_MDAC_DIV_POW_REG       MAKE_REG(0,0,12)
+#define AIC3262_DOSR_MSB_REG           MAKE_REG(0,0,13)
+#define AIC3262_DOSR_MSB_MASK          0x3
+#define AIC3262_DOSR_LSB_REG           MAKE_REG(0,0,14)
+#define AIC3262_DOSR_LSB_MASK          0xFF
+
+#define AIC3262_NADC_DIV_POW_REG       MAKE_REG(0,0,18)
+#define AIC3262_MADC_DIV_POW_REG       MAKE_REG(0,0,19)
+#define AIC3262_AOSR_REG               MAKE_REG(0,0,20)
+#define AIC3262_CLKOUT_MUX             MAKE_REG(0,0,21)
+#define AIC3262_CLKOUT_MDIV_VAL                MAKE_REG(0,0,22)
+#define AIC3262_TIMER_REG              MAKE_REG(0,0,23)
+
+#define AIC3262_LF_CLK_CNTL            MAKE_REG(0,0,24)
+#define AIC3262_HF_CLK_CNTL_R1         MAKE_REG(0,0,25)
+#define AIC3262_HF_CLK_CNTL_R2         MAKE_REG(0,0,26)
+#define AIC3262_HF_CLK_CNTL_R3         MAKE_REG(0,0,27)
+#define AIC3262_HF_CLK_CNTL_R4         MAKE_REG(0,0,28)
+#define AIC3262_HF_CLK_TRIM_R1         MAKE_REG(0,0,29)
+#define AIC3262_HF_CLK_TRIM_R2         MAKE_REG(0,0,30)
+#define AIC3262_HF_CLK_TRIM_R3         MAKE_REG(0,0,31)
+#define AIC3262_HF_CLK_TRIM_R4         MAKE_REG(0,0,32)
+#define AIC3262_LDAC_POWER_MASK                0x80
+#define AIC3262_RDAC_POWER_MASK                0x08
+#define AIC3262_DAC_FLAG               MAKE_REG(0,0,37)
+#define AIC3262_ADC_FLAG                MAKE_REG(0,0,36)
+#define AIC3262_JACK_WITH_STEREO_HS    (0b00000010)
+#define AIC3262_JACK_WITH_MIC          (0b00110000)    
+#define AIC3262_HEADSET_NOT_INSERTED   (0b00000011)
+
+#define AIC3262_INT_STICKY_FLAG1               MAKE_REG(0,0,42)
+#define AIC3262_LEFT_DAC_OVERFLOW_INT  0x80
+#define AIC3262_RIGHT_DAC_OVERFLOW_INT 0x40
+#define AIC3262_MINIDSP_D_BARREL_SHIFT_OVERFLOW_INT    0x20
+#define AIC3262_LEFT_ADC_OVERFLOW_INT  0x08
+#define AIC3262_RIGHT_ADC_OVERFLOW_INT 0x04
+#define AIC3262_MINIDSP_A_BARREL_SHIFT_OVERFLOW_INT    0x02
+#define AIC3262_INT_STICKY_FLAG2               MAKE_REG(0,0,44)
+#define AIC3262_LEFT_OUTPUT_DRIVER_OVERCURRENT_INT     0x80
+#define AIC3262_RIGHT_OUTPUT_DRIVER_OVERCURRENT_INT    0x40
+#define AIC3262_BUTTON_PRESS_INT                       0x20
+#define AIC3262_HEADSET_PLUG_UNPLUG_INT                        0x10
+#define AIC3262_LEFT_DRC_THRES_INT                     0x08
+#define AIC3262_RIGHT_DRC_THRES_INT                    0x04
+#define AIC3262_MINIDSP_D_STD_INT                      0x02
+#define AIC3262_RIGHT_DRC_AUX_INT                      0x01
+#define AIC3262_INT_STICKY_FLAG3               MAKE_REG(0,0,45)
+#define AIC3262_SPK_OVER_CURRENT_INT           0x80
+#define AIC3262_LEFT_AGC_NOISE_INT                     0x40
+#define AIC3262_RIGHT_AGC_NOISE_INT                    0x20
+#define AIC3262_INT1_CNTL              MAKE_REG(0,0,48)
+#define AIC3262_HEADSET_IN_MASK                0x80
+#define AIC3262_BUTTON_PRESS_MASK      0x40
+#define AIC3262_DAC_DRC_THRES_MASK     0x20
+#define AIC3262_AGC_NOISE_MASK         0x10
+#define AIC3262_OVER_CURRENT_MASK      0x08
+#define AIC3262_OVERFLOW_MASK          0x04
+#define AIC3262_SPK_OVERCURRENT_MASK   0x02
+#define AIC3262_INT2_CNTL              MAKE_REG(0,0,49)
+#define AIC3262_INT_FMT                        MAKE_REG(0,0,51)
+
+#define AIC3262_DAC_PRB                        MAKE_REG(0,0,60)
+#define AIC3262_ADC_PRB                        MAKE_REG(0,0,61)
+#define AIC3262_PASI_DAC_DP_SETUP      MAKE_REG(0,0,63)
+
+#define AIC3262_DAC_MVOL_CONF          MAKE_REG(0,0,64)
+#define AIC3262_DAC_LR_MUTE_MASK       0xc
+#define AIC3262_DAC_LR_MUTE            0xc     
+
+#define AIC3262_DAC_LVOL               MAKE_REG(0,0,65)
+#define AIC3262_DAC_RVOL               MAKE_REG(0,0,66)
+#define AIC3262_HP_DETECT              MAKE_REG(0,0,67)
+#define AIC3262_DRC_CNTL_R1            MAKE_REG(0,0,68)
+#define AIC3262_DRC_CNTL_R2            MAKE_REG(0,0,69)
+#define AIC3262_DRC_CNTL_R3            MAKE_REG(0,0,70)
+#define AIC3262_BEEP_CNTL_R1           MAKE_REG(0,0,71)
+#define AIC3262_BEEP_CNTL_R2           MAKE_REG(0,0,72)
+
+#define AIC3262_ADC_CHANNEL_POW                MAKE_REG(0,0,81)
+#define AIC3262_ADC_FINE_GAIN          MAKE_REG(0,0,82)
+#define AIC3262_LADC_VOL               MAKE_REG(0,0,83)
+#define AIC3262_RADC_VOL               MAKE_REG(0,0,84)
+#define AIC3262_ADC_PHASE              MAKE_REG(0,0,85)
+
+#define AIC3262_LAGC_CNTL              MAKE_REG(0,0,86)
+#define AIC3262_LAGC_CNTL_R2           MAKE_REG(0,0,87)
+#define AIC3262_LAGC_CNTL_R3           MAKE_REG(0,0,88)
+#define AIC3262_LAGC_CNTL_R4           MAKE_REG(0,0,89)
+#define AIC3262_LAGC_CNTL_R5           MAKE_REG(0,0,90)
+#define AIC3262_LAGC_CNTL_R6           MAKE_REG(0,0,91)
+#define AIC3262_LAGC_CNTL_R7           MAKE_REG(0,0,92)
+#define AIC3262_LAGC_CNTL_R8           MAKE_REG(0,0,93)
+
+#define AIC3262_RAGC_CNTL              MAKE_REG(0,0,94)
+#define AIC3262_RAGC_CNTL_R2           MAKE_REG(0,0,95)
+#define AIC3262_RAGC_CNTL_R3           MAKE_REG(0,0,96)
+#define AIC3262_RAGC_CNTL_R4           MAKE_REG(0,0,97)
+#define AIC3262_RAGC_CNTL_R5           MAKE_REG(0,0,98)
+#define AIC3262_RAGC_CNTL_R6           MAKE_REG(0,0,99)
+#define AIC3262_RAGC_CNTL_R7           MAKE_REG(0,0,100)
+#define AIC3262_RAGC_CNTL_R8           MAKE_REG(0,0,101)
+#define AIC3262_MINIDSP_ACCESS_CTRL    MAKE_REG(0,0,121)
+/* ****************** Page 1 Registers **************************************/
+#define AIC3262_PAGE_1                 128
+
+#define AIC3262_POWER_CONF             MAKE_REG(0,1, 1)
+
+#define AIC3262_AVDD_TO_DVDD_MASK      (0b00001000) 
+#define        AIC3262_AVDD_TO_DVDD            0x8
+#define AIC3262_EXT_ANALOG_SUPPLY_MASK (0b00001000) 
+#define        AIC3262_EXT_ANALOG_SUPPLY_OFF   0x4
+
+#define AIC3262_LDAC_PTM               MAKE_REG(0,1, 3)
+#define AIC3262_RDAC_PTM               MAKE_REG(0,1, 4)
+#define AIC3262_CM_REG                         MAKE_REG(0,1, 8)
+#define AIC3262_HP_CTL                         MAKE_REG(0,1, 9)
+#define AIC3262_HP_DEPOP               MAKE_REG(0,1, 11)
+#define AIC3262_RECV_DEPOP             MAKE_REG(0,1, 12)
+#define AIC3262_MA_CNTL                        MAKE_REG(0,1, 17)
+#define AIC3262_LADC_PGA_MAL_VOL       MAKE_REG(0,1, 18)
+#define AIC3262_RADC_PGA_MAR_VOL       MAKE_REG(0,1, 19)
+
+
+#define AIC3262_LINE_AMP_CNTL_R1       MAKE_REG(0,1, 22)
+#define AIC3262_LINE_AMP_CNTL_R2       MAKE_REG(0,1, 23)
+
+#define AIC3262_HP_AMP_CNTL_R1         MAKE_REG(0,1, 27)
+#define AIC3262_HP_AMP_CNTL_R2         MAKE_REG(0,1, 28)
+#define AIC3262_HP_AMP_CNTL_R3         MAKE_REG(0,1, 29)
+
+#define AIC3262_HPL_VOL                        MAKE_REG(0,1, 31)
+#define AIC3262_HPR_VOL                        MAKE_REG(0,1, 32)
+#define AIC3262_INT1_SEL_L             MAKE_REG(0,1, 34)
+#define AIC3262_CHARGE_PUMP_CNTL       MAKE_REG(0,1, 35)
+#define AIC3262_RAMP_CNTL_R1           MAKE_REG(0,1, 36)
+#define AIC3262_RAMP_CNTL_R2           MAKE_REG(0,1, 37)
+#define AIC3262_IN1L_SEL_RM            MAKE_REG(0,1, 38)
+#define AIC3262_IN1R_SEL_RM            MAKE_REG(0,1, 39)
+#define AIC3262_REC_AMP_CNTL_R5                MAKE_REG(0,1, 40)
+#define AIC3262_RAMPR_VOL              MAKE_REG(0,1, 41)
+#define AIC3262_RAMP_TIME_CNTL         MAKE_REG(0,1, 42)
+#define AIC3262_SPK_AMP_CNTL_R1                MAKE_REG(0,1, 45)
+#define AIC3262_SPK_AMP_CNTL_R2                MAKE_REG(0,1, 46)
+#define AIC3262_SPK_AMP_CNTL_R3                MAKE_REG(0,1, 47)
+#define AIC3262_SPK_AMP_CNTL_R4                MAKE_REG(0,1, 48)
+#define AIC3262_MIC_BIAS_CNTL          MAKE_REG(0,1, 51)
+
+#define AIC3262_LMIC_PGA_PIN           MAKE_REG(0,1, 52)
+#define AIC3262_LMIC_PGA_PM_IN4                MAKE_REG(0,1, 53)
+#define AIC3262_LMIC_PGA_MIN           MAKE_REG(0,1, 54)
+#define AIC3262_RMIC_PGA_PIN           MAKE_REG(0,1, 55)
+#define AIC3262_RMIC_PGA_PM_IN4                MAKE_REG(0,1, 56)
+#define AIC3262_RMIC_PGA_MIN           MAKE_REG(0,1, 57)
+#define AIC3262_HP_FLAG                        MAKE_REG(0,1,66)
+#define AIC3262_SPKL_POWER_MASK                0x2
+#define AIC3262_SPKR_POWER_MASK                0x1
+#define AIC3262_HPL_POWER_MASK         0x20
+#define AIC3262_HPR_POWER_MASK         0x10
+/* MIC PGA Gain Registers */
+#define AIC3262_MICL_PGA               MAKE_REG(0,1, 59)
+#define AIC3262_MICR_PGA               MAKE_REG(0,1, 60)
+#define AIC3262_HEADSET_TUNING1_REG    MAKE_REG(0,1, 119)
+#define AIC3262_HEADSET_DETECTOR_PULSE_MASK (0b11000000)
+#define AIC3262_HEADSET_DETECTOR_PULSE_RESET (0B10000000)
+#define AIC3262_MIC_PWR_DLY            MAKE_REG(0,1, 121)
+#define AIC3262_REF_PWR_DLY            MAKE_REG(0,1, 122)
+#define AIC3262_CHIP_REF_PWR_ON_MASK   0x4 
+#define AIC3262_CHIP_REF_PWR_ON                0x4
+/* ****************** Page 4 Registers **************************************/
+#define AIC3262_PAGE_4                 512
+#define AIC3262_ASI1_BUS_FMT           MAKE_REG(0,4, 1)
+#define AIC3262_ASI_SELECTION_MASK     (0b1100000)
+#define AIC3262_ASI_DATA_WORD_LENGTH_MASK      (0b0011000)
+#define AIC3262_ASI_BCLK_N_MASK                (0b01111111)
+#define AIC3262_ASI1_LCH_OFFSET                MAKE_REG(0,4, 2)
+#define AIC3262_ASI1_RCH_OFFSET                MAKE_REG(0,4, 3)
+#define AIC3262_ASI1_CHNL_SETUP                MAKE_REG(0,4, 4)
+#define AIC3262_ASI1_MULTI_CH_SETUP_R1 MAKE_REG(0,4, 5)
+#define AIC3262_ASI1_MULTI_CH_SETUP_R2 MAKE_REG(0,4, 6)
+#define AIC3262_ASI1_ADC_INPUT_CNTL    MAKE_REG(0,4, 7)
+#define AIC3262_ASI1_DAC_OUT_CNTL      MAKE_REG(0,4, 8)
+#define AIC3262_ASI1_ADC_OUT_TRISTATE  MAKE_REG(0,4, 9)
+#define AIC3262_ASI1_BWCLK_CNTL_REG    MAKE_REG(0,4, 10)
+#define AIC3262_ASI1_BCLK_N_CNTL       MAKE_REG(0,4, 11)
+#define AIC3262_ASI1_BCLK_N            MAKE_REG(0,4, 12)
+#define AIC3262_ASI1_WCLK_N            MAKE_REG(0,4, 13)
+#define AIC3262_ASI1_BWCLK_OUT_CNTL    MAKE_REG(0,4, 14)
+#define AIC3262_ASI1_DOUT_CNTL         MAKE_REG(0,4, 15)
+#define AIC3262_ASI2_BUS_FMT           MAKE_REG(0,4, 17)
+#define AIC3262_ASI2_LCH_OFFSET                MAKE_REG(0,4, 18)
+#define AIC3262_ASI2_ADC_INPUT_CNTL    MAKE_REG(0,4, 23)
+#define AIC3262_ASI2_DAC_OUT_CNTL      MAKE_REG(0,4, 24)
+#define AIC3262_ASI2_BWCLK_CNTL_REG    MAKE_REG(0,4, 26)
+#define AIC3262_ASI2_BCLK_N_CNTL       MAKE_REG(0,4, 27)
+#define AIC3262_ASI2_BCLK_N            MAKE_REG(0,4, 28)
+#define AIC3262_ASI2_WCLK_N            MAKE_REG(0,4, 29)
+#define AIC3262_ASI2_BWCLK_OUT_CNTL    MAKE_REG(0,4, 30)
+#define AIC3262_ASI2_DOUT_CNTL         MAKE_REG(0,4, 31)
+#define AIC3262_ASI3_BUS_FMT           MAKE_REG(0,4, 33)
+#define AIC3262_ASI3_LCH_OFFSET                MAKE_REG(0,4, 34)
+#define AIC3262_ASI3_ADC_INPUT_CNTL    MAKE_REG(0,4, 39)
+#define AIC3262_ASI3_DAC_OUT_CNTL      MAKE_REG(0,4, 40)
+#define AIC3262_ASI3_BWCLK_CNTL_REG    MAKE_REG(0,4, 42)
+#define AIC3262_ASI3_BCLK_N_CNTL       MAKE_REG(0,4, 43)
+#define AIC3262_ASI3_BCLK_N            MAKE_REG(0,4, 44)
+#define AIC3262_ASI3_WCLK_N            MAKE_REG(0,4, 45)
+#define AIC3262_ASI3_BWCLK_OUT_CNTL    MAKE_REG(0,4, 46)
+#define AIC3262_ASI3_DOUT_CNTL         MAKE_REG(0,4, 47)
+#define AIC3262_DMIC_INPUT_CNTL                MAKE_REG(0,4, 101)
+#define AIC3262_GPIO1_IO_CNTL          MAKE_REG(0,4, 86)
+#define AIC3262_GPIO_D6_D2             (0b01111100)    
+#define AIC3262_GPIO_D2_SHIFT          (2)
+#define AIC3262_GPIO_D1_SHIFT          (1)
+#define AIC3262_GPIO_D4_SHIFT          (4)
+#define AIC3262_GPIO2_IO_CNTL          MAKE_REG(0,4, 87)
+#define AIC3262_GPI1_EN                        MAKE_REG(0,4, 91)
+#define AIC3262_GPI1_D2_D1             (0b00000110)    
+#define AIC3262_GPI2_D5_D4             (0b00110000)    
+#define AIC3262_GPI2_EN                        MAKE_REG(0, 4, 92)
+#define AIC3262_GPO1_OUT_CNTL          MAKE_REG(0, 4, 96)
+#define AIC3262_GPO1_D4_D1             (0b00011110)    
+#define AIC3262_DMIC_INPUT_CONTROL     MAKE_REG(0, 4, 101)
+#define AIC3262_DMIC_CONFIGURE_MASK    (0b00011111)
+#define AIC3262_DMIC_CONFIGURE_SHIFT   (0)
+#define AIC3262_MINIDSP_DATA_PORT_CNTL MAKE_REG(0, 4, 118)
+
+#define AIC3262_DAC_ASI_LR_UNMUTE_MASK 0x50
+#define AIC3262_DAC_ASI_LR_UNMUTE      0x50    
+#define AIC3262_WCLK_BCLK_MASTER_MASK (0b00100110)
+#define AIC3262_WCLK_MASTER_MASK (0b00100000)
+#define AIC3262_BCLK_MASTER_MASK (0b00000100)
+#define AIC3262_BCLK_OFFSET_MASK (0b11111111)
+#define AIC3262_ASI_INTERFACE_MASK (0b11100000)
+#define AIC3262_WCLK_OUT_MASK (0b00100000)
+#define AIC3262_BCLK_OUT_MASK (0b00000100)
+#define AIC3262_BCLK_INV_MASK (0b00000010)
+
+#define AIC3262_ADC_ADAPTIVE_CRAM_REG    MAKE_REG(40,0,1)
+#define AIC3262_DAC_ADAPTIVE_BANK1_REG   MAKE_REG(80,0,1)
+#define AIC3262_DAC_ADAPTIVE_BANK2_REG   MAKE_REG(82,0,1)
+#define AIC3262_ADC_DATAPATH_SETUP      MAKE_REG(0,0,81)
+#define AIC3262_DAC_DATAPATH_SETUP      MAKE_REG(0,0,63)
+
+#endif
index 594a1662839fdc351af19091d6321e15ed94754c..ab6dbb51b7c24ffb767949f8b348375851786ca8 100644 (file)
@@ -247,6 +247,9 @@ config SND_SOC_TLV320DAC33
 config SND_SOC_TLV320AIC3111
        tristate
 
+config SND_SOC_TLV320AIC326X
+       tristate
+
 config SND_SOC_TWL4030
        select TWL4030_CODEC
        tristate
index 3720639b5912c2b674e89cb0e787b5c9b92ea7ac..ea82f0d8e08e2dfb74d01c5c4a9d83cdc303430d 100644 (file)
@@ -35,6 +35,7 @@ snd-soc-tlv320aic3x-objs := tlv320aic3x.o
 snd-soc-tlv320aic32x4-objs := tlv320aic32x4.o
 snd-soc-tlv320aic3111-objs := tlv320aic3111.o
 snd-soc-tlv320dac33-objs := tlv320dac33.o
+snd-soc-tlv320aic326x-objs := tlv320aic326x.o aic326x_tiload.o aic3xxx_cfw_ops.o aic3262_codec_ops.o
 snd-soc-twl4030-objs := twl4030.o
 snd-soc-twl6040-objs := twl6040.o
 snd-soc-uda134x-objs := uda134x.o
@@ -134,6 +135,7 @@ obj-$(CONFIG_SND_SOC_TLV320AIC3X)   += snd-soc-tlv320aic3x.o
 obj-$(CONFIG_SND_SOC_TVL320AIC32X4)     += snd-soc-tlv320aic32x4.o
 obj-$(CONFIG_SND_SOC_TLV320AIC3111)    += snd-soc-tlv320aic3111.o
 obj-$(CONFIG_SND_SOC_TLV320DAC33)      += snd-soc-tlv320dac33.o
+obj-$(CONFIG_SND_SOC_TLV320AIC326X)    += snd-soc-tlv320aic326x.o
 obj-$(CONFIG_SND_SOC_TWL4030)  += snd-soc-twl4030.o
 obj-$(CONFIG_SND_SOC_TWL6040)  += snd-soc-twl6040.o
 obj-$(CONFIG_SND_SOC_UDA134X)  += snd-soc-uda134x.o
diff --git a/sound/soc/codecs/aic3262_codec_ops.c b/sound/soc/codecs/aic3262_codec_ops.c
new file mode 100644 (file)
index 0000000..c948303
--- /dev/null
@@ -0,0 +1,407 @@
+#include "aic3xxx_cfw.h"
+#include "aic3xxx_cfw_ops.h"
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/mfd/tlv320aic3262-core.h>
+#include <linux/mfd/tlv320aic3262-registers.h>
+#include "tlv320aic326x.h"
+#include <sound/soc.h>
+#include "aic3262_codec_ops.h"
+
+#define DSP_STATUS(rs,adc_dac,rpos,rspos)  rs |= ( ((adc_dac>>rpos) & 1) << rspos) 
+
+
+
+int aic3262_ops_reg_read(void *p,unsigned int reg)
+{
+       struct aic3262_priv *ps = p;
+        cfw_register *c = (cfw_register *) &reg;
+       aic326x_reg_union mreg;
+       
+               mreg.aic326x_register.offset = c->offset;
+               mreg.aic326x_register.page = c->page;
+               mreg.aic326x_register.book = c->book;
+               mreg.aic326x_register.reserved = 0;
+       
+               return aic3262_reg_read(ps->codec->control_data,
+                                       mreg.aic326x_register_int);
+       
+}
+int aic3262_ops_reg_write(void  *p,unsigned int reg,unsigned char mval)
+{
+               struct aic3262_priv *ps = p;
+               aic326x_reg_union mreg;
+        cfw_register *c = (cfw_register *) &reg;
+
+               mreg.aic326x_register.offset = c->offset;
+               mreg.aic326x_register.page = c->page;
+               mreg.aic326x_register.book = c->book;
+               mreg.aic326x_register.reserved = 0;
+               mval = c->data;
+               DBG("reg_write:page %d book %d offset %d mval : %#x\n",mreg.aic326x_register.page,mreg.aic326x_register.book,mreg.aic326x_register.offset,mval);
+
+               return aic3262_reg_write(ps->codec->control_data, mreg.aic326x_register_int, mval);
+}
+
+int aic3262_ops_set_bits(void *p,unsigned int reg,
+               unsigned char mask, unsigned char val)
+{
+       struct aic3262_priv *ps = p;
+
+       aic326x_reg_union mreg;
+       cfw_register *c = (cfw_register *) &reg;
+       mreg.aic326x_register.offset = c->offset;
+       mreg.aic326x_register.page = c->page;
+       mreg.aic326x_register.book = c->book;
+       mreg.aic326x_register.reserved = 0;
+       DBG("set_bits:page %d book %d offset %d mask %#x val %#x\n",mreg.aic326x_register.page,mreg.aic326x_register.book,mreg.aic326x_register.offset,mask,val);
+
+       return aic3262_set_bits(ps->codec->control_data,mreg.aic326x_register_int,mask,val); 
+
+}
+int aic3262_ops_bulk_read(void *p,unsigned int reg,int count, u8 *buf)
+{
+       struct aic3262_priv  *ps = p;
+
+       aic326x_reg_union mreg;
+       cfw_register *c = (cfw_register *) &reg;
+       mreg.aic326x_register.offset = c->offset;
+       mreg.aic326x_register.page = c->page;
+       mreg.aic326x_register.book = c->book;
+       mreg.aic326x_register.reserved = 0;
+
+       return aic3262_bulk_read(ps->codec->control_data,mreg.aic326x_register_int,count,buf);
+}
+
+int aic3262_ops_bulk_write(void *p,unsigned int reg ,int count, const u8 *buf)
+{
+       struct aic3262_priv *ps = p;
+       aic326x_reg_union mreg;
+       cfw_register *c = (cfw_register *) &reg;
+
+       mreg.aic326x_register.offset = c->offset;
+       mreg.aic326x_register.page = c->page;
+       mreg.aic326x_register.book = c->book;
+       mreg.aic326x_register.reserved = 0;
+       DBG("bulk_write: ncmd %d page %d book %d offset %d data[0] %d\n",count,mreg.aic326x_register.page,mreg.aic326x_register.book,mreg.aic326x_register.offset,buf[0]);
+
+       aic3262_bulk_write(ps->codec->control_data,mreg.aic326x_register_int,count,buf);
+       return 0;
+}
+/*****************************************************************************
+  Function Name : aic3262_ops_dlock_lock
+Argument      : pointer argument to the codec
+Return value  : Integer 
+Purpose              : To Read the run state of the DAC and ADC
+by reading the codec and returning the run state 
+
+Run state Bit format
+
+------------------------------------------------------
+D31|..........| D7 | D6|  D5  |  D4  | D3 | D2 | D1  |   D0  |
+R               R    R   LADC   RADC    R    R   LDAC   RDAC
+------------------------------------------------------
+
+ *******************************************************************************/
+
+int aic3262_ops_lock(void *pv)
+{
+       int run_state=0;
+       struct aic3262_priv *aic3262 = (struct aic3262_priv *) pv;
+       mutex_lock(&aic3262->codec->mutex);
+
+       /* Reading the run state of adc and dac */
+       run_state = get_runstate(aic3262->codec->control_data); 
+
+       return run_state;       
+}
+/********************************************************************************
+  Function name        : aic3262_ops_dlock_unlock
+Argument       : pointer argument to the codec
+Return Value   : integer returning 0
+Purpose                : To unlock the mutex acqiured for reading 
+run state of the codec 
+ *********************************************************************************/
+int aic3262_ops_unlock(void *pv)
+{
+       /*Releasing the lock of mutex */
+       struct aic3262_priv *aic3262 = (struct aic3262_priv *) pv;
+
+       mutex_unlock(&aic3262->codec->mutex);
+       return 0;
+}
+/*********************************************************************************
+  Function Name        : aic3262_ops_dlock_stop
+Argument       : pointer Argument to the codec
+mask tells us the bit format of the
+codec running state
+
+Bit Format:
+------------------------------------------------------
+D31|..........| D7 | D6| D5 | D4 | D3 | D2 | D1 | D0 |
+R               R    R   AL   AR    R    R   DL   DR
+------------------------------------------------------
+R  - Reserved
+A  - minidsp_A
+D  - minidsp_D
+ ***********************************************************************************/
+
+
+
+int aic3262_ops_stop (void *pv, int mask)
+{
+       int     run_state=0;
+       int     cur_state=0;
+       int     count = 100;
+       struct aic3262_priv *aic3262 = (struct aic3262_priv *) pv;
+       int     limask=0;       
+
+       mutex_lock(&aic3262->codec->mutex);
+       run_state = get_runstate(aic3262->codec->control_data); 
+
+       if ( ( limask=(mask & AIC3XX_COPS_MDSP_A) ) )
+       {
+               if((limask & 0x30) == 0x30)   //Both ADC's  needs to switchoff
+                       aic3262_set_bits(aic3262->codec->control_data,AIC3262_ADC_DATAPATH_SETUP,0xC0,0);  
+               else
+               {
+                       if(limask & 0x10)   //Right ADC is on, we need to switchoff
+                               aic3262_set_bits(aic3262->codec->control_data,AIC3262_ADC_DATAPATH_SETUP,0x40,0);  
+
+                       if(limask & 0x20) // Left ADC is on , we need to switchoff
+                               aic3262_set_bits(aic3262->codec->control_data,AIC3262_ADC_DATAPATH_SETUP,0x80,0);  
+               }
+
+       }
+
+       if( ( limask= (mask & AIC3XX_COPS_MDSP_D) ) )
+       {
+               if( (limask & 0x03)== 0x03 )
+               {
+                       aic3262_set_bits(aic3262->codec->control_data,AIC3262_DAC_DATAPATH_SETUP,0xC0,0);
+               }
+               else
+               {
+                       if(limask & 0x01)
+                               aic3262_set_bits(aic3262->codec->control_data,AIC3262_DAC_DATAPATH_SETUP,0x40,0);
+
+                       if(limask & 0x02)
+                               aic3262_set_bits(aic3262->codec->control_data,AIC3262_DAC_DATAPATH_SETUP,0x80,0);
+               }
+       }
+       // waiting for write to complete
+
+       do
+       {
+               cur_state = get_runstate(aic3262->codec->control_data);
+               count--;
+       }while( ( (cur_state&mask&AIC3XX_COPS_MDSP_A)  || (cur_state&mask&AIC3XX_COPS_MDSP_D) )  && count );   
+
+       return run_state;
+
+}
+/*****************************************************************************
+  Function name        : aic3262_ops_dlock_restore
+Argument       : pointer argument to the codec,run_state 
+Return Value   : integer returning 0
+Purpose                : To unlock the mutex acqiured for reading 
+run state of the codec and to restore the states of the dsp 
+ *******************************************************************************/
+int aic3262_ops_restore(void *pv, int run_state)
+{
+       int     sync_state = 0;
+       int     li_cur_state = 0;
+       struct aic3262_priv *aic3262 = (struct aic3262_priv *)pv;       
+       /*      This is for read the sync mode register state  */
+       sync_state = SYNC_STATE(aic3262);
+       /*      Reading the current dsp state                   */
+       li_cur_state = get_runstate(aic3262->codec->control_data);
+
+
+       //checking whether the sync mode has been set or not and checking the current state 
+       if( ((run_state & 0x30) && (run_state & 0x03)) && (sync_state & 0x80) )
+               aic3262_restart_dsps_sync(pv,run_state);
+       else
+               aic3262_dsp_pwrup(pv,run_state);
+
+
+       mutex_unlock(&aic3262->codec->mutex);
+
+       return 0;
+}
+
+/*****************************************************************************
+  Function name   : aic3262_ops_adaptivebuffer_swap
+Argument        : pointer argument to the codec,mask tells us which dsp has to
+be chosen for swapping 
+Return Value    : integer returning 0
+Purpose         : To swap the coefficient buffers of minidsp according to mask 
+ *******************************************************************************/
+
+int aic3262_ops_adaptivebuffer_swap(void *pv,int mask)
+{
+       int read_state=0;
+       struct aic3262_priv *aic3262 = (struct aic3262_priv *) pv;
+
+       if(mask & AIC3XX_ABUF_MDSP_A)
+       {
+
+               int count=0;
+               aic3262_set_bits(aic3262->codec->control_data,AIC3262_ADC_ADAPTIVE_CRAM_REG,0x1,0x1);
+
+               do
+               {
+                       read_state = aic3262_reg_read(aic3262->codec->control_data,AIC3262_ADC_ADAPTIVE_CRAM_REG);
+                       count++;
+               }while( (read_state & 0x1) && (count <= 60) );
+       }
+
+       if(mask & AIC3XX_ABUF_MDSP_D1)
+       {
+
+               int count=0;
+
+               aic3262_set_bits(aic3262->codec->control_data,AIC3262_DAC_ADAPTIVE_BANK1_REG,0x1,0x1);
+               do
+               {
+                       read_state = aic3262_reg_read(aic3262->codec->control_data, AIC3262_DAC_ADAPTIVE_BANK1_REG );
+                       count++;
+               }while( (read_state & 0x1) && (count <= 60) );
+       }
+
+       if(mask & AIC3XX_ABUF_MDSP_D2)
+       {
+
+               int count=0;
+               aic3262_set_bits(aic3262->codec->control_data,AIC3262_DAC_ADAPTIVE_BANK2_REG,0x1,0x1);
+               do
+               {
+                       read_state = aic3262_reg_read(aic3262->codec->control_data,AIC3262_DAC_ADAPTIVE_BANK2_REG);
+                       count++;
+               }while( (read_state & 0x1) && (count <= 60) );
+       }
+
+       return 0;
+}
+/*****************************************************************************
+  Function name        : get_runstate
+Argument       : pointer argument to the codec 
+Return Value   : integer returning the runstate
+Purpose                : To read the current state of the dac's and adc's 
+ *******************************************************************************/
+
+int get_runstate(void *ps)
+{
+       struct aic3262 *pr = ps;        
+       int run_state=0;
+       int DAC_state=0,ADC_state=0;
+       /* Read the run state */
+       DAC_state = aic3262_reg_read(pr,AIC3262_DAC_FLAG);
+       ADC_state = aic3262_reg_read(pr,AIC3262_ADC_FLAG);
+
+       DSP_STATUS(run_state,ADC_state,6,5);
+       DSP_STATUS(run_state,ADC_state,2,4);
+       DSP_STATUS(run_state,DAC_state,7,1);
+       DSP_STATUS(run_state,DAC_state,3,0);
+
+       return run_state;
+
+}
+/*****************************************************************************
+  Function name        : aic3262_dsp_pwrdwn_status
+Argument       : pointer argument to the codec , cur_state of dac's and adc's 
+Return Value   : integer returning 0
+Purpose                : To read the status of dsp's 
+ *******************************************************************************/
+
+int aic3262_dsp_pwrdwn_status(
+               void *pv  //ptr to the priv data structure
+               )
+{
+       struct aic3262_priv *aic3262 = pv;
+       int count = 100;
+       int cur_state = 0;
+
+       aic3262_set_bits(aic3262->codec->control_data,AIC3262_ADC_DATAPATH_SETUP,0XC0,0);
+       aic3262_set_bits(aic3262->codec->control_data,AIC3262_DAC_DATAPATH_SETUP,0XC0,0);
+
+       do
+       {
+               cur_state = get_runstate(aic3262->codec->control_data);
+       }while(cur_state && count--);
+
+
+       return 0;
+}
+int aic3262_dsp_pwrup(void *pv,int state)
+{
+       int cur_state = 0;
+       int count =100;
+       struct aic3262_priv *aic3262  = (struct aic3262_priv *)pv;
+
+       if(state & AIC3262_COPS_MDSP_A) 
+               aic3262_set_bits(aic3262->codec->control_data,AIC3262_ADC_DATAPATH_SETUP,0XC0,0xC0);
+       else
+       {
+               if(state & AIC3262_COPS_MDSP_A_L)
+                       aic3262_set_bits(aic3262->codec->control_data,AIC3262_ADC_DATAPATH_SETUP,0x80,0x80);
+               if(state & AIC3262_COPS_MDSP_A_R)
+                       aic3262_set_bits(aic3262->codec->control_data,AIC3262_ADC_DATAPATH_SETUP,0x40,0x40);
+       }
+
+
+       if(state & AIC3262_COPS_MDSP_D) 
+               aic3262_set_bits(aic3262->codec->control_data,AIC3262_DAC_DATAPATH_SETUP,0XC0,0xC0);
+       else
+       {
+               if(state & AIC3262_COPS_MDSP_D_L)
+                       aic3262_set_bits(aic3262->codec->control_data,AIC3262_DAC_DATAPATH_SETUP,0x80,0x80);
+               if(state & AIC3262_COPS_MDSP_D_R)
+                       aic3262_set_bits(aic3262->codec->control_data,AIC3262_DAC_DATAPATH_SETUP,0x40,0x40);
+       }
+
+       //loop for waiting for the dsps to power up together
+       do
+       {
+               cur_state = get_runstate(aic3262->codec->control_data);
+       }while ((state == cur_state ) && count--);
+
+       return 0;
+}
+
+int aic3262_restart_dsps_sync(void *pv,int run_state)
+{
+
+       aic3262_dsp_pwrdwn_status(pv);
+       //specific command sequence to be added later
+       /*
+          ....................
+          ....................
+          ....................
+        */
+
+       aic3262_dsp_pwrup(pv,run_state);         
+
+       //specific commands to be added later
+       /*
+          ....................
+          ....................
+          ....................
+        */
+       return 0;
+}
+
+const aic3xxx_codec_ops aic3262_cfw_codec_ops = {
+       .reg_read       =       aic3262_ops_reg_read,
+       .reg_write      =       aic3262_ops_reg_write,                         
+       .set_bits       =       aic3262_ops_set_bits,                          
+       .bulk_read      =       aic3262_ops_bulk_read,                         
+       .bulk_write     =       aic3262_ops_bulk_write,                        
+       .lock   =       aic3262_ops_lock,                   
+       .unlock =       aic3262_ops_unlock,                 
+       .stop   =       aic3262_ops_stop ,                  
+       .restore        =       aic3262_ops_restore,                
+       .bswap  =       aic3262_ops_adaptivebuffer_swap,          
+};                                    
+
+
diff --git a/sound/soc/codecs/aic3262_codec_ops.h b/sound/soc/codecs/aic3262_codec_ops.h
new file mode 100644 (file)
index 0000000..54d835b
--- /dev/null
@@ -0,0 +1,42 @@
+#define SYNC_STATE(p) aic3262_reg_read(p->codec->control_data,AIC3262_DAC_PRB)
+
+#define AIC3262_COPS_MDSP_A    0x30
+#define AIC3262_COPS_MDSP_A_L  0x20
+#define AIC3262_COPS_MDSP_A_R  0x10
+
+
+
+#define AIC3262_COPS_MDSP_D    0x03
+#define AIC3262_COPS_MDSP_D_L  0x02
+#define AIC3262_COPS_MDSP_D_R  0x01
+
+
+int get_runstate(void *);
+
+int aic3262_dsp_pwrup(void *,int);
+
+int aic3262_pwr_down(void *,int ,int ,int ,int);
+
+int aic3262_dsp_pwrdwn_status(void *);
+
+int aic3262_ops_reg_read(void *p,unsigned int reg);
+
+int aic3262_ops_reg_write(void  *p,unsigned int reg,unsigned char mval);
+
+int aic3262_ops_set_bits(void *p,unsigned int reg,unsigned char mask, unsigned char val);
+
+int aic3262_ops_bulk_read(void *p,unsigned int reg,int count, u8 *buf);
+
+int aic3262_ops_bulk_write(void *p, unsigned int reg,int count, const u8 *buf);
+
+int aic3262_ops_lock(void *pv);
+
+int aic3262_ops_unlock(void *pv);
+
+int aic3262_ops_stop (void *pv, int mask);
+
+int aic3262_ops_restore(void *pv, int run_state);
+
+int aic3262_ops_adaptivebuffer_swap(void *pv,int mask);
+
+int aic3262_restart_dsps_sync(void *pv,int run_state);
diff --git a/sound/soc/codecs/aic326x_tiload.c b/sound/soc/codecs/aic326x_tiload.c
new file mode 100644 (file)
index 0000000..df1581e
--- /dev/null
@@ -0,0 +1,349 @@
+/*
+ * linux/sound/soc/codecs/AIC3262_tiload.c
+ *
+ *
+ * Copyright (C) 2010 Texas Instruments, Inc.
+ *
+ *
+ *
+ * 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      Tiload support                 TI         16-09-2010
+ *
+ *          The Tiload programming support is added to AIC3262.
+ *
+ */
+
+#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 <asm/io.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/platform_device.h>
+#include <sound/soc.h>
+#include <sound/control.h>
+#include <linux/switch.h>
+#include <sound/jack.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+
+#include <linux/mfd/tlv320aic3262-core.h>
+#include "tlv320aic326x.h"
+#include "aic326x_tiload.h"
+
+/* enable debug prints in the driver */
+//#define DEBUG
+#undef DEBUG
+
+#ifdef DEBUG
+#define dprintk(x...)  printk(x)
+#else
+#define dprintk(x...)
+#endif
+
+#ifdef AIC3262_TiLoad
+
+/* Function prototypes */
+#ifdef REG_DUMP_aic3262
+static void aic3262_dump_page(struct i2c_client *i2c, u8 page);
+#endif
+
+/* externs */
+/*extern int aic3262_change_page(struct snd_soc_codec *codec, u8 new_page);
+extern int aic3262_change_book(struct snd_soc_codec *codec, u8 new_book);*/
+extern int aic3262_write(struct snd_soc_codec *codec, unsigned int reg,
+                        unsigned int value);
+
+int aic3262_driver_init(struct snd_soc_codec *codec);
+/************** Dynamic aic3262 driver, TI LOAD support  ***************/
+
+static struct cdev *aic3262_cdev;
+static aic326x_reg_union aic_reg;
+static int aic3262_major = 0;  /* Dynamic allocation of Mjr No. */
+static int aic3262_opened = 0; /* Dynamic allocation of Mjr No. */
+static struct snd_soc_codec *aic3262_codec;
+struct class *tiload_class;
+static unsigned int magic_num = 0xE0;
+
+/******************************** Debug section *****************************/
+
+#ifdef REG_DUMP_aic3262
+/*
+ *----------------------------------------------------------------------------
+ * 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[8];
+
+       dprintk("TiLoad DRIVER : %s\n", __FUNCTION__);
+//     aic3262_change_page(codec, page);
+
+       data = 0x0;
+
+       i2c_master_send(i2c, data, 1);
+       i2c_master_recv(i2c, test_page_array, 8);
+
+       dprintk("\n------- aic3262 PAGE %d DUMP --------\n", page);
+       for (i = 0; i < 8; i++) {
+               printk(" [ %d ] = 0x%x\n", i, test_page_array[i]);
+       }
+}
+#endif
+
+/*
+ *----------------------------------------------------------------------------
+ * Function : tiload_open
+ *
+ * Purpose  : open method for aic3262-tiload programming interface
+ *----------------------------------------------------------------------------
+ */
+static int tiload_open(struct inode *in, struct file *filp)
+{
+       dprintk("TiLoad DRIVER : %s\n", __FUNCTION__);
+       if (aic3262_opened) {
+               dprintk("%s device is already opened\n", "aic3262");
+               dprintk("%s: only one instance of driver is allowed\n",
+                      "aic3262");
+               return -1;
+       }
+       aic3262_opened++;
+       return 0;
+}
+
+/*
+ *----------------------------------------------------------------------------
+ * Function : tiload_release
+ *
+ * Purpose  : close method for aic3262_tilaod programming interface
+ *----------------------------------------------------------------------------
+ */
+static int tiload_release(struct inode *in, struct file *filp)
+{
+       dprintk("TiLoad DRIVER : %s\n", __FUNCTION__);
+       aic3262_opened--;
+       return 0;
+}
+
+/*
+ *----------------------------------------------------------------------------
+ * Function : tiload_read
+ *
+ * Purpose  : read method for mini dsp programming interface
+ *----------------------------------------------------------------------------
+ */
+static ssize_t tiload_read(struct file *file, char __user * buf,
+                          size_t count, loff_t * offset)
+{
+       static char rd_data[8];
+       char reg_addr;
+       size_t size;
+       #ifdef DEBUG
+       int i;
+       #endif
+       struct aic3262 *control = aic3262_codec->control_data;
+
+       dprintk("TiLoad DRIVER : %s\n", __FUNCTION__);
+       if (count > 128) {
+               printk("Max 128 bytes can be read\n");
+               count = 128;
+       }
+
+       /* copy register address from user space  */
+       size = copy_from_user(&reg_addr, buf, 1);
+       if (size != 0) {
+               printk("read: copy_from_user failure\n");
+               return -1;
+       }
+       /* Send the address to device thats is to be read */
+       
+       aic_reg.aic326x_register.offset = reg_addr;
+       size = aic3262_bulk_read(control, aic_reg.aic326x_register_int, count, rd_data);
+/*
+       if (i2c_master_send(i2c, &reg_addr, 1) != 1) {
+               dprintk("Can not write register address\n");
+               return -1;
+       }
+       size = i2c_master_recv(i2c, rd_data, count);
+*/
+#ifdef DEBUG
+       printk(KERN_ERR "read size = %d, reg_addr= %x , count = %d\n",
+              (int)size, reg_addr, (int)count);
+       for (i = 0; i < (int)size; i++) {
+               dprintk(KERN_ERR "rd_data[%d]=%x\n", i, rd_data[i]);
+       }
+#endif
+       if (size != count) {
+               dprintk("read %d registers from the codec\n", size);
+       }
+
+       if (copy_to_user(buf, rd_data, size) != 0) {
+               dprintk("copy_to_user failed\n");
+               return -1;
+       }
+
+       return size;
+}
+
+/*
+ *----------------------------------------------------------------------------
+ * Function : tiload_write
+ *
+ * Purpose  : write method for aic3262_tiload programming interface
+ *----------------------------------------------------------------------------
+ */
+static ssize_t tiload_write(struct file *file, const char __user * buf,
+                           size_t count, loff_t * offset)
+{
+       static char wr_data[8];
+       u8 pg_no;
+       unsigned int reg;
+       #ifdef DEBUG
+       int i;
+       #endif
+       struct aic3262 *control = aic3262_codec->control_data;
+
+       dprintk("TiLoad DRIVER : %s\n", __FUNCTION__);
+       /* copy buffer from user space  */
+       if (copy_from_user(wr_data, buf, count)) {
+               printk("copy_from_user failure\n");
+               return -1;
+       }
+#ifdef DEBUG
+       dprintk(KERN_ERR "write size = %d\n", (int)count);
+       for (i = 0; i < (int)count; i++) {
+               printk(KERN_INFO "\nwr_data[%d]=%x\n", i, wr_data[i]);
+       }
+#endif
+       if(wr_data[0] == 0)
+       {
+               //change of page seen, but will only be registered              
+               aic_reg.aic326x_register.page = wr_data[1];
+               return count;// trick
+               
+       }       
+       else
+       if(wr_data[0] == 127 /* && aic_reg.aic326x_register.page == 0*/) 
+       {       
+               //change of book seen, but will not be sent for I2C write
+               aic_reg.aic326x_register.book = wr_data[1];
+               return count; //trick
+                
+       }
+       else
+       { 
+               aic_reg.aic326x_register.offset = wr_data[0];   
+               aic3262_bulk_write(control, aic_reg.aic326x_register_int, count - 1,&wr_data[1]); 
+               return count;
+       }
+/*     if (wr_data[0] == 0) {
+               aic3262_change_page(aic3262_codec, wr_data[1]);
+               return count;
+       }
+       pg_no = aic3262_private->page_no;
+
+       if ((wr_data[0] == 127) && (pg_no == 0)) {
+               aic3262_change_book(aic3262_codec, wr_data[1]);
+               return count;
+       }
+       return i2c_master_send(i2c, wr_data, count);*/
+       
+}
+
+static int tiload_ioctl(struct file *filp,
+                       unsigned int cmd, unsigned long arg)
+{
+       int num = 0;
+       void __user *argp = (void __user *)arg;
+       if (_IOC_TYPE(cmd) != aic3262_IOC_MAGIC)
+               return -ENOTTY;
+
+       dprintk("TiLoad DRIVER : %s\n", __FUNCTION__);
+       switch (cmd) {
+       case aic3262_IOMAGICNUM_GET:
+               num = copy_to_user(argp, &magic_num, sizeof(int));
+               break;
+       case aic3262_IOMAGICNUM_SET:
+               num = copy_from_user(&magic_num, argp, sizeof(int));
+               break;
+       }
+       return num;
+}
+
+/*********** File operations structure for aic3262-tiload programming *************/
+static struct file_operations aic3262_fops = {
+       .owner = THIS_MODULE,
+       .open = tiload_open,
+       .release = tiload_release,
+       .read = tiload_read,
+       .write = tiload_write,
+       .unlocked_ioctl = tiload_ioctl,
+};
+
+/*
+ *----------------------------------------------------------------------------
+ * Function : aic3262_driver_init
+ *
+ * Purpose  : Register a char driver for dynamic aic3262-tiload programming
+ *----------------------------------------------------------------------------
+ */
+int aic3262_driver_init(struct snd_soc_codec *codec)
+{
+       int result;
+
+       dev_t dev = MKDEV(aic3262_major, 0);
+       dprintk("TiLoad DRIVER : %s\n", __FUNCTION__);
+       aic3262_codec = codec;
+
+       dprintk("allocating dynamic major number\n");
+
+       result = alloc_chrdev_region(&dev, 0, 1, DEVICE_NAME);
+       if (result < 0) {
+               dprintk("cannot allocate major number %d\n", aic3262_major);
+               return result;
+       }
+
+       tiload_class = class_create(THIS_MODULE, DEVICE_NAME);
+       aic3262_major = MAJOR(dev);
+       dprintk("allocated Major Number: %d\n", aic3262_major);
+
+       aic3262_cdev = cdev_alloc();
+       cdev_init(aic3262_cdev, &aic3262_fops);
+       aic3262_cdev->owner = THIS_MODULE;
+       aic3262_cdev->ops = &aic3262_fops;
+
+       aic_reg.aic326x_register.page = 0;
+       aic_reg.aic326x_register.book = 0;
+
+       if (cdev_add(aic3262_cdev, dev, 1) < 0) {
+               dprintk("aic3262_driver: cdev_add failed \n");
+               unregister_chrdev_region(dev, 1);
+               aic3262_cdev = NULL;
+               return 1;
+       }
+       dprintk("Registered aic3262 TiLoad driver, Major number: %d \n",
+              aic3262_major);
+       //class_device_create(tiload_class, NULL, dev, NULL, DEVICE_NAME, 0);
+       return 0;
+}
+
+#endif
diff --git a/sound/soc/codecs/aic326x_tiload.h b/sound/soc/codecs/aic326x_tiload.h
new file mode 100644 (file)
index 0000000..747bb20
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * linux/sound/soc/codecs/aic3262_tiload.h
+ *
+ *
+ * Copyright (C) 2011 Texas Instruments Inc.
+ *
+ *
+ *
+ * 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:
+ *
+ * 
+ *
+ * 
+ */
+
+#ifndef _AIC3262_TILOAD_H
+#define _AIC3262_TILOAD_H
+
+/* typedefs required for the included header files */
+typedef char *string;
+
+/* defines */
+#define DEVICE_NAME            "tiload_node"
+#define aic3262_IOC_MAGIC      0xE0
+#define aic3262_IOMAGICNUM_GET _IOR(aic3262_IOC_MAGIC, 1, int)
+#define aic3262_IOMAGICNUM_SET _IOW(aic3262_IOC_MAGIC, 2, int)
+
+#endif
diff --git a/sound/soc/codecs/aic3xxx_cfw.h b/sound/soc/codecs/aic3xxx_cfw.h
new file mode 100644 (file)
index 0000000..7d9a6fb
--- /dev/null
@@ -0,0 +1,425 @@
+/**
+ * \file Codec Firmware Declarations
+ */
+
+#ifndef CFW_FIRMWARE_H_
+#define CFW_FIRMWARE_H_
+
+/** \defgroup bt Basic Types */
+/* @{ */
+#ifndef AIC3XXX_CFW_HOST_BLD
+#include <asm-generic/int-ll64.h>
+#else
+typedef unsigned char u8;
+typedef unsigned short int u16;
+typedef unsigned long  int u32;
+#endif
+typedef signed char i8;
+typedef signed short int i16;
+typedef signed long  int i32;
+
+#define CFW_FW_MAGIC 0xC0D1F1ED
+/* @} */
+
+
+/** \defgroup pd Arbitrary Limitations */
+/* @{ */
+#ifndef CFW_MAX_ID
+#    define CFW_MAX_ID          (64)    ///<Max length of string identifies
+#endif
+#ifndef CFW_MAX_DESC
+#   define  CFW_MAX_DESC        (512)   ///<Max length of description
+#endif
+#ifndef CFW_MAX_NOVLY
+#    define CFW_MAX_NOVLY       (4)     ///<Max number of overlays per PFW
+#endif
+
+#ifndef CFW_MAX_NCFG
+#    define CFW_MAX_NCFG        (16)    ///<Max number of configurations per PFW
+#endif
+
+#ifndef CFW_MAX_TRANSITIONS
+#    define CFW_MAX_TRANSITIONS (32)    ///<max number of pre-defined transition
+#endif
+
+#ifndef CFW_MAX_NPFW
+#    define CFW_MAX_NPFW        (16)    ///<Max number fo process flows
+#endif
+
+#ifndef CFW_MAX_MODES
+#    define CFW_MAX_MODES       (32)    ///<Max number of modes
+#endif
+
+#ifndef CFW_MAX_ASI
+#    define CFW_MAX_ASI         (4)     ///<Max number ASIs in a single device
+#endif
+
+/* @} */
+
+
+
+/** \defgroup st Enums, Flags, Macros and Supporting Types */
+/* @{ */
+
+/**
+ * Sample rate bitmask
+ *
+ */ 
+enum cfw_fs {
+    CFW_FS_8KHZ     = 0x0001u,
+    CFW_FS_11KHZ    = 0x0002u,
+    CFW_FS_16KHZ    = 0x0004u,
+    CFW_FS_22KHZ    = 0x0008u,
+    CFW_FS_24KHZ    = 0x0010u,
+    CFW_FS_32KHZ    = 0x0020u,
+    CFW_FS_44KHZ    = 0x0040u,
+    CFW_FS_48KHZ    = 0x0080u,
+    CFW_FS_88KHZ    = 0x0100u,
+    CFW_FS_96KHZ    = 0x0200u,
+    CFW_FS_176KHZ   = 0x0400u,
+    CFW_FS_192KHZ   = 0x0800u,
+    CFW_FS_ANY      = 0x8000u,
+    CFW_FS_ALL      = 0x0FFFu,
+};
+
+/**
+ * Sample rate index
+ *
+ */
+enum cfw_fsi {
+    CFW_FSI_8KHZ,
+    CFW_FSI_11KHZ,
+    CFW_FSI_16KHZ,
+    CFW_FSI_22KHZ,
+    CFW_FSI_24KHZ,
+    CFW_FSI_32KHZ,
+    CFW_FSI_44KHZ,
+    CFW_FSI_48KHZ,
+    CFW_FSI_88KHZ,
+    CFW_FSI_96KHZ,
+    CFW_FSI_176KHZ,
+    CFW_FSI_192KHZ,
+    CFW_FSI_ANY = 15,
+};
+
+
+/**
+ * Device Family Identifier
+ *
+ */
+typedef enum __attribute__ ((__packed__)) cfw_dfamily {
+    CFW_DFM_TYPE_A,
+    CFW_DFM_TYPE_B,
+    CFW_DFM_TYPE_C
+} cfw_dfamily;
+
+/**
+ * Device Identifier
+ *
+ */
+typedef enum __attribute__ ((__packed__)) cfw_device {
+    CFW_DEV_DAC3120,
+    CFW_DEV_DAC3100,
+
+    CFW_DEV_AIC3120,
+    CFW_DEV_AIC3100,
+    CFW_DEV_AIC3110,
+    CFW_DEV_AIC3111,
+
+    CFW_DEV_AIC36,
+
+    CFW_DEV_AIC3206,
+    CFW_DEV_AIC3204,
+    CFW_DEV_AIC3254,
+    CFW_DEV_AIC3256,
+    CFW_DEV_AIC3253,
+    
+    CFW_DEV_AIC3212,
+    CFW_DEV_AIC3262,
+    CFW_DEV_AIC3017,
+    CFW_DEV_AIC3008,
+
+} cfw_device;
+
+/**
+ * Transition Sequence Identifier
+ *
+ */
+typedef enum cfw_transition_t {
+    CFW_TRN_INIT,
+    CFW_TRN_RESUME,
+    CFW_TRN_NEUTRAL,
+    CFW_TRN_SUSPEND,
+    CFW_TRN_EXIT,
+    CFW_TRN_N
+} cfw_transition_t;
+static const char * const cfw_transition_id[] = {
+    [CFW_TRN_INIT] "INIT",
+    [CFW_TRN_RESUME] "RESUME",
+    [CFW_TRN_NEUTRAL] "NEUTRAL",
+    [CFW_TRN_SUSPEND] "SUSPEND",
+    [CFW_TRN_EXIT] "EXIT",
+};
+
+/* @} */
+
+/** \defgroup ds Data Structures */
+/* @{ */
+
+
+/**
+* CFW Meta Command
+* These commands do not appear in the register
+* set of the device.
+* Mainly delay, wait and set_bits.
+*/
+typedef enum __attribute__ ((__packed__)) cfw_meta_cmd {
+    CFW_META_DELAY = 0x80,
+    CFW_META_UPDTBITS,
+    CFW_META_WAITBITS,
+    CFW_META_LOCK,
+} cfw_meta_cmd;
+
+/**
+* CFW Delay
+* Used for the meta command delay
+* Has one parameter of delay time in ms
+*/
+typedef struct cfw_meta_delay {
+    u16 delay;
+    cfw_meta_cmd mcmd;
+    u8         unused1;
+} cfw_meta_delay;
+
+/**
+* CFW set_bits or wait
+* Both these meta commands have same arguments
+* mcmd will be used to specify which command it is
+* has parameters of book, page, offset and mask
+*/
+typedef struct cfw_meta_bitop {
+    u16 unused1;
+    cfw_meta_cmd mcmd;
+    u8   mask;
+} cfw_meta_bitop;
+
+/**
+* CFW meta register
+* Contains the data structures for the meta commands
+*/
+typedef union cfw_meta_register {
+    struct {
+        u16 unused1;
+        cfw_meta_cmd mcmd;
+        u8 unused2;
+    };
+    cfw_meta_delay delay;
+    cfw_meta_bitop bitop;
+} cfw_meta_register;
+
+
+/**
+ * CFW Register
+ *
+ * A single reg write
+ *
+ */
+typedef union cfw_register {
+    struct {
+        u8 book;
+        u8 page;
+        u8 offset;
+        u8 data;
+    };
+    u32 bpod;
+    cfw_meta_register meta;
+} cfw_register;
+
+/**
+ * CFW Burst
+ *
+ * A single I2C/SPI burst write sequence
+ *
+ */
+typedef struct cfw_burst {
+    u32 length;
+    union {
+        cfw_register reg;
+        struct {
+            u8 bpo[3];
+            u8 data[1];
+        };
+    };
+} cfw_burst;
+
+
+
+/**
+ * CFW Command
+ *
+ * Can be a either a
+ *      -# single register write, 
+ *      -# a burst write, or
+ *      -# meta-command 
+ *
+ */
+typedef union cfw_cmd {
+    cfw_register reg;
+    cfw_burst    *burst;
+}  cfw_cmd;
+
+
+/**
+ * CFW Block Type
+ *
+ * Block identifier
+ *
+ */
+typedef enum __attribute__ ((__packed__)) cfw_block_t {
+    CFW_BLOCK_SYSTEM_PRE,
+    CFW_BLOCK_A_INST,
+    CFW_BLOCK_A_A_COEF,
+    CFW_BLOCK_A_B_COEF,
+    CFW_BLOCK_A_F_COEF,
+    CFW_BLOCK_D_INST,
+    CFW_BLOCK_D_A1_COEF,
+    CFW_BLOCK_D_B1_COEF,
+    CFW_BLOCK_D_A2_COEF,
+    CFW_BLOCK_D_B2_COEF,
+    CFW_BLOCK_D_F_COEF,
+    CFW_BLOCK_SYSTEM_POST,
+    CFW_BLOCK_N,
+    CFW_BLOCK_BURSTS = 0x80
+} cfw_block_t;
+#define CFW_BLOCK_BURSTS(x) ((x)&CFW_BLOCK_BURSTS)
+#define CFW_BLOCK_D_A_COEF CFW_BLOCK_D_A1_COEF
+#define CFW_BLOCK_D_B_COEF CFW_BLOCK_D_B1_COEF
+
+/**
+ * CFW Block
+ *
+ * A block of logically grouped sequences/commands/meta-commands
+ *
+ */
+typedef struct cfw_block  {
+    cfw_block_t type;
+    int ncmds;
+    cfw_cmd cmd[1];
+} cfw_block;
+
+
+/**
+ * CFW Image
+ *
+ * A downloadable image
+ */
+typedef struct cfw_image {
+    char name[CFW_MAX_ID];  ///< Name of the pfw/overlay/configuration
+    char desc[CFW_MAX_DESC];    ///< User string
+    cfw_block *block[CFW_BLOCK_N];
+} cfw_image;
+
+
+/**
+ * Sysclk source
+ *
+ */
+typedef enum __attribute__ ((__packed__)) cfw_sclk_source {
+    CFW_SYSCLK_MCLK1,
+    CFW_SYSCLK_MCLK2,
+    CFW_SYSCLK_BCLK1,
+    CFW_SYSCLK_GPIO1,
+    CFW_SYSCLK_PLL_CLK,
+    CFW_SYSCLK_BCLK2,
+    CFW_SYSCLK_GPI1,
+    CFW_SYSCLK_HF_REF_CLK,
+    CFW_SYSCLK_HF_OSC_CLK,
+    CFW_SYSCLK_GPIO2,
+    CFW_SYSCLK_GPI2,
+} cfw_sclk_source;
+
+    
+/**
+ * Process flow
+ *
+ * Complete description of a process flow
+ */
+typedef struct cfw_pfw {
+    char name[CFW_MAX_ID];  ///< Name of the process flow
+    char desc[CFW_MAX_DESC];    ///< User string
+    u32 version;
+    u16 supported_fs;       ///< Sampling  rates at which this process flow may run (bit mask; see \ref cfw_fs)
+    u8  prb_a;
+    u8  prb_d;
+    int novly;              ///< Number of overlays (1 or more)
+    int ncfg;              ///< Number of configurations (0 or more)
+    cfw_block *pll;
+    cfw_image *base;           ///< Base sequence
+    cfw_image *ovly_cfg[CFW_MAX_NOVLY][CFW_MAX_NCFG]; ///< Overlay and cfg
+                                                ///< patches (if any)
+} cfw_pfw;
+
+
+/**
+ * Process transition
+ *
+ * Sequence for specific state transisitions within the driver
+ *
+ */
+typedef struct cfw_transition {
+    u32 id;
+    char name[CFW_MAX_ID];  ///< Name of the transition    
+    char desc[CFW_MAX_DESC];    ///< User string
+    cfw_block *block;
+} cfw_transition;
+
+/**
+ * Device audio mode
+ *
+ * Structure linking various operating modes to process flows,
+ * configurations and sequences
+ *
+ */
+typedef struct cfw_mode {
+    u32 id;
+    char name[CFW_MAX_ID];
+    char desc[CFW_MAX_DESC];    ///< User string
+    u32 flags;
+    u8  pfw;
+    u8  ovly;
+    u8  cfg;
+    u32 supported_cfgs;
+    cfw_block *entry;
+    cfw_block *exit;
+} cfw_mode;
+
+/**
+ * CFW Project 
+ *
+ * Top level structure describing the CFW project
+ */
+typedef struct cfw_project {
+    u32 magic;
+    u32 bmagic;
+    u32 size;
+    u32 cksum;
+    u32 version;
+    u32 tstamp;
+    char name[CFW_MAX_ID];      ///< Project name
+    char desc[CFW_MAX_DESC];    ///< User string
+    cfw_dfamily dfamily;
+    cfw_device  device;
+    u32  flags;
+    cfw_sclk_source clksrc;     ///< Clock source
+    u32  clkfreq;               ///< Clock frequency
+    cfw_transition *transition[CFW_MAX_TRANSITIONS];
+    u16  npfw;                  ///< Number of process flows
+    u16  nmode;                  ///< Number of operating modes
+    cfw_pfw  *pfw[CFW_MAX_NPFW]; ///< Indices to PFW locations
+    cfw_mode *mode[CFW_MAX_MODES];
+} cfw_project;
+
+
+/* @} */
+
+#endif /* CFW_FIRMWARE_H_ */
diff --git a/sound/soc/codecs/aic3xxx_cfw_ops.c b/sound/soc/codecs/aic3xxx_cfw_ops.c
new file mode 100644 (file)
index 0000000..ca1cddb
--- /dev/null
@@ -0,0 +1,447 @@
+#ifndef AIC3XXX_CFW_HOST_BLD
+#   include <linux/module.h>
+#   include <linux/delay.h>
+#   define warn(fmt, ...) printk(fmt "\n", ##__VA_ARGS__)
+#   define error(fmt, ...) printk(fmt "\n", ##__VA_ARGS__)
+#else
+#   define _GNU_SOURCE
+#   include <stdlib.h>
+#   include "utils.h"
+#   include <string.h>
+#endif
+
+#include "aic3xxx_cfw.h"
+#include "aic3xxx_cfw_ops.h"
+
+
+/*
+ * Firmware version numbers are used to make sure that the
+ * host and target code stay in sync.  It is _not_ recommended
+ * to provide this number from the outside (E.g., from a makefile)
+ * Instead, a set of automated tools are relied upon to keep the numbers
+ * in sync at the time of host testing.
+ */
+#define CFW_FW_VERSION 0x000100AF
+
+
+static int aic3xxx_cfw_dlimage(void *pv, cfw_image *pim);
+static int aic3xxx_cfw_dlcfg(void *pv, cfw_image *pim);
+static void aic3xxx_cfw_dlcmds(void *pv, cfw_block *pb);
+cfw_meta_register *aic3xxx_read_meta(cfw_block *pb, int i);
+void aic3xxx_wait(void *p, unsigned int reg, u8 mask, u8 data);
+static cfw_project *aic3xxx_cfw_unpickle(void *p, int n);
+
+#if defined(AIC3XXX_CFW_HOST_BLD)
+// Host test only...
+extern const aic3xxx_codec_ops dummy_codec_ops;
+extern void *dummy_codec_ops_obj;
+
+void mdelay(int val)
+{
+    int i;
+    for (i=0; i<val*10; i++);
+}
+void *aic3xxx_cfw_init(void *pcfw, int n)
+{
+    cfw_state *ps = malloc(sizeof(cfw_state));
+    ps->ops = &dummy_codec_ops;
+    ps->ops_obj = dummy_codec_ops_obj;
+    aic3xxx_cfw_reload(ps, pcfw, n);
+    return ps;
+}
+void *aic3xxx_cfw_getpjt(void *ps)
+{
+    return ((cfw_state *)ps)->pjt;
+}
+// ...till here
+#endif
+
+int aic3xxx_cfw_reload(void *pv, void *pcfw, int n)
+{
+    cfw_state *ps = pv;
+    ps->pjt = aic3xxx_cfw_unpickle(pcfw, n);
+    ps->cur_mode =
+            ps->cur_pfw =
+            ps->cur_ovly =
+            ps->cur_cfg = -1;
+    return 0;
+}
+int aic3xxx_cfw_setmode(void *pv, int mode)
+{
+    cfw_state *ps = pv;
+    cfw_project *pjt = ps->pjt;
+    return aic3xxx_cfw_setmode_cfg(pv, mode, pjt->mode[mode]->cfg);
+}
+int aic3xxx_cfw_setcfg(void *pv, int cfg)
+{
+    cfw_state *ps = pv;
+    cfw_project *pjt = ps->pjt;
+    cfw_pfw *pfw;
+    if (ps->cur_pfw >= pjt->npfw)
+        return -1; // Non miniDSP
+    if (!(pjt->mode[ps->cur_mode]->supported_cfgs&(1 << cfg)))
+        return -1;
+    if (ps->cur_cfg == cfg)
+        return 0;
+    pfw = pjt->pfw[ps->cur_pfw];
+    ps->cur_cfg = cfg;
+    return aic3xxx_cfw_dlcfg(pv, pfw->ovly_cfg[ps->cur_ovly][ps->cur_cfg]);
+}
+int aic3xxx_cfw_setmode_cfg(void *pv, int mode, int cfg)
+{
+    cfw_state *ps = pv;
+    cfw_project *pjt = ps->pjt;
+    int which = 0;
+
+    if (mode >= pjt->nmode)
+        return -1;
+    if (pjt->mode[mode]->pfw < pjt->npfw) {   // New mode uses miniDSP
+        // FIXME: Add support for entry and exit sequences
+        cfw_pfw *pfw = pjt->pfw[pjt->mode[mode]->pfw];
+        // Make sure cfg is valid and supported in this mode
+        if (cfg >= pfw->ncfg ||
+                !(pjt->mode[mode]->supported_cfgs&(1u<<cfg)))
+            return -1;
+        /*
+         * Decisions about which miniDSP to stop/restart are taken
+         * on the basis of sections present in the _base_ image
+         * This allows for correct sync mode operation even in cases
+         * where the base PFW uses both miniDSPs where a particular
+         * overlay applies only to one
+         */
+        cfw_image *im = pfw->base;
+        if (im->block[CFW_BLOCK_A_INST])
+            which |= AIC3XX_COPS_MDSP_A;
+        if (im->block[CFW_BLOCK_D_INST])
+            which |= AIC3XX_COPS_MDSP_D;
+
+        if (pjt->mode[mode]->pfw !=  ps->cur_pfw) { // New mode requires different PFW
+            ps->cur_pfw = pjt->mode[mode]->pfw;
+            ps->cur_ovly = 0;
+            ps->cur_cfg = 0;
+
+            which = ps->ops->stop(ps->ops_obj, which);
+            aic3xxx_cfw_dlimage(pv, im);
+            if (pjt->mode[mode]->ovly && pjt->mode[mode]->ovly < pfw->novly) {
+                // New mode uses ovly
+                aic3xxx_cfw_dlimage(pv, pfw->ovly_cfg[pjt->mode[mode]->ovly][cfg]);
+            } else if (cfg) {
+                // new mode needs only a cfg change
+                aic3xxx_cfw_dlimage(pv, pfw->ovly_cfg[0][cfg]);
+            }
+            ps->ops->restore(ps->ops_obj, which);
+
+        } else if (pjt->mode[mode]->ovly != ps->cur_ovly) {
+            // New mode requires only an ovly change
+            which = ps->ops->stop(ps->ops_obj, which);
+            aic3xxx_cfw_dlimage(pv, pfw->ovly_cfg[pjt->mode[mode]->ovly][cfg]);
+            ps->ops->restore(ps->ops_obj, which);
+        } else if (cfg != ps->cur_cfg) { // New mode requires only a cfg change
+            aic3xxx_cfw_dlcfg(pv, pfw->ovly_cfg[pjt->mode[mode]->ovly][cfg]);
+        }
+        ps->cur_ovly = pjt->mode[mode]->ovly;
+        ps->cur_cfg = cfg;
+
+        // FIXME: Update PLL settings if present
+        // FIXME: This is hack and needs to go one way or another
+        ps->cur_mode = mode;
+        aic3xxx_cfw_set_pll(pv, 0);
+
+    } else if (pjt->mode[mode]->pfw  == 0xFF) { // Bypass mode
+        // FIXME
+    } else { // Error
+        warn("Bad pfw setting detected (%d).  Max pfw=%d", pjt->mode[mode]->pfw,
+                pjt->npfw);
+    }
+    ps->cur_mode = mode;
+    warn("setmode_cfg: DONE (mode=%d pfw=%d ovly=%d cfg=%d)", ps->cur_mode, ps->cur_pfw, ps->cur_ovly, ps->cur_cfg);
+    return 0;
+}
+int aic3xxx_cfw_transition(void *pv, char *ttype)
+{
+    cfw_state *ps = pv;
+     int i;
+     for (i = 0; i < CFW_TRN_N; ++i) {
+         if (!strcasecmp(ttype, cfw_transition_id[i])) {
+            if (ps->pjt->transition[i]) {
+                DBG("Sending transition %s[%d]", ttype, i);
+                aic3xxx_cfw_dlcmds(pv, ps->pjt->transition[i]->block);
+            }
+            return 0;
+         }
+     }
+     warn("Transition %s not present or invalid", ttype);
+     return 0;
+}
+int aic3xxx_cfw_set_pll(void *pv, int asi)
+{
+    // FIXME: no error checks!!
+    cfw_state *ps = pv;
+    cfw_project *pjt = ps->pjt;
+    cfw_pfw *pfw = pjt->pfw[pjt->mode[ps->cur_mode]->pfw];
+    if (pfw->pll) {
+        warn("Configuring PLL for ASI%d using PFW%d", asi,
+                pjt->mode[ps->cur_mode]->pfw);
+        aic3xxx_cfw_dlcmds(pv, pfw->pll);
+    }
+    return 0;
+}
+static void aic3xxx_cfw_dlcmds(void *pv, cfw_block *pb)
+{
+    cfw_state *ps = pv;
+    int i = 0, lock = 0;
+
+    while (i < pb->ncmds) {
+        if (CFW_BLOCK_BURSTS(pb->type))
+            ps->ops->bulk_write(ps->ops_obj, pb->cmd[i].burst->reg.bpod,
+                pb->cmd[i].burst->length,
+                pb->cmd[i].burst->data);
+        else {
+            cfw_meta_delay d = pb->cmd[i].reg.meta.delay;
+            cfw_meta_bitop b = pb->cmd[i].reg.meta.bitop;
+            switch (pb->cmd[i].reg.meta.mcmd) {
+            case CFW_META_DELAY:
+                mdelay(d.delay);
+                break;
+            case CFW_META_UPDTBITS:
+                ps->ops->set_bits(ps->ops_obj,  pb->cmd[i+1].reg.bpod,
+                        b.mask, pb->cmd[i+1].reg.data);
+                i++;
+                break;
+            case CFW_META_WAITBITS:
+                aic3xxx_wait(ps,  pb->cmd[i+1].reg.bpod,
+                        b.mask, pb->cmd[i+1].reg.data);
+                i++;
+                break;
+            case CFW_META_LOCK:
+                if (d.delay) {
+                    ps->ops->lock(ps->ops_obj);
+                    lock = 1;
+                } else {
+                    if (!lock)
+                        error("Attempt to unlock without first locking");
+                    ps->ops->unlock(ps->ops_obj);
+                    lock = 0;
+                }
+                break;
+            default:
+                ps->ops->reg_write(ps->ops_obj, pb->cmd[i].reg.bpod,  pb->cmd[i].reg.data);
+            }
+        }
+        ++i;
+    }
+    if (lock)
+        error("exiting blkcmds with lock ON");
+}
+
+void aic3xxx_wait(void *p, unsigned int reg, u8 mask, u8 data)
+{
+    cfw_state *ps = p;
+    while ((ps->ops->reg_read(ps->ops_obj, reg)&mask) != data)
+        mdelay(2);
+}
+
+static int aic3xxx_cfw_dlcfg(void *pv, cfw_image *pim)
+{
+    cfw_state *ps = pv;
+    int i,run_state,swap;
+    struct {
+        u32 mdsp;
+        int buf_a, buf_b;
+        u32 swap;
+    } csecs[] = {
+        {
+            .mdsp=AIC3XX_COPS_MDSP_A,
+            .swap=AIC3XX_ABUF_MDSP_A,
+            .buf_a=CFW_BLOCK_A_A_COEF,
+            .buf_b=CFW_BLOCK_A_B_COEF
+        },
+        {
+            .mdsp=AIC3XX_COPS_MDSP_D,
+            .swap=AIC3XX_ABUF_MDSP_D1,
+            .buf_a=CFW_BLOCK_D_A1_COEF,
+            .buf_b=CFW_BLOCK_D_B1_COEF
+        },
+        {
+            .mdsp=AIC3XX_COPS_MDSP_D,
+            .swap=AIC3XX_ABUF_MDSP_D2,
+            .buf_a=CFW_BLOCK_D_A2_COEF,
+            .buf_b=CFW_BLOCK_D_B2_COEF
+        },
+    };
+    DBG("Download CFG %s", pim->name);
+    run_state = ps->ops->lock(ps->ops_obj);
+    swap = 0;
+    for (i = 0; i < sizeof(csecs)/sizeof(csecs[0]); ++i) {
+        if (pim->block[csecs[i].buf_a]) {
+            if (run_state & csecs[i].mdsp) {
+                aic3xxx_cfw_dlcmds(pv, pim->block[csecs[i].buf_a]);
+                swap |=  csecs[i].swap;
+                aic3xxx_cfw_dlcmds(pv, pim->block[csecs[i].buf_b]);
+            } else {
+                aic3xxx_cfw_dlcmds(pv, pim->block[csecs[i].buf_a]);
+                aic3xxx_cfw_dlcmds(pv, pim->block[csecs[i].buf_b]);
+            }
+        }
+    }
+    if (swap) // Check needed? FIXME
+        ps->ops->bswap(ps->ops_obj, swap);
+    ps->ops->unlock(ps->ops_obj);
+    return 0;
+}
+static int aic3xxx_cfw_dlimage(void *pv, cfw_image *pim)
+{
+    //cfw_state *ps = pv;
+    int i;
+    DBG("Download IMAGE %s", pim->name);
+    for (i = 0; i < CFW_BLOCK_N; ++i)
+        if (pim->block[i])
+            aic3xxx_cfw_dlcmds(pv, pim->block[i]);
+    return 0;
+}
+
+#   define FW_NDX2PTR(x, b) do {                        \
+        x = (void *)((u8 *)(b) + ((int)(x)));           \
+    } while (0)
+static void aic3xxx_cfw_unpickle_block(cfw_block *pb, void *p)
+{
+    int i;
+    if (CFW_BLOCK_BURSTS(pb->type)) {
+        for (i = 0; i < pb->ncmds; ++i) {
+            FW_NDX2PTR(pb->cmd[i].burst, p);
+        }
+    }
+}
+static void aic3xxx_cfw_unpickle_image(cfw_image *im, void *p)
+{
+    int i;
+    for (i = 0; i < CFW_BLOCK_N; ++i)
+        if (im->block[i]) {
+            FW_NDX2PTR(im->block[i], p);
+            aic3xxx_cfw_unpickle_block(im->block[i], p);
+        }
+}
+#ifndef AIC3XXX_CFW_HOST_BLD
+static
+#endif
+unsigned int crc32(unsigned int *pdata, int n)
+{
+    u32 crc = 0, i, crc_poly = 0x04C11DB7;                  /* CRC - 32 */
+    u32 msb;
+    u32 residue_value;
+    int bits;
+
+    for (i = 0; i < (n >> 2); i++) {
+        bits = 32;
+        while (--bits >= 0) {
+            msb = crc & 0x80000000;
+            crc = (crc << 1) ^ ((*pdata >> bits) & 1);
+            if (msb)
+                crc = crc ^ crc_poly;
+        }
+        pdata++;
+    }
+
+    switch (n & 3) {
+        case 0:
+            break;
+        case 1:
+            residue_value = (*pdata & 0xFF);
+            bits = 8;
+            break;
+        case 2:
+            residue_value = (*pdata & 0xFFFF);
+            bits = 16;
+            break;
+        case 3:
+            residue_value = (*pdata & 0xFFFFFF);
+            bits = 24;
+            break;
+    }
+
+    if (n & 3) {
+        while (--bits >= 0) {
+            msb = crc & 0x80000000;
+            crc = (crc << 1) ^ ((residue_value >> bits) & 1);
+            if (msb)
+                crc = crc ^ crc_poly;
+        }
+    }
+    return (crc);
+}
+static int crc_chk(void *p, int n)
+{
+    cfw_project *pjt = (void *)p;
+    u32 crc  = pjt->cksum, crc_comp;
+    pjt->cksum = 0;
+    DBG("Entering crc %d",n);
+    crc_comp = crc32(p, n);
+    if (crc_comp != crc) {
+        DBG("CRC mismatch 0x%08X != 0x%08X", crc, crc_comp);
+        return 0; // Dead code
+    }
+    DBG("CRC pass");
+    pjt->cksum = crc;
+    return 1;
+}
+#ifndef AIC3XXX_CFW_HOST_BLD
+static
+#endif
+cfw_project *aic3xxx_cfw_unpickle(void *p, int n)
+{
+    cfw_project *pjt = p;
+    int i, j, k;
+    if (pjt->magic != CFW_FW_MAGIC ||
+           pjt->size != n ||
+           pjt->bmagic != CFW_FW_VERSION ||
+            !crc_chk(p, n)) {
+        error("magic:0x%08X!=0x%08X || size:%d!=%d || version:0x%08X!=0x%08X",
+               pjt->magic, CFW_FW_MAGIC, pjt->size, n, pjt->cksum,
+               CFW_FW_VERSION);
+        return NULL;
+    }
+    DBG("Loaded firmware inside unpickle\n");
+
+    for (i = 0; i < CFW_MAX_TRANSITIONS; i++) {
+        if (pjt->transition[i]) {
+            FW_NDX2PTR(pjt->transition[i], p);
+            FW_NDX2PTR(pjt->transition[i]->block, p);
+            aic3xxx_cfw_unpickle_block(pjt->transition[i]->block, p);
+        }
+    }
+
+    for (i = 0; i < pjt->npfw; i++) {
+        DBG("loading pfw %d\n",i);
+        FW_NDX2PTR(pjt->pfw[i], p);
+        if (pjt->pfw[i]->base) {
+            FW_NDX2PTR(pjt->pfw[i]->base, p);
+            aic3xxx_cfw_unpickle_image(pjt->pfw[i]->base, p);
+        }
+        if (pjt->pfw[i]->pll) {
+            FW_NDX2PTR(pjt->pfw[i]->pll, p);
+            aic3xxx_cfw_unpickle_block(pjt->pfw[i]->pll, p);
+        }
+        for (j =0; j < pjt->pfw[i]->novly; ++j)
+            for (k =0; k < pjt->pfw[i]->ncfg; ++k) {
+                FW_NDX2PTR(pjt->pfw[i]->ovly_cfg[j][k], p);
+                aic3xxx_cfw_unpickle_image(pjt->pfw[i]->ovly_cfg[j][k], p);
+            }
+    }
+
+    DBG("loaded pfw's\n");
+    for (i = 0; i < pjt->nmode; i++) {
+        FW_NDX2PTR(pjt->mode[i], p);
+        if (pjt->mode[i]->entry) {
+            FW_NDX2PTR(pjt->mode[i]->entry, p);
+            aic3xxx_cfw_unpickle_block(pjt->mode[i]->entry, p);
+        }
+        if (pjt->mode[i]->exit) {
+            FW_NDX2PTR(pjt->mode[i]->exit, p);
+            aic3xxx_cfw_unpickle_block(pjt->mode[i]->exit, p);
+        }
+    }
+    DBG("loaded modes\n");
+    return pjt;
+}
+
+
diff --git a/sound/soc/codecs/aic3xxx_cfw_ops.h b/sound/soc/codecs/aic3xxx_cfw_ops.h
new file mode 100644 (file)
index 0000000..82ca5f2
--- /dev/null
@@ -0,0 +1,69 @@
+#ifndef AIC3XXX_CFW_OPS_H_
+#define AIC3XXX_CFW_OPS_H_
+
+#ifdef AIC3XXX_CFW_HOST_BLD
+void *aic3xxx_cfw_init(void *pcfw, int n);
+void *aic3xxx_cfw_getpjt(void *ps);
+cfw_project *aic3xxx_cfw_unpickle(void *,int);
+unsigned int crc32(unsigned int *pdata, int n);
+#endif
+
+int aic3xxx_cfw_reload(void *pv, void *pcfw, int n);
+int aic3xxx_cfw_setmode(void *pv, int mode);
+int aic3xxx_cfw_setmode_cfg(void *pv, int mode, int cfg);
+int aic3xxx_cfw_setcfg(void *pv, int cfg);
+int aic3xxx_cfw_transition(void *pv, char *ttype);
+int aic3xxx_cfw_set_pll(void *pv, int asi);
+
+
+#define AIC3XX_COPS_MDSP_D  (0x00000003u)
+#define AIC3XX_COPS_MDSP_A  (0x00000030u)
+#define AIC3XX_COPS_MDSP_ALL (AIC3XX_COPS_MDSP_D|AIC3XX_COPS_MDSP_A)
+
+#define AIC3XX_ABUF_MDSP_D1 (0x00000001u)
+#define AIC3XX_ABUF_MDSP_D2 (0x00000002u)
+#define AIC3XX_ABUF_MDSP_A  (0x00000010u)
+#define AIC3XX_ABUF_MDSP_ALL \
+    (AIC3XX_ABUF_MDSP_D1| AIC3XX_ABUF_MDSP_D2| AIC3XX_ABUF_MDSP_A)
+
+typedef struct aic3xxx_codec_ops {
+    int (*reg_read)(void *p, unsigned int reg);
+    int (*reg_write)(void *p, unsigned int reg,
+            unsigned int val);
+    int (*set_bits)(void *p, unsigned int reg, 
+            unsigned char mask, unsigned char val);
+    int (*bulk_read)(void *p, unsigned int reg, 
+            int count, u8 *buf);
+    int (*bulk_write)(void *p, unsigned int reg, 
+            int count, const u8 *buf);
+
+    int (*lock)(void *p);
+    int (*unlock)(void *p);
+    int (*stop)(void *p, int mask);
+    int (*restore)(void *p, int runstate);
+    int (*bswap)(void *p,int mask);
+} aic3xxx_codec_ops;
+
+typedef struct cfw_state {
+    cfw_project *pjt;
+    const aic3xxx_codec_ops *ops;
+    void *ops_obj;
+    int cur_mode;
+    int cur_pfw;
+    int cur_ovly;
+    int cur_cfg;
+} cfw_state;
+
+#ifndef AIC3XXX_CFW_HOST_BLD
+#ifdef DEBUG
+
+#   define DBG(fmt,...) printk("CFW[%s:%d]: " fmt "\n",      \
+                        __FILE__, __LINE__, ##__VA_ARGS__)
+#else
+
+#   define DBG(fmt,...) 
+
+#endif
+
+#endif
+#endif
diff --git a/sound/soc/codecs/pickle.h b/sound/soc/codecs/pickle.h
new file mode 100644 (file)
index 0000000..488012a
--- /dev/null
@@ -0,0 +1,7 @@
+#ifndef PICKLE_H_
+#define  PICKLE_H_
+
+void *pickle_pjt(cfw_project *p, int *n);
+cfw_project *unpickle_pjt(void *p, int n);
+
+#endif
diff --git a/sound/soc/codecs/tlv320aic3262_default_fw.h b/sound/soc/codecs/tlv320aic3262_default_fw.h
new file mode 100644 (file)
index 0000000..e51851b
--- /dev/null
@@ -0,0 +1,320 @@
+unsigned char default_firmware[] = {
+    237,241,209,192,175,  0,  1,  0,219, 19,  0,  0, 28, 84, 36, 37,
+      0,  0,  0,  0,161, 85,149, 79, 70,105,114,109,119, 97,114,101,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  2, 13,  0,  0,  8,  2,  0,  0,
+      0,  0,  0,  0,  0,240, 73,  2,172,  3,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  1,  0,  1,  0, 32,  6,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,131, 17,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    105,110,105,116,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+     73,110,105,116,105, 97,108,105,122, 97,116,105,111,110, 32,115,
+    101,113,117,101,110, 99,101, 32, 40, 97,112,112,108,105,101,100,
+     32,111,110,108,121, 32,111,110, 32,115,121,115,116,101,109, 32,
+     98,111,111,116, 41,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    244,  5,  0,  0,  0,  0,  0,  0,  9,  0,  0,  0,100,  0,128,  0,
+      0,  1,  1,  0,  0,  1,122,  1,  0,  0,  4, 51,  0,  0, 82,  0,
+      0,  0, 67,151,  0,  1,119,127,  0,  0,129,  1,  0,  4, 11,  1,
+    100,101,102, 97,117,108,116,  0, 98, 97,115,101, 95,109, 97,105,
+    110, 95, 82, 97,116,101, 52, 56, 46, 99,102,103,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  1,  0,  0,  0,  2,  0,  0,  0,
+    253, 11,  0,  0,120,  9,  0,  0,121, 12,  0,  0,254, 14,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,100,101,102, 97,117,108,116, 47,
+     98, 97,115,101, 95,109, 97,105,110, 95, 82, 97,116,101, 52, 56,
+     46, 99,102,103,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 96,  8,115,247,
+      0,  0,  0,  0,137, 55,  1,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,232, 11,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,128,  0,  0,  0,  1,  0,  0,  0,
+    244, 11,  0,  0,  2,  0,  0,  0,  0,  0, 60,  1,  1,  0,  0,  0,
+      0, 29,  0,  0,  0,  0,  0,129,127,  0,  0,  6, 33,  0,  0,129,
+     63,  0,  0,  7,  5,  0,  0,  8,  4,  0,  0,  9,176,  0,  0,129,
+    127,  0,  0, 10,  1,  0,  0,129,127,  0,  0, 11,  2,  0,  0,129,
+    127,  0,  0, 12,  8,  0,  0, 13,  0,  0,  0, 14,128,  0,  0, 18,
+    130,  0,  0, 19,136,  0,  0, 20,128,  0,  0,129,  3,  0,  4, 11,
+      0,  0,  0,129,127,  0,  4, 12,  4,  0,  0,129,127,  0,  4, 13,
+     32,  0,  0,129,119,  0,  4, 14,  0,  0,  4,119,240,  0,  4,120,
+      0,100,  0, 20,128,120,  0, 20,  0,100,101,102, 97,117,108,116,
+     47, 80, 97,116, 99,104, 95, 98, 97,115,101, 95,109, 97,105,110,
+     95, 82, 97,116,101, 52, 56, 46, 99,102,103,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,233, 14,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,128,  0,  0,  0,  1,  0,  0,
+      0,245, 14,  0,  0,  2,  0,  0,  0,  0,  0, 60,  1,  1,100,101,
+    102, 97,117,108,116, 47, 80, 97,116, 99,104, 95, 98, 97,115,101,
+     95,115,112,107, 95, 82, 97,116,101, 52, 56, 46, 99,102,103,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0, 96,  8,115,247,  0,  0,  0,  0,233, 58,  1,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,110, 17,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,128, 36,
+    115,247,  1,  0,  0,  0,122, 17,  0,  0,  2,  0,  0,  0,  0,  0,
+     60,  1,  1,  0,  0,  0,  0,100,101,102, 97,117,108,116,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  3,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+};
diff --git a/sound/soc/codecs/tlv320aic326x.c b/sound/soc/codecs/tlv320aic326x.c
new file mode 100644 (file)
index 0000000..33d7cd8
--- /dev/null
@@ -0,0 +1,2869 @@
+/*
+ * linux/sound/soc/codecs/tlv320aic326x.c
+ *
+ * Copyright (C) 2011 Texas Instruments Inc.,
+ *
+ * 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    TI         20-01-2011
+ *
+ *                      The AIC325x ASoC driver is ported for the codec AIC3262.
+ * Rev 0.2   ASoC driver support    TI         21-03-2011
+ *                      The AIC326x ASoC driver is updated for linux 2.6.32 Kernel.
+ * Rev 0.3   ASoC driver support    TI     20-04-2011
+ *                      The AIC326x ASoC driver is ported to 2.6.35 omap4 kernel
+ */
+
+/*
+ *****************************************************************************
+ * INCLUDES
+ *****************************************************************************
+ */
+//#define DEBUG 1
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/pm_runtime.h>
+#include <linux/spi/spi.h>
+#include <linux/platform_device.h>
+#include <linux/switch.h>
+#include <sound/jack.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/cdev.h>
+#include <linux/slab.h>
+#include <linux/firmware.h>
+
+#include <sound/tlv.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/initval.h>
+#include <linux/mfd/tlv320aic3262-registers.h>
+#include <linux/mfd/tlv320aic3262-core.h>
+#include "aic3xxx_cfw.h"
+#include "aic3xxx_cfw_ops.h"
+
+#include "tlv320aic326x.h"
+#include "aic3262_codec_ops.h"
+#include "tlv320aic3262_default_fw.h"
+
+#if 0
+#define        DBG(x...)       printk(KERN_INFO x)
+#else
+#define        DBG(x...)
+#endif
+
+#ifdef AIC3262_TiLoad
+extern int aic3262_driver_init(struct snd_soc_codec *codec);
+#endif
+
+#define AIC3262_PROC
+#ifdef AIC3262_PROC
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
+#include <linux/vmalloc.h>
+char debug_write_read = 0;
+#endif
+
+static struct snd_soc_codec *aic3262_codec;
+
+/*
+ *******************************************************************************
+ * Global Variable                                                            *        
+ *******************************************************************************
+ */
+static u32 aic3262_reg_ctl;
+
+/* 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, \
+}
+/*
+ *****************************************************************************
+ * 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_dai_set_pll(struct snd_soc_dai *dai, int pll_id, int source,
+                          unsigned int Fin, unsigned int Fout);      
+
+static int aic3262_set_bias_level(struct snd_soc_codec *codec, enum snd_soc_bias_level level);
+
+unsigned int aic3262_codec_read(struct snd_soc_codec *codec, unsigned int reg);
+
+
+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);
+int aic3262_change_book(struct snd_soc_codec *codec, u8 new_book);
+
+
+void aic3262_firmware_load(const struct firmware *fw, void *context);
+static int aic3262_test_get(struct snd_kcontrol *kcontrol,
+               struct snd_ctl_elem_value *ucontrol);
+static int aic3262_test_put(struct snd_kcontrol *kcontrol,
+               struct snd_ctl_elem_value *ucontrol);
+static int aic3262_set_mode_get(struct snd_kcontrol *kcontrol,
+               struct snd_ctl_elem_value *ucontrol);
+static int aic3262_set_mode_put(struct snd_kcontrol *kcontrol,
+               struct snd_ctl_elem_value *ucontrol);
+
+static int aic326x_adc_dsp_event(struct snd_soc_dapm_widget *w,struct snd_kcontrol *kcontrol, int event);
+/*static int aic326x_adcl_event(struct snd_soc_dapm_widget *w,struct snd_kcontrol *kcontrol, int event);
+static int aic326x_adcr_event(struct snd_soc_dapm_widget *w,struct snd_kcontrol *kcontrol, int event);*/
+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;
+}
+
+static long debug_level = 0;
+module_param(debug_level, int, 0);
+MODULE_PARM_DESC(debug_level, "Debug level for printing");
+
+/*
+ *----------------------------------------------------------------------------
+ * 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 = snd_soc_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);
+       u32 data_from_user = ucontrol->value.integer.value[0];
+       u8 val = data_from_user & 0x00ff;
+       u32 reg = data_from_user >> 8;//MAKE_REG(book,page,offset)
+       snd_soc_write(codec, reg, val);
+       aic3262_reg_ctl = reg;
+
+       return 0;
+}
+
+static ssize_t debug_level_show(struct device *dev, 
+               struct device_attribute *attr,
+               char *buf, size_t count)
+{
+       return sprintf(buf, "%ld\n", debug_level);
+}
+
+static ssize_t debug_level_set(struct device *dev, 
+               struct device_attribute *attr,
+               const char *buf, size_t count)
+{
+       int ret;
+       ret = strict_strtol(buf, 10, &debug_level);
+       if(ret)
+               return ret;
+       return count;
+}
+
+static DEVICE_ATTR(debug_level,0644, debug_level_show, debug_level_set);
+
+static const DECLARE_TLV_DB_SCALE(dac_vol_tlv, -6350, 50, 0);
+static const DECLARE_TLV_DB_SCALE(adc_vol_tlv, -1200, 50, 0);
+static const DECLARE_TLV_DB_SCALE(spk_gain_tlv, 600, 600, 0);
+static const DECLARE_TLV_DB_SCALE(output_gain_tlv, -600, 100, 1);
+static const DECLARE_TLV_DB_SCALE(micpga_gain_tlv, 0, 50, 0);
+static const DECLARE_TLV_DB_SCALE(adc_fine_gain_tlv, -40, 10, 0);
+static const DECLARE_TLV_DB_SCALE(beep_gen_volume_tlv, -6300, 100, 0);
+
+/* Chip-level Input and Output CM Mode Controls */
+static const char *input_common_mode_text[] = {
+       "0.9v", "0.75v" };
+
+static const char *output_common_mode_text[] = {
+       "Input CM", "1.25v", "1.5v", "1.65v" };
+
+static const struct soc_enum input_cm_mode =
+       SOC_ENUM_SINGLE(AIC3262_CM_REG, 2, 2, input_common_mode_text);  
+       
+static const struct soc_enum output_cm_mode =
+       SOC_ENUM_SINGLE(AIC3262_CM_REG, 0, 4, output_common_mode_text);         
+/*
+ *****************************************************************************
+ * 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_SX_TLV("PCM Playback Volume", 
+                       AIC3262_DAC_LVOL, AIC3262_DAC_RVOL, 8,0xffffff81, 0x30, dac_vol_tlv),
+#endif
+       /*HP Driver Gain Control*/
+       SOC_DOUBLE_R_SX_TLV("HeadPhone Driver Amplifier Volume", AIC3262_HPL_VOL, AIC3262_HPR_VOL, 6, 0xffffffb9, 0xffffffce, output_gain_tlv),
+       /*LO Driver Gain Control*/
+       SOC_DOUBLE_TLV("Speaker Amplifier Volume", AIC3262_SPK_AMP_CNTL_R4, 4, 0, 5, 0, spk_gain_tlv),
+
+       SOC_DOUBLE_R_SX_TLV("Receiver Amplifier Volume", AIC3262_REC_AMP_CNTL_R5, AIC3262_RAMPR_VOL, 6, 0xffffffb9, 0xffffffd6, output_gain_tlv),
+
+       SOC_DOUBLE_R_SX_TLV("PCM Capture Volume", 
+                       AIC3262_LADC_VOL, AIC3262_RADC_VOL, 7,0xffffff68, 0xffffffa8, adc_vol_tlv),
+
+
+       SOC_DOUBLE_R_TLV ("MicPGA Volume Control",                                                                                                           
+                       AIC3262_MICL_PGA, AIC3262_MICR_PGA, 0, 0x5F, 0, micpga_gain_tlv),        
+       SOC_DOUBLE_TLV("PCM Capture Fine Gain Volume", AIC3262_ADC_FINE_GAIN, 4, 0, 5, 1, adc_fine_gain_tlv),
+       SOC_DOUBLE("ADC channel mute", AIC3262_ADC_FINE_GAIN, 7, 3, 1, 0),
+
+       SOC_DOUBLE("DAC MUTE", AIC3262_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", AIC3262_RESET_REG, 0,1,0),
+
+       SOC_SINGLE("DAC VOL SOFT STEPPING", AIC3262_DAC_MVOL_CONF, 0, 2, 0),
+
+
+       SOC_SINGLE("DAC AUTO MUTE CONTROL", AIC3262_DAC_MVOL_CONF, 4, 7, 0),
+       SOC_SINGLE("RIGHT MODULATOR SETUP", AIC3262_DAC_MVOL_CONF, 7, 1, 0),
+
+       SOC_SINGLE("ADC Volume soft stepping", AIC3262_ADC_CHANNEL_POW, 0, 3, 0),
+
+       SOC_SINGLE("Mic Bias ext independent enable", AIC3262_MIC_BIAS_CNTL, 7, 1, 0),
+       //      SOC_SINGLE("MICBIAS_EXT ON", MIC_BIAS_CNTL, 6, 1, 0),
+       SOC_SINGLE("MICBIAS EXT Power Level", AIC3262_MIC_BIAS_CNTL, 4, 3, 0),
+
+       //      SOC_SINGLE("MICBIAS_INT ON", MIC_BIAS_CNTL, 2, 1, 0),
+       SOC_SINGLE("MICBIAS INT Power Level", AIC3262_MIC_BIAS_CNTL, 0, 3, 0),
+
+       SOC_DOUBLE("DRC_EN_CTL", AIC3262_DRC_CNTL_R1, 6, 5, 1, 0),
+       SOC_SINGLE("DRC_THRESHOLD_LEVEL", AIC3262_DRC_CNTL_R1, 2, 7, 1),
+       SOC_SINGLE("DRC_HYSTERISIS_LEVEL", AIC3262_DRC_CNTL_R1, 0, 7, 0),
+
+       SOC_SINGLE("DRC_HOLD_LEVEL", AIC3262_DRC_CNTL_R2, 3, 0x0F, 0),
+       SOC_SINGLE("DRC_GAIN_RATE", AIC3262_DRC_CNTL_R2, 0, 4, 0),
+       SOC_SINGLE("DRC_ATTACK_RATE", AIC3262_DRC_CNTL_R3, 4, 0x0F, 1),
+       SOC_SINGLE("DRC_DECAY_RATE", AIC3262_DRC_CNTL_R3, 0, 0x0F, 1),
+
+       SOC_SINGLE("BEEP_GEN_EN", AIC3262_BEEP_CNTL_R1, 7, 1, 0),
+       SOC_DOUBLE_R("BEEP_VOL_CNTL", AIC3262_BEEP_CNTL_R1, AIC3262_BEEP_CNTL_R2, 0, 0x0F, 1),
+       SOC_SINGLE("BEEP_MAS_VOL", AIC3262_BEEP_CNTL_R2, 6, 3, 0),
+
+       SOC_DOUBLE_R("AGC_EN", AIC3262_LAGC_CNTL, AIC3262_RAGC_CNTL, 7, 1, 0),
+       SOC_DOUBLE_R("AGC_TARGET_LEVEL", AIC3262_LAGC_CNTL, AIC3262_RAGC_CNTL, 4, 7, 1),
+
+       SOC_DOUBLE_R("AGC_GAIN_HYSTERESIS", AIC3262_LAGC_CNTL, AIC3262_RAGC_CNTL, 0, 3, 0),
+       SOC_DOUBLE_R("AGC_HYSTERESIS", AIC3262_LAGC_CNTL_R2, AIC3262_RAGC_CNTL_R2, 6, 3, 0),
+       SOC_DOUBLE_R("AGC_NOISE_THRESHOLD", AIC3262_LAGC_CNTL_R2, AIC3262_RAGC_CNTL_R2, 1, 31, 1),
+
+       SOC_DOUBLE_R("AGC_MAX_GAIN", AIC3262_LAGC_CNTL_R3, AIC3262_RAGC_CNTL_R3, 0, 116, 0),
+       SOC_DOUBLE_R("AGC_ATCK_TIME", AIC3262_LAGC_CNTL_R4, AIC3262_RAGC_CNTL_R4, 3, 31, 0),
+       SOC_DOUBLE_R("AGC_ATCK_SCALE_FACTOR", AIC3262_LAGC_CNTL_R4, AIC3262_RAGC_CNTL_R4, 0, 7, 0),
+
+       SOC_DOUBLE_R("AGC_DECAY_TIME", AIC3262_LAGC_CNTL_R5, AIC3262_RAGC_CNTL_R5, 3, 31, 0),
+       SOC_DOUBLE_R("AGC_DECAY_SCALE_FACTOR", AIC3262_LAGC_CNTL_R5, AIC3262_RAGC_CNTL_R5, 0, 7, 0),
+       SOC_DOUBLE_R("AGC_NOISE_DEB_TIME", AIC3262_LAGC_CNTL_R6, AIC3262_RAGC_CNTL_R6, 0, 31, 0),
+
+       SOC_DOUBLE_R("AGC_SGL_DEB_TIME", AIC3262_LAGC_CNTL_R7, AIC3262_RAGC_CNTL_R7, 0, 0x0F, 0),
+
+       SOC_SINGLE("DAC PRB Selection",AIC3262_DAC_PRB, 0, 26, 0),
+       SOC_SINGLE("ADC PRB Selection",AIC3262_ADC_PRB, 0, 18, 0),
+       SOC_ENUM("Input CM mode", input_cm_mode),
+       SOC_ENUM("Output CM mode", output_cm_mode),
+
+       SOC_SINGLE_EXT("FIRMWARE LOAD",SND_SOC_NOPM,0,0,0,aic3262_test_get,aic3262_test_put),
+       SOC_SINGLE_EXT("FIRMWARE SET MODE",SND_SOC_NOPM,0,0xffff,0,aic3262_set_mode_get,aic3262_set_mode_put), 
+
+
+};
+/*
+ *----------------------------------------------------------------------------
+ * @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_asi1_dai_ops = {
+       .hw_params = aic3262_hw_params,
+       .digital_mute = aic3262_mute,
+       .set_sysclk = aic3262_set_dai_sysclk,
+       .set_fmt = aic3262_set_dai_fmt,
+       .set_pll = aic3262_dai_set_pll,
+};
+struct snd_soc_dai_ops aic3262_asi2_dai_ops = {
+       .hw_params = aic3262_hw_params,
+       .digital_mute = aic3262_mute,
+       .set_sysclk = aic3262_set_dai_sysclk,
+       .set_fmt = aic3262_set_dai_fmt,
+       .set_pll = aic3262_dai_set_pll,
+};
+struct snd_soc_dai_ops aic3262_asi3_dai_ops = {
+       .hw_params = aic3262_hw_params,
+       .digital_mute = aic3262_mute,
+       .set_sysclk = aic3262_set_dai_sysclk,
+       .set_fmt = aic3262_set_dai_fmt,
+       .set_pll = aic3262_dai_set_pll,
+};
+
+struct snd_soc_dai_driver aic326x_dai_driver[] = {
+       {
+               .name = "aic326x-asi1",
+               .playback = {
+                       .stream_name = "ASI1 Playback",
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = AIC3262_RATES,
+                       .formats = AIC3262_FORMATS,
+               },
+               .capture = {
+                       .stream_name = "ASI1 Capture",
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = AIC3262_RATES,
+                       .formats = AIC3262_FORMATS,
+               },
+               .ops = &aic3262_asi1_dai_ops,
+       },
+       {
+               .name = "aic326x-asi2",
+               .playback = {
+                       .stream_name = "ASI2 Playback",
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = AIC3262_RATES,
+                       .formats = AIC3262_FORMATS,
+               },
+               .capture = {
+                       .stream_name = "ASI2 Capture",
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = AIC3262_RATES,
+                       .formats = AIC3262_FORMATS,
+               },
+               .ops = &aic3262_asi2_dai_ops,
+       },
+       {
+               .name = "aic326x-asi3",
+               .playback = {
+                       .stream_name = "ASI3 Playback",
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = AIC3262_RATES,
+                       .formats = AIC3262_FORMATS,
+               },
+               .capture = {
+                       .stream_name = "ASI3 Capture",
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = AIC3262_RATES,
+                       .formats = AIC3262_FORMATS,
+               },
+               .ops = &aic3262_asi3_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 */
+};
+
+static const unsigned int adc_ma_tlv[] = {
+       TLV_DB_RANGE_HEAD(4),
+       0, 29, TLV_DB_SCALE_ITEM(-1450, 500, 0),
+       30, 35, TLV_DB_SCALE_ITEM(-2060, 1000, 0),
+       36, 38, TLV_DB_SCALE_ITEM(-2660, 2000, 0),
+       39, 40, TLV_DB_SCALE_ITEM(-3610, 5000, 0),
+};
+static const DECLARE_TLV_DB_SCALE(lo_hp_tlv, -7830, 50, 0);
+static const struct snd_kcontrol_new mal_pga_mixer_controls[] = {
+       SOC_DAPM_SINGLE("IN1L Switch", AIC3262_MA_CNTL, 5, 1, 0),
+       SOC_DAPM_SINGLE_TLV("Left MicPGA Volume", AIC3262_LADC_PGA_MAL_VOL, 0, 0x3f, 1, adc_ma_tlv),
+
+};
+
+static const struct snd_kcontrol_new mar_pga_mixer_controls[] = {
+       SOC_DAPM_SINGLE("IN1R Switch", AIC3262_MA_CNTL, 4, 1, 0),
+       SOC_DAPM_SINGLE_TLV("Right MicPGA Volume", AIC3262_RADC_PGA_MAR_VOL, 0, 0x3f, 1, adc_ma_tlv),
+};
+
+/* Left HPL Mixer */
+static const struct snd_kcontrol_new hpl_output_mixer_controls[] = {
+       SOC_DAPM_SINGLE("MAL Switch", AIC3262_HP_AMP_CNTL_R1, 7, 1, 0),
+       SOC_DAPM_SINGLE("LDAC Switch", AIC3262_HP_AMP_CNTL_R1, 5, 1, 0),
+       SOC_DAPM_SINGLE_TLV("LOL-B1 Volume", AIC3262_HP_AMP_CNTL_R2, 0, 0x7f, 1, lo_hp_tlv),
+};
+
+/* Right HPR Mixer */
+static const struct snd_kcontrol_new hpr_output_mixer_controls[] = {
+       SOC_DAPM_SINGLE_TLV("LOR-B1 Volume", AIC3262_HP_AMP_CNTL_R3, 0, 0x7f, 1, lo_hp_tlv),
+       SOC_DAPM_SINGLE("LDAC Switch", AIC3262_HP_AMP_CNTL_R1,   2, 1, 0),
+       SOC_DAPM_SINGLE("RDAC Switch", AIC3262_HP_AMP_CNTL_R1, 4, 1, 0),
+       SOC_DAPM_SINGLE("MAR Switch", AIC3262_HP_AMP_CNTL_R1, 6, 1, 0),
+};
+
+/* Left LOL Mixer */
+static const struct snd_kcontrol_new lol_output_mixer_controls[] = {
+       SOC_DAPM_SINGLE("MAL Switch", AIC3262_LINE_AMP_CNTL_R2, 7, 1, 0),
+       SOC_DAPM_SINGLE("IN1L-B Switch", AIC3262_LINE_AMP_CNTL_R2, 3, 1,0),
+       SOC_DAPM_SINGLE("LDAC Switch", AIC3262_LINE_AMP_CNTL_R1, 7, 1, 0),
+       SOC_DAPM_SINGLE("RDAC Switch", AIC3262_LINE_AMP_CNTL_R1, 5, 1, 0),
+};
+
+/* Right LOR Mixer */
+static const struct snd_kcontrol_new lor_output_mixer_controls[] = {
+       SOC_DAPM_SINGLE("LOL Switch", AIC3262_LINE_AMP_CNTL_R1, 2, 1, 0),
+       SOC_DAPM_SINGLE("RDAC Switch", AIC3262_LINE_AMP_CNTL_R1, 6, 1, 0),
+       SOC_DAPM_SINGLE("MAR Switch", AIC3262_LINE_AMP_CNTL_R2, 6, 1, 0),
+       SOC_DAPM_SINGLE("IN1R-B Switch", AIC3262_LINE_AMP_CNTL_R2, 0, 1,0),
+};
+
+/* Left SPKL Mixer */
+static const struct snd_kcontrol_new spkl_output_mixer_controls[] = {
+       SOC_DAPM_SINGLE("MAL Switch", AIC3262_SPK_AMP_CNTL_R1, 7, 1, 0),
+       SOC_DAPM_SINGLE_TLV("LOL Volume", AIC3262_SPK_AMP_CNTL_R2, 0, 0x7f,1, lo_hp_tlv),
+       SOC_DAPM_SINGLE("SPR_IN Switch", AIC3262_SPK_AMP_CNTL_R1, 2, 1, 0),
+};
+
+/* Right SPKR Mixer */
+static const struct snd_kcontrol_new spkr_output_mixer_controls[] = {
+       SOC_DAPM_SINGLE_TLV("LOR Volume", AIC3262_SPK_AMP_CNTL_R3, 0, 0x7f, 1, lo_hp_tlv),
+       SOC_DAPM_SINGLE("MAR Switch", AIC3262_SPK_AMP_CNTL_R1, 6, 1, 0),
+};
+
+/* REC Mixer */
+static const struct snd_kcontrol_new rec_output_mixer_controls[] = {
+       SOC_DAPM_SINGLE_TLV("LOL-B2 Volume", AIC3262_RAMP_CNTL_R1, 0, 0x7f,1, lo_hp_tlv),
+       SOC_DAPM_SINGLE_TLV("IN1L Volume", AIC3262_IN1L_SEL_RM, 0, 0x7f, 1, lo_hp_tlv),
+       SOC_DAPM_SINGLE_TLV("IN1R Volume", AIC3262_IN1R_SEL_RM, 0, 0x7f, 1, lo_hp_tlv),
+       SOC_DAPM_SINGLE_TLV("LOR-B2 Volume", AIC3262_RAMP_CNTL_R2, 0,0x7f, 1,lo_hp_tlv),
+};
+
+/* Left Input Mixer */
+static const struct snd_kcontrol_new left_input_mixer_controls[] = {
+       SOC_DAPM_SINGLE("IN1L Switch", AIC3262_LMIC_PGA_PIN, 6, 3, 0),
+       SOC_DAPM_SINGLE("IN2L Switch", AIC3262_LMIC_PGA_PIN, 4, 3, 0),
+       SOC_DAPM_SINGLE("IN3L Switch", AIC3262_LMIC_PGA_PIN, 2, 3, 0),
+       SOC_DAPM_SINGLE("IN4L Switch", AIC3262_LMIC_PGA_PM_IN4, 5, 1, 0),
+       SOC_DAPM_SINGLE("IN1R Switch", AIC3262_LMIC_PGA_PIN, 0, 3, 0),
+       SOC_DAPM_SINGLE("IN2R Switch", AIC3262_LMIC_PGA_MIN, 4, 3, 0),
+       SOC_DAPM_SINGLE("IN3R Switch", AIC3262_LMIC_PGA_MIN, 2, 3, 0),
+       SOC_DAPM_SINGLE("IN4R Switch", AIC3262_LMIC_PGA_PM_IN4, 4, 1, 0),
+       SOC_DAPM_SINGLE("CM2L Switch", AIC3262_LMIC_PGA_MIN, 0, 3, 0),  
+       SOC_DAPM_SINGLE("CM1L Switch", AIC3262_LMIC_PGA_MIN, 6, 3, 0),
+};
+
+/* Right Input Mixer */
+static const struct snd_kcontrol_new right_input_mixer_controls[] = {
+       SOC_DAPM_SINGLE("IN1R Switch", AIC3262_RMIC_PGA_PIN, 6, 3, 0),
+       SOC_DAPM_SINGLE("IN2R Switch", AIC3262_RMIC_PGA_PIN, 4, 3, 0),
+       SOC_DAPM_SINGLE("IN3R Switch", AIC3262_RMIC_PGA_PIN, 2, 3, 0),
+       SOC_DAPM_SINGLE("IN4R Switch", AIC3262_RMIC_PGA_PM_IN4, 5, 1, 0),
+       SOC_DAPM_SINGLE("IN2L Switch", AIC3262_RMIC_PGA_PIN, 0, 3, 0),
+       SOC_DAPM_SINGLE("IN1L Switch", AIC3262_RMIC_PGA_MIN, 4, 3, 0),
+       SOC_DAPM_SINGLE("IN3L Switch", AIC3262_RMIC_PGA_MIN, 2, 3, 0),
+       SOC_DAPM_SINGLE("IN4L Switch", AIC3262_RMIC_PGA_PM_IN4, 4, 1, 0),
+       SOC_DAPM_SINGLE("CM1R Switch", AIC3262_RMIC_PGA_MIN, 6, 3, 0),
+       SOC_DAPM_SINGLE("CM2R Switch", AIC3262_RMIC_PGA_MIN, 0, 3, 0),
+};
+
+static const char *asi1lin_text[] = {                                                                                                                       
+       "Off", "ASI1 Left In","ASI1 Right In","ASI1 MonoMix In"
+};                                                                                                                                                           
+
+
+SOC_ENUM_SINGLE_DECL(asi1lin_enum, AIC3262_ASI1_DAC_OUT_CNTL, 6, asi1lin_text);
+
+static const struct snd_kcontrol_new asi1lin_control =                                                                                                       
+SOC_DAPM_ENUM("ASI1LIN Route", asi1lin_enum);      
+
+
+static const char *asi1rin_text[] = {                                                                                                                       
+       "Off", "ASI1 Right In","ASI1 Left In","ASI1 MonoMix In"
+};                                                                                                                                                           
+
+SOC_ENUM_SINGLE_DECL(asi1rin_enum, AIC3262_ASI1_DAC_OUT_CNTL, 4, asi1rin_text);
+
+static const struct snd_kcontrol_new asi1rin_control =                                                                                                       
+SOC_DAPM_ENUM("ASI1RIN Route", asi1rin_enum);      
+
+static const char *asi2lin_text[] = {                                                                                                                       
+       "Off", "ASI2 Left In","ASI2 Right In","ASI2 MonoMix In"
+};                                                                                                                                                           
+
+SOC_ENUM_SINGLE_DECL(asi2lin_enum, AIC3262_ASI2_DAC_OUT_CNTL, 6, asi2lin_text);
+
+static const struct snd_kcontrol_new asi2lin_control =                                                                                                       
+SOC_DAPM_ENUM("ASI2LIN Route", asi2lin_enum);      
+
+static const char *asi2rin_text[] = {                                                                                                                       
+       "Off", "ASI2 Right In","ASI2 Left In","ASI2 MonoMix In"
+};                                                                                                                                                           
+
+SOC_ENUM_SINGLE_DECL(asi2rin_enum, AIC3262_ASI2_DAC_OUT_CNTL, 4, asi2rin_text);
+
+static const struct snd_kcontrol_new asi2rin_control =                                                                                                        
+SOC_DAPM_ENUM("ASI2RIN Route", asi2rin_enum);      
+
+static const char *asi3lin_text[] = {                                                                                                                       
+       "Off", "ASI3 Left In","ASI3 Right In","ASI3 MonoMix In"
+};                                                                                                                                                           
+
+SOC_ENUM_SINGLE_DECL(asi3lin_enum, AIC3262_ASI3_DAC_OUT_CNTL, 6, asi3lin_text);
+
+static const struct snd_kcontrol_new asi3lin_control =                                                                                                                SOC_DAPM_ENUM("ASI3LIN Route", asi3lin_enum);      
+
+
+static const char *asi3rin_text[] = {                                                                                                                       
+       "Off", "ASI3 Right In","ASI3 Left In","ASI3 MonoMix In"
+};                                                                                                                                                           
+
+SOC_ENUM_SINGLE_DECL(asi3rin_enum, AIC3262_ASI3_DAC_OUT_CNTL, 4, asi3rin_text);
+
+static const struct snd_kcontrol_new asi3rin_control =                                                                                                       
+SOC_DAPM_ENUM("ASI3RIN Route", asi3rin_enum);      
+
+
+static const char *dacminidspin1_text[] = {                                                                                                       
+       "ASI1 In", "ASI2 In","ASI3 In","ADC MiniDSP Out"
+};                                                                                                                                                           
+
+SOC_ENUM_SINGLE_DECL(dacminidspin1_enum, AIC3262_MINIDSP_DATA_PORT_CNTL, 4, dacminidspin1_text); 
+
+static const struct snd_kcontrol_new dacminidspin1_control =                                                                                                
+SOC_DAPM_ENUM("DAC MiniDSP IN1 Route", dacminidspin1_enum);      
+
+static const char *dacminidspin2_text[] = {                                                                                                       
+       "ASI1 In", "ASI2 In","ASI3 In"
+};                                                                                                                                                           
+
+SOC_ENUM_SINGLE_DECL(dacminidspin2_enum, AIC3262_MINIDSP_DATA_PORT_CNTL, 2, dacminidspin2_text); 
+
+static const struct snd_kcontrol_new dacminidspin2_control =                                                                                                
+SOC_DAPM_ENUM("DAC MiniDSP IN2 Route", dacminidspin2_enum);      
+
+static const char *dacminidspin3_text[] = {                                                                                                       
+       "ASI1 In", "ASI2 In","ASI3 In"
+};                                                                                                                                                           
+
+SOC_ENUM_SINGLE_DECL(dacminidspin3_enum, AIC3262_MINIDSP_DATA_PORT_CNTL, 0, dacminidspin3_text); 
+
+static const struct snd_kcontrol_new dacminidspin3_control =                                                                                                
+SOC_DAPM_ENUM("DAC MiniDSP IN3 Route", dacminidspin3_enum);      
+
+
+static const char *adcdac_route_text[] = {
+       "Off",
+       "On",
+};
+
+SOC_ENUM_SINGLE_DECL(adcdac_enum, 0, 2, adcdac_route_text);
+       
+static const struct snd_kcontrol_new adcdacroute_control =
+       SOC_DAPM_ENUM_VIRT("ADC DAC Route", adcdac_enum);
+
+static const char *dout1_text[] = {                                                                                                                       
+       "ASI1 Out",
+       "DIN1 Bypass",
+       "DIN2 Bypass",
+       "DIN3 Bypass",
+};                                                                                                                                                           
+SOC_ENUM_SINGLE_DECL(dout1_enum, AIC3262_ASI1_DOUT_CNTL, 0, dout1_text);
+static const struct snd_kcontrol_new dout1_control =                                                                                                
+SOC_DAPM_ENUM("DOUT1 Route", dout1_enum);      
+
+
+static const char *dout2_text[] = {                                                                                                                       
+       "ASI2 Out",
+       "DIN1 Bypass",
+       "DIN2 Bypass",
+       "DIN3 Bypass",
+};                                                                                                                                                           
+SOC_ENUM_SINGLE_DECL(dout2_enum, AIC3262_ASI2_DOUT_CNTL, 0, dout2_text);
+static const struct snd_kcontrol_new dout2_control =                                                                                                
+SOC_DAPM_ENUM("DOUT2 Route", dout2_enum);      
+
+
+static const char *dout3_text[] = {                                                                                                                       
+       "ASI3 Out",
+       "DIN1 Bypass",
+       "DIN2 Bypass",
+       "DIN3 Bypass",
+};                                                                                                                                                           
+SOC_ENUM_SINGLE_DECL(dout3_enum, AIC3262_ASI3_DOUT_CNTL, 0, dout3_text);
+static const struct snd_kcontrol_new dout3_control =                                                                                                
+SOC_DAPM_ENUM("DOUT3 Route", dout3_enum);      
+
+static const char *asi1out_text[] = {                                                                                                                       
+       "Off",
+       "ADC MiniDSP Out1",
+       "ASI1In Bypass",
+       "ASI2In Bypass",
+       "ASI3In Bypass",
+};                                                                                                                                                           
+SOC_ENUM_SINGLE_DECL(asi1out_enum, AIC3262_ASI1_ADC_INPUT_CNTL, 0, asi1out_text);
+static const struct snd_kcontrol_new asi1out_control =                                                                                                
+SOC_DAPM_ENUM("ASI1OUT Route", asi1out_enum);      
+
+static const char *asi2out_text[] = {                                                                                                                       
+       "Off",
+       "ADC MiniDSP Out1",
+       "ASI1In Bypass",
+       "ASI2In Bypass",
+       "ASI3In Bypass",
+       "ADC MiniDSP Out2",
+};                                                                                                                                                           
+SOC_ENUM_SINGLE_DECL(asi2out_enum, AIC3262_ASI2_ADC_INPUT_CNTL, 0, asi2out_text);
+static const struct snd_kcontrol_new asi2out_control =                                                                                                
+SOC_DAPM_ENUM("ASI2OUT Route", asi2out_enum);      
+static const char *asi3out_text[] = {                                                                                                                       
+       "Off",
+       "ADC MiniDSP Out1",
+       "ASI1In Bypass",
+       "ASI2In Bypass",
+       "ASI3In Bypass",
+       "Reserved",
+       "ADC MiniDSP Out3",
+};                                                                                                                                                           
+SOC_ENUM_SINGLE_DECL(asi3out_enum, AIC3262_ASI3_ADC_INPUT_CNTL, 0, asi3out_text);
+static const struct snd_kcontrol_new asi3out_control =                                                                                                
+SOC_DAPM_ENUM("ASI3OUT Route", asi3out_enum);      
+static const char *asibclk_text[] = {                                                                                                                       
+       "DAC_CLK",
+       "DAC_MOD_CLK",
+       "ADC_CLK",
+       "ADC_MOD_CLK",
+};                                                                                                                                                           
+SOC_ENUM_SINGLE_DECL(asi1bclk_enum, AIC3262_ASI1_BCLK_N_CNTL, 0, asibclk_text);
+static const struct snd_kcontrol_new asi1bclk_control =                                                                                                
+SOC_DAPM_ENUM("ASI1_BCLK Route", asi1bclk_enum);      
+
+/*static const char *asi2bclk_text[] = {                                                                                                                       
+       "DAC_CLK",
+       "DAC_MOD_CLK",
+       "ADC_CLK",
+       "ADC_MOD_CLK",
+}; */                                                                                                                                                          
+SOC_ENUM_SINGLE_DECL(asi2bclk_enum, AIC3262_ASI2_BCLK_N_CNTL, 0, asibclk_text);
+static const struct snd_kcontrol_new asi2bclk_control =                                                                                                
+SOC_DAPM_ENUM("ASI2_BCLK Route", asi2bclk_enum);      
+/*static const char *asi3bclk_text[] = {                                                                                                                       
+       "DAC_CLK",
+       "DAC_MOD_CLK",
+       "ADC_CLK",
+       "ADC_MOD_CLK",
+};*/                                                                                                                                                           
+SOC_ENUM_SINGLE_DECL(asi3bclk_enum, AIC3262_ASI3_BCLK_N_CNTL, 0, asibclk_text);
+static const struct snd_kcontrol_new asi3bclk_control =                                                                                                
+SOC_DAPM_ENUM("ASI3_BCLK Route", asi3bclk_enum);      
+
+static const char *adc_mux_text[] = {
+       "Analog",
+       "Digital",
+};
+
+SOC_ENUM_SINGLE_DECL(adcl_enum, AIC3262_ADC_CHANNEL_POW, 4, adc_mux_text); 
+SOC_ENUM_SINGLE_DECL(adcr_enum, AIC3262_ADC_CHANNEL_POW, 2, adc_mux_text); 
+
+static const struct snd_kcontrol_new adcl_mux =
+       SOC_DAPM_ENUM("Left ADC Route", adcl_enum);
+
+static const struct snd_kcontrol_new adcr_mux =
+       SOC_DAPM_ENUM("Right ADC Route", adcr_enum);
+
+/*static const char *dmicinput_text[] = {
+       "GPI1",
+       "GPI2",
+       "DIN1",
+       "DIN2",
+       "GPIO1",
+       "GPIO2",
+       "MCLK2",
+};
+SOC_ENUM_SINGLE_DECL(dmicinput_enum, AIC3262_DMIC_INPUT_CNTL, 0, dmicinput_text); 
+
+static const struct snd_kcontrol_new dmicinput_control =
+       SOC_DAPM_ENUM("DMICDAT Input Route",  dmicinput_enum);
+*/
+static int aic326x_hp_event(struct snd_soc_dapm_widget *w,
+               struct snd_kcontrol *kcontrol, int event)
+{
+       int status;
+       int count=20;
+       int reg_mask = 0;
+       if(w->shift == 1) {// Left HPL
+               reg_mask = AIC3262_HPL_POWER_MASK;
+       }
+       if(w->shift == 0) { // Right HPR
+               reg_mask = AIC3262_HPR_POWER_MASK;
+       }
+       switch(event){
+       case SND_SOC_DAPM_POST_PMU:
+               do
+               {
+                       status = snd_soc_read(w->codec,AIC3262_HP_FLAG);
+                       count--;
+
+               }while(((status & reg_mask) == 0x00) && count != 0 ); //wait until hp powered up
+               break;
+       case SND_SOC_DAPM_POST_PMD:
+               do
+               {
+                       status = snd_soc_read(w->codec,AIC3262_HP_FLAG);
+                       count--;
+
+               }while(((status & reg_mask) == reg_mask) && count != 0 ); //wait until hp powered down
+               break;
+       default:
+               BUG();
+               return -EINVAL;
+       }
+       return 0;
+}
+
+/***********************************************************************
+Arguments     : pointer variable to dapm_widget,
+               pointer variable to sound control,
+               integer to event
+Return value  : 0
+Purpose              : Headset popup reduction and powering up dsps together 
+               when they are in sync mode  
+************************************************************************/
+static int aic326x_dac_event(struct snd_soc_dapm_widget *w,
+               struct snd_kcontrol *kcontrol, int event)
+{
+       int status;
+       int count=20;
+       int reg_mask = 0;
+       int run_state_mask;
+       struct aic3262_priv *aic3262 = snd_soc_codec_get_drvdata(w->codec);
+       int sync_needed = 0, non_sync_state =0;
+       int other_dsp = 0, run_state = 0;
+
+
+       if(w->shift == 7) {// Left DAC
+               reg_mask = AIC3262_LDAC_POWER_MASK;
+               run_state_mask = AIC3262_COPS_MDSP_D_L;
+       }
+       if (w->shift == 6) { // Right DAC
+               reg_mask = AIC3262_RDAC_POWER_MASK;
+               run_state_mask = AIC3262_COPS_MDSP_D_R;
+       }
+       switch(event){
+       case SND_SOC_DAPM_POST_PMU:
+               do
+               {
+                       status = snd_soc_read(w->codec, AIC3262_DAC_FLAG);
+                       count--;
+               } while(((status & reg_mask) == 0)&& count != 0);
+
+               sync_needed     =       SYNC_STATE(aic3262);
+               non_sync_state  =       DSP_NON_SYNC_MODE(aic3262->dsp_runstate);
+               other_dsp       =       aic3262->dsp_runstate & AIC3262_COPS_MDSP_A;
+
+               if( sync_needed && non_sync_state && other_dsp )
+               {
+                       run_state = get_runstate(aic3262->codec->control_data);
+                       aic3262_dsp_pwrdwn_status(aic3262);  
+                       aic3262_dsp_pwrup(aic3262,run_state);    
+               }       
+               aic3262->dsp_runstate  |= run_state_mask;
+               break;
+       case SND_SOC_DAPM_POST_PMD:
+               do
+               {
+                       status = snd_soc_read(w->codec, AIC3262_DAC_FLAG);
+                       count--;
+               } while(((status & reg_mask) == reg_mask)&& count != 0);
+       
+               aic3262->dsp_runstate = (aic3262->dsp_runstate & ~run_state_mask);
+               break;
+       default:
+               BUG();
+               return -EINVAL;
+       }
+       return 0;
+}
+
+
+
+static int aic326x_spk_event(struct snd_soc_dapm_widget *w,
+               struct snd_kcontrol *kcontrol, int event)
+{
+       int status;
+       int count=20;
+       int reg_mask;
+
+       if(w->shift == 1) {// Left SPK
+               reg_mask = AIC3262_SPKL_POWER_MASK;
+       }
+       if(w->shift == 0) { // Right SPK
+               reg_mask = AIC3262_SPKR_POWER_MASK;
+       }
+       switch(event){
+       case SND_SOC_DAPM_POST_PMU:
+               do
+               {
+                       status = snd_soc_read(w->codec,AIC3262_HP_FLAG);
+                       count--;
+
+               }while(((status & reg_mask) == 0x00) && count != 0 ); //wait until spk powered up
+               break;
+       case SND_SOC_DAPM_POST_PMD:
+               do
+               {
+                       status = snd_soc_read(w->codec,AIC3262_HP_FLAG);
+                       count--;
+
+               }while(((status & reg_mask) == reg_mask) && count != 0 ); //wait until spk powered up
+               break;
+       default:
+               BUG();
+               return -EINVAL;
+       }
+       return 0;
+}
+static int pll_power_on_event(struct snd_soc_dapm_widget *w,
+               struct snd_kcontrol *kcontrol, int event)
+{
+       if(event == SND_SOC_DAPM_POST_PMU)
+       {
+               mdelay(10);
+       }       
+       return 0;
+}
+static int aic3262_test_get(struct snd_kcontrol *kcontrol,
+               struct snd_ctl_elem_value *ucontrol)
+{
+
+       return 0;
+}
+
+static int aic3262_test_put(struct snd_kcontrol *kcontrol,
+               struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+
+       request_firmware_nowait(THIS_MODULE, FW_ACTION_HOTPLUG,
+                       "tlv320aic3262_fw_v1.bin", codec->dev, GFP_KERNEL,
+                       codec, aic3262_firmware_load);
+
+       return 0;
+}
+
+static int aic3262_set_mode_get(struct snd_kcontrol *kcontrol,
+               struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct aic3262_priv *priv_ds = snd_soc_codec_get_drvdata(codec);
+
+       return 0;
+}
+
+static int aic3262_set_mode_put(struct snd_kcontrol *kcontrol,
+               struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct aic3262_priv *priv_ds = snd_soc_codec_get_drvdata(codec);
+
+       int next_mode=0,next_cfg=0;
+
+       next_mode = (ucontrol->value.integer.value[0]>>8);
+       next_cfg = (ucontrol->value.integer.value[0])&0xFF;
+       if (priv_ds==NULL)
+       {       
+               dev_err(codec->dev,"\nFirmware not loaded, no mode switch can occur\n");
+       }
+       else
+       {
+                mutex_lock(&priv_ds->cfw_mutex);
+               aic3xxx_cfw_setmode_cfg(priv_ds->cfw_p,next_mode,next_cfg);
+                mutex_unlock(&priv_ds->cfw_mutex);
+       }
+
+       return 0;
+}
+static int aic326x_adc_dsp_event(struct snd_soc_dapm_widget *w,struct snd_kcontrol *kcontrol, int event)
+{
+       int run_state=0;
+       int non_sync_state = 0,sync_needed = 0;
+       int other_dsp = 0;
+       int run_state_mask = 0;
+       struct aic3262_priv *aic3262 = snd_soc_codec_get_drvdata(w->codec);
+
+       if(w->shift == 7) {// Left ADC
+               run_state_mask = AIC3262_COPS_MDSP_A_L;
+       }
+       if (w->shift == 6) { // Right ADC
+               run_state_mask = AIC3262_COPS_MDSP_A_R;
+       }
+       switch(event){
+               case SND_SOC_DAPM_POST_PMU:
+                       sync_needed     = SYNC_STATE(aic3262);
+                       non_sync_state  = DSP_NON_SYNC_MODE(aic3262->dsp_runstate);
+                       other_dsp       = aic3262->dsp_runstate & AIC3262_COPS_MDSP_D;
+                       if( sync_needed && non_sync_state && other_dsp ){
+                               run_state = get_runstate(aic3262->codec->control_data);
+                               aic3262_dsp_pwrdwn_status(aic3262);  
+                               aic3262_dsp_pwrup(aic3262,run_state);    
+                       }       
+                       aic3262->dsp_runstate  |= run_state_mask;
+                       break;
+               case SND_SOC_DAPM_POST_PMD:
+                       aic3262->dsp_runstate = (aic3262->dsp_runstate & ~run_state_mask) ;
+                       break;
+               default:
+                       BUG();
+                       return -EINVAL;
+       }
+       return 0;
+}
+
+static const struct snd_soc_dapm_widget aic3262_dapm_widgets[] = {
+       /* TODO: Can we switch these off ? */
+       SND_SOC_DAPM_AIF_IN("DIN1", "ASI1 Playback", 0, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_AIF_IN("DIN2", "ASI2 Playback", 0, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_AIF_IN("DIN3", "ASI3 Playback", 0, SND_SOC_NOPM, 0, 0),
+
+       SND_SOC_DAPM_DAC_E("Left DAC", NULL, AIC3262_PASI_DAC_DP_SETUP, 7, 0,
+               aic326x_dac_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+       SND_SOC_DAPM_DAC_E("Right DAC", NULL, AIC3262_PASI_DAC_DP_SETUP, 6, 0,
+               aic326x_dac_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+
+       /* dapm widget (path domain) for HPL Output Mixer */
+       SND_SOC_DAPM_MIXER("HPL Output Mixer", SND_SOC_NOPM, 0, 0,
+                       &hpl_output_mixer_controls[0],
+                       ARRAY_SIZE(hpl_output_mixer_controls)),
+
+       /* dapm widget (path domain) for HPR Output Mixer */
+       SND_SOC_DAPM_MIXER("HPR Output Mixer", SND_SOC_NOPM, 0, 0,
+                       &hpr_output_mixer_controls[0],
+                       ARRAY_SIZE(hpr_output_mixer_controls)),
+
+
+       SND_SOC_DAPM_PGA_E("HPL Driver", AIC3262_HP_AMP_CNTL_R1, 1, 0, NULL, 0, aic326x_hp_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+       SND_SOC_DAPM_PGA_E("HPR Driver", AIC3262_HP_AMP_CNTL_R1, 0, 0, NULL, 0, aic326x_hp_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+
+       /* dapm widget (path domain) for LOL Output Mixer */
+       SND_SOC_DAPM_MIXER("LOL Output Mixer", SND_SOC_NOPM, 0, 0,
+                       &lol_output_mixer_controls[0],
+                       ARRAY_SIZE(lol_output_mixer_controls)),
+
+       /* dapm widget (path domain) for LOR Output Mixer mixer */
+       SND_SOC_DAPM_MIXER("LOR Output Mixer", SND_SOC_NOPM, 0, 0,
+                       &lor_output_mixer_controls[0],
+                       ARRAY_SIZE(lor_output_mixer_controls)),
+
+       SND_SOC_DAPM_PGA("LOL Driver", AIC3262_LINE_AMP_CNTL_R1, 1, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("LOR Driver", AIC3262_LINE_AMP_CNTL_R1, 0, 0, NULL, 0),
+
+
+       /* dapm widget (path domain) for SPKL Output Mixer */
+       SND_SOC_DAPM_MIXER("SPKL Output Mixer", SND_SOC_NOPM, 0, 0,
+                       &spkl_output_mixer_controls[0],
+                       ARRAY_SIZE(spkl_output_mixer_controls)),
+
+       /* dapm widget (path domain) for SPKR Output Mixer */
+       SND_SOC_DAPM_MIXER("SPKR Output Mixer", SND_SOC_NOPM, 0, 0,
+                       &spkr_output_mixer_controls[0],
+                       ARRAY_SIZE(spkr_output_mixer_controls)),
+
+       SND_SOC_DAPM_PGA_E("SPKL Driver",AIC3262_SPK_AMP_CNTL_R1, 1, 0, NULL, 0, 
+               aic326x_spk_event, SND_SOC_DAPM_POST_PMD | SND_SOC_DAPM_POST_PMU),
+       SND_SOC_DAPM_PGA_E("SPKR Driver", AIC3262_SPK_AMP_CNTL_R1, 0, 0, NULL, 0, 
+               aic326x_spk_event, SND_SOC_DAPM_POST_PMD | SND_SOC_DAPM_POST_PMU),
+
+
+       /* dapm widget (path domain) for SPKR Output Mixer */
+       SND_SOC_DAPM_MIXER("REC Output Mixer", SND_SOC_NOPM, 0, 0,
+                       &rec_output_mixer_controls[0],
+                       ARRAY_SIZE(rec_output_mixer_controls)),
+
+       SND_SOC_DAPM_PGA("RECP Driver", AIC3262_REC_AMP_CNTL_R5, 7, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("RECM Driver", AIC3262_REC_AMP_CNTL_R5, 6, 0, NULL, 0),
+
+
+       SND_SOC_DAPM_MUX("ASI1LIN Route",                                                                                                        
+                       SND_SOC_NOPM, 0, 0, &asi1lin_control),       
+       SND_SOC_DAPM_MUX("ASI1RIN Route",                                                                                                        
+                       SND_SOC_NOPM, 0, 0, &asi1rin_control),       
+       SND_SOC_DAPM_MUX("ASI2LIN Route",                                                                                                        
+                       SND_SOC_NOPM, 0, 0, &asi2lin_control),       
+       SND_SOC_DAPM_MUX("ASI2RIN Route",                                                                                                        
+                       SND_SOC_NOPM, 0, 0, &asi2rin_control),       
+       SND_SOC_DAPM_MUX("ASI3LIN Route",                                                                                                        
+                       SND_SOC_NOPM, 0, 0, &asi3lin_control),       
+       SND_SOC_DAPM_MUX("ASI3RIN Route",                                                                                                        
+                       SND_SOC_NOPM, 0, 0, &asi3rin_control),       
+
+       SND_SOC_DAPM_PGA("ASI1LIN", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("ASI1RIN", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("ASI2LIN", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("ASI2RIN", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("ASI3LIN", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("ASI3RIN", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("ASI1MonoMixIN", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("ASI2MonoMixIN", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("ASI3MonoMixIN", SND_SOC_NOPM, 0, 0, NULL, 0),
+       /* TODO: Can we switch the ASIxIN off? */
+       SND_SOC_DAPM_PGA("ASI1IN Port", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("ASI2IN Port", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("ASI3IN Port", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+       SND_SOC_DAPM_MUX("DAC MiniDSP IN1 Route",                                                                                                        
+                       SND_SOC_NOPM, 0, 0, &dacminidspin1_control),       
+       SND_SOC_DAPM_MUX("DAC MiniDSP IN2 Route",                                                                                                        
+                       SND_SOC_NOPM, 0, 0, &dacminidspin2_control),       
+       SND_SOC_DAPM_MUX("DAC MiniDSP IN3 Route",                                                                                                        
+                       SND_SOC_NOPM, 0, 0, &dacminidspin3_control),       
+
+       SND_SOC_DAPM_VIRT_MUX("ADC DAC Route",                                                                                                        
+                       SND_SOC_NOPM, 0, 0, &adcdacroute_control),       
+
+       SND_SOC_DAPM_PGA("CM", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("CM1L", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("CM2L", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("CM1R", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("CM2R", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+       /* TODO: Can we switch these off ? */
+       SND_SOC_DAPM_AIF_OUT("DOUT1","ASI1 Capture", 0, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_AIF_OUT("DOUT2", "ASI2 Capture",0, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_AIF_OUT("DOUT3", "ASI3 Capture",0, SND_SOC_NOPM, 0, 0),
+
+       SND_SOC_DAPM_MUX("DOUT1 Route",                                                                                                        
+                       SND_SOC_NOPM, 0, 0, &dout1_control),       
+       SND_SOC_DAPM_MUX("DOUT2 Route",                                                                                                        
+                       SND_SOC_NOPM, 0, 0, &dout2_control),       
+       SND_SOC_DAPM_MUX("DOUT3 Route",                                                                                                        
+                       SND_SOC_NOPM, 0, 0, &dout3_control),       
+
+       SND_SOC_DAPM_PGA("ASI1OUT",  SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("ASI2OUT",  SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("ASI3OUT",  SND_SOC_NOPM, 0, 0, NULL, 0),
+
+
+       SND_SOC_DAPM_MUX("ASI1OUT Route",                                                                                                        
+                       SND_SOC_NOPM, 0, 0, &asi1out_control),       
+       SND_SOC_DAPM_MUX("ASI2OUT Route",                                                                                                        
+                       SND_SOC_NOPM, 0, 0, &asi2out_control),       
+       SND_SOC_DAPM_MUX("ASI3OUT Route",                                                                                                        
+                       SND_SOC_NOPM, 0, 0, &asi3out_control),       
+
+       /* TODO: Can we switch the ASI1 OUT1 off? */
+       /* TODO: Can we switch them off? */
+       SND_SOC_DAPM_PGA("ADC MiniDSP OUT1", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("ADC MiniDSP OUT2", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("ADC MiniDSP OUT3", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+       ///M SND_SOC_DAPM_PGA("GPI1 PIN", SND_SOC_NOPM, 0, 0, NULL, 0),
+       ///M SND_SOC_DAPM_PGA("GPI2 PIN", SND_SOC_NOPM, 0, 0, NULL, 0),
+       ///M SND_SOC_DAPM_PGA("DIN1 PIN", SND_SOC_NOPM, 0, 0, NULL, 0),
+       ///M SND_SOC_DAPM_PGA("DIN2 PIN", SND_SOC_NOPM, 0, 0, NULL, 0),
+       ///M SND_SOC_DAPM_PGA("GPIO1 PIN", SND_SOC_NOPM, 0, 0, NULL, 0),
+       ///M SND_SOC_DAPM_PGA("GPIO2 PIN", SND_SOC_NOPM, 0, 0, NULL, 0),
+       ///M SND_SOC_DAPM_PGA("MCLK2 PIN", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+//     SND_SOC_DAPM_MUX("DMICDAT Input Route",                                                                                                        
+//                     SND_SOC_NOPM, 0, 0, &dmicinput_control),       
+
+       SND_SOC_DAPM_MUX("Left ADC Route", SND_SOC_NOPM,0, 0, &adcl_mux), 
+       SND_SOC_DAPM_MUX("Right ADC Route", SND_SOC_NOPM,0, 0, &adcr_mux), 
+
+       SND_SOC_DAPM_ADC_E("Left ADC", NULL, AIC3262_ADC_CHANNEL_POW, 7, 0, 
+               aic326x_adc_dsp_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+       SND_SOC_DAPM_ADC_E("Right ADC", NULL, AIC3262_ADC_CHANNEL_POW, 6, 0,
+               aic326x_adc_dsp_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+       SND_SOC_DAPM_PGA("Left MicPGA",AIC3262_MICL_PGA, 7, 1, NULL, 0),
+       SND_SOC_DAPM_PGA("Right MicPGA",AIC3262_MICR_PGA, 7, 1, NULL, 0),
+
+       SND_SOC_DAPM_PGA("MAL PGA", AIC3262_MA_CNTL, 3, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("MAR PGA", AIC3262_MA_CNTL, 2, 0, NULL, 0),
+
+       /* dapm widget for MAL PGA Mixer*/
+       SND_SOC_DAPM_MIXER("MAL PGA Mixer", SND_SOC_NOPM, 0, 0,
+                       &mal_pga_mixer_controls[0],
+                       ARRAY_SIZE(mal_pga_mixer_controls)),
+
+       /* dapm widget for MAR PGA Mixer*/
+       SND_SOC_DAPM_MIXER("MAR PGA Mixer", SND_SOC_NOPM, 0, 0,
+                       &mar_pga_mixer_controls[0],
+                       ARRAY_SIZE(mar_pga_mixer_controls)),
+
+       /* dapm widget for Left Input Mixer*/
+       SND_SOC_DAPM_MIXER("Left Input Mixer", SND_SOC_NOPM, 0, 0,
+                       &left_input_mixer_controls[0],
+                       ARRAY_SIZE(left_input_mixer_controls)),
+
+       /* dapm widget for Right Input Mixer*/
+       SND_SOC_DAPM_MIXER("Right Input Mixer", SND_SOC_NOPM, 0, 0,
+                       &right_input_mixer_controls[0],
+                       ARRAY_SIZE(right_input_mixer_controls)),
+
+       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("RECP"),
+       SND_SOC_DAPM_OUTPUT("RECM"),
+
+       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"),
+//     SND_SOC_DAPM_INPUT("DMICDAT"),
+       SND_SOC_DAPM_INPUT("Left DMIC"),
+       SND_SOC_DAPM_INPUT("Right DMIC"),
+
+
+       SND_SOC_DAPM_MICBIAS("Mic Bias Ext", AIC3262_MIC_BIAS_CNTL, 6, 0),    
+       SND_SOC_DAPM_MICBIAS("Mic Bias Int", AIC3262_MIC_BIAS_CNTL, 2, 0),    
+
+
+       SND_SOC_DAPM_SUPPLY("PLLCLK",AIC3262_PLL_PR_POW_REG,7,0,pll_power_on_event,SND_SOC_DAPM_POST_PMU),
+       SND_SOC_DAPM_SUPPLY("DACCLK",AIC3262_NDAC_DIV_POW_REG,7,0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY("CODEC_CLK_IN",SND_SOC_NOPM,0,0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY("DAC_MOD_CLK",AIC3262_MDAC_DIV_POW_REG,7,0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY("ADCCLK",AIC3262_NADC_DIV_POW_REG,7,0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY("ADC_MOD_CLK",AIC3262_MADC_DIV_POW_REG,7,0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY("ASI1_BCLK",AIC3262_ASI1_BCLK_N,7,0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY("ASI1_WCLK",AIC3262_ASI1_WCLK_N,7,0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY("ASI2_BCLK",AIC3262_ASI2_BCLK_N,7,0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY("ASI2_WCLK",AIC3262_ASI2_WCLK_N,7,0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY("ASI3_BCLK",AIC3262_ASI3_BCLK_N,7,0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY("ASI3_WCLK",AIC3262_ASI3_WCLK_N,7,0, NULL, 0),
+       SND_SOC_DAPM_MUX("ASI1_BCLK Route",                                                                                                        
+                       SND_SOC_NOPM, 0, 0, &asi1bclk_control),       
+       SND_SOC_DAPM_MUX("ASI2_BCLK Route",                                                                                                        
+                       SND_SOC_NOPM, 0, 0, &asi2bclk_control),       
+       SND_SOC_DAPM_MUX("ASI3_BCLK Route",                                                                                                        
+                       SND_SOC_NOPM, 0, 0, &asi3bclk_control),       
+};
+
+static const struct snd_soc_dapm_route aic3262_dapm_routes[] ={
+       /* TODO: Do we need only DACCLK for ASIIN's and ADCCLK for ASIOUT??? */
+       /* Clock portion */
+       {"CODEC_CLK_IN", NULL, "PLLCLK"},
+       {"DACCLK", NULL, "CODEC_CLK_IN"},
+       {"ADCCLK", NULL, "CODEC_CLK_IN"},
+       {"DAC_MOD_CLK", NULL, "DACCLK"},
+#ifdef AIC3262_SYNC_MODE
+       {"ADC_MOD_CLK", NULL,"DACCLK"},
+#else
+       {"ADC_MOD_CLK", NULL, "ADCCLK"},
+#endif
+
+       {"ASI1_BCLK Route","DAC_CLK","DACCLK"},
+       {"ASI1_BCLK Route","DAC_MOD_CLK","DAC_MOD_CLK"},
+       {"ASI1_BCLK Route","ADC_CLK","ADCCLK"},
+       {"ASI1_BCLK Route","ADC_MOD_CLK","ADC_MOD_CLK"},
+
+       {"ASI2_BCLK Route","DAC_CLK","DACCLK"},
+       {"ASI2_BCLK Route","DAC_MOD_CLK","DAC_MOD_CLK"},
+       {"ASI2_BCLK Route","ADC_CLK","ADCCLK"},
+       {"ASI2_BCLK Route","ADC_MOD_CLK","ADC_MOD_CLK"},
+
+       {"ASI3_BCLK Route","DAC_CLK","DACCLK"},
+       {"ASI3_BCLK Route","DAC_MOD_CLK","DAC_MOD_CLK"},
+       {"ASI3_BCLK Route","ADC_CLK","ADCCLK"},
+       {"ASI3_BCLK Route","ADC_MOD_CLK","ADC_MOD_CLK"},
+
+       {"ASI1_BCLK", NULL, "ASI1_BCLK Route"},
+       {"ASI2_BCLK", NULL, "ASI2_BCLK Route"},
+       {"ASI3_BCLK", NULL, "ASI3_BCLK Route"},
+
+
+       {"DIN1", NULL , "PLLCLK"},
+       {"DIN1", NULL , "DACCLK"},
+       {"DIN1", NULL , "ADCCLK"},
+       {"DIN1", NULL , "DAC_MOD_CLK"},
+       {"DIN1", NULL , "ADC_MOD_CLK"},
+
+       {"DOUT1", NULL , "PLLCLK"},
+       {"DOUT1", NULL , "DACCLK"},
+       {"DOUT1", NULL , "ADCCLK"},
+       {"DOUT1", NULL , "DAC_MOD_CLK"},
+       {"DOUT1", NULL , "ADC_MOD_CLK"},
+#ifdef AIC3262_ASI1_MASTER
+       {"DIN1", NULL , "ASI1_BCLK"},
+       {"DOUT1", NULL , "ASI1_BCLK"},
+       {"DIN1", NULL , "ASI1_WCLK"},
+       {"DOUT1", NULL , "ASI1_WCLK"},
+#else
+
+#endif
+
+       {"DIN2", NULL , "PLLCLK"},
+       {"DIN2", NULL , "DACCLK"},
+       {"DIN2", NULL , "ADCCLK"},
+       {"DIN2", NULL , "DAC_MOD_CLK"},
+       {"DIN2", NULL , "ADC_MOD_CLK"},
+
+       {"DOUT2", NULL , "PLLCLK"},
+       {"DOUT2", NULL , "DACCLK"},
+       {"DOUT2", NULL , "ADCCLK"},
+       {"DOUT2", NULL , "DAC_MOD_CLK"},
+       {"DOUT2", NULL , "ADC_MOD_CLK"},
+
+#ifdef AIC3262_ASI2_MASTER
+       {"DIN2", NULL , "ASI2_BCLK"},
+       {"DOUT2", NULL , "ASI2_BCLK"},
+       {"DIN2", NULL , "ASI2_WCLK"},
+       {"DOUT2", NULL , "ASI2_WCLK"},
+#else
+
+#endif
+       {"DIN3", NULL , "PLLCLK"},
+       {"DIN3", NULL , "DACCLK"},
+       {"DIN3", NULL , "ADCCLK"},
+       {"DIN3", NULL , "DAC_MOD_CLK"},
+       {"DIN3", NULL , "ADC_MOD_CLK"},
+
+
+       {"DOUT3", NULL , "PLLCLK"},
+       {"DOUT3", NULL , "DACCLK"},
+       {"DOUT3", NULL , "ADCCLK"},
+       {"DOUT3", NULL , "DAC_MOD_CLK"},
+       {"DOUT3", NULL , "ADC_MOD_CLK"},
+
+#ifdef AIC3262_ASI3_MASTER
+       {"DIN3", NULL , "ASI3_BCLK"},
+       {"DOUT3", NULL , "ASI3_BCLK"},
+       {"DIN3", NULL , "ASI3_WCLK"},
+       {"DOUT3", NULL , "ASI3_WCLK"},
+#else
+
+#endif
+       /* Playback (DAC) Portion */
+       {"HPL Output Mixer","LDAC Switch","Left DAC"},
+       {"HPL Output Mixer","MAL Switch","MAL PGA"},
+       {"HPL Output Mixer","LOL-B1 Volume","LOL"},
+
+       {"HPR Output Mixer","LOR-B1 Volume","LOR"},
+       {"HPR Output Mixer","LDAC Switch","Left DAC"},
+       {"HPR Output Mixer","RDAC Switch","Right DAC"},
+       {"HPR Output Mixer","MAR Switch","MAR PGA"},
+
+       {"HPL Driver",NULL,"HPL Output Mixer"},
+       {"HPR Driver",NULL,"HPR Output Mixer"},
+
+       {"HPL",NULL,"HPL Driver"},
+       {"HPR",NULL,"HPR Driver"},
+
+       {"LOL Output Mixer","MAL Switch","MAL PGA"},
+       {"LOL Output Mixer","IN1L-B Switch","IN1L"},
+       {"LOL Output Mixer","LDAC Switch","Left DAC"},
+       {"LOL Output Mixer","RDAC Switch","Right DAC"},
+
+       {"LOR Output Mixer","LOL Switch","LOL"},
+       {"LOR Output Mixer","RDAC Switch","Right DAC"},
+       {"LOR Output Mixer","MAR Switch","MAR PGA"},
+       {"LOR Output Mixer","IN1R-B Switch","IN1R"},
+
+       {"LOL Driver",NULL,"LOL Output Mixer"},
+       {"LOR Driver",NULL,"LOR Output Mixer"},
+
+       {"LOL",NULL,"LOL Driver"},
+       {"LOR",NULL,"LOR Driver"},
+
+       {"REC Output Mixer","LOL-B2 Volume","LOL"},
+       {"REC Output Mixer","IN1L Volume","IN1L"},
+       {"REC Output Mixer","IN1R Volume","IN1R"},
+       {"REC Output Mixer","LOR-B2 Volume","LOR"},
+
+       {"RECP Driver",NULL,"REC Output Mixer"},
+       {"RECM Driver",NULL,"REC Output Mixer"},
+
+       {"RECP",NULL,"RECP Driver"},
+       {"RECM",NULL,"RECM Driver"},
+
+       {"SPKL Output Mixer","MAL Switch","MAL PGA"},
+       {"SPKL Output Mixer","LOL Volume","LOL"},
+       {"SPKL Output Mixer","SPR_IN Switch","SPKR Output Mixer"},
+
+       {"SPKR Output Mixer", "LOR Volume","LOR"},
+       {"SPKR Output Mixer", "MAR Switch","MAR PGA"},
+
+
+       {"SPKL Driver",NULL,"SPKL Output Mixer"},
+       {"SPKR Driver",NULL,"SPKR Output Mixer"},
+
+       {"SPKL",NULL,"SPKL Driver"},
+       {"SPKR",NULL,"SPKR Driver"},
+       /* ASI Input routing */
+       {"ASI1LIN", NULL, "DIN1"},
+       {"ASI1RIN", NULL, "DIN1"},
+       {"ASI1MonoMixIN", NULL, "DIN1"},
+       {"ASI2LIN", NULL, "DIN2"},
+       {"ASI2RIN", NULL, "DIN2"},
+       {"ASI2MonoMixIN", NULL, "DIN2"},
+       {"ASI3LIN", NULL, "DIN3"},
+       {"ASI3RIN", NULL, "DIN3"},
+       {"ASI3MonoMixIN", NULL, "DIN3"},
+
+       {"ASI1LIN Route","ASI1 Left In","ASI1LIN"},
+       {"ASI1LIN Route","ASI1 Right In","ASI1RIN"},
+       {"ASI1LIN Route","ASI1 MonoMix In","ASI1MonoMixIN"},
+
+       {"ASI1RIN Route","ASI1 Right In","ASI1RIN"},
+       {"ASI1RIN Route","ASI1 Left In","ASI1LIN"},
+       {"ASI1RIN Route","ASI1 MonoMix In","ASI1MonoMixIN"},
+
+
+       {"ASI2LIN Route","ASI2 Left In","ASI2LIN"},
+       {"ASI2LIN Route","ASI2 Right In","ASI2RIN"},
+       {"ASI2LIN Route","ASI2 MonoMix In","ASI2MonoMixIN"},
+
+       {"ASI2RIN Route","ASI2 Right In","ASI2RIN"},
+       {"ASI2RIN Route","ASI2 Left In","ASI2LIN"},
+       {"ASI2RIN Route","ASI2 MonoMix In","ASI2MonoMixIN"},
+
+
+       {"ASI3LIN Route","ASI3 Left In","ASI3LIN"},
+       {"ASI3LIN Route","ASI3 Right In","ASI3RIN"},
+       {"ASI3LIN Route","ASI3 MonoMix In","ASI3MonoMixIN"},
+
+       {"ASI3RIN Route","ASI3 Right In","ASI3RIN"},
+       {"ASI3RIN Route","ASI3 Left In","ASI3LIN"},
+       {"ASI3RIN Route","ASI3 MonoMix In","ASI3MonoMixIN"},
+
+       {"ASI1IN Port", NULL, "ASI1LIN Route"},
+       {"ASI1IN Port", NULL, "ASI1RIN Route"},
+       {"ASI2IN Port", NULL, "ASI2LIN Route"},
+       {"ASI2IN Port", NULL, "ASI2RIN Route"},
+       {"ASI3IN Port", NULL, "ASI3LIN Route"},
+       {"ASI3IN Port", NULL, "ASI3RIN Route"},
+
+       {"DAC MiniDSP IN1 Route","ASI1 In","ASI1IN Port"},
+       {"DAC MiniDSP IN1 Route","ASI2 In","ASI2IN Port"},
+       {"DAC MiniDSP IN1 Route","ASI3 In","ASI3IN Port"},
+       {"DAC MiniDSP IN1 Route","ADC MiniDSP Out","ADC MiniDSP OUT1"},
+
+       {"DAC MiniDSP IN2 Route","ASI1 In","ASI1IN Port"},
+       {"DAC MiniDSP IN2 Route","ASI2 In","ASI2IN Port"},
+       {"DAC MiniDSP IN2 Route","ASI3 In","ASI3IN Port"},
+
+       {"DAC MiniDSP IN3 Route","ASI1 In","ASI1IN Port"},
+       {"DAC MiniDSP IN3 Route","ASI2 In","ASI2IN Port"},
+       {"DAC MiniDSP IN3 Route","ASI3 In","ASI3IN Port"},
+
+
+       {"Left DAC", "NULL","DAC MiniDSP IN1 Route"},   
+       {"Right DAC", "NULL","DAC MiniDSP IN1 Route"},  
+       {"Left DAC", "NULL","DAC MiniDSP IN2 Route"},   
+       {"Right DAC", "NULL","DAC MiniDSP IN2 Route"},  
+       {"Left DAC", "NULL","DAC MiniDSP IN3 Route"},   
+       {"Right DAC", "NULL","DAC MiniDSP IN3 Route"},  
+
+
+
+
+       /* Mixer Amplifier */
+
+       {"MAL PGA Mixer", "IN1L Switch","IN1L"}, 
+       {"MAL PGA Mixer", "Left MicPGA Volume","Left MicPGA"}, 
+
+       {"MAL PGA", NULL, "MAL PGA Mixer"},
+
+
+       {"MAR PGA Mixer", "IN1R Switch","IN1R"}, 
+       {"MAR PGA Mixer", "Right MicPGA Volume","Right MicPGA"}, 
+
+       {"MAR PGA", NULL, "MAR PGA Mixer"},
+
+
+       /* Virtual connection between DAC and ADC for miniDSP IPC */
+       {"ADC DAC Route", "On", "Left ADC"},
+       {"ADC DAC Route", "On", "Right ADC"},
+       
+       {"Left DAC", NULL, "ADC DAC Route"},
+       {"Right DAC", NULL, "ADC DAC Route"},
+
+       /* Capture (ADC) portions */ 
+       /* Left Positive PGA input */
+       {"Left Input Mixer","IN1L Switch","IN1L"},
+       {"Left Input Mixer","IN2L Switch","IN2L"},
+       {"Left Input Mixer","IN3L Switch","IN3L"},
+       {"Left Input Mixer","IN4L Switch","IN4L"},
+       {"Left Input Mixer","IN1R Switch","IN1R"},
+       /* Left Negative PGA input */
+       {"Left Input Mixer","IN2R Switch","IN2R"},
+       {"Left Input Mixer","IN3R Switch","IN3R"},
+       {"Left Input Mixer","IN4R Switch","IN4R"},
+       {"Left Input Mixer","CM2L Switch","CM2L"},
+       {"Left Input Mixer","CM1L Switch","CM1L"},
+
+
+       /* Right Positive PGA Input */
+       {"Right Input Mixer","IN1R Switch","IN1R"},
+       {"Right Input Mixer","IN2R Switch","IN2R"},
+       {"Right Input Mixer","IN3R Switch","IN3R"},
+       {"Right Input Mixer","IN4R Switch","IN4R"},
+       {"Right Input Mixer","IN2L Switch","IN2L"},
+       /* Right Negative PGA Input */
+       {"Right Input Mixer","IN1L Switch","IN1L"},
+       {"Right Input Mixer","IN3L Switch","IN3L"},
+       {"Right Input Mixer","IN4L Switch","IN4L"},
+       {"Right Input Mixer","CM1R Switch","CM1R"},
+       {"Right Input Mixer","CM2R Switch","CM2R"},
+
+
+       {"CM1L", NULL, "CM"},
+       {"CM2L", NULL, "CM"},
+       {"CM1R", NULL, "CM"},
+       {"CM1R", NULL, "CM"},
+
+       {"Left MicPGA",NULL,"Left Input Mixer"},
+       {"Right MicPGA",NULL,"Right Input Mixer"},
+
+/*     {"DMICDAT Input Route","GPI1","GPI1 Pin"},
+       {"DMICDAT Input Route","GPI2","GPI2 Pin"},
+       {"DMICDAT Input Route","DIN1","DIN1 Pin"},
+       {"DMICDAT Input Route","GPIO1","GPIO1 Pin"},
+       {"DMICDAT Input Route","GPIO2","GPIO2 Pin"},
+       {"DMICDAT Input Route","MCLK2","MCLK2 Pin"},
+
+       {"DMICDAT", NULL, "DMICDAT Input Route"},
+       {"DMICDAT", NULL, "ADC_MOD_CLK"},
+*/
+//     {"Left DMIC", NULL, "DMICDAT"},
+//     {"Right DMIC", NULL, "DMICDAT"},
+
+       {"Left ADC Route", "Analog","Left MicPGA"},
+       {"Left ADC Route", "Digital", "Left DMIC"},
+
+       {"Right ADC Route", "Analog","Right MicPGA"},
+       {"Right ADC Route", "Digital", "Right DMIC"},
+
+       {"Left ADC", NULL, "Left ADC Route"},
+       {"Right ADC", NULL, "Right ADC Route"},
+
+
+       /* ASI Output Routing */
+       {"ADC MiniDSP OUT1", NULL, "Left ADC"},
+       {"ADC MiniDSP OUT1", NULL, "Right ADC"},
+       {"ADC MiniDSP OUT2", NULL, "Left ADC"},
+       {"ADC MiniDSP OUT2", NULL, "Right ADC"},
+       {"ADC MiniDSP OUT3", NULL, "Left ADC"},
+       {"ADC MiniDSP OUT3", NULL, "Right ADC"},
+
+
+       {"ASI1OUT Route", "ADC MiniDSP Out1","ADC MiniDSP OUT1"},// Port 1
+       {"ASI1OUT Route", "ASI1In Bypass","ASI1IN Port"},
+       {"ASI1OUT Route", "ASI2In Bypass","ASI2IN Port"},
+       {"ASI1OUT Route", "ASI3In Bypass","ASI3IN Port"},
+
+       {"ASI2OUT Route", "ADC MiniDSP Out1","ADC MiniDSP OUT1"},// Port 1
+       {"ASI2OUT Route", "ASI1In Bypass","ASI1IN Port"},
+       {"ASI2OUT Route", "ASI2In Bypass","ASI2IN Port"},
+       {"ASI2OUT Route", "ASI3In Bypass","ASI3IN Port"},
+       {"ASI2OUT Route", "ADC MiniDSP Out2","ADC MiniDSP OUT2"},// Port 2
+
+       {"ASI3OUT Route", "ADC MiniDSP Out1","ADC MiniDSP OUT1"},// Port 1
+       {"ASI3OUT Route", "ASI1In Bypass","ASI1IN Port"},
+       {"ASI3OUT Route", "ASI2In Bypass","ASI2IN Port"},
+       {"ASI3OUT Route", "ASI3In Bypass","ASI3IN Port"},
+       {"ASI3OUT Route", "ADC MiniDSP Out3","ADC MiniDSP OUT3"},// Port 3
+
+       {"ASI1OUT",NULL,"ASI1OUT Route"},       
+       {"ASI2OUT",NULL,"ASI2OUT Route"},       
+       {"ASI3OUT",NULL,"ASI3OUT Route"},       
+
+
+       {"DOUT1 Route", "ASI1 Out", "ASI1OUT"},
+       {"DOUT1 Route", "DIN1 Bypass", "DIN1"},
+       {"DOUT1 Route", "DIN2 Bypass", "DIN2"},
+       {"DOUT1 Route", "DIN3 Bypass", "DIN3"},
+
+       {"DOUT2 Route", "ASI2 Out", "ASI2OUT"},
+       {"DOUT2 Route", "DIN1 Bypass", "DIN1"},
+       {"DOUT2 Route", "DIN2 Bypass", "DIN2"},
+       {"DOUT2 Route", "DIN3 Bypass", "DIN3"},
+
+       {"DOUT3 Route", "ASI3 Out", "ASI3OUT"},
+       {"DOUT3 Route", "DIN1 Bypass", "DIN1"},
+       {"DOUT3 Route", "DIN2 Bypass", "DIN2"},
+       {"DOUT3 Route", "DIN3 Bypass", "DIN3"},
+
+       {"DOUT1", NULL, "DOUT1 Route"},
+       {"DOUT2", NULL, "DOUT2 Route"},
+       {"DOUT3", NULL, "DOUT3 Route"},
+
+
+};
+#define AIC3262_DAPM_ROUTE_NUM (sizeof(aic3262_dapm_routes)/sizeof(struct snd_soc_dapm_route))
+
+
+/* aic3262_firmware_load
+   This function is called by the request_firmware_nowait function as soon 
+   as the firmware has been loaded from the file. The firmware structure
+   contains the data and the size of the firmware loaded.
+ */
+
+void aic3262_firmware_load(const struct firmware *fw, void *context)
+{
+       struct snd_soc_codec *codec = context;
+       struct aic3262_priv *private_ds = snd_soc_codec_get_drvdata(codec);
+       
+       mutex_lock(&private_ds->cfw_mutex);
+       if(private_ds->cur_fw != NULL) release_firmware(private_ds->cur_fw);
+       private_ds->cur_fw = NULL ;  
+       if (fw==NULL)
+       {
+               dev_dbg(codec->dev,"Default firmware load\n");
+               /*Request firmware failed due to non availbility of firmware file. Hence,Default firmware is getting loaded */
+               if(!private_ds->isdefault_fw) // default firmware is already loaded
+               {
+                       aic3xxx_cfw_reload( private_ds->cfw_p,default_firmware,sizeof(default_firmware) );
+                       private_ds->isdefault_fw = 1;
+                       //init function for transition
+                       aic3xxx_cfw_transition(private_ds->cfw_p,"INIT");
+               }
+       }
+       else
+       {
+               dev_dbg(codec->dev,"Firmware load\n");
+               private_ds->cur_fw = fw;
+               aic3xxx_cfw_reload(private_ds->cfw_p,(void*)fw->data,fw->size);
+               private_ds->isdefault_fw        = 0;
+               //init function for transition
+               aic3xxx_cfw_transition(private_ds->cfw_p,"INIT");
+       }
+        // when new firmware is loaded, mode is changed to zero and config is changed to zero
+        aic3xxx_cfw_setmode_cfg(private_ds->cfw_p,0,0);
+        mutex_unlock(&private_ds->cfw_mutex);
+}
+
+/*
+ *****************************************************************************
+ * Function Definitions
+ *****************************************************************************
+ */
+
+/* headset work and headphone/headset jack interrupt handlers */
+
+
+static void aic3262_hs_jack_report(struct snd_soc_codec *codec,
+               struct snd_soc_jack *jack, int report)
+{
+       struct aic3262_priv *aic3262 = snd_soc_codec_get_drvdata(codec);
+       int status, state = 0;
+
+       mutex_lock(&aic3262->mutex);
+
+       // Sync status 
+       status = snd_soc_read(codec, AIC3262_DAC_FLAG);
+       // We will check only stereo MIC and headphone 
+       if(status & AIC3262_JACK_WITH_STEREO_HS)
+               state |= SND_JACK_HEADPHONE;
+       if(status & AIC3262_JACK_WITH_MIC)
+               state |= SND_JACK_MICROPHONE;
+
+
+       mutex_unlock(&aic3262->mutex);
+
+       snd_soc_jack_report(jack, state, report);
+       if (&aic3262->hs_jack.sdev)
+               switch_set_state(&aic3262->hs_jack.sdev, !!state);
+}
+
+void aic3262_hs_jack_detect(struct snd_soc_codec *codec,
+               struct snd_soc_jack *jack, int report)
+{
+       struct aic3262_priv *aic3262 = snd_soc_codec_get_drvdata(codec);
+       struct aic3262_jack_data *hs_jack = &aic3262->hs_jack;
+
+       hs_jack->jack = jack;
+       hs_jack->report = report;
+
+       aic3262_hs_jack_report(codec, hs_jack->jack, hs_jack->report);
+}
+EXPORT_SYMBOL_GPL(aic3262_hs_jack_detect);
+
+static void aic3262_accessory_work(struct work_struct *work)
+{
+       struct aic3262_priv *aic3262 = container_of(work,
+                       struct aic3262_priv, delayed_work.work);
+       struct snd_soc_codec *codec = aic3262->codec;
+       struct aic3262_jack_data *hs_jack = &aic3262->hs_jack;
+
+       aic3262_hs_jack_report(codec, hs_jack->jack, hs_jack->report);
+}
+
+/* audio interrupt handler */
+static irqreturn_t aic3262_audio_handler(int irq, void *data)
+{
+       struct snd_soc_codec *codec = data;
+       struct aic3262_priv *aic3262 = snd_soc_codec_get_drvdata(codec);
+
+       queue_delayed_work(aic3262->workqueue, &aic3262->delayed_work,
+                       msecs_to_jiffies(200));
+
+       return IRQ_HANDLED;
+}
+
+/*
+ *----------------------------------------------------------------------------
+ * 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;
+       }
+       cache[reg] = value;
+       return;
+}
+
+/*
+ *----------------------------------------------------------------------------
+ * Function : aic3262_codec_read
+ * Purpose  : This function is to read the aic3262 register space.
+ *
+ *----------------------------------------------------------------------------
+ */
+unsigned int aic3262_codec_read(struct snd_soc_codec *codec, unsigned int reg)
+{
+
+       u8 value;
+       aic326x_reg_union *aic_reg = (aic326x_reg_union *)&reg; 
+       value = aic3262_reg_read(codec->control_data, reg);
+       dev_dbg(codec->dev,"p %d ,r 30 %x %x \n",aic_reg->aic326x_register.page,aic_reg->aic326x_register.offset,value);
+       return value;
+}
+
+/*
+ *----------------------------------------------------------------------------
+ * Function : aic3262_write
+ * Purpose  : This function is to write to the aic3262 register space.
+ *
+ *----------------------------------------------------------------------------
+ */
+int aic3262_codec_write(struct snd_soc_codec *codec, unsigned int reg, unsigned int value)
+{
+       aic326x_reg_union *aic_reg = (aic326x_reg_union *)&reg; 
+       dev_dbg(codec->dev,"p %d,w 30 %x %x \n",aic_reg->aic326x_register.page,aic_reg->aic326x_register.offset,value);
+       return aic3262_reg_write(codec->control_data, reg, value);
+}
+
+/*
+ *----------------------------------------------------------------------------
+ * Function : aic3262_reset_cache
+ * Purpose  : This function is to reset the cache.
+ *----------------------------------------------------------------------------
+ */
+int aic3262_reset_cache (struct snd_soc_codec *codec)
+{
+       dev_dbg(codec->dev,KERN_ALERT "codec: %s : started\n", __func__);
+
+#if defined(EN_REG_CACHE)
+       if (codec->reg_cache != NULL) {
+               memcpy(codec->reg_cache, aic3262_reg, sizeof (aic3262_reg));
+               return 0;
+       }
+
+       codec->reg_cache = kmemdup (aic3262_reg, sizeof (aic3262_reg), GFP_KERNEL);
+       if (codec->reg_cache == NULL) {
+               dev_err(codec->dev,"aic32x4: kmemdup failed\n");
+               return -ENOMEM;
+       }
+#endif
+       dev_dbg(codec->dev,KERN_ALERT "codec: %s : ended\n", __func__);
+
+       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)
+{
+
+       snd_soc_dapm_new_controls(&codec->dapm, aic3262_dapm_widgets,
+                       ARRAY_SIZE(aic3262_dapm_widgets));
+       /* set up audio path interconnects */
+       dev_dbg(codec->dev,"#Completed adding new dapm widget controls size=%d\n",ARRAY_SIZE(aic3262_dapm_widgets));
+
+       snd_soc_dapm_add_routes(&codec->dapm, aic3262_dapm_routes, ARRAY_SIZE(aic3262_dapm_routes));
+       dev_dbg(codec->dev,"#Completed adding DAPM routes\n");
+       snd_soc_dapm_new_widgets(&codec->dapm);
+       dev_dbg(codec->dev,"#Completed updating dapm\n");
+
+       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.
+ *
+ *----------------------------------------------------------------------------
+ */
+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 asi_reg, bclk_reg;
+       u8 data = 0;
+
+
+       if(substream->stream==SNDRV_PCM_STREAM_PLAYBACK)
+               aic3262->stream_status=1;
+       else
+               aic3262->stream_status=0;
+
+
+       switch(dai->id)
+       {
+               case 0:
+                       asi_reg = AIC3262_ASI1_BUS_FMT;
+                       bclk_reg = AIC3262_ASI1_BCLK_N;
+                       break;
+               case 1:
+                       asi_reg = AIC3262_ASI2_BUS_FMT;
+                       bclk_reg = AIC3262_ASI2_BCLK_N;
+                       break;
+               case 2:
+                       asi_reg = AIC3262_ASI3_BUS_FMT;
+                       bclk_reg = AIC3262_ASI3_BCLK_N;
+                       break;
+               default:
+                       return -EINVAL;
+
+
+       }
+
+       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 */
+       snd_soc_update_bits(codec, asi_reg, AIC3262_ASI_DATA_WORD_LENGTH_MASK, data);
+       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;
+       //      int mute_reg;
+
+       struct aic3262_priv *aic3262 = snd_soc_codec_get_drvdata(codec);
+
+       dev_dbg(codec->dev, "codec : %s : started\n", __FUNCTION__ );
+       if(dai->id > 2)
+               return -EINVAL;
+       if(mute) {
+               aic3262->mute_asi &= ~((0x1) << dai->id);
+               if(aic3262->mute_asi == 0)// Mute only when all asi's are muted
+                       snd_soc_update_bits_locked(codec, AIC3262_DAC_MVOL_CONF, AIC3262_DAC_LR_MUTE_MASK,AIC3262_DAC_LR_MUTE);
+
+       } else { // Unmute
+               if(aic3262->mute_asi == 0)// Unmute for the first asi that need to unmute. rest unmute will pass 
+                       snd_soc_update_bits_locked(codec, AIC3262_DAC_MVOL_CONF, AIC3262_DAC_LR_MUTE_MASK, 0x0);
+               aic3262->mute_asi |= ((0x1) <<  dai->id);
+       }
+       dev_dbg(codec->dev, "codec : %s : ended\n", __FUNCTION__ );
+       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 aic3262_priv *aic3262; 
+       struct snd_soc_codec *codec;
+       codec = codec_dai->codec;
+       aic3262 = snd_soc_codec_get_drvdata(codec);
+       switch (freq) {
+               case AIC3262_FREQ_12000000:
+                       aic3262->sysclk = freq;
+                       return 0;
+               case AIC3262_FREQ_24000000:
+                       aic3262->sysclk = freq;
+                       return 0;
+                       break;
+               case AIC3262_FREQ_19200000:
+                       aic3262->sysclk = freq;
+                       return 0;
+                       break;
+               case AIC3262_FREQ_38400000:
+                       aic3262->sysclk = freq;
+                       dev_dbg(codec->dev,"codec: sysclk = %d\n", aic3262->sysclk);
+                       return 0;
+                       break;
+
+       }
+       dev_err(codec->dev,"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 aic3262_priv *aic3262 = aic3262_priv_data;
+       struct aic3262_priv *aic3262; 
+       struct snd_soc_codec *codec;
+       u8 iface_val, master,dsp_a_val ;
+       int aif_bclk_wclk_reg; 
+       int aif_interface_reg; 
+       int aif_bclk_offset_reg; 
+       int iface_reg; 
+       codec = codec_dai->codec;
+       aic3262 = snd_soc_codec_get_drvdata(codec);
+       iface_val = 0x00;
+       master = 0x0;
+       dsp_a_val = 0x0;
+       switch(codec_dai->id)
+       {
+               case 0:
+                       aif_bclk_wclk_reg = AIC3262_ASI1_BWCLK_CNTL_REG;
+                       aif_interface_reg = AIC3262_ASI1_BUS_FMT;
+                       aif_bclk_offset_reg = AIC3262_ASI1_LCH_OFFSET;  
+                       break;
+               case 1:
+                       aif_bclk_wclk_reg = AIC3262_ASI2_BWCLK_CNTL_REG;
+                       aif_interface_reg = AIC3262_ASI2_BUS_FMT;
+                       aif_bclk_offset_reg = AIC3262_ASI2_LCH_OFFSET;  
+                       break;
+               case 2:
+                       aif_bclk_wclk_reg = AIC3262_ASI3_BWCLK_CNTL_REG;
+                       aif_interface_reg = AIC3262_ASI3_BUS_FMT;
+                       aif_bclk_offset_reg = AIC3262_ASI3_LCH_OFFSET;  
+                       break;
+               default:
+                       return -EINVAL;
+
+       }
+       /* set master/slave audio interface */
+       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+               case SND_SOC_DAIFMT_CBM_CFM:
+                       dev_dbg(codec->dev, "setdai_fmt : SND_SOC_DAIFMT_CBM_CFM : master=1 \n");
+                       aic3262->master = 1;
+                       master |= (AIC3262_WCLK_OUT_MASK | AIC3262_BCLK_OUT_MASK);
+                       break;
+               case SND_SOC_DAIFMT_CBS_CFS:
+                       dev_dbg(codec->dev, "setdai_fmt : SND_SOC_DAIFMT_CBS_CFS : master=0 \n");
+
+                       aic3262->master = 0;
+                       break;
+               case SND_SOC_DAIFMT_CBS_CFM: //new case..just for debugging
+                       master |= (AIC3262_WCLK_OUT_MASK);
+                       dev_dbg(codec->dev,"%s: SND_SOC_DAIFMT_CBS_CFM\n", __FUNCTION__);
+                       aic3262->master = 0;
+                       break;
+               case SND_SOC_DAIFMT_CBM_CFS:    
+                       master |= (AIC3262_BCLK_OUT_MASK);
+                       aic3262->master = 0;
+                       break;
+
+               default:
+                       dev_err(codec->dev, "Invalid DAI master/slave interface\n");
+
+                       return -EINVAL;
+       }
+
+       /* interface format */
+       switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+               case SND_SOC_DAIFMT_I2S:
+                       iface_val = (iface_reg & 0x1f);
+                       break;
+               case SND_SOC_DAIFMT_DSP_A:
+                       dsp_a_val = 0x1; /* Intentionally falling back to following case */
+               case SND_SOC_DAIFMT_DSP_B:
+                       iface_val = (iface_reg & 0x1f) | 0x20;
+                       break;
+               case SND_SOC_DAIFMT_RIGHT_J:
+                       iface_val = (iface_reg & 0x1f) | 0x40;
+                       break;
+               case SND_SOC_DAIFMT_LEFT_J:
+                       iface_val = (iface_reg & 0x1f) | 0x60;
+                       break;
+
+                       dev_err(codec->dev,"Invalid DAI interface format\n");
+
+                       return -EINVAL;
+       }
+       switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+               case SND_SOC_DAIFMT_DSP_A:      
+               case SND_SOC_DAIFMT_DSP_B:      
+                       switch(fmt & SND_SOC_DAIFMT_INV_MASK) {
+                               case SND_SOC_DAIFMT_NB_NF:
+                                       break;
+                               case SND_SOC_DAIFMT_IB_NF:
+                                       master |= AIC3262_BCLK_INV_MASK;
+                                       break;
+                               default:
+                                       return -EINVAL;
+                       }
+                       break;
+               case SND_SOC_DAIFMT_I2S:
+               case SND_SOC_DAIFMT_RIGHT_J:
+               case SND_SOC_DAIFMT_LEFT_J:
+                       switch(fmt & SND_SOC_DAIFMT_INV_MASK) {
+                               case SND_SOC_DAIFMT_NB_NF:
+                                       break;
+                               case SND_SOC_DAIFMT_IB_NF:
+                                       master |= AIC3262_BCLK_INV_MASK; 
+                                       break;
+                               default:
+                                       return -EINVAL;
+                       }
+                       break;
+               default:
+                       return -EINVAL;
+       }
+       snd_soc_update_bits(codec, aif_bclk_wclk_reg, AIC3262_WCLK_BCLK_MASTER_MASK ,master);
+       snd_soc_update_bits(codec, aif_interface_reg, AIC3262_ASI_INTERFACE_MASK ,iface_val);
+       snd_soc_update_bits(codec, aif_bclk_offset_reg, AIC3262_BCLK_OFFSET_MASK,dsp_a_val);
+
+       return 0;
+}
+
+static int aic3262_dai_set_pll(struct snd_soc_dai *dai, int pll_id, int source,
+                          unsigned int Fin, unsigned int Fout)      
+{
+       struct snd_soc_codec *codec = dai->codec;
+       struct aic3262_priv *aic3262 = snd_soc_codec_get_drvdata(codec);
+       
+       dev_dbg(codec->dev,"In aic3262: dai_set_pll\n");
+       dev_dbg(codec->dev,"%d,%s,dai->id = %d\n", __LINE__ , __FUNCTION__ ,dai->id);   
+       // select the PLL_CLKIN
+       snd_soc_update_bits(codec, AIC3262_PLL_CLKIN_REG, AIC3262_PLL_CLKIN_MASK, source << AIC3262_PLL_CLKIN_SHIFT);
+       // TODO: How to select low/high clock range?
+       
+        mutex_lock(&aic3262->cfw_mutex);
+       aic3xxx_cfw_set_pll(aic3262->cfw_p,dai->id);
+        mutex_unlock(&aic3262->cfw_mutex);
+
+       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)
+{
+
+       switch (level) {
+               /* full On */
+               case SND_SOC_BIAS_ON:
+
+                       dev_dbg(codec->dev, "set_bias_on \n");
+                       break;
+
+                       /* partial On */
+               case SND_SOC_BIAS_PREPARE:
+                       dev_dbg(codec->dev, "set_bias_prepare \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
+                        */
+                       dev_dbg(codec->dev, "set_bias_stby \n");
+                       if(codec->dapm.bias_level == SND_SOC_BIAS_OFF)
+                       {
+                               snd_soc_update_bits(codec, AIC3262_POWER_CONF, (AIC3262_AVDD_TO_DVDD_MASK | AIC3262_EXT_ANALOG_SUPPLY_MASK), 0x0);
+
+                       }
+                       snd_soc_update_bits(codec, AIC3262_REF_PWR_DLY, AIC3262_CHIP_REF_PWR_ON_MASK, AIC3262_CHIP_REF_PWR_ON);
+
+                       break;
+
+
+                       /* Off, without power */
+               case SND_SOC_BIAS_OFF:
+                       dev_dbg(codec->dev, "set_bias_off \n");
+                       /* force all power off */
+                       snd_soc_update_bits(codec, AIC3262_REF_PWR_DLY, AIC3262_CHIP_REF_PWR_ON_MASK, 0x0);
+                       snd_soc_update_bits(codec, AIC3262_POWER_CONF, (AIC3262_AVDD_TO_DVDD_MASK | AIC3262_EXT_ANALOG_SUPPLY_MASK),
+                                                (AIC3262_AVDD_TO_DVDD | AIC3262_EXT_ANALOG_SUPPLY_OFF));
+                       break;
+       }
+
+       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)
+{
+       aic3262_set_bias_level(codec, SND_SOC_BIAS_OFF);
+       return 0;
+}
+
+/*
+ *----------------------------------------------------------------------------
+ * Function : aic3262_resume
+ * Purpose  : This function is to resume the AIC3262 driver
+ *
+ *----------------------------------------------------------------------------
+ */
+static int aic3262_resume(struct snd_soc_codec *codec)
+{
+       aic3262_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+
+       return 0;
+}
+
+/*
+ *----------------------------------------------------------------------------
+ * Function : aic3262_probe
+ * Purpose  : This is first driver function called by the SoC core driver.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+#ifdef AIC3262_PROC    
+static int aic3262_proc_init(void);
+#endif
+
+static int aic3262_codec_probe(struct snd_soc_codec *codec)
+{
+       int ret = 0;
+       struct aic3262 *control;
+       struct aic3262_priv *aic3262; 
+       struct aic3262_jack_data *jack;
+       if(codec == NULL)
+               dev_err(codec->dev,"codec pointer is NULL. \n");
+
+       DBG("aic3262_codec_probe is ok\n"); //sxj
+
+       #ifdef AIC3262_PROC     
+       aic3262_proc_init();
+       #endif
+
+       codec->control_data = dev_get_drvdata(codec->dev->parent);
+       control = codec->control_data;
+
+       aic3262 = kzalloc(sizeof(struct aic3262_priv), GFP_KERNEL);
+
+       if(aic3262 == NULL)
+               return -ENOMEM;
+       snd_soc_codec_set_drvdata( codec, aic3262);
+
+       aic3262->pdata = dev_get_platdata(codec->dev->parent);
+       aic3262->codec = codec;
+
+       aic3262->cur_fw = NULL;
+       aic3262->isdefault_fw= 0;
+        aic3262->cfw_p = &(aic3262->cfw_ps);
+       aic3262->cfw_p->ops = &aic3262_cfw_codec_ops; 
+       aic3262->cfw_p->ops_obj = aic3262;
+
+       aic3262->workqueue = create_singlethread_workqueue("aic3262-codec");
+       if( !aic3262->workqueue) {
+               ret = -ENOMEM;
+               goto work_err;
+       }
+       ret = device_create_file(codec->dev, &dev_attr_debug_level);
+       if (ret)                                                        
+               dev_info(codec->dev, "Failed to add debug_level sysfs \n");     
+       INIT_DELAYED_WORK(&aic3262->delayed_work, aic3262_accessory_work);
+
+       mutex_init(&aic3262->mutex);
+       mutex_init(&aic3262->cfw_mutex);        
+       pm_runtime_enable(codec->dev);
+       pm_runtime_resume(codec->dev);
+       aic3262->dsp_runstate = 0;
+       /* use switch-class based headset reporting if platform requires it */
+       jack = &aic3262->hs_jack;                       
+       jack->sdev.name = "h2w";
+       ret = switch_dev_register(&jack->sdev);
+       if(ret) {
+               dev_err(codec->dev, "error registering switch device %d\n",ret);
+               goto reg_err;
+       }
+       if(control->irq)
+       {
+               ret = aic3262_request_irq(codec->control_data, AIC3262_IRQ_HEADSET_DETECT,
+                       aic3262_audio_handler, IRQF_NO_SUSPEND,"aic3262_irq_headset",
+                       codec);
+
+               if(ret){
+                       dev_err(codec->dev, "HEADSET detect irq request failed:%d\n",ret);
+                       goto irq_err;
+               }
+       }
+
+       aic3262_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+
+       aic3262->mute_asi = 0;
+
+       snd_soc_add_controls(codec, aic3262_snd_controls,
+                       ARRAY_SIZE(aic3262_snd_controls));
+       mutex_init(&codec->mutex);
+
+       aic3262_add_widgets(codec);
+
+#ifdef AIC3262_TiLoad
+       ret = aic3262_driver_init(codec);
+       if (ret < 0)
+               dev_err(codec->dev,"\nTiLoad Initialization failed\n");
+#endif
+        // force loading the default firmware
+        aic3262_firmware_load(NULL,codec);
+       dev_dbg(codec->dev,"%d,%s,Firmware test\n",__LINE__,__FUNCTION__);
+       request_firmware_nowait(THIS_MODULE, FW_ACTION_HOTPLUG,"tlv320aic3262_fw_v1.bin", codec->dev, GFP_KERNEL,codec, aic3262_firmware_load);
+       
+       aic3262_codec = codec;
+       DBG("%s end of aic3262_codec_probe\n",__FILE__); //sxj
+       return 0;
+irq_err:
+       switch_dev_unregister(&jack->sdev);
+reg_err:
+work_err:
+       kfree(aic3262);
+       return 0;       
+}
+
+/*
+ *----------------------------------------------------------------------------
+ * Function : aic3262_remove
+ * Purpose  : to remove aic3262 soc device
+ *
+ *----------------------------------------------------------------------------
+ */
+static int aic3262_codec_remove(struct snd_soc_codec *codec)
+{
+       /* power down chip */
+       struct aic3262_priv *aic3262 = snd_soc_codec_get_drvdata(codec);
+       struct aic3262 *control = codec->control_data;
+       struct aic3262_jack_data *jack = &aic3262->hs_jack;
+
+       aic3262_set_bias_level(codec, SND_SOC_BIAS_OFF);
+
+       pm_runtime_disable(codec->dev);
+       /* free_irq if any */
+       switch(control->type) {
+               case TLV320AIC3262:
+                       aic3262_free_irq(control, AIC3262_IRQ_HEADSET_DETECT, codec);
+                       break;
+       }
+       /* release firmware if any */
+       if(aic3262->cur_fw != NULL)
+       {
+               release_firmware(aic3262->cur_fw);
+       }
+       /* destroy workqueue for jac dev */
+       switch_dev_unregister(&jack->sdev);
+       destroy_workqueue(aic3262->workqueue);
+
+       kfree(aic3262);
+
+       return 0;
+}
+
+static struct snd_soc_codec_driver soc_codec_driver_aic326x = {
+       .probe = aic3262_codec_probe,
+       .remove = aic3262_codec_remove,
+       .suspend = aic3262_suspend,
+       .resume = aic3262_resume,
+       .read = aic3262_codec_read,
+       .write = aic3262_codec_write,
+       .set_bias_level = aic3262_set_bias_level,
+       .reg_cache_size = ARRAY_SIZE(aic3262_reg),
+       .reg_word_size = sizeof(u8),
+       .reg_cache_default = aic3262_reg,
+};
+static int aic326x_probe(struct platform_device *pdev)
+{
+       return snd_soc_register_codec(&pdev->dev, &soc_codec_driver_aic326x, 
+                       aic326x_dai_driver, ARRAY_SIZE(aic326x_dai_driver));
+
+}
+
+static int aic326x_remove(struct platform_device *pdev)
+{
+       snd_soc_unregister_codec(&pdev->dev);
+       return 0;
+}
+
+static struct platform_driver aic326x_codec_driver = {
+       .driver = {
+               .name = "tlv320aic3262-codec",
+               .owner = THIS_MODULE,
+       },
+       .probe = aic326x_probe,
+       .remove = __devexit_p(aic326x_remove),
+};
+/*
+ *----------------------------------------------------------------------------
+ * Function : tlv320aic3262_modinit
+ * Purpose  : module init function. First function to run.
+ *
+ *----------------------------------------------------------------------------
+ */
+static int __init tlv320aic3262_modinit(void)
+{
+       return platform_driver_register(&aic326x_codec_driver);
+}
+
+module_init(tlv320aic3262_modinit);
+
+/*
+ *----------------------------------------------------------------------------
+ * Function : tlv320aic3262_exit
+ * Purpose  : module init function. First function to run.
+ *
+ *----------------------------------------------------------------------------
+ */
+static void __exit tlv320aic3262_exit(void)
+{
+       platform_driver_unregister(&aic326x_codec_driver);
+
+}
+
+module_exit(tlv320aic3262_exit);
+MODULE_ALIAS("platform:tlv320aic3262-codec");
+MODULE_DESCRIPTION("ASoC TLV320AIC3262 codec driver");
+MODULE_AUTHOR("Y Preetam Sashank Reddy ");
+MODULE_AUTHOR("Barani Prashanth ");
+MODULE_AUTHOR("Mukund Navada K <navada@ti.com>");
+MODULE_AUTHOR("Naren Vasanad <naren.vasanad@ti.com>");
+MODULE_LICENSE("GPL");
+
+
+#ifdef AIC3262_PROC
+
+
+/*static void test_playback(void)
+{
+       int ret;
+       printk("test palyback start\n");
+
+       aic3262_write(aic3262_codec, 0x00, 0x00);
+       ret = aic3262_read(aic3262_codec,0x00);
+       printk("0x00 = %x\n",ret);
+       aic3262_write(aic3262_codec, 0x7f, 0x00);
+       ret = aic3262_read(aic3262_codec,0x7f);
+       printk("0x7f = %x\n",ret);
+       aic3262_write(aic3262_codec, 0x01, 0x01);
+       ret = aic3262_read(aic3262_codec,0x01);
+       printk("0x01 = %x\n",ret);
+
+       aic3262_write(aic3262_codec, 0x04, 0x00);
+       aic3262_write(aic3262_codec, 0x0b, 0x81);
+       aic3262_write(aic3262_codec, 0x0c, 0x82);
+       aic3262_write(aic3262_codec, 0x0d, 0x00);
+       aic3262_write(aic3262_codec, 0x0e, 0x80);
+       
+       aic3262_write(aic3262_codec, 0x00, 0x01);
+       aic3262_write(aic3262_codec, 0x01+1*128, 0x00);
+       aic3262_write(aic3262_codec, 0x7a+1*128, 0x01);
+
+       aic3262_write(aic3262_codec, 0x00, 0x04);
+       aic3262_write(aic3262_codec, 0x01+4*128, 0x00);
+       aic3262_write(aic3262_codec, 0x0a+4*128, 0x00);
+
+       aic3262_write(aic3262_codec, 0x00, 0x00);
+       aic3262_write(aic3262_codec, 0x3c, 0x01);
+
+       aic3262_write(aic3262_codec, 0x00, 0x01);
+       aic3262_write(aic3262_codec, 0x03+1*128, 0x00);
+       aic3262_write(aic3262_codec, 0x04+1*128, 0x00);
+       aic3262_write(aic3262_codec, 0x1f+1*128, 0x80);
+       aic3262_write(aic3262_codec, 0x20+1*128, 0x00);
+       aic3262_write(aic3262_codec, 0x21+1*128, 0x28);
+       aic3262_write(aic3262_codec, 0x23+1*128, 0x10);
+       aic3262_write(aic3262_codec, 0x1b+1*128, 0x33);
+       aic3262_write(aic3262_codec, 0x00, 0x00);
+       aic3262_write(aic3262_codec, 0x3f, 0xc0);
+       aic3262_write(aic3262_codec, 0x40, 0x00);
+
+       aic3262_write(aic3262_codec, 0x00, 0x01);
+       aic3262_write(aic3262_codec, 0x16+1*128, 0xc3);
+       ret = aic3262_read(aic3262_codec,0x16);
+       printk("0x16 = %x\n",ret);
+       aic3262_write(aic3262_codec, 0xae, 0x00);
+       aic3262_write(aic3262_codec, 0x2f+1*128, 0x00);
+       aic3262_write(aic3262_codec, 0x30+1*128, 0x11);
+       aic3262_write(aic3262_codec, 0x52+1*128, 0x75);
+       aic3262_write(aic3262_codec, 0x53+1*128, 0x03);
+       aic3262_write(aic3262_codec, 0x2d+1*128, 0x03);
+       aic3262_write(aic3262_codec, 0x00, 0x00);
+       aic3262_write(aic3262_codec, 0x3f, 0xc0);
+       aic3262_write(aic3262_codec, 0x40, 0x00);
+
+}*/
+
+
+static void AP_to_speaker(void)
+{
+       printk("AP_to_speaker\n");
+
+       aic3262_codec_write(aic3262_codec, AIC3262_PAGE_SEL_REG, 0x00);
+       aic3262_codec_write(aic3262_codec, MAKE_REG(0,0,127), 0x00);
+       aic3262_codec_write(aic3262_codec, AIC3262_RESET_REG, 0x01);
+
+       aic3262_codec_write(aic3262_codec, AIC3262_DAC_ADC_CLKIN_REG, 0x00);
+       aic3262_codec_write(aic3262_codec, AIC3262_NDAC_DIV_POW_REG, 0x81);
+       aic3262_codec_write(aic3262_codec, AIC3262_MDAC_DIV_POW_REG, 0x82);
+       aic3262_codec_write(aic3262_codec, AIC3262_DOSR_MSB_REG, 0x00);
+       aic3262_codec_write(aic3262_codec, AIC3262_DOSR_LSB_REG, 0x80);
+       
+       aic3262_codec_write(aic3262_codec, AIC3262_PAGE_SEL_REG, 0x01);
+       aic3262_codec_write(aic3262_codec, AIC3262_POWER_CONF, 0x00);
+       aic3262_codec_write(aic3262_codec, AIC3262_REF_PWR_DLY, 0x01);
+
+       aic3262_codec_write(aic3262_codec, AIC3262_PAGE_SEL_REG, 0x04);
+       aic3262_codec_write(aic3262_codec, AIC3262_ASI1_BUS_FMT, 0x00);
+       aic3262_codec_write(aic3262_codec, AIC3262_ASI1_BWCLK_CNTL_REG, 0x00);
+
+       aic3262_codec_write(aic3262_codec, AIC3262_PAGE_SEL_REG, 0x00);
+       aic3262_codec_write(aic3262_codec, AIC3262_DAC_PRB, 0x01);
+
+       aic3262_codec_write(aic3262_codec, AIC3262_PAGE_SEL_REG, 0x01);
+       aic3262_codec_write(aic3262_codec, AIC3262_LDAC_PTM, 0x00);
+       aic3262_codec_write(aic3262_codec, AIC3262_RDAC_PTM, 0x00);
+       aic3262_codec_write(aic3262_codec, AIC3262_LINE_AMP_CNTL_R1, 0xC3);
+       aic3262_codec_write(aic3262_codec, AIC3262_SPK_AMP_CNTL_R2, 0x00);
+       aic3262_codec_write(aic3262_codec, AIC3262_SPK_AMP_CNTL_R3, 0x00);
+       aic3262_codec_write(aic3262_codec, AIC3262_SPK_AMP_CNTL_R4, 0x11);
+       aic3262_codec_write(aic3262_codec, MAKE_REG(0,1, 82), 0x75);
+       aic3262_codec_write(aic3262_codec, MAKE_REG(0,1, 83), 0x03);
+       aic3262_codec_write(aic3262_codec, AIC3262_SPK_AMP_CNTL_R1, 0x03);
+
+       aic3262_codec_write(aic3262_codec, AIC3262_PAGE_SEL_REG, 0x00);
+       aic3262_codec_write(aic3262_codec, AIC3262_PASI_DAC_DP_SETUP, 0xc0);
+       aic3262_codec_write(aic3262_codec, AIC3262_DAC_MVOL_CONF, 0x00);
+
+}
+
+
+static void AP_to_headphone(void)
+{
+       printk("AP_to_headphone\n");
+
+       aic3262_codec_write(aic3262_codec, AIC3262_PAGE_SEL_REG, 0x00);
+       aic3262_codec_write(aic3262_codec, MAKE_REG(0,0,127), 0x00);
+       aic3262_codec_write(aic3262_codec, AIC3262_RESET_REG, 0x01);
+
+       aic3262_codec_write(aic3262_codec, AIC3262_DAC_ADC_CLKIN_REG, 0x00);
+       aic3262_codec_write(aic3262_codec, AIC3262_NDAC_DIV_POW_REG, 0x81);
+       aic3262_codec_write(aic3262_codec, AIC3262_MDAC_DIV_POW_REG, 0x82);
+       aic3262_codec_write(aic3262_codec, AIC3262_DOSR_MSB_REG, 0x00);
+       aic3262_codec_write(aic3262_codec, AIC3262_DOSR_LSB_REG, 0x80);
+       
+       aic3262_codec_write(aic3262_codec, AIC3262_PAGE_SEL_REG, 0x01);
+       aic3262_codec_write(aic3262_codec, AIC3262_POWER_CONF, 0x00);
+       aic3262_codec_write(aic3262_codec, AIC3262_REF_PWR_DLY, 0x01);
+
+       aic3262_codec_write(aic3262_codec, AIC3262_PAGE_SEL_REG, 0x04);
+       aic3262_codec_write(aic3262_codec, AIC3262_ASI1_BUS_FMT, 0x00);
+       aic3262_codec_write(aic3262_codec, AIC3262_ASI1_BWCLK_CNTL_REG, 0x00);
+
+       aic3262_codec_write(aic3262_codec, AIC3262_PAGE_SEL_REG, 0x00);
+       aic3262_codec_write(aic3262_codec, AIC3262_DAC_PRB, 0x01);
+
+       aic3262_codec_write(aic3262_codec, AIC3262_PAGE_SEL_REG, 0x01);
+       aic3262_codec_write(aic3262_codec, AIC3262_LDAC_PTM, 0x00);
+       aic3262_codec_write(aic3262_codec, AIC3262_RDAC_PTM, 0x00);
+       aic3262_codec_write(aic3262_codec, AIC3262_HPL_VOL, 0x80);
+       aic3262_codec_write(aic3262_codec, AIC3262_HPR_VOL, 0x80);
+       aic3262_codec_write(aic3262_codec, MAKE_REG(0,1, 33), 0x28);
+       aic3262_codec_write(aic3262_codec, AIC3262_CHARGE_PUMP_CNTL, 0x10);
+       aic3262_codec_write(aic3262_codec, AIC3262_HP_AMP_CNTL_R1, 0x33);
+       aic3262_codec_write(aic3262_codec, AIC3262_PAGE_SEL_REG, 0x00);
+       aic3262_codec_write(aic3262_codec, AIC3262_PASI_DAC_DP_SETUP, 0xc0);
+       aic3262_codec_write(aic3262_codec, AIC3262_DAC_MVOL_CONF, 0x00);
+
+}
+
+static void record_in1lr(void)
+{
+       printk("record in1lr\n");
+
+       aic3262_codec_write(aic3262_codec, AIC3262_PAGE_SEL_REG, 0x00);
+       aic3262_codec_write(aic3262_codec, MAKE_REG(0,0,127), 0x00);
+       aic3262_codec_write(aic3262_codec, AIC3262_RESET_REG, 0x01);
+
+       aic3262_codec_write(aic3262_codec, AIC3262_DAC_ADC_CLKIN_REG, 0x00);
+       aic3262_codec_write(aic3262_codec, AIC3262_NADC_DIV_POW_REG, 0x81);
+       aic3262_codec_write(aic3262_codec, AIC3262_MADC_DIV_POW_REG, 0x82);
+       aic3262_codec_write(aic3262_codec, AIC3262_AOSR_REG, 0x80);
+
+       aic3262_codec_write(aic3262_codec, AIC3262_PAGE_SEL_REG, 0x01);
+       aic3262_codec_write(aic3262_codec, AIC3262_POWER_CONF, 0x00);
+       aic3262_codec_write(aic3262_codec, AIC3262_REF_PWR_DLY, 0x01);
+       aic3262_codec_write(aic3262_codec, AIC3262_MIC_PWR_DLY, 0x33);
+
+       aic3262_codec_write(aic3262_codec, AIC3262_PAGE_SEL_REG, 0x04);
+       aic3262_codec_write(aic3262_codec, AIC3262_ASI1_BUS_FMT, 0x00);
+       aic3262_codec_write(aic3262_codec, AIC3262_ASI1_BWCLK_CNTL_REG, 0x00);
+
+       aic3262_codec_write(aic3262_codec, AIC3262_PAGE_SEL_REG, 0x00);
+       aic3262_codec_write(aic3262_codec, AIC3262_ADC_PRB, 0x01);
+
+       aic3262_codec_write(aic3262_codec, AIC3262_PAGE_SEL_REG, 0x01);
+       aic3262_codec_write(aic3262_codec, AIC3262_MIC_BIAS_CNTL, 0x40);
+       aic3262_codec_write(aic3262_codec, AIC3262_LMIC_PGA_PIN, 0x80);
+       aic3262_codec_write(aic3262_codec, AIC3262_LMIC_PGA_MIN, 0x80);
+       aic3262_codec_write(aic3262_codec, AIC3262_RMIC_PGA_PIN, 0x80);
+       aic3262_codec_write(aic3262_codec, AIC3262_RMIC_PGA_MIN, 0x80);
+
+       aic3262_codec_write(aic3262_codec, AIC3262_MICL_PGA, 0x3c);
+       aic3262_codec_write(aic3262_codec, AIC3262_MICR_PGA, 0x3c);
+       aic3262_codec_write(aic3262_codec, MAKE_REG(0,1, 61), 0x00);
+
+       aic3262_codec_write(aic3262_codec, AIC3262_PAGE_SEL_REG, 0x00);
+       aic3262_codec_write(aic3262_codec, AIC3262_PASI_DAC_DP_SETUP, 0xc0);
+       aic3262_codec_write(aic3262_codec, AIC3262_DAC_MVOL_CONF, 0x00);
+}
+
+static void record_in2lr(void)
+{
+       printk("record in2lr\n");
+
+       aic3262_codec_write(aic3262_codec, AIC3262_PAGE_SEL_REG, 0x00);
+       aic3262_codec_write(aic3262_codec, MAKE_REG(0,0,127), 0x00);
+       aic3262_codec_write(aic3262_codec, AIC3262_RESET_REG, 0x01);
+
+}
+
+static void test_playback(void)
+{
+       int ret;
+       printk("test palyback start\n");
+
+       record_in1lr( );
+
+}
+
+
+static ssize_t aic3262_proc_write(struct file *file, const char __user *buffer,
+                          unsigned long len, void *data)
+{
+       char *cookie_pot; 
+       char *p;
+       int reg;
+       int value;
+       
+       cookie_pot = (char *)vmalloc( len );
+       if (!cookie_pot) 
+       {
+               return -ENOMEM;
+       } 
+       else 
+       {
+               if (copy_from_user( cookie_pot, buffer, len )) 
+                       return -EFAULT;
+       }
+
+       switch(cookie_pot[0])
+       {
+       case 'd':
+       case 'D':
+               debug_write_read ++;
+               debug_write_read %= 2;
+               if(debug_write_read != 0)
+                       printk("Debug read and write reg on\n");
+               else    
+                       printk("Debug read and write reg off\n");       
+               break;  
+       case 'r':
+       case 'R':
+               printk("Read reg debug\n");             
+               if(cookie_pot[1] ==':')
+               {
+                       debug_write_read = 1;
+                       strsep(&cookie_pot,":");
+                       while((p=strsep(&cookie_pot,",")))
+                       {
+                               reg = simple_strtol(p,NULL,16);
+                               value = aic3262_codec_read(aic3262_codec,reg);
+                               printk("aic3262_codec_read:0x%04x = 0x%04x\n",reg,value);
+                       }
+                       debug_write_read = 0;
+                       printk("\n");
+               }
+               else
+               {
+                       printk("Error Read reg debug.\n");
+                       printk("For example: echo r:22,23,24,25>aic3262_ts\n");
+               }
+               break;
+       case 'w':
+       case 'W':
+               printk("Write reg debug\n");            
+               if(cookie_pot[1] ==':')
+               {
+                       debug_write_read = 1;
+                       strsep(&cookie_pot,":");
+                       while((p=strsep(&cookie_pot,"=")))
+                       {
+                               reg = simple_strtol(p,NULL,16);
+                               p=strsep(&cookie_pot,",");
+                               value = simple_strtol(p,NULL,16);
+                               aic3262_codec_write(aic3262_codec,reg,value);
+                               printk("aic3262_codec_write:0x%04x = 0x%04x\n",reg,value);
+                       }
+                       debug_write_read = 0;
+                       printk("\n");
+               }
+               else
+               {
+                       printk("Error Write reg debug.\n");
+                       printk("For example: w:22=0,23=0,24=0,25=0>aic3262_ts\n");
+               }
+               break;
+       case 'f':
+       case 'F':
+               test_playback( );
+               break;
+       case 'a':
+               printk("Dump reg \n");          
+
+               for(reg = 0; reg < 0x6e; reg+=2)
+               {
+                       value = aic3262_codec_read(aic3262_codec,reg);
+                       printk("aic3262_codec_read:0x%04x = 0x%04x\n",reg,value);
+               }
+
+               break;          
+       default:
+               printk("Help for aic3262_ts .\n-->The Cmd list: \n");
+               printk("-->'d&&D' Open or Off the debug\n");
+               printk("-->'r&&R' Read reg debug,Example: echo 'r:22,23,24,25'>aic3262_ts\n");
+               printk("-->'w&&W' Write reg debug,Example: echo 'w:22=0,23=0,24=0,25=0'>aic3262_ts\n");
+               break;
+       }
+
+       return len;
+}
+
+static const struct file_operations aic3262_proc_fops = {
+       .owner          = THIS_MODULE,
+};
+
+static int aic3262_proc_init(void)
+{
+       struct proc_dir_entry *aic3262_proc_entry;
+       aic3262_proc_entry = create_proc_entry("driver/aic3262_ts", 0777, NULL);
+       if(aic3262_proc_entry != NULL)
+       {
+               aic3262_proc_entry->write_proc = aic3262_proc_write;
+               return 0;
+       }
+       else
+       {
+               printk("create proc error !\n");
+               return -1;
+       }
+}
+#endif
diff --git a/sound/soc/codecs/tlv320aic326x.h b/sound/soc/codecs/tlv320aic326x.h
new file mode 100644 (file)
index 0000000..c07950d
--- /dev/null
@@ -0,0 +1,260 @@
+/*
+ * linux/sound/soc/codecs/tlv320aic326x.h
+ *
+ * Copyright (C) 2011 TI 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    TI         20-01-2011
+ *
+ *                       The AIC325x ASoC driver is ported for the codec AIC3262.
+ * Rev 0.2   ASoC driver support    TI         21-03-2011
+ *                       The AIC326x ASoC driver is updated for linux 2.6.32 Kernel.
+ * Rev 0.3   ASoC driver support    TI         20-04-2011
+ *                       The AIC326x ASoC driver is ported to 2.6.35 omap4 kernel
+ */
+
+#ifndef _TLV320AIC3262_H
+#define _TLV320AIC3262_H
+#include "aic3xxx_cfw.h"
+#include "aic3xxx_cfw_ops.h"
+#include <linux/switch.h>
+
+/*#ifdef DEBUG
+        #define dprintk(x...)   printk(x)
+        #define DBG(x...)       printk(x)
+#else
+        #define dprintk(x...)
+        #define DBG(x...)
+#endif
+*/
+  
+#define AUDIO_NAME "aic3262"
+#define AIC3262_VERSION "1.1"
+/* Macro to enable the inclusion of tiload kernel driver */
+#define AIC3262_TiLoad
+
+
+
+//#define AIC3262_SYNC_MODE
+#undef AIC3262_SYNC_MODE
+
+#define AIC3262_ASI1_MASTER
+//#undef AIC3262_ASI1_MASTER
+//#define AIC3262_ASI2_MASTER
+#undef AIC3262_ASI2_MASTER
+//#define AIC3262_ASI3_MASTER
+#undef AIC3262_ASI3_MASTER
+/* Macro for McBsp master / slave configuration */
+#define AIC3262_MCBSP_SLAVE    /*3262 master*/
+//#undef AIC3262_MCBSP_SLAVE
+
+/* 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
+
+
+/* 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_19200000 19200000
+#define AIC3262_FREQ_24000000 24000000
+#define AIC3262_FREQ_38400000 38400000
+/* 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           1
+/* 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
+
+/* AIC3262 register space */
+#define        AIC3262_CACHEREGNUM                             1024 /* Updated from 256 to support Page 3 registers */
+#define DAC_FLAG                                       37
+#define ADC_FLAG                                       36
+#define DSP_NON_SYNC_MODE(state)   (!( (state & 0x03) && (state & 0x30) ))
+/*
+ *----------------------------------------------------------------------------
+ * @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_jack_data {
+        struct snd_soc_jack *jack;
+        int report;
+        struct switch_dev sdev;
+};
+/*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_priv {
+       u32 sysclk;
+       s32 master;
+       u8 book_no;
+       u8 page_no;
+       u8 process_flow;
+       u8 mute_codec;
+       u8 stream_status;
+       int current_dac_config[2];
+       int current_adc_config[2];
+       struct aic3262_jack_data hs_jack; 
+       struct workqueue_struct *workqueue;
+       struct delayed_work delayed_work;
+       struct snd_soc_codec *codec;
+       struct mutex mutex;
+       struct mutex cfw_mutex;
+       struct cfw_state cfw_ps;    
+       struct cfw_state *cfw_p;    
+       struct aic3262_pdata *pdata;
+       int mute_asi; // Bit 0 -> ASI1, Bit 1-> ASI2, Bit 2 -> ASI3
+       int dsp_runstate;
+       struct firmware *cur_fw;
+       int isdefault_fw;
+};
+/*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];
+};
+
+/*
+ *----------------------------------------------------------------------------
+ * @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.
+ *----------------------------------------------------------------------------
+ */
+extern struct snd_soc_dai tlv320aic3262_dai;
+
+/*
+ *----------------------------------------------------------------------------
+nt aic3262_write(struct snd_soc_codec *codec, unsigned int reg, unsigned int value)
+ * @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()
+ *
+ */
+extern struct snd_soc_codec_device soc_codec_dev_aic3262;
+extern const aic3xxx_codec_ops aic3262_cfw_codec_ops;
+void aic3262_hs_jack_detect(struct snd_soc_codec *codec,
+                               struct snd_soc_jack *jack, int report);
+
+unsigned int aic3262_read(struct snd_soc_codec *codec, unsigned int reg);
+ int aic3262_write(struct snd_soc_codec *codec, unsigned int reg, unsigned int value);
+#endif                         /* _TLV320AIC3262_H */
+
index 5b7508b91456aa130273bff21012cdf845cb5e0c..1bc84a597cdf74c6242575e2e422bfedc65c0f99 100755 (executable)
@@ -134,6 +134,15 @@ config SND_RK29_SOC_AIC3111
          Say Y if you want to add support for SoC audio on rockchip
          with the AIC3111.
 
+config SND_RK29_SOC_AIC3262
+       tristate "SoC I2S Audio support for rockchip - AIC3262"
+       depends on SND_RK29_SOC
+       select SND_RK29_SOC_I2S
+       select SND_SOC_TLV320AIC326X
+       help
+         Say Y if you want to add support for SoC audio on rockchip
+         with the AIC3262.
+
 config SND_RK29_SOC_RK1000
        tristate "SoC I2S Audio support for rockchip - RK1000"
        depends on SND_RK29_SOC
@@ -160,7 +169,7 @@ config SND_RK29_SOC_RK610
          Say Y if you want to add support for SoC audio on rockchip
          with the RK610(JETTA).
 
-if SND_RK29_SOC_WM8988 || SND_RK29_SOC_RK1000 || SND_RK29_SOC_WM8994 || SND_RK29_SOC_WM8900 || SND_RK29_SOC_RT5621 || SND_RK29_SOC_RT5631 || SND_RK29_SOC_RT5625 || SND_RK29_SOC_CS42L52 || SND_RK29_SOC_AIC3111 || SND_RK29_SOC_HDMI || SND_RK29_SOC_RK610
+if SND_RK29_SOC_WM8988 || SND_RK29_SOC_RK1000 || SND_RK29_SOC_WM8994 || SND_RK29_SOC_WM8900 || SND_RK29_SOC_RT5621 || SND_RK29_SOC_RT5631 || SND_RK29_SOC_RT5625 || SND_RK29_SOC_CS42L52 || SND_RK29_SOC_AIC3111 || SND_RK29_SOC_HDMI || SND_RK29_SOC_RK610 || SND_RK29_SOC_AIC3262
 choice
   bool "Set i2s type"
   default SND_RK29_CODEC_SOC_SLAVE
index 81759578ebfb490068762e120ce390e02aa3fd24..a1f0de123846cc73573971a94c3c724e980582ec 100644 (file)
@@ -24,6 +24,7 @@ snd-soc-rk1000-objs := rk29_rk1000codec.o
 snd-soc-wm8994-objs := rk29_wm8994.o
 snd-soc-hdmi-objs := rk29_hdmi.o
 snd-soc-rk610-objs := rk29_jetta_codec.o
+snd-soc-aic3262-objs := rk29_aic3262.o
 
 obj-$(CONFIG_SND_RK29_SOC_WM8994) += snd-soc-wm8994.o
 obj-$(CONFIG_SND_RK29_SOC_WM8988) += snd-soc-wm8988.o
@@ -34,5 +35,6 @@ obj-$(CONFIG_SND_RK29_SOC_RT5625) += snd-soc-rt5625.o
 obj-$(CONFIG_SND_RK29_SOC_RK1000) += snd-soc-rk1000.o
 obj-$(CONFIG_SND_RK29_SOC_CS42L52) += snd-soc-cs42l52.o
 obj-$(CONFIG_SND_RK29_SOC_AIC3111) += snd-soc-aic3111.o
+obj-$(CONFIG_SND_RK29_SOC_AIC3262) += snd-soc-aic3262.o
 obj-$(CONFIG_SND_RK29_SOC_HDMI) += snd-soc-hdmi.o
 obj-$(CONFIG_SND_RK29_SOC_RK610) += snd-soc-rk610.o
\ No newline at end of file
diff --git a/sound/soc/rk29/rk29_aic3262.c b/sound/soc/rk29/rk29_aic3262.c
new file mode 100644 (file)
index 0000000..bca9305
--- /dev/null
@@ -0,0 +1,412 @@
+/*
+ * rk29_aic3262.c  --  SoC audio for rockchip
+ *
+ * Driver for rockchip aic3262 audio
+ *  Copyright (C) 2009 lhh
+ *
+ *  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.
+ *
+ *
+ */
+
+#define DEBUG 1
+#include <linux/clk.h>
+#include <linux/platform_device.h>
+#include <linux/i2c.h>
+#include <linux/i2c/twl.h>
+#include <linux/regulator/consumer.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/jack.h>
+#include <linux/switch.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/gpio.h>
+
+#include <asm/mach-types.h>
+#include <linux/module.h>
+#include <linux/device.h>
+
+#include <asm/io.h>
+#include <mach/hardware.h>
+#include "../codecs/wm8994.h"
+#include "rk29_pcm.h"
+#include "rk29_i2s.h"
+#include <linux/clk.h>
+
+#include "../codecs/tlv320aic326x.h"
+
+#if 0
+#define        DBG(x...)       printk(KERN_INFO x)
+#else
+#define        DBG(x...)
+#endif
+
+struct regulator *vddhf_reg=NULL;
+
+/* Headset jack */
+static struct snd_soc_jack hs_jack;
+
+/*Headset jack detection DAPM pins */
+static struct snd_soc_jack_pin hs_jack_pins[] = {
+       {
+               .pin = "Headset Mic",
+               .mask = SND_JACK_MICROPHONE,
+       },
+       {
+               .pin = "Headset Stereophone",
+               .mask = SND_JACK_HEADPHONE,
+       },
+};
+
+static int spk_event(struct snd_soc_dapm_widget *w,
+                struct snd_kcontrol *kcontrol, int event)
+{
+        //struct snd_soc_codec *codec = w->codec;
+        int ret;
+        if (SND_SOC_DAPM_EVENT_ON(event)) {
+
+                       printk(" I am NULL is %d event is %d\n",vddhf_reg,event);
+
+                       if (vddhf_reg) {
+                           ret = regulator_enable(vddhf_reg);
+                           if(ret) {
+                                   printk("failed to enable vddhf \n");
+                                   return ret;
+                           }
+                       }
+        }
+        else {
+
+            if (vddhf_reg) {
+                ret = regulator_disable(vddhf_reg);
+                if (ret) {
+                        printk("failed to disable "
+                                "VDDHF regulator %d\n", ret);
+                        return ret;
+                }
+            }
+        }
+        return 0;
+}
+
+
+
+/* rk29 machine DAPM */
+static const struct snd_soc_dapm_widget rk29_aic3262_dapm_widgets[] = {
+       SND_SOC_DAPM_MIC("Ext Mic", NULL),
+       SND_SOC_DAPM_SPK("Ext Spk", NULL),
+       SND_SOC_DAPM_MIC("Headset Mic", NULL),
+       SND_SOC_DAPM_HP("Headset Stereophone", NULL),
+       SND_SOC_DAPM_SPK("Earphone Spk", NULL),
+       SND_SOC_DAPM_INPUT("FM Stereo In"),
+       SND_SOC_DAPM_LINE("FM Stereo Out",NULL),
+};
+
+static const struct snd_soc_dapm_route audio_map[] = {
+       /* External Mics: MAINMIC, SUBMIC with bias*/
+       {"IN2L", NULL, "Mic Bias Int"},
+       {"IN2R", NULL, "Mic Bias Int"},
+       {"IN3L", NULL, "Mic Bias Int"},
+       {"IN3R", NULL, "Mic Bias Int"},
+       {"Mic Bias Int", NULL, "Ext Mic"},
+
+       /* External Speakers: HFL, HFR */
+       {"Ext Spk", NULL, "SPKL"},
+       {"Ext Spk", NULL, "SPKR"},
+
+       /* Headset Mic: HSMIC with bias */
+       {"IN1L", NULL, "Mic Bias Ext"},
+       {"IN1R", NULL, "Mic Bias Ext"},
+       {"Mic Bias Ext", NULL, "Headset Mic"},
+
+       /* Headset Stereophone (Headphone): HPL, HPR */
+       {"Headset Stereophone", NULL, "HPL"},
+       {"Headset Stereophone", NULL, "HPR"},
+
+       /* Earphone speaker */
+       {"Earphone Spk", NULL, "RECP"},
+       {"Earphone Spk", NULL, "RECM"},
+
+       /* Aux/FM Stereo In: IN4L, IN4R */
+       {"IN4L", NULL, "FM Stereo In"},
+       {"IN4R", NULL, "FM Stereo In"},
+       
+       /* Aux/FM Stereo Out: LOL, LOR */
+       {"FM Stereo Out", NULL, "LOL"},
+       {"FM Stereo Out", NULL, "LOR"},
+};
+
+static const struct snd_kcontrol_new rk29_aic326x_controls[] = {
+       SOC_DAPM_PIN_SWITCH("Ext Mic"),
+       SOC_DAPM_PIN_SWITCH("Ext Spk"),
+       SOC_DAPM_PIN_SWITCH("Headset Mic"),
+       SOC_DAPM_PIN_SWITCH("Headset Stereophone"),
+       SOC_DAPM_PIN_SWITCH("Earphone Spk"),
+       SOC_DAPM_PIN_SWITCH("FM Stereo In"),
+       SOC_DAPM_PIN_SWITCH("FM Stereo Out"),
+};
+
+static int rk29_aic3262_init(struct snd_soc_pcm_runtime *rtd)
+{
+       struct snd_soc_codec *codec = rtd->codec;
+       struct snd_soc_dapm_context *dapm = &codec->dapm;
+       int ret;
+
+       DBG("rk29_aic3262_init\n");
+
+       ret = snd_soc_add_controls(codec, rk29_aic326x_controls,
+                                  ARRAY_SIZE(rk29_aic326x_controls));
+
+       if (ret < 0) {
+               printk("rk29_aic3262: Err snd_soc_add_controls ret: %d\n", ret );
+               return ret;
+       }
+
+       /* Add rk29 specific widgets */
+       ret = snd_soc_dapm_new_controls(dapm, rk29_aic3262_dapm_widgets,
+                               ARRAY_SIZE(rk29_aic3262_dapm_widgets));
+       if (ret)
+               return ret;
+
+       /* Set up rk29 specific audio path audio_map */
+       snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
+
+
+       ret = snd_soc_dapm_sync(dapm);
+       if (ret)
+               return ret;
+
+       /* Headset jack detection */
+       ret = snd_soc_jack_new(codec, "Headset Jack",
+                               SND_JACK_HEADSET, &hs_jack);
+       if (ret)
+               return ret;
+
+    ret = snd_soc_jack_add_pins(&hs_jack, ARRAY_SIZE(hs_jack_pins),
+                            hs_jack_pins);  
+    aic3262_hs_jack_detect(codec, &hs_jack, SND_JACK_HEADSET);
+       
+    /* don't wait before switching of HS power */
+       rtd->pmdown_time = 0;
+       return ret;
+}
+
+static int rk29_aif1_hw_params(struct snd_pcm_substream *substream,
+       struct snd_pcm_hw_params *params)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+       unsigned int pll_out = 0; 
+       int div_bclk,div_mclk;
+       int ret;
+       struct clk      *general_pll;
+
+
+       printk("Enter::%s----%d\n",__FUNCTION__,__LINE__);
+
+       /* set codec DAI configuration */
+#if defined (CONFIG_SND_RK29_CODEC_SOC_SLAVE) 
+       DBG("Set codec_dai slave\n");
+       ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
+               SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
+#endif 
+#if defined (CONFIG_SND_RK29_CODEC_SOC_MASTER)                            
+       ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
+               SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM);
+       DBG("Set codec_dai master\n");
+#endif
+       if (ret < 0)
+               return ret; 
+
+       /* set cpu DAI configuration */
+#if defined (CONFIG_SND_RK29_CODEC_SOC_SLAVE) 
+       DBG("Set cpu_dai master\n");
+       ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
+               SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM);
+#endif 
+#if defined (CONFIG_SND_RK29_CODEC_SOC_MASTER)  
+       ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
+               SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); 
+       DBG("Set cpu_dai slave\n"); 
+#endif         
+       if (ret < 0)
+               return ret;
+
+       switch(params_rate(params)) {
+               case 8000:
+               case 16000:
+               case 24000:
+               case 32000:
+               case 48000:
+                       pll_out = 12288000;
+                       break;
+               case 11025:
+               case 22050:
+               case 44100:
+                       pll_out = 11289600;
+                       break;
+               default:
+                       DBG("Enter:%s, %d, Error rate=%d\n",__FUNCTION__,__LINE__,params_rate(params));
+                       return -EINVAL;
+       }
+
+       general_pll=clk_get(NULL, "general_pll");
+       if(clk_get_rate(general_pll)>260000000)
+       {//288m 
+               div_bclk=(pll_out/4)/params_rate(params)-1;
+               div_mclk=3;
+       }
+
+       DBG("func is%s,gpll=%ld,pll_out=%d,div_mclk=%d\n",__FUNCTION__,clk_get_rate(general_pll),pll_out,div_mclk);
+       ret = snd_soc_dai_set_sysclk(cpu_dai, 0, 12000000, 0);
+       if(ret < 0)
+       {
+               DBG("rk29_hw_params_aic3262:failed to set the cpu sysclk for codec side\n"); 
+               return ret;
+       }
+       snd_soc_dai_set_clkdiv(cpu_dai, ROCKCHIP_DIV_BCLK,div_bclk);
+       snd_soc_dai_set_clkdiv(cpu_dai, ROCKCHIP_DIV_MCLK, div_mclk);
+       DBG("Enter:%s, %d, LRCK=%d\n",__FUNCTION__,__LINE__,(pll_out/4)/params_rate(params));
+
+       //MCLK == 11289600 or 12288000
+       ret = snd_soc_dai_set_sysclk(codec_dai, 0, 12000000, 0);
+       if (ret < 0) {
+               DBG("rk29_hw_params_aic3262:failed to set the sysclk for codec side\n"); 
+               return ret;
+       }
+       
+       return 0;
+}
+
+static int rk29_aif2_hw_params(struct snd_pcm_substream *substream,
+       struct snd_pcm_hw_params *params)
+{
+       return 0;
+}
+
+static int rk29_aif3_hw_params(struct snd_pcm_substream *substream,
+       struct snd_pcm_hw_params *params)
+{
+       return 0;
+}
+
+static struct snd_soc_ops rk29_aif1_ops = {
+         .hw_params = rk29_aif1_hw_params,
+};
+
+static struct snd_soc_ops rk29_aif2_ops = {
+         .hw_params = rk29_aif2_hw_params,
+};
+
+static struct snd_soc_ops rk29_aif3_ops = {
+         .hw_params = rk29_aif3_hw_params,
+};
+
+static struct snd_soc_dai_link rk29_dai[] = {
+
+       {
+               .name = "AIC3262 I2S1",
+               .stream_name = "AIC3262 PCM",
+               .codec_name = "tlv320aic3262-codec",
+               .platform_name = "rockchip-audio",
+#if defined(CONFIG_SND_RK29_SOC_I2S_8CH)       
+        .cpu_dai_name = "rk29_i2s.0",
+#elif defined(CONFIG_SND_RK29_SOC_I2S_2CH)
+               .cpu_dai_name = "rk29_i2s.1",
+#else  
+               .cpu_dai_name = "rk29_i2s.2",
+#endif
+               .codec_dai_name = "aic326x-asi1",
+               .ops = &rk29_aif1_ops,
+               .init = rk29_aic3262_init,
+       },
+       
+       {
+               .name = "AIC3262 I2S2",
+               .stream_name = "AIC3262 PCM",
+               .codec_name = "tlv320aic3262-codec",
+               .platform_name = "rockchip-audio",
+#if defined(CONFIG_SND_RK29_SOC_I2S_8CH)       
+               .cpu_dai_name = "rk29_i2s.0",
+#elif defined(CONFIG_SND_RK29_SOC_I2S_2CH)
+               .cpu_dai_name = "rk29_i2s.1",
+#else  
+               .cpu_dai_name = "rk29_i2s.2",
+#endif
+               .codec_dai_name = "aic326x-asi2",
+               .ops = &rk29_aif2_ops,
+       },
+
+       
+       {
+               .name = "AIC3262 I2S3",
+               .stream_name = "AIC3262 PCM",
+               .codec_name = "tlv320aic3262-codec",
+               .platform_name = "rockchip-audio",
+#if defined(CONFIG_SND_RK29_SOC_I2S_8CH)       
+               .cpu_dai_name = "rk29_i2s.0",
+#elif defined(CONFIG_SND_RK29_SOC_I2S_2CH)
+               .cpu_dai_name = "rk29_i2s.1",
+#else  
+               .cpu_dai_name = "rk29_i2s.2",
+#endif
+               .codec_dai_name = "aic326x-asi3",
+               .ops = &rk29_aif3_ops,
+       },
+
+};
+
+
+static struct snd_soc_card snd_soc_card_rk29 = {
+       .name = "RK29_AIC3262",
+       .dai_link = rk29_dai,
+       .num_links = ARRAY_SIZE(rk29_dai),
+};
+
+static struct platform_device *rk29_snd_device;
+
+static int __init audio_card_init(void)
+{
+       int ret =0;
+
+       DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);
+
+       rk29_snd_device = platform_device_alloc("soc-audio", -1);
+       if (!rk29_snd_device) {
+                 printk("platform device allocation failed\n");
+                 return -ENOMEM;
+       }
+       
+       platform_set_drvdata(rk29_snd_device, &snd_soc_card_rk29);
+       ret = platform_device_add(rk29_snd_device);
+       if (ret) {
+               printk("platform device add failed\n");
+       //      snd_soc_unregister_dai(&rk29_snd_device->dev);
+               platform_device_put(rk29_snd_device);
+               return ret;
+       }
+       
+       return ret;             
+}
+
+static void __exit audio_card_exit(void)
+{
+       platform_device_unregister(rk29_snd_device);
+}
+
+module_init(audio_card_init);
+module_exit(audio_card_exit);
+
+/* Module information */
+MODULE_AUTHOR("rockchip");
+MODULE_DESCRIPTION("ROCKCHIP i2s ASoC Interface");
+MODULE_LICENSE("GPL");
+
index 4610963ae48f6ce81a2604d5f08af314263cb193..668897314ba54348fd8e377c6e49c770d39448b4 100644 (file)
@@ -3147,7 +3147,7 @@ EXPORT_SYMBOL_GPL(snd_soc_get_volsw_2r_sx);
 int snd_soc_put_volsw_2r_sx(struct snd_kcontrol *kcontrol,
                        struct snd_ctl_elem_value *ucontrol)
 {
-       struct soc_mixer_control *mc =
+       /*struct soc_mixer_control *mc =
                (struct soc_mixer_control *)kcontrol->private_value;
        struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
        unsigned int mask = (1<<mc->shift)-1;
@@ -3175,6 +3175,31 @@ int snd_soc_put_volsw_2r_sx(struct snd_kcontrol *kcontrol,
                        return ret;
        }
 
+       return 0;*/             //sxj modify, this function have bug
+
+       struct soc_mixer_control *mc =
+         (struct soc_mixer_control *)kcontrol->private_value;
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       unsigned int mask = (1<<mc->shift)-1;
+       int min = mc->min;
+       int ret;
+       unsigned int val, valr, oval, ovalr;
+
+       val = ((ucontrol->value.integer.value[0]+min) & 0xff);
+       val &= mask;
+       valr = ((ucontrol->value.integer.value[1]+min) & 0xff);
+       valr &= mask;
+
+       ret = 0;
+       ret = snd_soc_update_bits_locked(codec, mc->reg, mask, val);
+       if(ret < 0)
+               return ret;
+
+       ret = snd_soc_update_bits_locked(codec, mc->rreg, mask, valr);
+
+       if(ret < 0)
+               return ret;
+
        return 0;
 }
 EXPORT_SYMBOL_GPL(snd_soc_put_volsw_2r_sx);