Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/drivers/input/touchscreen/tps6507x-ts.c
15111 views
1
/*
2
* drivers/input/touchscreen/tps6507x_ts.c
3
*
4
* Touchscreen driver for the tps6507x chip.
5
*
6
* Copyright (c) 2009 RidgeRun ([email protected])
7
*
8
* Credits:
9
*
10
* Using code from tsc2007, MtekVision Co., Ltd.
11
*
12
* For licencing details see kernel-base/COPYING
13
*
14
* TPS65070, TPS65073, TPS650731, and TPS650732 support
15
* 10 bit touch screen interface.
16
*/
17
18
#include <linux/module.h>
19
#include <linux/workqueue.h>
20
#include <linux/slab.h>
21
#include <linux/input.h>
22
#include <linux/platform_device.h>
23
#include <linux/mfd/tps6507x.h>
24
#include <linux/input/tps6507x-ts.h>
25
#include <linux/delay.h>
26
27
#define TSC_DEFAULT_POLL_PERIOD 30 /* ms */
28
#define TPS_DEFAULT_MIN_PRESSURE 0x30
29
#define MAX_10BIT ((1 << 10) - 1)
30
31
#define TPS6507X_ADCONFIG_CONVERT_TS (TPS6507X_ADCONFIG_AD_ENABLE | \
32
TPS6507X_ADCONFIG_START_CONVERSION | \
33
TPS6507X_ADCONFIG_INPUT_REAL_TSC)
34
#define TPS6507X_ADCONFIG_POWER_DOWN_TS (TPS6507X_ADCONFIG_INPUT_REAL_TSC)
35
36
struct ts_event {
37
u16 x;
38
u16 y;
39
u16 pressure;
40
};
41
42
struct tps6507x_ts {
43
struct input_dev *input_dev;
44
struct device *dev;
45
char phys[32];
46
struct delayed_work work;
47
unsigned polling; /* polling is active */
48
struct ts_event tc;
49
struct tps6507x_dev *mfd;
50
u16 model;
51
unsigned pendown;
52
int irq;
53
void (*clear_penirq)(void);
54
unsigned long poll_period; /* ms */
55
u16 min_pressure;
56
int vref; /* non-zero to leave vref on */
57
};
58
59
static int tps6507x_read_u8(struct tps6507x_ts *tsc, u8 reg, u8 *data)
60
{
61
int err;
62
63
err = tsc->mfd->read_dev(tsc->mfd, reg, 1, data);
64
65
if (err)
66
return err;
67
68
return 0;
69
}
70
71
static int tps6507x_write_u8(struct tps6507x_ts *tsc, u8 reg, u8 data)
72
{
73
return tsc->mfd->write_dev(tsc->mfd, reg, 1, &data);
74
}
75
76
static s32 tps6507x_adc_conversion(struct tps6507x_ts *tsc,
77
u8 tsc_mode, u16 *value)
78
{
79
s32 ret;
80
u8 adc_status;
81
u8 result;
82
83
/* Route input signal to A/D converter */
84
85
ret = tps6507x_write_u8(tsc, TPS6507X_REG_TSCMODE, tsc_mode);
86
if (ret) {
87
dev_err(tsc->dev, "TSC mode read failed\n");
88
goto err;
89
}
90
91
/* Start A/D conversion */
92
93
ret = tps6507x_write_u8(tsc, TPS6507X_REG_ADCONFIG,
94
TPS6507X_ADCONFIG_CONVERT_TS);
95
if (ret) {
96
dev_err(tsc->dev, "ADC config write failed\n");
97
return ret;
98
}
99
100
do {
101
ret = tps6507x_read_u8(tsc, TPS6507X_REG_ADCONFIG,
102
&adc_status);
103
if (ret) {
104
dev_err(tsc->dev, "ADC config read failed\n");
105
goto err;
106
}
107
} while (adc_status & TPS6507X_ADCONFIG_START_CONVERSION);
108
109
ret = tps6507x_read_u8(tsc, TPS6507X_REG_ADRESULT_2, &result);
110
if (ret) {
111
dev_err(tsc->dev, "ADC result 2 read failed\n");
112
goto err;
113
}
114
115
*value = (result & TPS6507X_REG_ADRESULT_2_MASK) << 8;
116
117
ret = tps6507x_read_u8(tsc, TPS6507X_REG_ADRESULT_1, &result);
118
if (ret) {
119
dev_err(tsc->dev, "ADC result 1 read failed\n");
120
goto err;
121
}
122
123
*value |= result;
124
125
dev_dbg(tsc->dev, "TSC channel %d = 0x%X\n", tsc_mode, *value);
126
127
err:
128
return ret;
129
}
130
131
/* Need to call tps6507x_adc_standby() after using A/D converter for the
132
* touch screen interrupt to work properly.
133
*/
134
135
static s32 tps6507x_adc_standby(struct tps6507x_ts *tsc)
136
{
137
s32 ret;
138
s32 loops = 0;
139
u8 val;
140
141
ret = tps6507x_write_u8(tsc, TPS6507X_REG_ADCONFIG,
142
TPS6507X_ADCONFIG_INPUT_TSC);
143
if (ret)
144
return ret;
145
146
ret = tps6507x_write_u8(tsc, TPS6507X_REG_TSCMODE,
147
TPS6507X_TSCMODE_STANDBY);
148
if (ret)
149
return ret;
150
151
ret = tps6507x_read_u8(tsc, TPS6507X_REG_INT, &val);
152
if (ret)
153
return ret;
154
155
while (val & TPS6507X_REG_TSC_INT) {
156
mdelay(10);
157
ret = tps6507x_read_u8(tsc, TPS6507X_REG_INT, &val);
158
if (ret)
159
return ret;
160
loops++;
161
}
162
163
return ret;
164
}
165
166
static void tps6507x_ts_handler(struct work_struct *work)
167
{
168
struct tps6507x_ts *tsc = container_of(work,
169
struct tps6507x_ts, work.work);
170
struct input_dev *input_dev = tsc->input_dev;
171
int pendown;
172
int schd;
173
int poll = 0;
174
s32 ret;
175
176
ret = tps6507x_adc_conversion(tsc, TPS6507X_TSCMODE_PRESSURE,
177
&tsc->tc.pressure);
178
if (ret)
179
goto done;
180
181
pendown = tsc->tc.pressure > tsc->min_pressure;
182
183
if (unlikely(!pendown && tsc->pendown)) {
184
dev_dbg(tsc->dev, "UP\n");
185
input_report_key(input_dev, BTN_TOUCH, 0);
186
input_report_abs(input_dev, ABS_PRESSURE, 0);
187
input_sync(input_dev);
188
tsc->pendown = 0;
189
}
190
191
if (pendown) {
192
193
if (!tsc->pendown) {
194
dev_dbg(tsc->dev, "DOWN\n");
195
input_report_key(input_dev, BTN_TOUCH, 1);
196
} else
197
dev_dbg(tsc->dev, "still down\n");
198
199
ret = tps6507x_adc_conversion(tsc, TPS6507X_TSCMODE_X_POSITION,
200
&tsc->tc.x);
201
if (ret)
202
goto done;
203
204
ret = tps6507x_adc_conversion(tsc, TPS6507X_TSCMODE_Y_POSITION,
205
&tsc->tc.y);
206
if (ret)
207
goto done;
208
209
input_report_abs(input_dev, ABS_X, tsc->tc.x);
210
input_report_abs(input_dev, ABS_Y, tsc->tc.y);
211
input_report_abs(input_dev, ABS_PRESSURE, tsc->tc.pressure);
212
input_sync(input_dev);
213
tsc->pendown = 1;
214
poll = 1;
215
}
216
217
done:
218
/* always poll if not using interrupts */
219
poll = 1;
220
221
if (poll) {
222
schd = schedule_delayed_work(&tsc->work,
223
msecs_to_jiffies(tsc->poll_period));
224
if (schd)
225
tsc->polling = 1;
226
else {
227
tsc->polling = 0;
228
dev_err(tsc->dev, "re-schedule failed");
229
}
230
} else
231
tsc->polling = 0;
232
233
ret = tps6507x_adc_standby(tsc);
234
}
235
236
static int tps6507x_ts_probe(struct platform_device *pdev)
237
{
238
int error;
239
struct tps6507x_ts *tsc;
240
struct tps6507x_dev *tps6507x_dev = dev_get_drvdata(pdev->dev.parent);
241
struct touchscreen_init_data *init_data;
242
struct input_dev *input_dev;
243
struct tps6507x_board *tps_board;
244
int schd;
245
246
/**
247
* tps_board points to pmic related constants
248
* coming from the board-evm file.
249
*/
250
251
tps_board = (struct tps6507x_board *)tps6507x_dev->dev->platform_data;
252
253
if (!tps_board) {
254
dev_err(tps6507x_dev->dev,
255
"Could not find tps6507x platform data\n");
256
return -EIO;
257
}
258
259
/**
260
* init_data points to array of regulator_init structures
261
* coming from the board-evm file.
262
*/
263
264
init_data = tps_board->tps6507x_ts_init_data;
265
266
tsc = kzalloc(sizeof(struct tps6507x_ts), GFP_KERNEL);
267
if (!tsc) {
268
dev_err(tps6507x_dev->dev, "failed to allocate driver data\n");
269
error = -ENOMEM;
270
goto err0;
271
}
272
273
tps6507x_dev->ts = tsc;
274
tsc->mfd = tps6507x_dev;
275
tsc->dev = tps6507x_dev->dev;
276
input_dev = input_allocate_device();
277
if (!input_dev) {
278
dev_err(tsc->dev, "Failed to allocate input device.\n");
279
error = -ENOMEM;
280
goto err1;
281
}
282
283
input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
284
input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
285
286
input_set_abs_params(input_dev, ABS_X, 0, MAX_10BIT, 0, 0);
287
input_set_abs_params(input_dev, ABS_Y, 0, MAX_10BIT, 0, 0);
288
input_set_abs_params(input_dev, ABS_PRESSURE, 0, MAX_10BIT, 0, 0);
289
290
input_dev->name = "TPS6507x Touchscreen";
291
input_dev->id.bustype = BUS_I2C;
292
input_dev->dev.parent = tsc->dev;
293
294
snprintf(tsc->phys, sizeof(tsc->phys),
295
"%s/input0", dev_name(tsc->dev));
296
input_dev->phys = tsc->phys;
297
298
dev_dbg(tsc->dev, "device: %s\n", input_dev->phys);
299
300
input_set_drvdata(input_dev, tsc);
301
302
tsc->input_dev = input_dev;
303
304
INIT_DELAYED_WORK(&tsc->work, tps6507x_ts_handler);
305
306
if (init_data) {
307
tsc->poll_period = init_data->poll_period;
308
tsc->vref = init_data->vref;
309
tsc->min_pressure = init_data->min_pressure;
310
input_dev->id.vendor = init_data->vendor;
311
input_dev->id.product = init_data->product;
312
input_dev->id.version = init_data->version;
313
} else {
314
tsc->poll_period = TSC_DEFAULT_POLL_PERIOD;
315
tsc->min_pressure = TPS_DEFAULT_MIN_PRESSURE;
316
}
317
318
error = tps6507x_adc_standby(tsc);
319
if (error)
320
goto err2;
321
322
error = input_register_device(input_dev);
323
if (error)
324
goto err2;
325
326
schd = schedule_delayed_work(&tsc->work,
327
msecs_to_jiffies(tsc->poll_period));
328
329
if (schd)
330
tsc->polling = 1;
331
else {
332
tsc->polling = 0;
333
dev_err(tsc->dev, "schedule failed");
334
goto err2;
335
}
336
platform_set_drvdata(pdev, tps6507x_dev);
337
338
return 0;
339
340
err2:
341
cancel_delayed_work_sync(&tsc->work);
342
input_free_device(input_dev);
343
err1:
344
kfree(tsc);
345
tps6507x_dev->ts = NULL;
346
err0:
347
return error;
348
}
349
350
static int __devexit tps6507x_ts_remove(struct platform_device *pdev)
351
{
352
struct tps6507x_dev *tps6507x_dev = platform_get_drvdata(pdev);
353
struct tps6507x_ts *tsc = tps6507x_dev->ts;
354
struct input_dev *input_dev = tsc->input_dev;
355
356
cancel_delayed_work_sync(&tsc->work);
357
358
input_unregister_device(input_dev);
359
360
tps6507x_dev->ts = NULL;
361
kfree(tsc);
362
363
return 0;
364
}
365
366
static struct platform_driver tps6507x_ts_driver = {
367
.driver = {
368
.name = "tps6507x-ts",
369
.owner = THIS_MODULE,
370
},
371
.probe = tps6507x_ts_probe,
372
.remove = __devexit_p(tps6507x_ts_remove),
373
};
374
375
static int __init tps6507x_ts_init(void)
376
{
377
return platform_driver_register(&tps6507x_ts_driver);
378
}
379
module_init(tps6507x_ts_init);
380
381
static void __exit tps6507x_ts_exit(void)
382
{
383
platform_driver_unregister(&tps6507x_ts_driver);
384
}
385
module_exit(tps6507x_ts_exit);
386
387
MODULE_AUTHOR("Todd Fischer <[email protected]>");
388
MODULE_DESCRIPTION("TPS6507x - TouchScreen driver");
389
MODULE_LICENSE("GPL v2");
390
MODULE_ALIAS("platform:tps6507x-tsc");
391
392