summaryrefslogtreecommitdiff
path: root/drivers/mfd/vt1603-core.c
diff options
context:
space:
mode:
authorSrikant Patnaik2015-01-13 15:08:24 +0530
committerSrikant Patnaik2015-01-13 15:08:24 +0530
commit97327692361306d1e6259021bc425e32832fdb50 (patch)
treefe9088f3248ec61e24f404f21b9793cb644b7f01 /drivers/mfd/vt1603-core.c
parent2d05a8f663478a44e088d122e0d62109bbc801d0 (diff)
parenta3a8b90b61e21be3dde9101c4e86c881e0f06210 (diff)
downloadFOSSEE-netbook-kernel-source-97327692361306d1e6259021bc425e32832fdb50.tar.gz
FOSSEE-netbook-kernel-source-97327692361306d1e6259021bc425e32832fdb50.tar.bz2
FOSSEE-netbook-kernel-source-97327692361306d1e6259021bc425e32832fdb50.zip
dirty fix to merging
Diffstat (limited to 'drivers/mfd/vt1603-core.c')
-rwxr-xr-xdrivers/mfd/vt1603-core.c472
1 files changed, 472 insertions, 0 deletions
diff --git a/drivers/mfd/vt1603-core.c b/drivers/mfd/vt1603-core.c
new file mode 100755
index 00000000..965d7881
--- /dev/null
+++ b/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