/* * cyttsp5_i2c.c * Parade TrueTouch(TM) Standard Product V5 I2C Module. * For use with Parade touchscreen controllers. * Supported parts include: * CYTMA5XX * CYTMA448 * CYTMA445A * CYTT21XXX * CYTT31XXX * * Copyright (C) 2015 Parade Technologies * Copyright (C) 2012-2015 Cypress Semiconductor * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * version 2, and only version 2, as published by the * Free Software Foundation. * * 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. * * Contact Parade Technologies at www.paradetech.com * */ #include "cyttsp5_regs.h" #include #include #define CY_I2C_DATA_SIZE (2 * 256) static void cyttsp5_i2c_remove(struct i2c_client *client); static int cyttsp5_i2c_read_default(struct device *dev, void *buf, int size) { struct i2c_client *client = to_i2c_client(dev); int rc; if (!buf || !size || size > CY_I2C_DATA_SIZE) return -EINVAL; //printk("*****cyttsp5_i2c_read_default size=%d\n", size); rc = i2c_master_recv(client, buf, size); return (rc < 0) ? rc : rc != size ? -EIO : 0; } static int cyttsp5_i2c_read_default_nosize(struct device *dev, u8 *buf, u32 max) { struct i2c_client *client = to_i2c_client(dev); struct i2c_msg msgs[2]; u8 msg_count = 1; int rc; u32 size; if (!buf) return -EINVAL; //printk("*****cyttsp5_i2c_read_default_nosize max=%d\n", max); msgs[0].addr = client->addr; msgs[0].flags = (client->flags & I2C_M_TEN) | I2C_M_RD; msgs[0].len = 2; msgs[0].buf = buf; rc = i2c_transfer(client->adapter, msgs, msg_count); if (rc < 0 || rc != msg_count) return (rc < 0) ? rc : -EIO; size = get_unaligned_le16(&buf[0]); if (!size || size == 2 || size >= CY_PIP_1P7_EMPTY_BUF) /* Before PIP 1.7, empty buffer is 0x0002; From PIP 1.7, empty buffer is 0xFFXX */ return 0; if (size > max) return -EINVAL; rc = i2c_master_recv(client, buf, size); return (rc < 0) ? rc : rc != (int)size ? -EIO : 0; } static int cyttsp5_i2c_write_read_specific(struct device *dev, u8 write_len, u8 *write_buf, u8 *read_buf) { struct i2c_client *client = to_i2c_client(dev); struct i2c_msg msgs[2]; u8 msg_count = 1; int rc; //printk("*****cyttsp5_i2c_write_read_specific 0x%x, 0x%x, len=%d\n", write_buf[0], write_buf[1],write_len); if (!write_buf || !write_len) return -EINVAL; msgs[0].addr = client->addr; msgs[0].flags = client->flags & I2C_M_TEN; msgs[0].len = write_len; msgs[0].buf = write_buf; rc = i2c_transfer(client->adapter, msgs, msg_count); //printk("*****cyttsp5_i2c_write_read_specific rc=%d\n", rc); if (rc < 0 || rc != msg_count) return (rc < 0) ? rc : -EIO; rc = 0; //printk("*****cyttsp5_i2c_write_read_specific read_buf=0x%x\n", read_buf); if (read_buf) rc = cyttsp5_i2c_read_default_nosize(dev, read_buf, CY_I2C_DATA_SIZE); return rc; } static struct cyttsp5_bus_ops cyttsp5_i2c_bus_ops = { .bustype = BUS_I2C, .read_default = cyttsp5_i2c_read_default, .read_default_nosize = cyttsp5_i2c_read_default_nosize, .write_read_specific = cyttsp5_i2c_write_read_specific, }; #ifdef CONFIG_TOUCHSCREEN_CYPRESS_CYTTSP5_DEVICETREE_SUPPORT static const struct of_device_id cyttsp5_i2c_of_match[] = { { .compatible = "cy,cyttsp5_i2c_adapter", }, { } }; MODULE_DEVICE_TABLE(of, cyttsp5_i2c_of_match); #endif static int cyttsp5_i2c_probe(struct i2c_client *client, const struct i2c_device_id *i2c_id) { struct device *dev = &client->dev; #ifdef CONFIG_TOUCHSCREEN_CYPRESS_CYTTSP5_DEVICETREE_SUPPORT const struct of_device_id *match; #endif struct cyttsp5_platform_data *pdata; int rc; printk("*****cyttsp5_i2c_probe start \n"); if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { dev_err(dev, "I2C functionality not Supported\n"); return -EIO; } #ifdef CONFIG_TOUCHSCREEN_CYPRESS_CYTTSP5_DEVICETREE_SUPPORT match = of_match_device(of_match_ptr(cyttsp5_i2c_of_match), dev); if (match) { rc = cyttsp5_devtree_create_and_get_pdata(dev); if (rc < 0) return rc; } #endif pdata = dev_get_platdata(dev); if (pdata && pdata->core_pdata) { char buf[32]; /* Call platform init function */ if (pdata->core_pdata->init) { dev_info(dev, "%s: Init HW\n", __func__); rc = pdata->core_pdata->init(pdata->core_pdata, 1, dev); if (rc < 0) { dev_err(dev, "%s: HW Init fail %d\n", __func__, rc); return -EIO; } } else { dev_info(dev, "%s: No HW INIT function\n", __func__); } rc = cyttsp5_i2c_read_default(&client->dev, buf, 16); if (rc < 0) { dev_err(dev, "%s, read_default rc=%d\n", __func__, rc); return -ENODEV; } } rc = cyttsp5_probe(&cyttsp5_i2c_bus_ops, &client->dev, client->irq, CY_I2C_DATA_SIZE); #ifdef CONFIG_TOUCHSCREEN_CYPRESS_CYTTSP5_DEVICETREE_SUPPORT if (rc && match) cyttsp5_devtree_clean_pdata(dev); #endif return rc; } static void cyttsp5_i2c_remove(struct i2c_client *client) { #ifdef CONFIG_TOUCHSCREEN_CYPRESS_CYTTSP5_DEVICETREE_SUPPORT struct device *dev = &client->dev; const struct of_device_id *match; #endif struct cyttsp5_core_data *cd = i2c_get_clientdata(client); cyttsp5_release(cd); #ifdef CONFIG_TOUCHSCREEN_CYPRESS_CYTTSP5_DEVICETREE_SUPPORT match = of_match_device(of_match_ptr(cyttsp5_i2c_of_match), dev); if (match) cyttsp5_devtree_clean_pdata(dev); #endif } static const struct i2c_device_id cyttsp5_i2c_id[] = { { CYTTSP5_I2C_NAME, 0, }, { } }; MODULE_DEVICE_TABLE(i2c, cyttsp5_i2c_id); static struct i2c_driver cyttsp5_i2c_driver = { .driver = { .name = CYTTSP5_I2C_NAME, .owner = THIS_MODULE, .pm = &cyttsp5_pm_ops, #ifdef CONFIG_TOUCHSCREEN_CYPRESS_CYTTSP5_DEVICETREE_SUPPORT .of_match_table = cyttsp5_i2c_of_match, #endif }, .probe = cyttsp5_i2c_probe, .remove = cyttsp5_i2c_remove, .id_table = cyttsp5_i2c_id, }; #if (KERNEL_VERSION(3, 3, 0) <= LINUX_VERSION_CODE) module_i2c_driver(cyttsp5_i2c_driver); #else static int __init cyttsp5_i2c_init(void) { int rc = i2c_add_driver(&cyttsp5_i2c_driver); pr_info("%s: Parade TTSP I2C Driver (Built %s) rc=%d\n", __func__, CY_DRIVER_VERSION, rc); return rc; } late_initcall(cyttsp5_i2c_init); static void __exit cyttsp5_i2c_exit(void) { i2c_del_driver(&cyttsp5_i2c_driver); } module_exit(cyttsp5_i2c_exit); #endif MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Parade TrueTouch(R) Standard Product I2C driver"); MODULE_AUTHOR("Parade Technologies ");