OLD | NEW |
---|---|
(Empty) | |
1 /* Quanta I2C Touchpad Driver | |
2 * | |
3 * Copyright (C) 2009 Quanta Computer Inc. | |
4 * Author: Hsin Wu <hsin.wu@quantatw.com> | |
5 * Author: Austin Lai <austin.lai@quantatw.com> | |
6 * | |
7 * This software is licensed under the terms of the GNU General Public | |
8 * License version 2, as published by the Free Software Foundation, and | |
9 * may be copied, distributed, and modified under those terms. | |
10 * | |
11 * This program is distributed in the hope that it will be useful, | |
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
14 * GNU General Public License for more details. | |
15 * | |
16 */ | |
17 | |
18 /* | |
19 * | |
20 * The Driver with I/O communications via the I2C Interface for ON2 of AP BU. | |
21 * And it is only working on the nuvoTon WPCE775x Embedded Controller. | |
22 * | |
23 */ | |
24 | |
25 #include <linux/kernel.h> | |
26 #include <linux/init.h> | |
27 #include <linux/module.h> | |
28 #include <linux/slab.h> | |
29 #include <linux/jiffies.h> | |
30 #include <linux/i2c.h> | |
31 #include <linux/mutex.h> | |
32 #include <linux/interrupt.h> | |
33 #include <linux/input.h> | |
34 #include <linux/keyboard.h> | |
35 #include <linux/gpio.h> | |
36 #include <linux/delay.h> | |
37 | |
38 #define TOUCHPAD_ID_NAME "qci-i2cpad" | |
39 #define TOUCHPAD_NAME "PS2 Touchpad" | |
40 #define TOUCHPAD_DEVICE "/i2c/input1" | |
41 #define TOUCHPAD_CMD_ENABLE 0xF4 | |
42 | |
43 static int __devinit qcitp_probe(struct i2c_client *client, | |
44 const struct i2c_device_id *id); | |
45 static int __devexit qcitp_remove(struct i2c_client *kbd); | |
46 | |
47 /* General structure to hold the driver data */ | |
48 struct i2ctpad_drv_data { | |
49 struct i2c_client *ti2c_client; | |
50 struct work_struct work; | |
51 struct input_dev *qcitp_dev; | |
52 struct kobject *tp_kobj; | |
53 unsigned int qcitp_gpio; | |
54 unsigned int qcitp_irq; | |
55 char ecdata[8]; | |
56 }; | |
57 | |
58 static int tp_sense_val = 10; | |
59 static ssize_t tp_sensitive_show(struct kobject *kobj, | |
60 struct kobj_attribute *attr, char * buf) | |
61 { | |
62 return sprintf(buf, "%d\n", tp_sense_val); | |
63 } | |
64 | |
65 static ssize_t tp_sensitive_store(struct kobject *kobj, | |
66 struct kobj_attribute *attr, const char* buf, size_t n) | |
67 { | |
68 unsigned int val = 0; | |
69 sscanf(buf, "%d", &val); | |
70 | |
71 if (val >= 1 && val <= 10) | |
72 tp_sense_val = val; | |
73 else | |
74 return -ENOSYS; | |
75 | |
76 return sizeof(buf); | |
77 } | |
78 | |
79 static struct kobj_attribute tp_sensitivity = __ATTR(tp_sensitivity , | |
80 0644 , | |
81 tp_sensitive_show , | |
82 tp_sensitive_store); | |
83 | |
84 static struct attribute *g_tp[] = { | |
85 &tp_sensitivity.attr, | |
86 NULL, | |
87 }; | |
88 | |
89 static struct attribute_group attr_group = { | |
90 .attrs = g_tp, | |
91 }; | |
92 | |
93 /*----------------------------------------------------------------------------- | |
94 * Driver functions | |
95 *---------------------------------------------------------------------------*/ | |
96 | |
97 #ifdef CONFIG_PM | |
98 static int qcitp_suspend(struct device *dev) | |
99 { | |
100 return 0; | |
101 } | |
102 | |
103 static int qcitp_resume(struct device *dev) | |
104 { | |
105 return 0; | |
106 } | |
107 #endif | |
108 | |
109 static const struct i2c_device_id qcitp_idtable[] = { | |
110 { TOUCHPAD_ID_NAME, 0 }, | |
111 { } | |
112 }; | |
113 | |
114 MODULE_DEVICE_TABLE(i2c, qcitp_idtable); | |
115 #ifdef CONFIG_PM | |
116 static struct dev_pm_ops qcitp_pm_ops = { | |
117 .suspend = qcitp_suspend, | |
118 .resume = qcitp_resume, | |
119 }; | |
120 #endif | |
121 static struct i2c_driver i2ctp_driver = { | |
122 .driver = { | |
123 .owner = THIS_MODULE, | |
124 .name = TOUCHPAD_ID_NAME, | |
125 #ifdef CONFIG_PM | |
126 .pm = &qcitp_pm_ops, | |
127 #endif | |
128 }, | |
129 .probe = qcitp_probe, | |
130 .remove = __devexit_p(qcitp_remove), | |
131 .id_table = qcitp_idtable, | |
132 }; | |
133 | |
134 static void qcitp_fetch_data(struct i2c_client *tpad_client, | |
135 char *ec_data) | |
136 { | |
137 struct i2c_msg tp_msg; | |
138 int ret; | |
139 tp_msg.addr = tpad_client->addr; | |
140 tp_msg.flags = I2C_M_RD; | |
141 tp_msg.len = 3; | |
142 tp_msg.buf = (char *)&ec_data[0]; | |
143 ret = i2c_transfer(tpad_client->adapter, &tp_msg, 1); | |
144 } | |
145 | |
146 static void qcitp_report_key(struct input_dev *tpad_dev, char *ec_data) | |
147 { | |
148 int dx = 0; | |
149 int dy = 0; | |
150 | |
151 if (ec_data[1]) | |
152 dx = (int) ec_data[1] - | |
153 (int) ((ec_data[0] << 4) & 0x100); | |
154 | |
155 if (ec_data[2]) | |
156 dy = (int) ((ec_data[0] << 3) & 0x100) - | |
157 (int) ec_data[2]; | |
158 | |
159 dx = (dx * tp_sense_val)/10; | |
160 dy = (dy * tp_sense_val)/10; | |
161 | |
162 input_report_key(tpad_dev, BTN_LEFT, ec_data[0] & 0x01); | |
163 input_report_key(tpad_dev, BTN_RIGHT, ec_data[0] & 0x02); | |
164 input_report_key(tpad_dev, BTN_MIDDLE, ec_data[0] & 0x04); | |
165 input_report_rel(tpad_dev, REL_X, dx); | |
166 input_report_rel(tpad_dev, REL_Y, dy); | |
167 input_sync(tpad_dev); | |
168 } | |
169 | |
170 static void qcitp_work_handler(struct work_struct *_work) | |
171 { | |
172 struct i2ctpad_drv_data *itpad_drv_data = | |
173 container_of(_work, struct i2ctpad_drv_data, work); | |
174 | |
175 struct i2c_client *itpad_client = itpad_drv_data->ti2c_client; | |
176 struct input_dev *itpad_dev = itpad_drv_data->qcitp_dev; | |
177 | |
178 qcitp_fetch_data(itpad_client, itpad_drv_data->ecdata); | |
179 qcitp_report_key(itpad_dev, itpad_drv_data->ecdata); | |
180 } | |
181 | |
182 static irqreturn_t qcitp_interrupt(int irq, void *dev_id) | |
183 { | |
184 struct i2ctpad_drv_data *itpad_drv_data = dev_id; | |
185 schedule_work(&itpad_drv_data->work); | |
186 return IRQ_HANDLED; | |
187 } | |
188 | |
189 static int __devinit qcitp_probe(struct i2c_client *client, | |
190 const struct i2c_device_id *id) | |
191 { | |
192 int err = -ENOMEM; | |
193 struct i2ctpad_drv_data *context = 0; | |
194 | |
195 context = kzalloc(sizeof(struct i2ctpad_drv_data), GFP_KERNEL); | |
196 if (!context) | |
197 return err; | |
198 i2c_set_clientdata(client, context); | |
199 context->ti2c_client = client; | |
200 context->qcitp_gpio = client->irq; | |
201 | |
202 /* Enable mouse */ | |
203 i2c_smbus_write_byte(client, TOUCHPAD_CMD_ENABLE); | |
204 mdelay(100); | |
205 i2c_smbus_read_byte(client); | |
206 /*allocate and register input device*/ | |
207 context->qcitp_dev = input_allocate_device(); | |
208 if (!context->qcitp_dev) { | |
209 pr_err("[TouchPad] allocting memory fail\n"); | |
210 err = -ENOMEM; | |
211 goto allocate_fail; | |
212 } | |
213 context->qcitp_dev->name = TOUCHPAD_NAME; | |
214 context->qcitp_dev->phys = TOUCHPAD_DEVICE; | |
215 context->qcitp_dev->id.bustype = BUS_I2C; | |
216 context->qcitp_dev->id.vendor = 0x1050; | |
217 context->qcitp_dev->id.product = 0x1; | |
218 context->qcitp_dev->id.version = 0x1; | |
219 context->qcitp_dev->evbit[0] = BIT_MASK(EV_KEY) | | |
220 BIT_MASK(EV_REL); | |
221 context->qcitp_dev->relbit[0] = BIT_MASK(REL_X) | | |
222 BIT_MASK(REL_Y); | |
223 context->qcitp_dev->keybit[BIT_WORD(BTN_LEFT)] = BIT_MASK(BTN_LEFT) | | |
224 BIT_MASK(BTN_MIDDLE) | | |
225 BIT_MASK(BTN_RIGHT); | |
226 | |
227 input_set_drvdata(context->qcitp_dev, context); | |
228 err = input_register_device(context->qcitp_dev); | |
229 if (err) { | |
230 pr_err("[TouchPad] register device fail\n"); | |
231 goto register_fail; | |
232 } | |
233 | |
234 /*request intterrupt*/ | |
Mandeep Singh Baines
2010/03/23 18:06:03
request interrupt
| |
235 INIT_WORK(&context->work, qcitp_work_handler); | |
236 | |
237 err = gpio_request(context->qcitp_gpio, "qci-pad"); | |
238 if (err) { | |
239 pr_err("[TouchPad]err gpio request\n"); | |
240 goto gpio_request_fail; | |
241 } | |
242 | |
243 context->qcitp_irq = gpio_to_irq(context->qcitp_gpio); | |
244 err = request_irq(context->qcitp_irq, | |
245 qcitp_interrupt, | |
246 IRQF_TRIGGER_FALLING, | |
247 TOUCHPAD_ID_NAME, | |
248 context); | |
249 if (err) { | |
250 pr_err("[TouchPad] unable to get IRQ\n"); | |
251 goto request_irq_fail; | |
252 } | |
253 /*create touchpad kobject*/ | |
254 context->tp_kobj = kobject_create_and_add("touchpad", NULL); | |
255 | |
256 err = sysfs_create_group(context->tp_kobj, &attr_group); | |
257 if (err) | |
258 pr_warning("[TouchPad] sysfs create fail\n"); | |
259 | |
260 tp_sense_val = 10; | |
261 | |
262 return 0; | |
263 | |
264 request_irq_fail: | |
265 gpio_free(context->qcitp_gpio); | |
266 | |
267 gpio_request_fail: | |
268 input_unregister_device(context->qcitp_dev); | |
269 | |
270 register_fail: | |
271 input_free_device(context->qcitp_dev); | |
272 | |
273 allocate_fail: | |
274 i2c_set_clientdata(client, NULL); | |
275 kfree(context); | |
276 return err; | |
277 } | |
278 | |
279 static int __devexit qcitp_remove(struct i2c_client *dev) | |
280 { | |
281 struct i2ctpad_drv_data *context = i2c_get_clientdata(dev); | |
282 | |
283 free_irq(context->qcitp_irq, context); | |
284 gpio_free(context->qcitp_gpio); | |
285 input_free_device(context->qcitp_dev); | |
286 input_unregister_device(context->qcitp_dev); | |
287 kfree(context); | |
288 | |
289 return 0; | |
290 } | |
291 | |
292 static int __init qcitp_init(void) | |
293 { | |
294 return i2c_add_driver(&i2ctp_driver); | |
295 } | |
296 | |
297 | |
298 static void __exit qcitp_exit(void) | |
299 { | |
300 i2c_del_driver(&i2ctp_driver); | |
301 } | |
302 | |
303 module_init(qcitp_init); | |
304 module_exit(qcitp_exit); | |
305 | |
306 MODULE_AUTHOR("Quanta Computer Inc."); | |
307 MODULE_DESCRIPTION("Quanta Embedded Controller I2C Touch Pad Driver"); | |
308 MODULE_LICENSE("GPL v2"); | |
OLD | NEW |