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,126 @@ 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
- {
78
+
79
+ while (!kthread_should_stop ()) {
69
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 ));
83
+ iowrite8 (99 ,
84
+ ts -> ts_base +
85
+ offsetof(struct ft5406_regs , num_points ));
86
+
73
87
// Do not output if theres no new information (num_points is 99)
74
88
// 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
- {
89
+ if (!(regs .num_points == 99 ||
90
+ ( regs . num_points == 0 && known_ids == 0 ))) {
77
91
int i ;
78
92
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
93
94
+ for (i = 0 ; i < regs .num_points ; i ++ ) {
95
+ int x = (((int ) regs .point [i ].xh & 0xf ) << 8 ) +
96
+ regs .point [i ].xl ;
97
+ int y = (((int ) regs .point [i ].yh & 0xf ) << 8 ) +
98
+ regs .point [i ].yl ;
99
+ int touchid = (regs .point [i ].yh >> 4 ) & 0xf ;
100
+ int event_type = (regs .point [i ].xh >> 6 ) & 0x03 ;
101
+
102
+ modified_ids |= ID_TO_BIT (touchid );
103
+
104
+ if (event_type == FTS_TOUCH_DOWN ||
105
+ event_type == FTS_TOUCH_CONTACT ) {
106
+ if (ts -> hflip )
107
+ x = ts -> max_x - 1 - x ;
108
+
109
+ if (ts -> vflip )
110
+ y = ts -> max_y - 1 - y ;
111
+
112
+ if (ts -> xyswap )
113
+ swap (x , y );
114
+
115
+ if (!((ID_TO_BIT (touchid )) & known_ids ))
116
+ dev_dbg (& ts -> pdev -> dev ,
117
+ "x = %d, y = %d, "
118
+ "press = %d, "
119
+ "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, "
144
+ "modified = %x\n" ,
145
+ i , known_ids , modified_ids );
104
146
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 );
147
+ input_mt_report_slot_state (
148
+ ts -> input_dev ,
149
+ MT_TOOL_FINGER ,
150
+ 0 );
151
+ modified_ids &= ~(ID_TO_BIT (i ));
107
152
}
108
153
}
109
154
known_ids = modified_ids ;
110
-
155
+
111
156
input_mt_report_pointer_emulation (ts -> input_dev , true);
112
157
input_sync (ts -> input_dev );
113
158
}
114
-
115
159
}
116
-
160
+
117
161
return 0 ;
118
162
}
119
163
@@ -122,22 +166,25 @@ static int ft5406_probe(struct platform_device *pdev)
122
166
int err = 0 ;
123
167
struct device * dev = & pdev -> dev ;
124
168
struct device_node * np = dev -> of_node ;
125
- struct ft5406 * ts ;
169
+ struct ft5406 * ts ;
126
170
struct device_node * fw_node ;
127
171
struct rpi_firmware * fw ;
128
172
u32 touchbuf ;
129
-
173
+ u32 val ;
174
+
130
175
dev_info (dev , "Probing device\n" );
131
-
176
+
132
177
fw_node = of_parse_phandle (np , "firmware" , 0 );
133
178
if (!fw_node ) {
134
179
dev_err (dev , "Missing firmware node\n" );
135
180
return - ENOENT ;
136
181
}
137
182
138
183
fw = rpi_firmware_get (fw_node );
139
- if (!fw )
184
+ if (!fw ) {
185
+ dev_err (dev , "No firmware node - deferring\n" );
140
186
return - EPROBE_DEFER ;
187
+ }
141
188
142
189
ts = devm_kzalloc (dev , sizeof (struct ft5406 ), GFP_KERNEL );
143
190
if (!ts ) {
@@ -151,7 +198,8 @@ static int ft5406_probe(struct platform_device *pdev)
151
198
return - ENOMEM ;
152
199
}
153
200
154
- ts -> ts_base = dma_zalloc_coherent (dev , PAGE_SIZE , & ts -> bus_addr , GFP_KERNEL );
201
+ ts -> ts_base = dma_zalloc_coherent (dev , PAGE_SIZE , & ts -> bus_addr ,
202
+ GFP_KERNEL );
155
203
if (!ts -> ts_base ) {
156
204
pr_err ("[%s]: failed to dma_alloc_coherent(%ld)\n" ,
157
205
__func__ , PAGE_SIZE );
@@ -164,17 +212,23 @@ static int ft5406_probe(struct platform_device *pdev)
164
212
& touchbuf , sizeof (touchbuf ));
165
213
166
214
if (err || touchbuf != 0 ) {
167
- dev_warn (dev , "Failed to set touchbuf, trying to get err:%x\n" , err );
215
+ dev_warn (dev , "Failed to set touchbuf, trying to get err:%x\n" ,
216
+ err );
168
217
dma_free_coherent (dev , PAGE_SIZE , ts -> ts_base , ts -> bus_addr );
169
218
ts -> ts_base = 0 ;
170
219
ts -> bus_addr = 0 ;
171
220
}
172
221
173
222
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 ));
223
+ dev_warn (dev ,
224
+ "set failed, trying get"
225
+ " (err:%d touchbuf:%x virt:%p bus:%x)\n" ,
226
+ err , touchbuf , ts -> ts_base , ts -> bus_addr );
227
+
228
+ err = rpi_firmware_property (
229
+ fw ,
230
+ RPI_FIRMWARE_FRAMEBUFFER_GET_TOUCHBUF ,
231
+ & touchbuf , sizeof (touchbuf ));
178
232
if (err ) {
179
233
dev_err (dev , "Failed to get touch buffer\n" );
180
234
goto out ;
@@ -191,31 +245,54 @@ static int ft5406_probe(struct platform_device *pdev)
191
245
// mmap the physical memory
192
246
touchbuf &= ~0xc0000000 ;
193
247
ts -> ts_base = ioremap (touchbuf , sizeof (struct ft5406_regs ));
194
- if (ts -> ts_base == NULL )
195
- {
248
+ if (ts -> ts_base == NULL ) {
196
249
dev_err (dev , "Failed to map physical address\n" );
197
250
err = - ENOMEM ;
198
251
goto out ;
199
252
}
200
253
}
201
254
platform_set_drvdata (pdev , ts );
202
255
ts -> pdev = pdev ;
203
-
256
+
204
257
ts -> input_dev -> name = "FT5406 memory based driver" ;
205
-
258
+
259
+ if (of_property_read_u32 (np , "touchscreen-size-x" , & val ) >= 0 )
260
+ ts -> max_x = val ;
261
+ else
262
+ ts -> max_x = DEFAULT_SCREEN_WIDTH ;
263
+
264
+ if (of_property_read_u32 (np , "touchscreen-size-y" , & val ) >= 0 )
265
+ ts -> max_y = val ;
266
+ else
267
+ ts -> max_y = DEFAULT_SCREEN_HEIGHT ;
268
+
269
+ if (of_property_read_u32 (np , "touchscreen-inverted-x" , & val ) >= 0 )
270
+ ts -> hflip = val ;
271
+
272
+ if (of_property_read_u32 (np , "touchscreen-inverted-y" , & val ) >= 0 )
273
+ ts -> vflip = val ;
274
+
275
+ if (of_property_read_u32 (np , "touchscreen-swapped-x-y" , & val ) >= 0 )
276
+ ts -> xyswap = val ;
277
+
278
+ dev_dbg (dev ,
279
+ "Touchscreen parameters (%d,%d), hflip=%d, vflip=%d, xyswap=%d" ,
280
+ ts -> max_x , ts -> max_y , ts -> hflip , ts -> vflip , ts -> xyswap );
281
+
206
282
__set_bit (EV_KEY , ts -> input_dev -> evbit );
207
283
__set_bit (EV_SYN , ts -> input_dev -> evbit );
208
284
__set_bit (EV_ABS , ts -> input_dev -> evbit );
209
285
210
286
input_set_abs_params (ts -> input_dev , ABS_MT_POSITION_X , 0 ,
211
- SCREEN_WIDTH , 0 , 0 );
287
+ ts -> xyswap ? ts -> max_y : ts -> max_x , 0 , 0 );
212
288
input_set_abs_params (ts -> input_dev , ABS_MT_POSITION_Y , 0 ,
213
- SCREEN_HEIGHT , 0 , 0 );
289
+ ts -> xyswap ? ts -> max_x : ts -> max_y , 0 , 0 );
214
290
215
- input_mt_init_slots (ts -> input_dev , MAXIMUM_SUPPORTED_POINTS , INPUT_MT_DIRECT );
291
+ input_mt_init_slots (ts -> input_dev ,
292
+ MAXIMUM_SUPPORTED_POINTS , INPUT_MT_DIRECT );
216
293
217
294
input_set_drvdata (ts -> input_dev , ts );
218
-
295
+
219
296
err = input_register_device (ts -> input_dev );
220
297
if (err ) {
221
298
dev_err (dev , "could not register input device, %d\n" ,
@@ -225,8 +302,7 @@ static int ft5406_probe(struct platform_device *pdev)
225
302
226
303
// create thread to poll the touch events
227
304
ts -> thread = kthread_run (ft5406_thread , ts , "ft5406" );
228
- if (ts -> thread == NULL )
229
- {
305
+ if (ts -> thread == NULL ) {
230
306
dev_err (dev , "Failed to create kernel thread" );
231
307
err = - ENOMEM ;
232
308
goto out ;
@@ -254,9 +330,9 @@ static int ft5406_remove(struct platform_device *pdev)
254
330
{
255
331
struct device * dev = & pdev -> dev ;
256
332
struct ft5406 * ts = (struct ft5406 * ) platform_get_drvdata (pdev );
257
-
333
+
258
334
dev_info (dev , "Removing rpi-ft5406\n" );
259
-
335
+
260
336
kthread_stop (ts -> thread );
261
337
262
338
if (ts -> bus_addr )
@@ -265,7 +341,7 @@ static int ft5406_remove(struct platform_device *pdev)
265
341
iounmap (ts -> ts_base );
266
342
if (ts -> input_dev )
267
343
input_unregister_device (ts -> input_dev );
268
-
344
+
269
345
return 0 ;
270
346
}
271
347
0 commit comments