Skip to content

Commit 6e35c26

Browse files
JamesH65Phil Elwell
authored and
Phil Elwell
committed
Tidy up of the ft5406 driver to use DT (#2189)
Driver was using a fixed resolution, this commit adds touchscreen size, and coordinate flip and swap features via device tree overlays. Adds overrides so the VC4 can adjust the DT parameters appropriately; there is a newer version of the VC4 side driver that can now set up the appropriate DT values if required. Signed-off-by: James Hughes <[email protected]>
1 parent 28417d5 commit 6e35c26

File tree

3 files changed

+164
-75
lines changed

3 files changed

+164
-75
lines changed

arch/arm/boot/dts/overlays/README

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1299,8 +1299,12 @@ Params: speed Display SPI bus speed
12991299

13001300
Name: rpi-ft5406
13011301
Info: Official Raspberry Pi display touchscreen
1302-
Load: dtoverlay=rpi-ft5406
1303-
Params: <None>
1302+
Load: dtoverlay=rpi-ft5406,<param>=<val>
1303+
Params: touchscreen-size-x Touchscreen X resolution (default 800)
1304+
touchscreen-size-y Touchscreen Y resolution (default 600);
1305+
touchscreen-inverted-x Invert touchscreen X coordinates (default 0);
1306+
touchscreen-inverted-y Invert touchscreen Y coordinates (default 0);
1307+
touchscreen-swapped-x-y Swap X and Y cordinates (default 0);
13041308

13051309

13061310
Name: rpi-proto

arch/arm/boot/dts/overlays/rpi-ft5406-overlay.dts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,20 @@
1111
compatible = "rpi,rpi-ft5406";
1212
firmware = <&firmware>;
1313
status = "okay";
14+
touchscreen-size-x = <800>;
15+
touchscreen-size-y = <600>;
16+
touchscreen-inverted-x = <0>;
17+
touchscreen-inverted-y = <0>;
18+
touchscreen-swapped-x-y = <0>;
1419
};
1520
};
1621
};
22+
23+
__overrides__ {
24+
touchscreen-size-x = <&rpi_ft5406>,"touchscreen-size-x:0";
25+
touchscreen-size-y = <&rpi_ft5406>,"touchscreen-size-y:0";
26+
touchscreen-inverted-x = <&rpi_ft5406>,"touchscreen-inverted-x:0";
27+
touchscreen-inverted-y = <&rpi_ft5406>,"touchscreen-inverted-y:0";
28+
touchscreen-swapped-x-y = <&rpi_ft5406>,"touchscreen-swapped-x-y:0";
29+
};
1730
};

drivers/input/touchscreen/rpi-ft5406.c

Lines changed: 145 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,14 @@
11
/*
22
* Driver for memory based ft5406 touchscreen
33
*
4-
* Copyright (C) 2015 Raspberry Pi
4+
* Copyright (C) 2015, 2017 Raspberry Pi
55
*
66
*
77
* This program is free software; you can redistribute it and/or modify
88
* it under the terms of the GNU General Public License version 2 as
99
* published by the Free Software Foundation.
1010
*/
1111

12-
1312
#include <linux/module.h>
1413
#include <linux/interrupt.h>
1514
#include <linux/input.h>
@@ -21,11 +20,15 @@
2120
#include <linux/kthread.h>
2221
#include <linux/platform_device.h>
2322
#include <linux/stddef.h>
24-
#include <asm/io.h>
23+
#include <linux/io.h>
2524
#include <linux/dma-mapping.h>
2625
#include <soc/bcm2835/raspberrypi-firmware.h>
2726

2827
#define MAXIMUM_SUPPORTED_POINTS 10
28+
#define FTS_TOUCH_DOWN 0
29+
#define FTS_TOUCH_UP 1
30+
#define FTS_TOUCH_CONTACT 2
31+
2932
struct ft5406_regs {
3033
uint8_t device_mode;
3134
uint8_t gesture_id;
@@ -35,85 +38,125 @@ struct ft5406_regs {
3538
uint8_t xl;
3639
uint8_t yh;
3740
uint8_t yl;
38-
uint8_t res1;
39-
uint8_t res2;
41+
uint8_t pressure; /* Not supported */
42+
uint8_t area; /* Not supported */
4043
} point[MAXIMUM_SUPPORTED_POINTS];
4144
};
4245

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
4549

4650
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;
5262
};
5363

