summaryrefslogtreecommitdiff
path: root/ANDROID_3.4.5/drivers/mfd
diff options
context:
space:
mode:
Diffstat (limited to 'ANDROID_3.4.5/drivers/mfd')
-rw-r--r--ANDROID_3.4.5/drivers/mfd/Kconfig20
-rw-r--r--ANDROID_3.4.5/drivers/mfd/Makefile4
-rwxr-xr-xANDROID_3.4.5/drivers/mfd/gmt/Kconfig8
-rwxr-xr-xANDROID_3.4.5/drivers/mfd/gmt/Makefile1
-rwxr-xr-xANDROID_3.4.5/drivers/mfd/gmt/gmt-core.c285
-rwxr-xr-xANDROID_3.4.5/drivers/mfd/vt1603-core.c472
-rw-r--r--ANDROID_3.4.5/drivers/mfd/wm8994-core.c38
7 files changed, 817 insertions, 11 deletions
diff --git a/ANDROID_3.4.5/drivers/mfd/Kconfig b/ANDROID_3.4.5/drivers/mfd/Kconfig
index 11e44386..ca4ab95a 100644
--- a/ANDROID_3.4.5/drivers/mfd/Kconfig
+++ b/ANDROID_3.4.5/drivers/mfd/Kconfig
@@ -847,6 +847,24 @@ config MFD_TPS65090
additional drivers must be enabled in order to use the
functionality of the device.
+config VT1603_CORE
+ bool "WMT VT1603 Support"
+ select MFD_CORE
+choice
+ prompt "VT1603 control bus select"
+ default VT1603_IOCTRL_SPI
+ depends on VT1603_CORE
+config VT1603_IOCTRL_SPI
+ bool "SPI"
+ ---help---
+ Say Y here if you want to use SPI bus.
+config VT1603_IOCTRL_I2C
+ bool "I2C"
+ ---help---
+ Say Y here if you want to use I2C bus.
+endchoice
+
+
config MFD_AAT2870_CORE
bool "Support for the AnalogicTech AAT2870"
select MFD_CORE
@@ -888,6 +906,8 @@ config MFD_ANATOP
MFD controller. This controller embeds regulator and
thermal devices for Freescale i.MX platforms.
+source "drivers/mfd/gmt/Kconfig"
+
endmenu
endif
diff --git a/ANDROID_3.4.5/drivers/mfd/Makefile b/ANDROID_3.4.5/drivers/mfd/Makefile
index 05fa538c..f978b2f9 100644
--- a/ANDROID_3.4.5/drivers/mfd/Makefile
+++ b/ANDROID_3.4.5/drivers/mfd/Makefile
@@ -111,8 +111,12 @@ obj-$(CONFIG_MFD_PM8921_CORE) += pm8921-core.o
obj-$(CONFIG_MFD_PM8XXX_IRQ) += pm8xxx-irq.o
obj-$(CONFIG_TPS65911_COMPARATOR) += tps65911-comparator.o
obj-$(CONFIG_MFD_TPS65090) += tps65090.o
+obj-$(CONFIG_VT1603_CORE) += vt1603-core.o
+
obj-$(CONFIG_MFD_AAT2870_CORE) += aat2870-core.o
obj-$(CONFIG_MFD_INTEL_MSIC) += intel_msic.o
obj-$(CONFIG_MFD_RC5T583) += rc5t583.o rc5t583-irq.o
obj-$(CONFIG_MFD_S5M_CORE) += s5m-core.o s5m-irq.o
obj-$(CONFIG_MFD_ANATOP) += anatop-mfd.o
+obj-$(CONFIG_VT1603_CORE) += vt1603-core.o
+obj-$(CONFIG_MFD_GMT) += gmt/
diff --git a/ANDROID_3.4.5/drivers/mfd/gmt/Kconfig b/ANDROID_3.4.5/drivers/mfd/gmt/Kconfig
new file mode 100755
index 00000000..8fa734c6
--- /dev/null
+++ b/ANDROID_3.4.5/drivers/mfd/gmt/Kconfig
@@ -0,0 +1,8 @@
+config MFD_GMT
+ bool "GMT PMIC & Charger SUPPORT"
+ depends on I2C=y
+ select MFD_CORE
+ select REGMAP_I2C
+ select MFD_GMT_CORE
+config MFD_GMT_CORE
+ bool
diff --git a/ANDROID_3.4.5/drivers/mfd/gmt/Makefile b/ANDROID_3.4.5/drivers/mfd/gmt/Makefile
new file mode 100755
index 00000000..7a10de77
--- /dev/null
+++ b/ANDROID_3.4.5/drivers/mfd/gmt/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_MFD_GMT_CORE) += gmt-core.o
diff --git a/ANDROID_3.4.5/drivers/mfd/gmt/gmt-core.c b/ANDROID_3.4.5/drivers/mfd/gmt/gmt-core.c
new file mode 100755
index 00000000..c50987fc
--- /dev/null
+++ b/ANDROID_3.4.5/drivers/mfd/gmt/gmt-core.c
@@ -0,0 +1,285 @@
+/*++
+ drivers/mtd/gmt/gmt-core.c - GMT Core driver
+
+ Copyright (c) 2013 WonderMedia Technologies, Inc.
+
+ 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.
+
+ This program is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+ PARTICULAR PURPOSE. See the GNU General Public License for more details.
+ You should have received a copy of the GNU General Public License along with
+ this program. If not, see <http://www.gnu.org/licenses/>.
+
+ WonderMedia Technologies, Inc.
+ 10F, 529, Chung-Cheng Road, Hsin-Tien, Taipei 231, R.O.C.
+--*/
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/pm_runtime.h>
+#include <linux/mutex.h>
+#include <linux/mfd/core.h>
+#include <mach/gmt-core.h>
+#include <linux/regmap.h>
+
+static struct mfd_cell gmt_devs[] = {
+ {
+ .name = "gmt-pmic",
+ }, {
+ .name = "gmt-charger",
+ },
+};
+
+int gmt2214_reg_read(struct gmt2214_dev *gmt2214, u8 reg, void *dest)
+{
+ struct i2c_msg msg[2];
+ unsigned char data[4];
+ int err;
+ struct i2c_client *client;
+
+ client = gmt2214->i2c;
+
+ if (!client || !client->adapter)
+ return -ENODEV;
+
+ if (!dest)
+ return -EINVAL;
+
+ data[0] = reg;
+ msg[0].addr = client->addr;
+ msg[0].flags = 0 | I2C_M_NOSTART;
+ msg[0].len = 1;
+ msg[0].buf = (unsigned char *)data;
+
+ msg[1].addr = client->addr;
+ msg[1].flags = (I2C_M_RD);
+ msg[1].len = 1;
+ msg[1].buf = (unsigned char *)dest;
+
+ err = i2c_transfer(client->adapter, msg, sizeof(msg)/sizeof(struct i2c_msg));
+ return err;
+}
+EXPORT_SYMBOL_GPL(gmt2214_reg_read);
+
+int gmt2214_reg_write(struct gmt2214_dev *gmt2214, u8 reg, u8 value)
+{
+ unsigned char buffer4Write[256];
+ struct i2c_client *client = gmt2214->i2c;
+ struct i2c_msg msgs[1] = {
+ {
+ .addr = client->addr,
+ .flags = 0,
+ .len = 2,
+ .buf = buffer4Write
+ }
+ };
+
+ buffer4Write[0] = reg;
+ buffer4Write[1] = value;
+
+ return i2c_transfer(client->adapter, msgs, 1);
+
+}
+EXPORT_SYMBOL_GPL(gmt2214_reg_write);
+
+static struct regmap_config gmt2214_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+};
+
+static int gmt2214_i2c_probe(struct i2c_client *i2c,
+ const struct i2c_device_id *id)
+{
+ struct gmt2214_platform_data *pdata = i2c->dev.platform_data;
+ struct gmt2214_dev *gmt2214;
+ int ret;
+
+ gmt2214 = devm_kzalloc(&i2c->dev, sizeof(struct gmt2214_dev),
+ GFP_KERNEL);
+ if (gmt2214 == NULL)
+ return -ENOMEM;
+
+ i2c_set_clientdata(i2c, gmt2214);
+ gmt2214->dev = &i2c->dev;
+ gmt2214->i2c = i2c;
+
+ if (pdata)
+ gmt2214->device_type = pdata->device_type;
+
+ gmt2214->regmap = regmap_init_i2c(i2c, &gmt2214_regmap_config);
+ if (IS_ERR(gmt2214->regmap)) {
+ ret = PTR_ERR(gmt2214->regmap);
+ dev_err(&i2c->dev, "Failed to allocate register map: %d\n",
+ ret);
+ goto err;
+ }
+
+ pm_runtime_set_active(gmt2214->dev);
+
+ ret = mfd_add_devices(gmt2214->dev, -1, gmt_devs,
+ ARRAY_SIZE(gmt_devs), NULL, 0);
+
+ if (ret < 0)
+ goto err;
+
+ return ret;
+
+err:
+ mfd_remove_devices(gmt2214->dev);
+ regmap_exit(gmt2214->regmap);
+ return ret;
+}
+
+static int gmt2214_i2c_remove(struct i2c_client *i2c)
+{
+ struct gmt2214_dev *gmt2214 = i2c_get_clientdata(i2c);
+
+ mfd_remove_devices(gmt2214->dev);
+ regmap_exit(gmt2214->regmap);
+ return 0;
+}
+
+static struct i2c_board_info gmt_i2c_board_info = {
+ .type = "gmt2214",
+ .flags = 0x00,
+ .addr = 0x12,
+ .platform_data = NULL,
+ .archdata = NULL,
+ .irq = -1,
+};
+
+static const struct i2c_device_id gmt2214_i2c_id[] = {
+ {"gmt2214", 0},
+ {}
+};
+MODULE_DEVICE_TABLE(i2c, gmt2214_i2c_id);
+
+static struct i2c_driver gmt2214_i2c_driver = {
+ .driver = {
+ .name = "gmt2214",
+ .owner = THIS_MODULE,
+ },
+ .probe = gmt2214_i2c_probe,
+ .remove = gmt2214_i2c_remove,
+ .id_table = gmt2214_i2c_id,
+};
+
+extern int wmt_getsyspara(char *varname, unsigned char *varval, int *varlen);
+
+#define par_len 80
+static unsigned int g_i2cbus_id = 3;
+static unsigned int g_pmic_en = 0;
+
+static int parse_pmic_param(void)
+{
+ int retval;
+ unsigned char buf[par_len];
+ unsigned char tmp_buf[par_len];
+ unsigned int delay_time;
+ int i = 0;
+ int j = 0;
+ int varlen = par_len;
+ char *varname = "wmt.pmic.param";
+ unsigned int pmic_en = 0;
+ retval = wmt_getsyspara(varname, buf, &varlen);
+ if (retval == 0) {
+ pmic_en = (buf[i] - '0' == 1)?1:0;
+ if (pmic_en == 0) {/*disable*/
+ g_pmic_en = 0;
+ return -1;
+ }
+ i += 2;
+ for (; i < par_len; ++i) {
+ if (buf[i] == ':')
+ break;
+ tmp_buf[j] = buf[i];
+ ++j;
+ }
+ if (strncmp(tmp_buf,"gmt2214",7)) {
+ g_pmic_en = 0;
+ return -1;
+ }
+ ++i;
+
+ sscanf((buf + i), "%d:%d", &g_i2cbus_id, &delay_time);
+ } else {
+ g_pmic_en = 0;
+ return -1;
+ }
+ g_pmic_en = 1;
+ return 0;
+}
+
+static unsigned int g_chg_en = 0;
+int parse_charger_param(void)
+{
+ int retval;
+ unsigned char buf[240];
+ int varlen = par_len;
+ //char *varname = "wmt.io.chg";
+ char *varname = "wmt.charger.param";
+ retval = wmt_getsyspara(varname, buf, &varlen);
+ if (retval == 0) {
+ g_chg_en = (buf[0] - '0' == 1)?1:0;
+ if (g_chg_en == 0)
+ return -1;
+ if (strncmp((buf + 2), "g2214", 5)) {
+ g_chg_en = 0;
+ return -1;
+ }
+ } else {
+ g_chg_en = 0;
+ return -1;
+ }
+ g_chg_en = 1;
+ return 1;
+}
+static int __init gmt2214_i2c_init(void)
+{
+ struct i2c_board_info *gmt2214_i2c_bi;
+ struct i2c_adapter *adapter = NULL;
+ struct i2c_client *client = NULL;
+
+ parse_pmic_param();
+ parse_charger_param();
+ if (g_pmic_en == 0 && g_chg_en == 0) {
+ printk("Don't support GMT2214\n");
+ return -ENODEV;
+ }
+ gmt2214_i2c_bi = &gmt_i2c_board_info;
+ adapter = i2c_get_adapter(g_i2cbus_id);/*in bus 3*/
+
+ if (NULL == adapter) {
+ printk("can not get i2c adapter, client address error\n");
+ return -ENODEV;
+ }
+
+ client = i2c_new_device(adapter, gmt2214_i2c_bi);
+ if (client == NULL) {
+ printk("allocate i2c client failed\n");
+ return -ENODEV;
+ }
+ i2c_put_adapter(adapter);
+
+ return i2c_add_driver(&gmt2214_i2c_driver);
+}
+
+subsys_initcall_sync(gmt2214_i2c_init);
+
+static void __exit gmt2214_i2c_exit(void)
+{
+ i2c_del_driver(&gmt2214_i2c_driver);
+}
+module_exit(gmt2214_i2c_exit);
+
+MODULE_AUTHOR("WonderMedia Technologies, Inc.");
+MODULE_DESCRIPTION("GMT2214 Core Driver");
+MODULE_LICENSE("GPL");
diff --git a/ANDROID_3.4.5/drivers/mfd/vt1603-core.c b/ANDROID_3.4.5/drivers/mfd/vt1603-core.c
new file mode 100755
index 00000000..965d7881
--- /dev/null
+++ b/ANDROID_3.4.5/drivers/mfd/vt1603-core.c
@@ -0,0 +1,472 @@
+/*++
+ * WonderMedia core driver for VT1603/VT1609
+ *
+ * Copyright c 2010 WonderMedia Technologies, Inc.
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * WonderMedia Technologies, Inc.
+ * 4F, 533, Chung-Cheng Road, Hsin-Tien, Taipei 231, R.O.C
+--*/
+
+#include <linux/init.h>
+#include <linux/mutex.h>
+#include <linux/platform_device.h>
+#include <linux/err.h>
+#include <linux/mfd/core.h>
+#include <linux/regulator/consumer.h>
+#include <linux/regulator/machine.h>
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/spi/spi.h>
+#include <linux/mfd/vt1603/core.h>
+
+/*----------------------------------------------------------------------*/
+
+
+/*----------------------------------------------------------------------*/
+extern int wmt_getsyspara(char *varname, unsigned char *varval, int *varlen);
+
+int vt1603_reg_write(struct vt1603 *vt1603, u8 reg, u8 val)
+{
+ return vt1603->reg_write(vt1603, reg, val);
+}
+
+int vt1603_reg_read(struct vt1603 *vt1603, u8 reg, u8 *val)
+{
+ return vt1603->reg_read(vt1603, reg, val);
+}
+
+void vt1603_regs_dump(struct vt1603 *vt1603)
+{
+ int reg, ret;
+ u8 val;
+ pr_info("\n>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n");
+ for (reg = 0; reg < 0xe8; reg++) {
+ ret = vt1603->reg_read(vt1603, reg, &val);
+ if (ret) {
+ pr_err("\nvt1603_hw_read[r:%d] error\n", reg);
+ goto out;
+ }
+ if(reg%4 == 0)
+ pr_info("\n");
+ pr_info("reg[%02x]=%02x ", reg, val);
+ }
+out:
+ pr_info("\n<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n\n");
+}
+
+/*----------------------------------------------------------------------*/
+
+
+/*----------------------------------------------------------------------*/
+
+static int vt1603_mfd_init(struct vt1603 *vt1603)
+{
+ int ret;
+ struct mfd_cell cell[] = {
+ {
+ .name = "vt1603-codec",
+ .platform_data = vt1603,
+ .pdata_size = sizeof(*vt1603),
+ },
+ {
+ .name = "vt1603-touch",
+ .platform_data = vt1603,
+ .pdata_size = sizeof(*vt1603),
+ },
+ {
+ .name = "vt1603-batt",
+ .platform_data = vt1603,
+ .pdata_size = sizeof(*vt1603),
+ },
+ };
+
+ ret = mfd_add_devices(vt1603->dev, -1,
+ cell, ARRAY_SIZE(cell),
+ NULL, 0);
+ if (ret != 0) {
+ pr_err("vt1603_mfd_init error: %d\n", ret);
+ goto err;
+ }
+ return 0;
+
+err:
+ mfd_remove_devices(vt1603->dev);
+ kfree(vt1603);
+ return ret;
+}
+
+static void vt1603_mfd_release(struct vt1603 *vt1603)
+{
+ mfd_remove_devices(vt1603->dev);
+ kfree(vt1603);
+}
+
+/*----------------------------------------------------------------------*/
+
+
+/*----------------------------------------------------------------------*/
+
+#if defined(CONFIG_I2C) /*&& defined(CONFIG_VT1603_IOCTRL_I2C) */
+static int vt1603_i2c_write(struct vt1603 *vt1603, u8 reg, u8 val)
+{
+ int ret;
+ struct i2c_client *i2c = vt1603->control_data;
+ struct i2c_msg xfer[1];
+ u8 buf[2];
+
+ /*
+ * [MSG1]: fill the register address data
+ * fill the data Tx buffer
+ */
+ xfer[0].addr = i2c->addr;
+ xfer[0].len = 2;
+ xfer[0].flags = 0 ;
+ xfer[0].flags &= ~(I2C_M_RD);
+ xfer[0].buf = buf;
+ buf[0] = reg;
+ buf[1] = val;
+ ret = i2c_transfer(i2c->adapter, xfer, ARRAY_SIZE(xfer));
+
+ /* i2c_transfer returns number of messages transferred */
+ if (ret != ARRAY_SIZE(xfer)) {
+ pr_err("vt1603_i2c_read[r:%d, v:%d] errcode[%d]\n", reg, val, ret);
+ if (ret < 0)
+ return ret;
+ else
+ return -EIO;
+ } else
+ return 0;
+}
+
+static int vt1603_i2c_read(struct vt1603 *vt1603, u8 reg, u8 *val)
+{
+ int ret;
+ struct i2c_client *i2c = vt1603->control_data;
+ struct i2c_msg xfer[2];
+
+ /* [MSG1] fill the register address data */
+ xfer[0].addr = i2c->addr;
+ xfer[0].len = 1;
+ xfer[0].flags = 0| I2C_M_NOSTART; //2; /* Read the register val */ //modify 2014-1-20
+ xfer[0].buf = &reg;
+ /* [MSG2] fill the data rx buffer */
+ xfer[1].addr = i2c->addr;
+ xfer[1].flags = I2C_M_RD; /* Read the register val */
+ xfer[1].len = 1; /* only n bytes */
+ xfer[1].buf = val;
+ ret = i2c_transfer(i2c->adapter, xfer, ARRAY_SIZE(xfer));
+
+ /* i2c_transfer returns number of messages transferred */
+ if (ret != ARRAY_SIZE(xfer)) {
+ pr_err("vt1603_i2c_read[r:%d] errcode[%d]\n", reg, ret);
+ if (ret < 0)
+ return ret;
+ else
+ return -EIO;
+ } else {
+ return 0;
+ }
+}
+
+static int __devinit vt1603_i2c_probe(struct i2c_client *i2c,
+ const struct i2c_device_id *id)
+{
+ struct vt1603 *vt1603;
+
+ if (i2c_check_functionality(i2c->adapter, I2C_FUNC_I2C) == 0) {
+ pr_err("vt1603_i2c_probe: can't talk I2C?\n");
+ return -EIO;
+ }
+
+ vt1603 = kzalloc(sizeof(struct vt1603), GFP_KERNEL);
+ if (vt1603 == NULL)
+ return -ENOMEM;
+
+ vt1603->dev = &i2c->dev;
+ vt1603->control_data = i2c;
+ vt1603->reg_read = vt1603_i2c_read;
+ vt1603->reg_write = vt1603_i2c_write;
+ vt1603->type = id->driver_data;
+ i2c_set_clientdata(i2c, vt1603);
+ dev_set_drvdata(vt1603->dev, vt1603);
+
+ return vt1603_mfd_init(vt1603);
+}
+
+static int __devexit vt1603_i2c_remove(struct i2c_client *i2c)
+{
+ struct vt1603 *vt1603 = i2c_get_clientdata(i2c);
+ vt1603_mfd_release(vt1603);
+ return 0;
+}
+
+static const struct i2c_device_id vt1603_i2c_id[] = {
+ { "vt1603", VT1603 },
+ { "vt1609", VT1609 },
+};
+MODULE_DEVICE_TABLE(i2c, vt1603_i2c_id);
+
+/* corgi i2c codec control layer */
+static struct i2c_driver vt1603_i2c_driver = {
+ .driver = {
+ .name = "VT1603",
+ .owner = THIS_MODULE,
+ },
+ .probe = vt1603_i2c_probe,
+ .remove = __devexit_p(vt1603_i2c_remove),
+ .id_table = vt1603_i2c_id,
+};
+#endif
+
+/*----------------------------------------------------------------------*/
+
+
+/*----------------------------------------------------------------------*/
+
+#if defined(CONFIG_SPI_MASTER) && defined(CONFIG_VT1603_IOCTRL_SPI)
+static int vt1603_spi_write_then_read(struct spi_device *spi,
+ const u8 *txbuf, unsigned n_tx,
+ u8 *rxbuf, unsigned n_rx)
+{
+ static DEFINE_MUTEX(lock);
+ static u8 buf[32];
+
+ int status;
+ struct spi_message message;
+ struct spi_transfer x;
+ u8 *local_buf;
+
+ /* Use preallocated DMA-safe buffer. We can't avoid copying here,
+ * (as a pure convenience thing), but we can keep heap costs
+ * out of the hot path ...
+ */
+ if ((n_tx + n_rx) > ARRAY_SIZE(buf))
+ return -EINVAL;
+
+ spi_message_init(&message);
+ memset(&x, 0, sizeof x);
+ x.len = n_tx + n_rx;
+ spi_message_add_tail(&x, &message);
+
+ /* ... unless someone else is using the pre-allocated buffer */
+ if (!mutex_trylock(&lock)) {
+ local_buf = kmalloc(ARRAY_SIZE(buf), GFP_KERNEL);
+ if (!local_buf)
+ return -ENOMEM;
+ }
+ else {
+ memset(buf, 0x00, sizeof(buf));
+ local_buf = buf;
+ }
+
+ memcpy(local_buf, txbuf, n_tx);
+ x.tx_buf = local_buf;
+ x.rx_buf = local_buf;
+
+ /* do the i/o */
+ status = spi_sync(spi, &message);
+ if (status == 0)
+ memcpy(rxbuf, x.rx_buf + n_tx, n_rx);
+
+ if (x.tx_buf == buf)
+ mutex_unlock(&lock);
+ else
+ kfree(local_buf);
+
+ return status;
+}
+
+static int vt1603_spi_write(struct vt1603 *vt1603, u8 reg, u8 val)
+{
+ int ret = 0;
+ u8 xfer[3] = { 0 };
+ struct spi_device *spi = vt1603->control_data;
+
+ xfer[0] = ((reg & 0xff) | 0x80);
+ xfer[1] = ((reg & 0xff) >> 7);
+ xfer[2] = val & 0xff;
+ ret = spi_write(spi, xfer, ARRAY_SIZE(xfer));
+ if (ret != 0)
+ pr_err("vt1603_spi_write[r:%d, v:%d] errcode[%d]\n", reg, val, ret);
+
+ return ret;
+}
+
+static int vt1603_spi_read(struct vt1603 *vt1603, u8 reg, u8 *val)
+{
+ u8 addr[3] = { 0 };
+ u8 data[3] = { 0 };
+ int ret = 0;
+ struct spi_device *spi = vt1603->control_data;
+
+ addr[0] = ((reg & 0xff) & (~ 0x80));
+ addr[1] = ((reg & 0xff) >> 7);
+ addr[2] = 0xff;
+ ret = vt1603_spi_write_then_read(spi, addr, 2, data, 3);
+ if(ret != 0)
+ pr_err("vt1603_spi_read[r:%d] errcode[%d]\n", reg, ret);
+
+ *val = data[2];
+ return ret;
+}
+
+static int vt1603_spi_probe(struct spi_device *spi )
+{
+ struct vt1603 *vt1603;
+ const struct spi_device_id *id = spi_get_device_id(spi);
+
+ vt1603 = kzalloc(sizeof(struct vt1603), GFP_KERNEL);
+ if (vt1603 == NULL)
+ return -ENOMEM;
+
+ vt1603->dev = &spi->dev;
+ vt1603->control_data = spi;
+ vt1603->reg_read = vt1603_spi_read;
+ vt1603->reg_write = vt1603_spi_write;
+ vt1603->type = id->driver_data;
+
+ spi_set_drvdata(spi, vt1603);
+ dev_set_drvdata(vt1603->dev, vt1603);
+
+ return vt1603_mfd_init(vt1603);
+}
+
+static int vt1603_spi_remove(struct spi_device *spi)
+{
+ struct vt1603 *vt1603 = spi_get_drvdata(spi);
+ vt1603_mfd_release(vt1603);
+ return 0;
+}
+
+static const struct spi_device_id vt1603_spi_id[] = {
+ { "vt1603", VT1603},
+ { "vt1609", VT1609},
+};
+MODULE_DEVICE_TABLE(spi, vt1603_spi_id);
+
+static struct spi_driver vt1603_spi_driver = {
+ .driver = {
+ .name = "VT1603",
+ .owner = THIS_MODULE,
+ },
+ .probe = vt1603_spi_probe,
+ .remove = __devexit_p(vt1603_spi_remove),
+ .id_table = vt1603_spi_id,
+};
+#endif
+
+
+static struct i2c_board_info vt1603_i2c_board_info = {
+ .type = "vt1603", //VT1603
+ .flags = 0x00,
+ .addr = 0x1a,//0x1a, 0x05 err -5 IOerr
+ .platform_data = NULL,
+ .archdata = NULL,
+ .irq = -1,
+};
+static int g_i2c_no = 0;
+static int g_i2c_cotrol = 0;
+static int vt1603_i2c_register_device (void)
+{
+ struct i2c_board_info *vt1603_i2c_bi;
+ struct i2c_adapter *adapter = NULL;
+ struct i2c_client *l_client = NULL;
+
+ //struct i2c_client *client = NULL;
+ vt1603_i2c_bi = &vt1603_i2c_board_info;
+ adapter = i2c_get_adapter(g_i2c_no);/*in bus 0*/
+
+ if (NULL == adapter) {
+ printk("can not get i2c adapter, client address error\n");
+ return -1;
+ }
+ l_client = i2c_new_device(adapter, vt1603_i2c_bi);
+ if (l_client == NULL) {
+ printk("allocate i2c client failed\n");
+ return -1;
+ }
+ i2c_put_adapter(adapter);
+ return 0;
+}
+/*----------------------------------------------------------------------*/
+
+
+/*----------------------------------------------------------------------*/
+
+static int __init vt1603_init(void)
+{
+ int ret = -1;
+
+ char buf[100];
+ int varlen = sizeof(buf);//
+ int bus = 0;
+ int no = 0;
+ //int i2c_control = 0;
+ //int i2c_no = 0;
+
+ memset(buf, 0, 100);
+ printk("<<<%s wmt.vt1603.bus\n", __func__);
+ ret = wmt_getsyspara("wmt.vt1603.bus", buf, &varlen);
+
+ if (ret == 0)
+ {
+ printk("<<<%s wmt.vt1603.bus:%s\n",__func__, buf);
+ //i2c---->0x1 spi--->0x0
+ sscanf(buf, "%d:%d", &bus, &no);
+ if (bus > 0) {
+ g_i2c_cotrol = 1;
+ //i2c_no = no;
+ g_i2c_no = no;
+ }
+ }
+#if defined(CONFIG_I2C) /*&& defined(CONFIG_VT1603_IOCTRL_I2C) */
+ if (g_i2c_cotrol) {
+
+ vt1603_i2c_register_device();
+ ret = i2c_add_driver(&vt1603_i2c_driver);
+ if (ret != 0)
+ pr_err("Failed to register vt1603 I2C driver: %d\n", ret);
+
+ printk("<<<<<%s using i2c bus\n", __func__);
+ return 0;
+ }
+#endif
+#if defined(CONFIG_SPI_MASTER) && defined(CONFIG_VT1603_IOCTRL_SPI)
+ ret = spi_register_driver(&vt1603_spi_driver);
+ if (ret != 0)
+ pr_err("Failed to register vt1603 SPI driver: %d\n", ret);
+
+ printk("<<<<<%s using spi bus\n", __func__);
+#endif
+ return ret;
+}
+module_init(vt1603_init);
+
+static void __exit vt1603_exit(void)
+{
+#if defined(CONFIG_I2C) /*&& defined(CONFIG_VT1603_IOCTRL_I2C) */
+ if (g_i2c_cotrol)
+ i2c_del_driver(&vt1603_i2c_driver);
+#endif
+#if defined(CONFIG_SPI_MASTER) && defined(CONFIG_VT1603_IOCTRL_SPI)
+ spi_unregister_driver(&vt1603_spi_driver);
+#endif
+}
+module_exit(vt1603_exit);
+
+
+MODULE_AUTHOR("WonderMedia Technologies, Inc.");
+MODULE_LICENSE("GPL"); \ No newline at end of file
diff --git a/ANDROID_3.4.5/drivers/mfd/wm8994-core.c b/ANDROID_3.4.5/drivers/mfd/wm8994-core.c
index 9d7ca1e9..98ff03f5 100644
--- a/ANDROID_3.4.5/drivers/mfd/wm8994-core.c
+++ b/ANDROID_3.4.5/drivers/mfd/wm8994-core.c
@@ -203,7 +203,7 @@ static int wm8994_suspend(struct device *dev)
if (ret < 0) {
dev_err(dev, "Failed to read power status: %d\n", ret);
} else if (ret & WM8994_VMID_SEL_MASK) {
- dev_dbg(dev, "CODEC still active, ignoring suspend\n");
+ dev_warn(dev, "CODEC still active, ignoring suspend [%d]\n", __LINE__);
return 0;
}
@@ -213,17 +213,16 @@ static int wm8994_suspend(struct device *dev)
} else if (ret & (WM8994_AIF2ADCL_ENA | WM8994_AIF2ADCR_ENA |
WM8994_AIF1ADC2L_ENA | WM8994_AIF1ADC2R_ENA |
WM8994_AIF1ADC1L_ENA | WM8994_AIF1ADC1R_ENA)) {
- dev_dbg(dev, "CODEC still active, ignoring suspend\n");
+ dev_warn(dev, "CODEC still active, ignoring suspend [%d]\n", __LINE__);
return 0;
}
ret = wm8994_reg_read(wm8994, WM8994_POWER_MANAGEMENT_5);
if (ret < 0) {
dev_err(dev, "Failed to read power status: %d\n", ret);
- } else if (ret & (WM8994_AIF2DACL_ENA | WM8994_AIF2DACR_ENA |
- WM8994_AIF1DAC2L_ENA | WM8994_AIF1DAC2R_ENA |
+ } else if (ret & (WM8994_AIF1DAC2L_ENA | WM8994_AIF1DAC2R_ENA |
WM8994_AIF1DAC1L_ENA | WM8994_AIF1DAC1R_ENA)) {
- dev_dbg(dev, "CODEC still active, ignoring suspend\n");
+ dev_warn(dev, "CODEC still active, ignoring suspend [%d]\n", __LINE__);
return 0;
}
@@ -234,7 +233,7 @@ static int wm8994_suspend(struct device *dev)
if (ret < 0) {
dev_err(dev, "Failed to read power status: %d\n", ret);
} else if (ret & WM8958_MICD_ENA) {
- dev_dbg(dev, "CODEC still active, ignoring suspend\n");
+ dev_warn(dev, "CODEC still active, ignoring suspend\n");
return 0;
}
break;
@@ -248,7 +247,7 @@ static int wm8994_suspend(struct device *dev)
if (ret < 0) {
dev_err(dev, "Failed to read jackdet: %d\n", ret);
} else if (ret & WM1811_JACKDET_MODE_MASK) {
- dev_dbg(dev, "CODEC still active, ignoring suspend\n");
+ dev_warn(dev, "CODEC still active, ignoring suspend\n");
return 0;
}
break;
@@ -262,7 +261,7 @@ static int wm8994_suspend(struct device *dev)
if (ret < 0) {
dev_err(dev, "Failed to read jackdet: %d\n", ret);
} else if (ret & WM1811_JACKDET_MODE_MASK) {
- dev_dbg(dev, "CODEC still active, ignoring suspend\n");
+ dev_warn(dev, "CODEC still active, ignoring suspend\n");
return 0;
}
break;
@@ -302,6 +301,7 @@ static int wm8994_resume(struct device *dev)
{
struct wm8994 *wm8994 = dev_get_drvdata(dev);
int ret;
+ int retry = 0;
/* We may have lied to the PM core about suspending */
if (!wm8994->suspended)
@@ -315,9 +315,22 @@ static int wm8994_resume(struct device *dev)
}
regcache_cache_only(wm8994->regmap, false);
- ret = regcache_sync(wm8994->regmap);
- if (ret != 0) {
- dev_err(dev, "Failed to restore register map: %d\n", ret);
+ //ret = regcache_sync(wm8994->regmap);
+ //if (ret != 0) {
+ // dev_err(dev, "Failed to restore register map: %d\n", ret);
+ // goto err_enable;
+ //}
+
+ for (retry = 0; retry < 50; retry++) {
+ ret = regcache_sync(wm8994->regmap);
+ if (ret != 0)
+ dev_err(dev, "Failed to restore register map: %d, retry count: %d\n", ret, retry);
+ else
+ break;
+ msleep(50);
+ }
+ if (retry == 50) {
+ dev_err(dev, "Finally failed to restore register map: %d\n", ret);
goto err_enable;
}
@@ -556,6 +569,9 @@ static __devinit int wm8994_device_init(struct wm8994 *wm8994, int irq)
dev_info(wm8994->dev, "%s revision %c\n", devname,
'A' + wm8994->revision);
+ wm8994_reg_write(wm8994, WM8994_SOFTWARE_RESET,
+ wm8994_reg_read(wm8994, WM8994_SOFTWARE_RESET));
+
switch (wm8994->type) {
case WM1811:
regmap_config = &wm1811_regmap_config;