Skip to content

Commit 8f299ba

Browse files
tzuhsuan12wzyy2
authored andcommitted
MINIARM: ts: Add the ft5406 touch driver for tinker board.
Change-Id: I03eeb48d60cfad984038bf2301f7bb41d4d95804
1 parent a62972a commit 8f299ba

5 files changed

Lines changed: 402 additions & 0 deletions

File tree

arch/arm/mach-rockchip/rockchip.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,12 @@ static struct i2c_board_info __initdata i2c_devices_tinker_mcu[] = {
4040
},
4141
};
4242

43+
static struct i2c_board_info __initdata i2c_devices_tinker_ft5406[] = {
44+
{
45+
I2C_BOARD_INFO("tinker_ft5406", 0x38),
46+
},
47+
};
48+
4349
static void __init rockchip_timer_init(void)
4450
{
4551
if (of_machine_is_compatible("rockchip,rk3288")) {
@@ -71,6 +77,7 @@ static void __init rockchip_dt_init(void)
7177
platform_device_register_simple("cpufreq-dt", 0, NULL, 0);
7278

7379
i2c_register_board_info(3, i2c_devices_tinker_mcu, ARRAY_SIZE(i2c_devices_tinker_mcu));
80+
i2c_register_board_info(3, i2c_devices_tinker_ft5406, ARRAY_SIZE(i2c_devices_tinker_ft5406));
7481
}
7582

7683
static const char * const rockchip_board_dt_compat[] = {

drivers/miniarm/dsi/Kconfig

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,3 +34,10 @@ config TINKER_MCU
3434
depends on I2C
3535
help
3636
Control the power of touch screen for tinker board.
37+
38+
config TOUCHSCREEN_TINKER_FT5406
39+
tristate "tinker ft5406"
40+
default y
41+
depends on I2C
42+
help
43+
Control ft5406 touch ic.

drivers/miniarm/dsi/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,4 @@ obj-$(CONFIG_DRM_PANEL_TOSHIBA_TC358762) += panel-toshiba-tc358762.o
22
obj-$(CONFIG_ASUS_RPI_MCU) += asus_mcu.o
33
obj-$(CONFIG_ROCKCHIP_DW_MIPI_DSI2) += dw-mipi-dsi.o
44
obj-$(CONFIG_TINKER_MCU) += tinker_mcu.o
5+
obj-$(CONFIG_TOUCHSCREEN_TINKER_FT5406) += tinker_ft5406.o
Lines changed: 323 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,323 @@
1+
/*
2+
*
3+
* TINKER BOARD FT5406 touch driver.
4+
*
5+
* Copyright (c) 2016 ASUSTek Computer Inc.
6+
* Copyright (c) 2012-2014, The Linux Foundation. All rights reserved.
7+
*
8+
* This software is licensed under the terms of the GNU General Public
9+
* License version 2, as published by the Free Software Foundation, and
10+
* may be copied, distributed, and modified under those terms.
11+
*
12+
* This program is distributed in the hope that it will be useful,
13+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15+
* GNU General Public License for more details.
16+
*
17+
*/
18+
19+
#include <linux/module.h>
20+
#include <linux/slab.h>
21+
#include <linux/delay.h>
22+
#include <linux/i2c.h>
23+
#include <linux/input.h>
24+
#include <linux/input/mt.h>
25+
#include <linux/module.h>
26+
#include <linux/workqueue.h>
27+
#include "tinker_ft5406.h"
28+
29+
static int fts_i2c_read(struct i2c_client *client, char *writebuf,
30+
int writelen, char *readbuf, int readlen)
31+
{
32+
int ret;
33+
34+
if (writelen > 0) {
35+
struct i2c_msg msgs[] = {
36+
{
37+
.addr = client->addr,
38+
.flags = 0,
39+
.len = writelen,
40+
.buf = writebuf,
41+
},
42+
{
43+
.addr = client->addr,
44+
.flags = I2C_M_RD,
45+
.len = readlen,
46+
.buf = readbuf,
47+
},
48+
};
49+
ret = i2c_transfer(client->adapter, msgs, 2);
50+
if (ret < 0)
51+
LOG_ERR("i2c read error, %d\n", ret);
52+
} else {
53+
struct i2c_msg msgs[] = {
54+
{
55+
.addr = client->addr,
56+
.flags = I2C_M_RD,
57+
.len = readlen,
58+
.buf = readbuf,
59+
},
60+
};
61+
ret = i2c_transfer(client->adapter, msgs, 1);
62+
if (ret < 0)
63+
LOG_ERR("i2c read error, %d\n", ret);
64+
}
65+
66+
return ret;
67+
}
68+
69+
static int fts_read_reg(struct i2c_client *client, u8 addr, u8 *val)
70+
{
71+
return fts_i2c_read(client, &addr, 1, val, 1);
72+
}
73+
74+
static int fts_check_fw_ver(struct i2c_client *client)
75+
{
76+
u8 reg_addr, fw_ver[3];
77+
int ret;
78+
79+
reg_addr = FT_REG_FW_VER;
80+
ret = fts_i2c_read(client, &reg_addr, 1, &fw_ver[0], 1);
81+
if (ret < 0)
82+
goto error;
83+
84+
reg_addr = FT_REG_FW_MIN_VER;
85+
ret = fts_i2c_read(client, &reg_addr, 1, &fw_ver[1], 1);
86+
if (ret < 0)
87+
goto error;
88+
89+
reg_addr = FT_REG_FW_SUB_MIN_VER;
90+
ret = fts_i2c_read(client, &reg_addr, 1, &fw_ver[2], 1);
91+
if (ret < 0)
92+
goto error;
93+
94+
LOG_INFO("Firmware version = %d.%d.%d\n", fw_ver[0], fw_ver[1], fw_ver[2]);
95+
return 0;
96+
97+
error:
98+
return ret;
99+
}
100+
101+
static int fts_read_td_status(struct tinker_ft5406_data *ts_data)
102+
{
103+
u8 td_status;
104+
int ret = -1;
105+
ret = fts_read_reg(ts_data->client, FT_TD_STATUS_REG, &td_status);
106+
if (ret < 0) {
107+
LOG_ERR("get reg td_status failed, %d\n", ret);
108+
return ret;
109+
}
110+
return (int)td_status;
111+
}
112+
113+
static int fts_read_touchdata(struct tinker_ft5406_data *ts_data)
114+
{
115+
struct ts_event *event = &ts_data->event;
116+
int ret = -1, i;
117+
u8 buf[FT_ONE_TCH_LEN-2] = { 0 };
118+
u8 reg_addr, pointid = FT_MAX_ID;
119+
120+
for (i = 0; i < event->touch_point && i < MAX_TOUCH_POINTS; i++) {
121+
reg_addr = FT_TOUCH_X_H_REG + (i * FT_ONE_TCH_LEN);
122+
ret = fts_i2c_read(ts_data->client, &reg_addr, 1, buf, FT_ONE_TCH_LEN-2);
123+
if (ret < 0) {
124+
LOG_ERR("read touchdata failed.\n");
125+
return ret;
126+
}
127+
128+
pointid = (buf[FT_TOUCH_ID]) >> 4;
129+
if (pointid >= MAX_TOUCH_POINTS)
130+
break;
131+
event->au8_finger_id[i] = pointid;
132+
event->au16_x[i] = (s16) (buf[FT_TOUCH_X_H] & 0x0F) << 8 | (s16) buf[FT_TOUCH_X_L];
133+
event->au16_y[i] = (s16) (buf[FT_TOUCH_Y_H] & 0x0F) << 8 | (s16) buf[FT_TOUCH_Y_L];
134+
event->au8_touch_event[i] = buf[FT_TOUCH_EVENT] >> 6;
135+
136+
#if XY_REVERSE
137+
event->au16_x[i] = SCREEN_WIDTH - event->au16_x[i] - 1;
138+
event->au16_y[i] = SCREEN_HEIGHT - event->au16_y[i] - 1;
139+
#endif
140+
}
141+
event->pressure = FT_PRESS;
142+
143+
return 0;
144+
}
145+
146+
static void fts_report_value(struct tinker_ft5406_data *ts_data)
147+
{
148+
struct ts_event *event = &ts_data->event;
149+
int i, modified_ids = 0, released_ids;
150+
151+
for (i = 0; i < event->touch_point && i < MAX_TOUCH_POINTS; i++) {
152+
if (event->au8_touch_event[i]== FT_TOUCH_DOWN
153+
|| event->au8_touch_event[i] == FT_TOUCH_CONTACT)
154+
{
155+
modified_ids |= 1 << event->au8_finger_id[i];
156+
input_mt_slot(ts_data->input_dev, event->au8_finger_id[i]);
157+
input_mt_report_slot_state(ts_data->input_dev, MT_TOOL_FINGER,
158+
true);
159+
input_report_abs(ts_data->input_dev, ABS_MT_TOUCH_MAJOR,
160+
event->pressure);
161+
input_report_abs(ts_data->input_dev, ABS_MT_POSITION_X,
162+
event->au16_x[i]);
163+
input_report_abs(ts_data->input_dev, ABS_MT_POSITION_Y,
164+
event->au16_y[i]);
165+
166+
if(!((1 << event->au8_finger_id[i]) & ts_data->known_ids))
167+
LOG_DBG("Touch id-%d: x = %d, y = %d\n",
168+
event->au8_finger_id[i], event->au16_x[i], event->au16_y[i]);
169+
}
170+
}
171+
172+
released_ids = ts_data->known_ids & ~modified_ids;
173+
for(i = 0; released_ids && i < MAX_TOUCH_POINTS; i++) {
174+
if(released_ids & (1<<i)) {
175+
LOG_DBG("Release id-%d, known = %x modified = %x\n", i, ts_data->known_ids, modified_ids);
176+
input_mt_slot(ts_data->input_dev, i);
177+
input_mt_report_slot_state(ts_data->input_dev, MT_TOOL_FINGER, false);
178+
modified_ids &= ~(1 << i);
179+
}
180+
}
181+
ts_data->known_ids = modified_ids;
182+
input_mt_report_pointer_emulation(ts_data->input_dev, true);
183+
input_sync(ts_data->input_dev);
184+
}
185+
186+
extern int tinker_mcu_is_connected(void);
187+
188+
static void tinker_ft5406_work(struct work_struct *work)
189+
{
190+
struct tinker_ft5406_data *ts_data
191+
= container_of(work, struct tinker_ft5406_data, ft5406_work);
192+
struct ts_event *event = &ts_data->event;
193+
int ret = 0, count = 8, td_status;
194+
195+
while(count > 0) {
196+
ret = fts_check_fw_ver(ts_data->client);
197+
if (ret == 0)
198+
break;
199+
LOG_INFO("checking touch ic, countdown: %d\n", count);
200+
msleep(1000);
201+
count--;
202+
}
203+
if (!count) {
204+
LOG_ERR("checking touch ic timeout, %d\n", ret);
205+
return;
206+
}
207+
208+
//polling 60fps
209+
while(1) {
210+
td_status = fts_read_td_status(ts_data);
211+
if (td_status < VALID_TD_STATUS_VAL+1 && (td_status > 0 || ts_data->known_ids != 0)) {
212+
memset(event, -1, sizeof(struct ts_event));
213+
event->touch_point = td_status;
214+
ret = fts_read_touchdata(ts_data);
215+
if (ret == 0)
216+
fts_report_value(ts_data);
217+
}
218+
msleep_interruptible(17);
219+
}
220+
}
221+
222+
static int tinker_ft5406_probe(struct i2c_client *client,
223+
const struct i2c_device_id *id)
224+
{
225+
struct tinker_ft5406_data *ts_data;
226+
struct input_dev *input_dev;
227+
int ret = 0, timeout = 10;
228+
229+
LOG_INFO("address = 0x%x\n", client->addr);
230+
231+
ts_data = kzalloc(sizeof(struct tinker_ft5406_data), GFP_KERNEL);
232+
if (ts_data == NULL) {
233+
LOG_ERR("no memory for device\n");
234+
return -ENOMEM;
235+
}
236+
237+
ts_data->client = client;
238+
i2c_set_clientdata(client, ts_data);
239+
240+
while(!tinker_mcu_is_connected() && timeout > 0) {
241+
msleep(50);
242+
timeout--;
243+
}
244+
245+
if (timeout == 0) {
246+
LOG_ERR("wait connected timeout\n");
247+
ret = -ENODEV;
248+
goto timeout_failed;
249+
}
250+
251+
input_dev = input_allocate_device();
252+
if (!input_dev) {
253+
LOG_ERR("failed to allocate input device\n");
254+
goto input_allocate_failed;
255+
}
256+
input_dev->name = "fts_ts";
257+
input_dev->id.bustype = BUS_I2C;
258+
input_dev->dev.parent = &ts_data->client->dev;
259+
260+
ts_data->input_dev = input_dev;
261+
input_set_drvdata(input_dev, ts_data);
262+
263+
__set_bit(EV_SYN, input_dev->evbit);
264+
__set_bit(EV_KEY, input_dev->evbit);
265+
__set_bit(EV_ABS, input_dev->evbit);
266+
__set_bit(BTN_TOUCH, input_dev->keybit);
267+
268+
input_mt_init_slots(input_dev, MAX_TOUCH_POINTS, 0);
269+
input_set_abs_params(input_dev, ABS_MT_POSITION_X, 0,
270+
SCREEN_WIDTH, 0, 0);
271+
input_set_abs_params(input_dev, ABS_MT_POSITION_Y, 0,
272+
SCREEN_HEIGHT, 0, 0);
273+
274+
ret = input_register_device(input_dev);
275+
if (ret) {
276+
LOG_ERR("Input device registration failed\n");
277+
goto input_register_failed;
278+
}
279+
280+
INIT_WORK(&ts_data->ft5406_work, tinker_ft5406_work);
281+
schedule_work(&ts_data->ft5406_work);
282+
283+
return 0;
284+
285+
input_register_failed:
286+
input_free_device(input_dev);
287+
input_allocate_failed:
288+
timeout_failed:
289+
kfree(ts_data);
290+
return ret;
291+
}
292+
293+
static int tinker_ft5406_remove(struct i2c_client *client)
294+
{
295+
struct tinker_ft5406_data *ts_data = i2c_get_clientdata(client);
296+
297+
cancel_work_sync(&ts_data->ft5406_work);
298+
if (ts_data->input_dev) {
299+
input_unregister_device(ts_data->input_dev);
300+
input_free_device(ts_data->input_dev);
301+
}
302+
kfree(ts_data);
303+
return 0;
304+
}
305+
306+
static const struct i2c_device_id tinker_ft5406_id[] = {
307+
{"tinker_ft5406", 0},
308+
{},
309+
};
310+
311+
static struct i2c_driver tinker_ft5406_driver = {
312+
.driver = {
313+
.name = "tinker_ft5406",
314+
},
315+
.probe = tinker_ft5406_probe,
316+
.remove = tinker_ft5406_remove,
317+
.id_table = tinker_ft5406_id,
318+
};
319+
module_i2c_driver(tinker_ft5406_driver);
320+
321+
MODULE_DESCRIPTION("TINKER BOARD FT5406 Touch driver");
322+
MODULE_LICENSE("GPL v2");
323+

0 commit comments

Comments
 (0)