diff options
41 files changed, 2928 insertions, 129 deletions
diff --git a/Documentation/devicetree/bindings/input/atmel,captouch.txt b/Documentation/devicetree/bindings/input/atmel,captouch.txt new file mode 100644 index 000000000000..fe9ee5c53bcc --- /dev/null +++ b/Documentation/devicetree/bindings/input/atmel,captouch.txt | |||
@@ -0,0 +1,36 @@ | |||
1 | Device tree bindings for Atmel capacitive touch device, typically | ||
2 | an Atmel touch sensor connected to AtmegaXX MCU running firmware | ||
3 | based on Qtouch library. | ||
4 | |||
5 | The node for this device must be a child of a I2C controller node, as the | ||
6 | device communicates via I2C. | ||
7 | |||
8 | Required properties: | ||
9 | |||
10 | compatible: Must be "atmel,captouch". | ||
11 | reg: The I2C slave address of the device. | ||
12 | interrupts: Property describing the interrupt line the device | ||
13 | is connected to. The device only has one interrupt | ||
14 | source. | ||
15 | linux,keycodes: Specifies an array of numeric keycode values to | ||
16 | be used for reporting button presses. The array can | ||
17 | contain up to 8 entries. | ||
18 | |||
19 | Optional properties: | ||
20 | |||
21 | autorepeat: Enables the Linux input system's autorepeat | ||
22 | feature on the input device. | ||
23 | |||
24 | Example: | ||
25 | |||
26 | atmel-captouch@51 { | ||
27 | compatible = "atmel,captouch"; | ||
28 | reg = <0x51>; | ||
29 | interrupt-parent = <&tlmm>; | ||
30 | interrupts = <67 IRQ_TYPE_EDGE_FALLING>; | ||
31 | linux,keycodes = <BTN_0>, <BTN_1>, | ||
32 | <BTN_2>, <BTN_3>, | ||
33 | <BTN_4>, <BTN_5>, | ||
34 | <BTN_6>, <BTN_7>; | ||
35 | autorepeat; | ||
36 | }; | ||
diff --git a/Documentation/devicetree/bindings/input/raydium_i2c_ts.txt b/Documentation/devicetree/bindings/input/raydium_i2c_ts.txt new file mode 100644 index 000000000000..5b6232db7c61 --- /dev/null +++ b/Documentation/devicetree/bindings/input/raydium_i2c_ts.txt | |||
@@ -0,0 +1,20 @@ | |||
1 | Raydium I2C touchscreen | ||
2 | |||
3 | Required properties: | ||
4 | - compatible: must be "raydium,rm32380" | ||
5 | - reg: The I2C address of the device | ||
6 | - interrupt-parent: the phandle for the interrupt controller | ||
7 | - interrupts: interrupt to which the chip is connected | ||
8 | See ../interrupt-controller/interrupts.txt | ||
9 | Optional properties: | ||
10 | - avdd-supply: analog power supply needed to power device | ||
11 | - vccio-supply: IO Power source | ||
12 | - reset-gpios: reset gpio the chip is connected to. | ||
13 | |||
14 | Example: | ||
15 | touchscreen@39 { | ||
16 | compatible = "raydium,rm32380"; | ||
17 | reg = <0x39>; | ||
18 | interrupt-parent = <&gpio>; | ||
19 | interrupts = <0x0 IRQ_TYPE_EDGE_FALLING>; | ||
20 | }; | ||
diff --git a/Documentation/devicetree/bindings/input/rmi4/rmi_i2c.txt b/Documentation/devicetree/bindings/input/rmi4/rmi_i2c.txt index 95fa715c6046..ec908b91fd90 100644 --- a/Documentation/devicetree/bindings/input/rmi4/rmi_i2c.txt +++ b/Documentation/devicetree/bindings/input/rmi4/rmi_i2c.txt | |||
@@ -22,6 +22,15 @@ See Documentation/devicetree/bindings/interrupt-controller/interrupts.txt | |||
22 | - syna,reset-delay-ms: The number of milliseconds to wait after resetting the | 22 | - syna,reset-delay-ms: The number of milliseconds to wait after resetting the |
23 | device. | 23 | device. |
24 | 24 | ||
25 | - syna,startup-delay-ms: The number of milliseconds to wait after powering on | ||
26 | the device. | ||
27 | |||
28 | - vdd-supply: VDD power supply. | ||
29 | See ../regulator/regulator.txt | ||
30 | |||
31 | - vio-supply: VIO power supply | ||
32 | See ../regulator/regulator.txt | ||
33 | |||
25 | Function Parameters: | 34 | Function Parameters: |
26 | Parameters specific to RMI functions are contained in child nodes of the rmi device | 35 | Parameters specific to RMI functions are contained in child nodes of the rmi device |
27 | node. Documentation for the parameters of each function can be found in: | 36 | node. Documentation for the parameters of each function can be found in: |
diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt index 2c2500df0dce..d2bce2239769 100644 --- a/Documentation/devicetree/bindings/vendor-prefixes.txt +++ b/Documentation/devicetree/bindings/vendor-prefixes.txt | |||
@@ -214,6 +214,7 @@ raidsonic RaidSonic Technology GmbH | |||
214 | ralink Mediatek/Ralink Technology Corp. | 214 | ralink Mediatek/Ralink Technology Corp. |
215 | ramtron Ramtron International | 215 | ramtron Ramtron International |
216 | raspberrypi Raspberry Pi Foundation | 216 | raspberrypi Raspberry Pi Foundation |
217 | raydium Raydium Semiconductor Corp. | ||
217 | realtek Realtek Semiconductor Corp. | 218 | realtek Realtek Semiconductor Corp. |
218 | renesas Renesas Electronics Corporation | 219 | renesas Renesas Electronics Corporation |
219 | richtek Richtek Technology Corporation | 220 | richtek Richtek Technology Corporation |
diff --git a/drivers/input/input-mt.c b/drivers/input/input-mt.c index 54fce56c8023..a1bbec9cda8d 100644 --- a/drivers/input/input-mt.c +++ b/drivers/input/input-mt.c | |||
@@ -218,8 +218,23 @@ void input_mt_report_pointer_emulation(struct input_dev *dev, bool use_count) | |||
218 | } | 218 | } |
219 | 219 | ||
220 | input_event(dev, EV_KEY, BTN_TOUCH, count > 0); | 220 | input_event(dev, EV_KEY, BTN_TOUCH, count > 0); |
221 | if (use_count) | 221 | |
222 | if (use_count) { | ||
223 | if (count == 0 && | ||
224 | !test_bit(ABS_MT_DISTANCE, dev->absbit) && | ||
225 | test_bit(ABS_DISTANCE, dev->absbit) && | ||
226 | input_abs_get_val(dev, ABS_DISTANCE) != 0) { | ||
227 | /* | ||
228 | * Force reporting BTN_TOOL_FINGER for devices that | ||
229 | * only report general hover (and not per-contact | ||
230 | * distance) when contact is in proximity but not | ||
231 | * on the surface. | ||
232 | */ | ||
233 | count = 1; | ||
234 | } | ||
235 | |||
222 | input_mt_report_finger_count(dev, count); | 236 | input_mt_report_finger_count(dev, count); |
237 | } | ||
223 | 238 | ||
224 | if (oldest) { | 239 | if (oldest) { |
225 | int x = input_mt_get_value(oldest, ABS_MT_POSITION_X); | 240 | int x = input_mt_get_value(oldest, ABS_MT_POSITION_X); |
diff --git a/drivers/input/input.c b/drivers/input/input.c index b87ffbd4547d..d95c34ee5dc1 100644 --- a/drivers/input/input.c +++ b/drivers/input/input.c | |||
@@ -153,8 +153,6 @@ static void input_pass_values(struct input_dev *dev, | |||
153 | 153 | ||
154 | rcu_read_unlock(); | 154 | rcu_read_unlock(); |
155 | 155 | ||
156 | add_input_randomness(vals->type, vals->code, vals->value); | ||
157 | |||
158 | /* trigger auto repeat for key events */ | 156 | /* trigger auto repeat for key events */ |
159 | if (test_bit(EV_REP, dev->evbit) && test_bit(EV_KEY, dev->evbit)) { | 157 | if (test_bit(EV_REP, dev->evbit) && test_bit(EV_KEY, dev->evbit)) { |
160 | for (v = vals; v != vals + count; v++) { | 158 | for (v = vals; v != vals + count; v++) { |
@@ -371,9 +369,10 @@ static int input_get_disposition(struct input_dev *dev, | |||
371 | static void input_handle_event(struct input_dev *dev, | 369 | static void input_handle_event(struct input_dev *dev, |
372 | unsigned int type, unsigned int code, int value) | 370 | unsigned int type, unsigned int code, int value) |
373 | { | 371 | { |
374 | int disposition; | 372 | int disposition = input_get_disposition(dev, type, code, &value); |
375 | 373 | ||
376 | disposition = input_get_disposition(dev, type, code, &value); | 374 | if (disposition != INPUT_IGNORE_EVENT && type != EV_SYN) |
375 | add_input_randomness(type, code, value); | ||
377 | 376 | ||
378 | if ((disposition & INPUT_PASS_TO_DEVICE) && dev->event) | 377 | if ((disposition & INPUT_PASS_TO_DEVICE) && dev->event) |
379 | dev->event(dev, type, code, value); | 378 | dev->event(dev, type, code, value); |
diff --git a/drivers/input/keyboard/tc3589x-keypad.c b/drivers/input/keyboard/tc3589x-keypad.c index e92dfd8889c2..ec0070e97090 100644 --- a/drivers/input/keyboard/tc3589x-keypad.c +++ b/drivers/input/keyboard/tc3589x-keypad.c | |||
@@ -32,7 +32,7 @@ | |||
32 | #define TC3589x_PULL_DOWN_MASK 0x1 | 32 | #define TC3589x_PULL_DOWN_MASK 0x1 |
33 | #define TC3589x_PULL_UP_MASK 0x2 | 33 | #define TC3589x_PULL_UP_MASK 0x2 |
34 | #define TC3589x_PULLUP_ALL_MASK 0xAA | 34 | #define TC3589x_PULLUP_ALL_MASK 0xAA |
35 | #define TC3589x_IO_PULL_VAL(index, mask) ((mask)<<((index)%4)*2)) | 35 | #define TC3589x_IO_PULL_VAL(index, mask) ((mask)<<((index)%4)*2) |
36 | 36 | ||
37 | /* Bit masks for IOCFG register */ | 37 | /* Bit masks for IOCFG register */ |
38 | #define IOCFG_BALLCFG 0x01 | 38 | #define IOCFG_BALLCFG 0x01 |
diff --git a/drivers/input/keyboard/tegra-kbc.c b/drivers/input/keyboard/tegra-kbc.c index acc5394afb03..7d61439be5f2 100644 --- a/drivers/input/keyboard/tegra-kbc.c +++ b/drivers/input/keyboard/tegra-kbc.c | |||
@@ -552,7 +552,7 @@ static int tegra_kbc_parse_dt(struct tegra_kbc *kbc) | |||
552 | 552 | ||
553 | if (!num_rows || !num_cols || ((num_rows + num_cols) > KBC_MAX_GPIO)) { | 553 | if (!num_rows || !num_cols || ((num_rows + num_cols) > KBC_MAX_GPIO)) { |
554 | dev_err(kbc->dev, | 554 | dev_err(kbc->dev, |
555 | "keypad rows/columns not porperly specified\n"); | 555 | "keypad rows/columns not properly specified\n"); |
556 | return -EINVAL; | 556 | return -EINVAL; |
557 | } | 557 | } |
558 | 558 | ||
diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig index 1f2337abcf2f..efb0ca871327 100644 --- a/drivers/input/misc/Kconfig +++ b/drivers/input/misc/Kconfig | |||
@@ -82,6 +82,20 @@ config INPUT_ARIZONA_HAPTICS | |||
82 | To compile this driver as a module, choose M here: the | 82 | To compile this driver as a module, choose M here: the |
83 | module will be called arizona-haptics. | 83 | module will be called arizona-haptics. |
84 | 84 | ||
85 | config INPUT_ATMEL_CAPTOUCH | ||
86 | tristate "Atmel Capacitive Touch Button Driver" | ||
87 | depends on OF || COMPILE_TEST | ||
88 | depends on I2C | ||
89 | help | ||
90 | Say Y here if an Atmel Capacitive Touch Button device which | ||
91 | implements "captouch" protocol is connected to I2C bus. Typically | ||
92 | this device consists of Atmel Touch sensor controlled by AtMegaXX | ||
93 | MCU running firmware based on Qtouch library. | ||
94 | One should find "atmel,captouch" node in the board specific DTS. | ||
95 | |||
96 | To compile this driver as a module, choose M here: the | ||
97 | module will be called atmel_captouch. | ||
98 | |||
85 | config INPUT_BMA150 | 99 | config INPUT_BMA150 |
86 | tristate "BMA150/SMB380 acceleration sensor support" | 100 | tristate "BMA150/SMB380 acceleration sensor support" |
87 | depends on I2C | 101 | depends on I2C |
@@ -796,4 +810,13 @@ config INPUT_DRV2667_HAPTICS | |||
796 | To compile this driver as a module, choose M here: the | 810 | To compile this driver as a module, choose M here: the |
797 | module will be called drv2667-haptics. | 811 | module will be called drv2667-haptics. |
798 | 812 | ||
813 | config INPUT_HISI_POWERKEY | ||
814 | tristate "Hisilicon PMIC ONKEY support" | ||
815 | depends on ARCH_HISI || COMPILE_TEST | ||
816 | help | ||
817 | Say Y to enable support for PMIC ONKEY. | ||
818 | |||
819 | To compile this driver as a module, choose M here: the | ||
820 | module will be called hisi_powerkey. | ||
821 | |||
799 | endif | 822 | endif |
diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile index 0357a088c6a9..6a1e5e20fc1c 100644 --- a/drivers/input/misc/Makefile +++ b/drivers/input/misc/Makefile | |||
@@ -17,6 +17,7 @@ obj-$(CONFIG_INPUT_APANEL) += apanel.o | |||
17 | obj-$(CONFIG_INPUT_ARIZONA_HAPTICS) += arizona-haptics.o | 17 | obj-$(CONFIG_INPUT_ARIZONA_HAPTICS) += arizona-haptics.o |
18 | obj-$(CONFIG_INPUT_ATI_REMOTE2) += ati_remote2.o | 18 | obj-$(CONFIG_INPUT_ATI_REMOTE2) += ati_remote2.o |
19 | obj-$(CONFIG_INPUT_ATLAS_BTNS) += atlas_btns.o | 19 | obj-$(CONFIG_INPUT_ATLAS_BTNS) += atlas_btns.o |
20 | obj-$(CONFIG_INPUT_ATMEL_CAPTOUCH) += atmel_captouch.o | ||
20 | obj-$(CONFIG_INPUT_BFIN_ROTARY) += bfin_rotary.o | 21 | obj-$(CONFIG_INPUT_BFIN_ROTARY) += bfin_rotary.o |
21 | obj-$(CONFIG_INPUT_BMA150) += bma150.o | 22 | obj-$(CONFIG_INPUT_BMA150) += bma150.o |
22 | obj-$(CONFIG_INPUT_CM109) += cm109.o | 23 | obj-$(CONFIG_INPUT_CM109) += cm109.o |
@@ -34,6 +35,7 @@ obj-$(CONFIG_INPUT_DRV2667_HAPTICS) += drv2667.o | |||
34 | obj-$(CONFIG_INPUT_GP2A) += gp2ap002a00f.o | 35 | obj-$(CONFIG_INPUT_GP2A) += gp2ap002a00f.o |
35 | obj-$(CONFIG_INPUT_GPIO_BEEPER) += gpio-beeper.o | 36 | obj-$(CONFIG_INPUT_GPIO_BEEPER) += gpio-beeper.o |
36 | obj-$(CONFIG_INPUT_GPIO_TILT_POLLED) += gpio_tilt_polled.o | 37 | obj-$(CONFIG_INPUT_GPIO_TILT_POLLED) += gpio_tilt_polled.o |
38 | obj-$(CONFIG_INPUT_HISI_POWERKEY) += hisi_powerkey.o | ||
37 | obj-$(CONFIG_HP_SDC_RTC) += hp_sdc_rtc.o | 39 | obj-$(CONFIG_HP_SDC_RTC) += hp_sdc_rtc.o |
38 | obj-$(CONFIG_INPUT_IMS_PCU) += ims-pcu.o | 40 | obj-$(CONFIG_INPUT_IMS_PCU) += ims-pcu.o |
39 | obj-$(CONFIG_INPUT_IXP4XX_BEEPER) += ixp4xx-beeper.o | 41 | obj-$(CONFIG_INPUT_IXP4XX_BEEPER) += ixp4xx-beeper.o |
diff --git a/drivers/input/misc/apanel.c b/drivers/input/misc/apanel.c index a8d2b8db4e35..53630afab606 100644 --- a/drivers/input/misc/apanel.c +++ b/drivers/input/misc/apanel.c | |||
@@ -297,7 +297,7 @@ static int __init apanel_init(void) | |||
297 | 297 | ||
298 | if (slave != i2c_addr) { | 298 | if (slave != i2c_addr) { |
299 | pr_notice(APANEL ": only one SMBus slave " | 299 | pr_notice(APANEL ": only one SMBus slave " |
300 | "address supported, skiping device...\n"); | 300 | "address supported, skipping device...\n"); |
301 | continue; | 301 | continue; |
302 | } | 302 | } |
303 | 303 | ||
diff --git a/drivers/input/misc/atmel_captouch.c b/drivers/input/misc/atmel_captouch.c new file mode 100644 index 000000000000..941265415a89 --- /dev/null +++ b/drivers/input/misc/atmel_captouch.c | |||
@@ -0,0 +1,290 @@ | |||
1 | /* | ||
2 | * Atmel Atmegaxx Capacitive Touch Button Driver | ||
3 | * | ||
4 | * Copyright (C) 2016 Google, inc. | ||
5 | * | ||
6 | * This software is licensed under the terms of the GNU General Public | ||
7 | * License version 2, as published by the Free Software Foundation, and | ||
8 | * may be copied, distributed, and modified under those terms. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | */ | ||
15 | |||
16 | /* | ||
17 | * It's irrelevant that the HW used to develop captouch driver is based | ||
18 | * on Atmega88PA part and uses QtouchADC parts for sensing touch. | ||
19 | * Calling this driver "captouch" is an arbitrary way to distinguish | ||
20 | * the protocol this driver supported by other atmel/qtouch drivers. | ||
21 | * | ||
22 | * Captouch driver supports a newer/different version of the I2C | ||
23 | * registers/commands than the qt1070.c driver. | ||
24 | * Don't let the similarity of the general driver structure fool you. | ||
25 | * | ||
26 | * For raw i2c access from userspace, use i2cset/i2cget | ||
27 | * to poke at /dev/i2c-N devices. | ||
28 | */ | ||
29 | |||
30 | #include <linux/device.h> | ||
31 | #include <linux/kernel.h> | ||
32 | #include <linux/module.h> | ||
33 | #include <linux/init.h> | ||
34 | #include <linux/i2c.h> | ||
35 | #include <linux/input.h> | ||
36 | #include <linux/interrupt.h> | ||
37 | #include <linux/slab.h> | ||
38 | |||
39 | /* Maximum number of buttons supported */ | ||
40 | #define MAX_NUM_OF_BUTTONS 8 | ||
41 | |||
42 | /* Registers */ | ||
43 | #define REG_KEY1_THRESHOLD 0x02 | ||
44 | #define REG_KEY2_THRESHOLD 0x03 | ||
45 | #define REG_KEY3_THRESHOLD 0x04 | ||
46 | #define REG_KEY4_THRESHOLD 0x05 | ||
47 | |||
48 | #define REG_KEY1_REF_H 0x20 | ||
49 | #define REG_KEY1_REF_L 0x21 | ||
50 | #define REG_KEY2_REF_H 0x22 | ||
51 | #define REG_KEY2_REF_L 0x23 | ||
52 | #define REG_KEY3_REF_H 0x24 | ||
53 | #define REG_KEY3_REF_L 0x25 | ||
54 | #define REG_KEY4_REF_H 0x26 | ||
55 | #define REG_KEY4_REF_L 0x27 | ||
56 | |||
57 | #define REG_KEY1_DLT_H 0x30 | ||
58 | #define REG_KEY1_DLT_L 0x31 | ||
59 | #define REG_KEY2_DLT_H 0x32 | ||
60 | #define REG_KEY2_DLT_L 0x33 | ||
61 | #define REG_KEY3_DLT_H 0x34 | ||
62 | #define REG_KEY3_DLT_L 0x35 | ||
63 | #define REG_KEY4_DLT_H 0x36 | ||
64 | #define REG_KEY4_DLT_L 0x37 | ||
65 | |||
66 | #define REG_KEY_STATE 0x3C | ||
67 | |||
68 | /* | ||
69 | * @i2c_client: I2C slave device client pointer | ||
70 | * @input: Input device pointer | ||
71 | * @num_btn: Number of buttons | ||
72 | * @keycodes: map of button# to KeyCode | ||
73 | * @prev_btn: Previous key state to detect button "press" or "release" | ||
74 | * @xfer_buf: I2C transfer buffer | ||
75 | */ | ||
76 | struct atmel_captouch_device { | ||
77 | struct i2c_client *client; | ||
78 | struct input_dev *input; | ||
79 | u32 num_btn; | ||
80 | u32 keycodes[MAX_NUM_OF_BUTTONS]; | ||
81 | u8 prev_btn; | ||
82 | u8 xfer_buf[8] ____cacheline_aligned; | ||
83 | }; | ||
84 | |||
85 | /* | ||
86 | * Read from I2C slave device | ||
87 | * The protocol is that the client has to provide both the register address | ||
88 | * and the length, and while reading back the device would prepend the data | ||
89 | * with address and length for verification. | ||
90 | */ | ||
91 | static int atmel_read(struct atmel_captouch_device *capdev, | ||
92 | u8 reg, u8 *data, size_t len) | ||
93 | { | ||
94 | struct i2c_client *client = capdev->client; | ||
95 | struct device *dev = &client->dev; | ||
96 | struct i2c_msg msg[2]; | ||
97 | int err; | ||
98 | |||
99 | if (len > sizeof(capdev->xfer_buf) - 2) | ||
100 | return -EINVAL; | ||
101 | |||
102 | capdev->xfer_buf[0] = reg; | ||
103 | capdev->xfer_buf[1] = len; | ||
104 | |||
105 | msg[0].addr = client->addr; | ||
106 | msg[0].flags = 0; | ||
107 | msg[0].buf = capdev->xfer_buf; | ||
108 | msg[0].len = 2; | ||
109 | |||
110 | msg[1].addr = client->addr; | ||
111 | msg[1].flags = I2C_M_RD; | ||
112 | msg[1].buf = capdev->xfer_buf; | ||
113 | msg[1].len = len + 2; | ||
114 | |||
115 | err = i2c_transfer(client->adapter, msg, ARRAY_SIZE(msg)); | ||
116 | if (err != ARRAY_SIZE(msg)) | ||
117 | return err < 0 ? err : -EIO; | ||
118 | |||
119 | if (capdev->xfer_buf[0] != reg) { | ||
120 | dev_err(dev, | ||
121 | "I2C read error: register address does not match (%#02x vs %02x)\n", | ||
122 | capdev->xfer_buf[0], reg); | ||
123 | return -ECOMM; | ||
124 | } | ||
125 | |||
126 | memcpy(data, &capdev->xfer_buf[2], len); | ||
127 | |||
128 | return 0; | ||
129 | } | ||
130 | |||
131 | /* | ||
132 | * Handle interrupt and report the key changes to the input system. | ||
133 | * Multi-touch can be supported; however, it really depends on whether | ||
134 | * the device can multi-touch. | ||
135 | */ | ||
136 | static irqreturn_t atmel_captouch_isr(int irq, void *data) | ||
137 | { | ||
138 | struct atmel_captouch_device *capdev = data; | ||
139 | struct device *dev = &capdev->client->dev; | ||
140 | int error; | ||
141 | int i; | ||
142 | u8 new_btn; | ||
143 | u8 changed_btn; | ||
144 | |||
145 | error = atmel_read(capdev, REG_KEY_STATE, &new_btn, 1); | ||
146 | if (error) { | ||
147 | dev_err(dev, "failed to read button state: %d\n", error); | ||
148 | goto out; | ||
149 | } | ||
150 | |||
151 | dev_dbg(dev, "%s: button state %#02x\n", __func__, new_btn); | ||
152 | |||
153 | changed_btn = new_btn ^ capdev->prev_btn; | ||
154 | capdev->prev_btn = new_btn; | ||
155 | |||
156 | for (i = 0; i < capdev->num_btn; i++) { | ||
157 | if (changed_btn & BIT(i)) | ||
158 | input_report_key(capdev->input, | ||
159 | capdev->keycodes[i], | ||
160 | new_btn & BIT(i)); | ||
161 | } | ||
162 | |||
163 | input_sync(capdev->input); | ||
164 | |||
165 | out: | ||
166 | return IRQ_HANDLED; | ||
167 | } | ||
168 | |||
169 | /* | ||
170 | * Probe function to setup the device, input system and interrupt | ||
171 | */ | ||
172 | static int atmel_captouch_probe(struct i2c_client *client, | ||
173 | const struct i2c_device_id *id) | ||
174 | { | ||
175 | struct atmel_captouch_device *capdev; | ||
176 | struct device *dev = &client->dev; | ||
177 | struct device_node *node; | ||
178 | int i; | ||
179 | int err; | ||
180 | |||
181 | if (!i2c_check_functionality(client->adapter, | ||
182 | I2C_FUNC_SMBUS_BYTE_DATA | | ||
183 | I2C_FUNC_SMBUS_WORD_DATA | | ||
184 | I2C_FUNC_SMBUS_I2C_BLOCK)) { | ||
185 | dev_err(dev, "needed i2c functionality is not supported\n"); | ||
186 | return -EINVAL; | ||
187 | } | ||
188 | |||
189 | capdev = devm_kzalloc(dev, sizeof(*capdev), GFP_KERNEL); | ||
190 | if (!capdev) | ||
191 | return -ENOMEM; | ||
192 | |||
193 | capdev->client = client; | ||
194 | i2c_set_clientdata(client, capdev); | ||
195 | |||
196 | err = atmel_read(capdev, REG_KEY_STATE, | ||
197 | &capdev->prev_btn, sizeof(capdev->prev_btn)); | ||
198 | if (err) { | ||
199 | dev_err(dev, "failed to read initial button state: %d\n", err); | ||
200 | return err; | ||
201 | } | ||
202 | |||
203 | capdev->input = devm_input_allocate_device(dev); | ||
204 | if (!capdev->input) { | ||
205 | dev_err(dev, "failed to allocate input device\n"); | ||
206 | return -ENOMEM; | ||
207 | } | ||
208 | |||
209 | capdev->input->id.bustype = BUS_I2C; | ||
210 | capdev->input->id.product = 0x880A; | ||
211 | capdev->input->id.version = 0; | ||
212 | capdev->input->name = "ATMegaXX Capacitive Button Controller"; | ||
213 | __set_bit(EV_KEY, capdev->input->evbit); | ||
214 | |||
215 | node = dev->of_node; | ||
216 | if (!node) { | ||
217 | dev_err(dev, "failed to find matching node in device tree\n"); | ||
218 | return -EINVAL; | ||
219 | } | ||
220 | |||
221 | if (of_property_read_bool(node, "autorepeat")) | ||
222 | __set_bit(EV_REP, capdev->input->evbit); | ||
223 | |||
224 | capdev->num_btn = of_property_count_u32_elems(node, "linux,keymap"); | ||
225 | if (capdev->num_btn > MAX_NUM_OF_BUTTONS) | ||
226 | capdev->num_btn = MAX_NUM_OF_BUTTONS; | ||
227 | |||
228 | err = of_property_read_u32_array(node, "linux,keycodes", | ||
229 | capdev->keycodes, | ||
230 | capdev->num_btn); | ||
231 | if (err) { | ||
232 | dev_err(dev, | ||
233 | "failed to read linux,keycode property: %d\n", err); | ||
234 | return err; | ||
235 | } | ||
236 | |||
237 | for (i = 0; i < capdev->num_btn; i++) | ||
238 | __set_bit(capdev->keycodes[i], capdev->input->keybit); | ||
239 | |||
240 | capdev->input->keycode = capdev->keycodes; | ||
241 | capdev->input->keycodesize = sizeof(capdev->keycodes[0]); | ||
242 | capdev->input->keycodemax = capdev->num_btn; | ||
243 | |||
244 | err = input_register_device(capdev->input); | ||
245 | if (err) | ||
246 | return err; | ||
247 | |||
248 | err = devm_request_threaded_irq(dev, client->irq, | ||
249 | NULL, atmel_captouch_isr, | ||
250 | IRQF_ONESHOT, | ||
251 | "atmel_captouch", capdev); | ||
252 | if (err) { | ||
253 | dev_err(dev, "failed to request irq %d: %d\n", | ||
254 | client->irq, err); | ||
255 | return err; | ||
256 | } | ||
257 | |||
258 | return 0; | ||
259 | } | ||
260 | |||
261 | #ifdef CONFIG_OF | ||
262 | static const struct of_device_id atmel_captouch_of_id[] = { | ||
263 | { | ||
264 | .compatible = "atmel,captouch", | ||
265 | }, | ||
266 | { /* sentinel */ } | ||
267 | }; | ||
268 | MODULE_DEVICE_TABLE(of, atmel_captouch_of_id); | ||
269 | #endif | ||
270 | |||
271 | static const struct i2c_device_id atmel_captouch_id[] = { | ||
272 | { "atmel_captouch", 0 }, | ||
273 | { } | ||
274 | }; | ||
275 | MODULE_DEVICE_TABLE(i2c, atmel_captouch_id); | ||
276 | |||
277 | static struct i2c_driver atmel_captouch_driver = { | ||
278 | .probe = atmel_captouch_probe, | ||
279 | .id_table = atmel_captouch_id, | ||
280 | .driver = { | ||
281 | .name = "atmel_captouch", | ||
282 | .of_match_table = of_match_ptr(atmel_captouch_of_id), | ||
283 | }, | ||
284 | }; | ||
285 | module_i2c_driver(atmel_captouch_driver); | ||
286 | |||
287 | /* Module information */ | ||
288 | MODULE_AUTHOR("Hung-yu Wu <hywu@google.com>"); | ||
289 | MODULE_DESCRIPTION("Atmel ATmegaXX Capacitance Touch Sensor I2C Driver"); | ||
290 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/input/misc/hisi_powerkey.c b/drivers/input/misc/hisi_powerkey.c new file mode 100644 index 000000000000..675539c529ce --- /dev/null +++ b/drivers/input/misc/hisi_powerkey.c | |||
@@ -0,0 +1,142 @@ | |||
1 | /* | ||
2 | * Hisilicon PMIC powerkey driver | ||
3 | * | ||
4 | * Copyright (C) 2013 Hisilicon Ltd. | ||
5 | * Copyright (C) 2015, 2016 Linaro Ltd. | ||
6 | * | ||
7 | * This file is subject to the terms and conditions of the GNU General | ||
8 | * Public License. See the file "COPYING" in the main directory of this | ||
9 | * archive for more details. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | */ | ||
16 | |||
17 | #include <linux/platform_device.h> | ||
18 | #include <linux/interrupt.h> | ||
19 | #include <linux/reboot.h> | ||
20 | #include <linux/kernel.h> | ||
21 | #include <linux/module.h> | ||
22 | #include <linux/of_irq.h> | ||
23 | #include <linux/input.h> | ||
24 | #include <linux/slab.h> | ||
25 | |||
26 | /* the held interrupt will trigger after 4 seconds */ | ||
27 | #define MAX_HELD_TIME (4 * MSEC_PER_SEC) | ||
28 | |||
29 | static irqreturn_t hi65xx_power_press_isr(int irq, void *q) | ||
30 | { | ||
31 | struct input_dev *input = q; | ||
32 | |||
33 | pm_wakeup_event(input->dev.parent, MAX_HELD_TIME); | ||
34 | input_report_key(input, KEY_POWER, 1); | ||
35 | input_sync(input); | ||
36 | |||
37 | return IRQ_HANDLED; | ||
38 | } | ||
39 | |||
40 | static irqreturn_t hi65xx_power_release_isr(int irq, void *q) | ||
41 | { | ||
42 | struct input_dev *input = q; | ||
43 | |||
44 | pm_wakeup_event(input->dev.parent, MAX_HELD_TIME); | ||
45 | input_report_key(input, KEY_POWER, 0); | ||
46 | input_sync(input); | ||
47 | |||
48 | return IRQ_HANDLED; | ||
49 | } | ||
50 | |||
51 | static irqreturn_t hi65xx_restart_toggle_isr(int irq, void *q) | ||
52 | { | ||
53 | struct input_dev *input = q; | ||
54 | int value = test_bit(KEY_RESTART, input->key); | ||
55 | |||
56 | pm_wakeup_event(input->dev.parent, MAX_HELD_TIME); | ||
57 | input_report_key(input, KEY_RESTART, !value); | ||
58 | input_sync(input); | ||
59 | |||
60 | return IRQ_HANDLED; | ||
61 | } | ||
62 | |||
63 | static const struct { | ||
64 | const char *name; | ||
65 | irqreturn_t (*handler)(int irq, void *q); | ||
66 | } hi65xx_irq_info[] = { | ||
67 | { "down", hi65xx_power_press_isr }, | ||
68 | { "up", hi65xx_power_release_isr }, | ||
69 | { "hold 4s", hi65xx_restart_toggle_isr }, | ||
70 | }; | ||
71 | |||
72 | static int hi65xx_powerkey_probe(struct platform_device *pdev) | ||
73 | { | ||
74 | struct device *dev = &pdev->dev; | ||
75 | struct input_dev *input; | ||
76 | int irq, i, error; | ||
77 | |||
78 | input = devm_input_allocate_device(&pdev->dev); | ||
79 | if (!input) { | ||
80 | dev_err(&pdev->dev, "failed to allocate input device\n"); | ||
81 | return -ENOMEM; | ||
82 | } | ||
83 | |||
84 | input->phys = "hisi_on/input0"; | ||
85 | input->name = "HISI 65xx PowerOn Key"; | ||
86 | |||
87 | input_set_capability(input, EV_KEY, KEY_POWER); | ||
88 | input_set_capability(input, EV_KEY, KEY_RESTART); | ||
89 | |||
90 | for (i = 0; i < ARRAY_SIZE(hi65xx_irq_info); i++) { | ||
91 | |||
92 | irq = platform_get_irq_byname(pdev, hi65xx_irq_info[i].name); | ||
93 | if (irq < 0) { | ||
94 | error = irq; | ||
95 | dev_err(dev, "couldn't get irq %s: %d\n", | ||
96 | hi65xx_irq_info[i].name, error); | ||
97 | return error; | ||
98 | } | ||
99 | |||
100 | error = devm_request_any_context_irq(dev, irq, | ||
101 | hi65xx_irq_info[i].handler, | ||
102 | IRQF_ONESHOT, | ||
103 | hi65xx_irq_info[i].name, | ||
104 | input); | ||
105 | if (error < 0) { | ||
106 | dev_err(dev, "couldn't request irq %s: %d\n", | ||
107 | hi65xx_irq_info[i].name, error); | ||
108 | return error; | ||
109 | } | ||
110 | } | ||
111 | |||
112 | error = input_register_device(input); | ||
113 | if (error) { | ||
114 | dev_err(&pdev->dev, "failed to register input device: %d\n", | ||
115 | error); | ||
116 | return error; | ||
117 | } | ||
118 | |||
119 | device_init_wakeup(&pdev->dev, 1); | ||
120 | |||
121 | return 0; | ||
122 | } | ||
123 | |||
124 | static int hi65xx_powerkey_remove(struct platform_device *pdev) | ||
125 | { | ||
126 | device_init_wakeup(&pdev->dev, 0); | ||
127 | |||
128 | return 0; | ||
129 | } | ||
130 | |||
131 | static struct platform_driver hi65xx_powerkey_driver = { | ||
132 | .driver = { | ||
133 | .name = "hi65xx-powerkey", | ||
134 | }, | ||
135 | .probe = hi65xx_powerkey_probe, | ||
136 | .remove = hi65xx_powerkey_remove, | ||
137 | }; | ||
138 | module_platform_driver(hi65xx_powerkey_driver); | ||
139 | |||
140 | MODULE_AUTHOR("Zhiliang Xue <xuezhiliang@huawei.com"); | ||
141 | MODULE_DESCRIPTION("Hisi PMIC Power key driver"); | ||
142 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/input/misc/regulator-haptic.c b/drivers/input/misc/regulator-haptic.c index a804705eb04a..2e8f801932be 100644 --- a/drivers/input/misc/regulator-haptic.c +++ b/drivers/input/misc/regulator-haptic.c | |||
@@ -124,7 +124,7 @@ regulator_haptic_parse_dt(struct device *dev, struct regulator_haptic *haptic) | |||
124 | 124 | ||
125 | node = dev->of_node; | 125 | node = dev->of_node; |
126 | if(!node) { | 126 | if(!node) { |
127 | dev_err(dev, "Missing dveice tree data\n"); | 127 | dev_err(dev, "Missing device tree data\n"); |
128 | return -EINVAL; | 128 | return -EINVAL; |
129 | } | 129 | } |
130 | 130 | ||
diff --git a/drivers/input/misc/xen-kbdfront.c b/drivers/input/misc/xen-kbdfront.c index 0a9ad2cfb55c..227fbd2dbb71 100644 --- a/drivers/input/misc/xen-kbdfront.c +++ b/drivers/input/misc/xen-kbdfront.c | |||
@@ -130,8 +130,8 @@ static int xenkbd_probe(struct xenbus_device *dev, | |||
130 | if (xenbus_scanf(XBT_NIL, dev->otherend, "feature-abs-pointer", "%d", &abs) < 0) | 130 | if (xenbus_scanf(XBT_NIL, dev->otherend, "feature-abs-pointer", "%d", &abs) < 0) |
131 | abs = 0; | 131 | abs = 0; |
132 | if (abs) { | 132 | if (abs) { |
133 | ret = xenbus_printf(XBT_NIL, dev->nodename, | 133 | ret = xenbus_write(XBT_NIL, dev->nodename, |
134 | "request-abs-pointer", "1"); | 134 | "request-abs-pointer", "1"); |
135 | if (ret) { | 135 | if (ret) { |
136 | pr_warning("xenkbd: can't request abs-pointer"); | 136 | pr_warning("xenkbd: can't request abs-pointer"); |
137 | abs = 0; | 137 | abs = 0; |
@@ -327,8 +327,8 @@ InitWait: | |||
327 | if (ret < 0) | 327 | if (ret < 0) |
328 | val = 0; | 328 | val = 0; |
329 | if (val) { | 329 | if (val) { |
330 | ret = xenbus_printf(XBT_NIL, info->xbdev->nodename, | 330 | ret = xenbus_write(XBT_NIL, info->xbdev->nodename, |
331 | "request-abs-pointer", "1"); | 331 | "request-abs-pointer", "1"); |
332 | if (ret) | 332 | if (ret) |
333 | pr_warning("xenkbd: can't request abs-pointer"); | 333 | pr_warning("xenkbd: can't request abs-pointer"); |
334 | } | 334 | } |
diff --git a/drivers/input/mouse/elantech.c b/drivers/input/mouse/elantech.c index be5b399da5d3..615d23ec0d8e 100644 --- a/drivers/input/mouse/elantech.c +++ b/drivers/input/mouse/elantech.c | |||
@@ -1708,7 +1708,7 @@ int elantech_init(struct psmouse *psmouse) | |||
1708 | snprintf(etd->tp_phys, sizeof(etd->tp_phys), "%s/input1", | 1708 | snprintf(etd->tp_phys, sizeof(etd->tp_phys), "%s/input1", |
1709 | psmouse->ps2dev.serio->phys); | 1709 | psmouse->ps2dev.serio->phys); |
1710 | tp_dev->phys = etd->tp_phys; | 1710 | tp_dev->phys = etd->tp_phys; |
1711 | tp_dev->name = "Elantech PS/2 TrackPoint"; | 1711 | tp_dev->name = "ETPS/2 Elantech TrackPoint"; |
1712 | tp_dev->id.bustype = BUS_I8042; | 1712 | tp_dev->id.bustype = BUS_I8042; |
1713 | tp_dev->id.vendor = 0x0002; | 1713 | tp_dev->id.vendor = 0x0002; |
1714 | tp_dev->id.product = PSMOUSE_ELANTECH; | 1714 | tp_dev->id.product = PSMOUSE_ELANTECH; |
diff --git a/drivers/input/mouse/lifebook.c b/drivers/input/mouse/lifebook.c index e5ed216824e9..13d324cef7df 100644 --- a/drivers/input/mouse/lifebook.c +++ b/drivers/input/mouse/lifebook.c | |||
@@ -287,7 +287,7 @@ static int lifebook_create_relative_device(struct psmouse *psmouse) | |||
287 | "%s/input1", psmouse->ps2dev.serio->phys); | 287 | "%s/input1", psmouse->ps2dev.serio->phys); |
288 | 288 | ||
289 | dev2->phys = priv->phys; | 289 | dev2->phys = priv->phys; |
290 | dev2->name = "PS/2 Touchpad"; | 290 | dev2->name = "LBPS/2 Fujitsu Lifebook Touchpad"; |
291 | dev2->id.bustype = BUS_I8042; | 291 | dev2->id.bustype = BUS_I8042; |
292 | dev2->id.vendor = 0x0002; | 292 | dev2->id.vendor = 0x0002; |
293 | dev2->id.product = PSMOUSE_LIFEBOOK; | 293 | dev2->id.product = PSMOUSE_LIFEBOOK; |
diff --git a/drivers/input/rmi4/rmi_f01.c b/drivers/input/rmi4/rmi_f01.c index eb362bc71a4c..fac81fc9bcf6 100644 --- a/drivers/input/rmi4/rmi_f01.c +++ b/drivers/input/rmi4/rmi_f01.c | |||
@@ -81,26 +81,26 @@ struct f01_basic_properties { | |||
81 | * This bit disables whatever sleep mode may be selected by the sleep_mode | 81 | * This bit disables whatever sleep mode may be selected by the sleep_mode |
82 | * field and forces the device to run at full power without sleeping. | 82 | * field and forces the device to run at full power without sleeping. |
83 | */ | 83 | */ |
84 | #define RMI_F01_CRTL0_NOSLEEP_BIT BIT(2) | 84 | #define RMI_F01_CTRL0_NOSLEEP_BIT BIT(2) |
85 | 85 | ||
86 | /* | 86 | /* |
87 | * When this bit is set, the touch controller employs a noise-filtering | 87 | * When this bit is set, the touch controller employs a noise-filtering |
88 | * algorithm designed for use with a connected battery charger. | 88 | * algorithm designed for use with a connected battery charger. |
89 | */ | 89 | */ |
90 | #define RMI_F01_CRTL0_CHARGER_BIT BIT(5) | 90 | #define RMI_F01_CTRL0_CHARGER_BIT BIT(5) |
91 | 91 | ||
92 | /* | 92 | /* |
93 | * Sets the report rate for the device. The effect of this setting is | 93 | * Sets the report rate for the device. The effect of this setting is |
94 | * highly product dependent. Check the spec sheet for your particular | 94 | * highly product dependent. Check the spec sheet for your particular |
95 | * touch sensor. | 95 | * touch sensor. |
96 | */ | 96 | */ |
97 | #define RMI_F01_CRTL0_REPORTRATE_BIT BIT(6) | 97 | #define RMI_F01_CTRL0_REPORTRATE_BIT BIT(6) |
98 | 98 | ||
99 | /* | 99 | /* |
100 | * Written by the host as an indicator that the device has been | 100 | * Written by the host as an indicator that the device has been |
101 | * successfully configured. | 101 | * successfully configured. |
102 | */ | 102 | */ |
103 | #define RMI_F01_CRTL0_CONFIGURED_BIT BIT(7) | 103 | #define RMI_F01_CTRL0_CONFIGURED_BIT BIT(7) |
104 | 104 | ||
105 | /** | 105 | /** |
106 | * @ctrl0 - see the bit definitions above. | 106 | * @ctrl0 - see the bit definitions above. |
@@ -330,10 +330,10 @@ static int rmi_f01_probe(struct rmi_function *fn) | |||
330 | case RMI_F01_NOSLEEP_DEFAULT: | 330 | case RMI_F01_NOSLEEP_DEFAULT: |
331 | break; | 331 | break; |
332 | case RMI_F01_NOSLEEP_OFF: | 332 | case RMI_F01_NOSLEEP_OFF: |
333 | f01->device_control.ctrl0 &= ~RMI_F01_CRTL0_NOSLEEP_BIT; | 333 | f01->device_control.ctrl0 &= ~RMI_F01_CTRL0_NOSLEEP_BIT; |
334 | break; | 334 | break; |
335 | case RMI_F01_NOSLEEP_ON: | 335 | case RMI_F01_NOSLEEP_ON: |
336 | f01->device_control.ctrl0 |= RMI_F01_CRTL0_NOSLEEP_BIT; | 336 | f01->device_control.ctrl0 |= RMI_F01_CTRL0_NOSLEEP_BIT; |
337 | break; | 337 | break; |
338 | } | 338 | } |
339 | 339 | ||
@@ -349,7 +349,7 @@ static int rmi_f01_probe(struct rmi_function *fn) | |||
349 | f01->device_control.ctrl0 &= ~RMI_F01_CTRL0_SLEEP_MODE_MASK; | 349 | f01->device_control.ctrl0 &= ~RMI_F01_CTRL0_SLEEP_MODE_MASK; |
350 | } | 350 | } |
351 | 351 | ||
352 | f01->device_control.ctrl0 |= RMI_F01_CRTL0_CONFIGURED_BIT; | 352 | f01->device_control.ctrl0 |= RMI_F01_CTRL0_CONFIGURED_BIT; |
353 | 353 | ||
354 | error = rmi_write(rmi_dev, fn->fd.control_base_addr, | 354 | error = rmi_write(rmi_dev, fn->fd.control_base_addr, |
355 | f01->device_control.ctrl0); | 355 | f01->device_control.ctrl0); |
@@ -535,8 +535,8 @@ static int rmi_f01_suspend(struct rmi_function *fn) | |||
535 | int error; | 535 | int error; |
536 | 536 | ||
537 | f01->old_nosleep = | 537 | f01->old_nosleep = |
538 | f01->device_control.ctrl0 & RMI_F01_CRTL0_NOSLEEP_BIT; | 538 | f01->device_control.ctrl0 & RMI_F01_CTRL0_NOSLEEP_BIT; |
539 | f01->device_control.ctrl0 &= ~RMI_F01_CRTL0_NOSLEEP_BIT; | 539 | f01->device_control.ctrl0 &= ~RMI_F01_CTRL0_NOSLEEP_BIT; |
540 | 540 | ||
541 | f01->device_control.ctrl0 &= ~RMI_F01_CTRL0_SLEEP_MODE_MASK; | 541 | f01->device_control.ctrl0 &= ~RMI_F01_CTRL0_SLEEP_MODE_MASK; |
542 | if (device_may_wakeup(fn->rmi_dev->xport->dev)) | 542 | if (device_may_wakeup(fn->rmi_dev->xport->dev)) |
@@ -549,7 +549,7 @@ static int rmi_f01_suspend(struct rmi_function *fn) | |||
549 | if (error) { | 549 | if (error) { |
550 | dev_err(&fn->dev, "Failed to write sleep mode: %d.\n", error); | 550 | dev_err(&fn->dev, "Failed to write sleep mode: %d.\n", error); |
551 | if (f01->old_nosleep) | 551 | if (f01->old_nosleep) |
552 | f01->device_control.ctrl0 |= RMI_F01_CRTL0_NOSLEEP_BIT; | 552 | f01->device_control.ctrl0 |= RMI_F01_CTRL0_NOSLEEP_BIT; |
553 | f01->device_control.ctrl0 &= ~RMI_F01_CTRL0_SLEEP_MODE_MASK; | 553 | f01->device_control.ctrl0 &= ~RMI_F01_CTRL0_SLEEP_MODE_MASK; |
554 | f01->device_control.ctrl0 |= RMI_SLEEP_MODE_NORMAL; | 554 | f01->device_control.ctrl0 |= RMI_SLEEP_MODE_NORMAL; |
555 | return error; | 555 | return error; |
@@ -564,7 +564,7 @@ static int rmi_f01_resume(struct rmi_function *fn) | |||
564 | int error; | 564 | int error; |
565 | 565 | ||
566 | if (f01->old_nosleep) | 566 | if (f01->old_nosleep) |
567 | f01->device_control.ctrl0 |= RMI_F01_CRTL0_NOSLEEP_BIT; | 567 | f01->device_control.ctrl0 |= RMI_F01_CTRL0_NOSLEEP_BIT; |
568 | 568 | ||
569 | f01->device_control.ctrl0 &= ~RMI_F01_CTRL0_SLEEP_MODE_MASK; | 569 | f01->device_control.ctrl0 &= ~RMI_F01_CTRL0_SLEEP_MODE_MASK; |
570 | f01->device_control.ctrl0 |= RMI_SLEEP_MODE_NORMAL; | 570 | f01->device_control.ctrl0 |= RMI_SLEEP_MODE_NORMAL; |
diff --git a/drivers/input/rmi4/rmi_f11.c b/drivers/input/rmi4/rmi_f11.c index ec8a10d53288..20c7134b3d3b 100644 --- a/drivers/input/rmi4/rmi_f11.c +++ b/drivers/input/rmi4/rmi_f11.c | |||
@@ -530,8 +530,8 @@ static void rmi_f11_rel_pos_report(struct f11_data *f11, u8 n_finger) | |||
530 | struct f11_2d_data *data = &f11->data; | 530 | struct f11_2d_data *data = &f11->data; |
531 | s8 x, y; | 531 | s8 x, y; |
532 | 532 | ||
533 | x = data->rel_pos[n_finger * 2]; | 533 | x = data->rel_pos[n_finger * RMI_F11_REL_BYTES]; |
534 | y = data->rel_pos[n_finger * 2 + 1]; | 534 | y = data->rel_pos[n_finger * RMI_F11_REL_BYTES + 1]; |
535 | 535 | ||
536 | rmi_2d_sensor_rel_report(sensor, x, y); | 536 | rmi_2d_sensor_rel_report(sensor, x, y); |
537 | } | 537 | } |
@@ -1241,7 +1241,6 @@ static int rmi_f11_attention(struct rmi_function *fn, unsigned long *irq_bits) | |||
1241 | struct rmi_driver_data *drvdata = dev_get_drvdata(&rmi_dev->dev); | 1241 | struct rmi_driver_data *drvdata = dev_get_drvdata(&rmi_dev->dev); |
1242 | struct f11_data *f11 = dev_get_drvdata(&fn->dev); | 1242 | struct f11_data *f11 = dev_get_drvdata(&fn->dev); |
1243 | u16 data_base_addr = fn->fd.data_base_addr; | 1243 | u16 data_base_addr = fn->fd.data_base_addr; |
1244 | u16 data_base_addr_offset = 0; | ||
1245 | int error; | 1244 | int error; |
1246 | 1245 | ||
1247 | if (rmi_dev->xport->attn_data) { | 1246 | if (rmi_dev->xport->attn_data) { |
@@ -1251,8 +1250,7 @@ static int rmi_f11_attention(struct rmi_function *fn, unsigned long *irq_bits) | |||
1251 | rmi_dev->xport->attn_size -= f11->sensor.attn_size; | 1250 | rmi_dev->xport->attn_size -= f11->sensor.attn_size; |
1252 | } else { | 1251 | } else { |
1253 | error = rmi_read_block(rmi_dev, | 1252 | error = rmi_read_block(rmi_dev, |
1254 | data_base_addr + data_base_addr_offset, | 1253 | data_base_addr, f11->sensor.data_pkt, |
1255 | f11->sensor.data_pkt, | ||
1256 | f11->sensor.pkt_size); | 1254 | f11->sensor.pkt_size); |
1257 | if (error < 0) | 1255 | if (error < 0) |
1258 | return error; | 1256 | return error; |
@@ -1260,7 +1258,6 @@ static int rmi_f11_attention(struct rmi_function *fn, unsigned long *irq_bits) | |||
1260 | 1258 | ||
1261 | rmi_f11_finger_handler(f11, &f11->sensor, irq_bits, | 1259 | rmi_f11_finger_handler(f11, &f11->sensor, irq_bits, |
1262 | drvdata->num_of_irq_regs); | 1260 | drvdata->num_of_irq_regs); |
1263 | data_base_addr_offset += f11->sensor.pkt_size; | ||
1264 | 1261 | ||
1265 | return 0; | 1262 | return 0; |
1266 | } | 1263 | } |
diff --git a/drivers/input/rmi4/rmi_f12.c b/drivers/input/rmi4/rmi_f12.c index 88e91559c84e..332c02f0b107 100644 --- a/drivers/input/rmi4/rmi_f12.c +++ b/drivers/input/rmi4/rmi_f12.c | |||
@@ -27,7 +27,6 @@ enum rmi_f12_object_type { | |||
27 | }; | 27 | }; |
28 | 28 | ||
29 | struct f12_data { | 29 | struct f12_data { |
30 | struct rmi_function *fn; | ||
31 | struct rmi_2d_sensor sensor; | 30 | struct rmi_2d_sensor sensor; |
32 | struct rmi_2d_sensor_platform_data sensor_pdata; | 31 | struct rmi_2d_sensor_platform_data sensor_pdata; |
33 | 32 | ||
diff --git a/drivers/input/rmi4/rmi_i2c.c b/drivers/input/rmi4/rmi_i2c.c index a96a326b53bd..6f2e0e4f0296 100644 --- a/drivers/input/rmi4/rmi_i2c.c +++ b/drivers/input/rmi4/rmi_i2c.c | |||
@@ -11,6 +11,8 @@ | |||
11 | #include <linux/rmi.h> | 11 | #include <linux/rmi.h> |
12 | #include <linux/irq.h> | 12 | #include <linux/irq.h> |
13 | #include <linux/of.h> | 13 | #include <linux/of.h> |
14 | #include <linux/delay.h> | ||
15 | #include <linux/regulator/consumer.h> | ||
14 | #include "rmi_driver.h" | 16 | #include "rmi_driver.h" |
15 | 17 | ||
16 | #define BUFFER_SIZE_INCREMENT 32 | 18 | #define BUFFER_SIZE_INCREMENT 32 |
@@ -37,6 +39,9 @@ struct rmi_i2c_xport { | |||
37 | 39 | ||
38 | u8 *tx_buf; | 40 | u8 *tx_buf; |
39 | size_t tx_buf_size; | 41 | size_t tx_buf_size; |
42 | |||
43 | struct regulator_bulk_data supplies[2]; | ||
44 | u32 startup_delay; | ||
40 | }; | 45 | }; |
41 | 46 | ||
42 | #define RMI_PAGE_SELECT_REGISTER 0xff | 47 | #define RMI_PAGE_SELECT_REGISTER 0xff |
@@ -246,6 +251,24 @@ static int rmi_i2c_probe(struct i2c_client *client, | |||
246 | return -ENODEV; | 251 | return -ENODEV; |
247 | } | 252 | } |
248 | 253 | ||
254 | rmi_i2c->supplies[0].supply = "vdd"; | ||
255 | rmi_i2c->supplies[1].supply = "vio"; | ||
256 | retval = devm_regulator_bulk_get(&client->dev, | ||
257 | ARRAY_SIZE(rmi_i2c->supplies), | ||
258 | rmi_i2c->supplies); | ||
259 | if (retval < 0) | ||
260 | return retval; | ||
261 | |||
262 | retval = regulator_bulk_enable(ARRAY_SIZE(rmi_i2c->supplies), | ||
263 | rmi_i2c->supplies); | ||
264 | if (retval < 0) | ||
265 | return retval; | ||
266 | |||
267 | of_property_read_u32(client->dev.of_node, "syna,startup-delay-ms", | ||
268 | &rmi_i2c->startup_delay); | ||
269 | |||
270 | msleep(rmi_i2c->startup_delay); | ||
271 | |||
249 | rmi_i2c->client = client; | 272 | rmi_i2c->client = client; |
250 | mutex_init(&rmi_i2c->page_mutex); | 273 | mutex_init(&rmi_i2c->page_mutex); |
251 | 274 | ||
@@ -286,6 +309,8 @@ static int rmi_i2c_remove(struct i2c_client *client) | |||
286 | struct rmi_i2c_xport *rmi_i2c = i2c_get_clientdata(client); | 309 | struct rmi_i2c_xport *rmi_i2c = i2c_get_clientdata(client); |
287 | 310 | ||
288 | rmi_unregister_transport_device(&rmi_i2c->xport); | 311 | rmi_unregister_transport_device(&rmi_i2c->xport); |
312 | regulator_bulk_disable(ARRAY_SIZE(rmi_i2c->supplies), | ||
313 | rmi_i2c->supplies); | ||
289 | 314 | ||
290 | return 0; | 315 | return 0; |
291 | } | 316 | } |
@@ -308,6 +333,10 @@ static int rmi_i2c_suspend(struct device *dev) | |||
308 | dev_warn(dev, "Failed to enable irq for wake: %d\n", | 333 | dev_warn(dev, "Failed to enable irq for wake: %d\n", |
309 | ret); | 334 | ret); |
310 | } | 335 | } |
336 | |||
337 | regulator_bulk_disable(ARRAY_SIZE(rmi_i2c->supplies), | ||
338 | rmi_i2c->supplies); | ||
339 | |||
311 | return ret; | 340 | return ret; |
312 | } | 341 | } |
313 | 342 | ||
@@ -317,6 +346,13 @@ static int rmi_i2c_resume(struct device *dev) | |||
317 | struct rmi_i2c_xport *rmi_i2c = i2c_get_clientdata(client); | 346 | struct rmi_i2c_xport *rmi_i2c = i2c_get_clientdata(client); |
318 | int ret; | 347 | int ret; |
319 | 348 | ||
349 | ret = regulator_bulk_enable(ARRAY_SIZE(rmi_i2c->supplies), | ||
350 | rmi_i2c->supplies); | ||
351 | if (ret) | ||
352 | return ret; | ||
353 | |||
354 | msleep(rmi_i2c->startup_delay); | ||
355 | |||
320 | enable_irq(rmi_i2c->irq); | 356 | enable_irq(rmi_i2c->irq); |
321 | if (device_may_wakeup(&client->dev)) { | 357 | if (device_may_wakeup(&client->dev)) { |
322 | ret = disable_irq_wake(rmi_i2c->irq); | 358 | ret = disable_irq_wake(rmi_i2c->irq); |
@@ -346,6 +382,9 @@ static int rmi_i2c_runtime_suspend(struct device *dev) | |||
346 | 382 | ||
347 | disable_irq(rmi_i2c->irq); | 383 | disable_irq(rmi_i2c->irq); |
348 | 384 | ||
385 | regulator_bulk_disable(ARRAY_SIZE(rmi_i2c->supplies), | ||
386 | rmi_i2c->supplies); | ||
387 | |||
349 | return 0; | 388 | return 0; |
350 | } | 389 | } |
351 | 390 | ||
@@ -355,6 +394,13 @@ static int rmi_i2c_runtime_resume(struct device *dev) | |||
355 | struct rmi_i2c_xport *rmi_i2c = i2c_get_clientdata(client); | 394 | struct rmi_i2c_xport *rmi_i2c = i2c_get_clientdata(client); |
356 | int ret; | 395 | int ret; |
357 | 396 | ||
397 | ret = regulator_bulk_enable(ARRAY_SIZE(rmi_i2c->supplies), | ||
398 | rmi_i2c->supplies); | ||
399 | if (ret) | ||
400 | return ret; | ||
401 | |||
402 | msleep(rmi_i2c->startup_delay); | ||
403 | |||
358 | enable_irq(rmi_i2c->irq); | 404 | enable_irq(rmi_i2c->irq); |
359 | 405 | ||
360 | ret = rmi_driver_resume(rmi_i2c->xport.rmi_dev); | 406 | ret = rmi_driver_resume(rmi_i2c->xport.rmi_dev); |
diff --git a/drivers/input/serio/ams_delta_serio.c b/drivers/input/serio/ams_delta_serio.c index 45887e31242a..3df501c3421b 100644 --- a/drivers/input/serio/ams_delta_serio.c +++ b/drivers/input/serio/ams_delta_serio.c | |||
@@ -56,7 +56,7 @@ static int check_data(int data) | |||
56 | /* it should be odd */ | 56 | /* it should be odd */ |
57 | if (!(parity & 0x01)) { | 57 | if (!(parity & 0x01)) { |
58 | dev_warn(&ams_delta_serio->dev, | 58 | dev_warn(&ams_delta_serio->dev, |
59 | "paritiy check failed, data=0x%X parity=0x%X\n", | 59 | "parity check failed, data=0x%X parity=0x%X\n", |
60 | data, parity); | 60 | data, parity); |
61 | return SERIO_PARITY; | 61 | return SERIO_PARITY; |
62 | } | 62 | } |
diff --git a/drivers/input/tablet/Kconfig b/drivers/input/tablet/Kconfig index 623bb9e0d5a4..a2b9f97422ce 100644 --- a/drivers/input/tablet/Kconfig +++ b/drivers/input/tablet/Kconfig | |||
@@ -73,6 +73,21 @@ config TABLET_USB_KBTAB | |||
73 | To compile this driver as a module, choose M here: the | 73 | To compile this driver as a module, choose M here: the |
74 | module will be called kbtab. | 74 | module will be called kbtab. |
75 | 75 | ||
76 | config TABLET_USB_PEGASUS | ||
77 | tristate "Pegasus Mobile Notetaker Pen input tablet support" | ||
78 | depends on USB_ARCH_HAS_HCD | ||
79 | select USB | ||
80 | help | ||
81 | Say Y here if you want to use the Pegasus Mobile Notetaker, | ||
82 | also known as: | ||
83 | Genie e-note The Notetaker, | ||
84 | Staedtler Digital ballpoint pen 990 01, | ||
85 | IRISnotes Express or | ||
86 | NEWLink Digital Note Taker. | ||
87 | |||
88 | To compile this driver as a module, choose M here: the | ||
89 | module will be called pegasus_notetaker. | ||
90 | |||
76 | config TABLET_SERIAL_WACOM4 | 91 | config TABLET_SERIAL_WACOM4 |
77 | tristate "Wacom protocol 4 serial tablet support" | 92 | tristate "Wacom protocol 4 serial tablet support" |
78 | select SERIO | 93 | select SERIO |
diff --git a/drivers/input/tablet/Makefile b/drivers/input/tablet/Makefile index 2e130101cf3c..200fc4e11987 100644 --- a/drivers/input/tablet/Makefile +++ b/drivers/input/tablet/Makefile | |||
@@ -8,4 +8,5 @@ obj-$(CONFIG_TABLET_USB_AIPTEK) += aiptek.o | |||
8 | obj-$(CONFIG_TABLET_USB_GTCO) += gtco.o | 8 | obj-$(CONFIG_TABLET_USB_GTCO) += gtco.o |
9 | obj-$(CONFIG_TABLET_USB_HANWANG) += hanwang.o | 9 | obj-$(CONFIG_TABLET_USB_HANWANG) += hanwang.o |
10 | obj-$(CONFIG_TABLET_USB_KBTAB) += kbtab.o | 10 | obj-$(CONFIG_TABLET_USB_KBTAB) += kbtab.o |
11 | obj-$(CONFIG_TABLET_USB_PEGASUS) += pegasus_notetaker.o | ||
11 | obj-$(CONFIG_TABLET_SERIAL_WACOM4) += wacom_serial4.o | 12 | obj-$(CONFIG_TABLET_SERIAL_WACOM4) += wacom_serial4.o |
diff --git a/drivers/input/tablet/pegasus_notetaker.c b/drivers/input/tablet/pegasus_notetaker.c new file mode 100644 index 000000000000..949dacc78664 --- /dev/null +++ b/drivers/input/tablet/pegasus_notetaker.c | |||
@@ -0,0 +1,450 @@ | |||
1 | /* | ||
2 | * Pegasus Mobile Notetaker Pen input tablet driver | ||
3 | * | ||
4 | * Copyright (c) 2016 Martin Kepplinger <martink@posteo.de> | ||
5 | */ | ||
6 | |||
7 | /* | ||
8 | * request packet (control endpoint): | ||
9 | * |-------------------------------------| | ||
10 | * | Report ID | Nr of bytes | command | | ||
11 | * | (1 byte) | (1 byte) | (n bytes) | | ||
12 | * |-------------------------------------| | ||
13 | * | 0x02 | n | | | ||
14 | * |-------------------------------------| | ||
15 | * | ||
16 | * data packet after set xy mode command, 0x80 0xb5 0x02 0x01 | ||
17 | * and pen is in range: | ||
18 | * | ||
19 | * byte byte name value (bits) | ||
20 | * -------------------------------------------- | ||
21 | * 0 status 0 1 0 0 0 0 X X | ||
22 | * 1 color 0 0 0 0 H 0 S T | ||
23 | * 2 X low | ||
24 | * 3 X high | ||
25 | * 4 Y low | ||
26 | * 5 Y high | ||
27 | * | ||
28 | * X X battery state: | ||
29 | * no state reported 0x00 | ||
30 | * battery low 0x01 | ||
31 | * battery good 0x02 | ||
32 | * | ||
33 | * H Hovering | ||
34 | * S Switch 1 (pen button) | ||
35 | * T Tip | ||
36 | */ | ||
37 | |||
38 | #include <linux/kernel.h> | ||
39 | #include <linux/module.h> | ||
40 | #include <linux/input.h> | ||
41 | #include <linux/usb/input.h> | ||
42 | #include <linux/slab.h> | ||
43 | |||
44 | /* USB HID defines */ | ||
45 | #define USB_REQ_GET_REPORT 0x01 | ||
46 | #define USB_REQ_SET_REPORT 0x09 | ||
47 | |||
48 | #define USB_VENDOR_ID_PEGASUSTECH 0x0e20 | ||
49 | #define USB_DEVICE_ID_PEGASUS_NOTETAKER_EN100 0x0101 | ||
50 | |||
51 | /* device specific defines */ | ||
52 | #define NOTETAKER_REPORT_ID 0x02 | ||
53 | #define NOTETAKER_SET_CMD 0x80 | ||
54 | #define NOTETAKER_SET_MODE 0xb5 | ||
55 | |||
56 | #define NOTETAKER_LED_MOUSE 0x02 | ||
57 | #define PEN_MODE_XY 0x01 | ||
58 | |||
59 | #define SPECIAL_COMMAND 0x80 | ||
60 | #define BUTTON_PRESSED 0xb5 | ||
61 | #define COMMAND_VERSION 0xa9 | ||
62 | |||
63 | /* in xy data packet */ | ||
64 | #define BATTERY_NO_REPORT 0x40 | ||
65 | #define BATTERY_LOW 0x41 | ||
66 | #define BATTERY_GOOD 0x42 | ||
67 | #define PEN_BUTTON_PRESSED BIT(1) | ||
68 | #define PEN_TIP BIT(0) | ||
69 | |||
70 | struct pegasus { | ||
71 | unsigned char *data; | ||
72 | u8 data_len; | ||
73 | dma_addr_t data_dma; | ||
74 | struct input_dev *dev; | ||
75 | struct usb_device *usbdev; | ||
76 | struct usb_interface *intf; | ||
77 | struct urb *irq; | ||
78 | char name[128]; | ||
79 | char phys[64]; | ||
80 | struct work_struct init; | ||
81 | }; | ||
82 | |||
83 | static int pegasus_control_msg(struct pegasus *pegasus, u8 *data, int len) | ||
84 | { | ||
85 | const int sizeof_buf = len + 2; | ||
86 | int result; | ||
87 | int error; | ||
88 | u8 *cmd_buf; | ||
89 | |||
90 | cmd_buf = kmalloc(sizeof_buf, GFP_KERNEL); | ||
91 | if (!cmd_buf) | ||
92 | return -ENOMEM; | ||
93 | |||
94 | cmd_buf[0] = NOTETAKER_REPORT_ID; | ||
95 | cmd_buf[1] = len; | ||
96 | memcpy(cmd_buf + 2, data, len); | ||
97 | |||
98 | result = usb_control_msg(pegasus->usbdev, | ||
99 | usb_sndctrlpipe(pegasus->usbdev, 0), | ||
100 | USB_REQ_SET_REPORT, | ||
101 | USB_TYPE_VENDOR | USB_DIR_OUT, | ||
102 | 0, 0, cmd_buf, sizeof_buf, | ||
103 | USB_CTRL_SET_TIMEOUT); | ||
104 | |||
105 | kfree(cmd_buf); | ||
106 | |||
107 | if (unlikely(result != sizeof_buf)) { | ||
108 | error = result < 0 ? result : -EIO; | ||
109 | dev_err(&pegasus->usbdev->dev, "control msg error: %d\n", | ||
110 | error); | ||
111 | return error; | ||
112 | } | ||
113 | |||
114 | return 0; | ||
115 | } | ||
116 | |||
117 | static int pegasus_set_mode(struct pegasus *pegasus, u8 mode, u8 led) | ||
118 | { | ||
119 | u8 cmd[] = { NOTETAKER_SET_CMD, NOTETAKER_SET_MODE, led, mode }; | ||
120 | |||
121 | return pegasus_control_msg(pegasus, cmd, sizeof(cmd)); | ||
122 | } | ||
123 | |||
124 | static void pegasus_parse_packet(struct pegasus *pegasus) | ||
125 | { | ||
126 | unsigned char *data = pegasus->data; | ||
127 | struct input_dev *dev = pegasus->dev; | ||
128 | u16 x, y; | ||
129 | |||
130 | switch (data[0]) { | ||
131 | case SPECIAL_COMMAND: | ||
132 | /* device button pressed */ | ||
133 | if (data[1] == BUTTON_PRESSED) | ||
134 | schedule_work(&pegasus->init); | ||
135 | |||
136 | break; | ||
137 | |||
138 | /* xy data */ | ||
139 | case BATTERY_LOW: | ||
140 | dev_warn_once(&dev->dev, "Pen battery low\n"); | ||
141 | /* fall through */ | ||
142 | |||
143 | case BATTERY_NO_REPORT: | ||
144 | case BATTERY_GOOD: | ||
145 | x = le16_to_cpup((__le16 *)&data[2]); | ||
146 | y = le16_to_cpup((__le16 *)&data[4]); | ||
147 | |||
148 | /* pen-up event */ | ||
149 | if (x == 0 && y == 0) | ||
150 | break; | ||
151 | |||
152 | input_report_key(dev, BTN_TOUCH, data[1] & PEN_TIP); | ||
153 | input_report_key(dev, BTN_RIGHT, data[1] & PEN_BUTTON_PRESSED); | ||
154 | input_report_key(dev, BTN_TOOL_PEN, 1); | ||
155 | input_report_abs(dev, ABS_X, (s16)x); | ||
156 | input_report_abs(dev, ABS_Y, y); | ||
157 | |||
158 | input_sync(dev); | ||
159 | break; | ||
160 | |||
161 | default: | ||
162 | dev_warn_once(&pegasus->usbdev->dev, | ||
163 | "unknown answer from device\n"); | ||
164 | } | ||
165 | } | ||
166 | |||
167 | static void pegasus_irq(struct urb *urb) | ||
168 | { | ||
169 | struct pegasus *pegasus = urb->context; | ||
170 | struct usb_device *dev = pegasus->usbdev; | ||
171 | int retval; | ||
172 | |||
173 | switch (urb->status) { | ||
174 | case 0: | ||
175 | pegasus_parse_packet(pegasus); | ||
176 | usb_mark_last_busy(pegasus->usbdev); | ||
177 | break; | ||
178 | |||
179 | case -ECONNRESET: | ||
180 | case -ENOENT: | ||
181 | case -ESHUTDOWN: | ||
182 | dev_err(&dev->dev, "%s - urb shutting down with status: %d", | ||
183 | __func__, urb->status); | ||
184 | return; | ||
185 | |||
186 | default: | ||
187 | dev_err(&dev->dev, "%s - nonzero urb status received: %d", | ||
188 | __func__, urb->status); | ||
189 | break; | ||
190 | } | ||
191 | |||
192 | retval = usb_submit_urb(urb, GFP_ATOMIC); | ||
193 | if (retval) | ||
194 | dev_err(&dev->dev, "%s - usb_submit_urb failed with result %d", | ||
195 | __func__, retval); | ||
196 | } | ||
197 | |||
198 | static void pegasus_init(struct work_struct *work) | ||
199 | { | ||
200 | struct pegasus *pegasus = container_of(work, struct pegasus, init); | ||
201 | int error; | ||
202 | |||
203 | error = pegasus_set_mode(pegasus, PEN_MODE_XY, NOTETAKER_LED_MOUSE); | ||
204 | if (error) | ||
205 | dev_err(&pegasus->usbdev->dev, "pegasus_set_mode error: %d\n", | ||
206 | error); | ||
207 | } | ||
208 | |||
209 | static int pegasus_open(struct input_dev *dev) | ||
210 | { | ||
211 | struct pegasus *pegasus = input_get_drvdata(dev); | ||
212 | int error; | ||
213 | |||
214 | error = usb_autopm_get_interface(pegasus->intf); | ||
215 | if (error) | ||
216 | return error; | ||
217 | |||
218 | pegasus->irq->dev = pegasus->usbdev; | ||
219 | if (usb_submit_urb(pegasus->irq, GFP_KERNEL)) { | ||
220 | error = -EIO; | ||
221 | goto err_autopm_put; | ||
222 | } | ||
223 | |||
224 | error = pegasus_set_mode(pegasus, PEN_MODE_XY, NOTETAKER_LED_MOUSE); | ||
225 | if (error) | ||
226 | goto err_kill_urb; | ||
227 | |||
228 | return 0; | ||
229 | |||
230 | err_kill_urb: | ||
231 | usb_kill_urb(pegasus->irq); | ||
232 | cancel_work_sync(&pegasus->init); | ||
233 | err_autopm_put: | ||
234 | usb_autopm_put_interface(pegasus->intf); | ||
235 | return error; | ||
236 | } | ||
237 | |||
238 | static void pegasus_close(struct input_dev *dev) | ||
239 | { | ||
240 | struct pegasus *pegasus = input_get_drvdata(dev); | ||
241 | |||
242 | usb_kill_urb(pegasus->irq); | ||
243 | cancel_work_sync(&pegasus->init); | ||
244 | usb_autopm_put_interface(pegasus->intf); | ||
245 | } | ||
246 | |||
247 | static int pegasus_probe(struct usb_interface *intf, | ||
248 | const struct usb_device_id *id) | ||
249 | { | ||
250 | struct usb_device *dev = interface_to_usbdev(intf); | ||
251 | struct usb_endpoint_descriptor *endpoint; | ||
252 | struct pegasus *pegasus; | ||
253 | struct input_dev *input_dev; | ||
254 | int error; | ||
255 | int pipe; | ||
256 | |||
257 | /* We control interface 0 */ | ||
258 | if (intf->cur_altsetting->desc.bInterfaceNumber >= 1) | ||
259 | return -ENODEV; | ||
260 | |||
261 | /* Sanity check that the device has an endpoint */ | ||
262 | if (intf->altsetting[0].desc.bNumEndpoints < 1) { | ||
263 | dev_err(&intf->dev, "Invalid number of endpoints\n"); | ||
264 | return -EINVAL; | ||
265 | } | ||
266 | |||
267 | endpoint = &intf->cur_altsetting->endpoint[0].desc; | ||
268 | |||
269 | pegasus = kzalloc(sizeof(*pegasus), GFP_KERNEL); | ||
270 | input_dev = input_allocate_device(); | ||
271 | if (!pegasus || !input_dev) { | ||
272 | error = -ENOMEM; | ||
273 | goto err_free_mem; | ||
274 | } | ||
275 | |||
276 | pegasus->usbdev = dev; | ||
277 | pegasus->dev = input_dev; | ||
278 | pegasus->intf = intf; | ||
279 | |||
280 | pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress); | ||
281 | pegasus->data_len = usb_maxpacket(dev, pipe, usb_pipeout(pipe)); | ||
282 | |||
283 | pegasus->data = usb_alloc_coherent(dev, pegasus->data_len, GFP_KERNEL, | ||
284 | &pegasus->data_dma); | ||
285 | if (!pegasus->data) { | ||
286 | error = -ENOMEM; | ||
287 | goto err_free_mem; | ||
288 | } | ||
289 | |||
290 | pegasus->irq = usb_alloc_urb(0, GFP_KERNEL); | ||
291 | if (!pegasus->irq) { | ||
292 | error = -ENOMEM; | ||
293 | goto err_free_dma; | ||
294 | } | ||
295 | |||
296 | usb_fill_int_urb(pegasus->irq, dev, pipe, | ||
297 | pegasus->data, pegasus->data_len, | ||
298 | pegasus_irq, pegasus, endpoint->bInterval); | ||
299 | |||
300 | pegasus->irq->transfer_dma = pegasus->data_dma; | ||
301 | pegasus->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; | ||
302 | |||
303 | if (dev->manufacturer) | ||
304 | strlcpy(pegasus->name, dev->manufacturer, | ||
305 | sizeof(pegasus->name)); | ||
306 | |||
307 | if (dev->product) { | ||
308 | if (dev->manufacturer) | ||
309 | strlcat(pegasus->name, " ", sizeof(pegasus->name)); | ||
310 | strlcat(pegasus->name, dev->product, sizeof(pegasus->name)); | ||
311 | } | ||
312 | |||
313 | if (!strlen(pegasus->name)) | ||
314 | snprintf(pegasus->name, sizeof(pegasus->name), | ||
315 | "USB Pegasus Device %04x:%04x", | ||
316 | le16_to_cpu(dev->descriptor.idVendor), | ||
317 | le16_to_cpu(dev->descriptor.idProduct)); | ||
318 | |||
319 | usb_make_path(dev, pegasus->phys, sizeof(pegasus->phys)); | ||
320 | strlcat(pegasus->phys, "/input0", sizeof(pegasus->phys)); | ||
321 | |||
322 | INIT_WORK(&pegasus->init, pegasus_init); | ||
323 | |||
324 | usb_set_intfdata(intf, pegasus); | ||
325 | |||
326 | input_dev->name = pegasus->name; | ||
327 | input_dev->phys = pegasus->phys; | ||
328 | usb_to_input_id(dev, &input_dev->id); | ||
329 | input_dev->dev.parent = &intf->dev; | ||
330 | |||
331 | input_set_drvdata(input_dev, pegasus); | ||
332 | |||
333 | input_dev->open = pegasus_open; | ||
334 | input_dev->close = pegasus_close; | ||
335 | |||
336 | __set_bit(EV_ABS, input_dev->evbit); | ||
337 | __set_bit(EV_KEY, input_dev->evbit); | ||
338 | |||
339 | __set_bit(ABS_X, input_dev->absbit); | ||
340 | __set_bit(ABS_Y, input_dev->absbit); | ||
341 | |||
342 | __set_bit(BTN_TOUCH, input_dev->keybit); | ||
343 | __set_bit(BTN_RIGHT, input_dev->keybit); | ||
344 | __set_bit(BTN_TOOL_PEN, input_dev->keybit); | ||
345 | |||
346 | __set_bit(INPUT_PROP_DIRECT, input_dev->propbit); | ||
347 | __set_bit(INPUT_PROP_POINTER, input_dev->propbit); | ||
348 | |||
349 | input_set_abs_params(input_dev, ABS_X, -1500, 1500, 8, 0); | ||
350 | input_set_abs_params(input_dev, ABS_Y, 1600, 3000, 8, 0); | ||
351 | |||
352 | error = input_register_device(pegasus->dev); | ||
353 | if (error) | ||
354 | goto err_free_urb; | ||
355 | |||
356 | return 0; | ||
357 | |||
358 | err_free_urb: | ||
359 | usb_free_urb(pegasus->irq); | ||
360 | err_free_dma: | ||
361 | usb_free_coherent(dev, pegasus->data_len, | ||
362 | pegasus->data, pegasus->data_dma); | ||
363 | err_free_mem: | ||
364 | input_free_device(input_dev); | ||
365 | kfree(pegasus); | ||
366 | usb_set_intfdata(intf, NULL); | ||
367 | |||
368 | return error; | ||
369 | } | ||
370 | |||
371 | static void pegasus_disconnect(struct usb_interface *intf) | ||
372 | { | ||
373 | struct pegasus *pegasus = usb_get_intfdata(intf); | ||
374 | |||
375 | input_unregister_device(pegasus->dev); | ||
376 | |||
377 | usb_free_urb(pegasus->irq); | ||
378 | usb_free_coherent(interface_to_usbdev(intf), | ||
379 | pegasus->data_len, pegasus->data, | ||
380 | pegasus->data_dma); | ||
381 | |||
382 | kfree(pegasus); | ||
383 | usb_set_intfdata(intf, NULL); | ||
384 | } | ||
385 | |||
386 | static int pegasus_suspend(struct usb_interface *intf, pm_message_t message) | ||
387 | { | ||
388 | struct pegasus *pegasus = usb_get_intfdata(intf); | ||
389 | |||
390 | mutex_lock(&pegasus->dev->mutex); | ||
391 | usb_kill_urb(pegasus->irq); | ||
392 | cancel_work_sync(&pegasus->init); | ||
393 | mutex_unlock(&pegasus->dev->mutex); | ||
394 | |||
395 | return 0; | ||
396 | } | ||
397 | |||
398 | static int pegasus_resume(struct usb_interface *intf) | ||
399 | { | ||
400 | struct pegasus *pegasus = usb_get_intfdata(intf); | ||
401 | int retval = 0; | ||
402 | |||
403 | mutex_lock(&pegasus->dev->mutex); | ||
404 | if (pegasus->dev->users && usb_submit_urb(pegasus->irq, GFP_NOIO) < 0) | ||
405 | retval = -EIO; | ||
406 | mutex_unlock(&pegasus->dev->mutex); | ||
407 | |||
408 | return retval; | ||
409 | } | ||
410 | |||
411 | static int pegasus_reset_resume(struct usb_interface *intf) | ||
412 | { | ||
413 | struct pegasus *pegasus = usb_get_intfdata(intf); | ||
414 | int retval = 0; | ||
415 | |||
416 | mutex_lock(&pegasus->dev->mutex); | ||
417 | if (pegasus->dev->users) { | ||
418 | retval = pegasus_set_mode(pegasus, PEN_MODE_XY, | ||
419 | NOTETAKER_LED_MOUSE); | ||
420 | if (!retval && usb_submit_urb(pegasus->irq, GFP_NOIO) < 0) | ||
421 | retval = -EIO; | ||
422 | } | ||
423 | mutex_unlock(&pegasus->dev->mutex); | ||
424 | |||
425 | return retval; | ||
426 | } | ||
427 | |||
428 | static const struct usb_device_id pegasus_ids[] = { | ||
429 | { USB_DEVICE(USB_VENDOR_ID_PEGASUSTECH, | ||
430 | USB_DEVICE_ID_PEGASUS_NOTETAKER_EN100) }, | ||
431 | { } | ||
432 | }; | ||
433 | MODULE_DEVICE_TABLE(usb, pegasus_ids); | ||
434 | |||
435 | static struct usb_driver pegasus_driver = { | ||
436 | .name = "pegasus_notetaker", | ||
437 | .probe = pegasus_probe, | ||
438 | .disconnect = pegasus_disconnect, | ||
439 | .suspend = pegasus_suspend, | ||
440 | .resume = pegasus_resume, | ||
441 | .reset_resume = pegasus_reset_resume, | ||
442 | .id_table = pegasus_ids, | ||
443 | .supports_autosuspend = 1, | ||
444 | }; | ||
445 | |||
446 | module_usb_driver(pegasus_driver); | ||
447 | |||
448 | MODULE_AUTHOR("Martin Kepplinger <martink@posteo.de>"); | ||
449 | MODULE_DESCRIPTION("Pegasus Mobile Notetaker Pen tablet driver"); | ||
450 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index 8ecdc38fd489..ee02dc7422bd 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig | |||
@@ -632,7 +632,7 @@ config TOUCHSCREEN_EDT_FT5X06 | |||
632 | 632 | ||
633 | config TOUCHSCREEN_MIGOR | 633 | config TOUCHSCREEN_MIGOR |
634 | tristate "Renesas MIGO-R touchscreen" | 634 | tristate "Renesas MIGO-R touchscreen" |
635 | depends on SH_MIGOR && I2C | 635 | depends on (SH_MIGOR || COMPILE_TEST) && I2C |
636 | help | 636 | help |
637 | Say Y here to enable MIGO-R touchscreen support. | 637 | Say Y here to enable MIGO-R touchscreen support. |
638 | 638 | ||
@@ -1046,6 +1046,19 @@ config TOUCHSCREEN_PCAP | |||
1046 | To compile this driver as a module, choose M here: the | 1046 | To compile this driver as a module, choose M here: the |
1047 | module will be called pcap_ts. | 1047 | module will be called pcap_ts. |
1048 | 1048 | ||
1049 | config TOUCHSCREEN_RM_TS | ||
1050 | tristate "Raydium I2C Touchscreen" | ||
1051 | depends on I2C | ||
1052 | depends on GPIOLIB || COMPILE_TEST | ||
1053 | help | ||
1054 | Say Y here if you have Raydium series I2C touchscreen, | ||
1055 | such as RM32380, connected to your system. | ||
1056 | |||
1057 | If unsure, say N. | ||
1058 | |||
1059 | To compile this driver as a module, choose M here: the | ||
1060 | module will be called raydium_i2c_ts. | ||
1061 | |||
1049 | config TOUCHSCREEN_ST1232 | 1062 | config TOUCHSCREEN_ST1232 |
1050 | tristate "Sitronix ST1232 touchscreen controllers" | 1063 | tristate "Sitronix ST1232 touchscreen controllers" |
1051 | depends on I2C | 1064 | depends on I2C |
@@ -1094,6 +1107,19 @@ config TOUCHSCREEN_SUR40 | |||
1094 | To compile this driver as a module, choose M here: the | 1107 | To compile this driver as a module, choose M here: the |
1095 | module will be called sur40. | 1108 | module will be called sur40. |
1096 | 1109 | ||
1110 | config TOUCHSCREEN_SURFACE3_SPI | ||
1111 | tristate "Ntrig/Microsoft Surface 3 SPI touchscreen" | ||
1112 | depends on SPI | ||
1113 | depends on GPIOLIB || COMPILE_TEST | ||
1114 | help | ||
1115 | Say Y here if you have the Ntrig/Microsoft SPI touchscreen | ||
1116 | controller chip as found on the Surface 3 in your system. | ||
1117 | |||
1118 | If unsure, say N. | ||
1119 | |||
1120 | To compile this driver as a module, choose M here: the | ||
1121 | module will be called surface3_spi. | ||
1122 | |||
1097 | config TOUCHSCREEN_SX8654 | 1123 | config TOUCHSCREEN_SX8654 |
1098 | tristate "Semtech SX8654 touchscreen" | 1124 | tristate "Semtech SX8654 touchscreen" |
1099 | depends on I2C | 1125 | depends on I2C |
diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile index f42975e719e0..3315882905f7 100644 --- a/drivers/input/touchscreen/Makefile +++ b/drivers/input/touchscreen/Makefile | |||
@@ -62,11 +62,13 @@ obj-$(CONFIG_TOUCHSCREEN_USB_COMPOSITE) += usbtouchscreen.o | |||
62 | obj-$(CONFIG_TOUCHSCREEN_PCAP) += pcap_ts.o | 62 | obj-$(CONFIG_TOUCHSCREEN_PCAP) += pcap_ts.o |
63 | obj-$(CONFIG_TOUCHSCREEN_PENMOUNT) += penmount.o | 63 | obj-$(CONFIG_TOUCHSCREEN_PENMOUNT) += penmount.o |
64 | obj-$(CONFIG_TOUCHSCREEN_PIXCIR) += pixcir_i2c_ts.o | 64 | obj-$(CONFIG_TOUCHSCREEN_PIXCIR) += pixcir_i2c_ts.o |
65 | obj-$(CONFIG_TOUCHSCREEN_RM_TS) += raydium_i2c_ts.o | ||
65 | obj-$(CONFIG_TOUCHSCREEN_S3C2410) += s3c2410_ts.o | 66 | obj-$(CONFIG_TOUCHSCREEN_S3C2410) += s3c2410_ts.o |
66 | obj-$(CONFIG_TOUCHSCREEN_ST1232) += st1232.o | 67 | obj-$(CONFIG_TOUCHSCREEN_ST1232) += st1232.o |
67 | obj-$(CONFIG_TOUCHSCREEN_STMPE) += stmpe-ts.o | 68 | obj-$(CONFIG_TOUCHSCREEN_STMPE) += stmpe-ts.o |
68 | obj-$(CONFIG_TOUCHSCREEN_SUN4I) += sun4i-ts.o | 69 | obj-$(CONFIG_TOUCHSCREEN_SUN4I) += sun4i-ts.o |
69 | obj-$(CONFIG_TOUCHSCREEN_SUR40) += sur40.o | 70 | obj-$(CONFIG_TOUCHSCREEN_SUR40) += sur40.o |
71 | obj-$(CONFIG_TOUCHSCREEN_SURFACE3_SPI) += surface3_spi.o | ||
70 | obj-$(CONFIG_TOUCHSCREEN_TI_AM335X_TSC) += ti_am335x_tsc.o | 72 | obj-$(CONFIG_TOUCHSCREEN_TI_AM335X_TSC) += ti_am335x_tsc.o |
71 | obj-$(CONFIG_TOUCHSCREEN_TOUCHIT213) += touchit213.o | 73 | obj-$(CONFIG_TOUCHSCREEN_TOUCHIT213) += touchit213.o |
72 | obj-$(CONFIG_TOUCHSCREEN_TOUCHRIGHT) += touchright.o | 74 | obj-$(CONFIG_TOUCHSCREEN_TOUCHRIGHT) += touchright.o |
diff --git a/drivers/input/touchscreen/ad7879.c b/drivers/input/touchscreen/ad7879.c index e4bf1103e6f8..e16a44667da7 100644 --- a/drivers/input/touchscreen/ad7879.c +++ b/drivers/input/touchscreen/ad7879.c | |||
@@ -595,7 +595,7 @@ struct ad7879 *ad7879_probe(struct device *dev, u8 devid, unsigned int irq, | |||
595 | } else { | 595 | } else { |
596 | input_set_abs_params(input_dev, ABS_X, 0, MAX_12BIT, 0, 0); | 596 | input_set_abs_params(input_dev, ABS_X, 0, MAX_12BIT, 0, 0); |
597 | input_set_abs_params(input_dev, ABS_Y, 0, MAX_12BIT, 0, 0); | 597 | input_set_abs_params(input_dev, ABS_Y, 0, MAX_12BIT, 0, 0); |
598 | touchscreen_parse_properties(input_dev, false); | 598 | touchscreen_parse_properties(input_dev, false, NULL); |
599 | if (!input_abs_get_max(input_dev, ABS_PRESSURE)) { | 599 | if (!input_abs_get_max(input_dev, ABS_PRESSURE)) { |
600 | dev_err(dev, "Touchscreen pressure is not specified\n"); | 600 | dev_err(dev, "Touchscreen pressure is not specified\n"); |
601 | return ERR_PTR(-EINVAL); | 601 | return ERR_PTR(-EINVAL); |
diff --git a/drivers/input/touchscreen/chipone_icn8318.c b/drivers/input/touchscreen/chipone_icn8318.c index 22a6fead8cfb..0bf14067c167 100644 --- a/drivers/input/touchscreen/chipone_icn8318.c +++ b/drivers/input/touchscreen/chipone_icn8318.c | |||
@@ -17,6 +17,7 @@ | |||
17 | #include <linux/i2c.h> | 17 | #include <linux/i2c.h> |
18 | #include <linux/input.h> | 18 | #include <linux/input.h> |
19 | #include <linux/input/mt.h> | 19 | #include <linux/input/mt.h> |
20 | #include <linux/input/touchscreen.h> | ||
20 | #include <linux/module.h> | 21 | #include <linux/module.h> |
21 | #include <linux/of.h> | 22 | #include <linux/of.h> |
22 | 23 | ||
@@ -52,11 +53,7 @@ struct icn8318_data { | |||
52 | struct i2c_client *client; | 53 | struct i2c_client *client; |
53 | struct input_dev *input; | 54 | struct input_dev *input; |
54 | struct gpio_desc *wake_gpio; | 55 | struct gpio_desc *wake_gpio; |
55 | u32 max_x; | 56 | struct touchscreen_properties prop; |
56 | u32 max_y; | ||
57 | bool invert_x; | ||
58 | bool invert_y; | ||
59 | bool swap_x_y; | ||
60 | }; | 57 | }; |
61 | 58 | ||
62 | static int icn8318_read_touch_data(struct i2c_client *client, | 59 | static int icn8318_read_touch_data(struct i2c_client *client, |
@@ -91,7 +88,7 @@ static irqreturn_t icn8318_irq(int irq, void *dev_id) | |||
91 | struct icn8318_data *data = dev_id; | 88 | struct icn8318_data *data = dev_id; |
92 | struct device *dev = &data->client->dev; | 89 | struct device *dev = &data->client->dev; |
93 | struct icn8318_touch_data touch_data; | 90 | struct icn8318_touch_data touch_data; |
94 | int i, ret, x, y; | 91 | int i, ret; |
95 | 92 | ||
96 | ret = icn8318_read_touch_data(data->client, &touch_data); | 93 | ret = icn8318_read_touch_data(data->client, &touch_data); |
97 | if (ret < 0) { | 94 | if (ret < 0) { |
@@ -124,22 +121,9 @@ static irqreturn_t icn8318_irq(int irq, void *dev_id) | |||
124 | if (!act) | 121 | if (!act) |
125 | continue; | 122 | continue; |
126 | 123 | ||
127 | x = be16_to_cpu(touch->x); | 124 | touchscreen_report_pos(data->input, &data->prop, |
128 | y = be16_to_cpu(touch->y); | 125 | be16_to_cpu(touch->x), |
129 | 126 | be16_to_cpu(touch->y), true); | |
130 | if (data->invert_x) | ||
131 | x = data->max_x - x; | ||
132 | |||
133 | if (data->invert_y) | ||
134 | y = data->max_y - y; | ||
135 | |||
136 | if (!data->swap_x_y) { | ||
137 | input_event(data->input, EV_ABS, ABS_MT_POSITION_X, x); | ||
138 | input_event(data->input, EV_ABS, ABS_MT_POSITION_Y, y); | ||
139 | } else { | ||
140 | input_event(data->input, EV_ABS, ABS_MT_POSITION_X, y); | ||
141 | input_event(data->input, EV_ABS, ABS_MT_POSITION_Y, x); | ||
142 | } | ||
143 | } | 127 | } |
144 | 128 | ||
145 | input_mt_sync_frame(data->input); | 129 | input_mt_sync_frame(data->input); |
@@ -200,10 +184,8 @@ static int icn8318_probe(struct i2c_client *client, | |||
200 | const struct i2c_device_id *id) | 184 | const struct i2c_device_id *id) |
201 | { | 185 | { |
202 | struct device *dev = &client->dev; | 186 | struct device *dev = &client->dev; |
203 | struct device_node *np = dev->of_node; | ||
204 | struct icn8318_data *data; | 187 | struct icn8318_data *data; |
205 | struct input_dev *input; | 188 | struct input_dev *input; |
206 | u32 fuzz_x = 0, fuzz_y = 0; | ||
207 | int error; | 189 | int error; |
208 | 190 | ||
209 | if (!client->irq) { | 191 | if (!client->irq) { |
@@ -223,19 +205,6 @@ static int icn8318_probe(struct i2c_client *client, | |||
223 | return error; | 205 | return error; |
224 | } | 206 | } |
225 | 207 | ||
226 | if (of_property_read_u32(np, "touchscreen-size-x", &data->max_x) || | ||
227 | of_property_read_u32(np, "touchscreen-size-y", &data->max_y)) { | ||
228 | dev_err(dev, "Error touchscreen-size-x and/or -y missing\n"); | ||
229 | return -EINVAL; | ||
230 | } | ||
231 | |||
232 | /* Optional */ | ||
233 | of_property_read_u32(np, "touchscreen-fuzz-x", &fuzz_x); | ||
234 | of_property_read_u32(np, "touchscreen-fuzz-y", &fuzz_y); | ||
235 | data->invert_x = of_property_read_bool(np, "touchscreen-inverted-x"); | ||
236 | data->invert_y = of_property_read_bool(np, "touchscreen-inverted-y"); | ||
237 | data->swap_x_y = of_property_read_bool(np, "touchscreen-swapped-x-y"); | ||
238 | |||
239 | input = devm_input_allocate_device(dev); | 208 | input = devm_input_allocate_device(dev); |
240 | if (!input) | 209 | if (!input) |
241 | return -ENOMEM; | 210 | return -ENOMEM; |
@@ -246,16 +215,14 @@ static int icn8318_probe(struct i2c_client *client, | |||
246 | input->close = icn8318_stop; | 215 | input->close = icn8318_stop; |
247 | input->dev.parent = dev; | 216 | input->dev.parent = dev; |
248 | 217 | ||
249 | if (!data->swap_x_y) { | 218 | input_set_capability(input, EV_ABS, ABS_MT_POSITION_X); |
250 | input_set_abs_params(input, ABS_MT_POSITION_X, 0, | 219 | input_set_capability(input, EV_ABS, ABS_MT_POSITION_Y); |
251 | data->max_x, fuzz_x, 0); | 220 | |
252 | input_set_abs_params(input, ABS_MT_POSITION_Y, 0, | 221 | touchscreen_parse_properties(input, true, &data->prop); |
253 | data->max_y, fuzz_y, 0); | 222 | if (!input_abs_get_max(input, ABS_MT_POSITION_X) || |
254 | } else { | 223 | !input_abs_get_max(input, ABS_MT_POSITION_Y)) { |
255 | input_set_abs_params(input, ABS_MT_POSITION_X, 0, | 224 | dev_err(dev, "Error touchscreen-size-x and/or -y missing\n"); |
256 | data->max_y, fuzz_y, 0); | 225 | return -EINVAL; |
257 | input_set_abs_params(input, ABS_MT_POSITION_Y, 0, | ||
258 | data->max_x, fuzz_x, 0); | ||
259 | } | 226 | } |
260 | 227 | ||
261 | error = input_mt_init_slots(input, ICN8318_MAX_TOUCHES, | 228 | error = input_mt_init_slots(input, ICN8318_MAX_TOUCHES, |
diff --git a/drivers/input/touchscreen/cyttsp_core.c b/drivers/input/touchscreen/cyttsp_core.c index 91cda8f8119d..79381cc1774a 100644 --- a/drivers/input/touchscreen/cyttsp_core.c +++ b/drivers/input/touchscreen/cyttsp_core.c | |||
@@ -657,7 +657,7 @@ struct cyttsp *cyttsp_probe(const struct cyttsp_bus_ops *bus_ops, | |||
657 | 657 | ||
658 | input_set_capability(input_dev, EV_ABS, ABS_MT_POSITION_X); | 658 | input_set_capability(input_dev, EV_ABS, ABS_MT_POSITION_X); |
659 | input_set_capability(input_dev, EV_ABS, ABS_MT_POSITION_Y); | 659 | input_set_capability(input_dev, EV_ABS, ABS_MT_POSITION_Y); |
660 | touchscreen_parse_properties(input_dev, true); | 660 | touchscreen_parse_properties(input_dev, true, NULL); |
661 | 661 | ||
662 | error = input_mt_init_slots(input_dev, CY_MAX_ID, 0); | 662 | error = input_mt_init_slots(input_dev, CY_MAX_ID, 0); |
663 | if (error) { | 663 | if (error) { |
diff --git a/drivers/input/touchscreen/edt-ft5x06.c b/drivers/input/touchscreen/edt-ft5x06.c index 23fbe382da8b..703e295a37ed 100644 --- a/drivers/input/touchscreen/edt-ft5x06.c +++ b/drivers/input/touchscreen/edt-ft5x06.c | |||
@@ -86,6 +86,7 @@ struct edt_reg_addr { | |||
86 | struct edt_ft5x06_ts_data { | 86 | struct edt_ft5x06_ts_data { |
87 | struct i2c_client *client; | 87 | struct i2c_client *client; |
88 | struct input_dev *input; | 88 | struct input_dev *input; |
89 | struct touchscreen_properties prop; | ||
89 | u16 num_x; | 90 | u16 num_x; |
90 | u16 num_y; | 91 | u16 num_y; |
91 | 92 | ||
@@ -246,8 +247,8 @@ static irqreturn_t edt_ft5x06_ts_isr(int irq, void *dev_id) | |||
246 | if (!down) | 247 | if (!down) |
247 | continue; | 248 | continue; |
248 | 249 | ||
249 | input_report_abs(tsdata->input, ABS_MT_POSITION_X, x); | 250 | touchscreen_report_pos(tsdata->input, &tsdata->prop, x, y, |
250 | input_report_abs(tsdata->input, ABS_MT_POSITION_Y, y); | 251 | true); |
251 | } | 252 | } |
252 | 253 | ||
253 | input_mt_report_pointer_emulation(tsdata->input, true); | 254 | input_mt_report_pointer_emulation(tsdata->input, true); |
@@ -972,7 +973,7 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client, | |||
972 | input_set_abs_params(input, ABS_MT_POSITION_Y, | 973 | input_set_abs_params(input, ABS_MT_POSITION_Y, |
973 | 0, tsdata->num_y * 64 - 1, 0, 0); | 974 | 0, tsdata->num_y * 64 - 1, 0, 0); |
974 | 975 | ||
975 | touchscreen_parse_properties(input, true); | 976 | touchscreen_parse_properties(input, true, &tsdata->prop); |
976 | 977 | ||
977 | error = input_mt_init_slots(input, tsdata->max_support_points, | 978 | error = input_mt_init_slots(input, tsdata->max_support_points, |
978 | INPUT_MT_DIRECT); | 979 | INPUT_MT_DIRECT); |
diff --git a/drivers/input/touchscreen/migor_ts.c b/drivers/input/touchscreen/migor_ts.c index c038db93e2c3..02fb11985819 100644 --- a/drivers/input/touchscreen/migor_ts.c +++ b/drivers/input/touchscreen/migor_ts.c | |||
@@ -202,7 +202,7 @@ static int migor_ts_remove(struct i2c_client *client) | |||
202 | return 0; | 202 | return 0; |
203 | } | 203 | } |
204 | 204 | ||
205 | static int migor_ts_suspend(struct device *dev) | 205 | static int __maybe_unused migor_ts_suspend(struct device *dev) |
206 | { | 206 | { |
207 | struct i2c_client *client = to_i2c_client(dev); | 207 | struct i2c_client *client = to_i2c_client(dev); |
208 | struct migor_ts_priv *priv = i2c_get_clientdata(client); | 208 | struct migor_ts_priv *priv = i2c_get_clientdata(client); |
@@ -213,7 +213,7 @@ static int migor_ts_suspend(struct device *dev) | |||
213 | return 0; | 213 | return 0; |
214 | } | 214 | } |
215 | 215 | ||
216 | static int migor_ts_resume(struct device *dev) | 216 | static int __maybe_unused migor_ts_resume(struct device *dev) |
217 | { | 217 | { |
218 | struct i2c_client *client = to_i2c_client(dev); | 218 | struct i2c_client *client = to_i2c_client(dev); |
219 | struct migor_ts_priv *priv = i2c_get_clientdata(client); | 219 | struct migor_ts_priv *priv = i2c_get_clientdata(client); |
@@ -230,7 +230,7 @@ static const struct i2c_device_id migor_ts_id[] = { | |||
230 | { "migor_ts", 0 }, | 230 | { "migor_ts", 0 }, |
231 | { } | 231 | { } |
232 | }; | 232 | }; |
233 | MODULE_DEVICE_TABLE(i2c, migor_ts); | 233 | MODULE_DEVICE_TABLE(i2c, migor_ts_id); |
234 | 234 | ||
235 | static struct i2c_driver migor_ts_driver = { | 235 | static struct i2c_driver migor_ts_driver = { |
236 | .driver = { | 236 | .driver = { |
diff --git a/drivers/input/touchscreen/of_touchscreen.c b/drivers/input/touchscreen/of_touchscreen.c index bb6f2fe14667..8d7f9c8f2771 100644 --- a/drivers/input/touchscreen/of_touchscreen.c +++ b/drivers/input/touchscreen/of_touchscreen.c | |||
@@ -55,12 +55,16 @@ static void touchscreen_set_params(struct input_dev *dev, | |||
55 | * @input: input device that should be parsed | 55 | * @input: input device that should be parsed |
56 | * @multitouch: specifies whether parsed properties should be applied to | 56 | * @multitouch: specifies whether parsed properties should be applied to |
57 | * single-touch or multi-touch axes | 57 | * single-touch or multi-touch axes |
58 | * @prop: pointer to a struct touchscreen_properties into which to store | ||
59 | * axis swap and invert info for use with touchscreen_report_x_y(); | ||
60 | * or %NULL | ||
58 | * | 61 | * |
59 | * This function parses common DT properties for touchscreens and setups the | 62 | * This function parses common DT properties for touchscreens and setups the |
60 | * input device accordingly. The function keeps previously set up default | 63 | * input device accordingly. The function keeps previously set up default |
61 | * values if no value is specified via DT. | 64 | * values if no value is specified via DT. |
62 | */ | 65 | */ |
63 | void touchscreen_parse_properties(struct input_dev *input, bool multitouch) | 66 | void touchscreen_parse_properties(struct input_dev *input, bool multitouch, |
67 | struct touchscreen_properties *prop) | ||
64 | { | 68 | { |
65 | struct device *dev = input->dev.parent; | 69 | struct device *dev = input->dev.parent; |
66 | unsigned int axis; | 70 | unsigned int axis; |
@@ -104,5 +108,80 @@ void touchscreen_parse_properties(struct input_dev *input, bool multitouch) | |||
104 | &fuzz); | 108 | &fuzz); |
105 | if (data_present) | 109 | if (data_present) |
106 | touchscreen_set_params(input, axis, maximum, fuzz); | 110 | touchscreen_set_params(input, axis, maximum, fuzz); |
111 | |||
112 | if (!prop) | ||
113 | return; | ||
114 | |||
115 | axis = multitouch ? ABS_MT_POSITION_X : ABS_X; | ||
116 | |||
117 | prop->max_x = input_abs_get_max(input, axis); | ||
118 | prop->max_y = input_abs_get_max(input, axis + 1); | ||
119 | prop->invert_x = | ||
120 | device_property_read_bool(dev, "touchscreen-inverted-x"); | ||
121 | prop->invert_y = | ||
122 | device_property_read_bool(dev, "touchscreen-inverted-y"); | ||
123 | prop->swap_x_y = | ||
124 | device_property_read_bool(dev, "touchscreen-swapped-x-y"); | ||
125 | |||
126 | if (prop->swap_x_y) | ||
127 | swap(input->absinfo[axis], input->absinfo[axis + 1]); | ||
107 | } | 128 | } |
108 | EXPORT_SYMBOL(touchscreen_parse_properties); | 129 | EXPORT_SYMBOL(touchscreen_parse_properties); |
130 | |||
131 | static void | ||
132 | touchscreen_apply_prop_to_x_y(const struct touchscreen_properties *prop, | ||
133 | unsigned int *x, unsigned int *y) | ||
134 | { | ||
135 | if (prop->invert_x) | ||
136 | *x = prop->max_x - *x; | ||
137 | |||
138 | if (prop->invert_y) | ||
139 | *y = prop->max_y - *y; | ||
140 | |||
141 | if (prop->swap_x_y) | ||
142 | swap(*x, *y); | ||
143 | } | ||
144 | |||
145 | /** | ||
146 | * touchscreen_set_mt_pos - Set input_mt_pos coordinates | ||
147 | * @pos: input_mt_pos to set coordinates of | ||
148 | * @prop: pointer to a struct touchscreen_properties | ||
149 | * @x: X coordinate to store in pos | ||
150 | * @y: Y coordinate to store in pos | ||
151 | * | ||
152 | * Adjust the passed in x and y values applying any axis inversion and | ||
153 | * swapping requested in the passed in touchscreen_properties and store | ||
154 | * the result in a struct input_mt_pos. | ||
155 | */ | ||
156 | void touchscreen_set_mt_pos(struct input_mt_pos *pos, | ||
157 | const struct touchscreen_properties *prop, | ||
158 | unsigned int x, unsigned int y) | ||
159 | { | ||
160 | touchscreen_apply_prop_to_x_y(prop, &x, &y); | ||
161 | pos->x = x; | ||
162 | pos->y = y; | ||
163 | } | ||
164 | EXPORT_SYMBOL(touchscreen_set_mt_pos); | ||
165 | |||
166 | /** | ||
167 | * touchscreen_report_pos - Report touchscreen coordinates | ||
168 | * @input: input_device to report coordinates for | ||
169 | * @prop: pointer to a struct touchscreen_properties | ||
170 | * @x: X coordinate to report | ||
171 | * @y: Y coordinate to report | ||
172 | * @multitouch: Report coordinates on single-touch or multi-touch axes | ||
173 | * | ||
174 | * Adjust the passed in x and y values applying any axis inversion and | ||
175 | * swapping requested in the passed in touchscreen_properties and then | ||
176 | * report the resulting coordinates on the input_dev's x and y axis. | ||
177 | */ | ||
178 | void touchscreen_report_pos(struct input_dev *input, | ||
179 | const struct touchscreen_properties *prop, | ||
180 | unsigned int x, unsigned int y, | ||
181 | bool multitouch) | ||
182 | { | ||
183 | touchscreen_apply_prop_to_x_y(prop, &x, &y); | ||
184 | input_report_abs(input, multitouch ? ABS_MT_POSITION_X : ABS_X, x); | ||
185 | input_report_abs(input, multitouch ? ABS_MT_POSITION_Y : ABS_Y, y); | ||
186 | } | ||
187 | EXPORT_SYMBOL(touchscreen_report_pos); | ||
diff --git a/drivers/input/touchscreen/pixcir_i2c_ts.c b/drivers/input/touchscreen/pixcir_i2c_ts.c index 09523a3d3f23..d159e14f4d20 100644 --- a/drivers/input/touchscreen/pixcir_i2c_ts.c +++ b/drivers/input/touchscreen/pixcir_i2c_ts.c | |||
@@ -27,9 +27,9 @@ | |||
27 | #include <linux/input/touchscreen.h> | 27 | #include <linux/input/touchscreen.h> |
28 | #include <linux/gpio.h> | 28 | #include <linux/gpio.h> |
29 | #include <linux/gpio/consumer.h> | 29 | #include <linux/gpio/consumer.h> |
30 | /*#include <linux/of.h>*/ | ||
31 | #include <linux/of_device.h> | 30 | #include <linux/of_device.h> |
32 | #include <linux/platform_data/pixcir_i2c_ts.h> | 31 | #include <linux/platform_data/pixcir_i2c_ts.h> |
32 | #include <asm/unaligned.h> | ||
33 | 33 | ||
34 | #define PIXCIR_MAX_SLOTS 5 /* Max fingers supported by driver */ | 34 | #define PIXCIR_MAX_SLOTS 5 /* Max fingers supported by driver */ |
35 | 35 | ||
@@ -41,19 +41,15 @@ struct pixcir_i2c_ts_data { | |||
41 | struct gpio_desc *gpio_enable; | 41 | struct gpio_desc *gpio_enable; |
42 | struct gpio_desc *gpio_wake; | 42 | struct gpio_desc *gpio_wake; |
43 | const struct pixcir_i2c_chip_data *chip; | 43 | const struct pixcir_i2c_chip_data *chip; |
44 | struct touchscreen_properties prop; | ||
44 | int max_fingers; /* Max fingers supported in this instance */ | 45 | int max_fingers; /* Max fingers supported in this instance */ |
45 | bool running; | 46 | bool running; |
46 | }; | 47 | }; |
47 | 48 | ||
48 | struct pixcir_touch { | ||
49 | int x; | ||
50 | int y; | ||
51 | int id; | ||
52 | }; | ||
53 | |||
54 | struct pixcir_report_data { | 49 | struct pixcir_report_data { |
55 | int num_touches; | 50 | int num_touches; |
56 | struct pixcir_touch touches[PIXCIR_MAX_SLOTS]; | 51 | struct input_mt_pos pos[PIXCIR_MAX_SLOTS]; |
52 | int ids[PIXCIR_MAX_SLOTS]; | ||
57 | }; | 53 | }; |
58 | 54 | ||
59 | static void pixcir_ts_parse(struct pixcir_i2c_ts_data *tsdata, | 55 | 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, | |||
98 | bufptr = &rdbuf[2]; | 94 | bufptr = &rdbuf[2]; |
99 | 95 | ||
100 | for (i = 0; i < touch; i++) { | 96 | for (i = 0; i < touch; i++) { |
101 | report->touches[i].x = (bufptr[1] << 8) | bufptr[0]; | 97 | touchscreen_set_mt_pos(&report->pos[i], &tsdata->prop, |
102 | report->touches[i].y = (bufptr[3] << 8) | bufptr[2]; | 98 | get_unaligned_le16(bufptr), |
103 | 99 | get_unaligned_le16(bufptr + 2)); | |
104 | if (chip->has_hw_ids) { | 100 | if (chip->has_hw_ids) { |
105 | report->touches[i].id = bufptr[4]; | 101 | report->ids[i] = bufptr[4]; |
106 | bufptr = bufptr + 5; | 102 | bufptr = bufptr + 5; |
107 | } else { | 103 | } else { |
108 | bufptr = bufptr + 4; | 104 | bufptr = bufptr + 4; |
@@ -113,9 +109,7 @@ static void pixcir_ts_parse(struct pixcir_i2c_ts_data *tsdata, | |||
113 | static void pixcir_ts_report(struct pixcir_i2c_ts_data *ts, | 109 | static void pixcir_ts_report(struct pixcir_i2c_ts_data *ts, |
114 | struct pixcir_report_data *report) | 110 | struct pixcir_report_data *report) |
115 | { | 111 | { |
116 | struct input_mt_pos pos[PIXCIR_MAX_SLOTS]; | ||
117 | int slots[PIXCIR_MAX_SLOTS]; | 112 | int slots[PIXCIR_MAX_SLOTS]; |
118 | struct pixcir_touch *touch; | ||
119 | int n, i, slot; | 113 | int n, i, slot; |
120 | struct device *dev = &ts->client->dev; | 114 | struct device *dev = &ts->client->dev; |
121 | const struct pixcir_i2c_chip_data *chip = ts->chip; | 115 | const struct pixcir_i2c_chip_data *chip = ts->chip; |
@@ -124,24 +118,16 @@ static void pixcir_ts_report(struct pixcir_i2c_ts_data *ts, | |||
124 | if (n > PIXCIR_MAX_SLOTS) | 118 | if (n > PIXCIR_MAX_SLOTS) |
125 | n = PIXCIR_MAX_SLOTS; | 119 | n = PIXCIR_MAX_SLOTS; |
126 | 120 | ||
127 | if (!ts->chip->has_hw_ids) { | 121 | if (!ts->chip->has_hw_ids) |
128 | for (i = 0; i < n; i++) { | 122 | input_mt_assign_slots(ts->input, slots, report->pos, n, 0); |
129 | touch = &report->touches[i]; | ||
130 | pos[i].x = touch->x; | ||
131 | pos[i].y = touch->y; | ||
132 | } | ||
133 | |||
134 | input_mt_assign_slots(ts->input, slots, pos, n, 0); | ||
135 | } | ||
136 | 123 | ||
137 | for (i = 0; i < n; i++) { | 124 | for (i = 0; i < n; i++) { |
138 | touch = &report->touches[i]; | ||
139 | |||
140 | if (chip->has_hw_ids) { | 125 | if (chip->has_hw_ids) { |
141 | slot = input_mt_get_slot_by_key(ts->input, touch->id); | 126 | slot = input_mt_get_slot_by_key(ts->input, |
127 | report->ids[i]); | ||
142 | if (slot < 0) { | 128 | if (slot < 0) { |
143 | dev_dbg(dev, "no free slot for id 0x%x\n", | 129 | dev_dbg(dev, "no free slot for id 0x%x\n", |
144 | touch->id); | 130 | report->ids[i]); |
145 | continue; | 131 | continue; |
146 | } | 132 | } |
147 | } else { | 133 | } else { |
@@ -149,14 +135,15 @@ static void pixcir_ts_report(struct pixcir_i2c_ts_data *ts, | |||
149 | } | 135 | } |
150 | 136 | ||
151 | input_mt_slot(ts->input, slot); | 137 | input_mt_slot(ts->input, slot); |
152 | input_mt_report_slot_state(ts->input, | 138 | input_mt_report_slot_state(ts->input, MT_TOOL_FINGER, true); |
153 | MT_TOOL_FINGER, true); | ||
154 | 139 | ||
155 | input_event(ts->input, EV_ABS, ABS_MT_POSITION_X, touch->x); | 140 | input_report_abs(ts->input, ABS_MT_POSITION_X, |
156 | input_event(ts->input, EV_ABS, ABS_MT_POSITION_Y, touch->y); | 141 | report->pos[i].x); |
142 | input_report_abs(ts->input, ABS_MT_POSITION_Y, | ||
143 | report->pos[i].y); | ||
157 | 144 | ||
158 | dev_dbg(dev, "%d: slot %d, x %d, y %d\n", | 145 | dev_dbg(dev, "%d: slot %d, x %d, y %d\n", |
159 | i, slot, touch->x, touch->y); | 146 | i, slot, report->pos[i].x, report->pos[i].y); |
160 | } | 147 | } |
161 | 148 | ||
162 | input_mt_sync_frame(ts->input); | 149 | input_mt_sync_frame(ts->input); |
@@ -515,7 +502,7 @@ static int pixcir_i2c_ts_probe(struct i2c_client *client, | |||
515 | } else { | 502 | } else { |
516 | input_set_capability(input, EV_ABS, ABS_MT_POSITION_X); | 503 | input_set_capability(input, EV_ABS, ABS_MT_POSITION_X); |
517 | input_set_capability(input, EV_ABS, ABS_MT_POSITION_Y); | 504 | input_set_capability(input, EV_ABS, ABS_MT_POSITION_Y); |
518 | touchscreen_parse_properties(input, true); | 505 | touchscreen_parse_properties(input, true, &tsdata->prop); |
519 | if (!input_abs_get_max(input, ABS_MT_POSITION_X) || | 506 | if (!input_abs_get_max(input, ABS_MT_POSITION_X) || |
520 | !input_abs_get_max(input, ABS_MT_POSITION_Y)) { | 507 | !input_abs_get_max(input, ABS_MT_POSITION_Y)) { |
521 | dev_err(dev, "Touchscreen size is not specified\n"); | 508 | dev_err(dev, "Touchscreen size is not specified\n"); |
diff --git a/drivers/input/touchscreen/raydium_i2c_ts.c b/drivers/input/touchscreen/raydium_i2c_ts.c new file mode 100644 index 000000000000..a99fb5cac5a0 --- /dev/null +++ b/drivers/input/touchscreen/raydium_i2c_ts.c | |||
@@ -0,0 +1,1238 @@ | |||
1 | /* | ||
2 | * Raydium touchscreen I2C driver. | ||
3 | * | ||
4 | * Copyright (C) 2012-2014, Raydium Semiconductor Corporation. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public License | ||
8 | * version 2, and only version 2, as published by the | ||
9 | * Free Software Foundation. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * Raydium reserves the right to make changes without further notice | ||
17 | * to the materials described herein. Raydium does not assume any | ||
18 | * liability arising out of the application described herein. | ||
19 | * | ||
20 | * Contact Raydium Semiconductor Corporation at www.rad-ic.com | ||
21 | */ | ||
22 | |||
23 | #include <linux/acpi.h> | ||
24 | #include <linux/delay.h> | ||
25 | #include <linux/firmware.h> | ||
26 | #include <linux/gpio/consumer.h> | ||
27 | #include <linux/i2c.h> | ||
28 | #include <linux/input.h> | ||
29 | #include <linux/input/mt.h> | ||
30 | #include <linux/interrupt.h> | ||
31 | #include <linux/module.h> | ||
32 | #include <linux/of.h> | ||
33 | #include <linux/regulator/consumer.h> | ||
34 | #include <linux/slab.h> | ||
35 | #include <asm/unaligned.h> | ||
36 | |||
37 | /* Slave I2C mode */ | ||
38 | #define RM_BOOT_BLDR 0x02 | ||
39 | #define RM_BOOT_MAIN 0x03 | ||
40 | |||
41 | /* I2C bootoloader commands */ | ||
42 | #define RM_CMD_BOOT_PAGE_WRT 0x0B /* send bl page write */ | ||
43 | #define RM_CMD_BOOT_WRT 0x11 /* send bl write */ | ||
44 | #define RM_CMD_BOOT_ACK 0x22 /* send ack*/ | ||
45 | #define RM_CMD_BOOT_CHK 0x33 /* send data check */ | ||
46 | #define RM_CMD_BOOT_READ 0x44 /* send wait bl data ready*/ | ||
47 | |||
48 | #define RM_BOOT_RDY 0xFF /* bl data ready */ | ||
49 | |||
50 | /* I2C main commands */ | ||
51 | #define RM_CMD_QUERY_BANK 0x2B | ||
52 | #define RM_CMD_DATA_BANK 0x4D | ||
53 | #define RM_CMD_ENTER_SLEEP 0x4E | ||
54 | #define RM_CMD_BANK_SWITCH 0xAA | ||
55 | |||
56 | #define RM_RESET_MSG_ADDR 0x40000004 | ||
57 | |||
58 | #define RM_MAX_READ_SIZE 56 | ||
59 | #define RM_PACKET_CRC_SIZE 2 | ||
60 | |||
61 | /* Touch relative info */ | ||
62 | #define RM_MAX_RETRIES 3 | ||
63 | #define RM_MAX_TOUCH_NUM 10 | ||
64 | #define RM_BOOT_DELAY_MS 100 | ||
65 | |||
66 | /* Offsets in contact data */ | ||
67 | #define RM_CONTACT_STATE_POS 0 | ||
68 | #define RM_CONTACT_X_POS 1 | ||
69 | #define RM_CONTACT_Y_POS 3 | ||
70 | #define RM_CONTACT_PRESSURE_POS 5 | ||
71 | #define RM_CONTACT_WIDTH_X_POS 6 | ||
72 | #define RM_CONTACT_WIDTH_Y_POS 7 | ||
73 | |||
74 | /* Bootloader relative info */ | ||
75 | #define RM_BL_WRT_CMD_SIZE 3 /* bl flash wrt cmd size */ | ||
76 | #define RM_BL_WRT_PKG_SIZE 32 /* bl wrt pkg size */ | ||
77 | #define RM_BL_WRT_LEN (RM_BL_WRT_PKG_SIZE + RM_BL_WRT_CMD_SIZE) | ||
78 | #define RM_FW_PAGE_SIZE 128 | ||
79 | #define RM_MAX_FW_RETRIES 30 | ||
80 | #define RM_MAX_FW_SIZE 0xD000 | ||
81 | |||
82 | #define RM_POWERON_DELAY_USEC 500 | ||
83 | #define RM_RESET_DELAY_MSEC 50 | ||
84 | |||
85 | enum raydium_bl_cmd { | ||
86 | BL_HEADER = 0, | ||
87 | BL_PAGE_STR, | ||
88 | BL_PKG_IDX, | ||
89 | BL_DATA_STR, | ||
90 | }; | ||
91 | |||
92 | enum raydium_bl_ack { | ||
93 | RAYDIUM_ACK_NULL = 0, | ||
94 | RAYDIUM_WAIT_READY, | ||
95 | RAYDIUM_PATH_READY, | ||
96 | }; | ||
97 | |||
98 | enum raydium_boot_mode { | ||
99 | RAYDIUM_TS_MAIN = 0, | ||
100 | RAYDIUM_TS_BLDR, | ||
101 | }; | ||
102 | |||
103 | /* Response to RM_CMD_DATA_BANK request */ | ||
104 | struct raydium_data_info { | ||
105 | __le32 data_bank_addr; | ||
106 | u8 pkg_size; | ||
107 | u8 tp_info_size; | ||
108 | }; | ||
109 | |||
110 | struct raydium_info { | ||
111 | __le32 hw_ver; /*device version */ | ||
112 | u8 main_ver; | ||
113 | u8 sub_ver; | ||
114 | __le16 ft_ver; /* test version */ | ||
115 | u8 x_num; | ||
116 | u8 y_num; | ||
117 | __le16 x_max; | ||
118 | __le16 y_max; | ||
119 | u8 x_res; /* units/mm */ | ||
120 | u8 y_res; /* units/mm */ | ||
121 | }; | ||
122 | |||
123 | /* struct raydium_data - represents state of Raydium touchscreen device */ | ||
124 | struct raydium_data { | ||
125 | struct i2c_client *client; | ||
126 | struct input_dev *input; | ||
127 | |||
128 | struct regulator *avdd; | ||
129 | struct regulator *vccio; | ||
130 | struct gpio_desc *reset_gpio; | ||
131 | |||
132 | struct raydium_info info; | ||
133 | |||
134 | struct mutex sysfs_mutex; | ||
135 | |||
136 | u8 *report_data; | ||
137 | |||
138 | u32 data_bank_addr; | ||
139 | u8 report_size; | ||
140 | u8 contact_size; | ||
141 | u8 pkg_size; | ||
142 | |||
143 | enum raydium_boot_mode boot_mode; | ||
144 | |||
145 | bool wake_irq_enabled; | ||
146 | }; | ||
147 | |||
148 | static int raydium_i2c_send(struct i2c_client *client, | ||
149 | u8 addr, const void *data, size_t len) | ||
150 | { | ||
151 | u8 *buf; | ||
152 | int tries = 0; | ||
153 | int ret; | ||
154 | |||
155 | buf = kmalloc(len + 1, GFP_KERNEL); | ||
156 | if (!buf) | ||
157 | return -ENOMEM; | ||
158 | |||
159 | buf[0] = addr; | ||
160 | memcpy(buf + 1, data, len); | ||
161 | |||
162 | do { | ||
163 | ret = i2c_master_send(client, buf, len + 1); | ||
164 | if (likely(ret == len + 1)) | ||
165 | break; | ||
166 | |||
167 | msleep(20); | ||
168 | } while (++tries < RM_MAX_RETRIES); | ||
169 | |||
170 | kfree(buf); | ||
171 | |||
172 | if (unlikely(ret != len + 1)) { | ||
173 | if (ret >= 0) | ||
174 | ret = -EIO; | ||
175 | dev_err(&client->dev, "%s failed: %d\n", __func__, ret); | ||
176 | return ret; | ||
177 | } | ||
178 | |||
179 | return 0; | ||
180 | } | ||
181 | |||
182 | static int raydium_i2c_read(struct i2c_client *client, | ||
183 | u8 addr, void *data, size_t len) | ||
184 | { | ||
185 | struct i2c_msg xfer[] = { | ||
186 | { | ||
187 | .addr = client->addr, | ||
188 | .len = 1, | ||
189 | .buf = &addr, | ||
190 | }, | ||
191 | { | ||
192 | .addr = client->addr, | ||
193 | .flags = I2C_M_RD, | ||
194 | .len = len, | ||
195 | .buf = data, | ||
196 | } | ||
197 | }; | ||
198 | int ret; | ||
199 | |||
200 | ret = i2c_transfer(client->adapter, xfer, ARRAY_SIZE(xfer)); | ||
201 | if (unlikely(ret != ARRAY_SIZE(xfer))) | ||
202 | return ret < 0 ? ret : -EIO; | ||
203 | |||
204 | return 0; | ||
205 | } | ||
206 | |||
207 | static int raydium_i2c_read_message(struct i2c_client *client, | ||
208 | u32 addr, void *data, size_t len) | ||
209 | { | ||
210 | __be32 be_addr; | ||
211 | size_t xfer_len; | ||
212 | int error; | ||
213 | |||
214 | while (len) { | ||
215 | xfer_len = min_t(size_t, len, RM_MAX_READ_SIZE); | ||
216 | |||
217 | be_addr = cpu_to_be32(addr); | ||
218 | |||
219 | error = raydium_i2c_send(client, RM_CMD_BANK_SWITCH, | ||
220 | &be_addr, sizeof(be_addr)); | ||
221 | if (!error) | ||
222 | error = raydium_i2c_read(client, addr & 0xff, | ||
223 | data, xfer_len); | ||
224 | if (error) | ||
225 | return error; | ||
226 | |||
227 | len -= xfer_len; | ||
228 | data += xfer_len; | ||
229 | addr += xfer_len; | ||
230 | } | ||
231 | |||
232 | return 0; | ||
233 | } | ||
234 | |||
235 | static int raydium_i2c_send_message(struct i2c_client *client, | ||
236 | u32 addr, const void *data, size_t len) | ||
237 | { | ||
238 | __be32 be_addr = cpu_to_be32(addr); | ||
239 | int error; | ||
240 | |||
241 | error = raydium_i2c_send(client, RM_CMD_BANK_SWITCH, | ||
242 | &be_addr, sizeof(be_addr)); | ||
243 | if (!error) | ||
244 | error = raydium_i2c_send(client, addr & 0xff, data, len); | ||
245 | |||
246 | return error; | ||
247 | } | ||
248 | |||
249 | static int raydium_i2c_sw_reset(struct i2c_client *client) | ||
250 | { | ||
251 | const u8 soft_rst_cmd = 0x01; | ||
252 | int error; | ||
253 | |||
254 | error = raydium_i2c_send_message(client, RM_RESET_MSG_ADDR, | ||
255 | &soft_rst_cmd, sizeof(soft_rst_cmd)); | ||
256 | if (error) { | ||
257 | dev_err(&client->dev, "software reset failed: %d\n", error); | ||
258 | return error; | ||
259 | } | ||
260 | |||
261 | msleep(RM_RESET_DELAY_MSEC); | ||
262 | |||
263 | return 0; | ||
264 | } | ||
265 | |||
266 | static int raydium_i2c_query_ts_info(struct raydium_data *ts) | ||
267 | { | ||
268 | struct i2c_client *client = ts->client; | ||
269 | struct raydium_data_info data_info; | ||
270 | __le32 query_bank_addr; | ||
271 | |||
272 | int error, retry_cnt; | ||
273 | |||
274 | for (retry_cnt = 0; retry_cnt < RM_MAX_RETRIES; retry_cnt++) { | ||
275 | error = raydium_i2c_read(client, RM_CMD_DATA_BANK, | ||
276 | &data_info, sizeof(data_info)); | ||
277 | if (error) | ||
278 | continue; | ||
279 | |||
280 | /* | ||
281 | * Warn user if we already allocated memory for reports and | ||
282 | * then the size changed (due to firmware update?) and keep | ||
283 | * old size instead. | ||
284 | */ | ||
285 | if (ts->report_data && ts->pkg_size != data_info.pkg_size) { | ||
286 | dev_warn(&client->dev, | ||
287 | "report size changes, was: %d, new: %d\n", | ||
288 | ts->pkg_size, data_info.pkg_size); | ||
289 | } else { | ||
290 | ts->pkg_size = data_info.pkg_size; | ||
291 | ts->report_size = ts->pkg_size - RM_PACKET_CRC_SIZE; | ||
292 | } | ||
293 | |||
294 | ts->contact_size = data_info.tp_info_size; | ||
295 | ts->data_bank_addr = le32_to_cpu(data_info.data_bank_addr); | ||
296 | |||
297 | dev_dbg(&client->dev, | ||
298 | "data_bank_addr: %#08x, report_size: %d, contact_size: %d\n", | ||
299 | ts->data_bank_addr, ts->report_size, ts->contact_size); | ||
300 | |||
301 | error = raydium_i2c_read(client, RM_CMD_QUERY_BANK, | ||
302 | &query_bank_addr, | ||
303 | sizeof(query_bank_addr)); | ||
304 | if (error) | ||
305 | continue; | ||
306 | |||
307 | error = raydium_i2c_read_message(client, | ||
308 | le32_to_cpu(query_bank_addr), | ||
309 | &ts->info, sizeof(ts->info)); | ||
310 | if (error) | ||
311 | continue; | ||
312 | |||
313 | return 0; | ||
314 | } | ||
315 | |||
316 | dev_err(&client->dev, "failed to query device parameters: %d\n", error); | ||
317 | return error; | ||
318 | } | ||
319 | |||
320 | static int raydium_i2c_check_fw_status(struct raydium_data *ts) | ||
321 | { | ||
322 | struct i2c_client *client = ts->client; | ||
323 | static const u8 bl_ack = 0x62; | ||
324 | static const u8 main_ack = 0x66; | ||
325 | u8 buf[4]; | ||
326 | int error; | ||
327 | |||
328 | error = raydium_i2c_read(client, RM_CMD_BOOT_READ, buf, sizeof(buf)); | ||
329 | if (!error) { | ||
330 | if (buf[0] == bl_ack) | ||
331 | ts->boot_mode = RAYDIUM_TS_BLDR; | ||
332 | else if (buf[0] == main_ack) | ||
333 | ts->boot_mode = RAYDIUM_TS_MAIN; | ||
334 | return 0; | ||
335 | } | ||
336 | |||
337 | return error; | ||
338 | } | ||
339 | |||
340 | static int raydium_i2c_initialize(struct raydium_data *ts) | ||
341 | { | ||
342 | struct i2c_client *client = ts->client; | ||
343 | int error, retry_cnt; | ||
344 | |||
345 | for (retry_cnt = 0; retry_cnt < RM_MAX_RETRIES; retry_cnt++) { | ||
346 | /* Wait for Hello packet */ | ||
347 | msleep(RM_BOOT_DELAY_MS); | ||
348 | |||
349 | error = raydium_i2c_check_fw_status(ts); | ||
350 | if (error) { | ||
351 | dev_err(&client->dev, | ||
352 | "failed to read 'hello' packet: %d\n", error); | ||
353 | continue; | ||
354 | } | ||
355 | |||
356 | if (ts->boot_mode == RAYDIUM_TS_BLDR || | ||
357 | ts->boot_mode == RAYDIUM_TS_MAIN) { | ||
358 | break; | ||
359 | } | ||
360 | } | ||
361 | |||
362 | if (error) | ||
363 | ts->boot_mode = RAYDIUM_TS_BLDR; | ||
364 | |||
365 | if (ts->boot_mode == RAYDIUM_TS_BLDR) { | ||
366 | ts->info.hw_ver = cpu_to_le32(0xffffffffUL); | ||
367 | ts->info.main_ver = 0xff; | ||
368 | ts->info.sub_ver = 0xff; | ||
369 | } else { | ||
370 | raydium_i2c_query_ts_info(ts); | ||
371 | } | ||
372 | |||
373 | return error; | ||
374 | } | ||
375 | |||
376 | static int raydium_i2c_bl_chk_state(struct i2c_client *client, | ||
377 | enum raydium_bl_ack state) | ||
378 | { | ||
379 | static const u8 ack_ok[] = { 0xFF, 0x39, 0x30, 0x30, 0x54 }; | ||
380 | u8 rbuf[sizeof(ack_ok)]; | ||
381 | u8 retry; | ||
382 | int error; | ||
383 | |||
384 | for (retry = 0; retry < RM_MAX_FW_RETRIES; retry++) { | ||
385 | switch (state) { | ||
386 | case RAYDIUM_ACK_NULL: | ||
387 | return 0; | ||
388 | |||
389 | case RAYDIUM_WAIT_READY: | ||
390 | error = raydium_i2c_read(client, RM_CMD_BOOT_CHK, | ||
391 | &rbuf[0], 1); | ||
392 | if (!error && rbuf[0] == RM_BOOT_RDY) | ||
393 | return 0; | ||
394 | |||
395 | break; | ||
396 | |||
397 | case RAYDIUM_PATH_READY: | ||
398 | error = raydium_i2c_read(client, RM_CMD_BOOT_CHK, | ||
399 | rbuf, sizeof(rbuf)); | ||
400 | if (!error && !memcmp(rbuf, ack_ok, sizeof(ack_ok))) | ||
401 | return 0; | ||
402 | |||
403 | break; | ||
404 | |||
405 | default: | ||
406 | dev_err(&client->dev, "%s: invalid target state %d\n", | ||
407 | __func__, state); | ||
408 | return -EINVAL; | ||
409 | } | ||
410 | |||
411 | msleep(20); | ||
412 | } | ||
413 | |||
414 | return -ETIMEDOUT; | ||
415 | } | ||
416 | |||
417 | static int raydium_i2c_write_object(struct i2c_client *client, | ||
418 | const void *data, size_t len, | ||
419 | enum raydium_bl_ack state) | ||
420 | { | ||
421 | int error; | ||
422 | |||
423 | error = raydium_i2c_send(client, RM_CMD_BOOT_WRT, data, len); | ||
424 | if (error) { | ||
425 | dev_err(&client->dev, "WRT obj command failed: %d\n", | ||
426 | error); | ||
427 | return error; | ||
428 | } | ||
429 | |||
430 | error = raydium_i2c_send(client, RM_CMD_BOOT_ACK, NULL, 0); | ||
431 | if (error) { | ||
432 | dev_err(&client->dev, "Ack obj command failed: %d\n", error); | ||
433 | return error; | ||
434 | } | ||
435 | |||
436 | error = raydium_i2c_bl_chk_state(client, state); | ||
437 | if (error) { | ||
438 | dev_err(&client->dev, "BL check state failed: %d\n", error); | ||
439 | return error; | ||
440 | } | ||
441 | return 0; | ||
442 | } | ||
443 | |||
444 | static bool raydium_i2c_boot_trigger(struct i2c_client *client) | ||
445 | { | ||
446 | static const u8 cmd[7][6] = { | ||
447 | { 0x08, 0x0C, 0x09, 0x00, 0x50, 0xD7 }, | ||
448 | { 0x08, 0x04, 0x09, 0x00, 0x50, 0xA5 }, | ||
449 | { 0x08, 0x04, 0x09, 0x00, 0x50, 0x00 }, | ||
450 | { 0x08, 0x04, 0x09, 0x00, 0x50, 0xA5 }, | ||
451 | { 0x08, 0x0C, 0x09, 0x00, 0x50, 0x00 }, | ||
452 | { 0x06, 0x01, 0x00, 0x00, 0x00, 0x00 }, | ||
453 | { 0x02, 0xA2, 0x00, 0x00, 0x00, 0x00 }, | ||
454 | }; | ||
455 | int i; | ||
456 | int error; | ||
457 | |||
458 | for (i = 0; i < 7; i++) { | ||
459 | error = raydium_i2c_write_object(client, cmd[i], sizeof(cmd[i]), | ||
460 | RAYDIUM_WAIT_READY); | ||
461 | if (error) { | ||
462 | dev_err(&client->dev, | ||
463 | "boot trigger failed at step %d: %d\n", | ||
464 | i, error); | ||
465 | return error; | ||
466 | } | ||
467 | } | ||
468 | |||
469 | return 0; | ||
470 | } | ||
471 | |||
472 | static bool raydium_i2c_fw_trigger(struct i2c_client *client) | ||
473 | { | ||
474 | static const u8 cmd[5][11] = { | ||
475 | { 0, 0x09, 0x71, 0x0C, 0x09, 0x00, 0x50, 0xD7, 0, 0, 0 }, | ||
476 | { 0, 0x09, 0x71, 0x04, 0x09, 0x00, 0x50, 0xA5, 0, 0, 0 }, | ||
477 | { 0, 0x09, 0x71, 0x04, 0x09, 0x00, 0x50, 0x00, 0, 0, 0 }, | ||
478 | { 0, 0x09, 0x71, 0x04, 0x09, 0x00, 0x50, 0xA5, 0, 0, 0 }, | ||
479 | { 0, 0x09, 0x71, 0x0C, 0x09, 0x00, 0x50, 0x00, 0, 0, 0 }, | ||
480 | }; | ||
481 | int i; | ||
482 | int error; | ||
483 | |||
484 | for (i = 0; i < 5; i++) { | ||
485 | error = raydium_i2c_write_object(client, cmd[i], sizeof(cmd[i]), | ||
486 | RAYDIUM_ACK_NULL); | ||
487 | if (error) { | ||
488 | dev_err(&client->dev, | ||
489 | "fw trigger failed at step %d: %d\n", | ||
490 | i, error); | ||
491 | return error; | ||
492 | } | ||
493 | } | ||
494 | |||
495 | return 0; | ||
496 | } | ||
497 | |||
498 | static int raydium_i2c_check_path(struct i2c_client *client) | ||
499 | { | ||
500 | static const u8 cmd[] = { 0x09, 0x00, 0x09, 0x00, 0x50, 0x10, 0x00 }; | ||
501 | int error; | ||
502 | |||
503 | error = raydium_i2c_write_object(client, cmd, sizeof(cmd), | ||
504 | RAYDIUM_PATH_READY); | ||
505 | if (error) { | ||
506 | dev_err(&client->dev, "check path command failed: %d\n", error); | ||
507 | return error; | ||
508 | } | ||
509 | |||
510 | return 0; | ||
511 | } | ||
512 | |||
513 | static int raydium_i2c_enter_bl(struct i2c_client *client) | ||
514 | { | ||
515 | static const u8 cal_cmd[] = { 0x00, 0x01, 0x52 }; | ||
516 | int error; | ||
517 | |||
518 | error = raydium_i2c_write_object(client, cal_cmd, sizeof(cal_cmd), | ||
519 | RAYDIUM_ACK_NULL); | ||
520 | if (error) { | ||
521 | dev_err(&client->dev, "enter bl command failed: %d\n", error); | ||
522 | return error; | ||
523 | } | ||
524 | |||
525 | msleep(RM_BOOT_DELAY_MS); | ||
526 | return 0; | ||
527 | } | ||
528 | |||
529 | static int raydium_i2c_leave_bl(struct i2c_client *client) | ||
530 | { | ||
531 | static const u8 leave_cmd[] = { 0x05, 0x00 }; | ||
532 | int error; | ||
533 | |||
534 | error = raydium_i2c_write_object(client, leave_cmd, sizeof(leave_cmd), | ||
535 | RAYDIUM_ACK_NULL); | ||
536 | if (error) { | ||
537 | dev_err(&client->dev, "leave bl command failed: %d\n", error); | ||
538 | return error; | ||
539 | } | ||
540 | |||
541 | msleep(RM_BOOT_DELAY_MS); | ||
542 | return 0; | ||
543 | } | ||
544 | |||
545 | static int raydium_i2c_write_checksum(struct i2c_client *client, | ||
546 | size_t length, u16 checksum) | ||
547 | { | ||
548 | u8 checksum_cmd[] = { 0x00, 0x05, 0x6D, 0x00, 0x00, 0x00, 0x00 }; | ||
549 | int error; | ||
550 | |||
551 | put_unaligned_le16(length, &checksum_cmd[3]); | ||
552 | put_unaligned_le16(checksum, &checksum_cmd[5]); | ||
553 | |||
554 | error = raydium_i2c_write_object(client, | ||
555 | checksum_cmd, sizeof(checksum_cmd), | ||
556 | RAYDIUM_ACK_NULL); | ||
557 | if (error) { | ||
558 | dev_err(&client->dev, "failed to write checksum: %d\n", | ||
559 | error); | ||
560 | return error; | ||
561 | } | ||
562 | |||
563 | return 0; | ||
564 | } | ||
565 | |||
566 | static int raydium_i2c_disable_watch_dog(struct i2c_client *client) | ||
567 | { | ||
568 | static const u8 cmd[] = { 0x0A, 0xAA }; | ||
569 | int error; | ||
570 | |||
571 | error = raydium_i2c_write_object(client, cmd, sizeof(cmd), | ||
572 | RAYDIUM_WAIT_READY); | ||
573 | if (error) { | ||
574 | dev_err(&client->dev, "disable watchdog command failed: %d\n", | ||
575 | error); | ||
576 | return error; | ||
577 | } | ||
578 | |||
579 | return 0; | ||
580 | } | ||
581 | |||
582 | static int raydium_i2c_fw_write_page(struct i2c_client *client, | ||
583 | u16 page_idx, const void *data, size_t len) | ||
584 | { | ||
585 | u8 buf[RM_BL_WRT_LEN]; | ||
586 | size_t xfer_len; | ||
587 | int error; | ||
588 | int i; | ||
589 | |||
590 | BUILD_BUG_ON((RM_FW_PAGE_SIZE % RM_BL_WRT_PKG_SIZE) != 0); | ||
591 | |||
592 | for (i = 0; i < RM_FW_PAGE_SIZE / RM_BL_WRT_PKG_SIZE; i++) { | ||
593 | buf[BL_HEADER] = RM_CMD_BOOT_PAGE_WRT; | ||
594 | buf[BL_PAGE_STR] = page_idx ? 0xff : 0; | ||
595 | buf[BL_PKG_IDX] = i + 1; | ||
596 | |||
597 | xfer_len = min_t(size_t, len, RM_BL_WRT_PKG_SIZE); | ||
598 | memcpy(&buf[BL_DATA_STR], data, xfer_len); | ||
599 | if (len < RM_BL_WRT_PKG_SIZE) | ||
600 | memset(&buf[BL_DATA_STR + xfer_len], 0xff, | ||
601 | RM_BL_WRT_PKG_SIZE - xfer_len); | ||
602 | |||
603 | error = raydium_i2c_write_object(client, buf, RM_BL_WRT_LEN, | ||
604 | RAYDIUM_WAIT_READY); | ||
605 | if (error) { | ||
606 | dev_err(&client->dev, | ||
607 | "page write command failed for page %d, chunk %d: %d\n", | ||
608 | page_idx, i, error); | ||
609 | return error; | ||
610 | } | ||
611 | |||
612 | data += xfer_len; | ||
613 | len -= xfer_len; | ||
614 | } | ||
615 | |||
616 | return error; | ||
617 | } | ||
618 | |||
619 | static u16 raydium_calc_chksum(const u8 *buf, u16 len) | ||
620 | { | ||
621 | u16 checksum = 0; | ||
622 | u16 i; | ||
623 | |||
624 | for (i = 0; i < len; i++) | ||
625 | checksum += buf[i]; | ||
626 | |||
627 | return checksum; | ||
628 | } | ||
629 | |||
630 | static int raydium_i2c_do_update_firmware(struct raydium_data *ts, | ||
631 | const struct firmware *fw) | ||
632 | { | ||
633 | struct i2c_client *client = ts->client; | ||
634 | const void *data; | ||
635 | size_t data_len; | ||
636 | size_t len; | ||
637 | int page_nr; | ||
638 | int i; | ||
639 | int error; | ||
640 | u16 fw_checksum; | ||
641 | |||
642 | if (fw->size == 0 || fw->size > RM_MAX_FW_SIZE) { | ||
643 | dev_err(&client->dev, "Invalid firmware length\n"); | ||
644 | return -EINVAL; | ||
645 | } | ||
646 | |||
647 | error = raydium_i2c_check_fw_status(ts); | ||
648 | if (error) { | ||
649 | dev_err(&client->dev, "Unable to access IC %d\n", error); | ||
650 | return error; | ||
651 | } | ||
652 | |||
653 | if (ts->boot_mode == RAYDIUM_TS_MAIN) { | ||
654 | for (i = 0; i < RM_MAX_RETRIES; i++) { | ||
655 | error = raydium_i2c_enter_bl(client); | ||
656 | if (!error) { | ||
657 | error = raydium_i2c_check_fw_status(ts); | ||
658 | if (error) { | ||
659 | dev_err(&client->dev, | ||
660 | "unable to access IC: %d\n", | ||
661 | error); | ||
662 | return error; | ||
663 | } | ||
664 | |||
665 | if (ts->boot_mode == RAYDIUM_TS_BLDR) | ||
666 | break; | ||
667 | } | ||
668 | } | ||
669 | |||
670 | if (ts->boot_mode == RAYDIUM_TS_MAIN) { | ||
671 | dev_err(&client->dev, | ||
672 | "failied to jump to boot loader: %d\n", | ||
673 | error); | ||
674 | return -EIO; | ||
675 | } | ||
676 | } | ||
677 | |||
678 | error = raydium_i2c_disable_watch_dog(client); | ||
679 | if (error) | ||
680 | return error; | ||
681 | |||
682 | error = raydium_i2c_check_path(client); | ||
683 | if (error) | ||
684 | return error; | ||
685 | |||
686 | error = raydium_i2c_boot_trigger(client); | ||
687 | if (error) { | ||
688 | dev_err(&client->dev, "send boot trigger fail: %d\n", error); | ||
689 | return error; | ||
690 | } | ||
691 | |||
692 | msleep(RM_BOOT_DELAY_MS); | ||
693 | |||
694 | data = fw->data; | ||
695 | data_len = fw->size; | ||
696 | page_nr = 0; | ||
697 | |||
698 | while (data_len) { | ||
699 | len = min_t(size_t, data_len, RM_FW_PAGE_SIZE); | ||
700 | |||
701 | error = raydium_i2c_fw_write_page(client, page_nr++, data, len); | ||
702 | if (error) | ||
703 | return error; | ||
704 | |||
705 | msleep(20); | ||
706 | |||
707 | data += len; | ||
708 | data_len -= len; | ||
709 | } | ||
710 | |||
711 | error = raydium_i2c_leave_bl(client); | ||
712 | if (error) { | ||
713 | dev_err(&client->dev, | ||
714 | "failed to leave boot loader: %d\n", error); | ||
715 | return error; | ||
716 | } | ||
717 | |||
718 | dev_dbg(&client->dev, "left boot loader mode\n"); | ||
719 | msleep(RM_BOOT_DELAY_MS); | ||
720 | |||
721 | error = raydium_i2c_check_fw_status(ts); | ||
722 | if (error) { | ||
723 | dev_err(&client->dev, | ||
724 | "failed to check fw status after write: %d\n", | ||
725 | error); | ||
726 | return error; | ||
727 | } | ||
728 | |||
729 | if (ts->boot_mode != RAYDIUM_TS_MAIN) { | ||
730 | dev_err(&client->dev, | ||
731 | "failed to switch to main fw after writing firmware: %d\n", | ||
732 | error); | ||
733 | return -EINVAL; | ||
734 | } | ||
735 | |||
736 | error = raydium_i2c_fw_trigger(client); | ||
737 | if (error) { | ||
738 | dev_err(&client->dev, "failed to trigger fw: %d\n", error); | ||
739 | return error; | ||
740 | } | ||
741 | |||
742 | fw_checksum = raydium_calc_chksum(fw->data, fw->size); | ||
743 | |||
744 | error = raydium_i2c_write_checksum(client, fw->size, fw_checksum); | ||
745 | if (error) | ||
746 | return error; | ||
747 | |||
748 | return 0; | ||
749 | } | ||
750 | |||
751 | static int raydium_i2c_fw_update(struct raydium_data *ts) | ||
752 | { | ||
753 | struct i2c_client *client = ts->client; | ||
754 | const struct firmware *fw = NULL; | ||
755 | const char *fw_file = "raydium.fw"; | ||
756 | int error; | ||
757 | |||
758 | error = request_firmware(&fw, fw_file, &client->dev); | ||
759 | if (error) { | ||
760 | dev_err(&client->dev, "Unable to open firmware %s\n", fw_file); | ||
761 | return error; | ||
762 | } | ||
763 | |||
764 | disable_irq(client->irq); | ||
765 | |||
766 | error = raydium_i2c_do_update_firmware(ts, fw); | ||
767 | if (error) { | ||
768 | dev_err(&client->dev, "firmware update failed: %d\n", error); | ||
769 | ts->boot_mode = RAYDIUM_TS_BLDR; | ||
770 | goto out_enable_irq; | ||
771 | } | ||
772 | |||
773 | error = raydium_i2c_initialize(ts); | ||
774 | if (error) { | ||
775 | dev_err(&client->dev, | ||
776 | "failed to initialize device after firmware update: %d\n", | ||
777 | error); | ||
778 | ts->boot_mode = RAYDIUM_TS_BLDR; | ||
779 | goto out_enable_irq; | ||
780 | } | ||
781 | |||
782 | ts->boot_mode = RAYDIUM_TS_MAIN; | ||
783 | |||
784 | out_enable_irq: | ||
785 | enable_irq(client->irq); | ||
786 | msleep(100); | ||
787 | |||
788 | release_firmware(fw); | ||
789 | |||
790 | return error; | ||
791 | } | ||
792 | |||
793 | static void raydium_mt_event(struct raydium_data *ts) | ||
794 | { | ||
795 | int i; | ||
796 | |||
797 | for (i = 0; i < ts->report_size / ts->contact_size; i++) { | ||
798 | u8 *contact = &ts->report_data[ts->contact_size * i]; | ||
799 | bool state = contact[RM_CONTACT_STATE_POS]; | ||
800 | u8 wx, wy; | ||
801 | |||
802 | input_mt_slot(ts->input, i); | ||
803 | input_mt_report_slot_state(ts->input, MT_TOOL_FINGER, state); | ||
804 | |||
805 | if (!state) | ||
806 | continue; | ||
807 | |||
808 | input_report_abs(ts->input, ABS_MT_POSITION_X, | ||
809 | get_unaligned_le16(&contact[RM_CONTACT_X_POS])); | ||
810 | input_report_abs(ts->input, ABS_MT_POSITION_Y, | ||
811 | get_unaligned_le16(&contact[RM_CONTACT_Y_POS])); | ||
812 | input_report_abs(ts->input, ABS_MT_PRESSURE, | ||
813 | contact[RM_CONTACT_PRESSURE_POS]); | ||
814 | |||
815 | wx = contact[RM_CONTACT_WIDTH_X_POS]; | ||
816 | wy = contact[RM_CONTACT_WIDTH_Y_POS]; | ||
817 | |||
818 | input_report_abs(ts->input, ABS_MT_TOUCH_MAJOR, max(wx, wy)); | ||
819 | input_report_abs(ts->input, ABS_MT_TOUCH_MINOR, min(wx, wy)); | ||
820 | } | ||
821 | |||
822 | input_mt_sync_frame(ts->input); | ||
823 | input_sync(ts->input); | ||
824 | } | ||
825 | |||
826 | static irqreturn_t raydium_i2c_irq(int irq, void *_dev) | ||
827 | { | ||
828 | struct raydium_data *ts = _dev; | ||
829 | int error; | ||
830 | u16 fw_crc; | ||
831 | u16 calc_crc; | ||
832 | |||
833 | if (ts->boot_mode != RAYDIUM_TS_MAIN) | ||
834 | goto out; | ||
835 | |||
836 | error = raydium_i2c_read_message(ts->client, ts->data_bank_addr, | ||
837 | ts->report_data, ts->pkg_size); | ||
838 | if (error) | ||
839 | goto out; | ||
840 | |||
841 | fw_crc = get_unaligned_le16(&ts->report_data[ts->report_size]); | ||
842 | calc_crc = raydium_calc_chksum(ts->report_data, ts->report_size); | ||
843 | if (unlikely(fw_crc != calc_crc)) { | ||
844 | dev_warn(&ts->client->dev, | ||
845 | "%s: invalid packet crc %#04x vs %#04x\n", | ||
846 | __func__, calc_crc, fw_crc); | ||
847 | goto out; | ||
848 | } | ||
849 | |||
850 | raydium_mt_event(ts); | ||
851 | |||
852 | out: | ||
853 | return IRQ_HANDLED; | ||
854 | } | ||
855 | |||
856 | static ssize_t raydium_i2c_fw_ver_show(struct device *dev, | ||
857 | struct device_attribute *attr, char *buf) | ||
858 | { | ||
859 | struct i2c_client *client = to_i2c_client(dev); | ||
860 | struct raydium_data *ts = i2c_get_clientdata(client); | ||
861 | |||
862 | return sprintf(buf, "%d.%d\n", ts->info.main_ver, ts->info.sub_ver); | ||
863 | } | ||
864 | |||
865 | static ssize_t raydium_i2c_hw_ver_show(struct device *dev, | ||
866 | struct device_attribute *attr, char *buf) | ||
867 | { | ||
868 | struct i2c_client *client = to_i2c_client(dev); | ||
869 | struct raydium_data *ts = i2c_get_clientdata(client); | ||
870 | |||
871 | return sprintf(buf, "%#04x\n", le32_to_cpu(ts->info.hw_ver)); | ||
872 | } | ||
873 | |||
874 | static ssize_t raydium_i2c_boot_mode_show(struct device *dev, | ||
875 | struct device_attribute *attr, | ||
876 | char *buf) | ||
877 | { | ||
878 | struct i2c_client *client = to_i2c_client(dev); | ||
879 | struct raydium_data *ts = i2c_get_clientdata(client); | ||
880 | |||
881 | return sprintf(buf, "%s\n", | ||
882 | ts->boot_mode == RAYDIUM_TS_MAIN ? | ||
883 | "Normal" : "Recovery"); | ||
884 | } | ||
885 | |||
886 | static ssize_t raydium_i2c_update_fw_store(struct device *dev, | ||
887 | struct device_attribute *attr, | ||
888 | const char *buf, size_t count) | ||
889 | { | ||
890 | struct i2c_client *client = to_i2c_client(dev); | ||
891 | struct raydium_data *ts = i2c_get_clientdata(client); | ||
892 | int error; | ||
893 | |||
894 | error = mutex_lock_interruptible(&ts->sysfs_mutex); | ||
895 | if (error) | ||
896 | return error; | ||
897 | |||
898 | error = raydium_i2c_fw_update(ts); | ||
899 | |||
900 | mutex_unlock(&ts->sysfs_mutex); | ||
901 | |||
902 | return error ?: count; | ||
903 | } | ||
904 | |||
905 | static ssize_t raydium_i2c_calibrate_store(struct device *dev, | ||
906 | struct device_attribute *attr, | ||
907 | const char *buf, size_t count) | ||
908 | { | ||
909 | struct i2c_client *client = to_i2c_client(dev); | ||
910 | struct raydium_data *ts = i2c_get_clientdata(client); | ||
911 | static const u8 cal_cmd[] = { 0x00, 0x01, 0x9E }; | ||
912 | int error; | ||
913 | |||
914 | error = mutex_lock_interruptible(&ts->sysfs_mutex); | ||
915 | if (error) | ||
916 | return error; | ||
917 | |||
918 | error = raydium_i2c_write_object(client, cal_cmd, sizeof(cal_cmd), | ||
919 | RAYDIUM_WAIT_READY); | ||
920 | if (error) | ||
921 | dev_err(&client->dev, "calibrate command failed: %d\n", error); | ||
922 | |||
923 | mutex_unlock(&ts->sysfs_mutex); | ||
924 | return error ?: count; | ||
925 | } | ||
926 | |||
927 | static DEVICE_ATTR(fw_version, S_IRUGO, raydium_i2c_fw_ver_show, NULL); | ||
928 | static DEVICE_ATTR(hw_version, S_IRUGO, raydium_i2c_hw_ver_show, NULL); | ||
929 | static DEVICE_ATTR(boot_mode, S_IRUGO, raydium_i2c_boot_mode_show, NULL); | ||
930 | static DEVICE_ATTR(update_fw, S_IWUSR, NULL, raydium_i2c_update_fw_store); | ||
931 | static DEVICE_ATTR(calibrate, S_IWUSR, NULL, raydium_i2c_calibrate_store); | ||
932 | |||
933 | static struct attribute *raydium_i2c_attributes[] = { | ||
934 | &dev_attr_update_fw.attr, | ||
935 | &dev_attr_boot_mode.attr, | ||
936 | &dev_attr_fw_version.attr, | ||
937 | &dev_attr_hw_version.attr, | ||
938 | &dev_attr_calibrate.attr, | ||
939 | NULL | ||
940 | }; | ||
941 | |||
942 | static struct attribute_group raydium_i2c_attribute_group = { | ||
943 | .attrs = raydium_i2c_attributes, | ||
944 | }; | ||
945 | |||
946 | static void raydium_i2c_remove_sysfs_group(void *_data) | ||
947 | { | ||
948 | struct raydium_data *ts = _data; | ||
949 | |||
950 | sysfs_remove_group(&ts->client->dev.kobj, &raydium_i2c_attribute_group); | ||
951 | } | ||
952 | |||
953 | static int raydium_i2c_power_on(struct raydium_data *ts) | ||
954 | { | ||
955 | int error; | ||
956 | |||
957 | if (!ts->reset_gpio) | ||
958 | return 0; | ||
959 | |||
960 | gpiod_set_value_cansleep(ts->reset_gpio, 1); | ||
961 | |||
962 | error = regulator_enable(ts->avdd); | ||
963 | if (error) { | ||
964 | dev_err(&ts->client->dev, | ||
965 | "failed to enable avdd regulator: %d\n", error); | ||
966 | goto release_reset_gpio; | ||
967 | } | ||
968 | |||
969 | error = regulator_enable(ts->vccio); | ||
970 | if (error) { | ||
971 | regulator_disable(ts->avdd); | ||
972 | dev_err(&ts->client->dev, | ||
973 | "failed to enable vccio regulator: %d\n", error); | ||
974 | goto release_reset_gpio; | ||
975 | } | ||
976 | |||
977 | udelay(RM_POWERON_DELAY_USEC); | ||
978 | |||
979 | release_reset_gpio: | ||
980 | gpiod_set_value_cansleep(ts->reset_gpio, 0); | ||
981 | |||
982 | if (error) | ||
983 | return error; | ||
984 | |||
985 | msleep(RM_RESET_DELAY_MSEC); | ||
986 | |||
987 | return 0; | ||
988 | } | ||
989 | |||
990 | static void raydium_i2c_power_off(void *_data) | ||
991 | { | ||
992 | struct raydium_data *ts = _data; | ||
993 | |||
994 | if (ts->reset_gpio) { | ||
995 | gpiod_set_value_cansleep(ts->reset_gpio, 1); | ||
996 | regulator_disable(ts->vccio); | ||
997 | regulator_disable(ts->avdd); | ||
998 | } | ||
999 | } | ||
1000 | |||
1001 | static int raydium_i2c_probe(struct i2c_client *client, | ||
1002 | const struct i2c_device_id *id) | ||
1003 | { | ||
1004 | union i2c_smbus_data dummy; | ||
1005 | struct raydium_data *ts; | ||
1006 | int error; | ||
1007 | |||
1008 | if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { | ||
1009 | dev_err(&client->dev, | ||
1010 | "i2c check functionality error (need I2C_FUNC_I2C)\n"); | ||
1011 | return -ENXIO; | ||
1012 | } | ||
1013 | |||
1014 | ts = devm_kzalloc(&client->dev, sizeof(*ts), GFP_KERNEL); | ||
1015 | if (!ts) | ||
1016 | return -ENOMEM; | ||
1017 | |||
1018 | mutex_init(&ts->sysfs_mutex); | ||
1019 | |||
1020 | ts->client = client; | ||
1021 | i2c_set_clientdata(client, ts); | ||
1022 | |||
1023 | ts->avdd = devm_regulator_get(&client->dev, "avdd"); | ||
1024 | if (IS_ERR(ts->avdd)) { | ||
1025 | error = PTR_ERR(ts->avdd); | ||
1026 | if (error != -EPROBE_DEFER) | ||
1027 | dev_err(&client->dev, | ||
1028 | "Failed to get 'avdd' regulator: %d\n", error); | ||
1029 | return error; | ||
1030 | } | ||
1031 | |||
1032 | ts->vccio = devm_regulator_get(&client->dev, "vccio"); | ||
1033 | if (IS_ERR(ts->vccio)) { | ||
1034 | error = PTR_ERR(ts->vccio); | ||
1035 | if (error != -EPROBE_DEFER) | ||
1036 | dev_err(&client->dev, | ||
1037 | "Failed to get 'vccio' regulator: %d\n", error); | ||
1038 | return error; | ||
1039 | } | ||
1040 | |||
1041 | ts->reset_gpio = devm_gpiod_get_optional(&client->dev, "reset", | ||
1042 | GPIOD_OUT_LOW); | ||
1043 | if (IS_ERR(ts->reset_gpio)) { | ||
1044 | error = PTR_ERR(ts->reset_gpio); | ||
1045 | if (error != -EPROBE_DEFER) | ||
1046 | dev_err(&client->dev, | ||
1047 | "failed to get reset gpio: %d\n", error); | ||
1048 | return error; | ||
1049 | } | ||
1050 | |||
1051 | error = raydium_i2c_power_on(ts); | ||
1052 | if (error) | ||
1053 | return error; | ||
1054 | |||
1055 | error = devm_add_action(&client->dev, raydium_i2c_power_off, ts); | ||
1056 | if (error) { | ||
1057 | dev_err(&client->dev, | ||
1058 | "failed to install power off action: %d\n", error); | ||
1059 | raydium_i2c_power_off(ts); | ||
1060 | return error; | ||
1061 | } | ||
1062 | |||
1063 | /* Make sure there is something at this address */ | ||
1064 | if (i2c_smbus_xfer(client->adapter, client->addr, 0, | ||
1065 | I2C_SMBUS_READ, 0, I2C_SMBUS_BYTE, &dummy) < 0) { | ||
1066 | dev_err(&client->dev, "nothing at this address\n"); | ||
1067 | return -ENXIO; | ||
1068 | } | ||
1069 | |||
1070 | error = raydium_i2c_initialize(ts); | ||
1071 | if (error) { | ||
1072 | dev_err(&client->dev, "failed to initialize: %d\n", error); | ||
1073 | return error; | ||
1074 | } | ||
1075 | |||
1076 | ts->report_data = devm_kmalloc(&client->dev, | ||
1077 | ts->pkg_size, GFP_KERNEL); | ||
1078 | if (!ts->report_data) | ||
1079 | return -ENOMEM; | ||
1080 | |||
1081 | ts->input = devm_input_allocate_device(&client->dev); | ||
1082 | if (!ts->input) { | ||
1083 | dev_err(&client->dev, "Failed to allocate input device\n"); | ||
1084 | return -ENOMEM; | ||
1085 | } | ||
1086 | |||
1087 | ts->input->name = "Raydium Touchscreen"; | ||
1088 | ts->input->id.bustype = BUS_I2C; | ||
1089 | |||
1090 | input_set_drvdata(ts->input, ts); | ||
1091 | |||
1092 | input_set_abs_params(ts->input, ABS_MT_POSITION_X, | ||
1093 | 0, le16_to_cpu(ts->info.x_max), 0, 0); | ||
1094 | input_set_abs_params(ts->input, ABS_MT_POSITION_Y, | ||
1095 | 0, le16_to_cpu(ts->info.y_max), 0, 0); | ||
1096 | input_abs_set_res(ts->input, ABS_MT_POSITION_X, ts->info.x_res); | ||
1097 | input_abs_set_res(ts->input, ABS_MT_POSITION_Y, ts->info.y_res); | ||
1098 | |||
1099 | input_set_abs_params(ts->input, ABS_MT_TOUCH_MAJOR, 0, 255, 0, 0); | ||
1100 | input_set_abs_params(ts->input, ABS_MT_PRESSURE, 0, 255, 0, 0); | ||
1101 | |||
1102 | error = input_mt_init_slots(ts->input, RM_MAX_TOUCH_NUM, | ||
1103 | INPUT_MT_DIRECT | INPUT_MT_DROP_UNUSED); | ||
1104 | if (error) { | ||
1105 | dev_err(&client->dev, | ||
1106 | "failed to initialize MT slots: %d\n", error); | ||
1107 | return error; | ||
1108 | } | ||
1109 | |||
1110 | error = input_register_device(ts->input); | ||
1111 | if (error) { | ||
1112 | dev_err(&client->dev, | ||
1113 | "unable to register input device: %d\n", error); | ||
1114 | return error; | ||
1115 | } | ||
1116 | |||
1117 | error = devm_request_threaded_irq(&client->dev, client->irq, | ||
1118 | NULL, raydium_i2c_irq, | ||
1119 | IRQF_ONESHOT, client->name, ts); | ||
1120 | if (error) { | ||
1121 | dev_err(&client->dev, "Failed to register interrupt\n"); | ||
1122 | return error; | ||
1123 | } | ||
1124 | |||
1125 | error = sysfs_create_group(&client->dev.kobj, | ||
1126 | &raydium_i2c_attribute_group); | ||
1127 | if (error) { | ||
1128 | dev_err(&client->dev, "failed to create sysfs attributes: %d\n", | ||
1129 | error); | ||
1130 | return error; | ||
1131 | } | ||
1132 | |||
1133 | error = devm_add_action(&client->dev, | ||
1134 | raydium_i2c_remove_sysfs_group, ts); | ||
1135 | if (error) { | ||
1136 | raydium_i2c_remove_sysfs_group(ts); | ||
1137 | dev_err(&client->dev, | ||
1138 | "Failed to add sysfs cleanup action: %d\n", error); | ||
1139 | return error; | ||
1140 | } | ||
1141 | |||
1142 | return 0; | ||
1143 | } | ||
1144 | |||
1145 | static void __maybe_unused raydium_enter_sleep(struct i2c_client *client) | ||
1146 | { | ||
1147 | static const u8 sleep_cmd[] = { 0x5A, 0xff, 0x00, 0x0f }; | ||
1148 | int error; | ||
1149 | |||
1150 | error = raydium_i2c_send(client, RM_CMD_ENTER_SLEEP, | ||
1151 | sleep_cmd, sizeof(sleep_cmd)); | ||
1152 | if (error) | ||
1153 | dev_err(&client->dev, | ||
1154 | "sleep command failed: %d\n", error); | ||
1155 | } | ||
1156 | |||
1157 | static int __maybe_unused raydium_i2c_suspend(struct device *dev) | ||
1158 | { | ||
1159 | struct i2c_client *client = to_i2c_client(dev); | ||
1160 | struct raydium_data *ts = i2c_get_clientdata(client); | ||
1161 | |||
1162 | /* Sleep is not available in BLDR recovery mode */ | ||
1163 | if (ts->boot_mode != RAYDIUM_TS_MAIN) | ||
1164 | return -EBUSY; | ||
1165 | |||
1166 | disable_irq(client->irq); | ||
1167 | |||
1168 | if (device_may_wakeup(dev)) { | ||
1169 | raydium_enter_sleep(client); | ||
1170 | |||
1171 | ts->wake_irq_enabled = (enable_irq_wake(client->irq) == 0); | ||
1172 | } else { | ||
1173 | raydium_i2c_power_off(ts); | ||
1174 | } | ||
1175 | |||
1176 | return 0; | ||
1177 | } | ||
1178 | |||
1179 | static int __maybe_unused raydium_i2c_resume(struct device *dev) | ||
1180 | { | ||
1181 | struct i2c_client *client = to_i2c_client(dev); | ||
1182 | struct raydium_data *ts = i2c_get_clientdata(client); | ||
1183 | |||
1184 | if (device_may_wakeup(dev)) { | ||
1185 | if (ts->wake_irq_enabled) | ||
1186 | disable_irq_wake(client->irq); | ||
1187 | raydium_i2c_sw_reset(client); | ||
1188 | } else { | ||
1189 | raydium_i2c_power_on(ts); | ||
1190 | raydium_i2c_initialize(ts); | ||
1191 | } | ||
1192 | |||
1193 | enable_irq(client->irq); | ||
1194 | |||
1195 | return 0; | ||
1196 | } | ||
1197 | |||
1198 | static SIMPLE_DEV_PM_OPS(raydium_i2c_pm_ops, | ||
1199 | raydium_i2c_suspend, raydium_i2c_resume); | ||
1200 | |||
1201 | static const struct i2c_device_id raydium_i2c_id[] = { | ||
1202 | { "raydium_i2c" , 0 }, | ||
1203 | { "rm32380", 0 }, | ||
1204 | { /* sentinel */ } | ||
1205 | }; | ||
1206 | MODULE_DEVICE_TABLE(i2c, raydium_i2c_id); | ||
1207 | |||
1208 | #ifdef CONFIG_ACPI | ||
1209 | static const struct acpi_device_id raydium_acpi_id[] = { | ||
1210 | { "RAYD0001", 0 }, | ||
1211 | { /* sentinel */ } | ||
1212 | }; | ||
1213 | MODULE_DEVICE_TABLE(acpi, raydium_acpi_id); | ||
1214 | #endif | ||
1215 | |||
1216 | #ifdef CONFIG_OF | ||
1217 | static const struct of_device_id raydium_of_match[] = { | ||
1218 | { .compatible = "raydium,rm32380", }, | ||
1219 | { /* sentinel */ } | ||
1220 | }; | ||
1221 | MODULE_DEVICE_TABLE(of, raydium_of_match); | ||
1222 | #endif | ||
1223 | |||
1224 | static struct i2c_driver raydium_i2c_driver = { | ||
1225 | .probe = raydium_i2c_probe, | ||
1226 | .id_table = raydium_i2c_id, | ||
1227 | .driver = { | ||
1228 | .name = "raydium_ts", | ||
1229 | .pm = &raydium_i2c_pm_ops, | ||
1230 | .acpi_match_table = ACPI_PTR(raydium_acpi_id), | ||
1231 | .of_match_table = of_match_ptr(raydium_of_match), | ||
1232 | }, | ||
1233 | }; | ||
1234 | module_i2c_driver(raydium_i2c_driver); | ||
1235 | |||
1236 | MODULE_AUTHOR("Raydium"); | ||
1237 | MODULE_DESCRIPTION("Raydium I2c Touchscreen driver"); | ||
1238 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/input/touchscreen/surface3_spi.c b/drivers/input/touchscreen/surface3_spi.c new file mode 100644 index 000000000000..e12fb9b63f31 --- /dev/null +++ b/drivers/input/touchscreen/surface3_spi.c | |||
@@ -0,0 +1,427 @@ | |||
1 | /* | ||
2 | * Driver for Ntrig/Microsoft Touchscreens over SPI | ||
3 | * | ||
4 | * Copyright (c) 2016 Red Hat Inc. | ||
5 | */ | ||
6 | |||
7 | /* | ||
8 | * This program is free software; you can redistribute it and/or modify it | ||
9 | * under the terms of the GNU General Public License as published by the Free | ||
10 | * Software Foundation; version 2 of the License. | ||
11 | */ | ||
12 | |||
13 | #include <linux/kernel.h> | ||
14 | |||
15 | #include <linux/delay.h> | ||
16 | #include <linux/gpio/consumer.h> | ||
17 | #include <linux/input.h> | ||
18 | #include <linux/input/mt.h> | ||
19 | #include <linux/interrupt.h> | ||
20 | #include <linux/module.h> | ||
21 | #include <linux/slab.h> | ||
22 | #include <linux/spi/spi.h> | ||
23 | #include <linux/acpi.h> | ||
24 | |||
25 | #include <asm/unaligned.h> | ||
26 | |||
27 | #define SURFACE3_PACKET_SIZE 264 | ||
28 | |||
29 | #define SURFACE3_REPORT_TOUCH 0xd2 | ||
30 | #define SURFACE3_REPORT_PEN 0x16 | ||
31 | |||
32 | struct surface3_ts_data { | ||
33 | struct spi_device *spi; | ||
34 | struct gpio_desc *gpiod_rst[2]; | ||
35 | struct input_dev *input_dev; | ||
36 | struct input_dev *pen_input_dev; | ||
37 | int pen_tool; | ||
38 | |||
39 | u8 rd_buf[SURFACE3_PACKET_SIZE] ____cacheline_aligned; | ||
40 | }; | ||
41 | |||
42 | struct surface3_ts_data_finger { | ||
43 | u8 status; | ||
44 | __le16 tracking_id; | ||
45 | __le16 x; | ||
46 | __le16 cx; | ||
47 | __le16 y; | ||
48 | __le16 cy; | ||
49 | __le16 width; | ||
50 | __le16 height; | ||
51 | u32 padding; | ||
52 | } __packed; | ||
53 | |||
54 | struct surface3_ts_data_pen { | ||
55 | u8 status; | ||
56 | __le16 x; | ||
57 | __le16 y; | ||
58 | __le16 pressure; | ||
59 | u8 padding; | ||
60 | } __packed; | ||
61 | |||
62 | static int surface3_spi_read(struct surface3_ts_data *ts_data) | ||
63 | { | ||
64 | struct spi_device *spi = ts_data->spi; | ||
65 | |||
66 | memset(ts_data->rd_buf, 0, sizeof(ts_data->rd_buf)); | ||
67 | return spi_read(spi, ts_data->rd_buf, sizeof(ts_data->rd_buf)); | ||
68 | } | ||
69 | |||
70 | static void surface3_spi_report_touch(struct surface3_ts_data *ts_data, | ||
71 | struct surface3_ts_data_finger *finger) | ||
72 | { | ||
73 | int st = finger->status & 0x01; | ||
74 | int slot; | ||
75 | |||
76 | slot = input_mt_get_slot_by_key(ts_data->input_dev, | ||
77 | get_unaligned_le16(&finger->tracking_id)); | ||
78 | if (slot < 0) | ||
79 | return; | ||
80 | |||
81 | input_mt_slot(ts_data->input_dev, slot); | ||
82 | input_mt_report_slot_state(ts_data->input_dev, MT_TOOL_FINGER, st); | ||
83 | if (st) { | ||
84 | input_report_abs(ts_data->input_dev, | ||
85 | ABS_MT_POSITION_X, | ||
86 | get_unaligned_le16(&finger->x)); | ||
87 | input_report_abs(ts_data->input_dev, | ||
88 | ABS_MT_POSITION_Y, | ||
89 | get_unaligned_le16(&finger->y)); | ||
90 | input_report_abs(ts_data->input_dev, | ||
91 | ABS_MT_WIDTH_MAJOR, | ||
92 | get_unaligned_le16(&finger->width)); | ||
93 | input_report_abs(ts_data->input_dev, | ||
94 | ABS_MT_WIDTH_MINOR, | ||
95 | get_unaligned_le16(&finger->height)); | ||
96 | } | ||
97 | } | ||
98 | |||
99 | static void surface3_spi_process_touch(struct surface3_ts_data *ts_data, u8 *data) | ||
100 | { | ||
101 | u16 timestamp; | ||
102 | unsigned int i; | ||
103 | timestamp = get_unaligned_le16(&data[15]); | ||
104 | |||
105 | for (i = 0; i < 13; i++) { | ||
106 | struct surface3_ts_data_finger *finger; | ||
107 | |||
108 | finger = (struct surface3_ts_data_finger *)&data[17 + | ||
109 | i * sizeof(struct surface3_ts_data_finger)]; | ||
110 | |||
111 | /* | ||
112 | * When bit 5 of status is 1, it marks the end of the report: | ||
113 | * - touch present: 0xe7 | ||
114 | * - touch released: 0xe4 | ||
115 | * - nothing valuable: 0xff | ||
116 | */ | ||
117 | if (finger->status & 0x10) | ||
118 | break; | ||
119 | |||
120 | surface3_spi_report_touch(ts_data, finger); | ||
121 | } | ||
122 | |||
123 | input_mt_sync_frame(ts_data->input_dev); | ||
124 | input_sync(ts_data->input_dev); | ||
125 | } | ||
126 | |||
127 | static void surface3_spi_report_pen(struct surface3_ts_data *ts_data, | ||
128 | struct surface3_ts_data_pen *pen) | ||
129 | { | ||
130 | struct input_dev *dev = ts_data->pen_input_dev; | ||
131 | int st = pen->status; | ||
132 | int prox = st & 0x01; | ||
133 | int rubber = st & 0x18; | ||
134 | int tool = (prox && rubber) ? BTN_TOOL_RUBBER : BTN_TOOL_PEN; | ||
135 | |||
136 | /* fake proximity out to switch tools */ | ||
137 | if (ts_data->pen_tool != tool) { | ||
138 | input_report_key(dev, ts_data->pen_tool, 0); | ||
139 | input_sync(dev); | ||
140 | ts_data->pen_tool = tool; | ||
141 | } | ||
142 | |||
143 | input_report_key(dev, BTN_TOUCH, st & 0x12); | ||
144 | |||
145 | input_report_key(dev, ts_data->pen_tool, prox); | ||
146 | |||
147 | if (st) { | ||
148 | input_report_key(dev, | ||
149 | BTN_STYLUS, | ||
150 | st & 0x04); | ||
151 | |||
152 | input_report_abs(dev, | ||
153 | ABS_X, | ||
154 | get_unaligned_le16(&pen->x)); | ||
155 | input_report_abs(dev, | ||
156 | ABS_Y, | ||
157 | get_unaligned_le16(&pen->y)); | ||
158 | input_report_abs(dev, | ||
159 | ABS_PRESSURE, | ||
160 | get_unaligned_le16(&pen->pressure)); | ||
161 | } | ||
162 | } | ||
163 | |||
164 | static void surface3_spi_process_pen(struct surface3_ts_data *ts_data, u8 *data) | ||
165 | { | ||
166 | struct surface3_ts_data_pen *pen; | ||
167 | |||
168 | pen = (struct surface3_ts_data_pen *)&data[15]; | ||
169 | |||
170 | surface3_spi_report_pen(ts_data, pen); | ||
171 | input_sync(ts_data->pen_input_dev); | ||
172 | } | ||
173 | |||
174 | static void surface3_spi_process(struct surface3_ts_data *ts_data) | ||
175 | { | ||
176 | const char header[] = { | ||
177 | 0xff, 0xff, 0xff, 0xff, 0xa5, 0x5a, 0xe7, 0x7e, 0x01 | ||
178 | }; | ||
179 | u8 *data = ts_data->rd_buf; | ||
180 | |||
181 | if (memcmp(header, data, sizeof(header))) | ||
182 | dev_err(&ts_data->spi->dev, | ||
183 | "%s header error: %*ph, ignoring...\n", | ||
184 | __func__, (int)sizeof(header), data); | ||
185 | |||
186 | switch (data[9]) { | ||
187 | case SURFACE3_REPORT_TOUCH: | ||
188 | surface3_spi_process_touch(ts_data, data); | ||
189 | break; | ||
190 | case SURFACE3_REPORT_PEN: | ||
191 | surface3_spi_process_pen(ts_data, data); | ||
192 | break; | ||
193 | default: | ||
194 | dev_err(&ts_data->spi->dev, | ||
195 | "%s unknown packet type: %x, ignoring...\n", | ||
196 | __func__, data[9]); | ||
197 | break; | ||
198 | } | ||
199 | } | ||
200 | |||
201 | static irqreturn_t surface3_spi_irq_handler(int irq, void *dev_id) | ||
202 | { | ||
203 | struct surface3_ts_data *data = dev_id; | ||
204 | |||
205 | if (surface3_spi_read(data)) | ||
206 | return IRQ_HANDLED; | ||
207 | |||
208 | dev_dbg(&data->spi->dev, "%s received -> %*ph\n", | ||
209 | __func__, SURFACE3_PACKET_SIZE, data->rd_buf); | ||
210 | surface3_spi_process(data); | ||
211 | |||
212 | return IRQ_HANDLED; | ||
213 | } | ||
214 | |||
215 | static void surface3_spi_power(struct surface3_ts_data *data, bool on) | ||
216 | { | ||
217 | gpiod_set_value(data->gpiod_rst[0], on); | ||
218 | gpiod_set_value(data->gpiod_rst[1], on); | ||
219 | /* let the device settle a little */ | ||
220 | msleep(20); | ||
221 | } | ||
222 | |||
223 | /** | ||
224 | * surface3_spi_get_gpio_config - Get GPIO config from ACPI/DT | ||
225 | * | ||
226 | * @ts: surface3_spi_ts_data pointer | ||
227 | */ | ||
228 | static int surface3_spi_get_gpio_config(struct surface3_ts_data *data) | ||
229 | { | ||
230 | int error; | ||
231 | struct device *dev; | ||
232 | struct gpio_desc *gpiod; | ||
233 | int i; | ||
234 | |||
235 | dev = &data->spi->dev; | ||
236 | |||
237 | /* Get the reset lines GPIO pin number */ | ||
238 | for (i = 0; i < 2; i++) { | ||
239 | gpiod = devm_gpiod_get_index(dev, NULL, i, GPIOD_OUT_LOW); | ||
240 | if (IS_ERR(gpiod)) { | ||
241 | error = PTR_ERR(gpiod); | ||
242 | if (error != -EPROBE_DEFER) | ||
243 | dev_err(dev, | ||
244 | "Failed to get power GPIO %d: %d\n", | ||
245 | i, | ||
246 | error); | ||
247 | return error; | ||
248 | } | ||
249 | |||
250 | data->gpiod_rst[i] = gpiod; | ||
251 | } | ||
252 | |||
253 | return 0; | ||
254 | } | ||
255 | |||
256 | static int surface3_spi_create_touch_input(struct surface3_ts_data *data) | ||
257 | { | ||
258 | struct input_dev *input; | ||
259 | int error; | ||
260 | |||
261 | input = devm_input_allocate_device(&data->spi->dev); | ||
262 | if (!input) | ||
263 | return -ENOMEM; | ||
264 | |||
265 | data->input_dev = input; | ||
266 | |||
267 | input_set_abs_params(input, ABS_MT_POSITION_X, 0, 9600, 0, 0); | ||
268 | input_abs_set_res(input, ABS_MT_POSITION_X, 40); | ||
269 | input_set_abs_params(input, ABS_MT_POSITION_Y, 0, 7200, 0, 0); | ||
270 | input_abs_set_res(input, ABS_MT_POSITION_Y, 48); | ||
271 | input_set_abs_params(input, ABS_MT_WIDTH_MAJOR, 0, 1024, 0, 0); | ||
272 | input_set_abs_params(input, ABS_MT_WIDTH_MINOR, 0, 1024, 0, 0); | ||
273 | input_mt_init_slots(input, 10, INPUT_MT_DIRECT); | ||
274 | |||
275 | input->name = "Surface3 SPI Capacitive TouchScreen"; | ||
276 | input->phys = "input/ts"; | ||
277 | input->id.bustype = BUS_SPI; | ||
278 | input->id.vendor = 0x045e; /* Microsoft */ | ||
279 | input->id.product = 0x0001; | ||
280 | input->id.version = 0x0000; | ||
281 | |||
282 | error = input_register_device(input); | ||
283 | if (error) { | ||
284 | dev_err(&data->spi->dev, | ||
285 | "Failed to register input device: %d", error); | ||
286 | return error; | ||
287 | } | ||
288 | |||
289 | return 0; | ||
290 | } | ||
291 | |||
292 | static int surface3_spi_create_pen_input(struct surface3_ts_data *data) | ||
293 | { | ||
294 | struct input_dev *input; | ||
295 | int error; | ||
296 | |||
297 | input = devm_input_allocate_device(&data->spi->dev); | ||
298 | if (!input) | ||
299 | return -ENOMEM; | ||
300 | |||
301 | data->pen_input_dev = input; | ||
302 | data->pen_tool = BTN_TOOL_PEN; | ||
303 | |||
304 | __set_bit(INPUT_PROP_DIRECT, input->propbit); | ||
305 | __set_bit(INPUT_PROP_POINTER, input->propbit); | ||
306 | input_set_abs_params(input, ABS_X, 0, 9600, 0, 0); | ||
307 | input_abs_set_res(input, ABS_X, 40); | ||
308 | input_set_abs_params(input, ABS_Y, 0, 7200, 0, 0); | ||
309 | input_abs_set_res(input, ABS_Y, 48); | ||
310 | input_set_abs_params(input, ABS_PRESSURE, 0, 1024, 0, 0); | ||
311 | input_set_capability(input, EV_KEY, BTN_TOUCH); | ||
312 | input_set_capability(input, EV_KEY, BTN_STYLUS); | ||
313 | input_set_capability(input, EV_KEY, BTN_TOOL_PEN); | ||
314 | input_set_capability(input, EV_KEY, BTN_TOOL_RUBBER); | ||
315 | |||
316 | input->name = "Surface3 SPI Pen Input"; | ||
317 | input->phys = "input/ts"; | ||
318 | input->id.bustype = BUS_SPI; | ||
319 | input->id.vendor = 0x045e; /* Microsoft */ | ||
320 | input->id.product = 0x0002; | ||
321 | input->id.version = 0x0000; | ||
322 | |||
323 | error = input_register_device(input); | ||
324 | if (error) { | ||
325 | dev_err(&data->spi->dev, | ||
326 | "Failed to register input device: %d", error); | ||
327 | return error; | ||
328 | } | ||
329 | |||
330 | return 0; | ||
331 | } | ||
332 | |||
333 | static int surface3_spi_probe(struct spi_device *spi) | ||
334 | { | ||
335 | struct surface3_ts_data *data; | ||
336 | int error; | ||
337 | |||
338 | /* Set up SPI*/ | ||
339 | spi->bits_per_word = 8; | ||
340 | spi->mode = SPI_MODE_0; | ||
341 | error = spi_setup(spi); | ||
342 | if (error) | ||
343 | return error; | ||
344 | |||
345 | data = devm_kzalloc(&spi->dev, sizeof(*data), GFP_KERNEL); | ||
346 | if (!data) | ||
347 | return -ENOMEM; | ||
348 | |||
349 | data->spi = spi; | ||
350 | spi_set_drvdata(spi, data); | ||
351 | |||
352 | error = surface3_spi_get_gpio_config(data); | ||
353 | if (error) | ||
354 | return error; | ||
355 | |||
356 | surface3_spi_power(data, true); | ||
357 | surface3_spi_power(data, false); | ||
358 | surface3_spi_power(data, true); | ||
359 | |||
360 | error = surface3_spi_create_touch_input(data); | ||
361 | if (error) | ||
362 | return error; | ||
363 | |||
364 | error = surface3_spi_create_pen_input(data); | ||
365 | if (error) | ||
366 | return error; | ||
367 | |||
368 | error = devm_request_threaded_irq(&spi->dev, spi->irq, | ||
369 | NULL, surface3_spi_irq_handler, | ||
370 | IRQF_ONESHOT, | ||
371 | "Surface3-irq", data); | ||
372 | if (error) | ||
373 | return error; | ||
374 | |||
375 | return 0; | ||
376 | } | ||
377 | |||
378 | static int __maybe_unused surface3_spi_suspend(struct device *dev) | ||
379 | { | ||
380 | struct spi_device *spi = to_spi_device(dev); | ||
381 | struct surface3_ts_data *data = spi_get_drvdata(spi); | ||
382 | |||
383 | disable_irq(data->spi->irq); | ||
384 | |||
385 | surface3_spi_power(data, false); | ||
386 | |||
387 | return 0; | ||
388 | } | ||
389 | |||
390 | static int __maybe_unused surface3_spi_resume(struct device *dev) | ||
391 | { | ||
392 | struct spi_device *spi = to_spi_device(dev); | ||
393 | struct surface3_ts_data *data = spi_get_drvdata(spi); | ||
394 | |||
395 | surface3_spi_power(data, true); | ||
396 | |||
397 | enable_irq(data->spi->irq); | ||
398 | |||
399 | return 0; | ||
400 | } | ||
401 | |||
402 | static SIMPLE_DEV_PM_OPS(surface3_spi_pm_ops, | ||
403 | surface3_spi_suspend, | ||
404 | surface3_spi_resume); | ||
405 | |||
406 | #ifdef CONFIG_ACPI | ||
407 | static const struct acpi_device_id surface3_spi_acpi_match[] = { | ||
408 | { "MSHW0037", 0 }, | ||
409 | { } | ||
410 | }; | ||
411 | MODULE_DEVICE_TABLE(acpi, surface3_spi_acpi_match); | ||
412 | #endif | ||
413 | |||
414 | static struct spi_driver surface3_spi_driver = { | ||
415 | .driver = { | ||
416 | .name = "Surface3-spi", | ||
417 | .acpi_match_table = ACPI_PTR(surface3_spi_acpi_match), | ||
418 | .pm = &surface3_spi_pm_ops, | ||
419 | }, | ||
420 | .probe = surface3_spi_probe, | ||
421 | }; | ||
422 | |||
423 | module_spi_driver(surface3_spi_driver); | ||
424 | |||
425 | MODULE_AUTHOR("Benjamin Tissoires <benjamin.tissoires@gmail.com>"); | ||
426 | MODULE_DESCRIPTION("Surface 3 SPI touchscreen driver"); | ||
427 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/input/touchscreen/ti_am335x_tsc.c b/drivers/input/touchscreen/ti_am335x_tsc.c index 8b3f15ca7725..7953381d939a 100644 --- a/drivers/input/touchscreen/ti_am335x_tsc.c +++ b/drivers/input/touchscreen/ti_am335x_tsc.c | |||
@@ -406,7 +406,7 @@ static int titsc_probe(struct platform_device *pdev) | |||
406 | int err; | 406 | int err; |
407 | 407 | ||
408 | /* Allocate memory for device */ | 408 | /* Allocate memory for device */ |
409 | ts_dev = kzalloc(sizeof(struct titsc), GFP_KERNEL); | 409 | ts_dev = kzalloc(sizeof(*ts_dev), GFP_KERNEL); |
410 | input_dev = input_allocate_device(); | 410 | input_dev = input_allocate_device(); |
411 | if (!ts_dev || !input_dev) { | 411 | if (!ts_dev || !input_dev) { |
412 | dev_err(&pdev->dev, "failed to allocate memory.\n"); | 412 | dev_err(&pdev->dev, "failed to allocate memory.\n"); |
diff --git a/drivers/input/touchscreen/tsc200x-core.c b/drivers/input/touchscreen/tsc200x-core.c index dfa7f1c4f545..b7059ed8872e 100644 --- a/drivers/input/touchscreen/tsc200x-core.c +++ b/drivers/input/touchscreen/tsc200x-core.c | |||
@@ -568,7 +568,7 @@ int tsc200x_probe(struct device *dev, int irq, const struct input_id *tsc_id, | |||
568 | input_set_abs_params(input_dev, ABS_PRESSURE, 0, max_p, fudge_p, 0); | 568 | input_set_abs_params(input_dev, ABS_PRESSURE, 0, max_p, fudge_p, 0); |
569 | 569 | ||
570 | if (np) | 570 | if (np) |
571 | touchscreen_parse_properties(input_dev, false); | 571 | touchscreen_parse_properties(input_dev, false, NULL); |
572 | 572 | ||
573 | input_dev->open = tsc200x_open; | 573 | input_dev->open = tsc200x_open; |
574 | input_dev->close = tsc200x_close; | 574 | input_dev->close = tsc200x_close; |
diff --git a/drivers/input/touchscreen/wacom_w8001.c b/drivers/input/touchscreen/wacom_w8001.c index b6fc4bde79de..85e95725d0df 100644 --- a/drivers/input/touchscreen/wacom_w8001.c +++ b/drivers/input/touchscreen/wacom_w8001.c | |||
@@ -518,13 +518,21 @@ static int w8001_setup_touch(struct w8001 *w8001, char *basename, | |||
518 | w8001->pktlen = W8001_PKTLEN_TOUCH2FG; | 518 | w8001->pktlen = W8001_PKTLEN_TOUCH2FG; |
519 | 519 | ||
520 | __set_bit(BTN_TOOL_DOUBLETAP, dev->keybit); | 520 | __set_bit(BTN_TOOL_DOUBLETAP, dev->keybit); |
521 | input_mt_init_slots(dev, 2, 0); | 521 | error = input_mt_init_slots(dev, 2, 0); |
522 | if (error) { | ||
523 | dev_err(&w8001->serio->dev, | ||
524 | "failed to initialize MT slots: %d\n", error); | ||
525 | return error; | ||
526 | } | ||
527 | |||
522 | input_set_abs_params(dev, ABS_MT_POSITION_X, | 528 | input_set_abs_params(dev, ABS_MT_POSITION_X, |
523 | 0, touch.x, 0, 0); | 529 | 0, touch.x, 0, 0); |
524 | input_set_abs_params(dev, ABS_MT_POSITION_Y, | 530 | input_set_abs_params(dev, ABS_MT_POSITION_Y, |
525 | 0, touch.y, 0, 0); | 531 | 0, touch.y, 0, 0); |
526 | input_set_abs_params(dev, ABS_MT_TOOL_TYPE, | 532 | input_set_abs_params(dev, ABS_MT_TOOL_TYPE, |
527 | 0, MT_TOOL_MAX, 0, 0); | 533 | 0, MT_TOOL_MAX, 0, 0); |
534 | input_abs_set_res(dev, ABS_MT_POSITION_X, touch.panel_res); | ||
535 | input_abs_set_res(dev, ABS_MT_POSITION_Y, touch.panel_res); | ||
528 | 536 | ||
529 | strlcat(basename, " 2FG", basename_sz); | 537 | strlcat(basename, " 2FG", basename_sz); |
530 | if (w8001->max_pen_x && w8001->max_pen_y) | 538 | if (w8001->max_pen_x && w8001->max_pen_y) |
diff --git a/include/linux/input.h b/include/linux/input.h index 1e967694e9a5..a65e3b24fb18 100644 --- a/include/linux/input.h +++ b/include/linux/input.h | |||
@@ -95,7 +95,7 @@ struct input_value { | |||
95 | * @grab: input handle that currently has the device grabbed (via | 95 | * @grab: input handle that currently has the device grabbed (via |
96 | * EVIOCGRAB ioctl). When a handle grabs a device it becomes sole | 96 | * EVIOCGRAB ioctl). When a handle grabs a device it becomes sole |
97 | * recipient for all input events coming from the device | 97 | * recipient for all input events coming from the device |
98 | * @event_lock: this spinlock is is taken when input core receives | 98 | * @event_lock: this spinlock is taken when input core receives |
99 | * and processes a new event for the device (in input_event()). | 99 | * and processes a new event for the device (in input_event()). |
100 | * Code that accesses and/or modifies parameters of a device | 100 | * Code that accesses and/or modifies parameters of a device |
101 | * (such as keymap or absmin, absmax, absfuzz, etc.) after device | 101 | * (such as keymap or absmin, absmax, absfuzz, etc.) after device |
diff --git a/include/linux/input/touchscreen.h b/include/linux/input/touchscreen.h index c91e1376132b..09d22ccb9e41 100644 --- a/include/linux/input/touchscreen.h +++ b/include/linux/input/touchscreen.h | |||
@@ -10,7 +10,26 @@ | |||
10 | #define _TOUCHSCREEN_H | 10 | #define _TOUCHSCREEN_H |
11 | 11 | ||
12 | struct input_dev; | 12 | struct input_dev; |
13 | struct input_mt_pos; | ||
13 | 14 | ||
14 | void touchscreen_parse_properties(struct input_dev *dev, bool multitouch); | 15 | struct touchscreen_properties { |
16 | unsigned int max_x; | ||
17 | unsigned int max_y; | ||
18 | bool invert_x; | ||
19 | bool invert_y; | ||
20 | bool swap_x_y; | ||
21 | }; | ||
22 | |||
23 | void touchscreen_parse_properties(struct input_dev *input, bool multitouch, | ||
24 | struct touchscreen_properties *prop); | ||
25 | |||
26 | void touchscreen_set_mt_pos(struct input_mt_pos *pos, | ||
27 | const struct touchscreen_properties *prop, | ||
28 | unsigned int x, unsigned int y); | ||
29 | |||
30 | void touchscreen_report_pos(struct input_dev *input, | ||
31 | const struct touchscreen_properties *prop, | ||
32 | unsigned int x, unsigned int y, | ||
33 | bool multitouch); | ||
15 | 34 | ||
16 | #endif | 35 | #endif |