drivers: mfd: Add support for TI aic326x codec
Manoj Gangwal [Thu, 22 Nov 2012 06:41:49 +0000 (11:41 +0530)]
Add support for TI aic326x K3.4 codec driver

Bug 1179798

Change-Id: Icf0a275d318cf05679f8e99afdce53450a447d82
Signed-off-by: Manoj Gangwal <mgangwal@nvidia.com>
Reviewed-on: http://git-master/r/165616
Reviewed-by: Automatic_Commit_Validation_User
GVS: Gerrit_Virtual_Submit
Reviewed-by: Vijay Mali <vmali@nvidia.com>
Reviewed-by: Scott Peterson <speterson@nvidia.com>

drivers/mfd/Kconfig
drivers/mfd/Makefile
drivers/mfd/tlv320aic3262-core.c [deleted file]
drivers/mfd/tlv320aic3xxx-core.c [new file with mode: 0644]
drivers/mfd/tlv320aic3xxx-i2c.c [new file with mode: 0644]
drivers/mfd/tlv320aic3xxx-irq.c [moved from drivers/mfd/tlv320aic3262-irq.c with 71% similarity]
drivers/mfd/tlv320aic3xxx-spi.c [new file with mode: 0644]
include/linux/mfd/tlv320aic3262-registers.h
include/linux/mfd/tlv320aic3xxx-core.h [moved from include/linux/mfd/tlv320aic3262-core.h with 68% similarity]

index 989fc08..5e18375 100644 (file)
@@ -279,10 +279,18 @@ config TWL6040_CORE
          additional drivers must be enabled in order to use the
          functionality of the device (audio, vibra).
 
-config AIC3262_CODEC
-       bool
+config AIC3XXX_CORE
+       bool "Support for AIC3XXX audio codec"
+       depends on I2C=y && GENERIC_HARDIRQS
        select MFD_CORE
+       select REGMAP_I2C
        default n
+       help
+         Say yes here if you want support for Texas Instruments AIC3XXX audio
+         codec.
+         This driver provides common support for accessing the device,
+         additional drivers must be enabled in order to use the
+         functionality of the device (audio, vibra).
 
 config MFD_STMPE
        bool "Support STMicroelectronics STMPE"
index 7d15ab5..00fc5cc 100644 (file)
@@ -52,8 +52,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_AIC3XXX_CORE)     += tlv320aic3xxx-i2c.o tlv320aic3xxx-spi.o tlv320aic3xxx-core.o tlv320aic3xxx-irq.o
 obj-$(CONFIG_MFD_MC13XXX)      += mc13xxx-core.o
 
 obj-$(CONFIG_MFD_CORE)         += mfd-core.o
