1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
|
/*
* Driver for Freescale Semiconductor CRTOUCH - A Resistive and Capacitive
* touch device with i2c interface
*
* Copyright 2012 Freescale Semiconductor, 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.
*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/i2c.h>
#include <linux/interrupt.h>
#include <linux/input.h>
#include <linux/input/mt.h>
#include <linux/slab.h>
#include <linux/bitops.h>
#include <linux/gpio.h>
/* Resistive touch sense status registers */
#define RES_STA_ERROR 0x00
#define RES_STA_STATUS1 0x01
#define RES_STA_STATUS2 0x02
#define RES_STA_X_MSB 0x03
#define RES_STA_X_LSB 0x04
#define RES_STA_Y_MSB 0x05
#define RES_STA_Y_LSB 0x06
#define RES_STA_PRES_MSB 0x07
#define RES_STA_RRES_LSB 0x08
#define RES_STA_FIFO_STATUS 0x09
#define RES_STA_FIFO_X_MSB 0x0a
#define RES_STA_FIFO_X_LSB 0x0b
#define RES_STA_FIFO_Y_MSB 0x0c
#define RES_STA_FIFO_Y_LSB 0x0d
#define RES_STA_FIFO_PRES_MSB 0x0e
#define RES_STA_FIFO_PRES_LSB 0x0f
#define RES_STA_UART_BRATE_MSB 0x10
#define RES_STA_UART_BRATE_MID 0x11
#define RES_STA_UART_BRATE_LSB 0x12
#define RES_STA_DEV_IDEN 0x13
#define RES_STA_SLIDE_DISPLACE 0x14
#define RES_STA_ROTATE_ANGLE 0x15
/* Resistive touch configuration registers */
#define CR_CON_SYSTEM 0x40
#define CR_CON_TRIG_EVENT 0x41
#define CR_CON_FIFO_SETUP 0x42
#define CR_CON_SAMPLING_RATE 0x43
#define CR_CON_X_DELAY_MSB 0x44
#define CR_CON_X_DELAY_LSB 0x45
#define CR_CON_Y_DELAY_MSB 0x46
#define CR_CON_Y_DELAY_LSB 0x47
#define CR_CON_Z_DELAY_MSB 0x48
#define CR_CON_Z_DELAY_LSB 0x49
#define CR_CON_DIS_HOR_MSB 0x4a
#define CR_CON_DIS_HOR_LSB 0x4b
#define CR_CON_DIS_VER_MSB 0x4c
#define CR_CON_DIS_VER_LSB 0x4d
#define CR_CON_SLIDE_STEPS 0x4e
#define RTST_EVENT (1 << 7)
#define RTS2T_EVENT (1 << 6)
#define RTSZ_EVENT (1 << 5)
#define RTSR_EVENT (1 << 4)
#define RTSS_EVENT (1 << 3)
#define RTSF_EVENT (1 << 2)
#define RTSRDY_EVENT (1 << 0)
#define RTSSD_MASK (1 << 2)
#define RTSSD_H_POS (0 << 2)
#define RTSSD_H_NEG (1 << 2)
#define RTSSD_V_POS (1 << 3)
#define RTSSD_V_NEG (1 << 4)
#define RTSRD_MASK (1 << 4)
#define RTSRD_CLK_WISE (0 << 4)
#define RTSRD_COUNTER_CLK_WISE (1 << 4)
#define RTSZD_MASK (1 << 5)
#define RTSZD_ZOOM_IN (0 << 5)
#define RTSZD_ZOOM_OUT (1 << 5)
#define CRTOUCH_MAX_FINGER 2
#define CRTOUCH_MAX_AREA 0xfff
#define CRTOUCH_MAX_X 0x01df
#define CRTOUCH_MAX_Y 0x010f
struct crtouch_ts_data {
struct i2c_client *client;
struct input_dev *input_dev;
};
static u8 crtouch_read_reg(struct i2c_client *client, int addr)
{
return i2c_smbus_read_byte_data(client, addr);
}
static int crtouch_write_reg(struct i2c_client *client, int addr, int data)
{
return i2c_smbus_write_byte_data(client, addr, data);
}
static void calibration_pointer(u16 *x_orig, u16 *y_orig)
{
u16 x, y;
x = CRTOUCH_MAX_X - *x_orig;
*x_orig = x;
y = CRTOUCH_MAX_Y - *y_orig;
*y_orig = y;
}
static irqreturn_t crtouch_ts_interrupt(int irq, void *dev_id)
{
struct crtouch_ts_data *data = dev_id;
struct i2c_client *client = data->client;
u8 status1;
u16 valuep, valuex, valuey;
status1 = crtouch_read_reg(client, RES_STA_STATUS1);
/* For single touch */
if (status1 & RTST_EVENT) {
valuep = crtouch_read_reg(client, RES_STA_PRES_MSB);
valuep = ((valuep << 8) |
crtouch_read_reg(client, RES_STA_RRES_LSB));
valuex = crtouch_read_reg(client, RES_STA_X_MSB);
valuex = ((valuex << 8) |
crtouch_read_reg(client, RES_STA_X_LSB));
valuey = crtouch_read_reg(client, RES_STA_Y_MSB);
valuey = ((valuey << 8) |
crtouch_read_reg(client, RES_STA_Y_LSB));
calibration_pointer(&valuex, &valuey);
input_report_key(data->input_dev, BTN_TOUCH, 1);
input_report_abs(data->input_dev, ABS_X, valuex);
input_report_abs(data->input_dev, ABS_Y, valuey);
input_report_abs(data->input_dev, ABS_PRESSURE, valuep);
input_sync(data->input_dev);
} else {
input_report_abs(data->input_dev, ABS_PRESSURE, 0);
input_event(data->input_dev, EV_KEY, BTN_TOUCH, 0);
input_sync(data->input_dev);
}
return IRQ_HANDLED;
}
static void __devinit crtouch_ts_reg_init(struct crtouch_ts_data *data)
{
struct i2c_client *client = data->client;
crtouch_write_reg(client, CR_CON_SYSTEM, 0x9c);
crtouch_write_reg(client, CR_CON_TRIG_EVENT, 0xf9);
crtouch_write_reg(client, CR_CON_FIFO_SETUP, 0x1f);
crtouch_write_reg(client, CR_CON_SAMPLING_RATE, 0x08);
crtouch_write_reg(client, CR_CON_DIS_HOR_MSB, 0x01);
crtouch_write_reg(client, CR_CON_DIS_HOR_LSB, 0xdf);
crtouch_write_reg(client, CR_CON_DIS_VER_MSB, 0x01);
crtouch_write_reg(client, CR_CON_DIS_VER_LSB, 0x0f);
}
static int __devinit crtouch_ts_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct crtouch_ts_data *data;
struct input_dev *input_dev;
int error;
data = kzalloc(sizeof(struct crtouch_ts_data), GFP_KERNEL);
input_dev = input_allocate_device();
if (!data || !input_dev) {
dev_err(&client->dev, "Failed to allocate memory\n");
error = -ENOMEM;
goto err_free_mem;
}
data->client = client;
data->input_dev = input_dev;
input_dev->name = "crtouch_ts";
input_dev->id.bustype = BUS_I2C;
input_dev->dev.parent = &client->dev;
/* For single touch */
__set_bit(EV_KEY, input_dev->evbit);
__set_bit(BTN_TOUCH, input_dev->keybit);
__set_bit(EV_ABS, input_dev->evbit);
__set_bit(ABS_X, input_dev->absbit);
__set_bit(ABS_Y, input_dev->absbit);
__set_bit(ABS_PRESSURE, input_dev->absbit);
input_set_abs_params(input_dev, ABS_X, 0, CRTOUCH_MAX_X, 0, 0);
input_set_abs_params(input_dev, ABS_Y, 0, CRTOUCH_MAX_Y, 0, 0);
input_set_abs_params(input_dev, ABS_PRESSURE, 0,
CRTOUCH_MAX_AREA, 0, 0);
input_set_drvdata(input_dev, data);
crtouch_ts_reg_init(data);
error = gpio_request_one(21, GPIOF_IN, "TS_IRQ");
if (error) {
dev_err(&client->dev, "Failed to request gpio\n");
goto err_free_mem;
}
error = request_threaded_irq(gpio_to_irq(21), NULL,
crtouch_ts_interrupt, IRQF_TRIGGER_FALLING, "crtouch_ts", data);
if (error) {
dev_err(&client->dev, "Failed to register interrupt\n");
goto err_free_mem;
}
error = input_register_device(data->input_dev);
if (error)
goto err_free_irq;
i2c_set_clientdata(client, data);
return 0;
err_free_irq:
free_irq(client->irq, data);
err_free_mem:
input_free_device(input_dev);
kfree(data);
return error;
}
static __devexit int crtouch_ts_remove(struct i2c_client *client)
{
struct crtouch_ts_data *data = i2c_get_clientdata(client);
free_irq(client->irq, data);
input_unregister_device(data->input_dev);
kfree(data);
return 0;
}
static const struct i2c_device_id crtouch_ts_id[] = {
{"crtouch_ts", 0},
{ }
};
MODULE_DEVICE_TABLE(i2c, crtouch_ts_id);
static struct i2c_driver crtouch_ts_driver = {
.driver = {
.name = "crtouch_ts",
.owner = THIS_MODULE,
},
.id_table = crtouch_ts_id,
.probe = crtouch_ts_probe,
.remove = __devexit_p(crtouch_ts_remove),
};
static int __init crtouch_ts_init(void)
{
return i2c_add_driver(&crtouch_ts_driver);
}
static void __exit crtouch_ts_exit(void)
{
i2c_del_driver(&crtouch_ts_driver);
}
module_init(crtouch_ts_init);
module_exit(crtouch_ts_exit);
MODULE_AUTHOR("Alison Wang <b18965@freescale.com>");
MODULE_DESCRIPTION("Touchscreen driver for Freescale CRTOUCH");
MODULE_LICENSE("GPL");
|