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