Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Input: add driver for pixcir i2c touchscreens

This patch adds a driver for PIXCIR's I2C connected touchscreens.

Signed-off-by: Jianchun <jcbian@pixcir.com.cn>
Acked-by: Henrik Rydberg <rydberg@euromail.se>
Signed-off-by: Dmitry Torokhov <dtor@mail.ru>

authored by

Jianchun Bian and committed by
Dmitry Torokhov
36a281e2 48c98b1b

+262
+12
drivers/input/touchscreen/Kconfig
··· 458 458 To compile this driver as a module, choose M here: the 459 459 module will be called ucb1400_ts. 460 460 461 + config TOUCHSCREEN_PIXCIR 462 + tristate "PIXCIR I2C touchscreens" 463 + depends on I2C 464 + help 465 + Say Y here if you have a pixcir i2c touchscreen 466 + controller. 467 + 468 + If unsure, say N. 469 + 470 + To compile this driver as a module, choose M here: the 471 + module will be called pixcir_i2c_ts. 472 + 461 473 config TOUCHSCREEN_WM831X 462 474 tristate "Support for WM831x touchscreen controllers" 463 475 depends on MFD_WM831X
+1
drivers/input/touchscreen/Makefile
··· 41 41 obj-$(CONFIG_TOUCHSCREEN_USB_COMPOSITE) += usbtouchscreen.o 42 42 obj-$(CONFIG_TOUCHSCREEN_PCAP) += pcap_ts.o 43 43 obj-$(CONFIG_TOUCHSCREEN_PENMOUNT) += penmount.o 44 + obj-$(CONFIG_TOUCHSCREEN_PIXCIR) += pixcir_i2c_ts.o 44 45 obj-$(CONFIG_TOUCHSCREEN_S3C2410) += s3c2410_ts.o 45 46 obj-$(CONFIG_TOUCHSCREEN_ST1232) += st1232.o 46 47 obj-$(CONFIG_TOUCHSCREEN_STMPE) += stmpe-ts.o
+239
drivers/input/touchscreen/pixcir_i2c_ts.c
··· 1 + /* 2 + * Driver for Pixcir I2C touchscreen controllers. 3 + * 4 + * Copyright (C) 2010-2011 Pixcir, Inc. 5 + * 6 + * This software is licensed under the terms of the GNU General Public 7 + * License version 2, as published by the Free Software Foundation, and 8 + * may be copied, distributed, and modified under those terms. 9 + * 10 + * This program is distributed in the hope that it will be useful, 11 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 + * GNU General Public License for more details. 14 + * 15 + * You should have received a copy of the GNU General Public 16 + * License along with this library; if not, write to the Free Software 17 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 18 + */ 19 + 20 + #include <linux/delay.h> 21 + #include <linux/module.h> 22 + #include <linux/interrupt.h> 23 + #include <linux/slab.h> 24 + #include <linux/i2c.h> 25 + #include <linux/input.h> 26 + #include <linux/input/pixcir_ts.h> 27 + 28 + struct pixcir_i2c_ts_data { 29 + struct i2c_client *client; 30 + struct input_dev *input; 31 + const struct pixcir_ts_platform_data *chip; 32 + bool exiting; 33 + }; 34 + 35 + static void pixcir_ts_poscheck(struct pixcir_i2c_ts_data *data) 36 + { 37 + struct pixcir_i2c_ts_data *tsdata = data; 38 + u8 rdbuf[10], wrbuf[1] = { 0 }; 39 + u8 touch; 40 + int ret; 41 + 42 + ret = i2c_master_send(tsdata->client, wrbuf, sizeof(wrbuf)); 43 + if (ret != sizeof(wrbuf)) { 44 + dev_err(&tsdata->client->dev, 45 + "%s: i2c_master_send failed(), ret=%d\n", 46 + __func__, ret); 47 + return; 48 + } 49 + 50 + ret = i2c_master_recv(tsdata->client, rdbuf, sizeof(rdbuf)); 51 + if (ret != sizeof(rdbuf)) { 52 + dev_err(&tsdata->client->dev, 53 + "%s: i2c_master_recv failed(), ret=%d\n", 54 + __func__, ret); 55 + return; 56 + } 57 + 58 + touch = rdbuf[0]; 59 + if (touch) { 60 + u16 posx1 = (rdbuf[3] << 8) | rdbuf[2]; 61 + u16 posy1 = (rdbuf[5] << 8) | rdbuf[4]; 62 + u16 posx2 = (rdbuf[7] << 8) | rdbuf[6]; 63 + u16 posy2 = (rdbuf[9] << 8) | rdbuf[8]; 64 + 65 + input_report_key(tsdata->input, BTN_TOUCH, 1); 66 + input_report_abs(tsdata->input, ABS_X, posx1); 67 + input_report_abs(tsdata->input, ABS_Y, posy1); 68 + 69 + input_report_abs(tsdata->input, ABS_MT_POSITION_X, posx1); 70 + input_report_abs(tsdata->input, ABS_MT_POSITION_Y, posy1); 71 + input_mt_sync(tsdata->input); 72 + 73 + if (touch == 2) { 74 + input_report_abs(tsdata->input, 75 + ABS_MT_POSITION_X, posx2); 76 + input_report_abs(tsdata->input, 77 + ABS_MT_POSITION_Y, posy2); 78 + input_mt_sync(tsdata->input); 79 + } 80 + } else { 81 + input_report_key(tsdata->input, BTN_TOUCH, 0); 82 + } 83 + 84 + input_sync(tsdata->input); 85 + } 86 + 87 + static irqreturn_t pixcir_ts_isr(int irq, void *dev_id) 88 + { 89 + struct pixcir_i2c_ts_data *tsdata = dev_id; 90 + 91 + while (!tsdata->exiting) { 92 + pixcir_ts_poscheck(tsdata); 93 + 94 + if (tsdata->chip->attb_read_val()) 95 + break; 96 + 97 + msleep(20); 98 + } 99 + 100 + return IRQ_HANDLED; 101 + } 102 + 103 + #ifdef CONFIG_PM_SLEEP 104 + static int pixcir_i2c_ts_suspend(struct device *dev) 105 + { 106 + struct i2c_client *client = to_i2c_client(dev); 107 + 108 + if (device_may_wakeup(&client->dev)) 109 + enable_irq_wake(client->irq); 110 + 111 + return 0; 112 + } 113 + 114 + static int pixcir_i2c_ts_resume(struct device *dev) 115 + { 116 + struct i2c_client *client = to_i2c_client(dev); 117 + 118 + if (device_may_wakeup(&client->dev)) 119 + disable_irq_wake(client->irq); 120 + 121 + return 0; 122 + } 123 + #endif 124 + 125 + static SIMPLE_DEV_PM_OPS(pixcir_dev_pm_ops, 126 + pixcir_i2c_ts_suspend, pixcir_i2c_ts_resume); 127 + 128 + static int __devinit pixcir_i2c_ts_probe(struct i2c_client *client, 129 + const struct i2c_device_id *id) 130 + { 131 + const struct pixcir_ts_platform_data *pdata = client->dev.platform_data; 132 + struct pixcir_i2c_ts_data *tsdata; 133 + struct input_dev *input; 134 + int error; 135 + 136 + if (!pdata) { 137 + dev_err(&client->dev, "platform data not defined\n"); 138 + return -EINVAL; 139 + } 140 + 141 + tsdata = kzalloc(sizeof(*tsdata), GFP_KERNEL); 142 + input = input_allocate_device(); 143 + if (!tsdata || !input) { 144 + dev_err(&client->dev, "Failed to allocate driver data!\n"); 145 + error = -ENOMEM; 146 + goto err_free_mem; 147 + } 148 + 149 + tsdata->client = client; 150 + tsdata->input = input; 151 + tsdata->chip = pdata; 152 + 153 + input->name = client->name; 154 + input->id.bustype = BUS_I2C; 155 + input->dev.parent = &client->dev; 156 + 157 + __set_bit(EV_KEY, input->evbit); 158 + __set_bit(EV_ABS, input->evbit); 159 + __set_bit(BTN_TOUCH, input->keybit); 160 + input_set_abs_params(input, ABS_X, 0, pdata->x_max, 0, 0); 161 + input_set_abs_params(input, ABS_Y, 0, pdata->y_max, 0, 0); 162 + input_set_abs_params(input, ABS_MT_POSITION_X, 0, pdata->x_max, 0, 0); 163 + input_set_abs_params(input, ABS_MT_POSITION_Y, 0, pdata->y_max, 0, 0); 164 + 165 + input_set_drvdata(input, tsdata); 166 + 167 + error = request_threaded_irq(client->irq, NULL, pixcir_ts_isr, 168 + IRQF_TRIGGER_FALLING, 169 + client->name, tsdata); 170 + if (error) { 171 + dev_err(&client->dev, "Unable to request touchscreen IRQ.\n"); 172 + goto err_free_mem; 173 + } 174 + 175 + error = input_register_device(input); 176 + if (error) 177 + goto err_free_irq; 178 + 179 + i2c_set_clientdata(client, tsdata); 180 + device_init_wakeup(&client->dev, 1); 181 + 182 + return 0; 183 + 184 + err_free_irq: 185 + free_irq(client->irq, tsdata); 186 + err_free_mem: 187 + input_free_device(input); 188 + kfree(tsdata); 189 + return error; 190 + } 191 + 192 + static int __devexit pixcir_i2c_ts_remove(struct i2c_client *client) 193 + { 194 + struct pixcir_i2c_ts_data *tsdata = i2c_get_clientdata(client); 195 + 196 + device_init_wakeup(&client->dev, 0); 197 + 198 + tsdata->exiting = true; 199 + mb(); 200 + free_irq(client->irq, tsdata); 201 + 202 + input_unregister_device(tsdata->input); 203 + kfree(tsdata); 204 + 205 + return 0; 206 + } 207 + 208 + static const struct i2c_device_id pixcir_i2c_ts_id[] = { 209 + { "pixcir_ts", 0 }, 210 + { } 211 + }; 212 + MODULE_DEVICE_TABLE(i2c, pixcir_i2c_ts_id); 213 + 214 + static struct i2c_driver pixcir_i2c_ts_driver = { 215 + .driver = { 216 + .owner = THIS_MODULE, 217 + .name = "pixcir_ts", 218 + .pm = &pixcir_dev_pm_ops, 219 + }, 220 + .probe = pixcir_i2c_ts_probe, 221 + .remove = __devexit_p(pixcir_i2c_ts_remove), 222 + .id_table = pixcir_i2c_ts_id, 223 + }; 224 + 225 + static int __init pixcir_i2c_ts_init(void) 226 + { 227 + return i2c_add_driver(&pixcir_i2c_ts_driver); 228 + } 229 + module_init(pixcir_i2c_ts_init); 230 + 231 + static void __exit pixcir_i2c_ts_exit(void) 232 + { 233 + i2c_del_driver(&pixcir_i2c_ts_driver); 234 + } 235 + module_exit(pixcir_i2c_ts_exit); 236 + 237 + MODULE_AUTHOR("Jianchun Bian <jcbian@pixcir.com.cn>, Dequan Meng <dqmeng@pixcir.com.cn>"); 238 + MODULE_DESCRIPTION("Pixcir I2C Touchscreen Driver"); 239 + MODULE_LICENSE("GPL");
+10
include/linux/input/pixcir_ts.h
··· 1 + #ifndef _PIXCIR_I2C_TS_H 2 + #define _PIXCIR_I2C_TS_H 3 + 4 + struct pixcir_ts_platform_data { 5 + int (*attb_read_val)(void); 6 + int x_max; 7 + int y_max; 8 + }; 9 + 10 + #endif