1
1
/*
2
2
* Driver for memory based ft5406 touchscreen
3
3
*
4
- * Copyright (C) 2015 Raspberry Pi
4
+ * Copyright (C) 2015, 2017 Raspberry Pi
5
5
*
6
6
*
7
7
* This program is free software; you can redistribute it and/or modify
8
8
* it under the terms of the GNU General Public License version 2 as
9
9
* published by the Free Software Foundation.
10
10
*/
11
11
12
-
13
12
#include <linux/module.h>
14
13
#include <linux/interrupt.h>
15
14
#include <linux/input.h>
21
20
#include <linux/kthread.h>
22
21
#include <linux/platform_device.h>
23
22
#include <linux/stddef.h>
24
- #include <asm /io.h>
23
+ #include <linux /io.h>
25
24
#include <linux/dma-mapping.h>
26
25
#include <soc/bcm2835/raspberrypi-firmware.h>
27
26
28
27
#define MAXIMUM_SUPPORTED_POINTS 10
28
+ #define FTS_TOUCH_DOWN 0
29
+ #define FTS_TOUCH_UP 1
30
+ #define FTS_TOUCH_CONTACT 2
31
+
29
32
struct ft5406_regs {
30
33
uint8_t device_mode ;
31
34
uint8_t gesture_id ;
@@ -35,85 +38,125 @@ struct ft5406_regs {
35
38
uint8_t xl ;
36
39
uint8_t yh ;
37
40
uint8_t yl ;
38
- uint8_t res1 ;
39
- uint8_t res2 ;
41
+ uint8_t pressure ; /* Not supported */
42
+ uint8_t area ; /* Not supported */
40
43
} point [MAXIMUM_SUPPORTED_POINTS ];
41
44
};
42
45
43
- #define SCREEN_WIDTH 800
44
- #define SCREEN_HEIGHT 480
46
+ /* These are defaults if the DT entries are missing */
47
+ #define DEFAULT_SCREEN_WIDTH 800
48
+ #define DEFAULT_SCREEN_HEIGHT 480
45
49
46
50
struct ft5406 {
47
- struct platform_device * pdev ;
48
- struct input_dev * input_dev ;
49
- void __iomem * ts_base ;
50
- dma_addr_t bus_addr ;
51
- struct task_struct * thread ;
51
+ struct platform_device * pdev ;
52
+ struct input_dev * input_dev ;
53
+ void __iomem * ts_base ;
54
+ dma_addr_t bus_addr ;
55
+ struct task_struct * thread ;
56
+
57
+ uint16_t max_x ;
58
+ uint16_t max_y ;
59
+ uint8_t hflip ;
60
+ uint8_t vflip ;
61
+ uint8_t xyswap ;
52
62
};
53
63
54
64
/* Thread to poll for touchscreen events
55
- *
65
+ *
56
66
* This thread polls the memory based register copy of the ft5406 registers
57
67
* using the number of points register to know whether the copy has been
58
- * updated (we write 99 to the memory copy, the GPU will write between
68
+ * updated (we write 99 to the memory copy, the GPU will write between
59
69
* 0 - 10 points)
60
70
*/
71
+ #define ID_TO_BIT (a ) (1 << a)
72
+
61
73
static int ft5406_thread (void * arg )
62
74
{
63
75
struct ft5406 * ts = (struct ft5406 * ) arg ;
64
76
struct ft5406_regs regs ;
65
77
int known_ids = 0 ;
66
-
67
- while (!kthread_should_stop ())
68
- {
69
- // 60fps polling
78
+
79
+ while (!kthread_should_stop ()) {
80
+ /* 60fps polling */
70
81
msleep_interruptible (17 );
71
82
memcpy_fromio (& regs , ts -> ts_base , sizeof (struct ft5406_regs ));
72
- iowrite8 (99 , ts -> ts_base + offsetof(struct ft5406_regs , num_points ));
73
- // Do not output if theres no new information (num_points is 99)
74
- // or we have no touch points and don't need to release any
75
- if (!(regs .num_points == 99 || (regs .num_points == 0 && known_ids == 0 )))
76
- {
83
+ iowrite8 (99 ,
84
+ ts -> ts_base +
85
+ offsetof(struct ft5406_regs , num_points ));
86
+
87
+ /*
88
+ * Do not output if theres no new information (num_points is 99)
89
+ * or we have no touch points and don't need to release any
90
+ */
91
+ if (!(regs .num_points == 99 ||
92
+ (regs .num_points == 0 && known_ids == 0 ))) {
77
93
int i ;
78
94
int modified_ids = 0 , released_ids ;
79
- for (i = 0 ; i < regs .num_points ; i ++ )
80
- {
81
- int x = (((int ) regs .point [i ].xh & 0xf ) << 8 ) + regs .point [i ].xl ;
82
- int y = (((int ) regs .point [i ].yh & 0xf ) << 8 ) + regs .point [i ].yl ;
83
- int touchid = (regs .point [i ].yh >> 4 ) & 0xf ;
84
-
85
- modified_ids |= 1 << touchid ;
86
-
87
- if (!((1 << touchid ) & known_ids ))
88
- dev_dbg (& ts -> pdev -> dev , "x = %d, y = %d, touchid = %d\n" , x , y , touchid );
89
-
90
- input_mt_slot (ts -> input_dev , touchid );
91
- input_mt_report_slot_state (ts -> input_dev , MT_TOOL_FINGER , 1 );
92
-
93
- input_report_abs (ts -> input_dev , ABS_MT_POSITION_X , x );
94
- input_report_abs (ts -> input_dev , ABS_MT_POSITION_Y , y );
95
95
96
+ for (i = 0 ; i < regs .num_points ; i ++ ) {
97
+ int x = (((int ) regs .point [i ].xh & 0xf ) << 8 ) +
98
+ regs .point [i ].xl ;
99
+ int y = (((int ) regs .point [i ].yh & 0xf ) << 8 ) +
100
+ regs .point [i ].yl ;
101
+ int touchid = (regs .point [i ].yh >> 4 ) & 0xf ;
102
+ int event_type = (regs .point [i ].xh >> 6 ) & 0x03 ;
103
+
104
+ modified_ids |= ID_TO_BIT (touchid );
105
+
106
+ if (event_type == FTS_TOUCH_DOWN ||
107
+ event_type == FTS_TOUCH_CONTACT ) {
108
+ if (ts -> hflip )
109
+ x = ts -> max_x - 1 - x ;
110
+
111
+ if (ts -> vflip )
112
+ y = ts -> max_y - 1 - y ;
113
+
114
+ if (ts -> xyswap )
115
+ swap (x , y );
116
+
117
+ if (!((ID_TO_BIT (touchid )) & known_ids ))
118
+ dev_dbg (& ts -> pdev -> dev ,
119
+ "x = %d, y = %d, press = %d, touchid = %d\n" ,
120
+ x , y ,
121
+ regs .point [i ].pressure ,
122
+ touchid );
123
+
124
+ input_mt_slot (ts -> input_dev , touchid );
125
+ input_mt_report_slot_state (
126
+ ts -> input_dev ,
127
+ MT_TOOL_FINGER ,
128
+ 1 );
129
+
130
+ input_report_abs (ts -> input_dev ,
131
+ ABS_MT_POSITION_X , x );
132
+ input_report_abs (ts -> input_dev ,
133
+ ABS_MT_POSITION_Y , y );
134
+ }
96
135
}
97
136
98
137
released_ids = known_ids & ~modified_ids ;
99
- for (i = 0 ; released_ids && i < MAXIMUM_SUPPORTED_POINTS ; i ++ )
100
- {
101
- if (released_ids & (1 <<i ))
102
- {
103
- dev_dbg (& ts -> pdev -> dev , "Released %d, known = %x modified = %x\n" , i , known_ids , modified_ids );
138
+ for (i = 0 ;
139
+ released_ids && i < MAXIMUM_SUPPORTED_POINTS ;
140
+ i ++ ) {
141
+ if (released_ids & (1 <<i )) {
142
+ dev_dbg (& ts -> pdev -> dev ,
143
+ "Released %d, known = %x, modified = %x\n" ,
144
+ i , known_ids , modified_ids );
104
145
input_mt_slot (ts -> input_dev , i );
105
- input_mt_report_slot_state (ts -> input_dev , MT_TOOL_FINGER , 0 );
106
- modified_ids &= ~(1 << i );
146
+ input_mt_report_slot_state (
147
+ ts -> input_dev ,
148
+ MT_TOOL_FINGER ,
149
+ 0 );
150
+ modified_ids &= ~(ID_TO_BIT (i ));
107
151
}
108
152
}
109
153
known_ids = modified_ids ;
110
-
154
+
111
155
input_mt_report_pointer_emulation (ts -> input_dev , true);
112
156
input_sync (ts -> input_dev );
113
157
}
114
-
115
158
}
116
-
159
+
117
160
return 0 ;
118
161
}
119
162
@@ -122,13 +165,14 @@ static int ft5406_probe(struct platform_device *pdev)
122
165
int err = 0 ;
123
166
struct device * dev = & pdev -> dev ;
124
167
struct device_node * np = dev -> of_node ;
125
- struct ft5406 * ts ;
168
+ struct ft5406 * ts ;
126
169
struct device_node * fw_node ;
127
170
struct rpi_firmware * fw ;
128
171
u32 touchbuf ;
129
-
172
+ u32 val ;
173
+
130
174
dev_info (dev , "Probing device\n" );
131
-
175
+
132
176
fw_node = of_parse_phandle (np , "firmware" , 0 );
133
177
if (!fw_node ) {
134
178
dev_err (dev , "Missing firmware node\n" );
@@ -151,7 +195,8 @@ static int ft5406_probe(struct platform_device *pdev)
151
195
return - ENOMEM ;
152
196
}
153
197
154
- ts -> ts_base = dma_zalloc_coherent (dev , PAGE_SIZE , & ts -> bus_addr , GFP_KERNEL );
198
+ ts -> ts_base = dma_zalloc_coherent (dev , PAGE_SIZE , & ts -> bus_addr ,
199
+ GFP_KERNEL );
155
200
if (!ts -> ts_base ) {
156
201
pr_err ("[%s]: failed to dma_alloc_coherent(%ld)\n" ,
157
202
__func__ , PAGE_SIZE );
@@ -164,17 +209,22 @@ static int ft5406_probe(struct platform_device *pdev)
164
209
& touchbuf , sizeof (touchbuf ));
165
210
166
211
if (err || touchbuf != 0 ) {
167
- dev_warn (dev , "Failed to set touchbuf, trying to get err:%x\n" , err );
212
+ dev_warn (dev , "Failed to set touchbuf, trying to get err:%x\n" ,
213
+ err );
168
214
dma_free_coherent (dev , PAGE_SIZE , ts -> ts_base , ts -> bus_addr );
169
215
ts -> ts_base = 0 ;
170
216
ts -> bus_addr = 0 ;
171
217
}
172
218
173
219
if (!ts -> ts_base ) {
174
- dev_warn (dev , "set failed, trying get (err:%d touchbuf:%x virt:%p bus:%x)\n" , err , touchbuf , ts -> ts_base , ts -> bus_addr );
175
-
176
- err = rpi_firmware_property (fw , RPI_FIRMWARE_FRAMEBUFFER_GET_TOUCHBUF ,
177
- & touchbuf , sizeof (touchbuf ));
220
+ dev_warn (dev ,
221
+ "set failed, trying get (err:%d touchbuf:%x virt:%p bus:%x)\n" ,
222
+ err , touchbuf , ts -> ts_base , ts -> bus_addr );
223
+
224
+ err = rpi_firmware_property (
225
+ fw ,
226
+ RPI_FIRMWARE_FRAMEBUFFER_GET_TOUCHBUF ,
227
+ & touchbuf , sizeof (touchbuf ));
178
228
if (err ) {
179
229
dev_err (dev , "Failed to get touch buffer\n" );
180
230
goto out ;
@@ -188,45 +238,67 @@ static int ft5406_probe(struct platform_device *pdev)
188
238
189
239
dev_dbg (dev , "Got TS buffer 0x%x\n" , touchbuf );
190
240
191
- // mmap the physical memory
241
+ /* mmap the physical memory */
192
242
touchbuf &= ~0xc0000000 ;
193
243
ts -> ts_base = ioremap (touchbuf , sizeof (struct ft5406_regs ));
194
- if (ts -> ts_base == NULL )
195
- {
244
+ if (ts -> ts_base == NULL ) {
196
245
dev_err (dev , "Failed to map physical address\n" );
197
246
err = - ENOMEM ;
198
247
goto out ;
199
248
}
200
249
}
201
250
platform_set_drvdata (pdev , ts );
202
251
ts -> pdev = pdev ;
203
-
252
+
204
253
ts -> input_dev -> name = "FT5406 memory based driver" ;
205
-
254
+
255
+ if (of_property_read_u32 (np , "touchscreen-size-x" , & val ) >= 0 )
256
+ ts -> max_x = val ;
257
+ else
258
+ ts -> max_x = DEFAULT_SCREEN_WIDTH ;
259
+
260
+ if (of_property_read_u32 (np , "touchscreen-size-y" , & val ) >= 0 )
261
+ ts -> max_y = val ;
262
+ else
263
+ ts -> max_y = DEFAULT_SCREEN_HEIGHT ;
264
+
265
+ if (of_property_read_u32 (np , "touchscreen-inverted-x" , & val ) >= 0 )
266
+ ts -> hflip = val ;
267
+
268
+ if (of_property_read_u32 (np , "touchscreen-inverted-y" , & val ) >= 0 )
269
+ ts -> vflip = val ;
270
+
271
+ if (of_property_read_u32 (np , "touchscreen-swapped-x-y" , & val ) >= 0 )
272
+ ts -> xyswap = val ;
273
+
274
+ dev_dbg (dev ,
275
+ "Touchscreen parameters (%d,%d), hflip=%d, vflip=%d, xyswap=%d" ,
276
+ ts -> max_x , ts -> max_y , ts -> hflip , ts -> vflip , ts -> xyswap );
277
+
206
278
__set_bit (EV_KEY , ts -> input_dev -> evbit );
207
279
__set_bit (EV_SYN , ts -> input_dev -> evbit );
208
280
__set_bit (EV_ABS , ts -> input_dev -> evbit );
209
281
210
282
input_set_abs_params (ts -> input_dev , ABS_MT_POSITION_X , 0 ,
211
- SCREEN_WIDTH , 0 , 0 );
283
+ ts -> xyswap ? ts -> max_y : ts -> max_x , 0 , 0 );
212
284
input_set_abs_params (ts -> input_dev , ABS_MT_POSITION_Y , 0 ,
213
- SCREEN_HEIGHT , 0 , 0 );
285
+ ts -> xyswap ? ts -> max_x : ts -> max_y , 0 , 0 );
214
286
215
- input_mt_init_slots (ts -> input_dev , MAXIMUM_SUPPORTED_POINTS , INPUT_MT_DIRECT );
287
+ input_mt_init_slots (ts -> input_dev ,
288
+ MAXIMUM_SUPPORTED_POINTS , INPUT_MT_DIRECT );
216
289
217
290
input_set_drvdata (ts -> input_dev , ts );
218
-
291
+
219
292
err = input_register_device (ts -> input_dev );
220
293
if (err ) {
221
294
dev_err (dev , "could not register input device, %d\n" ,
222
295
err );
223
296
goto out ;
224
297
}
225
298
226
- // create thread to poll the touch events
299
+ /* create thread that polls the touch events */
227
300
ts -> thread = kthread_run (ft5406_thread , ts , "ft5406" );
228
- if (ts -> thread == NULL )
229
- {
301
+ if (ts -> thread == NULL ) {
230
302
dev_err (dev , "Failed to create kernel thread" );
231
303
err = - ENOMEM ;
232
304
goto out ;
@@ -254,9 +326,9 @@ static int ft5406_remove(struct platform_device *pdev)
254
326
{
255
327
struct device * dev = & pdev -> dev ;
256
328
struct ft5406 * ts = (struct ft5406 * ) platform_get_drvdata (pdev );
257
-
329
+
258
330
dev_info (dev , "Removing rpi-ft5406\n" );
259
-
331
+
260
332
kthread_stop (ts -> thread );
261
333
262
334
if (ts -> bus_addr )
@@ -265,7 +337,7 @@ static int ft5406_remove(struct platform_device *pdev)
265
337
iounmap (ts -> ts_base );
266
338
if (ts -> input_dev )
267
339
input_unregister_device (ts -> input_dev );
268
-
340
+
269
341
return 0 ;
270
342
}
271
343
0 commit comments