/*++ * 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 . * * WonderMedia Technologies, Inc. * 4F, 533, Chung-Cheng Road, Hsin-Tien, Taipei 231, R.O.C --*/ #include #include #include #include #include #include #include #include #include #include #include /*----------------------------------------------------------------------*/ /*----------------------------------------------------------------------*/ 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");