diff --git a/drivers/mfd/tlv320aic3262-core.c b/drivers/mfd/tlv320aic3262-core.c
deleted file mode 100644 (file)
index 7b61c74..0000000
+++ /dev/null
@@ -1,885 +0,0 @@
-
-#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/tlv320aic3xxx-core.c b/drivers/mfd/tlv320aic3xxx-core.c
new file mode 100644 (file)
index 0000000..798e010
--- /dev/null
@@ -0,0 +1,530 @@
+/*
+ * tlv320aic3xxx-core.c  -- driver for TLV320AIC3XXX
+ *
+ * Author:      Mukund Navada <navada@ti.com>
+ *              Mehar Bajwa <mehar.bajwa@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/err.h>
+#include <linux/delay.h>
+#include <linux/regmap.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/tlv320aic3xxx-core.h>
+#include <linux/mfd/tlv320aic3262-registers.h>
+
+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,
+        },
+};
+
+int set_aic3xxx_book(struct aic3xxx *aic3xxx, int book)
+{
+       int ret = 0;
+       u8 page_buf[] = { 0x0, 0x0 };
+       u8 book_buf[] = { 0x7f, 0x0 };
+
+       ret = regmap_write(aic3xxx->regmap, page_buf[0], page_buf[1]);
+
+       if (ret < 0)
+               return ret;
+       book_buf[1] = book;
+       ret = regmap_write(aic3xxx->regmap, book_buf[0], book_buf[1]);
+
+       if (ret < 0)
+               return ret;
+       aic3xxx->book_no = book;
+       aic3xxx->page_no = 0;
+
+       return ret;
+}
+
+int set_aic3xxx_page(struct aic3xxx *aic3xxx, int page)
+{
+       int ret = 0;
+       u8 page_buf[] = { 0x0, 0x0 };
+
+       page_buf[1] = page;
+       ret = regmap_write(aic3xxx->regmap, page_buf[0], page_buf[1]);
+
+       if (ret < 0)
+               return ret;
+       aic3xxx->page_no = page;
+       return ret;
+}
+/**
+ * aic3xxx_reg_read: Read a single TLV320AIC3262 register.
+ *
+ * @aic3xxx: Device to read from.
+ * @reg: Register to read.
+ */
+int aic3xxx_reg_read(struct aic3xxx *aic3xxx, unsigned int reg)
+{
+       unsigned int val;
+       int ret;
+       union aic3xxx_reg_union *aic_reg = (union aic3xxx_reg_union *) &reg;
+       u8 book, page, offset;
+
+       page = aic_reg->aic3xxx_register.page;
+       book = aic_reg->aic3xxx_register.book;
+       offset = aic_reg->aic3xxx_register.offset;
+
+       mutex_lock(&aic3xxx->io_lock);
+       if (aic3xxx->book_no != book) {
+               ret = set_aic3xxx_book(aic3xxx, book);
+               if (ret < 0) {
+                       mutex_unlock(&aic3xxx->io_lock);
+                       return ret;
+               }
+       }
+
+       if (aic3xxx->page_no != page) {
+               ret = set_aic3xxx_page(aic3xxx, page);
+               if (ret < 0) {
+                       mutex_unlock(&aic3xxx->io_lock);
+                       return ret;
+               }
+       }
+       ret = regmap_read(aic3xxx->regmap, offset, &val);
+       mutex_unlock(&aic3xxx->io_lock);
+
+       if (ret < 0)
+               return ret;
+       else
+               return val;
+}
+EXPORT_SYMBOL_GPL(aic3xxx_reg_read);
+
+/**
+ * aic3xxx_bulk_read: Read multiple TLV320AIC3262 registers
+ *
+ * @aic3xxx: Device to read from
+ * @reg: First register
+ * @count: Number of registers
+ * @buf: Buffer to fill.  The data will be returned big endian.
+ */
+int aic3xxx_bulk_read(struct aic3xxx *aic3xxx, unsigned int reg,
+                     int count, u8 *buf)
+{
+       int ret;
+       union aic3xxx_reg_union *aic_reg = (union aic3xxx_reg_union *) &reg;
+       u8 book, page, offset;
+
+       page = aic_reg->aic3xxx_register.page;
+       book = aic_reg->aic3xxx_register.book;
+       offset = aic_reg->aic3xxx_register.offset;
+
+       mutex_lock(&aic3xxx->io_lock);
+       if (aic3xxx->book_no != book) {
+               ret = set_aic3xxx_book(aic3xxx, book);
+               if (ret < 0) {
+                       mutex_unlock(&aic3xxx->io_lock);
+                       return ret;
+               }
+       }
+
+       if (aic3xxx->page_no != page) {
+               ret = set_aic3xxx_page(aic3xxx, page);
+               if (ret < 0) {
+                       mutex_unlock(&aic3xxx->io_lock);
+                       return ret;
+               }
+       }
+       ret = regmap_bulk_read(aic3xxx->regmap, offset, buf, count);
+       mutex_unlock(&aic3xxx->io_lock);
+               return ret;
+}
+EXPORT_SYMBOL_GPL(aic3xxx_bulk_read);
+
+/**
+ * aic3xxx_reg_write: Write a single TLV320AIC3262 register.
+ *
+ * @aic3xxx: Device to write to.
+ * @reg: Register to write to.
+ * @val: Value to write.
+ */
+int aic3xxx_reg_write(struct aic3xxx *aic3xxx, unsigned int reg,
+                     unsigned char val)
+{
+       union aic3xxx_reg_union *aic_reg = (union aic3xxx_reg_union *) &reg;
+       int ret = 0;
+       u8 page, book, offset;
+
+       page = aic_reg->aic3xxx_register.page;
+       book = aic_reg->aic3xxx_register.book;
+       offset = aic_reg->aic3xxx_register.offset;
+
+       mutex_lock(&aic3xxx->io_lock);
+       if (book != aic3xxx->book_no) {
+               ret = set_aic3xxx_book(aic3xxx, book);
+               if (ret < 0) {
+                       mutex_unlock(&aic3xxx->io_lock);
+                       return ret;
+               }
+       }
+       if (page != aic3xxx->page_no) {
+               ret = set_aic3xxx_page(aic3xxx, page);
+               if (ret < 0) {
+                       mutex_unlock(&aic3xxx->io_lock);
+                       return ret;
+               }
+       }
+       ret = regmap_write(aic3xxx->regmap, offset, val);
+       mutex_unlock(&aic3xxx->io_lock);
+       return ret;
+
+}
+EXPORT_SYMBOL_GPL(aic3xxx_reg_write);
+
+/**
+ * aic3xxx_bulk_write: Write multiple TLV320AIC3262 registers
+ *
+ * @aic3xxx: Device to write to
+ * @reg: First register
+ * @count: Number of registers
+ * @buf: Buffer to write from.  Data must be big-endian formatted.
+ */
+int aic3xxx_bulk_write(struct aic3xxx *aic3xxx, unsigned int reg,
+                      int count, const u8 *buf)
+{
+       union aic3xxx_reg_union *aic_reg = (union aic3xxx_reg_union *) &reg;
+       int ret = 0;
+       u8 page, book, offset;
+
+       page = aic_reg->aic3xxx_register.page;
+       book = aic_reg->aic3xxx_register.book;
+       offset = aic_reg->aic3xxx_register.offset;
+
+       mutex_lock(&aic3xxx->io_lock);
+       if (book != aic3xxx->book_no) {
+               ret = set_aic3xxx_book(aic3xxx, book);
+               if (ret < 0) {
+                       mutex_unlock(&aic3xxx->io_lock);
+                       return ret;
+               }
+       }
+       if (page != aic3xxx->page_no) {
+               ret = set_aic3xxx_page(aic3xxx, page);
+               if (ret < 0) {
+                       mutex_unlock(&aic3xxx->io_lock);
+                       return ret;
+               }
+       }
+       ret = regmap_raw_write(aic3xxx->regmap, offset, buf, count);
+       mutex_unlock(&aic3xxx->io_lock);
+       return ret;
+}
+EXPORT_SYMBOL_GPL(aic3xxx_bulk_write);
+
+/**
+ * aic3xxx_set_bits: Set the value of a bitfield in a TLV320AIC3262 register
+ *
+ * @aic3xxx: Device to write to.
+ * @reg: Register to write to.
+ * @mask: Mask of bits to set.
+ * @val: Value to set (unshifted)
+ */
+int aic3xxx_set_bits(struct aic3xxx *aic3xxx, unsigned int reg,
+                    unsigned char mask, unsigned char val)
+{
+       union aic3xxx_reg_union *aic_reg = (union aic3xxx_reg_union *) &reg;
+       int ret = 0;
+       u8 page, book, offset;
+
+       page = aic_reg->aic3xxx_register.page;
+       book = aic_reg->aic3xxx_register.book;
+       offset = aic_reg->aic3xxx_register.offset;
+
+       mutex_lock(&aic3xxx->io_lock);
+       if (book != aic3xxx->book_no) {
+               ret = set_aic3xxx_book(aic3xxx, book);
+               if (ret < 0) {
+                       mutex_unlock(&aic3xxx->io_lock);
+                       return ret;
+               }
+       }
+       if (page != aic3xxx->page_no) {
+               ret = set_aic3xxx_page(aic3xxx, page);
+               if (ret < 0) {
+                       mutex_unlock(&aic3xxx->io_lock);
+                       return ret;
+               }
+       }
+       ret = regmap_update_bits(aic3xxx->regmap, offset, mask, val);
+       mutex_unlock(&aic3xxx->io_lock);
+       return ret;
+
+}
+EXPORT_SYMBOL_GPL(aic3xxx_set_bits);
+
+/**
+ * aic3xxx_wait_bits: wait for a value of a bitfield in a TLV320AIC3262 register
+ *
+ * @aic3xxx: Device to write to.
+ * @reg: Register to write to.
+ * @mask: Mask of bits to set.
+ * @val: Value to set (unshifted)
+ * @mdelay: mdelay value in each iteration in milliseconds
+ * @count: iteration count for timeout
+ */
+int aic3xxx_wait_bits(struct aic3xxx *aic3xxx, unsigned int reg,
+                     unsigned char mask, unsigned char val, int sleep,
+                     int counter)
+{
+       int status;
+       int timeout = sleep * counter;
+
+       status = aic3xxx_reg_read(aic3xxx, reg);
+       while (((status & mask) != val) && counter) {
+               mdelay(sleep);
+               status = aic3xxx_reg_read(aic3xxx, reg);
+               counter--;
+       };
+       if (!counter)
+               dev_err(aic3xxx->dev,
+                       "wait_bits timedout (%d millisecs). lastval 0x%x\n",
+                       timeout, status);
+       return counter;
+}
+EXPORT_SYMBOL_GPL(aic3xxx_wait_bits);
+
+static struct mfd_cell aic3262_devs[] = {
+       {
+        .name = "tlv320aic3262-codec",
+       },
+       {
+       .name = "tlv320aic3262-gpio",
+       },
+};
+
+static struct mfd_cell aic3285_devs[] = {
+       { .name = "tlv320aic3285-codec" },
+       { .name = "tlv320aic3285-extcon" },
+       { .name = "tlv320aic3285-gpio" },
+};
+
+/**
+ * Instantiate the generic non-control parts of the device.
+ */
+int aic3xxx_device_init(struct aic3xxx *aic3xxx, int irq)
+{
+       struct aic3xxx_pdata *pdata = aic3xxx->dev->platform_data;
+       const char *devname;
+       int ret, i;
+       u8 resetVal = 1;
+
+       dev_info(aic3xxx->dev, "aic3xxx_device_init beginning\n");
+
+       mutex_init(&aic3xxx->io_lock);
+       dev_set_drvdata(aic3xxx->dev, aic3xxx);
+
+       if (!pdata)
+               return -EINVAL;
+
+       /*GPIO reset for TLV320AIC3262 codec */
+       if (pdata->gpio_reset) {
+               ret = gpio_request(pdata->gpio_reset, "aic3xxx-reset-pin");
+               if (ret != 0) {
+                       dev_err(aic3xxx->dev, "not able to acquire gpio\n");
+                       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 = aic3xxx_reg_write(aic3xxx, AIC3262_RESET_REG, resetVal);
+       if (ret < 0) {
+               dev_err(aic3xxx->dev, "Could not write to AIC3262 register\n");
+               goto err_return;
+       }
+
+       mdelay(10);
+
+       ret = aic3xxx_reg_read(aic3xxx, AIC3262_DEVICE_ID);
+       if (ret < 0) {
+               dev_err(aic3xxx->dev, "Failed to read ID register\n");
+               goto err_return;
+       }
+
+       switch (ret) {
+       case 3:
+               devname = "TLV320AIC3262";
+               if (aic3xxx->type != TLV320AIC3262)
+                       dev_warn(aic3xxx->dev, "Device registered as type %d\n",
+                                aic3xxx->type);
+               aic3xxx->type = TLV320AIC3262;
+               break;
+       case 4:
+               devname = "TLV320AIC3285";
+               if (aic3xxx->type != TLV320AIC3285)
+                       dev_warn(aic3xxx->dev, "Device registered as type %d\n",
+                                aic3xxx->type);
+               aic3xxx->type = TLV320AIC3285;
+       default:
+               dev_err(aic3xxx->dev, "Device is not a TLV320AIC3262");
+               ret = -EINVAL;
+               goto err_return;
+       }
+
+       dev_info(aic3xxx->dev, "%s revision %c\n", devname, 'D' + ret);
+
+       /*If naudint is gpio convert it to irq number */
+       if (pdata->gpio_irq == 1) {
+               aic3xxx->irq = gpio_to_irq(pdata->naudint_irq);
+               gpio_request(pdata->naudint_irq, "aic3xxx-gpio-irq");
+               gpio_direction_input(pdata->naudint_irq);
+       } else
+               aic3xxx->irq = pdata->naudint_irq;
+
+       aic3xxx->irq_base = pdata->irq_base;
+       for (i = 0; i < AIC3262_NUM_GPIO; i++) {
+               if (pdata->gpio[i].used) {
+                       if (pdata->gpio[i].in) {
+                               aic3xxx_set_bits(aic3xxx,
+                                                aic3262_gpio_control[i].reg,
+                                                aic3262_gpio_control[i].mask,
+                                                0x1 << aic3262_gpio_control[i].
+                                                shift);
+                               if (pdata->gpio[i].in_reg) {
+                                       aic3xxx_set_bits(aic3xxx,
+                                                        pdata->gpio[i].in_reg,
+                                                        pdata->gpio[i].
+                                                        in_reg_bitmask,
+                                                        pdata->gpio[i].
+                                                        value << pdata->
+                                                        gpio[i].in_reg_shift);
+                               }
+                       } else {
+                               aic3xxx_set_bits(aic3xxx,
+                                                aic3262_gpio_control[i].reg,
+                                                aic3262_gpio_control[i].mask,
+                                                pdata->gpio[i].
+                                                value <<
+                                                aic3262_gpio_control[i].shift);
+                       }
+               } else
+                       aic3xxx_set_bits(aic3xxx, aic3262_gpio_control[i].reg,
+                                        aic3262_gpio_control[i].mask, 0x0);
+       }
+
+       /* codec interrupt */
+       if (aic3xxx->irq) {
+               ret = aic3xxx_irq_init(aic3xxx);
+               if (ret < 0)
+                       goto err_irq;
+       }
+       switch (aic3xxx->type) {
+       case TLV320AIC3262:
+               ret = mfd_add_devices(aic3xxx->dev, -1,
+                             aic3262_devs, ARRAY_SIZE(aic3262_devs), NULL, 0);
+               break;
+
+       case TLV320AIC3285:
+               ret = mfd_add_devices(aic3xxx->dev, -1,
+                             aic3285_devs, ARRAY_SIZE(aic3285_devs), NULL, 0);
+               break;
+       case TLV320AIC3266:
+               break;
+
+       default:
+               dev_err(aic3xxx->dev, "unable to recognize codec\n");
+       }
+       if (ret != 0) {
+               dev_err(aic3xxx->dev, "Failed to add children: %d\n", ret);
+               goto err_mfd;
+       }
+       dev_info(aic3xxx->dev, "aic3xxx_device_init added mfd devices\n");
+
+       return 0;
+
+err_mfd:
+
+       aic3xxx_irq_exit(aic3xxx);
+err_irq:
+
+       if (pdata && pdata->gpio_irq)
+               gpio_free(pdata->naudint_irq);
+err_return:
+
+       if (pdata && pdata->gpio_reset)
+               gpio_free(pdata->gpio_reset);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(aic3xxx_device_init);
+
+void aic3xxx_device_exit(struct aic3xxx *aic3xxx)
+{
+       struct aic3xxx_pdata *pdata = aic3xxx->dev->platform_data;
+
+       pm_runtime_disable(aic3xxx->dev);
+       mfd_remove_devices(aic3xxx->dev);
+       aic3xxx_irq_exit(aic3xxx);
+
+       if (pdata && pdata->gpio_irq)
+               gpio_free(pdata->naudint_irq);
+       if (pdata && pdata->gpio_reset)
+               gpio_free(pdata->gpio_reset);
+
+}
+EXPORT_SYMBOL_GPL(aic3xxx_device_exit);
+
+MODULE_AUTHOR("Mukund Navada <navada@ti.comm>");
+MODULE_AUTHOR("Mehar Bajwa <mehar.bajwa@ti.com>");
+MODULE_DESCRIPTION("Core support for the TLV320AIC3XXX audio CODEC");
+MODULE_LICENSE("GPL");
diff --git a/drivers/mfd/tlv320aic3xxx-i2c.c b/drivers/mfd/tlv320aic3xxx-i2c.c
new file mode 100644 (file)
index 0000000..9de5dae
--- /dev/null
@@ -0,0 +1,133 @@
+/*
+ * tlv320aic3xxx-i2c.c  -- driver for TLV320AIC3XXX TODO
+ *
+ * Author:     Mukund Navada <navada@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+#include <linux/slab.h>
+
+#include <linux/mfd/tlv320aic3xxx-core.h>
+
+struct regmap_config aicxxx_i2c_regmap = {
+       .reg_bits = 8,
+       .val_bits = 8,
+       .cache_type = REGCACHE_NONE,
+};
+
+#ifdef CONFIG_PM
+static int aic3xxx_suspend(struct device *dev)
+{
+       struct aic3xxx *aic3xxx = dev_get_drvdata(dev);
+
+       aic3xxx->suspended = true;
+
+       return 0;
+}
+
+static int aic3xxx_resume(struct device *dev)
+{
+       struct aic3xxx *aic3xxx = dev_get_drvdata(dev);
+
+       aic3xxx->suspended = false;
+
+       return 0;
+}
+#endif
+
+static __devinit int aic3xxx_i2c_probe(struct i2c_client *i2c,
+                                         const struct i2c_device_id *id)
+{
+       struct aic3xxx *aicxxx;
+       const struct regmap_config *regmap_config;
+       int ret;
+
+       switch (id->driver_data) {
+       case TLV320AIC3262:
+               regmap_config = &aicxxx_i2c_regmap;
+               break;
+#ifdef CONFIG_MFD_AIC3285
+       case TLV320AIC3285:
+               regmap_config = &aicxxx_i2c_regmap;
+               break;
+#endif
+       default:
+               dev_err(&i2c->dev, "Unknown device type %ld\n",
+                       id->driver_data);
+               return -EINVAL;
+       }
+
+       aicxxx = devm_kzalloc(&i2c->dev, sizeof(*aicxxx), GFP_KERNEL);
+       if (aicxxx == NULL)
+               return -ENOMEM;
+
+       aicxxx->regmap = devm_regmap_init_i2c(i2c, regmap_config);
+
+       if (IS_ERR(aicxxx->regmap)) {
+               ret = PTR_ERR(aicxxx->regmap);
+               dev_err(&i2c->dev, "Failed to allocate register map: %d\n",
+                       ret);
+               return ret;
+       }
+
+       aicxxx->type = id->driver_data;
+       aicxxx->dev = &i2c->dev;
+       aicxxx->irq = i2c->irq;
+
+       return aic3xxx_device_init(aicxxx, aicxxx->irq);
+}
+
+static int __devexit aic3xxx_i2c_remove(struct i2c_client *i2c)
+{
+       struct aic3xxx *aicxxx = dev_get_drvdata(&i2c->dev);
+       aic3xxx_device_exit(aicxxx);
+       return 0;
+}
+
+static const struct i2c_device_id aic3xxx_i2c_id[] = {
+       {"tlv320aic3262", TLV320AIC3262},
+       {"tlv320aic3285", TLV320AIC3285},
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, aic3xxx_i2c_id);
+
+static UNIVERSAL_DEV_PM_OPS(aic3xxx_pm_ops, aic3xxx_suspend, aic3xxx_resume,
+                               NULL);
+
+static struct i2c_driver aic3xxx_i2c_driver = {
+       .driver = {
+               .name   = "tlv320aic3xxx",
+               .owner  = THIS_MODULE,
+               .pm     = &aic3xxx_pm_ops,
+       },
+       .probe          = aic3xxx_i2c_probe,
+       .remove         = __devexit_p(aic3xxx_i2c_remove),
+       .id_table       = aic3xxx_i2c_id,
+};
+
+module_i2c_driver(aic3xxx_i2c_driver);
+
+MODULE_DESCRIPTION("TLV320AIC3XXX I2C bus interface");
+MODULE_AUTHOR("Mukund Navada <navada@ti.com>");
+MODULE_LICENSE("GPL");
similarity index 71%
rename from drivers/mfd/tlv320aic3262-irq.c
rename to drivers/mfd/tlv320aic3xxx-irq.c
index 7e7a549..b05a097 100644 (file)
@@ -1,3 +1,25 @@
+/*
+ * tlv320aic3262-irq.c  --  Interrupt controller support for
+ *                      TI OMAP44XX TLV320AIC3262
+ *
+ * Author:      Mukund Navada <navada@ti.com>
+ *              Mehar Bajwa <mehar.bajwa@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
 
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/mfd/core.h>
 #include <linux/interrupt.h>
 
-#include <linux/mfd/tlv320aic3262-core.h>
+#include <linux/mfd/tlv320aic3xxx-core.h>
 #include <linux/mfd/tlv320aic3262-registers.h>
 
 #include <linux/delay.h>
+
 struct aic3262_irq_data {
        int mask;
        int status;
@@ -56,7 +79,7 @@ struct aic3262_gpio_data {
 
 };
 
-static inline struct aic3262_irq_data *irq_to_aic3262_irq(struct aic3262
+static inline struct aic3262_irq_data *irq_to_aic3262_irq(struct aic3xxx
                                                          *aic3262, int irq)
 {
        return &aic3262_irqs[irq - aic3262->irq_base];
@@ -64,19 +87,19 @@ static inline struct aic3262_irq_data *irq_to_aic3262_irq(struct aic3262
 
 static void aic3262_irq_lock(struct irq_data *data)
 {
-       struct aic3262 *aic3262 = irq_data_get_irq_chip_data(data);
+       struct aic3xxx *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);
+       struct aic3xxx *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,
+               aic3xxx_reg_write(aic3262, AIC3262_INT1_CNTL,
                                  aic3262->irq_masks_cur);
        }
 
@@ -85,7 +108,7 @@ static void aic3262_irq_sync_unlock(struct irq_data *data)
 
 static void aic3262_irq_unmask(struct irq_data *data)
 {
-       struct aic3262 *aic3262 = irq_data_get_irq_chip_data(data);
+       struct aic3xxx *aic3262 = irq_data_get_irq_chip_data(data);
        struct aic3262_irq_data *irq_data =
            irq_to_aic3262_irq(aic3262, data->irq);
 
@@ -94,7 +117,7 @@ static void aic3262_irq_unmask(struct irq_data *data)
 
 static void aic3262_irq_mask(struct irq_data *data)
 {
-       struct aic3262 *aic3262 = irq_data_get_irq_chip_data(data);
+       struct aic3xxx *aic3262 = irq_data_get_irq_chip_data(data);
        struct aic3262_irq_data *irq_data =
            irq_to_aic3262_irq(aic3262, data->irq);
 
@@ -111,17 +134,16 @@ static struct irq_chip aic3262_irq_chip = {
 
 static irqreturn_t aic3262_irq_thread(int irq, void *data)
 {
-       struct aic3262 *aic3262 = data;
+       struct aic3xxx *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);
+
+       /* Reading sticky bit registers acknowledges
+               the interrupt to the device */
+       aic3xxx_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)
@@ -141,7 +163,7 @@ static irqreturn_t aic3262_irq_thread(int irq, void *data)
        return IRQ_HANDLED;
 }
 
-int aic3262_irq_init(struct aic3262 *aic3262)
+int aic3xxx_irq_init(struct aic3xxx *aic3262)
 {
        int cur_irq, ret;
 
@@ -150,7 +172,7 @@ int aic3262_irq_init(struct aic3262 *aic3262)
        /* mask the individual interrupt sources */
        aic3262->irq_masks_cur = 0x0;
        aic3262->irq_masks_cache = 0x0;
-       aic3262_reg_write(aic3262, AIC3262_INT1_CNTL, 0x0);
+       aic3xxx_reg_write(aic3262, AIC3262_INT1_CNTL, 0x0);
 
        if (!aic3262->irq) {
                dev_warn(aic3262->dev,
@@ -186,7 +208,7 @@ int aic3262_irq_init(struct aic3262 *aic3262)
        ret = request_threaded_irq(aic3262->irq, NULL, aic3262_irq_thread,
                                   IRQF_TRIGGER_RISING,
                                   "tlv320aic3262", aic3262);
-       if (ret) {
+       if (ret < 0) {
                dev_err(aic3262->dev, "failed to request IRQ %d: %d\n",
                        aic3262->irq, ret);
                return ret;
@@ -194,11 +216,16 @@ int aic3262_irq_init(struct aic3262 *aic3262)
 
        return 0;
 }
-EXPORT_SYMBOL(aic3262_irq_init);
+EXPORT_SYMBOL(aic3xxx_irq_init);
 
-void aic3262_irq_exit(struct aic3262 *aic3262)
+void aic3xxx_irq_exit(struct aic3xxx *aic3262)
 {
        if (aic3262->irq)
                free_irq(aic3262->irq, aic3262);
 }
-EXPORT_SYMBOL(aic3262_irq_exit);
+EXPORT_SYMBOL(aic3xxx_irq_exit);
+MODULE_AUTHOR("Mukund navada <navada@ti.com>");
+MODULE_AUTHOR("Mehar Bajwa <mehar.bajwa@ti.com>");
+MODULE_DESCRIPTION
+       ("Interrupt controller support for TI OMAP44XX TLV320AIC3262");
+MODULE_LICENSE("GPL");
diff --git a/drivers/mfd/tlv320aic3xxx-spi.c b/drivers/mfd/tlv320aic3xxx-spi.c
new file mode 100644 (file)
index 0000000..6f1426a
--- /dev/null
@@ -0,0 +1,91 @@
+
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+#include <linux/slab.h>
+#include <linux/spi/spi.h>
+
+#include <linux/mfd/tlv320aic3xxx-core.h>
+
+struct regmap_config tlv320aic3xxx_spi_regmap = {
+       .reg_bits = 8,
+       .val_bits = 8,
+       .cache_type = REGCACHE_NONE,
+       .read_flag_mask = 0x1,
+};
+
+static int __devinit tlv320aic3xxx_spi_probe(struct spi_device *spi)
+{
+       const struct spi_device_id *id = spi_get_device_id(spi);
+       struct aic3xxx *tlv320aic3xxx;
+       const struct regmap_config *regmap_config;
+       int ret;
+
+       switch (id->driver_data) {
+#ifdef CONFIG_SND_SOC_AIC3262
+       case TLV320AIC3262:
+               regmap_config = &tlv320aic3xxx_spi_regmap;
+               break;
+#endif
+#ifdef CONFIG_MFD_AIC3285
+       case TLV320AIC3285:
+               regmap_config = &tlv320aic3285_spi_regmap;
+               break;
+#endif
+       default:
+               dev_err(&spi->dev, "Unknown device type %ld\n",
+                       id->driver_data);
+               return -EINVAL;
+       }
+
+       tlv320aic3xxx =
+               devm_kzalloc(&spi->dev, sizeof(struct aic3xxx), GFP_KERNEL);
+       if (tlv320aic3xxx == NULL)
+               return -ENOMEM;
+
+       tlv320aic3xxx->regmap = devm_regmap_init_spi(spi, regmap_config);
+       if (IS_ERR(tlv320aic3xxx->regmap)) {
+               ret = PTR_ERR(tlv320aic3xxx->regmap);
+               dev_err(&spi->dev, "Failed to allocate register map: %d\n",
+                       ret);
+               return ret;
+       }
+
+       tlv320aic3xxx->type = id->driver_data;
+       tlv320aic3xxx->dev = &spi->dev;
+       tlv320aic3xxx->irq = spi->irq;
+
+       return aic3xxx_device_init(tlv320aic3xxx, tlv320aic3xxx->irq);
+}
+
+static int __devexit tlv320aic3xxx_spi_remove(struct spi_device *spi)
+{
+       struct aic3xxx *tlv320aic3xxx = dev_get_drvdata(&spi->dev);
+       aic3xxx_device_exit(tlv320aic3xxx);
+       return 0;
+}
+
+static const struct spi_device_id aic3xxx_spi_ids[] = {
+       {"tlv320aic3262", TLV320AIC3262},
+       {"tlv320aic3285", TLV320AIC3285},
+       { }
+};
+MODULE_DEVICE_TABLE(spi, aic3xxx_spi_ids);
+
+static struct spi_driver tlv320aic3xxx_spi_driver = {
+       .driver = {
+               .name   = "tlv320aic3xxx",
+               .owner  = THIS_MODULE,
+       },
+       .probe          = tlv320aic3xxx_spi_probe,
+       .remove         = __devexit_p(tlv320aic3xxx_spi_remove),
+       .id_table       = aic3xxx_spi_ids,
+};
+
+module_spi_driver(tlv320aic3xxx_spi_driver);
+
+MODULE_DESCRIPTION("TLV320AIC3XXX SPI bus interface");
+MODULE_AUTHOR("Mukund Navada <navada@ti.com>");
+MODULE_LICENSE("GPL");
index 38d45d1..0a06bcc 100644 (file)
@@ -69,8 +69,8 @@
 #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_LDAC_POWER_STATUS_MASK         0x80
+#define AIC3262_RDAC_POWER_STATUS_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_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)
+#define AIC3262_DEVICE_ID              MAKE_REG(0, 0, 125)
 /* ****************** Page 1 Registers **************************************/
 #define AIC3262_PAGE_1                 128
 
 #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
+#define AIC3262_HPL_POWER_MASK         (0b00000010)
+#define AIC3262_HPR_POWER_MASK         (0b00000001)
+#define AIC3262_SPKL_POWER_STATUS_MASK         0x2
+#define AIC3262_SPKR_POWER_STATUS_MASK         0x1
+#define AIC3262_HPL_POWER_STATUS_MASK          0x20
+#define AIC3262_HPR_POWER_STATUS_MASK          0x10
+
+#define AIC3262_HP_STAGE_MASK          (0b01100000)
+#define AIC3262_HP_STAGE_100           (0)
+#define AIC3262_HP_STAGE_75            (1)
+#define AIC3262_HP_STAGE_50            (2)
+#define AIC3262_HP_STAGE_25            (3)
+#define AIC3262_HP_STAGE_SHIFT         (5)
+#define AIC3262_DYNAMIC_OFFSET_CALIB_MASK      (0b00100000)
+#define AIC3262_DYNAMIC_OFFSET_CALIB           (0b00100000)
+
 /* MIC PGA Gain Registers */
 #define AIC3262_MICL_PGA               MAKE_REG(0, 1, 59)
 #define AIC3262_MICR_PGA               MAKE_REG(0, 1, 60)
 #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_BCLK_N_MASK       (0b01111111)
+#define AIC3262_ASI1_WCLK_N_MASK       (0b01111111)
+#define AIC3262_ASI1_CHNL_MASK         (0b11000000)
+#define AIC3262_ASI1_DAC_OUT_OFFSET    (0b00000001)
 #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_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_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_INPUT_CONTROL     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
similarity index 68%
rename from include/linux/mfd/tlv320aic3262-core.h
rename to include/linux/mfd/tlv320aic3xxx-core.h
index 3c79ae9..56ed728 100644 (file)
@@ -1,10 +1,34 @@
+/*
+ * MFD driver for aic3262
+ *
+ * Author:      Mukund Navada <navada@ti.com>
+ *              Mehar Bajwa <mehar.bajwa@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
 #ifndef __MFD_AIC3262_CORE_H__
 #define __MFD_AIC3262_CORE_H__
 
 #include <linux/interrupt.h>
 #include <linux/mfd/core.h>
-enum aic3262_type {
+enum aic3xxx_type {
        TLV320AIC3262 = 0,
+       TLV320AIC3266 = 1,
+       TLV320AIC3285 = 2,
 };
 
 #define AIC3262_IRQ_HEADSET_DETECT     0
@@ -20,15 +44,40 @@ enum aic3262_type {
 #define AIC3262_GPI1                   9
 #define AIC3262_GPI2                   10
 #define AIC3262_GPO1                   11
+#define AIC3285_GPIO3                  9
+#define AIC3285_GPIO4                  10
+#define AIC3285_GPIO5                  11
+#define AIC3285_GPIO6                  12
+#define AIC3285_GPIO7                  13
+#define AIC3285_GPIO8                  14
+#define AIC3285_GPIO9                  15
+#define AIC3285_GPIO10                 16
+#define AIC3285_GPIO11                 17
+#define AIC3285_GPIO12                 18
+#define AIC3285_GPO1                   19
 
-union aic326x_reg_union {
-       struct aic326x_reg {
+struct aic3262_codec_data {
+       u16 hs_left_step;
+       u16 hs_right_step;
+       u16 hf_left_step;
+       u16 hf_right_step;
+};
+
+struct aic3262_platform_data {
+       int audpwron_gpio;      /* audio power-on gpio */
+       unsigned int irq_base;
+
+       struct aic3262_codec_data *codec;
+};
+
+union aic3xxx_reg_union {
+       struct aic3xxx_reg {
                u8 offset;
                u8 page;
                u8 book;
                u8 reserved;
-       } aic326x_register;
-       unsigned int aic326x_register_int;
+       } aic3xxx_register;
+       unsigned int aic3xxx_register_int;
 };
 
 /****************************             ************************************/
@@ -59,6 +108,9 @@ enum {
        AIC3262_GPIO1_FUNC_CLOCK_OUTPUT =       4,
        AIC3262_GPIO1_FUNC_INT1_OUTPUT =        5,
        AIC3262_GPIO1_FUNC_INT2_OUTPUT =        6,
+       AIC3285_GPIO_FUNC_DSD_CHAN1_OUTPUT =    7,
+       AIC3285_GPIO_FUNC_DSD_CHAN2_OUTPUT =    8,
+       AIC3285_GPIO_FUNC_DAC_MOD_CLK_OUTPUT =  9,
        AIC3262_GPIO1_FUNC_ADC_MOD_CLK_OUTPUT = 10,
        AIC3262_GPIO1_FUNC_SAR_ADC_INTERRUPT =  12,
        AIC3262_GPIO1_FUNC_ASI1_DATA_OUTPUT =   15,
@@ -67,7 +119,9 @@ enum {
        AIC3262_GPIO1_FUNC_ASI2_WCLK =          18,
        AIC3262_GPIO1_FUNC_ASI2_BCLK =          19,
        AIC3262_GPIO1_FUNC_ASI3_WCLK =          20,
-       AIC3262_GPIO1_FUNC_ASI3_BCLK =          21
+       AIC3262_GPIO1_FUNC_ASI3_BCLK =          21,
+       AIC3285_GPIO_I2C_MASTER_SCL =           30,
+       AIC3285_GPIO_I2C_MASTER_SDA =           30,
 };
 
 enum {
@@ -111,7 +165,7 @@ enum {
  *          value to set the AIC3262 register to initialize the AIC3262.
  *---------------------------------------------------------------------------
  */
-struct aic3262_configs {
+struct aic3xxx_configs {
        u8 book_no;
        u16 reg_offset;
        u8 reg_val;
@@ -147,16 +201,12 @@ struct aic3262_configs {
  * @field   u32 | blck_N |
  *          value for block N
  */
-struct aic3262 {
+struct aic3xxx {
        struct mutex io_lock;
        struct mutex irq_lock;
-       enum aic3262_type type;
+       enum aic3xxx_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);
-
+       struct regmap *regmap;
        void *control_data;
        unsigned int irq;
        unsigned int irq_base;
@@ -184,7 +234,7 @@ struct aic3262_gpio_setup {
                                /* is output, in_reg if its input */
 };
 
-struct aic3262_pdata {
+struct aic3xxx_pdata {
        unsigned int audio_mclk1;
        unsigned int audio_mclk2;
        unsigned int gpio_irq;  /* whether AIC3262 interrupts the host AP on */
@@ -196,42 +246,44 @@ struct aic3262_pdata {
        unsigned int irq_base;
 };
 
-static inline int aic3262_request_irq(struct aic3262 *aic3262, int irq,
+static inline int aic3xxx_request_irq(struct aic3xxx *aic3xxx, int irq,
                                      irq_handler_t handler,
                                      unsigned long irqflags, const char *name,
                                      void *data)
 {
-       if (!aic3262->irq_base)
+       if (!aic3xxx->irq_base)
                return -EINVAL;
 
-       return request_threaded_irq(aic3262->irq_base + irq, NULL, handler,
+       return request_threaded_irq(aic3xxx->irq_base + irq, NULL, handler,
                                    irqflags, name, data);
 }
 
-static inline int aic3262_free_irq(struct aic3262 *aic3262, int irq, void *data)
+static inline int aic3xxx_free_irq(struct aic3xxx *aic3xxx, int irq, void *data)
 {
-       if (!aic3262->irq_base)
+       if (!aic3xxx->irq_base)
                return -EINVAL;
 
-       free_irq(aic3262->irq_base + irq, data);
+       free_irq(aic3xxx->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,
+int aic3xxx_reg_read(struct aic3xxx *aic3xxx, unsigned int reg);
+int aic3xxx_reg_write(struct aic3xxx *aic3xxx, unsigned int reg,
                      unsigned char val);
-int aic3262_set_bits(struct aic3262 *aic3262, unsigned int reg,
+int aic3xxx_set_bits(struct aic3xxx *aic3xxx, unsigned int reg,
                     unsigned char mask, unsigned char val);
-int aic3262_bulk_read(struct aic3262 *aic3262, unsigned int reg,
+int aic3xxx_bulk_read(struct aic3xxx *aic3xxx, unsigned int reg,
                      int count, u8 *buf);
-int aic3262_bulk_write(struct aic3262 *aic3262, unsigned int reg,
+int aic3xxx_bulk_write(struct aic3xxx *aic3xxx, unsigned int reg,
                       int count, const u8 *buf);
-int aic3262_wait_bits(struct aic3262 *aic3262, unsigned int reg,
+int aic3xxx_wait_bits(struct aic3xxx *aic3xxx, 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);
+int aic3xxx_irq_init(struct aic3xxx *aic3xxx);
+void aic3xxx_irq_exit(struct aic3xxx *aic3xxx);
+int aic3xxx_device_init(struct aic3xxx *aic3xxx, int irq);
+void aic3xxx_device_exit(struct aic3xxx *aic3xxx);
 
 #endif /* End of __MFD_AIC3262_CORE_H__ */