Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
openeuler
raspberrypi-kernel
提交
a5cba18c
R
raspberrypi-kernel
项目概览
openeuler
/
raspberrypi-kernel
通知
14
Star
1
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
R
raspberrypi-kernel
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
提交
a5cba18c
编写于
7月 03, 2015
作者:
D
Dmitry Torokhov
浏览文件
操作
浏览文件
下载
差异文件
Merge branch 'next' into for-linus
Prepare second round of input updates for 4.2 merge window.
上级
f7ebc4dc
d55d0b56
变更
12
隐藏空白更改
内联
并排
Showing
12 changed file
with
1296 addition
and
76 deletion
+1296
-76
drivers/input/input.c
drivers/input/input.c
+9
-25
drivers/input/joystick/xpad.c
drivers/input/joystick/xpad.c
+65
-13
drivers/input/keyboard/imx_keypad.c
drivers/input/keyboard/imx_keypad.c
+3
-1
drivers/input/misc/axp20x-pek.c
drivers/input/misc/axp20x-pek.c
+6
-2
drivers/input/serio/Kconfig
drivers/input/serio/Kconfig
+1
-0
drivers/input/touchscreen/Kconfig
drivers/input/touchscreen/Kconfig
+12
-0
drivers/input/touchscreen/Makefile
drivers/input/touchscreen/Makefile
+1
-0
drivers/input/touchscreen/edt-ft5x06.c
drivers/input/touchscreen/edt-ft5x06.c
+2
-7
drivers/input/touchscreen/of_touchscreen.c
drivers/input/touchscreen/of_touchscreen.c
+44
-25
drivers/input/touchscreen/tsc2005.c
drivers/input/touchscreen/tsc2005.c
+1
-1
drivers/input/touchscreen/wdt87xx_i2c.c
drivers/input/touchscreen/wdt87xx_i2c.c
+1149
-0
include/linux/input/touchscreen.h
include/linux/input/touchscreen.h
+3
-2
未找到文件。
drivers/input/input.c
浏览文件 @
a5cba18c
...
...
@@ -677,12 +677,9 @@ static void input_dev_release_keys(struct input_dev *dev)
int
code
;
if
(
is_event_supported
(
EV_KEY
,
dev
->
evbit
,
EV_MAX
))
{
for
(
code
=
0
;
code
<=
KEY_MAX
;
code
++
)
{
if
(
is_event_supported
(
code
,
dev
->
keybit
,
KEY_MAX
)
&&
__test_and_clear_bit
(
code
,
dev
->
key
))
{
input_pass_event
(
dev
,
EV_KEY
,
code
,
0
);
}
}
for_each_set_bit
(
code
,
dev
->
key
,
KEY_CNT
)
input_pass_event
(
dev
,
EV_KEY
,
code
,
0
);
memset
(
dev
->
key
,
0
,
sizeof
(
dev
->
key
));
input_pass_event
(
dev
,
EV_SYN
,
SYN_REPORT
,
1
);
}
}
...
...
@@ -1626,10 +1623,7 @@ static int input_dev_uevent(struct device *device, struct kobj_uevent_env *env)
if (!test_bit(EV_##type, dev->evbit)) \
break; \
\
for (i = 0; i < type##_MAX; i++) { \
if (!test_bit(i, dev->bits##bit)) \
continue; \
\
for_each_set_bit(i, dev->bits##bit, type##_CNT) { \
active = test_bit(i, dev->bits); \
if (!active && !on) \
continue; \
...
...
@@ -1980,22 +1974,12 @@ static unsigned int input_estimate_events_per_packet(struct input_dev *dev)
events
=
mt_slots
+
1
;
/* count SYN_MT_REPORT and SYN_REPORT */
if
(
test_bit
(
EV_ABS
,
dev
->
evbit
))
{
for
(
i
=
0
;
i
<
ABS_CNT
;
i
++
)
{
if
(
test_bit
(
i
,
dev
->
absbit
))
{
if
(
input_is_mt_axis
(
i
))
events
+=
mt_slots
;
else
events
++
;
}
}
}
if
(
test_bit
(
EV_ABS
,
dev
->
evbit
))
for_each_set_bit
(
i
,
dev
->
absbit
,
ABS_CNT
)
events
+=
input_is_mt_axis
(
i
)
?
mt_slots
:
1
;
if
(
test_bit
(
EV_REL
,
dev
->
evbit
))
{
for
(
i
=
0
;
i
<
REL_CNT
;
i
++
)
if
(
test_bit
(
i
,
dev
->
relbit
))
events
++
;
}
if
(
test_bit
(
EV_REL
,
dev
->
evbit
))
events
+=
bitmap_weight
(
dev
->
relbit
,
REL_CNT
);
/* Make room for KEY and MSC events */
events
+=
7
;
...
...
drivers/input/joystick/xpad.c
浏览文件 @
a5cba18c
...
...
@@ -344,6 +344,7 @@ struct usb_xpad {
int
mapping
;
/* map d-pad to buttons or to axes */
int
xtype
;
/* type of xbox device */
unsigned
long
led_no
;
/* led to lit on xbox360 controllers */
};
/*
...
...
@@ -488,6 +489,8 @@ static void xpad360_process_packet(struct usb_xpad *xpad,
input_sync
(
dev
);
}
static
void
xpad_identify_controller
(
struct
usb_xpad
*
xpad
);
/*
* xpad360w_process_packet
*
...
...
@@ -510,6 +513,11 @@ static void xpad360w_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned cha
if
(
data
[
1
]
&
0x80
)
{
xpad
->
pad_present
=
1
;
usb_submit_urb
(
xpad
->
bulk_out
,
GFP_ATOMIC
);
/*
* Light up the segment corresponding to
* controller number.
*/
xpad_identify_controller
(
xpad
);
}
else
xpad
->
pad_present
=
0
;
}
...
...
@@ -881,17 +889,63 @@ struct xpad_led {
struct
usb_xpad
*
xpad
;
};
/**
* @param command
* 0: off
* 1: all blink, then previous setting
* 2: 1/top-left blink, then on
* 3: 2/top-right blink, then on
* 4: 3/bottom-left blink, then on
* 5: 4/bottom-right blink, then on
* 6: 1/top-left on
* 7: 2/top-right on
* 8: 3/bottom-left on
* 9: 4/bottom-right on
* 10: rotate
* 11: blink, based on previous setting
* 12: slow blink, based on previous setting
* 13: rotate with two lights
* 14: persistent slow all blink
* 15: blink once, then previous setting
*/
static
void
xpad_send_led_command
(
struct
usb_xpad
*
xpad
,
int
command
)
{
if
(
command
>=
0
&&
command
<
14
)
{
mutex_lock
(
&
xpad
->
odata_mutex
);
command
%=
16
;
mutex_lock
(
&
xpad
->
odata_mutex
);
switch
(
xpad
->
xtype
)
{
case
XTYPE_XBOX360
:
xpad
->
odata
[
0
]
=
0x01
;
xpad
->
odata
[
1
]
=
0x03
;
xpad
->
odata
[
2
]
=
command
;
xpad
->
irq_out
->
transfer_buffer_length
=
3
;
usb_submit_urb
(
xpad
->
irq_out
,
GFP_KERNEL
);
mutex_unlock
(
&
xpad
->
odata_mutex
);
break
;
case
XTYPE_XBOX360W
:
xpad
->
odata
[
0
]
=
0x00
;
xpad
->
odata
[
1
]
=
0x00
;
xpad
->
odata
[
2
]
=
0x08
;
xpad
->
odata
[
3
]
=
0x40
+
command
;
xpad
->
odata
[
4
]
=
0x00
;
xpad
->
odata
[
5
]
=
0x00
;
xpad
->
odata
[
6
]
=
0x00
;
xpad
->
odata
[
7
]
=
0x00
;
xpad
->
odata
[
8
]
=
0x00
;
xpad
->
odata
[
9
]
=
0x00
;
xpad
->
odata
[
10
]
=
0x00
;
xpad
->
odata
[
11
]
=
0x00
;
xpad
->
irq_out
->
transfer_buffer_length
=
12
;
break
;
}
usb_submit_urb
(
xpad
->
irq_out
,
GFP_KERNEL
);
mutex_unlock
(
&
xpad
->
odata_mutex
);
}
static
void
xpad_identify_controller
(
struct
usb_xpad
*
xpad
)
{
/* Light up the segment corresponding to controller number */
xpad_send_led_command
(
xpad
,
(
xpad
->
led_no
%
4
)
+
2
);
}
static
void
xpad_led_set
(
struct
led_classdev
*
led_cdev
,
...
...
@@ -905,22 +959,21 @@ static void xpad_led_set(struct led_classdev *led_cdev,
static
int
xpad_led_probe
(
struct
usb_xpad
*
xpad
)
{
static
atomic_t
led_seq
=
ATOMIC_INIT
(
-
1
);
unsigned
long
led_no
;
static
atomic_t
led_seq
=
ATOMIC_INIT
(
-
1
);
struct
xpad_led
*
led
;
struct
led_classdev
*
led_cdev
;
int
error
;
if
(
xpad
->
xtype
!=
XTYPE_XBOX360
)
if
(
xpad
->
xtype
!=
XTYPE_XBOX360
&&
xpad
->
xtype
!=
XTYPE_XBOX360W
)
return
0
;
xpad
->
led
=
led
=
kzalloc
(
sizeof
(
struct
xpad_led
),
GFP_KERNEL
);
if
(
!
led
)
return
-
ENOMEM
;
led_no
=
atomic_inc_return
(
&
led_seq
);
xpad
->
led_no
=
atomic_inc_return
(
&
led_seq
);
snprintf
(
led
->
name
,
sizeof
(
led
->
name
),
"xpad%lu"
,
led_no
);
snprintf
(
led
->
name
,
sizeof
(
led
->
name
),
"xpad%lu"
,
xpad
->
led_no
);
led
->
xpad
=
xpad
;
led_cdev
=
&
led
->
led_cdev
;
...
...
@@ -934,10 +987,8 @@ static int xpad_led_probe(struct usb_xpad *xpad)
return
error
;
}
/*
* Light up the segment corresponding to controller number
*/
xpad_send_led_command
(
xpad
,
(
led_no
%
4
)
+
2
);
/* Light up the segment corresponding to controller number */
xpad_identify_controller
(
xpad
);
return
0
;
}
...
...
@@ -954,6 +1005,7 @@ static void xpad_led_disconnect(struct usb_xpad *xpad)
#else
static
int
xpad_led_probe
(
struct
usb_xpad
*
xpad
)
{
return
0
;
}
static
void
xpad_led_disconnect
(
struct
usb_xpad
*
xpad
)
{
}
static
void
xpad_identify_controller
(
struct
usb_xpad
*
xpad
)
{
}
#endif
...
...
drivers/input/keyboard/imx_keypad.c
浏览文件 @
a5cba18c
...
...
@@ -506,7 +506,9 @@ static int imx_keypad_probe(struct platform_device *pdev)
input_set_drvdata
(
input_dev
,
keypad
);
/* Ensure that the keypad will stay dormant until opened */
clk_prepare_enable
(
keypad
->
clk
);
error
=
clk_prepare_enable
(
keypad
->
clk
);
if
(
error
)
return
error
;
imx_keypad_inhibit
(
keypad
);
clk_disable_unprepare
(
keypad
->
clk
);
...
...
drivers/input/misc/axp20x-pek.c
浏览文件 @
a5cba18c
...
...
@@ -167,9 +167,13 @@ static irqreturn_t axp20x_pek_irq(int irq, void *pwr)
struct
input_dev
*
idev
=
pwr
;
struct
axp20x_pek
*
axp20x_pek
=
input_get_drvdata
(
idev
);
if
(
irq
==
axp20x_pek
->
irq_dbr
)
/*
* The power-button is connected to ground so a falling edge (dbf)
* means it is pressed.
*/
if
(
irq
==
axp20x_pek
->
irq_dbf
)
input_report_key
(
idev
,
KEY_POWER
,
true
);
else
if
(
irq
==
axp20x_pek
->
irq_db
f
)
else
if
(
irq
==
axp20x_pek
->
irq_db
r
)
input_report_key
(
idev
,
KEY_POWER
,
false
);
input_sync
(
idev
);
...
...
drivers/input/serio/Kconfig
浏览文件 @
a5cba18c
...
...
@@ -244,6 +244,7 @@ config SERIO_PS2MULT
config SERIO_ARC_PS2
tristate "ARC PS/2 support"
depends on HAS_IOMEM
help
Say Y here if you have an ARC FPGA platform with a PS/2
controller in it.
...
...
drivers/input/touchscreen/Kconfig
浏览文件 @
a5cba18c
...
...
@@ -658,6 +658,18 @@ config TOUCHSCREEN_PIXCIR
To compile this driver as a module, choose M here: the
module will be called pixcir_i2c_ts.
config TOUCHSCREEN_WDT87XX_I2C
tristate "Weida HiTech I2C touchscreen"
depends on I2C
help
Say Y here if you have a Weida WDT87XX I2C touchscreen
connected to your system.
If unsure, say N.
To compile this driver as a module, choose M here: the
module will be called wdt87xx_i2c.
config TOUCHSCREEN_WM831X
tristate "Support for WM831x touchscreen controllers"
depends on MFD_WM831X
...
...
drivers/input/touchscreen/Makefile
浏览文件 @
a5cba18c
...
...
@@ -72,6 +72,7 @@ obj-$(CONFIG_TOUCHSCREEN_TSC2007) += tsc2007.o
obj-$(CONFIG_TOUCHSCREEN_UCB1400)
+=
ucb1400_ts.o
obj-$(CONFIG_TOUCHSCREEN_WACOM_W8001)
+=
wacom_w8001.o
obj-$(CONFIG_TOUCHSCREEN_WACOM_I2C)
+=
wacom_i2c.o
obj-$(CONFIG_TOUCHSCREEN_WDT87XX_I2C)
+=
wdt87xx_i2c.o
obj-$(CONFIG_TOUCHSCREEN_WM831X)
+=
wm831x-ts.o
obj-$(CONFIG_TOUCHSCREEN_WM97XX)
+=
wm97xx-ts.o
wm97xx-ts-$(CONFIG_TOUCHSCREEN_WM9705)
+=
wm9705.o
...
...
drivers/input/touchscreen/edt-ft5x06.c
浏览文件 @
a5cba18c
...
...
@@ -1035,20 +1035,15 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client,
input
->
id
.
bustype
=
BUS_I2C
;
input
->
dev
.
parent
=
&
client
->
dev
;
__set_bit
(
EV_KEY
,
input
->
evbit
);
__set_bit
(
EV_ABS
,
input
->
evbit
);
__set_bit
(
BTN_TOUCH
,
input
->
keybit
);
input_set_abs_params
(
input
,
ABS_X
,
0
,
tsdata
->
num_x
*
64
-
1
,
0
,
0
);
input_set_abs_params
(
input
,
ABS_Y
,
0
,
tsdata
->
num_y
*
64
-
1
,
0
,
0
);
input_set_abs_params
(
input
,
ABS_MT_POSITION_X
,
0
,
tsdata
->
num_x
*
64
-
1
,
0
,
0
);
input_set_abs_params
(
input
,
ABS_MT_POSITION_Y
,
0
,
tsdata
->
num_y
*
64
-
1
,
0
,
0
);
if
(
!
pdata
)
touchscreen_parse_of_params
(
input
);
touchscreen_parse_of_params
(
input
,
true
);
error
=
input_mt_init_slots
(
input
,
MAX_SUPPORT_POINTS
,
0
);
error
=
input_mt_init_slots
(
input
,
MAX_SUPPORT_POINTS
,
INPUT_MT_DIRECT
);
if
(
error
)
{
dev_err
(
&
client
->
dev
,
"Unable to init MT slots.
\n
"
);
return
error
;
...
...
drivers/input/touchscreen/of_touchscreen.c
浏览文件 @
a5cba18c
...
...
@@ -14,14 +14,22 @@
#include <linux/input/mt.h>
#include <linux/input/touchscreen.h>
static
u32
of_get_optional_u32
(
struct
device_node
*
np
,
const
char
*
property
)
static
bool
touchscreen_get_prop_u32
(
struct
device_node
*
np
,
const
char
*
property
,
unsigned
int
default_value
,
unsigned
int
*
value
)
{
u32
val
=
0
;
u32
val
;
int
error
;
of_property_read_u32
(
np
,
property
,
&
val
);
error
=
of_property_read_u32
(
np
,
property
,
&
val
);
if
(
error
)
{
*
value
=
default_value
;
return
false
;
}
return
val
;
*
value
=
val
;
return
true
;
}
static
void
touchscreen_set_params
(
struct
input_dev
*
dev
,
...
...
@@ -54,34 +62,45 @@ static void touchscreen_set_params(struct input_dev *dev,
* input device accordingly. The function keeps previously setuped default
* values if no value is specified via DT.
*/
void
touchscreen_parse_of_params
(
struct
input_dev
*
dev
)
void
touchscreen_parse_of_params
(
struct
input_dev
*
dev
,
bool
multitouch
)
{
struct
device_node
*
np
=
dev
->
dev
.
parent
->
of_node
;
u32
maximum
,
fuzz
;
unsigned
int
axis
;
unsigned
int
maximum
,
fuzz
;
bool
data_present
;
input_alloc_absinfo
(
dev
);
if
(
!
dev
->
absinfo
)
return
;
maximum
=
of_get_optional_u32
(
np
,
"touchscreen-size-x"
);
fuzz
=
of_get_optional_u32
(
np
,
"touchscreen-fuzz-x"
);
if
(
maximum
||
fuzz
)
{
touchscreen_set_params
(
dev
,
ABS_X
,
maximum
,
fuzz
);
touchscreen_set_params
(
dev
,
ABS_MT_POSITION_X
,
maximum
,
fuzz
);
}
axis
=
multitouch
?
ABS_MT_POSITION_X
:
ABS_X
;
data_present
=
touchscreen_get_prop_u32
(
np
,
"touchscreen-size-x"
,
input_abs_get_max
(
dev
,
axis
),
&
maximum
)
|
touchscreen_get_prop_u32
(
np
,
"touchscreen-fuzz-x"
,
input_abs_get_fuzz
(
dev
,
axis
),
&
fuzz
);
if
(
data_present
)
touchscreen_set_params
(
dev
,
axis
,
maximum
,
fuzz
);
maximum
=
of_get_optional_u32
(
np
,
"touchscreen-size-y"
);
fuzz
=
of_get_optional_u32
(
np
,
"touchscreen-fuzz-y"
);
if
(
maximum
||
fuzz
)
{
touchscreen_set_params
(
dev
,
ABS_Y
,
maximum
,
fuzz
);
touchscreen_set_params
(
dev
,
ABS_MT_POSITION_Y
,
maximum
,
fuzz
);
}
axis
=
multitouch
?
ABS_MT_POSITION_Y
:
ABS_Y
;
data_present
=
touchscreen_get_prop_u32
(
np
,
"touchscreen-size-y"
,
input_abs_get_max
(
dev
,
axis
),
&
maximum
)
|
touchscreen_get_prop_u32
(
np
,
"touchscreen-fuzz-y"
,
input_abs_get_fuzz
(
dev
,
axis
),
&
fuzz
);
if
(
data_present
)
touchscreen_set_params
(
dev
,
axis
,
maximum
,
fuzz
);
maximum
=
of_get_optional_u32
(
np
,
"touchscreen-max-pressure"
);
fuzz
=
of_get_optional_u32
(
np
,
"touchscreen-fuzz-pressure"
);
if
(
maximum
||
fuzz
)
{
touchscreen_set_params
(
dev
,
ABS_PRESSURE
,
maximum
,
fuzz
);
touchscreen_set_params
(
dev
,
ABS_MT_PRESSURE
,
maximum
,
fuzz
);
}
axis
=
multitouch
?
ABS_MT_PRESSURE
:
ABS_PRESSURE
;
data_present
=
touchscreen_get_prop_u32
(
np
,
"touchscreen-max-pressure"
,
input_abs_get_max
(
dev
,
axis
),
&
maximum
)
|
touchscreen_get_prop_u32
(
np
,
"touchscreen-fuzz-pressure"
,
input_abs_get_fuzz
(
dev
,
axis
),
&
fuzz
);
if
(
data_present
)
touchscreen_set_params
(
dev
,
axis
,
maximum
,
fuzz
);
}
EXPORT_SYMBOL
(
touchscreen_parse_of_params
);
drivers/input/touchscreen/tsc2005.c
浏览文件 @
a5cba18c
...
...
@@ -709,7 +709,7 @@ static int tsc2005_probe(struct spi_device *spi)
input_set_abs_params
(
input_dev
,
ABS_PRESSURE
,
0
,
max_p
,
fudge_p
,
0
);
if
(
np
)
touchscreen_parse_of_params
(
input_dev
);
touchscreen_parse_of_params
(
input_dev
,
false
);
input_dev
->
open
=
tsc2005_open
;
input_dev
->
close
=
tsc2005_close
;
...
...
drivers/input/touchscreen/wdt87xx_i2c.c
0 → 100644
浏览文件 @
a5cba18c
/*
* Weida HiTech WDT87xx TouchScreen I2C driver
*
* Copyright (c) 2015 Weida Hi-Tech Co., Ltd.
* HN Chen <hn.chen@weidahitech.com>
*
* This software is licensed under the terms of the GNU General Public
* License, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*/
#include <linux/i2c.h>
#include <linux/input.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/irq.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/firmware.h>
#include <linux/input/mt.h>
#include <linux/acpi.h>
#include <asm/unaligned.h>
#define WDT87XX_NAME "wdt87xx_i2c"
#define WDT87XX_DRV_VER "0.9.6"
#define WDT87XX_FW_NAME "wdt87xx_fw.bin"
#define WDT87XX_CFG_NAME "wdt87xx_cfg.bin"
#define MODE_ACTIVE 0x01
#define MODE_READY 0x02
#define MODE_IDLE 0x03
#define MODE_SLEEP 0x04
#define MODE_STOP 0xFF
#define WDT_MAX_FINGER 10
#define WDT_RAW_BUF_COUNT 54
#define WDT_V1_RAW_BUF_COUNT 74
#define WDT_FIRMWARE_ID 0xa9e368f5
#define PG_SIZE 0x1000
#define MAX_RETRIES 3
#define MAX_UNIT_AXIS 0x7FFF
#define PKT_READ_SIZE 72
#define PKT_WRITE_SIZE 80
/* the finger definition of the report event */
#define FINGER_EV_OFFSET_ID 0
#define FINGER_EV_OFFSET_X 1
#define FINGER_EV_OFFSET_Y 3
#define FINGER_EV_SIZE 5
#define FINGER_EV_V1_OFFSET_ID 0
#define FINGER_EV_V1_OFFSET_W 1
#define FINGER_EV_V1_OFFSET_P 2
#define FINGER_EV_V1_OFFSET_X 3
#define FINGER_EV_V1_OFFSET_Y 5
#define FINGER_EV_V1_SIZE 7
/* The definition of a report packet */
#define TOUCH_PK_OFFSET_REPORT_ID 0
#define TOUCH_PK_OFFSET_EVENT 1
#define TOUCH_PK_OFFSET_SCAN_TIME 51
#define TOUCH_PK_OFFSET_FNGR_NUM 53
#define TOUCH_PK_V1_OFFSET_REPORT_ID 0
#define TOUCH_PK_V1_OFFSET_EVENT 1
#define TOUCH_PK_V1_OFFSET_SCAN_TIME 71
#define TOUCH_PK_V1_OFFSET_FNGR_NUM 73
/* The definition of the controller parameters */
#define CTL_PARAM_OFFSET_FW_ID 0
#define CTL_PARAM_OFFSET_PLAT_ID 2
#define CTL_PARAM_OFFSET_XMLS_ID1 4
#define CTL_PARAM_OFFSET_XMLS_ID2 6
#define CTL_PARAM_OFFSET_PHY_CH_X 8
#define CTL_PARAM_OFFSET_PHY_CH_Y 10
#define CTL_PARAM_OFFSET_PHY_X0 12
#define CTL_PARAM_OFFSET_PHY_X1 14
#define CTL_PARAM_OFFSET_PHY_Y0 16
#define CTL_PARAM_OFFSET_PHY_Y1 18
#define CTL_PARAM_OFFSET_PHY_W 22
#define CTL_PARAM_OFFSET_PHY_H 24
#define CTL_PARAM_OFFSET_FACTOR 32
/* Communication commands */
#define PACKET_SIZE 56
#define VND_REQ_READ 0x06
#define VND_READ_DATA 0x07
#define VND_REQ_WRITE 0x08
#define VND_CMD_START 0x00
#define VND_CMD_STOP 0x01
#define VND_CMD_RESET 0x09
#define VND_CMD_ERASE 0x1A
#define VND_GET_CHECKSUM 0x66
#define VND_SET_DATA 0x83
#define VND_SET_COMMAND_DATA 0x84
#define VND_SET_CHECKSUM_CALC 0x86
#define VND_SET_CHECKSUM_LENGTH 0x87
#define VND_CMD_SFLCK 0xFC
#define VND_CMD_SFUNL 0xFD
#define CMD_SFLCK_KEY 0xC39B
#define CMD_SFUNL_KEY 0x95DA
#define STRIDX_PLATFORM_ID 0x80
#define STRIDX_PARAMETERS 0x81
#define CMD_BUF_SIZE 8
#define PKT_BUF_SIZE 64
/* The definition of the command packet */
#define CMD_REPORT_ID_OFFSET 0x0
#define CMD_TYPE_OFFSET 0x1
#define CMD_INDEX_OFFSET 0x2
#define CMD_KEY_OFFSET 0x3
#define CMD_LENGTH_OFFSET 0x4
#define CMD_DATA_OFFSET 0x8
/* The definition of firmware chunk tags */
#define FOURCC_ID_RIFF 0x46464952
#define FOURCC_ID_WHIF 0x46494857
#define FOURCC_ID_FRMT 0x544D5246
#define FOURCC_ID_FRWR 0x52575246
#define FOURCC_ID_CNFG 0x47464E43
#define CHUNK_ID_FRMT FOURCC_ID_FRMT
#define CHUNK_ID_FRWR FOURCC_ID_FRWR
#define CHUNK_ID_CNFG FOURCC_ID_CNFG
#define FW_FOURCC1_OFFSET 0
#define FW_SIZE_OFFSET 4
#define FW_FOURCC2_OFFSET 8
#define FW_PAYLOAD_OFFSET 40
#define FW_CHUNK_ID_OFFSET 0
#define FW_CHUNK_SIZE_OFFSET 4
#define FW_CHUNK_TGT_START_OFFSET 8
#define FW_CHUNK_PAYLOAD_LEN_OFFSET 12
#define FW_CHUNK_SRC_START_OFFSET 16
#define FW_CHUNK_VERSION_OFFSET 20
#define FW_CHUNK_ATTR_OFFSET 24
#define FW_CHUNK_PAYLOAD_OFFSET 32
/* Controller requires minimum 300us between commands */
#define WDT_COMMAND_DELAY_MS 2
#define WDT_FLASH_WRITE_DELAY_MS 4
struct
wdt87xx_sys_param
{
u16
fw_id
;
u16
plat_id
;
u16
xmls_id1
;
u16
xmls_id2
;
u16
phy_ch_x
;
u16
phy_ch_y
;
u16
phy_w
;
u16
phy_h
;
u16
scaling_factor
;
u32
max_x
;
u32
max_y
;
};
struct
wdt87xx_data
{
struct
i2c_client
*
client
;
struct
input_dev
*
input
;
/* Mutex for fw update to prevent concurrent access */
struct
mutex
fw_mutex
;
struct
wdt87xx_sys_param
param
;
u8
phys
[
32
];
};
static
int
wdt87xx_i2c_xfer
(
struct
i2c_client
*
client
,
void
*
txdata
,
size_t
txlen
,
void
*
rxdata
,
size_t
rxlen
)
{
struct
i2c_msg
msgs
[]
=
{
{
.
addr
=
client
->
addr
,
.
flags
=
0
,
.
len
=
txlen
,
.
buf
=
txdata
,
},
{
.
addr
=
client
->
addr
,
.
flags
=
I2C_M_RD
,
.
len
=
rxlen
,
.
buf
=
rxdata
,
},
};
int
error
;
int
ret
;
ret
=
i2c_transfer
(
client
->
adapter
,
msgs
,
ARRAY_SIZE
(
msgs
));
if
(
ret
!=
ARRAY_SIZE
(
msgs
))
{
error
=
ret
<
0
?
ret
:
-
EIO
;
dev_err
(
&
client
->
dev
,
"%s: i2c transfer failed: %d
\n
"
,
__func__
,
error
);
return
error
;
}
return
0
;
}
static
int
wdt87xx_get_string
(
struct
i2c_client
*
client
,
u8
str_idx
,
u8
*
buf
,
size_t
len
)
{
u8
tx_buf
[]
=
{
0x22
,
0x00
,
0x13
,
0x0E
,
str_idx
,
0x23
,
0x00
};
u8
rx_buf
[
PKT_WRITE_SIZE
];
size_t
rx_len
=
len
+
2
;
int
error
;
if
(
rx_len
>
sizeof
(
rx_buf
))
return
-
EINVAL
;
error
=
wdt87xx_i2c_xfer
(
client
,
tx_buf
,
sizeof
(
tx_buf
),
rx_buf
,
rx_len
);
if
(
error
)
{
dev_err
(
&
client
->
dev
,
"get string failed: %d
\n
"
,
error
);
return
error
;
}
if
(
rx_buf
[
1
]
!=
0x03
)
{
dev_err
(
&
client
->
dev
,
"unexpected response to get string: %d
\n
"
,
rx_buf
[
1
]);
return
-
EINVAL
;
}
rx_len
=
min_t
(
size_t
,
len
,
rx_buf
[
0
]);
memcpy
(
buf
,
&
rx_buf
[
2
],
rx_len
);
mdelay
(
WDT_COMMAND_DELAY_MS
);
return
0
;
}
static
int
wdt87xx_get_feature
(
struct
i2c_client
*
client
,
u8
*
buf
,
size_t
buf_size
)
{
u8
tx_buf
[
8
];
u8
rx_buf
[
PKT_WRITE_SIZE
];
size_t
tx_len
=
0
;
size_t
rx_len
=
buf_size
+
2
;
int
error
;
if
(
rx_len
>
sizeof
(
rx_buf
))
return
-
EINVAL
;
/* Get feature command packet */
tx_buf
[
tx_len
++
]
=
0x22
;
tx_buf
[
tx_len
++
]
=
0x00
;
if
(
buf
[
CMD_REPORT_ID_OFFSET
]
>
0xF
)
{
tx_buf
[
tx_len
++
]
=
0x30
;
tx_buf
[
tx_len
++
]
=
0x02
;
tx_buf
[
tx_len
++
]
=
buf
[
CMD_REPORT_ID_OFFSET
];
}
else
{
tx_buf
[
tx_len
++
]
=
0x30
|
buf
[
CMD_REPORT_ID_OFFSET
];
tx_buf
[
tx_len
++
]
=
0x02
;
}
tx_buf
[
tx_len
++
]
=
0x23
;
tx_buf
[
tx_len
++
]
=
0x00
;
error
=
wdt87xx_i2c_xfer
(
client
,
tx_buf
,
tx_len
,
rx_buf
,
rx_len
);
if
(
error
)
{
dev_err
(
&
client
->
dev
,
"get feature failed: %d
\n
"
,
error
);
return
error
;
}
rx_len
=
min_t
(
size_t
,
buf_size
,
get_unaligned_le16
(
rx_buf
));
memcpy
(
buf
,
&
rx_buf
[
2
],
rx_len
);
mdelay
(
WDT_COMMAND_DELAY_MS
);
return
0
;
}
static
int
wdt87xx_set_feature
(
struct
i2c_client
*
client
,
const
u8
*
buf
,
size_t
buf_size
)
{
u8
tx_buf
[
PKT_WRITE_SIZE
];
int
tx_len
=
0
;
int
error
;
/* Set feature command packet */
tx_buf
[
tx_len
++
]
=
0x22
;
tx_buf
[
tx_len
++
]
=
0x00
;
if
(
buf
[
CMD_REPORT_ID_OFFSET
]
>
0xF
)
{
tx_buf
[
tx_len
++
]
=
0x30
;
tx_buf
[
tx_len
++
]
=
0x03
;
tx_buf
[
tx_len
++
]
=
buf
[
CMD_REPORT_ID_OFFSET
];
}
else
{
tx_buf
[
tx_len
++
]
=
0x30
|
buf
[
CMD_REPORT_ID_OFFSET
];
tx_buf
[
tx_len
++
]
=
0x03
;
}
tx_buf
[
tx_len
++
]
=
0x23
;
tx_buf
[
tx_len
++
]
=
0x00
;
tx_buf
[
tx_len
++
]
=
(
buf_size
&
0xFF
);
tx_buf
[
tx_len
++
]
=
((
buf_size
&
0xFF00
)
>>
8
);
if
(
tx_len
+
buf_size
>
sizeof
(
tx_buf
))
return
-
EINVAL
;
memcpy
(
&
tx_buf
[
tx_len
],
buf
,
buf_size
);
tx_len
+=
buf_size
;
error
=
i2c_master_send
(
client
,
tx_buf
,
tx_len
);
if
(
error
<
0
)
{
dev_err
(
&
client
->
dev
,
"set feature failed: %d
\n
"
,
error
);
return
error
;
}
mdelay
(
WDT_COMMAND_DELAY_MS
);
return
0
;
}
static
int
wdt87xx_send_command
(
struct
i2c_client
*
client
,
int
cmd
,
int
value
)
{
u8
cmd_buf
[
CMD_BUF_SIZE
];
/* Set the command packet */
cmd_buf
[
CMD_REPORT_ID_OFFSET
]
=
VND_REQ_WRITE
;
cmd_buf
[
CMD_TYPE_OFFSET
]
=
VND_SET_COMMAND_DATA
;
put_unaligned_le16
((
u16
)
cmd
,
&
cmd_buf
[
CMD_INDEX_OFFSET
]);
switch
(
cmd
)
{
case
VND_CMD_START
:
case
VND_CMD_STOP
:
case
VND_CMD_RESET
:
/* Mode selector */
put_unaligned_le32
((
value
&
0xFF
),
&
cmd_buf
[
CMD_LENGTH_OFFSET
]);
break
;
case
VND_CMD_SFLCK
:
put_unaligned_le16
(
CMD_SFLCK_KEY
,
&
cmd_buf
[
CMD_KEY_OFFSET
]);
break
;
case
VND_CMD_SFUNL
:
put_unaligned_le16
(
CMD_SFUNL_KEY
,
&
cmd_buf
[
CMD_KEY_OFFSET
]);
break
;
case
VND_CMD_ERASE
:
case
VND_SET_CHECKSUM_CALC
:
case
VND_SET_CHECKSUM_LENGTH
:
put_unaligned_le32
(
value
,
&
cmd_buf
[
CMD_KEY_OFFSET
]);
break
;
default:
cmd_buf
[
CMD_REPORT_ID_OFFSET
]
=
0
;
dev_err
(
&
client
->
dev
,
"Invalid command: %d
\n
"
,
cmd
);
return
-
EINVAL
;
}
return
wdt87xx_set_feature
(
client
,
cmd_buf
,
sizeof
(
cmd_buf
));
}
static
int
wdt87xx_sw_reset
(
struct
i2c_client
*
client
)
{
int
error
;
dev_dbg
(
&
client
->
dev
,
"resetting device now
\n
"
);
error
=
wdt87xx_send_command
(
client
,
VND_CMD_RESET
,
0
);
if
(
error
)
{
dev_err
(
&
client
->
dev
,
"reset failed
\n
"
);
return
error
;
}
/* Wait the device to be ready */
msleep
(
200
);
return
0
;
}
static
const
void
*
wdt87xx_get_fw_chunk
(
const
struct
firmware
*
fw
,
u32
id
)
{
size_t
pos
=
FW_PAYLOAD_OFFSET
;
u32
chunk_id
,
chunk_size
;
while
(
pos
<
fw
->
size
)
{
chunk_id
=
get_unaligned_le32
(
fw
->
data
+
pos
+
FW_CHUNK_ID_OFFSET
);
if
(
chunk_id
==
id
)
return
fw
->
data
+
pos
;
chunk_size
=
get_unaligned_le32
(
fw
->
data
+
pos
+
FW_CHUNK_SIZE_OFFSET
);
pos
+=
chunk_size
+
2
*
sizeof
(
u32
);
/* chunk ID + size */
}
return
NULL
;
}
static
int
wdt87xx_get_sysparam
(
struct
i2c_client
*
client
,
struct
wdt87xx_sys_param
*
param
)
{
u8
buf
[
PKT_READ_SIZE
];
int
error
;
error
=
wdt87xx_get_string
(
client
,
STRIDX_PARAMETERS
,
buf
,
34
);
if
(
error
)
{
dev_err
(
&
client
->
dev
,
"failed to get parameters
\n
"
);
return
error
;
}
param
->
xmls_id1
=
get_unaligned_le16
(
buf
+
CTL_PARAM_OFFSET_XMLS_ID1
);
param
->
xmls_id2
=
get_unaligned_le16
(
buf
+
CTL_PARAM_OFFSET_XMLS_ID2
);
param
->
phy_ch_x
=
get_unaligned_le16
(
buf
+
CTL_PARAM_OFFSET_PHY_CH_X
);
param
->
phy_ch_y
=
get_unaligned_le16
(
buf
+
CTL_PARAM_OFFSET_PHY_CH_Y
);
param
->
phy_w
=
get_unaligned_le16
(
buf
+
CTL_PARAM_OFFSET_PHY_W
)
/
10
;
param
->
phy_h
=
get_unaligned_le16
(
buf
+
CTL_PARAM_OFFSET_PHY_H
)
/
10
;
/* Get the scaling factor of pixel to logical coordinate */
param
->
scaling_factor
=
get_unaligned_le16
(
buf
+
CTL_PARAM_OFFSET_FACTOR
);
param
->
max_x
=
MAX_UNIT_AXIS
;
param
->
max_y
=
DIV_ROUND_CLOSEST
(
MAX_UNIT_AXIS
*
param
->
phy_h
,
param
->
phy_w
);
error
=
wdt87xx_get_string
(
client
,
STRIDX_PLATFORM_ID
,
buf
,
8
);
if
(
error
)
{
dev_err
(
&
client
->
dev
,
"failed to get platform id
\n
"
);
return
error
;
}
param
->
plat_id
=
buf
[
1
];
buf
[
0
]
=
0xf2
;
error
=
wdt87xx_get_feature
(
client
,
buf
,
16
);
if
(
error
)
{
dev_err
(
&
client
->
dev
,
"failed to get firmware id
\n
"
);
return
error
;
}
if
(
buf
[
0
]
!=
0xf2
)
{
dev_err
(
&
client
->
dev
,
"wrong id of fw response: 0x%x
\n
"
,
buf
[
0
]);
return
-
EINVAL
;
}
param
->
fw_id
=
get_unaligned_le16
(
&
buf
[
1
]);
dev_info
(
&
client
->
dev
,
"fw_id: 0x%x, plat_id: 0x%x, xml_id1: %04x, xml_id2: %04x
\n
"
,
param
->
fw_id
,
param
->
plat_id
,
param
->
xmls_id1
,
param
->
xmls_id2
);
return
0
;
}
static
int
wdt87xx_validate_firmware
(
struct
wdt87xx_data
*
wdt
,
const
struct
firmware
*
fw
)
{
const
void
*
fw_chunk
;
u32
data1
,
data2
;
u32
size
;
u8
fw_chip_id
;
u8
chip_id
;
data1
=
get_unaligned_le32
(
fw
->
data
+
FW_FOURCC1_OFFSET
);
data2
=
get_unaligned_le32
(
fw
->
data
+
FW_FOURCC2_OFFSET
);
if
(
data1
!=
FOURCC_ID_RIFF
||
data2
!=
FOURCC_ID_WHIF
)
{
dev_err
(
&
wdt
->
client
->
dev
,
"check fw tag failed
\n
"
);
return
-
EINVAL
;
}
size
=
get_unaligned_le32
(
fw
->
data
+
FW_SIZE_OFFSET
);
if
(
size
!=
fw
->
size
)
{
dev_err
(
&
wdt
->
client
->
dev
,
"fw size mismatch: expected %d, actual %zu
\n
"
,
size
,
fw
->
size
);
return
-
EINVAL
;
}
/*
* Get the chip_id from the firmware. Make sure that it is the
* right controller to do the firmware and config update.
*/
fw_chunk
=
wdt87xx_get_fw_chunk
(
fw
,
CHUNK_ID_FRWR
);
if
(
!
fw_chunk
)
{
dev_err
(
&
wdt
->
client
->
dev
,
"unable to locate firmware chunk
\n
"
);
return
-
EINVAL
;
}
fw_chip_id
=
(
get_unaligned_le32
(
fw_chunk
+
FW_CHUNK_VERSION_OFFSET
)
>>
12
)
&
0xF
;
chip_id
=
(
wdt
->
param
.
fw_id
>>
12
)
&
0xF
;
if
(
fw_chip_id
!=
chip_id
)
{
dev_err
(
&
wdt
->
client
->
dev
,
"fw version mismatch: fw %d vs. chip %d
\n
"
,
fw_chip_id
,
chip_id
);
return
-
ENODEV
;
}
return
0
;
}
static
int
wdt87xx_validate_fw_chunk
(
const
void
*
data
,
int
id
)
{
if
(
id
==
CHUNK_ID_FRWR
)
{
u32
fw_id
;
fw_id
=
get_unaligned_le32
(
data
+
FW_CHUNK_PAYLOAD_OFFSET
);
if
(
fw_id
!=
WDT_FIRMWARE_ID
)
return
-
EINVAL
;
}
return
0
;
}
static
int
wdt87xx_write_data
(
struct
i2c_client
*
client
,
const
char
*
data
,
u32
address
,
int
length
)
{
u16
packet_size
;
int
count
=
0
;
int
error
;
u8
pkt_buf
[
PKT_BUF_SIZE
];
/* Address and length should be 4 bytes aligned */
if
((
address
&
0x3
)
!=
0
||
(
length
&
0x3
)
!=
0
)
{
dev_err
(
&
client
->
dev
,
"addr & len must be 4 bytes aligned %x, %x
\n
"
,
address
,
length
);
return
-
EINVAL
;
}
while
(
length
)
{
packet_size
=
min
(
length
,
PACKET_SIZE
);
pkt_buf
[
CMD_REPORT_ID_OFFSET
]
=
VND_REQ_WRITE
;
pkt_buf
[
CMD_TYPE_OFFSET
]
=
VND_SET_DATA
;
put_unaligned_le16
(
packet_size
,
&
pkt_buf
[
CMD_INDEX_OFFSET
]);
put_unaligned_le32
(
address
,
&
pkt_buf
[
CMD_LENGTH_OFFSET
]);
memcpy
(
&
pkt_buf
[
CMD_DATA_OFFSET
],
data
,
packet_size
);
error
=
wdt87xx_set_feature
(
client
,
pkt_buf
,
sizeof
(
pkt_buf
));
if
(
error
)
return
error
;
length
-=
packet_size
;
data
+=
packet_size
;
address
+=
packet_size
;
/* Wait for the controller to finish the write */
mdelay
(
WDT_FLASH_WRITE_DELAY_MS
);
if
((
++
count
%
32
)
==
0
)
{
/* Delay for fw to clear watch dog */
msleep
(
20
);
}
}
return
0
;
}
static
u16
misr
(
u16
cur_value
,
u8
new_value
)
{
u32
a
,
b
;
u32
bit0
;
u32
y
;
a
=
cur_value
;
b
=
new_value
;
bit0
=
a
^
(
b
&
1
);
bit0
^=
a
>>
1
;
bit0
^=
a
>>
2
;
bit0
^=
a
>>
4
;
bit0
^=
a
>>
5
;
bit0
^=
a
>>
7
;
bit0
^=
a
>>
11
;
bit0
^=
a
>>
15
;
y
=
(
a
<<
1
)
^
b
;
y
=
(
y
&
~
1
)
|
(
bit0
&
1
);
return
(
u16
)
y
;
}
static
u16
wdt87xx_calculate_checksum
(
const
u8
*
data
,
size_t
length
)
{
u16
checksum
=
0
;
size_t
i
;
for
(
i
=
0
;
i
<
length
;
i
++
)
checksum
=
misr
(
checksum
,
data
[
i
]);
return
checksum
;
}
static
int
wdt87xx_get_checksum
(
struct
i2c_client
*
client
,
u16
*
checksum
,
u32
address
,
int
length
)
{
int
error
;
int
time_delay
;
u8
pkt_buf
[
PKT_BUF_SIZE
];
u8
cmd_buf
[
CMD_BUF_SIZE
];
error
=
wdt87xx_send_command
(
client
,
VND_SET_CHECKSUM_LENGTH
,
length
);
if
(
error
)
{
dev_err
(
&
client
->
dev
,
"failed to set checksum length
\n
"
);
return
error
;
}
error
=
wdt87xx_send_command
(
client
,
VND_SET_CHECKSUM_CALC
,
address
);
if
(
error
)
{
dev_err
(
&
client
->
dev
,
"failed to set checksum address
\n
"
);
return
error
;
}
/* Wait the operation to complete */
time_delay
=
DIV_ROUND_UP
(
length
,
1024
);
msleep
(
time_delay
*
30
);
memset
(
cmd_buf
,
0
,
sizeof
(
cmd_buf
));
cmd_buf
[
CMD_REPORT_ID_OFFSET
]
=
VND_REQ_READ
;
cmd_buf
[
CMD_TYPE_OFFSET
]
=
VND_GET_CHECKSUM
;
error
=
wdt87xx_set_feature
(
client
,
cmd_buf
,
sizeof
(
cmd_buf
));
if
(
error
)
{
dev_err
(
&
client
->
dev
,
"failed to request checksum
\n
"
);
return
error
;
}
memset
(
pkt_buf
,
0
,
sizeof
(
pkt_buf
));
pkt_buf
[
CMD_REPORT_ID_OFFSET
]
=
VND_READ_DATA
;
error
=
wdt87xx_get_feature
(
client
,
pkt_buf
,
sizeof
(
pkt_buf
));
if
(
error
)
{
dev_err
(
&
client
->
dev
,
"failed to read checksum
\n
"
);
return
error
;
}
*
checksum
=
get_unaligned_le16
(
&
pkt_buf
[
CMD_DATA_OFFSET
]);
return
0
;
}
static
int
wdt87xx_write_firmware
(
struct
i2c_client
*
client
,
const
void
*
chunk
)
{
u32
start_addr
=
get_unaligned_le32
(
chunk
+
FW_CHUNK_TGT_START_OFFSET
);
u32
size
=
get_unaligned_le32
(
chunk
+
FW_CHUNK_PAYLOAD_LEN_OFFSET
);
const
void
*
data
=
chunk
+
FW_CHUNK_PAYLOAD_OFFSET
;
int
error
;
int
err1
;
int
page_size
;
int
retry
=
0
;
u16
device_checksum
,
firmware_checksum
;
dev_dbg
(
&
client
->
dev
,
"start 4k page program
\n
"
);
error
=
wdt87xx_send_command
(
client
,
VND_CMD_STOP
,
MODE_STOP
);
if
(
error
)
{
dev_err
(
&
client
->
dev
,
"stop report mode failed
\n
"
);
return
error
;
}
error
=
wdt87xx_send_command
(
client
,
VND_CMD_SFUNL
,
0
);
if
(
error
)
{
dev_err
(
&
client
->
dev
,
"unlock failed
\n
"
);
goto
out_enable_reporting
;
}
mdelay
(
10
);
while
(
size
)
{
dev_dbg
(
&
client
->
dev
,
"%s: %x, %x
\n
"
,
__func__
,
start_addr
,
size
);
page_size
=
min_t
(
u32
,
size
,
PG_SIZE
);
size
-=
page_size
;
for
(
retry
=
0
;
retry
<
MAX_RETRIES
;
retry
++
)
{
error
=
wdt87xx_send_command
(
client
,
VND_CMD_ERASE
,
start_addr
);
if
(
error
)
{
dev_err
(
&
client
->
dev
,
"erase failed at %#08x
\n
"
,
start_addr
);
break
;
}
msleep
(
50
);
error
=
wdt87xx_write_data
(
client
,
data
,
start_addr
,
page_size
);
if
(
error
)
{
dev_err
(
&
client
->
dev
,
"write failed at %#08x (%d bytes)
\n
"
,
start_addr
,
page_size
);
break
;
}
error
=
wdt87xx_get_checksum
(
client
,
&
device_checksum
,
start_addr
,
page_size
);
if
(
error
)
{
dev_err
(
&
client
->
dev
,
"failed to retrieve checksum for %#08x (len: %d)
\n
"
,
start_addr
,
page_size
);
break
;
}
firmware_checksum
=
wdt87xx_calculate_checksum
(
data
,
page_size
);
if
(
device_checksum
==
firmware_checksum
)
break
;
dev_err
(
&
client
->
dev
,
"checksum fail: %d vs %d, retry %d
\n
"
,
device_checksum
,
firmware_checksum
,
retry
);
}
if
(
retry
==
MAX_RETRIES
)
{
dev_err
(
&
client
->
dev
,
"page write failed
\n
"
);
error
=
-
EIO
;
goto
out_lock_device
;
}
start_addr
=
start_addr
+
page_size
;
data
=
data
+
page_size
;
}
out_lock_device:
err1
=
wdt87xx_send_command
(
client
,
VND_CMD_SFLCK
,
0
);
if
(
err1
)
dev_err
(
&
client
->
dev
,
"lock failed
\n
"
);
mdelay
(
10
);
out_enable_reporting:
err1
=
wdt87xx_send_command
(
client
,
VND_CMD_START
,
0
);
if
(
err1
)
dev_err
(
&
client
->
dev
,
"start to report failed
\n
"
);
return
error
?
error
:
err1
;
}
static
int
wdt87xx_load_chunk
(
struct
i2c_client
*
client
,
const
struct
firmware
*
fw
,
u32
ck_id
)
{
const
void
*
chunk
;
int
error
;
chunk
=
wdt87xx_get_fw_chunk
(
fw
,
ck_id
);
if
(
!
chunk
)
{
dev_err
(
&
client
->
dev
,
"unable to locate chunk (type %d)
\n
"
,
ck_id
);
return
-
EINVAL
;
}
error
=
wdt87xx_validate_fw_chunk
(
chunk
,
ck_id
);
if
(
error
)
{
dev_err
(
&
client
->
dev
,
"invalid chunk (type %d): %d
\n
"
,
ck_id
,
error
);
return
error
;
}
error
=
wdt87xx_write_firmware
(
client
,
chunk
);
if
(
error
)
{
dev_err
(
&
client
->
dev
,
"failed to write fw chunk (type %d): %d
\n
"
,
ck_id
,
error
);
return
error
;
}
return
0
;
}
static
int
wdt87xx_do_update_firmware
(
struct
i2c_client
*
client
,
const
struct
firmware
*
fw
,
unsigned
int
chunk_id
)
{
struct
wdt87xx_data
*
wdt
=
i2c_get_clientdata
(
client
);
int
error
;
error
=
wdt87xx_validate_firmware
(
wdt
,
fw
);
if
(
error
)
return
error
;
error
=
mutex_lock_interruptible
(
&
wdt
->
fw_mutex
);
if
(
error
)
return
error
;
disable_irq
(
client
->
irq
);
error
=
wdt87xx_load_chunk
(
client
,
fw
,
chunk_id
);
if
(
error
)
{
dev_err
(
&
client
->
dev
,
"firmware load failed (type: %d): %d
\n
"
,
chunk_id
,
error
);
goto
out
;
}
error
=
wdt87xx_sw_reset
(
client
);
if
(
error
)
{
dev_err
(
&
client
->
dev
,
"soft reset failed: %d
\n
"
,
error
);
goto
out
;
}
/* Refresh the parameters */
error
=
wdt87xx_get_sysparam
(
client
,
&
wdt
->
param
);
if
(
error
)
dev_err
(
&
client
->
dev
,
"failed to refresh system paramaters: %d
\n
"
,
error
);
out:
enable_irq
(
client
->
irq
);
mutex_unlock
(
&
wdt
->
fw_mutex
);
return
error
?
error
:
0
;
}
static
int
wdt87xx_update_firmware
(
struct
device
*
dev
,
const
char
*
fw_name
,
unsigned
int
chunk_id
)
{
struct
i2c_client
*
client
=
to_i2c_client
(
dev
);
const
struct
firmware
*
fw
;
int
error
;
error
=
request_firmware
(
&
fw
,
fw_name
,
dev
);
if
(
error
)
{
dev_err
(
&
client
->
dev
,
"unable to retrieve firmware %s: %d
\n
"
,
fw_name
,
error
);
return
error
;
}
error
=
wdt87xx_do_update_firmware
(
client
,
fw
,
chunk_id
);
release_firmware
(
fw
);
return
error
?
error
:
0
;
}
static
ssize_t
config_csum_show
(
struct
device
*
dev
,
struct
device_attribute
*
attr
,
char
*
buf
)
{
struct
i2c_client
*
client
=
to_i2c_client
(
dev
);
struct
wdt87xx_data
*
wdt
=
i2c_get_clientdata
(
client
);
u32
cfg_csum
;
cfg_csum
=
wdt
->
param
.
xmls_id1
;
cfg_csum
=
(
cfg_csum
<<
16
)
|
wdt
->
param
.
xmls_id2
;
return
scnprintf
(
buf
,
PAGE_SIZE
,
"%x
\n
"
,
cfg_csum
);
}
static
ssize_t
fw_version_show
(
struct
device
*
dev
,
struct
device_attribute
*
attr
,
char
*
buf
)
{
struct
i2c_client
*
client
=
to_i2c_client
(
dev
);
struct
wdt87xx_data
*
wdt
=
i2c_get_clientdata
(
client
);
return
scnprintf
(
buf
,
PAGE_SIZE
,
"%x
\n
"
,
wdt
->
param
.
fw_id
);
}
static
ssize_t
plat_id_show
(
struct
device
*
dev
,
struct
device_attribute
*
attr
,
char
*
buf
)
{
struct
i2c_client
*
client
=
to_i2c_client
(
dev
);
struct
wdt87xx_data
*
wdt
=
i2c_get_clientdata
(
client
);
return
scnprintf
(
buf
,
PAGE_SIZE
,
"%x
\n
"
,
wdt
->
param
.
plat_id
);
}
static
ssize_t
update_config_store
(
struct
device
*
dev
,
struct
device_attribute
*
attr
,
const
char
*
buf
,
size_t
count
)
{
int
error
;
error
=
wdt87xx_update_firmware
(
dev
,
WDT87XX_CFG_NAME
,
CHUNK_ID_CNFG
);
return
error
?
error
:
count
;
}
static
ssize_t
update_fw_store
(
struct
device
*
dev
,
struct
device_attribute
*
attr
,
const
char
*
buf
,
size_t
count
)
{
int
error
;
error
=
wdt87xx_update_firmware
(
dev
,
WDT87XX_FW_NAME
,
CHUNK_ID_FRWR
);
return
error
?
error
:
count
;
}
static
DEVICE_ATTR_RO
(
config_csum
);
static
DEVICE_ATTR_RO
(
fw_version
);
static
DEVICE_ATTR_RO
(
plat_id
);
static
DEVICE_ATTR_WO
(
update_config
);
static
DEVICE_ATTR_WO
(
update_fw
);
static
struct
attribute
*
wdt87xx_attrs
[]
=
{
&
dev_attr_config_csum
.
attr
,
&
dev_attr_fw_version
.
attr
,
&
dev_attr_plat_id
.
attr
,
&
dev_attr_update_config
.
attr
,
&
dev_attr_update_fw
.
attr
,
NULL
};
static
const
struct
attribute_group
wdt87xx_attr_group
=
{
.
attrs
=
wdt87xx_attrs
,
};
static
void
wdt87xx_report_contact
(
struct
input_dev
*
input
,
struct
wdt87xx_sys_param
*
param
,
u8
*
buf
)
{
int
finger_id
;
u32
x
,
y
,
w
;
u8
p
;
finger_id
=
(
buf
[
FINGER_EV_V1_OFFSET_ID
]
>>
3
)
-
1
;
if
(
finger_id
<
0
)
return
;
/* Check if this is an active contact */
if
(
!
(
buf
[
FINGER_EV_V1_OFFSET_ID
]
&
0x1
))
return
;
w
=
buf
[
FINGER_EV_V1_OFFSET_W
];
w
*=
param
->
scaling_factor
;
p
=
buf
[
FINGER_EV_V1_OFFSET_P
];
x
=
get_unaligned_le16
(
buf
+
FINGER_EV_V1_OFFSET_X
);
y
=
get_unaligned_le16
(
buf
+
FINGER_EV_V1_OFFSET_Y
);
y
=
DIV_ROUND_CLOSEST
(
y
*
param
->
phy_h
,
param
->
phy_w
);
/* Refuse incorrect coordinates */
if
(
x
>
param
->
max_x
||
y
>
param
->
max_y
)
return
;
dev_dbg
(
input
->
dev
.
parent
,
"tip on (%d), x(%d), y(%d)
\n
"
,
finger_id
,
x
,
y
);
input_mt_slot
(
input
,
finger_id
);
input_mt_report_slot_state
(
input
,
MT_TOOL_FINGER
,
1
);
input_report_abs
(
input
,
ABS_MT_TOUCH_MAJOR
,
w
);
input_report_abs
(
input
,
ABS_MT_PRESSURE
,
p
);
input_report_abs
(
input
,
ABS_MT_POSITION_X
,
x
);
input_report_abs
(
input
,
ABS_MT_POSITION_Y
,
y
);
}
static
irqreturn_t
wdt87xx_ts_interrupt
(
int
irq
,
void
*
dev_id
)
{
struct
wdt87xx_data
*
wdt
=
dev_id
;
struct
i2c_client
*
client
=
wdt
->
client
;
int
i
,
fingers
;
int
error
;
u8
raw_buf
[
WDT_V1_RAW_BUF_COUNT
]
=
{
0
};
error
=
i2c_master_recv
(
client
,
raw_buf
,
WDT_V1_RAW_BUF_COUNT
);
if
(
error
<
0
)
{
dev_err
(
&
client
->
dev
,
"read v1 raw data failed: %d
\n
"
,
error
);
goto
irq_exit
;
}
fingers
=
raw_buf
[
TOUCH_PK_V1_OFFSET_FNGR_NUM
];
if
(
!
fingers
)
goto
irq_exit
;
for
(
i
=
0
;
i
<
WDT_MAX_FINGER
;
i
++
)
wdt87xx_report_contact
(
wdt
->
input
,
&
wdt
->
param
,
&
raw_buf
[
TOUCH_PK_V1_OFFSET_EVENT
+
i
*
FINGER_EV_V1_SIZE
]);
input_mt_sync_frame
(
wdt
->
input
);
input_sync
(
wdt
->
input
);
irq_exit:
return
IRQ_HANDLED
;
}
static
int
wdt87xx_ts_create_input_device
(
struct
wdt87xx_data
*
wdt
)
{
struct
device
*
dev
=
&
wdt
->
client
->
dev
;
struct
input_dev
*
input
;
unsigned
int
res
=
DIV_ROUND_CLOSEST
(
MAX_UNIT_AXIS
,
wdt
->
param
.
phy_w
);
int
error
;
input
=
devm_input_allocate_device
(
dev
);
if
(
!
input
)
{
dev_err
(
dev
,
"failed to allocate input device
\n
"
);
return
-
ENOMEM
;
}
wdt
->
input
=
input
;
input
->
name
=
"WDT87xx Touchscreen"
;
input
->
id
.
bustype
=
BUS_I2C
;
input
->
phys
=
wdt
->
phys
;
input_set_abs_params
(
input
,
ABS_MT_POSITION_X
,
0
,
wdt
->
param
.
max_x
,
0
,
0
);
input_set_abs_params
(
input
,
ABS_MT_POSITION_Y
,
0
,
wdt
->
param
.
max_y
,
0
,
0
);
input_abs_set_res
(
input
,
ABS_MT_POSITION_X
,
res
);
input_abs_set_res
(
input
,
ABS_MT_POSITION_Y
,
res
);
input_set_abs_params
(
input
,
ABS_MT_TOUCH_MAJOR
,
0
,
wdt
->
param
.
max_x
,
0
,
0
);
input_set_abs_params
(
input
,
ABS_MT_PRESSURE
,
0
,
0xFF
,
0
,
0
);
input_mt_init_slots
(
input
,
WDT_MAX_FINGER
,
INPUT_MT_DIRECT
|
INPUT_MT_DROP_UNUSED
);
error
=
input_register_device
(
input
);
if
(
error
)
{
dev_err
(
dev
,
"failed to register input device: %d
\n
"
,
error
);
return
error
;
}
return
0
;
}
static
int
wdt87xx_ts_probe
(
struct
i2c_client
*
client
,
const
struct
i2c_device_id
*
id
)
{
struct
wdt87xx_data
*
wdt
;
int
error
;
dev_dbg
(
&
client
->
dev
,
"adapter=%d, client irq: %d
\n
"
,
client
->
adapter
->
nr
,
client
->
irq
);
/* Check if the I2C function is ok in this adaptor */
if
(
!
i2c_check_functionality
(
client
->
adapter
,
I2C_FUNC_I2C
))
return
-
ENXIO
;
wdt
=
devm_kzalloc
(
&
client
->
dev
,
sizeof
(
*
wdt
),
GFP_KERNEL
);
if
(
!
wdt
)
return
-
ENOMEM
;
wdt
->
client
=
client
;
mutex_init
(
&
wdt
->
fw_mutex
);
i2c_set_clientdata
(
client
,
wdt
);
snprintf
(
wdt
->
phys
,
sizeof
(
wdt
->
phys
),
"i2c-%u-%04x/input0"
,
client
->
adapter
->
nr
,
client
->
addr
);
error
=
wdt87xx_get_sysparam
(
client
,
&
wdt
->
param
);
if
(
error
)
return
error
;
error
=
wdt87xx_ts_create_input_device
(
wdt
);
if
(
error
)
return
error
;
error
=
devm_request_threaded_irq
(
&
client
->
dev
,
client
->
irq
,
NULL
,
wdt87xx_ts_interrupt
,
IRQF_ONESHOT
,
client
->
name
,
wdt
);
if
(
error
)
{
dev_err
(
&
client
->
dev
,
"request irq failed: %d
\n
"
,
error
);
return
error
;
}
error
=
sysfs_create_group
(
&
client
->
dev
.
kobj
,
&
wdt87xx_attr_group
);
if
(
error
)
{
dev_err
(
&
client
->
dev
,
"create sysfs failed: %d
\n
"
,
error
);
return
error
;
}
return
0
;
}
static
int
wdt87xx_ts_remove
(
struct
i2c_client
*
client
)
{
sysfs_remove_group
(
&
client
->
dev
.
kobj
,
&
wdt87xx_attr_group
);
return
0
;
}
static
int
__maybe_unused
wdt87xx_suspend
(
struct
device
*
dev
)
{
struct
i2c_client
*
client
=
to_i2c_client
(
dev
);
int
error
;
disable_irq
(
client
->
irq
);
error
=
wdt87xx_send_command
(
client
,
VND_CMD_STOP
,
MODE_IDLE
);
if
(
error
)
{
enable_irq
(
client
->
irq
);
dev_err
(
&
client
->
dev
,
"failed to stop device when suspending: %d
\n
"
,
error
);
return
error
;
}
return
0
;
}
static
int
__maybe_unused
wdt87xx_resume
(
struct
device
*
dev
)
{
struct
i2c_client
*
client
=
to_i2c_client
(
dev
);
int
error
;
/*
* The chip may have been reset while system is resuming,
* give it some time to settle.
*/
mdelay
(
100
);
error
=
wdt87xx_send_command
(
client
,
VND_CMD_START
,
0
);
if
(
error
)
dev_err
(
&
client
->
dev
,
"failed to start device when resuming: %d
\n
"
,
error
);
enable_irq
(
client
->
irq
);
return
0
;
}
static
SIMPLE_DEV_PM_OPS
(
wdt87xx_pm_ops
,
wdt87xx_suspend
,
wdt87xx_resume
);
static
const
struct
i2c_device_id
wdt87xx_dev_id
[]
=
{
{
WDT87XX_NAME
,
0
},
{
}
};
MODULE_DEVICE_TABLE
(
i2c
,
wdt87xx_dev_id
);
static
const
struct
acpi_device_id
wdt87xx_acpi_id
[]
=
{
{
"WDHT0001"
,
0
},
{
}
};
MODULE_DEVICE_TABLE
(
acpi
,
wdt87xx_acpi_id
);
static
struct
i2c_driver
wdt87xx_driver
=
{
.
probe
=
wdt87xx_ts_probe
,
.
remove
=
wdt87xx_ts_remove
,
.
id_table
=
wdt87xx_dev_id
,
.
driver
=
{
.
name
=
WDT87XX_NAME
,
.
pm
=
&
wdt87xx_pm_ops
,
.
acpi_match_table
=
ACPI_PTR
(
wdt87xx_acpi_id
),
},
};
module_i2c_driver
(
wdt87xx_driver
);
MODULE_AUTHOR
(
"HN Chen <hn.chen@weidahitech.com>"
);
MODULE_DESCRIPTION
(
"WeidaHiTech WDT87XX Touchscreen driver"
);
MODULE_VERSION
(
WDT87XX_DRV_VER
);
MODULE_LICENSE
(
"GPL"
);
include/linux/input/touchscreen.h
浏览文件 @
a5cba18c
...
...
@@ -12,9 +12,10 @@
#include <linux/input.h>
#ifdef CONFIG_OF
void
touchscreen_parse_of_params
(
struct
input_dev
*
dev
);
void
touchscreen_parse_of_params
(
struct
input_dev
*
dev
,
bool
multitouch
);
#else
static
inline
void
touchscreen_parse_of_params
(
struct
input_dev
*
dev
)
static
inline
void
touchscreen_parse_of_params
(
struct
input_dev
*
dev
,
bool
multitouch
)
{
}
#endif
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录