5464
/* Thread to poll for touchscreen events
55-
*
65+
*
5666
* This thread polls the memory based register copy of the ft5406 registers
5767
* 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
5969
* 0 - 10 points)
6070
*/
71+
#define ID_TO_BIT(a) (1 << a)
72+
6173
static int ft5406_thread(void *arg)
6274
{
6375
struct ft5406 *ts = (struct ft5406 *) arg;
6476
struct ft5406_regs regs;
6577
int known_ids = 0;
66-
67-
while(!kthread_should_stop())
68-
{
69-
// 60fps polling
78+
79+
while (!kthread_should_stop()) {
80+
/* 60fps polling */
7081
msleep_interruptible(17);
7182
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))) {
7793
int i;
7894
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);
9595

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+
}
96135
}
97136

98137
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);
104145
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));
107151
}
108152
}
109153
known_ids = modified_ids;
110-
154+
111155
input_mt_report_pointer_emulation(ts->input_dev, true);
112156
input_sync(ts->input_dev);
113157
}
114-
115158
}
116-
159+
117160
return 0;
118161
}
119162

@@ -122,13 +165,14 @@ static int ft5406_probe(struct platform_device *pdev)
122165
int err = 0;
123166
struct device *dev = &pdev->dev;
124167
struct device_node *np = dev->of_node;
125-
struct ft5406 * ts;
168+
struct ft5406 *ts;
126169
struct device_node *fw_node;
127170
struct rpi_firmware *fw;
128171
u32 touchbuf;
129-
172+
u32 val;
173+
130174
dev_info(dev, "Probing device\n");
131-
175+
132176
fw_node = of_parse_phandle(np, "firmware", 0);
133177
if (!fw_node) {
134178
dev_err(dev, "Missing firmware node\n");
@@ -151,7 +195,8 @@ static int ft5406_probe(struct platform_device *pdev)
151195
return -ENOMEM;
152196
}
153197

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);
155200
if (!ts->ts_base) {
156201
pr_err("[%s]: failed to dma_alloc_coherent(%ld)\n",
157202
__func__, PAGE_SIZE);
@@ -164,17 +209,22 @@ static int ft5406_probe(struct platform_device *pdev)
164209
&touchbuf, sizeof(touchbuf));
165210

166211
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);
168214
dma_free_coherent(dev, PAGE_SIZE, ts->ts_base, ts->bus_addr);
169215
ts->ts_base = 0;
170216
ts->bus_addr = 0;
171217
}
172218

173219
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));
178228
if (err) {
179229
dev_err(dev, "Failed to get touch buffer\n");
180230
goto out;
@@ -188,45 +238,67 @@ static int ft5406_probe(struct platform_device *pdev)
188238

189239
dev_dbg(dev, "Got TS buffer 0x%x\n", touchbuf);
190240

191-
// mmap the physical memory
241+
/* mmap the physical memory */
192242
touchbuf &= ~0xc0000000;
193243
ts->ts_base = ioremap(touchbuf, sizeof(struct ft5406_regs));
194-
if (ts->ts_base == NULL)
195-
{
244+
if (ts->ts_base == NULL) {
196245
dev_err(dev, "Failed to map physical address\n");
197246
err = -ENOMEM;
198247
goto out;
199248
}
200249
}
201250
platform_set_drvdata(pdev, ts);
202251
ts->pdev = pdev;
203-
252+
204253
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+
206278
__set_bit(EV_KEY, ts->input_dev->evbit);
207279
__set_bit(EV_SYN, ts->input_dev->evbit);
208280
__set_bit(EV_ABS, ts->input_dev->evbit);
209281

210282
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);
212284
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);
214286

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);
216289

217290
input_set_drvdata(ts->input_dev, ts);
218-
291+
219292
err = input_register_device(ts->input_dev);
220293
if (err) {
221294
dev_err(dev, "could not register input device, %d\n",
222295
err);
223296
goto out;
224297
}
225298

226-
// create thread to poll the touch events
299+
/* create thread that polls the touch events */
227300
ts->thread = kthread_run(ft5406_thread, ts, "ft5406");
228-
if(ts->thread == NULL)
229-
{
301+
if (ts->thread == NULL) {
230302
dev_err(dev, "Failed to create kernel thread");
231303
err = -ENOMEM;
232304
goto out;
@@ -254,9 +326,9 @@ static int ft5406_remove(struct platform_device *pdev)
254326
{
255327
struct device *dev = &pdev->dev;
256328
struct ft5406 *ts = (struct ft5406 *) platform_get_drvdata(pdev);
257-
329+
258330
dev_info(dev, "Removing rpi-ft5406\n");
259-
331+
260332
kthread_stop(ts->thread);
261333

262334
if (ts->bus_addr)
@@ -265,7 +337,7 @@ static int ft5406_remove(struct platform_device *pdev)
265337
iounmap(ts->ts_base);
266338
if (ts->input_dev)
267339
input_unregister_device(ts->input_dev);
268-
340+
269341
return 0;
270342
}
271343

0 commit comments

Comments
 (0)