drivers: mfd: Add support for TI aic3262 driver
Manoj Gangwal [Wed, 22 Aug 2012 10:15:42 +0000 (15:15 +0530)]
Bug 1034241

Change-Id: I5607d53cf0bdd25c5e2b8447cd7e676b64cd32a2
Signed-off-by: Manoj Gangwal <mgangwal@nvidia.com>
Reviewed-on: http://git-master/r/125169
Reviewed-by: Automatic_Commit_Validation_User
Reviewed-by: Lokesh Pathak <lpathak@nvidia.com>

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]

index e31f771..10dba0c 100644 (file)
@@ -270,6 +270,11 @@ config TWL6040_CORE
        select MFD_CORE
        default n
 
+config AIC3262_CODEC
+       bool
+       select MFD_CORE
+       default n
+
 config MFD_STMPE
        bool "Support STMicroelectronics STMPE"
        depends on I2C=y && GENERIC_HARDIRQS
index 482cd27..c8dc504 100644 (file)
@@ -49,6 +49,7 @@ obj-$(CONFIG_TWL4030_POWER)    += twl4030-power.o
 obj-$(CONFIG_MFD_TWL4030_AUDIO)        += twl4030-audio.o
 obj-$(CONFIG_TWL6030_PWM)      += twl6030-pwm.o
 obj-$(CONFIG_TWL6040_CORE)     += twl6040-core.o twl6040-irq.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..7b61c74
