Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
linux
Commits
08088828
Commit
08088828
authored
Jul 26, 2016
by
Dmitry Torokhov
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'next' into for-linus
Prepare first round of input updates for 4.8 merge window.
parents
e9003c9c
0097ff3d
Changes
42
Hide whitespace changes
Inline
Side-by-side
Showing
42 changed files
with
2932 additions
and
139 deletions
+2932
-139
Documentation/devicetree/bindings/input/atmel,captouch.txt
Documentation/devicetree/bindings/input/atmel,captouch.txt
+36
-0
Documentation/devicetree/bindings/input/raydium_i2c_ts.txt
Documentation/devicetree/bindings/input/raydium_i2c_ts.txt
+20
-0
Documentation/devicetree/bindings/input/rmi4/rmi_i2c.txt
Documentation/devicetree/bindings/input/rmi4/rmi_i2c.txt
+9
-0
Documentation/devicetree/bindings/vendor-prefixes.txt
Documentation/devicetree/bindings/vendor-prefixes.txt
+1
-0
drivers/input/input-mt.c
drivers/input/input-mt.c
+16
-1
drivers/input/input.c
drivers/input/input.c
+3
-4
drivers/input/keyboard/tc3589x-keypad.c
drivers/input/keyboard/tc3589x-keypad.c
+1
-1
drivers/input/keyboard/tegra-kbc.c
drivers/input/keyboard/tegra-kbc.c
+1
-1
drivers/input/misc/Kconfig
drivers/input/misc/Kconfig
+23
-0
drivers/input/misc/Makefile
drivers/input/misc/Makefile
+2
-0
drivers/input/misc/apanel.c
drivers/input/misc/apanel.c
+1
-1
drivers/input/misc/atmel_captouch.c
drivers/input/misc/atmel_captouch.c
+290
-0
drivers/input/misc/hisi_powerkey.c
drivers/input/misc/hisi_powerkey.c
+142
-0
drivers/input/misc/regulator-haptic.c
drivers/input/misc/regulator-haptic.c
+1
-1
drivers/input/misc/xen-kbdfront.c
drivers/input/misc/xen-kbdfront.c
+4
-4
drivers/input/mouse/elantech.c
drivers/input/mouse/elantech.c
+1
-1
drivers/input/mouse/lifebook.c
drivers/input/mouse/lifebook.c
+1
-1
drivers/input/rmi4/rmi_f01.c
drivers/input/rmi4/rmi_f01.c
+11
-11
drivers/input/rmi4/rmi_f11.c
drivers/input/rmi4/rmi_f11.c
+3
-6
drivers/input/rmi4/rmi_f12.c
drivers/input/rmi4/rmi_f12.c
+0
-1
drivers/input/rmi4/rmi_i2c.c
drivers/input/rmi4/rmi_i2c.c
+46
-0
drivers/input/serio/ams_delta_serio.c
drivers/input/serio/ams_delta_serio.c
+1
-1
drivers/input/tablet/Kconfig
drivers/input/tablet/Kconfig
+15
-0
drivers/input/tablet/Makefile
drivers/input/tablet/Makefile
+1
-0
drivers/input/tablet/pegasus_notetaker.c
drivers/input/tablet/pegasus_notetaker.c
+450
-0
drivers/input/touchscreen/Kconfig
drivers/input/touchscreen/Kconfig
+27
-1
drivers/input/touchscreen/Makefile
drivers/input/touchscreen/Makefile
+2
-0
drivers/input/touchscreen/ad7879.c
drivers/input/touchscreen/ad7879.c
+1
-1
drivers/input/touchscreen/chipone_icn8318.c
drivers/input/touchscreen/chipone_icn8318.c
+14
-47
drivers/input/touchscreen/cyttsp_core.c
drivers/input/touchscreen/cyttsp_core.c
+1
-1
drivers/input/touchscreen/edt-ft5x06.c
drivers/input/touchscreen/edt-ft5x06.c
+4
-3
drivers/input/touchscreen/migor_ts.c
drivers/input/touchscreen/migor_ts.c
+3
-3
drivers/input/touchscreen/of_touchscreen.c
drivers/input/touchscreen/of_touchscreen.c
+80
-1
drivers/input/touchscreen/pixcir_i2c_ts.c
drivers/input/touchscreen/pixcir_i2c_ts.c
+20
-33
drivers/input/touchscreen/raydium_i2c_ts.c
drivers/input/touchscreen/raydium_i2c_ts.c
+1238
-0
drivers/input/touchscreen/surface3_spi.c
drivers/input/touchscreen/surface3_spi.c
+427
-0
drivers/input/touchscreen/ti_am335x_tsc.c
drivers/input/touchscreen/ti_am335x_tsc.c
+1
-1
drivers/input/touchscreen/tsc200x-core.c
drivers/input/touchscreen/tsc200x-core.c
+1
-1
drivers/input/touchscreen/wacom_w8001.c
drivers/input/touchscreen/wacom_w8001.c
+9
-1
drivers/tty/vt/keyboard.c
drivers/tty/vt/keyboard.c
+4
-10
include/linux/input.h
include/linux/input.h
+1
-1
include/linux/input/touchscreen.h
include/linux/input/touchscreen.h
+20
-1
No files found.
Documentation/devicetree/bindings/input/atmel,captouch.txt
0 → 100644
View file @
08088828
Device tree bindings for Atmel capacitive touch device, typically
an Atmel touch sensor connected to AtmegaXX MCU running firmware
based on Qtouch library.
The node for this device must be a child of a I2C controller node, as the
device communicates via I2C.
Required properties:
compatible: Must be "atmel,captouch".
reg: The I2C slave address of the device.
interrupts: Property describing the interrupt line the device
is connected to. The device only has one interrupt
source.
linux,keycodes: Specifies an array of numeric keycode values to
be used for reporting button presses. The array can
contain up to 8 entries.
Optional properties:
autorepeat: Enables the Linux input system's autorepeat
feature on the input device.
Example:
atmel-captouch@51 {
compatible = "atmel,captouch";
reg = <0x51>;
interrupt-parent = <&tlmm>;
interrupts = <67 IRQ_TYPE_EDGE_FALLING>;
linux,keycodes = <BTN_0>, <BTN_1>,
<BTN_2>, <BTN_3>,
<BTN_4>, <BTN_5>,
<BTN_6>, <BTN_7>;
autorepeat;
};
Documentation/devicetree/bindings/input/raydium_i2c_ts.txt
0 → 100644
View file @
08088828
Raydium I2C touchscreen
Required properties:
- compatible: must be "raydium,rm32380"
- reg: The I2C address of the device
- interrupt-parent: the phandle for the interrupt controller
- interrupts: interrupt to which the chip is connected
See ../interrupt-controller/interrupts.txt
Optional properties:
- avdd-supply: analog power supply needed to power device
- vccio-supply: IO Power source
- reset-gpios: reset gpio the chip is connected to.
Example:
touchscreen@39 {
compatible = "raydium,rm32380";
reg = <0x39>;
interrupt-parent = <&gpio>;
interrupts = <0x0 IRQ_TYPE_EDGE_FALLING>;
};
Documentation/devicetree/bindings/input/rmi4/rmi_i2c.txt
View file @
08088828
...
...
@@ -22,6 +22,15 @@ See Documentation/devicetree/bindings/interrupt-controller/interrupts.txt
- syna,reset-delay-ms: The number of milliseconds to wait after resetting the
device.
- syna,startup-delay-ms: The number of milliseconds to wait after powering on
the device.
- vdd-supply: VDD power supply.
See ../regulator/regulator.txt
- vio-supply: VIO power supply
See ../regulator/regulator.txt
Function Parameters:
Parameters specific to RMI functions are contained in child nodes of the rmi device
node. Documentation for the parameters of each function can be found in:
...
...
Documentation/devicetree/bindings/vendor-prefixes.txt
View file @
08088828
...
...
@@ -198,6 +198,7 @@ raidsonic RaidSonic Technology GmbH
ralink Mediatek/Ralink Technology Corp.
ramtron Ramtron International
raspberrypi Raspberry Pi Foundation
raydium Raydium Semiconductor Corp.
realtek Realtek Semiconductor Corp.
renesas Renesas Electronics Corporation
richtek Richtek Technology Corporation
...
...
drivers/input/input-mt.c
View file @
08088828
...
...
@@ -218,8 +218,23 @@ void input_mt_report_pointer_emulation(struct input_dev *dev, bool use_count)
}
input_event
(
dev
,
EV_KEY
,
BTN_TOUCH
,
count
>
0
);
if
(
use_count
)
if
(
use_count
)
{
if
(
count
==
0
&&
!
test_bit
(
ABS_MT_DISTANCE
,
dev
->
absbit
)
&&
test_bit
(
ABS_DISTANCE
,
dev
->
absbit
)
&&
input_abs_get_val
(
dev
,
ABS_DISTANCE
)
!=
0
)
{
/*
* Force reporting BTN_TOOL_FINGER for devices that
* only report general hover (and not per-contact
* distance) when contact is in proximity but not
* on the surface.
*/
count
=
1
;
}
input_mt_report_finger_count
(
dev
,
count
);
}
if
(
oldest
)
{
int
x
=
input_mt_get_value
(
oldest
,
ABS_MT_POSITION_X
);
...
...
drivers/input/input.c
View file @
08088828
...
...
@@ -153,8 +153,6 @@ static void input_pass_values(struct input_dev *dev,
rcu_read_unlock
();
add_input_randomness
(
vals
->
type
,
vals
->
code
,
vals
->
value
);
/* trigger auto repeat for key events */
if
(
test_bit
(
EV_REP
,
dev
->
evbit
)
&&
test_bit
(
EV_KEY
,
dev
->
evbit
))
{
for
(
v
=
vals
;
v
!=
vals
+
count
;
v
++
)
{
...
...
@@ -371,9 +369,10 @@ static int input_get_disposition(struct input_dev *dev,
static
void
input_handle_event
(
struct
input_dev
*
dev
,
unsigned
int
type
,
unsigned
int
code
,
int
value
)
{
int
disposition
;
int
disposition
=
input_get_disposition
(
dev
,
type
,
code
,
&
value
)
;
disposition
=
input_get_disposition
(
dev
,
type
,
code
,
&
value
);
if
(
disposition
!=
INPUT_IGNORE_EVENT
&&
type
!=
EV_SYN
)
add_input_randomness
(
type
,
code
,
value
);
if
((
disposition
&
INPUT_PASS_TO_DEVICE
)
&&
dev
->
event
)
dev
->
event
(
dev
,
type
,
code
,
value
);
...
...
drivers/input/keyboard/tc3589x-keypad.c
View file @
08088828
...
...
@@ -32,7 +32,7 @@
#define TC3589x_PULL_DOWN_MASK 0x1
#define TC3589x_PULL_UP_MASK 0x2
#define TC3589x_PULLUP_ALL_MASK 0xAA
#define TC3589x_IO_PULL_VAL(index, mask) ((mask)<<((index)%4)*2)
)
#define TC3589x_IO_PULL_VAL(index, mask) ((mask)<<((index)%4)*2)
/* Bit masks for IOCFG register */
#define IOCFG_BALLCFG 0x01
...
...
drivers/input/keyboard/tegra-kbc.c
View file @
08088828
...
...
@@ -552,7 +552,7 @@ static int tegra_kbc_parse_dt(struct tegra_kbc *kbc)
if
(
!
num_rows
||
!
num_cols
||
((
num_rows
+
num_cols
)
>
KBC_MAX_GPIO
))
{
dev_err
(
kbc
->
dev
,
"keypad rows/columns not p
or
perly specified
\n
"
);
"keypad rows/columns not p
ro
perly specified
\n
"
);
return
-
EINVAL
;
}
...
...
drivers/input/misc/Kconfig
View file @
08088828
...
...
@@ -82,6 +82,20 @@ config INPUT_ARIZONA_HAPTICS
To compile this driver as a module, choose M here: the
module will be called arizona-haptics.
config INPUT_ATMEL_CAPTOUCH
tristate "Atmel Capacitive Touch Button Driver"
depends on OF || COMPILE_TEST
depends on I2C
help
Say Y here if an Atmel Capacitive Touch Button device which
implements "captouch" protocol is connected to I2C bus. Typically
this device consists of Atmel Touch sensor controlled by AtMegaXX
MCU running firmware based on Qtouch library.
One should find "atmel,captouch" node in the board specific DTS.
To compile this driver as a module, choose M here: the
module will be called atmel_captouch.
config INPUT_BMA150
tristate "BMA150/SMB380 acceleration sensor support"
depends on I2C
...
...
@@ -796,4 +810,13 @@ config INPUT_DRV2667_HAPTICS
To compile this driver as a module, choose M here: the
module will be called drv2667-haptics.
config INPUT_HISI_POWERKEY
tristate "Hisilicon PMIC ONKEY support"
depends on ARCH_HISI || COMPILE_TEST
help
Say Y to enable support for PMIC ONKEY.
To compile this driver as a module, choose M here: the
module will be called hisi_powerkey.
endif
drivers/input/misc/Makefile
View file @
08088828
...
...
@@ -17,6 +17,7 @@ obj-$(CONFIG_INPUT_APANEL) += apanel.o
obj-$(CONFIG_INPUT_ARIZONA_HAPTICS)
+=
arizona-haptics.o
obj-$(CONFIG_INPUT_ATI_REMOTE2)
+=
ati_remote2.o
obj-$(CONFIG_INPUT_ATLAS_BTNS)
+=
atlas_btns.o
obj-$(CONFIG_INPUT_ATMEL_CAPTOUCH)
+=
atmel_captouch.o
obj-$(CONFIG_INPUT_BFIN_ROTARY)
+=
bfin_rotary.o
obj-$(CONFIG_INPUT_BMA150)
+=
bma150.o
obj-$(CONFIG_INPUT_CM109)
+=
cm109.o
...
...
@@ -34,6 +35,7 @@ obj-$(CONFIG_INPUT_DRV2667_HAPTICS) += drv2667.o
obj-$(CONFIG_INPUT_GP2A)
+=
gp2ap002a00f.o
obj-$(CONFIG_INPUT_GPIO_BEEPER)
+=
gpio-beeper.o
obj-$(CONFIG_INPUT_GPIO_TILT_POLLED)
+=
gpio_tilt_polled.o
obj-$(CONFIG_INPUT_HISI_POWERKEY)
+=
hisi_powerkey.o
obj-$(CONFIG_HP_SDC_RTC)
+=
hp_sdc_rtc.o
obj-$(CONFIG_INPUT_IMS_PCU)
+=
ims-pcu.o
obj-$(CONFIG_INPUT_IXP4XX_BEEPER)
+=
ixp4xx-beeper.o
...
...
drivers/input/misc/apanel.c
View file @
08088828
...
...
@@ -297,7 +297,7 @@ static int __init apanel_init(void)
if
(
slave
!=
i2c_addr
)
{
pr_notice
(
APANEL
": only one SMBus slave "
"address supported, skiping device...
\n
"
);
"address supported, skip
p
ing device...
\n
"
);
continue
;
}
...
...
drivers/input/misc/atmel_captouch.c
0 → 100644
View file @
08088828
/*
* Atmel Atmegaxx Capacitive Touch Button Driver
*
* Copyright (C) 2016 Google, inc.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
/*
* It's irrelevant that the HW used to develop captouch driver is based
* on Atmega88PA part and uses QtouchADC parts for sensing touch.
* Calling this driver "captouch" is an arbitrary way to distinguish
* the protocol this driver supported by other atmel/qtouch drivers.
*
* Captouch driver supports a newer/different version of the I2C
* registers/commands than the qt1070.c driver.
* Don't let the similarity of the general driver structure fool you.
*
* For raw i2c access from userspace, use i2cset/i2cget
* to poke at /dev/i2c-N devices.
*/
#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/i2c.h>
#include <linux/input.h>
#include <linux/interrupt.h>
#include <linux/slab.h>
/* Maximum number of buttons supported */
#define MAX_NUM_OF_BUTTONS 8
/* Registers */
#define REG_KEY1_THRESHOLD 0x02
#define REG_KEY2_THRESHOLD 0x03
#define REG_KEY3_THRESHOLD 0x04
#define REG_KEY4_THRESHOLD 0x05
#define REG_KEY1_REF_H 0x20
#define REG_KEY1_REF_L 0x21
#define REG_KEY2_REF_H 0x22
#define REG_KEY2_REF_L 0x23
#define REG_KEY3_REF_H 0x24
#define REG_KEY3_REF_L 0x25
#define REG_KEY4_REF_H 0x26
#define REG_KEY4_REF_L 0x27
#define REG_KEY1_DLT_H 0x30
#define REG_KEY1_DLT_L 0x31
#define REG_KEY2_DLT_H 0x32
#define REG_KEY2_DLT_L 0x33
#define REG_KEY3_DLT_H 0x34
#define REG_KEY3_DLT_L 0x35
#define REG_KEY4_DLT_H 0x36
#define REG_KEY4_DLT_L 0x37
#define REG_KEY_STATE 0x3C
/*
* @i2c_client: I2C slave device client pointer
* @input: Input device pointer
* @num_btn: Number of buttons
* @keycodes: map of button# to KeyCode
* @prev_btn: Previous key state to detect button "press" or "release"
* @xfer_buf: I2C transfer buffer
*/
struct
atmel_captouch_device
{
struct
i2c_client
*
client
;
struct
input_dev
*
input
;
u32
num_btn
;
u32
keycodes
[
MAX_NUM_OF_BUTTONS
];
u8
prev_btn
;
u8
xfer_buf
[
8
]
____cacheline_aligned
;
};
/*
* Read from I2C slave device
* The protocol is that the client has to provide both the register address
* and the length, and while reading back the device would prepend the data
* with address and length for verification.
*/
static
int
atmel_read
(
struct
atmel_captouch_device
*
capdev
,
u8
reg
,
u8
*
data
,
size_t
len
)
{
struct
i2c_client
*
client
=
capdev
->
client
;
struct
device
*
dev
=
&
client
->
dev
;
struct
i2c_msg
msg
[
2
];
int
err
;
if
(
len
>
sizeof
(
capdev
->
xfer_buf
)
-
2
)
return
-
EINVAL
;
capdev
->
xfer_buf
[
0
]
=
reg
;
capdev
->
xfer_buf
[
1
]
=
len
;
msg
[
0
].
addr
=
client
->
addr
;
msg
[
0
].
flags
=
0
;
msg
[
0
].
buf
=
capdev
->
xfer_buf
;
msg
[
0
].
len
=
2
;
msg
[
1
].
addr
=
client
->
addr
;
msg
[
1
].
flags
=
I2C_M_RD
;
msg
[
1
].
buf
=
capdev
->
xfer_buf
;
msg
[
1
].
len
=
len
+
2
;
err
=
i2c_transfer
(
client
->
adapter
,
msg
,
ARRAY_SIZE
(
msg
));
if
(
err
!=
ARRAY_SIZE
(
msg
))
return
err
<
0
?
err
:
-
EIO
;
if
(
capdev
->
xfer_buf
[
0
]
!=
reg
)
{
dev_err
(
dev
,
"I2C read error: register address does not match (%#02x vs %02x)
\n
"
,
capdev
->
xfer_buf
[
0
],
reg
);
return
-
ECOMM
;
}
memcpy
(
data
,
&
capdev
->
xfer_buf
[
2
],
len
);
return
0
;
}
/*
* Handle interrupt and report the key changes to the input system.
* Multi-touch can be supported; however, it really depends on whether
* the device can multi-touch.
*/
static
irqreturn_t
atmel_captouch_isr
(
int
irq
,
void
*
data
)
{
struct
atmel_captouch_device
*
capdev
=
data
;
struct
device
*
dev
=
&
capdev
->
client
->
dev
;
int
error
;
int
i
;
u8
new_btn
;
u8
changed_btn
;
error
=
atmel_read
(
capdev
,
REG_KEY_STATE
,
&
new_btn
,
1
);
if
(
error
)
{
dev_err
(
dev
,
"failed to read button state: %d
\n
"
,
error
);
goto
out
;
}
dev_dbg
(
dev
,
"%s: button state %#02x
\n
"
,
__func__
,
new_btn
);
changed_btn
=
new_btn
^
capdev
->
prev_btn
;
capdev
->
prev_btn
=
new_btn
;
for
(
i
=
0
;
i
<
capdev
->
num_btn
;
i
++
)
{
if
(
changed_btn
&
BIT
(
i
))
input_report_key
(
capdev
->
input
,
capdev
->
keycodes
[
i
],
new_btn
&
BIT
(
i
));
}
input_sync
(
capdev
->
input
);
out:
return
IRQ_HANDLED
;
}
/*
* Probe function to setup the device, input system and interrupt
*/
static
int
atmel_captouch_probe
(
struct
i2c_client
*
client
,
const
struct
i2c_device_id
*
id
)
{
struct
atmel_captouch_device
*
capdev
;
struct
device
*
dev
=
&
client
->
dev
;
struct
device_node
*
node
;
int
i
;
int
err
;
if
(
!
i2c_check_functionality
(
client
->
adapter
,
I2C_FUNC_SMBUS_BYTE_DATA
|
I2C_FUNC_SMBUS_WORD_DATA
|
I2C_FUNC_SMBUS_I2C_BLOCK
))
{
dev_err
(
dev
,
"needed i2c functionality is not supported
\n
"
);
return
-
EINVAL
;
}
capdev
=
devm_kzalloc
(
dev
,
sizeof
(
*
capdev
),
GFP_KERNEL
);
if
(
!
capdev
)
return
-
ENOMEM
;
capdev
->
client
=
client
;
i2c_set_clientdata
(
client
,
capdev
);
err
=
atmel_read
(
capdev
,
REG_KEY_STATE
,
&
capdev
->
prev_btn
,
sizeof
(
capdev
->
prev_btn
));
if
(
err
)
{
dev_err
(
dev
,
"failed to read initial button state: %d
\n
"
,
err
);
return
err
;
}
capdev
->
input
=
devm_input_allocate_device
(
dev
);
if
(
!
capdev
->
input
)
{
dev_err
(
dev
,
"failed to allocate input device
\n
"
);
return
-
ENOMEM
;
}
capdev
->
input
->
id
.
bustype
=
BUS_I2C
;
capdev
->
input
->
id
.
product
=
0x880A
;
capdev
->
input
->
id
.
version
=
0
;
capdev
->
input
->
name
=
"ATMegaXX Capacitive Button Controller"
;
__set_bit
(
EV_KEY
,
capdev
->
input
->
evbit
);
node
=
dev
->
of_node
;
if
(
!
node
)
{
dev_err
(
dev
,
"failed to find matching node in device tree
\n
"
);
return
-
EINVAL
;
}
if
(
of_property_read_bool
(
node
,
"autorepeat"
))
__set_bit
(
EV_REP
,
capdev
->
input
->
evbit
);
capdev
->
num_btn
=
of_property_count_u32_elems
(
node
,
"linux,keymap"
);
if
(
capdev
->
num_btn
>
MAX_NUM_OF_BUTTONS
)
capdev
->
num_btn
=
MAX_NUM_OF_BUTTONS
;
err
=
of_property_read_u32_array
(
node
,
"linux,keycodes"
,
capdev
->
keycodes
,
capdev
->
num_btn
);
if
(
err
)
{
dev_err
(
dev
,
"failed to read linux,keycode property: %d
\n
"
,
err
);
return
err
;
}
for
(
i
=
0
;
i
<
capdev
->
num_btn
;
i
++
)
__set_bit
(
capdev
->
keycodes
[
i
],
capdev
->
input
->
keybit
);
capdev
->
input
->
keycode
=
capdev
->
keycodes
;
capdev
->
input
->
keycodesize
=
sizeof
(
capdev
->
keycodes
[
0
]);
capdev
->
input
->
keycodemax
=
capdev
->
num_btn
;
err
=
input_register_device
(
capdev
->
input
);
if
(
err
)
return
err
;
err
=
devm_request_threaded_irq
(
dev
,
client
->
irq
,
NULL
,
atmel_captouch_isr
,
IRQF_ONESHOT
,
"atmel_captouch"
,
capdev
);
if
(
err
)
{
dev_err
(
dev
,
"failed to request irq %d: %d
\n
"
,
client
->
irq
,
err
);
return
err
;
}
return
0
;
}
#ifdef CONFIG_OF
static
const
struct
of_device_id
atmel_captouch_of_id
[]
=
{
{
.
compatible
=
"atmel,captouch"
,
},
{
/* sentinel */
}
};
MODULE_DEVICE_TABLE
(
of
,
atmel_captouch_of_id
);
#endif
static
const
struct
i2c_device_id
atmel_captouch_id
[]
=
{
{
"atmel_captouch"
,
0
},
{
}
};
MODULE_DEVICE_TABLE
(
i2c
,
atmel_captouch_id
);
static
struct
i2c_driver
atmel_captouch_driver
=
{
.
probe
=
atmel_captouch_probe
,
.
id_table
=
atmel_captouch_id
,
.
driver
=
{
.
name
=
"atmel_captouch"
,
.
of_match_table
=
of_match_ptr
(
atmel_captouch_of_id
),
},
};
module_i2c_driver
(
atmel_captouch_driver
);
/* Module information */
MODULE_AUTHOR
(
"Hung-yu Wu <hywu@google.com>"
);
MODULE_DESCRIPTION
(
"Atmel ATmegaXX Capacitance Touch Sensor I2C Driver"
);
MODULE_LICENSE
(
"GPL v2"
);
drivers/input/misc/hisi_powerkey.c
0 → 100644
View file @
08088828
/*
* Hisilicon PMIC powerkey driver
*
* Copyright (C) 2013 Hisilicon Ltd.
* Copyright (C) 2015, 2016 Linaro Ltd.
*
* This file is subject to the terms and conditions of the GNU General
* Public License. See the file "COPYING" in the main directory of this
* archive for more details.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <linux/platform_device.h>
#include <linux/interrupt.h>
#include <linux/reboot.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of_irq.h>
#include <linux/input.h>
#include <linux/slab.h>
/* the held interrupt will trigger after 4 seconds */
#define MAX_HELD_TIME (4 * MSEC_PER_SEC)
static
irqreturn_t
hi65xx_power_press_isr
(
int
irq
,
void
*
q
)
{
struct
input_dev
*
input
=
q
;
pm_wakeup_event
(
input
->
dev
.
parent
,
MAX_HELD_TIME
);
input_report_key
(
input
,
KEY_POWER
,
1
);
input_sync
(
input
);
return
IRQ_HANDLED
;
}
static
irqreturn_t
hi65xx_power_release_isr
(
int
irq
,
void
*
q
)
{
struct
input_dev
*
input
=
q
;
pm_wakeup_event
(
input
->
dev
.
parent
,
MAX_HELD_TIME
);
input_report_key
(
input
,
KEY_POWER
,
0
);
input_sync
(
input
);
return
IRQ_HANDLED
;
}
static
irqreturn_t
hi65xx_restart_toggle_isr
(
int
irq
,
void
*
q
)
{
struct
input_dev
*
input
=
q
;
int
value
=
test_bit
(
KEY_RESTART
,
input
->
key
);
pm_wakeup_event
(
input
->
dev
.
parent
,
MAX_HELD_TIME
);
input_report_key
(
input
,
KEY_RESTART
,
!
value
);
input_sync
(
input
);
return
IRQ_HANDLED
;
}
static
const
struct
{
const
char
*
name
;
irqreturn_t
(
*
handler
)(
int
irq
,
void
*
q
);
}
hi65xx_irq_info
[]
=
{
{
"down"
,
hi65xx_power_press_isr
},
{
"up"
,
hi65xx_power_release_isr
},
{
"hold 4s"
,
hi65xx_restart_toggle_isr
},
};
static
int
hi65xx_powerkey_probe
(
struct
platform_device
*
pdev
)
{
struct
device
*
dev
=
&
pdev
->
dev
;
struct
input_dev
*
input
;
int
irq
,
i
,
error
;
input
=
devm_input_allocate_device
(
&
pdev
->
dev
);
if
(
!
input
)
{
dev_err
(
&
pdev
->
dev
,
"failed to allocate input device
\n
"
);
return
-
ENOMEM
;
}
input
->
phys
=
"hisi_on/input0"
;
input
->
name
=
"HISI 65xx PowerOn Key"
;
input_set_capability
(
input
,
EV_KEY
,
KEY_POWER
);
input_set_capability
(
input
,
EV_KEY
,
KEY_RESTART
);
for
(
i
=
0
;
i
<
ARRAY_SIZE
(
hi65xx_irq_info
);
i
++
)
{
irq
=
platform_get_irq_byname
(
pdev
,
hi65xx_irq_info
[
i
].
name
);
if
(
irq
<
0
)
{
error
=
irq
;
dev_err
(
dev
,
"couldn't get irq %s: %d
\n
"
,
hi65xx_irq_info
[
i
].
name
,
error
);
return
error
;
}
error
=
devm_request_any_context_irq
(
dev
,
irq
,
hi65xx_irq_info
[
i
].
handler
,
IRQF_ONESHOT
,
hi65xx_irq_info
[
i
].
name
,
input
);
if
(
error
<
0
)
{
dev_err
(
dev
,
"couldn't request irq %s: %d
\n
"
,
hi65xx_irq_info
[
i
].
name
,
error
);
return
error
;
}
}
error
=
input_register_device
(
input
);
if
(
error
)
{
dev_err
(
&
pdev
->
dev
,
"failed to register input device: %d
\n
"
,
error
);
return
error
;
}
device_init_wakeup
(
&
pdev
->
dev
,
1
);
return
0
;
}
static
int
hi65xx_powerkey_remove
(
struct
platform_device
*
pdev
)
{
device_init_wakeup
(
&
pdev
->
dev
,
0
);
return
0
;
}
static
struct
platform_driver
hi65xx_powerkey_driver
=
{
.
driver
=
{
.
name
=
"hi65xx-powerkey"
,
},
.
probe
=
hi65xx_powerkey_probe
,
.
remove
=
hi65xx_powerkey_remove
,
};
module_platform_driver
(
hi65xx_powerkey_driver
);
MODULE_AUTHOR
(
"Zhiliang Xue <xuezhiliang@huawei.com"
);
MODULE_DESCRIPTION
(
"Hisi PMIC Power key driver"
);
MODULE_LICENSE
(
"GPL v2"
);
drivers/input/misc/regulator-haptic.c
View file @
08088828
...
...
@@ -124,7 +124,7 @@ regulator_haptic_parse_dt(struct device *dev, struct regulator_haptic *haptic)
node
=
dev
->
of_node
;
if
(
!
node
)
{
dev_err
(
dev
,
"Missing d
ve
ice tree data
\n
"
);
dev_err
(
dev
,
"Missing d
ev
ice tree data
\n
"
);
return
-
EINVAL
;
}
...
...
drivers/input/misc/xen-kbdfront.c
View file @
08088828
...
...
@@ -130,8 +130,8 @@ static int xenkbd_probe(struct xenbus_device *dev,
if
(
xenbus_scanf
(
XBT_NIL
,
dev
->
otherend
,
"feature-abs-pointer"
,
"%d"
,
&
abs
)
<
0
)
abs
=
0
;
if
(
abs
)
{
ret
=
xenbus_
printf
(
XBT_NIL
,
dev
->
nodename
,
"request-abs-pointer"
,
"1"
);
ret
=
xenbus_
write
(
XBT_NIL
,
dev
->
nodename
,
"request-abs-pointer"
,
"1"
);
if
(
ret
)
{
pr_warning
(
"xenkbd: can't request abs-pointer"
);
abs
=
0
;
...
...
@@ -327,8 +327,8 @@ static void xenkbd_backend_changed(struct xenbus_device *dev,
if
(
ret
<
0
)
val
=
0
;
if
(
val
)
{
ret
=
xenbus_
printf
(
XBT_NIL
,
info
->
xbdev
->
nodename
,
"request-abs-pointer"
,
"1"
);
ret
=
xenbus_
write
(
XBT_NIL
,
info
->
xbdev
->
nodename
,
"request-abs-pointer"
,
"1"
);
if
(
ret
)
pr_warning
(
"xenkbd: can't request abs-pointer"
);
}
...
...
drivers/input/mouse/elantech.c
View file @
08088828
...
...
@@ -1708,7 +1708,7 @@ int elantech_init(struct psmouse *psmouse)
snprintf
(
etd
->
tp_phys
,
sizeof
(
etd
->
tp_phys
),
"%s/input1"
,
psmouse
->
ps2dev
.
serio
->
phys
);
tp_dev
->
phys
=
etd
->
tp_phys
;
tp_dev
->
name
=
"E
lantech PS/2
TrackPoint"
;
tp_dev
->
name
=
"E
TPS/2 Elantech
TrackPoint"
;
tp_dev
->
id
.
bustype
=
BUS_I8042
;
tp_dev
->
id
.
vendor
=
0x0002
;
tp_dev
->
id
.
product
=
PSMOUSE_ELANTECH
;
...
...
drivers/input/mouse/lifebook.c
View file @
08088828
...
...
@@ -287,7 +287,7 @@ static int lifebook_create_relative_device(struct psmouse *psmouse)
"%s/input1"
,
psmouse
->
ps2dev
.
serio
->
phys
);
dev2
->
phys
=
priv
->
phys
;
dev2
->
name
=
"
PS/2
Touchpad"
;
dev2
->
name
=
"
LBPS/2 Fujitsu Lifebook
Touchpad"
;
dev2
->
id
.
bustype
=
BUS_I8042
;
dev2
->
id
.
vendor
=
0x0002
;
dev2
->
id
.
product
=
PSMOUSE_LIFEBOOK
;
...
...
drivers/input/rmi4/rmi_f01.c
View file @
08088828
...
...
@@ -81,26 +81,26 @@ struct f01_basic_properties {
* This bit disables whatever sleep mode may be selected by the sleep_mode
* field and forces the device to run at full power without sleeping.
*/
#define RMI_F01_C
RT
L0_NOSLEEP_BIT BIT(2)
#define RMI_F01_C
TR
L0_NOSLEEP_BIT BIT(2)
/*
* When this bit is set, the touch controller employs a noise-filtering
* algorithm designed for use with a connected battery charger.
*/
#define RMI_F01_C
RT
L0_CHARGER_BIT BIT(5)
#define RMI_F01_C
TR
L0_CHARGER_BIT BIT(5)
/*
* Sets the report rate for the device. The effect of this setting is
* highly product dependent. Check the spec sheet for your particular
* touch sensor.
*/
#define RMI_F01_C
RT
L0_REPORTRATE_BIT BIT(6)
#define RMI_F01_C
TR
L0_REPORTRATE_BIT BIT(6)
/*
* Written by the host as an indicator that the device has been
* successfully configured.
*/
#define RMI_F01_C
RT
L0_CONFIGURED_BIT BIT(7)
#define RMI_F01_C
TR
L0_CONFIGURED_BIT BIT(7)
/**
* @ctrl0 - see the bit definitions above.
...
...
@@ -330,10 +330,10 @@ static int rmi_f01_probe(struct rmi_function *fn)
case
RMI_F01_NOSLEEP_DEFAULT
:
break
;
case
RMI_F01_NOSLEEP_OFF
:
f01
->
device_control
.
ctrl0
&=
~
RMI_F01_C
RT
L0_NOSLEEP_BIT
;
f01
->
device_control
.
ctrl0
&=
~
RMI_F01_C
TR
L0_NOSLEEP_BIT
;
break
;
case
RMI_F01_NOSLEEP_ON
:
f01
->
device_control
.
ctrl0
|=
RMI_F01_C
RT
L0_NOSLEEP_BIT
;
f01
->
device_control
.
ctrl0
|=
RMI_F01_C
TR
L0_NOSLEEP_BIT
;
break
;
}
...
...
@@ -349,7 +349,7 @@ static int rmi_f01_probe(struct rmi_function *fn)
f01
->
device_control
.
ctrl0
&=
~
RMI_F01_CTRL0_SLEEP_MODE_MASK
;
}
f01
->
device_control
.
ctrl0
|=
RMI_F01_C
RT
L0_CONFIGURED_BIT
;
f01
->
device_control
.
ctrl0
|=
RMI_F01_C
TR
L0_CONFIGURED_BIT
;
error
=
rmi_write
(
rmi_dev
,
fn
->
fd
.
control_base_addr
,
f01
->
device_control
.
ctrl0
);
...
...
@@ -535,8 +535,8 @@ static int rmi_f01_suspend(struct rmi_function *fn)
int
error
;
f01
->
old_nosleep
=
f01
->
device_control
.
ctrl0
&
RMI_F01_C
RT
L0_NOSLEEP_BIT
;
f01
->
device_control
.
ctrl0
&=
~
RMI_F01_C
RT
L0_NOSLEEP_BIT
;
f01
->
device_control
.
ctrl0
&
RMI_F01_C
TR
L0_NOSLEEP_BIT
;
f01
->
device_control
.
ctrl0
&=
~
RMI_F01_C
TR
L0_NOSLEEP_BIT
;
f01
->
device_control
.
ctrl0
&=
~
RMI_F01_CTRL0_SLEEP_MODE_MASK
;
if
(
device_may_wakeup
(
fn
->
rmi_dev
->
xport
->
dev
))
...
...
@@ -549,7 +549,7 @@ static int rmi_f01_suspend(struct rmi_function *fn)
if
(
error
)
{
dev_err
(
&
fn
->
dev
,
"Failed to write sleep mode: %d.
\n
"
,
error
);
if
(
f01
->
old_nosleep
)
f01
->
device_control
.
ctrl0
|=
RMI_F01_C
RT
L0_NOSLEEP_BIT
;
f01
->
device_control
.
ctrl0
|=
RMI_F01_C
TR
L0_NOSLEEP_BIT
;
f01
->
device_control
.
ctrl0
&=
~
RMI_F01_CTRL0_SLEEP_MODE_MASK
;
f01
->
device_control
.
ctrl0
|=
RMI_SLEEP_MODE_NORMAL
;
return
error
;
...
...
@@ -564,7 +564,7 @@ static int rmi_f01_resume(struct rmi_function *fn)
int
error
;
if
(
f01
->
old_nosleep
)
f01
->
device_control
.
ctrl0
|=
RMI_F01_C
RT
L0_NOSLEEP_BIT
;
f01
->
device_control
.
ctrl0
|=
RMI_F01_C
TR
L0_NOSLEEP_BIT
;
f01
->
device_control
.
ctrl0
&=
~
RMI_F01_CTRL0_SLEEP_MODE_MASK
;
f01
->
device_control
.
ctrl0
|=
RMI_SLEEP_MODE_NORMAL
;
...
...
drivers/input/rmi4/rmi_f11.c
View file @
08088828
...
...
@@ -530,8 +530,8 @@ static void rmi_f11_rel_pos_report(struct f11_data *f11, u8 n_finger)
struct
f11_2d_data
*
data
=
&
f11
->
data
;
s8
x
,
y
;
x
=
data
->
rel_pos
[
n_finger
*
2
];
y
=
data
->
rel_pos
[
n_finger
*
2
+
1
];
x
=
data
->
rel_pos
[
n_finger
*
RMI_F11_REL_BYTES
];
y
=
data
->
rel_pos
[
n_finger
*
RMI_F11_REL_BYTES
+
1
];
rmi_2d_sensor_rel_report
(
sensor
,
x
,
y
);
}
...
...
@@ -1241,7 +1241,6 @@ static int rmi_f11_attention(struct rmi_function *fn, unsigned long *irq_bits)
struct
rmi_driver_data
*
drvdata
=
dev_get_drvdata
(
&
rmi_dev
->
dev
);
struct
f11_data
*
f11
=
dev_get_drvdata
(
&
fn
->
dev
);
u16
data_base_addr
=
fn
->
fd
.
data_base_addr
;
u16
data_base_addr_offset
=
0
;
int
error
;
if
(
rmi_dev
->
xport
->
attn_data
)
{
...
...
@@ -1251,8 +1250,7 @@ static int rmi_f11_attention(struct rmi_function *fn, unsigned long *irq_bits)
rmi_dev
->
xport
->
attn_size
-=
f11
->
sensor
.
attn_size
;
}
else
{
error
=
rmi_read_block
(
rmi_dev
,
data_base_addr
+
data_base_addr_offset
,
f11
->
sensor
.
data_pkt
,
data_base_addr
,
f11
->
sensor
.
data_pkt
,
f11
->
sensor
.
pkt_size
);
if
(
error
<
0
)
return
error
;
...
...
@@ -1260,7 +1258,6 @@ static int rmi_f11_attention(struct rmi_function *fn, unsigned long *irq_bits)
rmi_f11_finger_handler
(
f11
,
&
f11
->
sensor
,
irq_bits
,
drvdata
->
num_of_irq_regs
);
data_base_addr_offset
+=
f11
->
sensor
.
pkt_size
;
return
0
;
}
...
...
drivers/input/rmi4/rmi_f12.c
View file @
08088828
...
...
@@ -27,7 +27,6 @@ enum rmi_f12_object_type {
};
struct
f12_data
{
struct
rmi_function
*
fn
;
struct
rmi_2d_sensor
sensor
;
struct
rmi_2d_sensor_platform_data
sensor_pdata
;
...
...
drivers/input/rmi4/rmi_i2c.c
View file @
08088828
...
...
@@ -11,6 +11,8 @@
#include <linux/rmi.h>
#include <linux/irq.h>
#include <linux/of.h>
#include <linux/delay.h>
#include <linux/regulator/consumer.h>
#include "rmi_driver.h"
#define BUFFER_SIZE_INCREMENT 32
...
...
@@ -37,6 +39,9 @@ struct rmi_i2c_xport {
u8
*
tx_buf
;
size_t
tx_buf_size
;
struct
regulator_bulk_data
supplies
[
2
];
u32
startup_delay
;
};
#define RMI_PAGE_SELECT_REGISTER 0xff
...
...
@@ -246,6 +251,24 @@ static int rmi_i2c_probe(struct i2c_client *client,
return
-
ENODEV
;
}
rmi_i2c
->
supplies
[
0
].
supply
=
"vdd"
;
rmi_i2c
->
supplies
[
1
].
supply
=
"vio"
;
retval
=
devm_regulator_bulk_get
(
&
client
->
dev
,
ARRAY_SIZE
(
rmi_i2c
->
supplies
),
rmi_i2c
->
supplies
);
if
(
retval
<
0
)
return
retval
;
retval
=
regulator_bulk_enable
(
ARRAY_SIZE
(
rmi_i2c
->
supplies
),
rmi_i2c
->
supplies
);
if
(
retval
<
0
)
return
retval
;
of_property_read_u32
(
client
->
dev
.
of_node
,
"syna,startup-delay-ms"
,
&
rmi_i2c
->
startup_delay
);
msleep
(
rmi_i2c
->
startup_delay
);
rmi_i2c
->
client
=
client
;
mutex_init
(
&
rmi_i2c
->
page_mutex
);
...
...
@@ -286,6 +309,8 @@ static int rmi_i2c_remove(struct i2c_client *client)
struct
rmi_i2c_xport
*
rmi_i2c
=
i2c_get_clientdata
(
client
);
rmi_unregister_transport_device
(
&
rmi_i2c
->
xport
);
regulator_bulk_disable
(
ARRAY_SIZE
(
rmi_i2c
->
supplies
),
rmi_i2c
->
supplies
);
return
0
;
}
...
...
@@ -308,6 +333,10 @@ static int rmi_i2c_suspend(struct device *dev)
dev_warn
(
dev
,
"Failed to enable irq for wake: %d
\n
"
,
ret
);
}
regulator_bulk_disable
(
ARRAY_SIZE
(
rmi_i2c
->
supplies
),
rmi_i2c
->
supplies
);
return
ret
;
}
...
...
@@ -317,6 +346,13 @@ static int rmi_i2c_resume(struct device *dev)
struct
rmi_i2c_xport
*
rmi_i2c
=
i2c_get_clientdata
(
client
);
int
ret
;
ret
=
regulator_bulk_enable
(
ARRAY_SIZE
(
rmi_i2c
->
supplies
),
rmi_i2c
->
supplies
);
if
(
ret
)
return
ret
;
msleep
(
rmi_i2c
->
startup_delay
);
enable_irq
(
rmi_i2c
->
irq
);
if
(
device_may_wakeup
(
&
client
->
dev
))
{
ret
=
disable_irq_wake
(
rmi_i2c
->
irq
);
...
...
@@ -346,6 +382,9 @@ static int rmi_i2c_runtime_suspend(struct device *dev)
disable_irq
(
rmi_i2c
->
irq
);
regulator_bulk_disable
(
ARRAY_SIZE
(
rmi_i2c
->
supplies
),
rmi_i2c
->
supplies
);
return
0
;
}
...
...
@@ -355,6 +394,13 @@ static int rmi_i2c_runtime_resume(struct device *dev)
struct
rmi_i2c_xport
*
rmi_i2c
=
i2c_get_clientdata
(
client
);
int
ret
;
ret
=
regulator_bulk_enable
(
ARRAY_SIZE
(
rmi_i2c
->
supplies
),
rmi_i2c
->
supplies
);
if
(
ret
)
return
ret
;
msleep
(
rmi_i2c
->
startup_delay
);
enable_irq
(
rmi_i2c
->
irq
);
ret
=
rmi_driver_resume
(
rmi_i2c
->
xport
.
rmi_dev
);
...
...
drivers/input/serio/ams_delta_serio.c
View file @
08088828
...
...
@@ -56,7 +56,7 @@ static int check_data(int data)
/* it should be odd */
if
(
!
(
parity
&
0x01
))
{
dev_warn
(
&
ams_delta_serio
->
dev
,
"parit
i
y check failed, data=0x%X parity=0x%X
\n
"
,
"parity check failed, data=0x%X parity=0x%X
\n
"
,
data
,
parity
);
return
SERIO_PARITY
;
}
...
...
drivers/input/tablet/Kconfig
View file @
08088828
...
...
@@ -73,6 +73,21 @@ config TABLET_USB_KBTAB
To compile this driver as a module, choose M here: the
module will be called kbtab.
config TABLET_USB_PEGASUS
tristate "Pegasus Mobile Notetaker Pen input tablet support"
depends on USB_ARCH_HAS_HCD
select USB
help
Say Y here if you want to use the Pegasus Mobile Notetaker,
also known as:
Genie e-note The Notetaker,
Staedtler Digital ballpoint pen 990 01,
IRISnotes Express or
NEWLink Digital Note Taker.
To compile this driver as a module, choose M here: the
module will be called pegasus_notetaker.
config TABLET_SERIAL_WACOM4
tristate "Wacom protocol 4 serial tablet support"
select SERIO
...
...
drivers/input/tablet/Makefile
View file @
08088828
...
...
@@ -8,4 +8,5 @@ obj-$(CONFIG_TABLET_USB_AIPTEK) += aiptek.o
obj-$(CONFIG_TABLET_USB_GTCO)
+=
gtco.o
obj-$(CONFIG_TABLET_USB_HANWANG)
+=
hanwang.o
obj-$(CONFIG_TABLET_USB_KBTAB)
+=
kbtab.o
obj-$(CONFIG_TABLET_USB_PEGASUS)
+=
pegasus_notetaker.o
obj-$(CONFIG_TABLET_SERIAL_WACOM4)
+=
wacom_serial4.o
drivers/input/tablet/pegasus_notetaker.c
0 → 100644
View file @
08088828
/*
* Pegasus Mobile Notetaker Pen input tablet driver
*
* Copyright (c) 2016 Martin Kepplinger <martink@posteo.de>
*/
/*
* request packet (control endpoint):
* |-------------------------------------|
* | Report ID | Nr of bytes | command |
* | (1 byte) | (1 byte) | (n bytes) |
* |-------------------------------------|
* | 0x02 | n | |
* |-------------------------------------|
*
* data packet after set xy mode command, 0x80 0xb5 0x02 0x01
* and pen is in range:
*
* byte byte name value (bits)
* --------------------------------------------
* 0 status 0 1 0 0 0 0 X X
* 1 color 0 0 0 0 H 0 S T
* 2 X low
* 3 X high
* 4 Y low
* 5 Y high
*
* X X battery state:
* no state reported 0x00
* battery low 0x01
* battery good 0x02
*
* H Hovering
* S Switch 1 (pen button)
* T Tip
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/input.h>
#include <linux/usb/input.h>
#include <linux/slab.h>
/* USB HID defines */
#define USB_REQ_GET_REPORT 0x01
#define USB_REQ_SET_REPORT 0x09
#define USB_VENDOR_ID_PEGASUSTECH 0x0e20
#define USB_DEVICE_ID_PEGASUS_NOTETAKER_EN100 0x0101
/* device specific defines */
#define NOTETAKER_REPORT_ID 0x02
#define NOTETAKER_SET_CMD 0x80
#define NOTETAKER_SET_MODE 0xb5
#define NOTETAKER_LED_MOUSE 0x02
#define PEN_MODE_XY 0x01
#define SPECIAL_COMMAND 0x80
#define BUTTON_PRESSED 0xb5
#define COMMAND_VERSION 0xa9
/* in xy data packet */
#define BATTERY_NO_REPORT 0x40
#define BATTERY_LOW 0x41
#define BATTERY_GOOD 0x42
#define PEN_BUTTON_PRESSED BIT(1)
#define PEN_TIP BIT(0)
struct
pegasus
{
unsigned
char
*
data
;
u8
data_len
;
dma_addr_t
data_dma
;
struct
input_dev
*
dev
;
struct
usb_device
*
usbdev
;
struct
usb_interface
*
intf
;
struct
urb
*
irq
;
char
name
[
128
];
char
phys
[
64
];
struct
work_struct
init
;
};
static
int
pegasus_control_msg
(
struct
pegasus
*
pegasus
,
u8
*
data
,
int
len
)
{
const
int
sizeof_buf
=
len
+
2
;
int
result
;
int
error
;
u8
*
cmd_buf
;
cmd_buf
=
kmalloc
(
sizeof_buf
,
GFP_KERNEL
);
if
(
!
cmd_buf
)
return
-
ENOMEM
;
cmd_buf
[
0
]
=
NOTETAKER_REPORT_ID
;
cmd_buf
[
1
]
=
len
;
memcpy
(
cmd_buf
+
2
,
data
,
len
);
result
=
usb_control_msg
(
pegasus
->
usbdev
,
usb_sndctrlpipe
(
pegasus
->
usbdev
,
0
),
USB_REQ_SET_REPORT
,
USB_TYPE_VENDOR
|
USB_DIR_OUT
,
0
,
0
,
cmd_buf
,
sizeof_buf
,
USB_CTRL_SET_TIMEOUT
);
kfree
(
cmd_buf
);
if
(
unlikely
(
result
!=
sizeof_buf
))
{
error
=
result
<
0
?
result
:
-
EIO
;
dev_err
(
&
pegasus
->
usbdev
->
dev
,
"control msg error: %d
\n
"
,
error
);
return
error
;
}
return
0
;
}
static
int
pegasus_set_mode
(
struct
pegasus
*
pegasus
,
u8
mode
,
u8
led
)
{
u8
cmd
[]
=
{
NOTETAKER_SET_CMD
,
NOTETAKER_SET_MODE
,
led
,
mode
};
return
pegasus_control_msg
(
pegasus
,
cmd
,
sizeof
(
cmd
));
}
static
void
pegasus_parse_packet
(
struct
pegasus
*
pegasus
)
{
unsigned
char
*
data
=
pegasus
->
data
;
struct
input_dev
*
dev
=
pegasus
->
dev
;
u16
x
,
y
;
switch
(
data
[
0
])
{
case
SPECIAL_COMMAND
:
/* device button pressed */
if
(
data
[
1
]
==
BUTTON_PRESSED
)
schedule_work
(
&
pegasus
->
init
);
break
;
/* xy data */
case
BATTERY_LOW
:
dev_warn_once
(
&
dev
->
dev
,
"Pen battery low
\n
"
);
/* fall through */
case
BATTERY_NO_REPORT
:
case
BATTERY_GOOD
:
x
=
le16_to_cpup
((
__le16
*
)
&
data
[
2
]);
y
=
le16_to_cpup
((
__le16
*
)
&
data
[
4
]);
/* pen-up event */
if
(
x
==
0
&&
y
==
0
)
break
;
input_report_key
(
dev
,
BTN_TOUCH
,
data
[
1
]
&
PEN_TIP
);
input_report_key
(
dev
,
BTN_RIGHT
,
data
[
1
]
&
PEN_BUTTON_PRESSED
);
input_report_key
(
dev
,
BTN_TOOL_PEN
,
1
);
input_report_abs
(
dev
,
ABS_X
,
(
s16
)
x
);
input_report_abs
(
dev
,
ABS_Y
,
y
);
input_sync
(
dev
);
break
;
default:
dev_warn_once
(
&
pegasus
->
usbdev
->
dev
,
"unknown answer from device
\n
"
);
}
}
static
void
pegasus_irq
(
struct
urb
*
urb
)
{
struct
pegasus
*
pegasus
=
urb
->
context
;
struct
usb_device
*
dev
=
pegasus
->
usbdev
;
int
retval
;
switch
(
urb
->
status
)
{
case
0
:
pegasus_parse_packet
(
pegasus
);
usb_mark_last_busy
(
pegasus
->
usbdev
);
break
;
case
-
ECONNRESET
:
case
-
ENOENT
:
case
-
ESHUTDOWN
:
dev_err
(
&
dev
->
dev
,
"%s - urb shutting down with status: %d"
,
__func__
,
urb
->
status
);
return
;
default:
dev_err
(
&
dev
->
dev
,
"%s - nonzero urb status received: %d"
,
__func__
,
urb
->
status
);
break
;
}
retval
=
usb_submit_urb
(
urb
,
GFP_ATOMIC
);
if
(
retval
)
dev_err
(
&
dev
->
dev
,
"%s - usb_submit_urb failed with result %d"
,
__func__
,
retval
);
}
static
void
pegasus_init
(
struct
work_struct
*
work
)
{
struct
pegasus
*
pegasus
=
container_of
(
work
,
struct
pegasus
,
init
);
int
error
;
error
=
pegasus_set_mode
(
pegasus
,
PEN_MODE_XY
,
NOTETAKER_LED_MOUSE
);
if
(
error
)
dev_err
(
&
pegasus
->
usbdev
->
dev
,
"pegasus_set_mode error: %d
\n
"
,
error
);
}
static
int
pegasus_open
(
struct
input_dev
*
dev
)
{
struct
pegasus
*
pegasus
=
input_get_drvdata
(
dev
);
int
error
;
error
=
usb_autopm_get_interface
(
pegasus
->
intf
);
if
(
error
)
return
error
;
pegasus
->
irq
->
dev
=
pegasus
->
usbdev
;
if
(
usb_submit_urb
(
pegasus
->
irq
,
GFP_KERNEL
))
{
error
=
-
EIO
;
goto
err_autopm_put
;
}
error
=
pegasus_set_mode
(
pegasus
,
PEN_MODE_XY
,
NOTETAKER_LED_MOUSE
);
if
(
error
)
goto
err_kill_urb
;
return
0
;
err_kill_urb:
usb_kill_urb
(
pegasus
->
irq
);
cancel_work_sync
(
&
pegasus
->
init
);
err_autopm_put:
usb_autopm_put_interface
(
pegasus
->
intf
);
return
error
;
}
static
void
pegasus_close
(
struct
input_dev
*
dev
)
{
struct
pegasus
*
pegasus
=
input_get_drvdata
(
dev
);
usb_kill_urb
(
pegasus
->
irq
);
cancel_work_sync
(
&
pegasus
->
init
);
usb_autopm_put_interface
(
pegasus
->
intf
);
}
static
int
pegasus_probe
(
struct
usb_interface
*
intf
,
const
struct
usb_device_id
*
id
)
{
struct
usb_device
*
dev
=
interface_to_usbdev
(
intf
);
struct
usb_endpoint_descriptor
*
endpoint
;
struct
pegasus
*
pegasus
;
struct
input_dev
*
input_dev
;
int
error
;
int
pipe
;
/* We control interface 0 */
if
(
intf
->
cur_altsetting
->
desc
.
bInterfaceNumber
>=
1
)
return
-
ENODEV
;
/* Sanity check that the device has an endpoint */
if
(
intf
->
altsetting
[
0
].
desc
.
bNumEndpoints
<
1
)
{
dev_err
(
&
intf
->
dev
,
"Invalid number of endpoints
\n
"
);
return
-
EINVAL
;
}
endpoint
=
&
intf
->
cur_altsetting
->
endpoint
[
0
].
desc
;
pegasus
=
kzalloc
(
sizeof
(
*
pegasus
),
GFP_KERNEL
);
input_dev
=
input_allocate_device
();
if
(
!
pegasus
||
!
input_dev
)
{
error
=
-
ENOMEM
;
goto
err_free_mem
;
}
pegasus
->
usbdev
=
dev
;
pegasus
->
dev
=
input_dev
;
pegasus
->
intf
=
intf
;
pipe
=
usb_rcvintpipe
(
dev
,
endpoint
->
bEndpointAddress
);
pegasus
->
data_len
=
usb_maxpacket
(
dev
,
pipe
,
usb_pipeout
(
pipe
));
pegasus
->
data
=
usb_alloc_coherent
(
dev
,
pegasus
->
data_len
,
GFP_KERNEL
,
&
pegasus
->
data_dma
);
if
(
!
pegasus
->
data
)
{
error
=
-
ENOMEM
;
goto
err_free_mem
;
}
pegasus
->
irq
=
usb_alloc_urb
(
0
,
GFP_KERNEL
);
if
(
!
pegasus
->
irq
)
{
error
=
-
ENOMEM
;
goto
err_free_dma
;
}
usb_fill_int_urb
(
pegasus
->
irq
,
dev
,
pipe
,
pegasus
->
data
,
pegasus
->
data_len
,
pegasus_irq
,
pegasus
,
endpoint
->
bInterval
);
pegasus
->
irq
->
transfer_dma
=
pegasus
->
data_dma
;
pegasus
->
irq
->
transfer_flags
|=
URB_NO_TRANSFER_DMA_MAP
;
if
(
dev
->
manufacturer
)
strlcpy
(
pegasus
->
name
,
dev
->
manufacturer
,
sizeof
(
pegasus
->
name
));
if
(
dev
->
product
)
{
if
(
dev
->
manufacturer
)
strlcat
(
pegasus
->
name
,
" "
,
sizeof
(
pegasus
->
name
));
strlcat
(
pegasus
->
name
,
dev
->
product
,
sizeof
(
pegasus
->
name
));
}
if
(
!
strlen
(
pegasus
->
name
))
snprintf
(
pegasus
->
name
,
sizeof
(
pegasus
->
name
),
"USB Pegasus Device %04x:%04x"
,
le16_to_cpu
(
dev
->
descriptor
.
idVendor
),
le16_to_cpu
(
dev
->
descriptor
.
idProduct
));
usb_make_path
(
dev
,
pegasus
->
phys
,
sizeof
(
pegasus
->
phys
));
strlcat
(
pegasus
->
phys
,
"/input0"
,
sizeof
(
pegasus
->
phys
));
INIT_WORK
(
&
pegasus
->
init
,
pegasus_init
);
usb_set_intfdata
(
intf
,
pegasus
);
input_dev
->
name
=
pegasus
->
name
;
input_dev
->
phys
=
pegasus
->
phys
;
usb_to_input_id
(
dev
,
&
input_dev
->
id
);
input_dev
->
dev
.
parent
=
&
intf
->
dev
;
input_set_drvdata
(
input_dev
,
pegasus
);
input_dev
->
open
=
pegasus_open
;
input_dev
->
close
=
pegasus_close
;
__set_bit
(
EV_ABS
,
input_dev
->
evbit
);
__set_bit
(
EV_KEY
,
input_dev
->
evbit
);
__set_bit
(
ABS_X
,
input_dev
->
absbit
);
__set_bit
(
ABS_Y
,
input_dev
->
absbit
);
__set_bit
(
BTN_TOUCH
,
input_dev
->
keybit
);
__set_bit
(
BTN_RIGHT
,
input_dev
->
keybit
);
__set_bit
(
BTN_TOOL_PEN
,
input_dev
->
keybit
);
__set_bit
(
INPUT_PROP_DIRECT
,
input_dev
->
propbit
);
__set_bit
(
INPUT_PROP_POINTER
,
input_dev
->
propbit
);
input_set_abs_params
(
input_dev
,
ABS_X
,
-
1500
,
1500
,
8
,
0
);
input_set_abs_params
(
input_dev
,
ABS_Y
,
1600
,
3000
,
8
,
0
);
error
=
input_register_device
(
pegasus
->
dev
);
if
(
error
)
goto
err_free_urb
;
return
0
;
err_free_urb:
usb_free_urb
(
pegasus
->
irq
);
err_free_dma:
usb_free_coherent
(
dev
,
pegasus
->
data_len
,
pegasus
->
data
,
pegasus
->
data_dma
);
err_free_mem:
input_free_device
(
input_dev
);
kfree
(
pegasus
);
usb_set_intfdata
(
intf
,
NULL
);
return
error
;
}
static
void
pegasus_disconnect
(
struct
usb_interface
*
intf
)
{
struct
pegasus
*
pegasus
=
usb_get_intfdata
(
intf
);
input_unregister_device
(
pegasus
->
dev
);
usb_free_urb
(
pegasus
->
irq
);
usb_free_coherent
(
interface_to_usbdev
(
intf
),
pegasus
->
data_len
,
pegasus
->
data
,
pegasus
->
data_dma
);
kfree
(
pegasus
);
usb_set_intfdata
(
intf
,
NULL
);
}
static
int
pegasus_suspend
(
struct
usb_interface
*
intf
,
pm_message_t
message
)
{
struct
pegasus
*
pegasus
=
usb_get_intfdata
(
intf
);
mutex_lock
(
&
pegasus
->
dev
->
mutex
);
usb_kill_urb
(
pegasus
->
irq
);
cancel_work_sync
(
&
pegasus
->
init
);
mutex_unlock
(
&
pegasus
->
dev
->
mutex
);
return
0
;
}
static
int
pegasus_resume
(
struct
usb_interface
*
intf
)
{
struct
pegasus
*
pegasus
=
usb_get_intfdata
(
intf
);
int
retval
=
0
;
mutex_lock
(
&
pegasus
->
dev
->
mutex
);
if
(
pegasus
->
dev
->
users
&&
usb_submit_urb
(
pegasus
->
irq
,
GFP_NOIO
)
<
0
)
retval
=
-
EIO
;
mutex_unlock
(
&
pegasus
->
dev
->
mutex
);
return
retval
;
}
static
int
pegasus_reset_resume
(
struct
usb_interface
*
intf
)
{
struct
pegasus
*
pegasus
=
usb_get_intfdata
(
intf
);
int
retval
=
0
;
mutex_lock
(
&
pegasus
->
dev
->
mutex
);
if
(
pegasus
->
dev
->
users
)
{
retval
=
pegasus_set_mode
(
pegasus
,
PEN_MODE_XY
,
NOTETAKER_LED_MOUSE
);
if
(
!
retval
&&
usb_submit_urb
(
pegasus
->
irq
,
GFP_NOIO
)
<
0
)
retval
=
-
EIO
;
}
mutex_unlock
(
&
pegasus
->
dev
->
mutex
);
return
retval
;
}
static
const
struct
usb_device_id
pegasus_ids
[]
=
{
{
USB_DEVICE
(
USB_VENDOR_ID_PEGASUSTECH
,
USB_DEVICE_ID_PEGASUS_NOTETAKER_EN100
)
},
{
}
};
MODULE_DEVICE_TABLE
(
usb
,
pegasus_ids
);
static
struct
usb_driver
pegasus_driver
=
{
.
name
=
"pegasus_notetaker"
,
.
probe
=
pegasus_probe
,
.
disconnect
=
pegasus_disconnect
,
.
suspend
=
pegasus_suspend
,
.
resume
=
pegasus_resume
,
.
reset_resume
=
pegasus_reset_resume
,
.
id_table
=
pegasus_ids
,
.
supports_autosuspend
=
1
,
};
module_usb_driver
(
pegasus_driver
);
MODULE_AUTHOR
(
"Martin Kepplinger <martink@posteo.de>"
);
MODULE_DESCRIPTION
(
"Pegasus Mobile Notetaker Pen tablet driver"
);
MODULE_LICENSE
(
"GPL"
);
drivers/input/touchscreen/Kconfig
View file @
08088828
...
...
@@ -632,7 +632,7 @@ config TOUCHSCREEN_EDT_FT5X06
config TOUCHSCREEN_MIGOR
tristate "Renesas MIGO-R touchscreen"
depends on
SH_MIGOR
&& I2C
depends on
(SH_MIGOR || COMPILE_TEST)
&& I2C
help
Say Y here to enable MIGO-R touchscreen support.
...
...
@@ -1046,6 +1046,19 @@ config TOUCHSCREEN_PCAP
To compile this driver as a module, choose M here: the
module will be called pcap_ts.
config TOUCHSCREEN_RM_TS
tristate "Raydium I2C Touchscreen"
depends on I2C
depends on GPIOLIB || COMPILE_TEST
help
Say Y here if you have Raydium series I2C touchscreen,
such as RM32380, connected to your system.
If unsure, say N.
To compile this driver as a module, choose M here: the
module will be called raydium_i2c_ts.
config TOUCHSCREEN_ST1232
tristate "Sitronix ST1232 touchscreen controllers"
depends on I2C
...
...
@@ -1094,6 +1107,19 @@ config TOUCHSCREEN_SUR40
To compile this driver as a module, choose M here: the
module will be called sur40.
config TOUCHSCREEN_SURFACE3_SPI
tristate "Ntrig/Microsoft Surface 3 SPI touchscreen"
depends on SPI
depends on GPIOLIB || COMPILE_TEST
help
Say Y here if you have the Ntrig/Microsoft SPI touchscreen
controller chip as found on the Surface 3 in your system.
If unsure, say N.
To compile this driver as a module, choose M here: the
module will be called surface3_spi.
config TOUCHSCREEN_SX8654
tristate "Semtech SX8654 touchscreen"
depends on I2C
...
...
drivers/input/touchscreen/Makefile
View file @
08088828
...
...
@@ -62,11 +62,13 @@ obj-$(CONFIG_TOUCHSCREEN_USB_COMPOSITE) += usbtouchscreen.o
obj-$(CONFIG_TOUCHSCREEN_PCAP)
+=
pcap_ts.o
obj-$(CONFIG_TOUCHSCREEN_PENMOUNT)
+=
penmount.o
obj-$(CONFIG_TOUCHSCREEN_PIXCIR)
+=
pixcir_i2c_ts.o
obj-$(CONFIG_TOUCHSCREEN_RM_TS)
+=
raydium_i2c_ts.o
obj-$(CONFIG_TOUCHSCREEN_S3C2410)
+=
s3c2410_ts.o
obj-$(CONFIG_TOUCHSCREEN_ST1232)
+=
st1232.o
obj-$(CONFIG_TOUCHSCREEN_STMPE)
+=
stmpe-ts.o
obj-$(CONFIG_TOUCHSCREEN_SUN4I)
+=
sun4i-ts.o
obj-$(CONFIG_TOUCHSCREEN_SUR40)
+=
sur40.o
obj-$(CONFIG_TOUCHSCREEN_SURFACE3_SPI)
+=
surface3_spi.o
obj-$(CONFIG_TOUCHSCREEN_TI_AM335X_TSC)
+=
ti_am335x_tsc.o
obj-$(CONFIG_TOUCHSCREEN_TOUCHIT213)
+=
touchit213.o
obj-$(CONFIG_TOUCHSCREEN_TOUCHRIGHT)
+=
touchright.o
...
...
drivers/input/touchscreen/ad7879.c
View file @
08088828
...
...
@@ -595,7 +595,7 @@ struct ad7879 *ad7879_probe(struct device *dev, u8 devid, unsigned int irq,
}
else
{
input_set_abs_params
(
input_dev
,
ABS_X
,
0
,
MAX_12BIT
,
0
,
0
);
input_set_abs_params
(
input_dev
,
ABS_Y
,
0
,
MAX_12BIT
,
0
,
0
);
touchscreen_parse_properties
(
input_dev
,
false
);
touchscreen_parse_properties
(
input_dev
,
false
,
NULL
);
if
(
!
input_abs_get_max
(
input_dev
,
ABS_PRESSURE
))
{
dev_err
(
dev
,
"Touchscreen pressure is not specified
\n
"
);
return
ERR_PTR
(
-
EINVAL
);
...
...
drivers/input/touchscreen/chipone_icn8318.c
View file @
08088828
...
...
@@ -17,6 +17,7 @@
#include <linux/i2c.h>
#include <linux/input.h>
#include <linux/input/mt.h>
#include <linux/input/touchscreen.h>
#include <linux/module.h>
#include <linux/of.h>
...
...
@@ -52,11 +53,7 @@ struct icn8318_data {
struct
i2c_client
*
client
;
struct
input_dev
*
input
;
struct
gpio_desc
*
wake_gpio
;
u32
max_x
;
u32
max_y
;
bool
invert_x
;
bool
invert_y
;
bool
swap_x_y
;
struct
touchscreen_properties
prop
;
};
static
int
icn8318_read_touch_data
(
struct
i2c_client
*
client
,
...
...
@@ -91,7 +88,7 @@ static irqreturn_t icn8318_irq(int irq, void *dev_id)
struct
icn8318_data
*
data
=
dev_id
;
struct
device
*
dev
=
&
data
->
client
->
dev
;
struct
icn8318_touch_data
touch_data
;
int
i
,
ret
,
x
,
y
;
int
i
,
ret
;
ret
=
icn8318_read_touch_data
(
data
->
client
,
&
touch_data
);
if
(
ret
<
0
)
{
...
...
@@ -124,22 +121,9 @@ static irqreturn_t icn8318_irq(int irq, void *dev_id)
if
(
!
act
)
continue
;
x
=
be16_to_cpu
(
touch
->
x
);
y
=
be16_to_cpu
(
touch
->
y
);
if
(
data
->
invert_x
)
x
=
data
->
max_x
-
x
;
if
(
data
->
invert_y
)
y
=
data
->
max_y
-
y
;
if
(
!
data
->
swap_x_y
)
{
input_event
(
data
->
input
,
EV_ABS
,
ABS_MT_POSITION_X
,
x
);
input_event
(
data
->
input
,
EV_ABS
,
ABS_MT_POSITION_Y
,
y
);
}
else
{
input_event
(
data
->
input
,
EV_ABS
,
ABS_MT_POSITION_X
,
y
);
input_event
(
data
->
input
,
EV_ABS
,
ABS_MT_POSITION_Y
,
x
);
}
touchscreen_report_pos
(
data
->
input
,
&
data
->
prop
,
be16_to_cpu
(
touch
->
x
),
be16_to_cpu
(
touch
->
y
),
true
);
}
input_mt_sync_frame
(
data
->
input
);
...
...
@@ -200,10 +184,8 @@ static int icn8318_probe(struct i2c_client *client,
const
struct
i2c_device_id
*
id
)
{
struct
device
*
dev
=
&
client
->
dev
;
struct
device_node
*
np
=
dev
->
of_node
;
struct
icn8318_data
*
data
;
struct
input_dev
*
input
;
u32
fuzz_x
=
0
,
fuzz_y
=
0
;
int
error
;
if
(
!
client
->
irq
)
{
...
...
@@ -223,19 +205,6 @@ static int icn8318_probe(struct i2c_client *client,
return
error
;
}
if
(
of_property_read_u32
(
np
,
"touchscreen-size-x"
,
&
data
->
max_x
)
||
of_property_read_u32
(
np
,
"touchscreen-size-y"
,
&
data
->
max_y
))
{
dev_err
(
dev
,
"Error touchscreen-size-x and/or -y missing
\n
"
);
return
-
EINVAL
;
}
/* Optional */
of_property_read_u32
(
np
,
"touchscreen-fuzz-x"
,
&
fuzz_x
);
of_property_read_u32
(
np
,
"touchscreen-fuzz-y"
,
&
fuzz_y
);
data
->
invert_x
=
of_property_read_bool
(
np
,
"touchscreen-inverted-x"
);
data
->
invert_y
=
of_property_read_bool
(
np
,
"touchscreen-inverted-y"
);
data
->
swap_x_y
=
of_property_read_bool
(
np
,
"touchscreen-swapped-x-y"
);
input
=
devm_input_allocate_device
(
dev
);
if
(
!
input
)
return
-
ENOMEM
;
...
...
@@ -246,16 +215,14 @@ static int icn8318_probe(struct i2c_client *client,
input
->
close
=
icn8318_stop
;
input
->
dev
.
parent
=
dev
;
if
(
!
data
->
swap_x_y
)
{
input_set_abs_params
(
input
,
ABS_MT_POSITION_X
,
0
,
data
->
max_x
,
fuzz_x
,
0
);
input_set_abs_params
(
input
,
ABS_MT_POSITION_Y
,
0
,
data
->
max_y
,
fuzz_y
,
0
);
}
else
{
input_set_abs_params
(
input
,
ABS_MT_POSITION_X
,
0
,
data
->
max_y
,
fuzz_y
,
0
);
input_set_abs_params
(
input
,
ABS_MT_POSITION_Y
,
0
,
data
->
max_x
,
fuzz_x
,
0
);
input_set_capability
(
input
,
EV_ABS
,
ABS_MT_POSITION_X
);
input_set_capability
(
input
,
EV_ABS
,
ABS_MT_POSITION_Y
);
touchscreen_parse_properties
(
input
,
true
,
&
data
->
prop
);
if
(
!
input_abs_get_max
(
input
,
ABS_MT_POSITION_X
)
||
!
input_abs_get_max
(
input
,
ABS_MT_POSITION_Y
))
{
dev_err
(
dev
,
"Error touchscreen-size-x and/or -y missing
\n
"
);
return
-
EINVAL
;
}
error
=
input_mt_init_slots
(
input
,
ICN8318_MAX_TOUCHES
,
...
...
drivers/input/touchscreen/cyttsp_core.c
View file @
08088828
...
...
@@ -657,7 +657,7 @@ struct cyttsp *cyttsp_probe(const struct cyttsp_bus_ops *bus_ops,
input_set_capability
(
input_dev
,
EV_ABS
,
ABS_MT_POSITION_X
);
input_set_capability
(
input_dev
,
EV_ABS
,
ABS_MT_POSITION_Y
);
touchscreen_parse_properties
(
input_dev
,
true
);
touchscreen_parse_properties
(
input_dev
,
true
,
NULL
);
error
=
input_mt_init_slots
(
input_dev
,
CY_MAX_ID
,
0
);
if
(
error
)
{
...
...
drivers/input/touchscreen/edt-ft5x06.c
View file @
08088828
...
...
@@ -86,6 +86,7 @@ struct edt_reg_addr {
struct
edt_ft5x06_ts_data
{
struct
i2c_client
*
client
;
struct
input_dev
*
input
;
struct
touchscreen_properties
prop
;
u16
num_x
;
u16
num_y
;
...
...
@@ -246,8 +247,8 @@ static irqreturn_t edt_ft5x06_ts_isr(int irq, void *dev_id)
if
(
!
down
)
continue
;
input_report_abs
(
tsdata
->
input
,
ABS_MT_POSITION_X
,
x
);
input_report_abs
(
tsdata
->
input
,
ABS_MT_POSITION_Y
,
y
);
touchscreen_report_pos
(
tsdata
->
input
,
&
tsdata
->
prop
,
x
,
y
,
true
);
}
input_mt_report_pointer_emulation
(
tsdata
->
input
,
true
);
...
...
@@ -972,7 +973,7 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client,
input_set_abs_params
(
input
,
ABS_MT_POSITION_Y
,
0
,
tsdata
->
num_y
*
64
-
1
,
0
,
0
);
touchscreen_parse_properties
(
input
,
true
);
touchscreen_parse_properties
(
input
,
true
,
&
tsdata
->
prop
);
error
=
input_mt_init_slots
(
input
,
tsdata
->
max_support_points
,
INPUT_MT_DIRECT
);
...
...
drivers/input/touchscreen/migor_ts.c
View file @
08088828
...
...
@@ -202,7 +202,7 @@ static int migor_ts_remove(struct i2c_client *client)
return
0
;
}
static
int
migor_ts_suspend
(
struct
device
*
dev
)
static
int
__maybe_unused
migor_ts_suspend
(
struct
device
*
dev
)
{
struct
i2c_client
*
client
=
to_i2c_client
(
dev
);
struct
migor_ts_priv
*
priv
=
i2c_get_clientdata
(
client
);
...
...
@@ -213,7 +213,7 @@ static int migor_ts_suspend(struct device *dev)
return
0
;
}
static
int
migor_ts_resume
(
struct
device
*
dev
)
static
int
__maybe_unused
migor_ts_resume
(
struct
device
*
dev
)
{
struct
i2c_client
*
client
=
to_i2c_client
(
dev
);
struct
migor_ts_priv
*
priv
=
i2c_get_clientdata
(
client
);
...
...
@@ -230,7 +230,7 @@ static const struct i2c_device_id migor_ts_id[] = {
{
"migor_ts"
,
0
},
{
}
};
MODULE_DEVICE_TABLE
(
i2c
,
migor_ts
);
MODULE_DEVICE_TABLE
(
i2c
,
migor_ts
_id
);
static
struct
i2c_driver
migor_ts_driver
=
{
.
driver
=
{
...
...
drivers/input/touchscreen/of_touchscreen.c
View file @
08088828
...
...
@@ -55,12 +55,16 @@ static void touchscreen_set_params(struct input_dev *dev,
* @input: input device that should be parsed
* @multitouch: specifies whether parsed properties should be applied to
* single-touch or multi-touch axes
* @prop: pointer to a struct touchscreen_properties into which to store
* axis swap and invert info for use with touchscreen_report_x_y();
* or %NULL
*
* This function parses common DT properties for touchscreens and setups the
* input device accordingly. The function keeps previously set up default
* values if no value is specified via DT.
*/
void
touchscreen_parse_properties
(
struct
input_dev
*
input
,
bool
multitouch
)
void
touchscreen_parse_properties
(
struct
input_dev
*
input
,
bool
multitouch
,
struct
touchscreen_properties
*
prop
)
{
struct
device
*
dev
=
input
->
dev
.
parent
;
unsigned
int
axis
;
...
...
@@ -104,5 +108,80 @@ void touchscreen_parse_properties(struct input_dev *input, bool multitouch)
&
fuzz
);
if
(
data_present
)
touchscreen_set_params
(
input
,
axis
,
maximum
,
fuzz
);
if
(
!
prop
)
return
;
axis
=
multitouch
?
ABS_MT_POSITION_X
:
ABS_X
;
prop
->
max_x
=
input_abs_get_max
(
input
,
axis
);
prop
->
max_y
=
input_abs_get_max
(
input
,
axis
+
1
);
prop
->
invert_x
=
device_property_read_bool
(
dev
,
"touchscreen-inverted-x"
);
prop
->
invert_y
=
device_property_read_bool
(
dev
,
"touchscreen-inverted-y"
);
prop
->
swap_x_y
=
device_property_read_bool
(
dev
,
"touchscreen-swapped-x-y"
);
if
(
prop
->
swap_x_y
)
swap
(
input
->
absinfo
[
axis
],
input
->
absinfo
[
axis
+
1
]);
}
EXPORT_SYMBOL
(
touchscreen_parse_properties
);
static
void
touchscreen_apply_prop_to_x_y
(
const
struct
touchscreen_properties
*
prop
,
unsigned
int
*
x
,
unsigned
int
*
y
)
{
if
(
prop
->
invert_x
)
*
x
=
prop
->
max_x
-
*
x
;
if
(
prop
->
invert_y
)
*
y
=
prop
->
max_y
-
*
y
;
if
(
prop
->
swap_x_y
)
swap
(
*
x
,
*
y
);
}
/**
* touchscreen_set_mt_pos - Set input_mt_pos coordinates
* @pos: input_mt_pos to set coordinates of
* @prop: pointer to a struct touchscreen_properties
* @x: X coordinate to store in pos
* @y: Y coordinate to store in pos
*
* Adjust the passed in x and y values applying any axis inversion and
* swapping requested in the passed in touchscreen_properties and store
* the result in a struct input_mt_pos.
*/
void
touchscreen_set_mt_pos
(
struct
input_mt_pos
*
pos
,
const
struct
touchscreen_properties
*
prop
,
unsigned
int
x
,
unsigned
int
y
)
{
touchscreen_apply_prop_to_x_y
(
prop
,
&
x
,
&
y
);
pos
->
x
=
x
;
pos
->
y
=
y
;
}
EXPORT_SYMBOL
(
touchscreen_set_mt_pos
);
/**
* touchscreen_report_pos - Report touchscreen coordinates
* @input: input_device to report coordinates for
* @prop: pointer to a struct touchscreen_properties
* @x: X coordinate to report
* @y: Y coordinate to report
* @multitouch: Report coordinates on single-touch or multi-touch axes
*
* Adjust the passed in x and y values applying any axis inversion and
* swapping requested in the passed in touchscreen_properties and then
* report the resulting coordinates on the input_dev's x and y axis.
*/
void
touchscreen_report_pos
(
struct
input_dev
*
input
,
const
struct
touchscreen_properties
*
prop
,
unsigned
int
x
,
unsigned
int
y
,
bool
multitouch
)
{
touchscreen_apply_prop_to_x_y
(
prop
,
&
x
,
&
y
);
input_report_abs
(
input
,
multitouch
?
ABS_MT_POSITION_X
:
ABS_X
,
x
);
input_report_abs
(
input
,
multitouch
?
ABS_MT_POSITION_Y
:
ABS_Y
,
y
);
}
EXPORT_SYMBOL
(
touchscreen_report_pos
);
drivers/input/touchscreen/pixcir_i2c_ts.c
View file @
08088828
...
...
@@ -27,9 +27,9 @@
#include <linux/input/touchscreen.h>
#include <linux/gpio.h>
#include <linux/gpio/consumer.h>
/*#include <linux/of.h>*/
#include <linux/of_device.h>
#include <linux/platform_data/pixcir_i2c_ts.h>
#include <asm/unaligned.h>
#define PIXCIR_MAX_SLOTS 5
/* Max fingers supported by driver */
...
...
@@ -41,19 +41,15 @@ struct pixcir_i2c_ts_data {
struct
gpio_desc
*
gpio_enable
;
struct
gpio_desc
*
gpio_wake
;
const
struct
pixcir_i2c_chip_data
*
chip
;
struct
touchscreen_properties
prop
;
int
max_fingers
;
/* Max fingers supported in this instance */
bool
running
;
};
struct
pixcir_touch
{
int
x
;
int
y
;
int
id
;
};
struct
pixcir_report_data
{
int
num_touches
;
struct
pixcir_touch
touches
[
PIXCIR_MAX_SLOTS
];
struct
input_mt_pos
pos
[
PIXCIR_MAX_SLOTS
];
int
ids
[
PIXCIR_MAX_SLOTS
];
};
static
void
pixcir_ts_parse
(
struct
pixcir_i2c_ts_data
*
tsdata
,
...
...
@@ -98,11 +94,11 @@ static void pixcir_ts_parse(struct pixcir_i2c_ts_data *tsdata,
bufptr
=
&
rdbuf
[
2
];
for
(
i
=
0
;
i
<
touch
;
i
++
)
{
report
->
touches
[
i
].
x
=
(
bufptr
[
1
]
<<
8
)
|
bufptr
[
0
];
report
->
touches
[
i
].
y
=
(
bufptr
[
3
]
<<
8
)
|
bufptr
[
2
];
touchscreen_set_mt_pos
(
&
report
->
pos
[
i
],
&
tsdata
->
prop
,
get_unaligned_le16
(
bufptr
),
get_unaligned_le16
(
bufptr
+
2
));
if
(
chip
->
has_hw_ids
)
{
report
->
touches
[
i
].
id
=
bufptr
[
4
];
report
->
ids
[
i
]
=
bufptr
[
4
];
bufptr
=
bufptr
+
5
;
}
else
{
bufptr
=
bufptr
+
4
;
...
...
@@ -113,9 +109,7 @@ static void pixcir_ts_parse(struct pixcir_i2c_ts_data *tsdata,
static
void
pixcir_ts_report
(
struct
pixcir_i2c_ts_data
*
ts
,
struct
pixcir_report_data
*
report
)
{
struct
input_mt_pos
pos
[
PIXCIR_MAX_SLOTS
];
int
slots
[
PIXCIR_MAX_SLOTS
];
struct
pixcir_touch
*
touch
;
int
n
,
i
,
slot
;
struct
device
*
dev
=
&
ts
->
client
->
dev
;
const
struct
pixcir_i2c_chip_data
*
chip
=
ts
->
chip
;
...
...
@@ -124,24 +118,16 @@ static void pixcir_ts_report(struct pixcir_i2c_ts_data *ts,
if
(
n
>
PIXCIR_MAX_SLOTS
)
n
=
PIXCIR_MAX_SLOTS
;
if
(
!
ts
->
chip
->
has_hw_ids
)
{
for
(
i
=
0
;
i
<
n
;
i
++
)
{
touch
=
&
report
->
touches
[
i
];
pos
[
i
].
x
=
touch
->
x
;
pos
[
i
].
y
=
touch
->
y
;
}
input_mt_assign_slots
(
ts
->
input
,
slots
,
pos
,
n
,
0
);
}
if
(
!
ts
->
chip
->
has_hw_ids
)
input_mt_assign_slots
(
ts
->
input
,
slots
,
report
->
pos
,
n
,
0
);
for
(
i
=
0
;
i
<
n
;
i
++
)
{
touch
=
&
report
->
touches
[
i
];
if
(
chip
->
has_hw_ids
)
{
slot
=
input_mt_get_slot_by_key
(
ts
->
input
,
touch
->
id
);
slot
=
input_mt_get_slot_by_key
(
ts
->
input
,
report
->
ids
[
i
]);
if
(
slot
<
0
)
{
dev_dbg
(
dev
,
"no free slot for id 0x%x
\n
"
,
touch
->
id
);
report
->
ids
[
i
]
);
continue
;
}
}
else
{
...
...
@@ -149,14 +135,15 @@ static void pixcir_ts_report(struct pixcir_i2c_ts_data *ts,
}
input_mt_slot
(
ts
->
input
,
slot
);
input_mt_report_slot_state
(
ts
->
input
,
MT_TOOL_FINGER
,
true
);
input_mt_report_slot_state
(
ts
->
input
,
MT_TOOL_FINGER
,
true
);
input_event
(
ts
->
input
,
EV_ABS
,
ABS_MT_POSITION_X
,
touch
->
x
);
input_event
(
ts
->
input
,
EV_ABS
,
ABS_MT_POSITION_Y
,
touch
->
y
);
input_report_abs
(
ts
->
input
,
ABS_MT_POSITION_X
,
report
->
pos
[
i
].
x
);
input_report_abs
(
ts
->
input
,
ABS_MT_POSITION_Y
,
report
->
pos
[
i
].
y
);
dev_dbg
(
dev
,
"%d: slot %d, x %d, y %d
\n
"
,
i
,
slot
,
touch
->
x
,
touch
->
y
);
i
,
slot
,
report
->
pos
[
i
].
x
,
report
->
pos
[
i
].
y
);
}
input_mt_sync_frame
(
ts
->
input
);
...
...
@@ -515,7 +502,7 @@ static int pixcir_i2c_ts_probe(struct i2c_client *client,
}
else
{
input_set_capability
(
input
,
EV_ABS
,
ABS_MT_POSITION_X
);
input_set_capability
(
input
,
EV_ABS
,
ABS_MT_POSITION_Y
);
touchscreen_parse_properties
(
input
,
true
);
touchscreen_parse_properties
(
input
,
true
,
&
tsdata
->
prop
);
if
(
!
input_abs_get_max
(
input
,
ABS_MT_POSITION_X
)
||
!
input_abs_get_max
(
input
,
ABS_MT_POSITION_Y
))
{
dev_err
(
dev
,
"Touchscreen size is not specified
\n
"
);
...
...
drivers/input/touchscreen/raydium_i2c_ts.c
0 → 100644
View file @
08088828
/*
* Raydium touchscreen I2C driver.
*
* Copyright (C) 2012-2014, Raydium Semiconductor Corporation.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2, and only version 2, as published by the
* Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* Raydium reserves the right to make changes without further notice
* to the materials described herein. Raydium does not assume any
* liability arising out of the application described herein.
*
* Contact Raydium Semiconductor Corporation at www.rad-ic.com
*/
#include <linux/acpi.h>
#include <linux/delay.h>
#include <linux/firmware.h>
#include <linux/gpio/consumer.h>
#include <linux/i2c.h>
#include <linux/input.h>
#include <linux/input/mt.h>
#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/regulator/consumer.h>
#include <linux/slab.h>
#include <asm/unaligned.h>
/* Slave I2C mode */
#define RM_BOOT_BLDR 0x02
#define RM_BOOT_MAIN 0x03
/* I2C bootoloader commands */
#define RM_CMD_BOOT_PAGE_WRT 0x0B
/* send bl page write */
#define RM_CMD_BOOT_WRT 0x11
/* send bl write */
#define RM_CMD_BOOT_ACK 0x22
/* send ack*/
#define RM_CMD_BOOT_CHK 0x33
/* send data check */
#define RM_CMD_BOOT_READ 0x44
/* send wait bl data ready*/
#define RM_BOOT_RDY 0xFF
/* bl data ready */
/* I2C main commands */
#define RM_CMD_QUERY_BANK 0x2B
#define RM_CMD_DATA_BANK 0x4D
#define RM_CMD_ENTER_SLEEP 0x4E
#define RM_CMD_BANK_SWITCH 0xAA
#define RM_RESET_MSG_ADDR 0x40000004
#define RM_MAX_READ_SIZE 56
#define RM_PACKET_CRC_SIZE 2
/* Touch relative info */
#define RM_MAX_RETRIES 3
#define RM_MAX_TOUCH_NUM 10
#define RM_BOOT_DELAY_MS 100
/* Offsets in contact data */
#define RM_CONTACT_STATE_POS 0
#define RM_CONTACT_X_POS 1
#define RM_CONTACT_Y_POS 3
#define RM_CONTACT_PRESSURE_POS 5
#define RM_CONTACT_WIDTH_X_POS 6
#define RM_CONTACT_WIDTH_Y_POS 7
/* Bootloader relative info */
#define RM_BL_WRT_CMD_SIZE 3
/* bl flash wrt cmd size */
#define RM_BL_WRT_PKG_SIZE 32
/* bl wrt pkg size */
#define RM_BL_WRT_LEN (RM_BL_WRT_PKG_SIZE + RM_BL_WRT_CMD_SIZE)
#define RM_FW_PAGE_SIZE 128
#define RM_MAX_FW_RETRIES 30
#define RM_MAX_FW_SIZE 0xD000
#define RM_POWERON_DELAY_USEC 500
#define RM_RESET_DELAY_MSEC 50
enum
raydium_bl_cmd
{
BL_HEADER
=
0
,
BL_PAGE_STR
,
BL_PKG_IDX
,
BL_DATA_STR
,
};
enum
raydium_bl_ack
{
RAYDIUM_ACK_NULL
=
0
,
RAYDIUM_WAIT_READY
,
RAYDIUM_PATH_READY
,
};
enum
raydium_boot_mode
{
RAYDIUM_TS_MAIN
=
0
,
RAYDIUM_TS_BLDR
,
};
/* Response to RM_CMD_DATA_BANK request */
struct
raydium_data_info
{
__le32
data_bank_addr
;
u8
pkg_size
;
u8
tp_info_size
;
};
struct
raydium_info
{
__le32
hw_ver
;
/*device version */
u8
main_ver
;
u8
sub_ver
;
__le16
ft_ver
;
/* test version */
u8
x_num
;
u8
y_num
;
__le16
x_max
;
__le16
y_max
;
u8
x_res
;
/* units/mm */
u8
y_res
;
/* units/mm */
};
/* struct raydium_data - represents state of Raydium touchscreen device */
struct
raydium_data
{
struct
i2c_client
*
client
;
struct
input_dev
*
input
;
struct
regulator
*
avdd
;
struct
regulator
*
vccio
;
struct
gpio_desc
*
reset_gpio
;
struct
raydium_info
info
;
struct
mutex
sysfs_mutex
;
u8
*
report_data
;
u32
data_bank_addr
;
u8
report_size
;
u8
contact_size
;
u8
pkg_size
;
enum
raydium_boot_mode
boot_mode
;
bool
wake_irq_enabled
;
};
static
int
raydium_i2c_send
(
struct
i2c_client
*
client
,
u8
addr
,
const
void
*
data
,
size_t
len
)
{
u8
*
buf
;
int
tries
=
0
;
int
ret
;
buf
=
kmalloc
(
len
+
1
,
GFP_KERNEL
);
if
(
!
buf
)
return
-
ENOMEM
;
buf
[
0
]
=
addr
;
memcpy
(
buf
+
1
,
data
,
len
);
do
{
ret
=
i2c_master_send
(
client
,
buf
,
len
+
1
);
if
(
likely
(
ret
==
len
+
1
))
break
;
msleep
(
20
);
}
while
(
++
tries
<
RM_MAX_RETRIES
);
kfree
(
buf
);
if
(
unlikely
(
ret
!=
len
+
1
))
{
if
(
ret
>=
0
)
ret
=
-
EIO
;
dev_err
(
&
client
->
dev
,
"%s failed: %d
\n
"
,
__func__
,
ret
);
return
ret
;
}
return
0
;
}
static
int
raydium_i2c_read
(
struct
i2c_client
*
client
,
u8
addr
,
void
*
data
,
size_t
len
)
{
struct
i2c_msg
xfer
[]
=
{
{
.
addr
=
client
->
addr
,
.
len
=
1
,
.
buf
=
&
addr
,
},
{
.
addr
=
client
->
addr
,
.
flags
=
I2C_M_RD
,
.
len
=
len
,
.
buf
=
data
,
}
};
int
ret
;
ret
=
i2c_transfer
(
client
->
adapter
,
xfer
,
ARRAY_SIZE
(
xfer
));
if
(
unlikely
(
ret
!=
ARRAY_SIZE
(
xfer
)))
return
ret
<
0
?
ret
:
-
EIO
;
return
0
;
}
static
int
raydium_i2c_read_message
(
struct
i2c_client
*
client
,
u32
addr
,
void
*
data
,
size_t
len
)
{
__be32
be_addr
;
size_t
xfer_len
;
int
error
;
while
(
len
)
{
xfer_len
=
min_t
(
size_t
,
len
,
RM_MAX_READ_SIZE
);
be_addr
=
cpu_to_be32
(
addr
);
error
=
raydium_i2c_send
(
client
,
RM_CMD_BANK_SWITCH
,
&
be_addr
,
sizeof
(
be_addr
));
if
(
!
error
)
error
=
raydium_i2c_read
(
client
,
addr
&
0xff
,
data
,
xfer_len
);
if
(
error
)
return
error
;
len
-=
xfer_len
;
data
+=
xfer_len
;
addr
+=
xfer_len
;
}
return
0
;
}
static
int
raydium_i2c_send_message
(
struct
i2c_client
*
client
,
u32
addr
,
const
void
*
data
,
size_t
len
)
{
__be32
be_addr
=
cpu_to_be32
(
addr
);
int
error
;
error
=
raydium_i2c_send
(
client
,
RM_CMD_BANK_SWITCH
,
&
be_addr
,
sizeof
(
be_addr
));
if
(
!
error
)
error
=
raydium_i2c_send
(
client
,
addr
&
0xff
,
data
,
len
);
return
error
;
}
static
int
raydium_i2c_sw_reset
(
struct
i2c_client
*
client
)
{
const
u8
soft_rst_cmd
=
0x01
;
int
error
;
error
=
raydium_i2c_send_message
(
client
,
RM_RESET_MSG_ADDR
,
&
soft_rst_cmd
,
sizeof
(
soft_rst_cmd
));
if
(
error
)
{
dev_err
(
&
client
->
dev
,
"software reset failed: %d
\n
"
,
error
);
return
error
;
}
msleep
(
RM_RESET_DELAY_MSEC
);
return
0
;
}
static
int
raydium_i2c_query_ts_info
(
struct
raydium_data
*
ts
)
{
struct
i2c_client
*
client
=
ts
->
client
;
struct
raydium_data_info
data_info
;
__le32
query_bank_addr
;
int
error
,
retry_cnt
;
for
(
retry_cnt
=
0
;
retry_cnt
<
RM_MAX_RETRIES
;
retry_cnt
++
)
{
error
=
raydium_i2c_read
(
client
,
RM_CMD_DATA_BANK
,
&
data_info
,
sizeof
(
data_info
));
if
(
error
)
continue
;
/*
* Warn user if we already allocated memory for reports and
* then the size changed (due to firmware update?) and keep
* old size instead.
*/
if
(
ts
->
report_data
&&
ts
->
pkg_size
!=
data_info
.
pkg_size
)
{
dev_warn
(
&
client
->
dev
,
"report size changes, was: %d, new: %d
\n
"
,
ts
->
pkg_size
,
data_info
.
pkg_size
);
}
else
{
ts
->
pkg_size
=
data_info
.
pkg_size
;
ts
->
report_size
=
ts
->
pkg_size
-
RM_PACKET_CRC_SIZE
;
}
ts
->
contact_size
=
data_info
.
tp_info_size
;
ts
->
data_bank_addr
=
le32_to_cpu
(
data_info
.
data_bank_addr
);
dev_dbg
(
&
client
->
dev
,
"data_bank_addr: %#08x, report_size: %d, contact_size: %d
\n
"
,
ts
->
data_bank_addr
,
ts
->
report_size
,
ts
->
contact_size
);
error
=
raydium_i2c_read
(
client
,
RM_CMD_QUERY_BANK
,
&
query_bank_addr
,
sizeof
(
query_bank_addr
));
if
(
error
)
continue
;
error
=
raydium_i2c_read_message
(
client
,
le32_to_cpu
(
query_bank_addr
),
&
ts
->
info
,
sizeof
(
ts
->
info
));
if
(
error
)
continue
;
return
0
;
}
dev_err
(
&
client
->
dev
,
"failed to query device parameters: %d
\n
"
,
error
);
return
error
;
}
static
int
raydium_i2c_check_fw_status
(
struct
raydium_data
*
ts
)
{
struct
i2c_client
*
client
=
ts
->
client
;
static
const
u8
bl_ack
=
0x62
;
static
const
u8
main_ack
=
0x66
;
u8
buf
[
4
];
int
error
;
error
=
raydium_i2c_read
(
client
,
RM_CMD_BOOT_READ
,
buf
,
sizeof
(
buf
));
if
(
!
error
)
{
if
(
buf
[
0
]
==
bl_ack
)
ts
->
boot_mode
=
RAYDIUM_TS_BLDR
;
else
if
(
buf
[
0
]
==
main_ack
)
ts
->
boot_mode
=
RAYDIUM_TS_MAIN
;
return
0
;
}
return
error
;
}
static
int
raydium_i2c_initialize
(
struct
raydium_data
*
ts
)
{
struct
i2c_client
*
client
=
ts
->
client
;
int
error
,
retry_cnt
;
for
(
retry_cnt
=
0
;
retry_cnt
<
RM_MAX_RETRIES
;
retry_cnt
++
)
{
/* Wait for Hello packet */
msleep
(
RM_BOOT_DELAY_MS
);
error
=
raydium_i2c_check_fw_status
(
ts
);
if
(
error
)
{
dev_err
(
&
client
->
dev
,
"failed to read 'hello' packet: %d
\n
"
,
error
);
continue
;
}
if
(
ts
->
boot_mode
==
RAYDIUM_TS_BLDR
||
ts
->
boot_mode
==
RAYDIUM_TS_MAIN
)
{
break
;
}
}
if
(
error
)
ts
->
boot_mode
=
RAYDIUM_TS_BLDR
;
if
(
ts
->
boot_mode
==
RAYDIUM_TS_BLDR
)
{
ts
->
info
.
hw_ver
=
cpu_to_le32
(
0xffffffffUL
);
ts
->
info
.
main_ver
=
0xff
;
ts
->
info
.
sub_ver
=
0xff
;
}
else
{
raydium_i2c_query_ts_info
(
ts
);
}
return
error
;
}
static
int
raydium_i2c_bl_chk_state
(
struct
i2c_client
*
client
,
enum
raydium_bl_ack
state
)
{
static
const
u8
ack_ok
[]
=
{
0xFF
,
0x39
,
0x30
,
0x30
,
0x54
};
u8
rbuf
[
sizeof
(
ack_ok
)];
u8
retry
;
int
error
;
for
(
retry
=
0
;
retry
<
RM_MAX_FW_RETRIES
;
retry
++
)
{
switch
(
state
)
{
case
RAYDIUM_ACK_NULL
:
return
0
;
case
RAYDIUM_WAIT_READY
:
error
=
raydium_i2c_read
(
client
,
RM_CMD_BOOT_CHK
,
&
rbuf
[
0
],
1
);
if
(
!
error
&&
rbuf
[
0
]
==
RM_BOOT_RDY
)
return
0
;
break
;
case
RAYDIUM_PATH_READY
:
error
=
raydium_i2c_read
(
client
,
RM_CMD_BOOT_CHK
,
rbuf
,
sizeof
(
rbuf
));
if
(
!
error
&&
!
memcmp
(
rbuf
,
ack_ok
,
sizeof
(
ack_ok
)))
return
0
;
break
;
default:
dev_err
(
&
client
->
dev
,
"%s: invalid target state %d
\n
"
,
__func__
,
state
);
return
-
EINVAL
;
}
msleep
(
20
);
}
return
-
ETIMEDOUT
;
}
static
int
raydium_i2c_write_object
(
struct
i2c_client
*
client
,
const
void
*
data
,
size_t
len
,
enum
raydium_bl_ack
state
)
{
int
error
;
error
=
raydium_i2c_send
(
client
,
RM_CMD_BOOT_WRT
,
data
,
len
);
if
(
error
)
{
dev_err
(
&
client
->
dev
,
"WRT obj command failed: %d
\n
"
,
error
);
return
error
;
}
error
=
raydium_i2c_send
(
client
,
RM_CMD_BOOT_ACK
,
NULL
,
0
);
if
(
error
)
{
dev_err
(
&
client
->
dev
,
"Ack obj command failed: %d
\n
"
,
error
);
return
error
;
}
error
=
raydium_i2c_bl_chk_state
(
client
,
state
);
if
(
error
)
{
dev_err
(
&
client
->
dev
,
"BL check state failed: %d
\n
"
,
error
);
return
error
;
}
return
0
;
}
static
bool
raydium_i2c_boot_trigger
(
struct
i2c_client
*
client
)
{
static
const
u8
cmd
[
7
][
6
]
=
{
{
0x08
,
0x0C
,
0x09
,
0x00
,
0x50
,
0xD7
},
{
0x08
,
0x04
,
0x09
,
0x00
,
0x50
,
0xA5
},
{
0x08
,
0x04
,
0x09
,
0x00
,
0x50
,
0x00
},
{
0x08
,
0x04
,
0x09
,
0x00
,
0x50
,
0xA5
},
{
0x08
,
0x0C
,
0x09
,
0x00
,
0x50
,
0x00
},
{
0x06
,
0x01
,
0x00
,
0x00
,
0x00
,
0x00
},
{
0x02
,
0xA2
,
0x00
,
0x00
,
0x00
,
0x00
},
};
int
i
;
int
error
;
for
(
i
=
0
;
i
<
7
;
i
++
)
{
error
=
raydium_i2c_write_object
(
client
,
cmd
[
i
],
sizeof
(
cmd
[
i
]),
RAYDIUM_WAIT_READY
);
if
(
error
)
{
dev_err
(
&
client
->
dev
,
"boot trigger failed at step %d: %d
\n
"
,
i
,
error
);
return
error
;
}
}
return
0
;
}
static
bool
raydium_i2c_fw_trigger
(
struct
i2c_client
*
client
)
{
static
const
u8
cmd
[
5
][
11
]
=
{
{
0
,
0x09
,
0x71
,
0x0C
,
0x09
,
0x00
,
0x50
,
0xD7
,
0
,
0
,
0
},
{
0
,
0x09
,
0x71
,
0x04
,
0x09
,
0x00
,
0x50
,
0xA5
,
0
,
0
,
0
},
{
0
,
0x09
,
0x71
,
0x04
,
0x09
,
0x00
,
0x50
,
0x00
,
0
,
0
,
0
},
{
0
,
0x09
,
0x71
,
0x04
,
0x09
,
0x00
,
0x50
,
0xA5
,
0
,
0
,
0
},
{
0
,
0x09
,
0x71
,
0x0C
,
0x09
,
0x00
,
0x50
,
0x00
,
0
,
0
,
0
},
};
int
i
;
int
error
;
for
(
i
=
0
;
i
<
5
;
i
++
)
{
error
=
raydium_i2c_write_object
(
client
,
cmd
[
i
],
sizeof
(
cmd
[
i
]),
RAYDIUM_ACK_NULL
);
if
(
error
)
{
dev_err
(
&
client
->
dev
,
"fw trigger failed at step %d: %d
\n
"
,
i
,
error
);
return
error
;
}
}
return
0
;
}
static
int
raydium_i2c_check_path
(
struct
i2c_client
*
client
)
{
static
const
u8
cmd
[]
=
{
0x09
,
0x00
,
0x09
,
0x00
,
0x50
,
0x10
,
0x00
};
int
error
;
error
=
raydium_i2c_write_object
(
client
,
cmd
,
sizeof
(
cmd
),
RAYDIUM_PATH_READY
);
if
(
error
)
{
dev_err
(
&
client
->
dev
,
"check path command failed: %d
\n
"
,
error
);
return
error
;
}
return
0
;
}
static
int
raydium_i2c_enter_bl
(
struct
i2c_client
*
client
)
{
static
const
u8
cal_cmd
[]
=
{
0x00
,
0x01
,
0x52
};
int
error
;
error
=
raydium_i2c_write_object
(
client
,
cal_cmd
,
sizeof
(
cal_cmd
),
RAYDIUM_ACK_NULL
);
if
(
error
)
{
dev_err
(
&
client
->
dev
,
"enter bl command failed: %d
\n
"
,
error
);
return
error
;
}
msleep
(
RM_BOOT_DELAY_MS
);
return
0
;
}
static
int
raydium_i2c_leave_bl
(
struct
i2c_client
*
client
)
{
static
const
u8
leave_cmd
[]
=
{
0x05
,
0x00
};
int
error
;
error
=
raydium_i2c_write_object
(
client
,
leave_cmd
,
sizeof
(
leave_cmd
),
RAYDIUM_ACK_NULL
);
if
(
error
)
{
dev_err
(
&
client
->
dev
,
"leave bl command failed: %d
\n
"
,
error
);
return
error
;
}
msleep
(
RM_BOOT_DELAY_MS
);
return
0
;
}
static
int
raydium_i2c_write_checksum
(
struct
i2c_client
*
client
,
size_t
length
,
u16
checksum
)
{
u8
checksum_cmd
[]
=
{
0x00
,
0x05
,
0x6D
,
0x00
,
0x00
,
0x00
,
0x00
};
int
error
;
put_unaligned_le16
(
length
,
&
checksum_cmd
[
3
]);
put_unaligned_le16
(
checksum
,
&
checksum_cmd
[
5
]);
error
=
raydium_i2c_write_object
(
client
,
checksum_cmd
,
sizeof
(
checksum_cmd
),
RAYDIUM_ACK_NULL
);
if
(
error
)
{
dev_err
(
&
client
->
dev
,
"failed to write checksum: %d
\n
"
,
error
);
return
error
;
}
return
0
;
}
static
int
raydium_i2c_disable_watch_dog
(
struct
i2c_client
*
client
)
{
static
const
u8
cmd
[]
=
{
0x0A
,
0xAA
};
int
error
;
error
=
raydium_i2c_write_object
(
client
,
cmd
,
sizeof
(
cmd
),
RAYDIUM_WAIT_READY
);
if
(
error
)
{
dev_err
(
&
client
->
dev
,
"disable watchdog command failed: %d
\n
"
,
error
);
return
error
;
}
return
0
;
}
static
int
raydium_i2c_fw_write_page
(
struct
i2c_client
*
client
,
u16
page_idx
,
const
void
*
data
,
size_t
len
)
{
u8
buf
[
RM_BL_WRT_LEN
];
size_t
xfer_len
;
int
error
;
int
i
;
BUILD_BUG_ON
((
RM_FW_PAGE_SIZE
%
RM_BL_WRT_PKG_SIZE
)
!=
0
);
for
(
i
=
0
;
i
<
RM_FW_PAGE_SIZE
/
RM_BL_WRT_PKG_SIZE
;
i
++
)
{
buf
[
BL_HEADER
]
=
RM_CMD_BOOT_PAGE_WRT
;
buf
[
BL_PAGE_STR
]
=
page_idx
?
0xff
:
0
;
buf
[
BL_PKG_IDX
]
=
i
+
1
;
xfer_len
=
min_t
(
size_t
,
len
,
RM_BL_WRT_PKG_SIZE
);
memcpy
(
&
buf
[
BL_DATA_STR
],
data
,
xfer_len
);
if
(
len
<
RM_BL_WRT_PKG_SIZE
)
memset
(
&
buf
[
BL_DATA_STR
+
xfer_len
],
0xff
,
RM_BL_WRT_PKG_SIZE
-
xfer_len
);
error
=
raydium_i2c_write_object
(
client
,
buf
,
RM_BL_WRT_LEN
,
RAYDIUM_WAIT_READY
);
if
(
error
)
{
dev_err
(
&
client
->
dev
,
"page write command failed for page %d, chunk %d: %d
\n
"
,
page_idx
,
i
,
error
);
return
error
;
}
data
+=
xfer_len
;
len
-=
xfer_len
;
}
return
error
;
}
static
u16
raydium_calc_chksum
(
const
u8
*
buf
,
u16
len
)
{
u16
checksum
=
0
;
u16
i
;
for
(
i
=
0
;
i
<
len
;
i
++
)
checksum
+=
buf
[
i
];
return
checksum
;
}
static
int
raydium_i2c_do_update_firmware
(
struct
raydium_data
*
ts
,
const
struct
firmware
*
fw
)
{
struct
i2c_client
*
client
=
ts
->
client
;
const
void
*
data
;
size_t
data_len
;
size_t
len
;
int
page_nr
;
int
i
;
int
error
;
u16
fw_checksum
;
if
(
fw
->
size
==
0
||
fw
->
size
>
RM_MAX_FW_SIZE
)
{
dev_err
(
&
client
->
dev
,
"Invalid firmware length
\n
"
);
return
-
EINVAL
;
}
error
=
raydium_i2c_check_fw_status
(
ts
);
if
(
error
)
{
dev_err
(
&
client
->
dev
,
"Unable to access IC %d
\n
"
,
error
);
return
error
;
}
if
(
ts
->
boot_mode
==
RAYDIUM_TS_MAIN
)
{
for
(
i
=
0
;
i
<
RM_MAX_RETRIES
;
i
++
)
{
error
=
raydium_i2c_enter_bl
(
client
);
if
(
!
error
)
{
error
=
raydium_i2c_check_fw_status
(
ts
);
if
(
error
)
{
dev_err
(
&
client
->
dev
,
"unable to access IC: %d
\n
"
,
error
);
return
error
;
}
if
(
ts
->
boot_mode
==
RAYDIUM_TS_BLDR
)
break
;
}
}
if
(
ts
->
boot_mode
==
RAYDIUM_TS_MAIN
)
{
dev_err
(
&
client
->
dev
,
"failied to jump to boot loader: %d
\n
"
,
error
);
return
-
EIO
;
}
}
error
=
raydium_i2c_disable_watch_dog
(
client
);
if
(
error
)
return
error
;
error
=
raydium_i2c_check_path
(
client
);
if
(
error
)
return
error
;
error
=
raydium_i2c_boot_trigger
(
client
);
if
(
error
)
{
dev_err
(
&
client
->
dev
,
"send boot trigger fail: %d
\n
"
,
error
);
return
error
;
}
msleep
(
RM_BOOT_DELAY_MS
);
data
=
fw
->
data
;
data_len
=
fw
->
size
;
page_nr
=
0
;
while
(
data_len
)
{
len
=
min_t
(
size_t
,
data_len
,
RM_FW_PAGE_SIZE
);
error
=
raydium_i2c_fw_write_page
(
client
,
page_nr
++
,
data
,
len
);
if
(
error
)
return
error
;
msleep
(
20
);
data
+=
len
;
data_len
-=
len
;
}
error
=
raydium_i2c_leave_bl
(
client
);
if
(
error
)
{
dev_err
(
&
client
->
dev
,
"failed to leave boot loader: %d
\n
"
,
error
);
return
error
;
}
dev_dbg
(
&
client
->
dev
,
"left boot loader mode
\n
"
);
msleep
(
RM_BOOT_DELAY_MS
);
error
=
raydium_i2c_check_fw_status
(
ts
);
if
(
error
)
{
dev_err
(
&
client
->
dev
,
"failed to check fw status after write: %d
\n
"
,
error
);
return
error
;
}
if
(
ts
->
boot_mode
!=
RAYDIUM_TS_MAIN
)
{
dev_err
(
&
client
->
dev
,
"failed to switch to main fw after writing firmware: %d
\n
"
,
error
);
return
-
EINVAL
;
}
error
=
raydium_i2c_fw_trigger
(
client
);
if
(
error
)
{
dev_err
(
&
client
->
dev
,
"failed to trigger fw: %d
\n
"
,
error
);
return
error
;
}
fw_checksum
=
raydium_calc_chksum
(
fw
->
data
,
fw
->
size
);
error
=
raydium_i2c_write_checksum
(
client
,
fw
->
size
,
fw_checksum
);
if
(
error
)
return
error
;
return
0
;
}
static
int
raydium_i2c_fw_update
(
struct
raydium_data
*
ts
)
{
struct
i2c_client
*
client
=
ts
->
client
;
const
struct
firmware
*
fw
=
NULL
;
const
char
*
fw_file
=
"raydium.fw"
;
int
error
;
error
=
request_firmware
(
&
fw
,
fw_file
,
&
client
->
dev
);
if
(
error
)
{
dev_err
(
&
client
->
dev
,
"Unable to open firmware %s
\n
"
,
fw_file
);
return
error
;
}
disable_irq
(
client
->
irq
);
error
=
raydium_i2c_do_update_firmware
(
ts
,
fw
);
if
(
error
)
{
dev_err
(
&
client
->
dev
,
"firmware update failed: %d
\n
"
,
error
);
ts
->
boot_mode
=
RAYDIUM_TS_BLDR
;
goto
out_enable_irq
;
}
error
=
raydium_i2c_initialize
(
ts
);
if
(
error
)
{
dev_err
(
&
client
->
dev
,
"failed to initialize device after firmware update: %d
\n
"
,
error
);
ts
->
boot_mode
=
RAYDIUM_TS_BLDR
;
goto
out_enable_irq
;
}
ts
->
boot_mode
=
RAYDIUM_TS_MAIN
;
out_enable_irq:
enable_irq
(
client
->
irq
);
msleep
(
100
);
release_firmware
(
fw
);
return
error
;
}
static
void
raydium_mt_event
(
struct
raydium_data
*
ts
)
{
int
i
;
for
(
i
=
0
;
i
<
ts
->
report_size
/
ts
->
contact_size
;
i
++
)
{
u8
*
contact
=
&
ts
->
report_data
[
ts
->
contact_size
*
i
];
bool
state
=
contact
[
RM_CONTACT_STATE_POS
];
u8
wx
,
wy
;
input_mt_slot
(
ts
->
input
,
i
);
input_mt_report_slot_state
(
ts
->
input
,
MT_TOOL_FINGER
,
state
);
if
(
!
state
)
continue
;
input_report_abs
(
ts
->
input
,
ABS_MT_POSITION_X
,
get_unaligned_le16
(
&
contact
[
RM_CONTACT_X_POS
]));
input_report_abs
(
ts
->
input
,
ABS_MT_POSITION_Y
,
get_unaligned_le16
(
&
contact
[
RM_CONTACT_Y_POS
]));
input_report_abs
(
ts
->
input
,
ABS_MT_PRESSURE
,
contact
[
RM_CONTACT_PRESSURE_POS
]);
wx
=
contact
[
RM_CONTACT_WIDTH_X_POS
];
wy
=
contact
[
RM_CONTACT_WIDTH_Y_POS
];
input_report_abs
(
ts
->
input
,
ABS_MT_TOUCH_MAJOR
,
max
(
wx
,
wy
));
input_report_abs
(
ts
->
input
,
ABS_MT_TOUCH_MINOR
,
min
(
wx
,
wy
));
}
input_mt_sync_frame
(
ts
->
input
);
input_sync
(
ts
->
input
);
}
static
irqreturn_t
raydium_i2c_irq
(
int
irq
,
void
*
_dev
)
{
struct
raydium_data
*
ts
=
_dev
;
int
error
;
u16
fw_crc
;
u16
calc_crc
;
if
(
ts
->
boot_mode
!=
RAYDIUM_TS_MAIN
)
goto
out
;
error
=
raydium_i2c_read_message
(
ts
->
client
,
ts
->
data_bank_addr
,
ts
->
report_data
,
ts
->
pkg_size
);
if
(
error
)
goto
out
;
fw_crc
=
get_unaligned_le16
(
&
ts
->
report_data
[
ts
->
report_size
]);
calc_crc
=
raydium_calc_chksum
(
ts
->
report_data
,
ts
->
report_size
);
if
(
unlikely
(
fw_crc
!=
calc_crc
))
{
dev_warn
(
&
ts
->
client
->
dev
,
"%s: invalid packet crc %#04x vs %#04x
\n
"
,
__func__
,
calc_crc
,
fw_crc
);
goto
out
;
}
raydium_mt_event
(
ts
);
out:
return
IRQ_HANDLED
;
}
static
ssize_t
raydium_i2c_fw_ver_show
(
struct
device
*
dev
,
struct
device_attribute
*
attr
,
char
*
buf
)
{
struct
i2c_client
*
client
=
to_i2c_client
(
dev
);
struct
raydium_data
*
ts
=
i2c_get_clientdata
(
client
);
return
sprintf
(
buf
,
"%d.%d
\n
"
,
ts
->
info
.
main_ver
,
ts
->
info
.
sub_ver
);
}
static
ssize_t
raydium_i2c_hw_ver_show
(
struct
device
*
dev
,
struct
device_attribute
*
attr
,
char
*
buf
)
{
struct
i2c_client
*
client
=
to_i2c_client
(
dev
);
struct
raydium_data
*
ts
=
i2c_get_clientdata
(
client
);
return
sprintf
(
buf
,
"%#04x
\n
"
,
le32_to_cpu
(
ts
->
info
.
hw_ver
));
}
static
ssize_t
raydium_i2c_boot_mode_show
(
struct
device
*
dev
,
struct
device_attribute
*
attr
,
char
*
buf
)
{
struct
i2c_client
*
client
=
to_i2c_client
(
dev
);
struct
raydium_data
*
ts
=
i2c_get_clientdata
(
client
);
return
sprintf
(
buf
,
"%s
\n
"
,
ts
->
boot_mode
==
RAYDIUM_TS_MAIN
?
"Normal"
:
"Recovery"
);
}
static
ssize_t
raydium_i2c_update_fw_store
(
struct
device
*
dev
,
struct
device_attribute
*
attr
,
const
char
*
buf
,
size_t
count
)
{
struct
i2c_client
*
client
=
to_i2c_client
(
dev
);
struct
raydium_data
*
ts
=
i2c_get_clientdata
(
client
);
int
error
;
error
=
mutex_lock_interruptible
(
&
ts
->
sysfs_mutex
);
if
(
error
)
return
error
;
error
=
raydium_i2c_fw_update
(
ts
);
mutex_unlock
(
&
ts
->
sysfs_mutex
);
return
error
?:
count
;
}
static
ssize_t
raydium_i2c_calibrate_store
(
struct
device
*
dev
,
struct
device_attribute
*
attr
,
const
char
*
buf
,
size_t
count
)
{
struct
i2c_client
*
client
=
to_i2c_client
(
dev
);
struct
raydium_data
*
ts
=
i2c_get_clientdata
(
client
);
static
const
u8
cal_cmd
[]
=
{
0x00
,
0x01
,
0x9E
};
int
error
;
error
=
mutex_lock_interruptible
(
&
ts
->
sysfs_mutex
);
if
(
error
)
return
error
;
error
=
raydium_i2c_write_object
(
client
,
cal_cmd
,
sizeof
(
cal_cmd
),
RAYDIUM_WAIT_READY
);
if
(
error
)
dev_err
(
&
client
->
dev
,
"calibrate command failed: %d
\n
"
,
error
);
mutex_unlock
(
&
ts
->
sysfs_mutex
);
return
error
?:
count
;
}
static
DEVICE_ATTR
(
fw_version
,
S_IRUGO
,
raydium_i2c_fw_ver_show
,
NULL
);
static
DEVICE_ATTR
(
hw_version
,
S_IRUGO
,
raydium_i2c_hw_ver_show
,
NULL
);
static
DEVICE_ATTR
(
boot_mode
,
S_IRUGO
,
raydium_i2c_boot_mode_show
,
NULL
);
static
DEVICE_ATTR
(
update_fw
,
S_IWUSR
,
NULL
,
raydium_i2c_update_fw_store
);
static
DEVICE_ATTR
(
calibrate
,
S_IWUSR
,
NULL
,
raydium_i2c_calibrate_store
);
static
struct
attribute
*
raydium_i2c_attributes
[]
=
{
&
dev_attr_update_fw
.
attr
,
&
dev_attr_boot_mode
.
attr
,
&
dev_attr_fw_version
.
attr
,
&
dev_attr_hw_version
.
attr
,
&
dev_attr_calibrate
.
attr
,
NULL
};
static
struct
attribute_group
raydium_i2c_attribute_group
=
{
.
attrs
=
raydium_i2c_attributes
,
};
static
void
raydium_i2c_remove_sysfs_group
(
void
*
_data
)
{
struct
raydium_data
*
ts
=
_data
;
sysfs_remove_group
(
&
ts
->
client
->
dev
.
kobj
,
&
raydium_i2c_attribute_group
);
}
static
int
raydium_i2c_power_on
(
struct
raydium_data
*
ts
)
{
int
error
;
if
(
!
ts
->
reset_gpio
)
return
0
;
gpiod_set_value_cansleep
(
ts
->
reset_gpio
,
1
);
error
=
regulator_enable
(
ts
->
avdd
);
if
(
error
)
{
dev_err
(
&
ts
->
client
->
dev
,
"failed to enable avdd regulator: %d
\n
"
,
error
);
goto
release_reset_gpio
;
}
error
=
regulator_enable
(
ts
->
vccio
);
if
(
error
)
{
regulator_disable
(
ts
->
avdd
);
dev_err
(
&
ts
->
client
->
dev
,
"failed to enable vccio regulator: %d
\n
"
,
error
);
goto
release_reset_gpio
;
}
udelay
(
RM_POWERON_DELAY_USEC
);
release_reset_gpio:
gpiod_set_value_cansleep
(
ts
->
reset_gpio
,
0
);
if
(
error
)
return
error
;
msleep
(
RM_RESET_DELAY_MSEC
);
return
0
;
}
static
void
raydium_i2c_power_off
(
void
*
_data
)
{
struct
raydium_data
*
ts
=
_data
;
if
(
ts
->
reset_gpio
)
{
gpiod_set_value_cansleep
(
ts
->
reset_gpio
,
1
);
regulator_disable
(
ts
->
vccio
);
regulator_disable
(
ts
->
avdd
);
}
}
static
int
raydium_i2c_probe
(
struct
i2c_client
*
client
,
const
struct
i2c_device_id
*
id
)
{
union
i2c_smbus_data
dummy
;
struct
raydium_data
*
ts
;
int
error
;
if
(
!
i2c_check_functionality
(
client
->
adapter
,
I2C_FUNC_I2C
))
{
dev_err
(
&
client
->
dev
,
"i2c check functionality error (need I2C_FUNC_I2C)
\n
"
);
return
-
ENXIO
;
}
ts
=
devm_kzalloc
(
&
client
->
dev
,
sizeof
(
*
ts
),
GFP_KERNEL
);
if
(
!
ts
)
return
-
ENOMEM
;
mutex_init
(
&
ts
->
sysfs_mutex
);
ts
->
client
=
client
;
i2c_set_clientdata
(
client
,
ts
);
ts
->
avdd
=
devm_regulator_get
(
&
client
->
dev
,
"avdd"
);
if
(
IS_ERR
(
ts
->
avdd
))
{
error
=
PTR_ERR
(
ts
->
avdd
);
if
(
error
!=
-
EPROBE_DEFER
)
dev_err
(
&
client
->
dev
,
"Failed to get 'avdd' regulator: %d
\n
"
,
error
);
return
error
;
}
ts
->
vccio
=
devm_regulator_get
(
&
client
->
dev
,
"vccio"
);
if
(
IS_ERR
(
ts
->
vccio
))
{
error
=
PTR_ERR
(
ts
->
vccio
);
if
(
error
!=
-
EPROBE_DEFER
)
dev_err
(
&
client
->
dev
,
"Failed to get 'vccio' regulator: %d
\n
"
,
error
);
return
error
;
}
ts
->
reset_gpio
=
devm_gpiod_get_optional
(
&
client
->
dev
,
"reset"
,
GPIOD_OUT_LOW
);
if
(
IS_ERR
(
ts
->
reset_gpio
))
{
error
=
PTR_ERR
(
ts
->
reset_gpio
);
if
(
error
!=
-
EPROBE_DEFER
)
dev_err
(
&
client
->
dev
,
"failed to get reset gpio: %d
\n
"
,
error
);
return
error
;
}
error
=
raydium_i2c_power_on
(
ts
);
if
(
error
)
return
error
;
error
=
devm_add_action
(
&
client
->
dev
,
raydium_i2c_power_off
,
ts
);
if
(
error
)
{
dev_err
(
&
client
->
dev
,
"failed to install power off action: %d
\n
"
,
error
);
raydium_i2c_power_off
(
ts
);
return
error
;
}
/* Make sure there is something at this address */
if
(
i2c_smbus_xfer
(
client
->
adapter
,
client
->
addr
,
0
,
I2C_SMBUS_READ
,
0
,
I2C_SMBUS_BYTE
,
&
dummy
)
<
0
)
{
dev_err
(
&
client
->
dev
,
"nothing at this address
\n
"
);
return
-
ENXIO
;
}
error
=
raydium_i2c_initialize
(
ts
);
if
(
error
)
{
dev_err
(
&
client
->
dev
,
"failed to initialize: %d
\n
"
,
error
);
return
error
;
}
ts
->
report_data
=
devm_kmalloc
(
&
client
->
dev
,
ts
->
pkg_size
,
GFP_KERNEL
);
if
(
!
ts
->
report_data
)
return
-
ENOMEM
;
ts
->
input
=
devm_input_allocate_device
(
&
client
->
dev
);
if
(
!
ts
->
input
)
{
dev_err
(
&
client
->
dev
,
"Failed to allocate input device
\n
"
);
return
-
ENOMEM
;
}
ts
->
input
->
name
=
"Raydium Touchscreen"
;
ts
->
input
->
id
.
bustype
=
BUS_I2C
;
input_set_drvdata
(
ts
->
input
,
ts
);
input_set_abs_params
(
ts
->
input
,
ABS_MT_POSITION_X
,
0
,
le16_to_cpu
(
ts
->
info
.
x_max
),
0
,
0
);
input_set_abs_params
(
ts
->
input
,
ABS_MT_POSITION_Y
,
0
,
le16_to_cpu
(
ts
->
info
.
y_max
),
0
,
0
);
input_abs_set_res
(
ts
->
input
,
ABS_MT_POSITION_X
,
ts
->
info
.
x_res
);
input_abs_set_res
(
ts
->
input
,
ABS_MT_POSITION_Y
,
ts
->
info
.
y_res
);
input_set_abs_params
(
ts
->
input
,
ABS_MT_TOUCH_MAJOR
,
0
,
255
,
0
,
0
);
input_set_abs_params
(
ts
->
input
,
ABS_MT_PRESSURE
,
0
,
255
,
0
,
0
);
error
=
input_mt_init_slots
(
ts
->
input
,
RM_MAX_TOUCH_NUM
,
INPUT_MT_DIRECT
|
INPUT_MT_DROP_UNUSED
);
if
(
error
)
{
dev_err
(
&
client
->
dev
,
"failed to initialize MT slots: %d
\n
"
,
error
);
return
error
;
}
error
=
input_register_device
(
ts
->
input
);
if
(
error
)
{
dev_err
(
&
client
->
dev
,
"unable to register input device: %d
\n
"
,
error
);
return
error
;
}
error
=
devm_request_threaded_irq
(
&
client
->
dev
,
client
->
irq
,
NULL
,
raydium_i2c_irq
,
IRQF_ONESHOT
,
client
->
name
,
ts
);
if
(
error
)
{
dev_err
(
&
client
->
dev
,
"Failed to register interrupt
\n
"
);
return
error
;
}
error
=
sysfs_create_group
(
&
client
->
dev
.
kobj
,
&
raydium_i2c_attribute_group
);
if
(
error
)
{
dev_err
(
&
client
->
dev
,
"failed to create sysfs attributes: %d
\n
"
,
error
);
return
error
;
}
error
=
devm_add_action
(
&
client
->
dev
,
raydium_i2c_remove_sysfs_group
,
ts
);
if
(
error
)
{
raydium_i2c_remove_sysfs_group
(
ts
);
dev_err
(
&
client
->
dev
,
"Failed to add sysfs cleanup action: %d
\n
"
,
error
);
return
error
;
}
return
0
;
}
static
void
__maybe_unused
raydium_enter_sleep
(
struct
i2c_client
*
client
)
{
static
const
u8
sleep_cmd
[]
=
{
0x5A
,
0xff
,
0x00
,
0x0f
};
int
error
;
error
=
raydium_i2c_send
(
client
,
RM_CMD_ENTER_SLEEP
,
sleep_cmd
,
sizeof
(
sleep_cmd
));
if
(
error
)
dev_err
(
&
client
->
dev
,
"sleep command failed: %d
\n
"
,
error
);
}
static
int
__maybe_unused
raydium_i2c_suspend
(
struct
device
*
dev
)
{
struct
i2c_client
*
client
=
to_i2c_client
(
dev
);
struct
raydium_data
*
ts
=
i2c_get_clientdata
(
client
);
/* Sleep is not available in BLDR recovery mode */
if
(
ts
->
boot_mode
!=
RAYDIUM_TS_MAIN
)
return
-
EBUSY
;
disable_irq
(
client
->
irq
);
if
(
device_may_wakeup
(
dev
))
{
raydium_enter_sleep
(
client
);
ts
->
wake_irq_enabled
=
(
enable_irq_wake
(
client
->
irq
)
==
0
);
}
else
{
raydium_i2c_power_off
(
ts
);
}
return
0
;
}
static
int
__maybe_unused
raydium_i2c_resume
(
struct
device
*
dev
)
{
struct
i2c_client
*
client
=
to_i2c_client
(
dev
);
struct
raydium_data
*
ts
=
i2c_get_clientdata
(
client
);
if
(
device_may_wakeup
(
dev
))
{
if
(
ts
->
wake_irq_enabled
)
disable_irq_wake
(
client
->
irq
);
raydium_i2c_sw_reset
(
client
);
}
else
{
raydium_i2c_power_on
(
ts
);
raydium_i2c_initialize
(
ts
);
}
enable_irq
(
client
->
irq
);
return
0
;
}
static
SIMPLE_DEV_PM_OPS
(
raydium_i2c_pm_ops
,
raydium_i2c_suspend
,
raydium_i2c_resume
);
static
const
struct
i2c_device_id
raydium_i2c_id
[]
=
{
{
"raydium_i2c"
,
0
},
{
"rm32380"
,
0
},
{
/* sentinel */
}
};
MODULE_DEVICE_TABLE
(
i2c
,
raydium_i2c_id
);
#ifdef CONFIG_ACPI
static
const
struct
acpi_device_id
raydium_acpi_id
[]
=
{
{
"RAYD0001"
,
0
},
{
/* sentinel */
}
};
MODULE_DEVICE_TABLE
(
acpi
,
raydium_acpi_id
);
#endif
#ifdef CONFIG_OF
static
const
struct
of_device_id
raydium_of_match
[]
=
{
{
.
compatible
=
"raydium,rm32380"
,
},
{
/* sentinel */
}
};
MODULE_DEVICE_TABLE
(
of
,
raydium_of_match
);
#endif
static
struct
i2c_driver
raydium_i2c_driver
=
{
.
probe
=
raydium_i2c_probe
,
.
id_table
=
raydium_i2c_id
,
.
driver
=
{
.
name
=
"raydium_ts"
,
.
pm
=
&
raydium_i2c_pm_ops
,
.
acpi_match_table
=
ACPI_PTR
(
raydium_acpi_id
),
.
of_match_table
=
of_match_ptr
(
raydium_of_match
),
},
};
module_i2c_driver
(
raydium_i2c_driver
);
MODULE_AUTHOR
(
"Raydium"
);
MODULE_DESCRIPTION
(
"Raydium I2c Touchscreen driver"
);
MODULE_LICENSE
(
"GPL v2"
);
drivers/input/touchscreen/surface3_spi.c
0 → 100644
View file @
08088828
/*
* Driver for Ntrig/Microsoft Touchscreens over SPI
*
* Copyright (c) 2016 Red Hat Inc.
*/
/*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation; version 2 of the License.
*/
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/gpio/consumer.h>
#include <linux/input.h>
#include <linux/input/mt.h>
#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/spi/spi.h>
#include <linux/acpi.h>
#include <asm/unaligned.h>
#define SURFACE3_PACKET_SIZE 264
#define SURFACE3_REPORT_TOUCH 0xd2
#define SURFACE3_REPORT_PEN 0x16
struct
surface3_ts_data
{
struct
spi_device
*
spi
;
struct
gpio_desc
*
gpiod_rst
[
2
];
struct
input_dev
*
input_dev
;
struct
input_dev
*
pen_input_dev
;
int
pen_tool
;
u8
rd_buf
[
SURFACE3_PACKET_SIZE
]
____cacheline_aligned
;
};
struct
surface3_ts_data_finger
{
u8
status
;
__le16
tracking_id
;
__le16
x
;
__le16
cx
;
__le16
y
;
__le16
cy
;
__le16
width
;
__le16
height
;
u32
padding
;
}
__packed
;
struct
surface3_ts_data_pen
{
u8
status
;
__le16
x
;
__le16
y
;
__le16
pressure
;
u8
padding
;
}
__packed
;
static
int
surface3_spi_read
(
struct
surface3_ts_data
*
ts_data
)
{
struct
spi_device
*
spi
=
ts_data
->
spi
;
memset
(
ts_data
->
rd_buf
,
0
,
sizeof
(
ts_data
->
rd_buf
));
return
spi_read
(
spi
,
ts_data
->
rd_buf
,
sizeof
(
ts_data
->
rd_buf
));
}
static
void
surface3_spi_report_touch
(
struct
surface3_ts_data
*
ts_data
,
struct
surface3_ts_data_finger
*
finger
)
{
int
st
=
finger
->
status
&
0x01
;
int
slot
;
slot
=
input_mt_get_slot_by_key
(
ts_data
->
input_dev
,
get_unaligned_le16
(
&
finger
->
tracking_id
));
if
(
slot
<
0
)
return
;
input_mt_slot
(
ts_data
->
input_dev
,
slot
);
input_mt_report_slot_state
(
ts_data
->
input_dev
,
MT_TOOL_FINGER
,
st
);
if
(
st
)
{
input_report_abs
(
ts_data
->
input_dev
,
ABS_MT_POSITION_X
,
get_unaligned_le16
(
&
finger
->
x
));
input_report_abs
(
ts_data
->
input_dev
,
ABS_MT_POSITION_Y
,
get_unaligned_le16
(
&
finger
->
y
));
input_report_abs
(
ts_data
->
input_dev
,
ABS_MT_WIDTH_MAJOR
,
get_unaligned_le16
(
&
finger
->
width
));
input_report_abs
(
ts_data
->
input_dev
,
ABS_MT_WIDTH_MINOR
,
get_unaligned_le16
(
&
finger
->
height
));
}
}
static
void
surface3_spi_process_touch
(
struct
surface3_ts_data
*
ts_data
,
u8
*
data
)
{
u16
timestamp
;
unsigned
int
i
;
timestamp
=
get_unaligned_le16
(
&
data
[
15
]);
for
(
i
=
0
;
i
<
13
;
i
++
)
{
struct
surface3_ts_data_finger
*
finger
;
finger
=
(
struct
surface3_ts_data_finger
*
)
&
data
[
17
+
i
*
sizeof
(
struct
surface3_ts_data_finger
)];
/*
* When bit 5 of status is 1, it marks the end of the report:
* - touch present: 0xe7
* - touch released: 0xe4
* - nothing valuable: 0xff
*/
if
(
finger
->
status
&
0x10
)
break
;
surface3_spi_report_touch
(
ts_data
,
finger
);
}
input_mt_sync_frame
(
ts_data
->
input_dev
);
input_sync
(
ts_data
->
input_dev
);
}
static
void
surface3_spi_report_pen
(
struct
surface3_ts_data
*
ts_data
,
struct
surface3_ts_data_pen
*
pen
)
{
struct
input_dev
*
dev
=
ts_data
->
pen_input_dev
;
int
st
=
pen
->
status
;
int
prox
=
st
&
0x01
;
int
rubber
=
st
&
0x18
;
int
tool
=
(
prox
&&
rubber
)
?
BTN_TOOL_RUBBER
:
BTN_TOOL_PEN
;
/* fake proximity out to switch tools */
if
(
ts_data
->
pen_tool
!=
tool
)
{
input_report_key
(
dev
,
ts_data
->
pen_tool
,
0
);
input_sync
(
dev
);
ts_data
->
pen_tool
=
tool
;
}
input_report_key
(
dev
,
BTN_TOUCH
,
st
&
0x12
);
input_report_key
(
dev
,
ts_data
->
pen_tool
,
prox
);
if
(
st
)
{
input_report_key
(
dev
,
BTN_STYLUS
,
st
&
0x04
);
input_report_abs
(
dev
,
ABS_X
,
get_unaligned_le16
(
&
pen
->
x
));
input_report_abs
(
dev
,
ABS_Y
,
get_unaligned_le16
(
&
pen
->
y
));
input_report_abs
(
dev
,
ABS_PRESSURE
,
get_unaligned_le16
(
&
pen
->
pressure
));
}
}
static
void
surface3_spi_process_pen
(
struct
surface3_ts_data
*
ts_data
,
u8
*
data
)
{
struct
surface3_ts_data_pen
*
pen
;
pen
=
(
struct
surface3_ts_data_pen
*
)
&
data
[
15
];
surface3_spi_report_pen
(
ts_data
,
pen
);
input_sync
(
ts_data
->
pen_input_dev
);
}
static
void
surface3_spi_process
(
struct
surface3_ts_data
*
ts_data
)
{
const
char
header
[]
=
{
0xff
,
0xff
,
0xff
,
0xff
,
0xa5
,
0x5a
,
0xe7
,
0x7e
,
0x01
};
u8
*
data
=
ts_data
->
rd_buf
;
if
(
memcmp
(
header
,
data
,
sizeof
(
header
)))
dev_err
(
&
ts_data
->
spi
->
dev
,
"%s header error: %*ph, ignoring...
\n
"
,
__func__
,
(
int
)
sizeof
(
header
),
data
);
switch
(
data
[
9
])
{
case
SURFACE3_REPORT_TOUCH
:
surface3_spi_process_touch
(
ts_data
,
data
);
break
;
case
SURFACE3_REPORT_PEN
:
surface3_spi_process_pen
(
ts_data
,
data
);
break
;
default:
dev_err
(
&
ts_data
->
spi
->
dev
,
"%s unknown packet type: %x, ignoring...
\n
"
,
__func__
,
data
[
9
]);
break
;
}
}
static
irqreturn_t
surface3_spi_irq_handler
(
int
irq
,
void
*
dev_id
)
{
struct
surface3_ts_data
*
data
=
dev_id
;
if
(
surface3_spi_read
(
data
))
return
IRQ_HANDLED
;
dev_dbg
(
&
data
->
spi
->
dev
,
"%s received -> %*ph
\n
"
,
__func__
,
SURFACE3_PACKET_SIZE
,
data
->
rd_buf
);
surface3_spi_process
(
data
);
return
IRQ_HANDLED
;
}
static
void
surface3_spi_power
(
struct
surface3_ts_data
*
data
,
bool
on
)
{
gpiod_set_value
(
data
->
gpiod_rst
[
0
],
on
);
gpiod_set_value
(
data
->
gpiod_rst
[
1
],
on
);
/* let the device settle a little */
msleep
(
20
);
}
/**
* surface3_spi_get_gpio_config - Get GPIO config from ACPI/DT
*
* @ts: surface3_spi_ts_data pointer
*/
static
int
surface3_spi_get_gpio_config
(
struct
surface3_ts_data
*
data
)
{
int
error
;
struct
device
*
dev
;
struct
gpio_desc
*
gpiod
;
int
i
;
dev
=
&
data
->
spi
->
dev
;
/* Get the reset lines GPIO pin number */
for
(
i
=
0
;
i
<
2
;
i
++
)
{
gpiod
=
devm_gpiod_get_index
(
dev
,
NULL
,
i
,
GPIOD_OUT_LOW
);
if
(
IS_ERR
(
gpiod
))
{
error
=
PTR_ERR
(
gpiod
);
if
(
error
!=
-
EPROBE_DEFER
)
dev_err
(
dev
,
"Failed to get power GPIO %d: %d
\n
"
,
i
,
error
);
return
error
;
}
data
->
gpiod_rst
[
i
]
=
gpiod
;
}
return
0
;
}
static
int
surface3_spi_create_touch_input
(
struct
surface3_ts_data
*
data
)
{
struct
input_dev
*
input
;
int
error
;
input
=
devm_input_allocate_device
(
&
data
->
spi
->
dev
);
if
(
!
input
)
return
-
ENOMEM
;
data
->
input_dev
=
input
;
input_set_abs_params
(
input
,
ABS_MT_POSITION_X
,
0
,
9600
,
0
,
0
);
input_abs_set_res
(
input
,
ABS_MT_POSITION_X
,
40
);
input_set_abs_params
(
input
,
ABS_MT_POSITION_Y
,
0
,
7200
,
0
,
0
);
input_abs_set_res
(
input
,
ABS_MT_POSITION_Y
,
48
);
input_set_abs_params
(
input
,
ABS_MT_WIDTH_MAJOR
,
0
,
1024
,
0
,
0
);
input_set_abs_params
(
input
,
ABS_MT_WIDTH_MINOR
,
0
,
1024
,
0
,
0
);
input_mt_init_slots
(
input
,
10
,
INPUT_MT_DIRECT
);
input
->
name
=
"Surface3 SPI Capacitive TouchScreen"
;
input
->
phys
=
"input/ts"
;
input
->
id
.
bustype
=
BUS_SPI
;
input
->
id
.
vendor
=
0x045e
;
/* Microsoft */
input
->
id
.
product
=
0x0001
;
input
->
id
.
version
=
0x0000
;
error
=
input_register_device
(
input
);
if
(
error
)
{
dev_err
(
&
data
->
spi
->
dev
,
"Failed to register input device: %d"
,
error
);
return
error
;
}
return
0
;
}
static
int
surface3_spi_create_pen_input
(
struct
surface3_ts_data
*
data
)
{
struct
input_dev
*
input
;
int
error
;
input
=
devm_input_allocate_device
(
&
data
->
spi
->
dev
);
if
(
!
input
)
return
-
ENOMEM
;
data
->
pen_input_dev
=
input
;
data
->
pen_tool
=
BTN_TOOL_PEN
;
__set_bit
(
INPUT_PROP_DIRECT
,
input
->
propbit
);
__set_bit
(
INPUT_PROP_POINTER
,
input
->
propbit
);
input_set_abs_params
(
input
,
ABS_X
,
0
,
9600
,
0
,
0
);
input_abs_set_res
(
input
,
ABS_X
,
40
);
input_set_abs_params
(
input
,
ABS_Y
,
0
,
7200
,
0
,
0
);
input_abs_set_res
(
input
,
ABS_Y
,
48
);
input_set_abs_params
(
input
,
ABS_PRESSURE
,
0
,
1024
,
0
,
0
);
input_set_capability
(
input
,
EV_KEY
,
BTN_TOUCH
);
input_set_capability
(
input
,
EV_KEY
,
BTN_STYLUS
);
input_set_capability
(
input
,
EV_KEY
,
BTN_TOOL_PEN
);
input_set_capability
(
input
,
EV_KEY
,
BTN_TOOL_RUBBER
);
input
->
name
=
"Surface3 SPI Pen Input"
;
input
->
phys
=
"input/ts"
;
input
->
id
.
bustype
=
BUS_SPI
;
input
->
id
.
vendor
=
0x045e
;
/* Microsoft */
input
->
id
.
product
=
0x0002
;
input
->
id
.
version
=
0x0000
;
error
=
input_register_device
(
input
);
if
(
error
)
{
dev_err
(
&
data
->
spi
->
dev
,
"Failed to register input device: %d"
,
error
);
return
error
;
}
return
0
;
}
static
int
surface3_spi_probe
(
struct
spi_device
*
spi
)
{
struct
surface3_ts_data
*
data
;
int
error
;
/* Set up SPI*/
spi
->
bits_per_word
=
8
;
spi
->
mode
=
SPI_MODE_0
;
error
=
spi_setup
(
spi
);
if
(
error
)
return
error
;
data
=
devm_kzalloc
(
&
spi
->
dev
,
sizeof
(
*
data
),
GFP_KERNEL
);
if
(
!
data
)
return
-
ENOMEM
;
data
->
spi
=
spi
;
spi_set_drvdata
(
spi
,
data
);
error
=
surface3_spi_get_gpio_config
(
data
);
if
(
error
)
return
error
;
surface3_spi_power
(
data
,
true
);
surface3_spi_power
(
data
,
false
);
surface3_spi_power
(
data
,
true
);
error
=
surface3_spi_create_touch_input
(
data
);
if
(
error
)
return
error
;
error
=
surface3_spi_create_pen_input
(
data
);
if
(
error
)
return
error
;
error
=
devm_request_threaded_irq
(
&
spi
->
dev
,
spi
->
irq
,
NULL
,
surface3_spi_irq_handler
,
IRQF_ONESHOT
,
"Surface3-irq"
,
data
);
if
(
error
)
return
error
;
return
0
;
}
static
int
__maybe_unused
surface3_spi_suspend
(
struct
device
*
dev
)
{
struct
spi_device
*
spi
=
to_spi_device
(
dev
);
struct
surface3_ts_data
*
data
=
spi_get_drvdata
(
spi
);
disable_irq
(
data
->
spi
->
irq
);
surface3_spi_power
(
data
,
false
);
return
0
;
}
static
int
__maybe_unused
surface3_spi_resume
(
struct
device
*
dev
)
{
struct
spi_device
*
spi
=
to_spi_device
(
dev
);
struct
surface3_ts_data
*
data
=
spi_get_drvdata
(
spi
);
surface3_spi_power
(
data
,
true
);
enable_irq
(
data
->
spi
->
irq
);
return
0
;
}
static
SIMPLE_DEV_PM_OPS
(
surface3_spi_pm_ops
,
surface3_spi_suspend
,
surface3_spi_resume
);
#ifdef CONFIG_ACPI
static
const
struct
acpi_device_id
surface3_spi_acpi_match
[]
=
{
{
"MSHW0037"
,
0
},
{
}
};
MODULE_DEVICE_TABLE
(
acpi
,
surface3_spi_acpi_match
);
#endif
static
struct
spi_driver
surface3_spi_driver
=
{
.
driver
=
{
.
name
=
"Surface3-spi"
,
.
acpi_match_table
=
ACPI_PTR
(
surface3_spi_acpi_match
),
.
pm
=
&
surface3_spi_pm_ops
,
},
.
probe
=
surface3_spi_probe
,
};
module_spi_driver
(
surface3_spi_driver
);
MODULE_AUTHOR
(
"Benjamin Tissoires <benjamin.tissoires@gmail.com>"
);
MODULE_DESCRIPTION
(
"Surface 3 SPI touchscreen driver"
);
MODULE_LICENSE
(
"GPL v2"
);
drivers/input/touchscreen/ti_am335x_tsc.c
View file @
08088828
...
...
@@ -406,7 +406,7 @@ static int titsc_probe(struct platform_device *pdev)
int
err
;
/* Allocate memory for device */
ts_dev
=
kzalloc
(
sizeof
(
struct
titsc
),
GFP_KERNEL
);
ts_dev
=
kzalloc
(
sizeof
(
*
ts_dev
),
GFP_KERNEL
);
input_dev
=
input_allocate_device
();
if
(
!
ts_dev
||
!
input_dev
)
{
dev_err
(
&
pdev
->
dev
,
"failed to allocate memory.
\n
"
);
...
...
drivers/input/touchscreen/tsc200x-core.c
View file @
08088828
...
...
@@ -568,7 +568,7 @@ int tsc200x_probe(struct device *dev, int irq, const struct input_id *tsc_id,
input_set_abs_params
(
input_dev
,
ABS_PRESSURE
,
0
,
max_p
,
fudge_p
,
0
);
if
(
np
)
touchscreen_parse_properties
(
input_dev
,
false
);
touchscreen_parse_properties
(
input_dev
,
false
,
NULL
);
input_dev
->
open
=
tsc200x_open
;
input_dev
->
close
=
tsc200x_close
;
...
...
drivers/input/touchscreen/wacom_w8001.c
View file @
08088828
...
...
@@ -518,13 +518,21 @@ static int w8001_setup_touch(struct w8001 *w8001, char *basename,
w8001
->
pktlen
=
W8001_PKTLEN_TOUCH2FG
;
__set_bit
(
BTN_TOOL_DOUBLETAP
,
dev
->
keybit
);
input_mt_init_slots
(
dev
,
2
,
0
);
error
=
input_mt_init_slots
(
dev
,
2
,
0
);
if
(
error
)
{
dev_err
(
&
w8001
->
serio
->
dev
,
"failed to initialize MT slots: %d
\n
"
,
error
);
return
error
;
}
input_set_abs_params
(
dev
,
ABS_MT_POSITION_X
,
0
,
touch
.
x
,
0
,
0
);
input_set_abs_params
(
dev
,
ABS_MT_POSITION_Y
,
0
,
touch
.
y
,
0
,
0
);
input_set_abs_params
(
dev
,
ABS_MT_TOOL_TYPE
,
0
,
MT_TOOL_MAX
,
0
,
0
);
input_abs_set_res
(
dev
,
ABS_MT_POSITION_X
,
touch
.
panel_res
);
input_abs_set_res
(
dev
,
ABS_MT_POSITION_Y
,
touch
.
panel_res
);
strlcat
(
basename
,
" 2FG"
,
basename_sz
);
if
(
w8001
->
max_pen_x
&&
w8001
->
max_pen_y
)
...
...
drivers/tty/vt/keyboard.c
View file @
08088828
...
...
@@ -1733,16 +1733,10 @@ int vt_do_diacrit(unsigned int cmd, void __user *udp, int perm)
return
-
EINVAL
;
if
(
ct
)
{
buf
=
kmalloc
(
ct
*
sizeof
(
struct
kbdiacruc
),
GFP_KERNEL
);
if
(
buf
==
NULL
)
return
-
ENOMEM
;
if
(
copy_from_user
(
buf
,
a
->
kbdiacruc
,
ct
*
sizeof
(
struct
kbdiacruc
)))
{
kfree
(
buf
);
return
-
EFAULT
;
}
buf
=
memdup_user
(
a
->
kbdiacruc
,
ct
*
sizeof
(
struct
kbdiacruc
));
if
(
IS_ERR
(
buf
))
return
PTR_ERR
(
buf
);
}
spin_lock_irqsave
(
&
kbd_event_lock
,
flags
);
if
(
ct
)
...
...
include/linux/input.h
View file @
08088828
...
...
@@ -95,7 +95,7 @@ struct input_value {
* @grab: input handle that currently has the device grabbed (via
* EVIOCGRAB ioctl). When a handle grabs a device it becomes sole
* recipient for all input events coming from the device
* @event_lock: this spinlock is
is
taken when input core receives
* @event_lock: this spinlock is taken when input core receives
* and processes a new event for the device (in input_event()).
* Code that accesses and/or modifies parameters of a device
* (such as keymap or absmin, absmax, absfuzz, etc.) after device
...
...
include/linux/input/touchscreen.h
View file @
08088828
...
...
@@ -10,7 +10,26 @@
#define _TOUCHSCREEN_H
struct
input_dev
;
struct
input_mt_pos
;
void
touchscreen_parse_properties
(
struct
input_dev
*
dev
,
bool
multitouch
);
struct
touchscreen_properties
{
unsigned
int
max_x
;
unsigned
int
max_y
;
bool
invert_x
;
bool
invert_y
;
bool
swap_x_y
;
};
void
touchscreen_parse_properties
(
struct
input_dev
*
input
,
bool
multitouch
,
struct
touchscreen_properties
*
prop
);
void
touchscreen_set_mt_pos
(
struct
input_mt_pos
*
pos
,
const
struct
touchscreen_properties
*
prop
,
unsigned
int
x
,
unsigned
int
y
);
void
touchscreen_report_pos
(
struct
input_dev
*
input
,
const
struct
touchscreen_properties
*
prop
,
unsigned
int
x
,
unsigned
int
y
,
bool
multitouch
);
#endif
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment