diff options
author | Srikant Patnaik | 2015-01-13 15:08:24 +0530 |
---|---|---|
committer | Srikant Patnaik | 2015-01-13 15:08:24 +0530 |
commit | 97327692361306d1e6259021bc425e32832fdb50 (patch) | |
tree | fe9088f3248ec61e24f404f21b9793cb644b7f01 /drivers/mfd/vt1603-core.c | |
parent | 2d05a8f663478a44e088d122e0d62109bbc801d0 (diff) | |
parent | a3a8b90b61e21be3dde9101c4e86c881e0f06210 (diff) | |
download | FOSSEE-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-x | drivers/mfd/vt1603-core.c | 472 |
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 = ® + /* [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 |