--- /dev/null
@@ -0,0 +1,885 @@
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/spi/spi.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
+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;
+       int i;
+       u8 *buf = dest;
+
+       BUG_ON(bytes <= 0);
+
+       ret = aic3262->read_dev(aic3262, reg, bytes, dest);
+       if (ret < 0)
+               return ret;
+
+       for (i = 0; i < bytes ; 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;
+       int i;
+
+       BUG_ON(bytes <= 0);
+
+       for (i = 0; i < bytes ; 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;
+
+
+       mutex_lock(&aic3262->io_lock);
+
+       dev_dbg(aic3262->dev, "w 30 %x %x", reg, val);
+       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);
+
+       dev_dbg(aic3262->dev, "w 30 %x %x", reg, r);
+       ret = aic3262_write(aic3262, reg, 1, &r);
+
+out:
+       mutex_unlock(&aic3262->io_lock);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(aic3262_set_bits);
+
+/**
+ * aic3262_wait_bits: wait for a 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)
+ * @sleep: mdelay value in each iteration in milliseconds
+ * @count: iteration count for timeout
+ */
+int aic3262_wait_bits(struct aic3262 *aic3262, unsigned int reg,
+               unsigned char mask, unsigned char val, int sleep, int counter)
+{
+       int status;
+       int timeout =  sleep*counter;
+
+       status = aic3262_reg_read(aic3262, reg);
+       while (((status & mask) != val) && counter) {
+               mdelay(sleep);
+               status = aic3262_reg_read(aic3262, reg);
+               counter--;
+       };
+       if (!counter)
+               dev_err(aic3262->dev,
+                "wait_bits timedout (%d millisecs). lastval 0x%x\n",
+                timeout, status);
+       return counter;
+}
+EXPORT_SYMBOL_GPL(aic3262_wait_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);
+
+       aic3262->suspended = true;
+
+       return 0;
+}
+
+static int aic3262_resume(struct device *dev)
+{
+       struct aic3262 *aic3262 = dev_get_drvdata(dev);
+
+
+       aic3262->suspended = false;
+
+       return 0;
+}
+
+static UNIVERSAL_DEV_PM_OPS(aic3262_pm_ops, aic3262_suspend, aic3262_resume,
+                               NULL);
+#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;
+
+       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,
+                               "Failed to reset aic3262 using gpio %d\n",
+                               pdata->gpio_reset);
+                               goto err_return;
+                       }
+                       gpio_direction_output(pdata->gpio_reset, 1);
+                       mdelay(5);
+                       gpio_direction_output(pdata->gpio_reset, 0);
+                       mdelay(5);
+                       gpio_direction_output(pdata->gpio_reset, 1);
+                       mdelay(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;
+       }
+
+       mdelay(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;
+       case 1:
+               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);
+
+
+       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) {
+                               /* Direction is input */
+                               if (pdata->gpio[i].in) {
+                                       /* 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 si 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
+                               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;
+       }
+
+       pm_runtime_enable(aic3262->dev);
+       pm_runtime_resume(aic3262->dev);
+
+       return 0;
+
+err_irq:
+       aic3262_irq_exit(aic3262);
+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);
+}
+
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+
+
+static int aic3262_i2c_read_device(struct aic3262 *aic3262, unsigned int reg,
+                                 int bytes, void *dest)
+{
+       struct i2c_client *i2c = aic3262->control_data;
+       union aic326x_reg_union *aic_reg = (union 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) {
+               /* 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;
+       }
+
+       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;
+
+       union aic326x_reg_union *aic_reg = (union aic326x_reg_union *) &reg;
+
+       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) {
+               /* 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;
+       }
+
+       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;
+       }
+       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;
+
+       aic3262 = kzalloc(sizeof(struct aic3262), GFP_KERNEL);
+       if (aic3262 == NULL)
+               return -ENOMEM;
+
+       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->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 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;
+       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);
+#endif
+#if defined(CONFIG_SPI_MASTER)
+/* TODO: UGLY
+ * NVidia's CS differs from what TI requires on the SPI bus. So before
+ * we do any write/read we pull down the CS gpio :(
+ * The problem is in spi_read.
+ * Can we set the flag spi_transfer.cs_change during read so that CS is
+ * pulled low until the next transaction occurs
+ * (spi_read requires a spi_write followed by spi_read)
+ */
+#include <linux/gpio.h>
+#include "../../../arch/arm/mach-tegra/gpio-names.h"
+#include <linux/delay.h>
+#define SPI_CS  TEGRA_GPIO_PX3
+#define CS(a)  gpio_set_value(SPI_CS, a)
+void nvidia_spi_cs_en(bool stop)
+{
+       if (stop) {
+               CS(1);
+               udelay(1);
+       } else {
+               CS(0);
+               udelay(1);
+       }
+       return;
+}
+static int aic3262_spi_read_device(struct aic3262 *aic3262, unsigned int reg,
+                                 int bytes, void *dest)
+{
+       struct spi_device *spi = aic3262->control_data;
+       union aic326x_reg_union *aic_reg = (union aic326x_reg_union *) &reg;
+       u8 *write_read_buf;
+       unsigned int i;
+       unsigned int time;
+       unsigned int last_count;
+       unsigned int spi_read_bufsize = max(32, SMP_CACHE_BYTES)-1;
+       struct spi_message      message;
+       struct spi_transfer     x[2];
+       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) {
+               /* 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;
+
+               nvidia_spi_cs_en(0);
+               ret = spi_write(spi, (unsigned char *)buf, 2);
+               nvidia_spi_cs_en(1);
+
+               if (ret < 0)
+                       return ret;
+               buf[0] = (127 << 1) ;
+               buf[1] = book;
+
+               nvidia_spi_cs_en(0);
+               ret = spi_write(spi, (unsigned char *)buf, 2);
+               nvidia_spi_cs_en(1);
+
+               if (ret < 0)
+                       return ret;
+               aic3262->book_no = book;
+               aic3262->page_no = 0x0;
+       }
+
+       if (aic3262->page_no != page) {
+               buf[0] = 0x0;
+               buf[1] = page;
+
+               nvidia_spi_cs_en(0);
+               ret = spi_write(spi, (unsigned char *)buf, 2);
+               nvidia_spi_cs_en(1);
+
+               if (ret < 0)
+                       return ret;
+               aic3262->page_no = page;
+       }
+
+       buf[0] = (offset << 1) | (0x01) ;
+       memset(x, 0, sizeof x);
+       spi_message_init(&message);
+       x[0].len = 1;
+       x[0].tx_buf = buf;
+       x[1].len = bytes;
+       x[1].rx_buf = dest ;
+
+       spi_message_add_tail(&x[0], &message);
+       spi_message_add_tail(&x[1], &message);
+
+       nvidia_spi_cs_en(0);
+       ret = spi_sync(spi, &message);
+       nvidia_spi_cs_en(1);
+       if (ret < 0)
+               return ret;
+
+       return bytes;
+
+}
+/* NVidia's CS differs from what TI requires on the SPI bus. So before
+ * we do any write/read we pull down the CS gpio :(
+ */
+static int aic3262_spi_write_device(struct aic3262 *aic3262, unsigned int reg,
+                                  int bytes, const void *src)
+{
+       struct spi_device *spi = aic3262->control_data;
+       int ret;
+
+       union aic326x_reg_union *aic_reg = (union aic326x_reg_union *) &reg;
+
+       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) {
+               /* 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;
+
+               nvidia_spi_cs_en(0);
+               ret = spi_write(spi, (unsigned char *)buf, 2);
+               nvidia_spi_cs_en(1);
+
+               if (ret < 0)
+                       return ret;
+               buf[0] = (127 << 1) ;
+               buf[1] = book;
+
+               nvidia_spi_cs_en(0);
+               ret = spi_write(spi, (unsigned char *)buf, 2);
+               nvidia_spi_cs_en(1);
+
+               if (ret < 0)
+                       return ret;
+               aic3262->book_no = book;
+               aic3262->page_no = 0x0;
+       }
+
+       if (aic3262->page_no != page) {
+               buf[0] = 0x0;
+               buf[1] = page;
+               nvidia_spi_cs_en(0);
+               ret = spi_write(spi, (unsigned char *) buf, 2);
+               nvidia_spi_cs_en(1);
+               if (ret < 0)
+                       return ret;
+               aic3262->page_no = page;
+       }
+       write_buf[0] = offset << 1 ;
+       memcpy(&write_buf[1], src, bytes);
+       nvidia_spi_cs_en(0);
+       ret = spi_write(spi, write_buf, bytes + 1);
+       nvidia_spi_cs_en(1);
+       if (ret < 0)
+               return ret;
+
+       return bytes;
+}
+
+static int aic3262_spi_probe(struct spi_device *spi)
+{
+       struct aic3262 *aic3262;
+
+       aic3262 = kzalloc(sizeof(struct aic3262), GFP_KERNEL);
+       if (aic3262 == NULL)
+               return -ENOMEM;
+
+       spi_set_drvdata(spi, aic3262);
+       aic3262->dev = &spi->dev;
+       aic3262->control_data = spi;
+       aic3262->read_dev = aic3262_spi_read_device;
+       aic3262->write_dev = aic3262_spi_write_device;
+       spi->bits_per_word = 8;
+       spi->mode = SPI_MODE_1;
+       spi->max_speed_hz = 4000*1000;
+       spi_setup(spi);
+
+       if (strcmp(spi->modalias, "tlv320aic3262") == 0)
+               aic3262->type = TLV320AIC3262;
+       aic3262->book_no = 255;
+       aic3262->page_no = 255;
+
+       return aic3262_device_init(aic3262, spi->irq);
+}
+
+static int aic3262_spi_remove(struct spi_device *spi)
+{
+       struct aic3262 *aic3262 = spi_get_drvdata(spi);
+
+       aic3262_device_exit(aic3262);
+
+       return 0;
+}
+
+static struct spi_driver aic3262_spi_driver = {
+       .driver = {
+               .name = "tlv320aic3262",
+               .owner = THIS_MODULE,
+               .pm = &aic3262_pm_ops,
+       },
+       .probe = aic3262_spi_probe,
+       .remove = aic3262_spi_remove,
+};
+
+static int __init aic3262_spi_init(void)
+{
+       int ret;
+       ret = spi_register_driver(&aic3262_spi_driver);
+       if (ret != 0)
+               pr_err("Failed to register aic3262 SPI driver: %d\n", ret);
+
+       return ret;
+}
+module_init(aic3262_spi_init);
+
+static void __exit aic3262_spi_exit(void)
+{
+       spi_unregister_driver(&aic3262_spi_driver);
+}
+module_exit(aic3262_spi_exit);
+#endif
+
+MODULE_DESCRIPTION("Core support for the TLV320AIC3262 audio CODEC");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Mukund Navada <navada@ti.com>");
diff --git a/drivers/mfd/tlv320aic3262-irq.c b/drivers/mfd/tlv320aic3262-irq.c
new file mode 100644 (file)
index 0000000..7e7a549
--- /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)
+               handle_nested_irq(aic3262->irq_base);
+
+       if (status[2] & aic3262_irqs[AIC3262_IRQ_BUTTON_PRESS].status)
+               handle_nested_irq(aic3262->irq_base + 1);
+       if (status[2] & aic3262_irqs[AIC3262_IRQ_DAC_DRC].status)
+               handle_nested_irq(aic3262->irq_base + 2);
+       if (status[3] & aic3262_irqs[AIC3262_IRQ_AGC_NOISE].status)
+               handle_nested_irq(aic3262->irq_base + 3);
+       if (status[2] & aic3262_irqs[AIC3262_IRQ_OVER_CURRENT].status)
+               handle_nested_irq(aic3262->irq_base + 4);
+       if (status[0] & aic3262_irqs[AIC3262_IRQ_OVERFLOW_EVENT].status)
+               handle_nested_irq(aic3262->irq_base + 5);
+       if (status[3] & aic3262_irqs[AIC3262_IRQ_SPEAKER_OVER_TEMP].status)
+               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..3c79ae9
--- /dev/null
@@ -0,0 +1,237 @@
+#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
+
+union aic326x_reg_union {
+       struct aic326x_reg {
+               u8 offset;
+               u8 page;
+               u8 book;
+               u8 reserved;
+       } aic326x_register;
+       unsigned int aic326x_register_int;
+};
+
+/****************************             ************************************/
+
+/*
+ *****************************************************************************
+ * 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;
+       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. */
+       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 int aic3262_free_irq(struct aic3262 *aic3262, int irq, void *data)
+{
+       if (!aic3262->irq_base)
+               return -EINVAL;
+
+       free_irq(aic3262->irq_base + irq, data);
+       return 0;
+}
+
+/* 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);
+int aic3262_wait_bits(struct aic3262 *aic3262, unsigned int reg,
+                     unsigned char mask, unsigned char val, int delay,
+                     int counter);
+
+int aic3262_irq_init(struct aic3262 *aic3262);
+void aic3262_irq_exit(struct aic3262 *aic3262);
+
+#endif /* End of __MFD_AIC3262_CORE_H__ */
diff --git a/include/linux/mfd/tlv320aic3262-registers.h b/include/linux/mfd/tlv320aic3262-registers.h
new file mode 100644 (file)
index 0000000..bdd7dfe
--- /dev/null
@@ -0,0 +1,323 @@
+
+#ifndef __MFD_AIC3262_REGISTERS_H__
+#define __MFD_AIC3262_REGISTERS_H__
+
+#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_POWER_MASK         0x88
+#define AIC3262_DAC_FLAG               MAKE_REG(0, 0, 37)
+#define AIC3262_LADC_POWER_MASK                0x40
+#define AIC3262_RADC_POWER_MASK                0x04
+#define AIC3262_ADC_POWER_MASK         0x44
+#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 (0b00000100)
+#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     (0b11100000)
+#define AIC3262_ASI_DATA_WORD_LENGTH_MASK      (0b00011000)
+#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_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_CNTL                MAKE_REG(0, 4, 101)
+#define AIC3262_DMIC_CONFIGURE_MASK    (0b00011111)
+#define AIC3262_DMIC_CONFIGURE_SHIFT   (0)
+#define AIC3262_DMIC_GPI1_LEFT_GPI1_RIGHT      (0)
+#define AIC3262_DMIC_GPI2_LEFT_GPI2_RIGHT      (1)
+#define AIC3262_DMIC_DIN1_LEFT_DIN1_RIGHT      (2)
+#define AIC3262_DMIC_DIN2_LEFT_DIN2_RIGHT      (3)
+#define AIC3262_DMIC_GPI01_LEFT_GPI01_RIGHT    (4)
+#define AIC3262_DMIC_GPI02_LEFT_GPI02_RIGHT    (5)
+#define AIC3262_DMIC_MCLK2_LEFT_MCLK2_RIGHT    (6)
+#define AIC3262_DMIC_GPI1_LEFT_GPI2_RIGHT      (7)
+#define AIC3262_DMIC_GPI1_LEFT_DIN1_RIGHT      (8)
+#define AIC3262_DMIC_GPI1_LEFT_DIN2_RIGHT      (9)
+#define AIC3262_DMIC_GPI1_LEFT_GPIO1_RIGHT     (10)
+#define AIC3262_DMIC_GPI1_LEFT_GPIO2_RIGHT     (11)
+#define AIC3262_DMIC_GPI1_LEFT_MCLK2_RIGHT     (12)
+#define AIC3262_DMIC_GPI2_LEFT_DIN1_RIGHT      (13)
+#define AIC3262_DMIC_GPI2_LEFT_DIN2_RIGHT      (14)
+#define AIC3262_DMIC_GPI2_LEFT_GPIO1_RIGHT     (15)
+#define AIC3262_DMIC_GPI2_LEFT_GPIO2_RIGHT     (16)
+#define AIC3262_DMIC_GPI2_LEFT_MCLK2_RIGHT     (17)
+#define AIC3262_DMIC_DIN1_LEFT_DIN2_RIGHT      (18)
+#define AIC3262_DMIC_DIN1_LEFT_GPIO1_RIGHT     (19)
+#define AIC3262_DMIC_DIN1_LEFT_GPIO2_RIGHT     (20)
+#define AIC3262_DMIC_DIN1_LEFT_MCLK2_RIGHT     (21)
+#define AIC3262_DMIC_DIN2_LEFT_GPIO1_RIGHT     (22)
+#define AIC3262_DMIC_DIN2_LEFT_GPIO2_RIGHT     (23)
+#define AIC3262_DMIC_DIN2_LEFT_MCLK2_RIGHT     (24)
+#define AIC3262_DMIC_GPI01_LEFT_GPI02_RIGHT    (25)
+#define AIC3262_DMIC_GPI01_LEFT_MCLK2_RIGHT    (26)
+#define AIC3262_DMIC_GPI02_LEFT_MCLK2_RIGHT    (27)
+#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