diff options
Diffstat (limited to 'ANDROID_3.4.5/drivers/mfd')
-rw-r--r-- | ANDROID_3.4.5/drivers/mfd/Kconfig | 20 | ||||
-rw-r--r-- | ANDROID_3.4.5/drivers/mfd/Makefile | 4 | ||||
-rwxr-xr-x | ANDROID_3.4.5/drivers/mfd/gmt/Kconfig | 8 | ||||
-rwxr-xr-x | ANDROID_3.4.5/drivers/mfd/gmt/Makefile | 1 | ||||
-rwxr-xr-x | ANDROID_3.4.5/drivers/mfd/gmt/gmt-core.c | 285 | ||||
-rwxr-xr-x | ANDROID_3.4.5/drivers/mfd/vt1603-core.c | 472 | ||||
-rw-r--r-- | ANDROID_3.4.5/drivers/mfd/wm8994-core.c | 38 |
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 = ® + /* [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; |