/* * Synaptics DSX touchscreen driver * * Copyright (C) 2012 Synaptics Incorporated * * Copyright (C) 2012 Alexandra Chin * Copyright (C) 2012 Scott Lin * * 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. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "tfa9890.h" #ifdef KERNEL_ABOVE_2_6_38 #include #endif #define DRIVER_NAME "tfa9890" #define MAX_BUFFER_SIZE 512 #define GPIO_SLEEP_LOW_US 10 #define RESET_DELAY 500 struct tfa9890_dev { wait_queue_head_t read_wq; struct mutex read_mutex; struct device *dev; struct i2c_client *i2c_client; struct miscdevice tfa9890_device; unsigned int ven_gpio; unsigned int firm_gpio; unsigned int irq_gpio; unsigned int irq_flags; unsigned int irq; unsigned int reset_gpio; unsigned int reset_flags; bool i2c_pull_up; struct regulator *vdd; struct regulator *vcc_i2c; bool do_reading; bool irq_enabled; bool cancel_read; bool first_open; }; static ssize_t tfa9890_dev_read(struct file *filp, char __user *buf, size_t count, loff_t *offset) { struct tfa9890_dev *tfa9890_dev = filp->private_data; char tmp[MAX_BUFFER_SIZE]; int ret; if (count > MAX_BUFFER_SIZE) count = MAX_BUFFER_SIZE; mutex_lock(&tfa9890_dev->read_mutex); /* Read data */ ret = i2c_master_recv(tfa9890_dev->i2c_client, tmp, count); if (ret < 0) { pr_err("%s: i2c_master_recv returned %d\n", __func__, ret); mutex_unlock(&tfa9890_dev->read_mutex); return ret; } if (ret > count) { pr_err("%s: received too many bytes from i2c (%d)\n", __func__, ret); mutex_unlock(&tfa9890_dev->read_mutex); return -EIO; } if (copy_to_user(buf, tmp, ret)) { pr_warning("%s : failed to copy to user space\n", __func__); mutex_unlock(&tfa9890_dev->read_mutex); return -EFAULT; } mutex_unlock(&tfa9890_dev->read_mutex); return ret; } static ssize_t tfa9890_dev_write(struct file *filp, const char __user *buf, size_t count, loff_t *offset) { struct tfa9890_dev *tfa9890_dev = filp->private_data; char tmp[MAX_BUFFER_SIZE]; int ret; if (count > MAX_BUFFER_SIZE) count = MAX_BUFFER_SIZE; if (copy_from_user(tmp, buf, count)) { pr_err("%s : failed to copy from user space\n", __func__); return -EFAULT; } /* Write data */ ret = i2c_master_send(tfa9890_dev->i2c_client, tmp, count); if (ret != count) { pr_err("%s : i2c_master_send returned %d\n", __func__, ret); ret = -EIO; } return ret; } static int tfa9890_dev_open(struct inode *inode, struct file *filp) { int ret; struct tfa9890_dev *tfa9890_dev = container_of(filp->private_data, struct tfa9890_dev, tfa9890_device); filp->private_data = tfa9890_dev; pr_err("%s : %d,%d\n", __func__, imajor(inode), iminor(inode)); if (tfa9890_dev->first_open) { if (gpio_is_valid(tfa9890_dev->reset_gpio)) { /* configure tfa9890s reset out gpio */ ret = gpio_request(tfa9890_dev->reset_gpio, "tfa9890_reset_gpio"); if (ret) { dev_err(&tfa9890_dev->i2c_client->dev, "unable to request gpio [%d]\n", tfa9890_dev->reset_gpio); goto err_reset_gpio_dir; } ret = gpio_direction_output(tfa9890_dev->reset_gpio, 1); if (ret) { dev_err(&tfa9890_dev->i2c_client->dev, "unable to set direction for gpio [%d]\n", tfa9890_dev->reset_gpio); goto err_reset_gpio_dir; } gpio_set_value(tfa9890_dev->reset_gpio, 1); mdelay(GPIO_SLEEP_LOW_US); gpio_set_value(tfa9890_dev->reset_gpio, 0); mdelay(RESET_DELAY); } tfa9890_dev->first_open = false; printk("%s enter, reset PA at first open\n", __func__); } return 0; err_reset_gpio_dir: if (gpio_is_valid(tfa9890_dev->reset_gpio)) gpio_free(tfa9890_dev->reset_gpio); return ret; } static long tfa9890_dev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { struct tfa9890_dev *tfa9890_dev = filp->private_data; switch(cmd) { case I2C_SLAVE: { tfa9890_dev->i2c_client->addr = arg; break; } case ENABLE_MI2S_CLK: { udelay(500); msm_q6_enable_mi2s_clocks(arg); //printk("[%s][%d]\n",__func__,__LINE__); break; } default: break; } return 0; } static const struct file_operations tfa9890_dev_fops = { .owner = THIS_MODULE, .llseek = no_llseek, .read = tfa9890_dev_read, .write = tfa9890_dev_write, .open = tfa9890_dev_open, .unlocked_ioctl = tfa9890_dev_ioctl, }; static int tfa9890_parse_dt(struct device *dev, struct tfa9890_i2c_platform_data *pdata) { int ret = 0; struct device_node *np = dev->of_node; /* reset, irq gpio info */ pdata->reset_gpio = of_get_named_gpio_flags(np, "reset-gpio", 0, &pdata->reset_flags); pr_info("%s,pdata->reset_gpio = %d\n", __func__, pdata->reset_gpio); pdata->irq_gpio = of_get_named_gpio_flags(np, "irq-gpio", 0, &pdata->irq_flags); pr_info("%s,pdata->irq_gpio = %d\n", __func__, pdata->irq_gpio); pdata->i2c_pull_up = of_property_read_bool(np, "tfa9890,i2c-pull-up"); pr_info("%s,pdata->i2c_pull_up = %d\n", __func__, pdata->i2c_pull_up); return ret; } /** * nxp_tfa9890_probe() * * Called by the kernel when an association with an I2C device of the * same name is made (after doing i2c_add_driver). * * This funtion allocates and initializes the resources for the driver * as an input driver, turns on the power to the sensor, queries the * sensor for its supported Functions and characteristics, registers * the driver to the input subsystem, sets up the interrupt, handles * the registration of the early_suspend and late_resume functions, * and creates a work queue for detection of other expansion Function * modules. */ static int nxp_tfa9890_probe(struct i2c_client *client, const struct i2c_device_id *dev_id) { int ret = 0; struct tfa9890_i2c_platform_data *platform_data; struct tfa9890_dev *tfa9890_dev; printk("%s\n", __func__); if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { pr_err("%s: i2c check failed\n", __func__); ret = -ENODEV; goto err_i2c; } if (client->dev.of_node) { platform_data = devm_kzalloc(&client->dev, sizeof(*platform_data), GFP_KERNEL); if (!platform_data) { dev_err(&client->dev, "Failed to allocate memory\n"); return -ENOMEM; } ret = tfa9890_parse_dt(&client->dev, platform_data); if (ret) return ret; } else { platform_data = client->dev.platform_data; } tfa9890_dev = kzalloc(sizeof(*tfa9890_dev), GFP_KERNEL); if (tfa9890_dev == NULL) { pr_err("failed to allocate memory for module data\n"); ret = -ENOMEM; goto err_exit; } tfa9890_dev->i2c_client = client; tfa9890_dev->dev = &client->dev; tfa9890_dev->do_reading = 0; /* Initialise mutex and work queue */ init_waitqueue_head(&tfa9890_dev->read_wq); mutex_init(&tfa9890_dev->read_mutex); tfa9890_dev->irq_enabled = false; tfa9890_dev->tfa9890_device.minor = MISC_DYNAMIC_MINOR; tfa9890_dev->tfa9890_device.name = "tfa9890"; tfa9890_dev->tfa9890_device.fops = &tfa9890_dev_fops; if (gpio_is_valid(platform_data->reset_gpio)) { /* configure tfa9890s reset out gpio */ ret = gpio_request(platform_data->reset_gpio, "tfa9890_reset_gpio"); if (ret) { dev_err(&client->dev, "unable to request gpio [%d]\n", platform_data->reset_gpio); goto err_reset_gpio_dir; } ret = gpio_direction_output(platform_data->reset_gpio, 1); if (ret) { dev_err(&client->dev, "unable to set direction for gpio [%d]\n", platform_data->reset_gpio); goto err_reset_gpio_dir; } gpio_set_value(platform_data->reset_gpio, 1); mdelay(GPIO_SLEEP_LOW_US); gpio_set_value(platform_data->reset_gpio, 0); mdelay(RESET_DELAY); } ret = misc_register(&tfa9890_dev->tfa9890_device); if (ret) { pr_err("%s : misc_register failed\n", __FILE__); goto err_misc_register; } printk("%s Done\n", __func__); return 0; err_misc_register: misc_deregister(&tfa9890_dev->tfa9890_device); mutex_destroy(&tfa9890_dev->read_mutex); kfree(tfa9890_dev); #if 1 err_reset_gpio_dir: if (gpio_is_valid(platform_data->reset_gpio)) gpio_free(platform_data->reset_gpio); #endif err_exit: err_i2c: kfree(platform_data); return ret; } /** * nxp_tfa9890_remove() * * Called by the kernel when the association with an I2C device of the * same name is broken (when the driver is unloaded). * * This funtion terminates the work queue, stops sensor data acquisition, * frees the interrupt, unregisters the driver from the input subsystem, * turns off the power to the sensor, and frees other allocated resources. */ static int nxp_tfa9890_remove(struct i2c_client *client) { struct tfa9890_dev *tfa9890_dev; pr_info("%s\n", __func__); tfa9890_dev = i2c_get_clientdata(client); misc_deregister(&tfa9890_dev->tfa9890_device); mutex_destroy(&tfa9890_dev->read_mutex); kfree(tfa9890_dev); return 0; } #ifdef CONFIG_PM /** * nxp_tfa9890_suspend() * * Called by the kernel during the suspend phase when the system * enters suspend. * * This function stops finger data acquisition and puts the sensor to * sleep (if not already done so during the early suspend phase), * disables the interrupt, and turns off the power to the sensor. */ static int nxp_tfa9890_suspend(struct device *dev) { pr_info(KERN_ALERT "----------------suspend"); return 0; } /** * nxp_tfa9890_resume() * * Called by the kernel during the resume phase when the system * wakes up from suspend. * * This function turns on the power to the sensor, wakes the sensor * from sleep, enables the interrupt, and starts finger data * acquisition. */ static int nxp_tfa9890_resume(struct device *dev) { return 0; } static const struct dev_pm_ops nxp_tfa9890_dev_pm_ops = { .suspend = nxp_tfa9890_suspend, .resume = nxp_tfa9890_resume, }; #endif static const struct i2c_device_id nxp_tfa9890_id_table[] = { {DRIVER_NAME, 0}, {}, }; MODULE_DEVICE_TABLE(i2c, nxp_tfa9890_id_table); #ifdef CONFIG_OF static struct of_device_id tfa9890_match_table[] = { { .compatible = "nxp,tfa9890",}, { }, }; #else #define tfa9890_match_table NULL #endif static struct i2c_driver nxp_tfa9890_driver = { .driver = { .name = DRIVER_NAME, .owner = THIS_MODULE, .of_match_table = tfa9890_match_table, #ifdef CONFIG_PM .pm = &nxp_tfa9890_dev_pm_ops, #endif }, .probe = nxp_tfa9890_probe, .remove =nxp_tfa9890_remove, .id_table = nxp_tfa9890_id_table, }; /** * nxp_tfa9890_init() * * Called by the kernel during do_initcalls (if built-in) * or when the driver is loaded (if a module). * * This function registers the driver to the I2C subsystem. * */ static int __init nxp_tfa9890_init(void) { printk("%s\n",__func__); return i2c_add_driver(&nxp_tfa9890_driver); } /** * nxp_tfa9890_exit() * * Called by the kernel when the driver is unloaded. * * This funtion unregisters the driver from the I2C subsystem. * */ static void __exit nxp_tfa9890_exit(void) { i2c_del_driver(&nxp_tfa9890_driver); return; } module_init(nxp_tfa9890_init); module_exit(nxp_tfa9890_exit); MODULE_AUTHOR("NXP, Inc."); MODULE_DESCRIPTION("NXP TFA9885 I2C Touch Driver"); MODULE_LICENSE("GPL v2");