diff options
61 files changed, 7957 insertions, 1302 deletions
diff --git a/Documentation/ABI/testing/sysfs-driver-input-axp-pek b/Documentation/ABI/testing/sysfs-driver-input-axp-pek new file mode 100644 index 000000000000..a5e671b9fa79 --- /dev/null +++ b/Documentation/ABI/testing/sysfs-driver-input-axp-pek | |||
@@ -0,0 +1,11 @@ | |||
1 | What: /sys/class/input/input(x)/device/startup | ||
2 | Date: March 2014 | ||
3 | Contact: Carlo Caione <carlo@caione.org> | ||
4 | Description: Startup time in us. Board is powered on if the button is pressed | ||
5 | for more than <startup_time> | ||
6 | |||
7 | What: /sys/class/input/input(x)/device/shutdown | ||
8 | Date: March 2014 | ||
9 | Contact: Carlo Caione <carlo@caione.org> | ||
10 | Description: Shutdown time in us. Board is powered off if the button is pressed | ||
11 | for more than <shutdown_time> | ||
diff --git a/Documentation/devicetree/bindings/input/e3x0-button.txt b/Documentation/devicetree/bindings/input/e3x0-button.txt new file mode 100644 index 000000000000..751665e8e47a --- /dev/null +++ b/Documentation/devicetree/bindings/input/e3x0-button.txt | |||
@@ -0,0 +1,25 @@ | |||
1 | National Instruments Ettus Research USRP E3x0 button driver | ||
2 | |||
3 | This module is part of the NI Ettus Research USRP E3x0 SDR. | ||
4 | |||
5 | This module provides a simple power button event via two interrupts. | ||
6 | |||
7 | Required properties: | ||
8 | - compatible: should be one of the following | ||
9 | - "ettus,e3x0-button": For devices such as the NI Ettus Research USRP E3x0 | ||
10 | - interrupt-parent: | ||
11 | - a phandle to the interrupt controller that it is attached to. | ||
12 | - interrupts: should be one of the following | ||
13 | - <0 30 1>, <0 31 1>: For devices such as the NI Ettus Research USRP E3x0 | ||
14 | - interrupt-names: should be one of the following | ||
15 | - "press", "release": For devices such as the NI Ettus Research USRP E3x0 | ||
16 | |||
17 | Note: Interrupt numbers might vary depending on the FPGA configuration. | ||
18 | |||
19 | Example: | ||
20 | button { | ||
21 | compatible = "ettus,e3x0-button"; | ||
22 | interrupt-parent = <&intc>; | ||
23 | interrupts = <0 30 1>, <0 31 1>; | ||
24 | interrupt-names = "press", "release"; | ||
25 | } | ||
diff --git a/Documentation/devicetree/bindings/input/regulator-haptic.txt b/Documentation/devicetree/bindings/input/regulator-haptic.txt new file mode 100644 index 000000000000..3ed1c7eb2f97 --- /dev/null +++ b/Documentation/devicetree/bindings/input/regulator-haptic.txt | |||
@@ -0,0 +1,21 @@ | |||
1 | * Regulator Haptic Device Tree Bindings | ||
2 | |||
3 | Required Properties: | ||
4 | - compatible : Should be "regulator-haptic" | ||
5 | - haptic-supply : Power supply to the haptic motor. | ||
6 | [*] refer Documentation/devicetree/bindings/regulator/regulator.txt | ||
7 | |||
8 | - max-microvolt : The maximum voltage value supplied to the haptic motor. | ||
9 | [The unit of the voltage is a micro] | ||
10 | |||
11 | - min-microvolt : The minimum voltage value supplied to the haptic motor. | ||
12 | [The unit of the voltage is a micro] | ||
13 | |||
14 | Example: | ||
15 | |||
16 | haptics { | ||
17 | compatible = "regulator-haptic"; | ||
18 | haptic-supply = <&motor_regulator>; | ||
19 | max-microvolt = <2700000>; | ||
20 | min-microvolt = <1100000>; | ||
21 | }; | ||
diff --git a/Documentation/devicetree/bindings/input/sun4i-lradc-keys.txt b/Documentation/devicetree/bindings/input/sun4i-lradc-keys.txt new file mode 100644 index 000000000000..b9c32f6fd687 --- /dev/null +++ b/Documentation/devicetree/bindings/input/sun4i-lradc-keys.txt | |||
@@ -0,0 +1,62 @@ | |||
1 | Allwinner sun4i low res adc attached tablet keys | ||
2 | ------------------------------------------------ | ||
3 | |||
4 | Required properties: | ||
5 | - compatible: "allwinner,sun4i-a10-lradc-keys" | ||
6 | - reg: mmio address range of the chip | ||
7 | - interrupts: interrupt to which the chip is connected | ||
8 | - vref-supply: powersupply for the lradc reference voltage | ||
9 | |||
10 | Each key is represented as a sub-node of "allwinner,sun4i-a10-lradc-keys": | ||
11 | |||
12 | Required subnode-properties: | ||
13 | - label: Descriptive name of the key. | ||
14 | - linux,code: Keycode to emit. | ||
15 | - channel: Channel this key is attached to, mut be 0 or 1. | ||
16 | - voltage: Voltage in µV at lradc input when this key is pressed. | ||
17 | |||
18 | Example: | ||
19 | |||
20 | #include <dt-bindings/input/input.h> | ||
21 | |||
22 | lradc: lradc@01c22800 { | ||
23 | compatible = "allwinner,sun4i-a10-lradc-keys"; | ||
24 | reg = <0x01c22800 0x100>; | ||
25 | interrupts = <31>; | ||
26 | vref-supply = <®_vcc3v0>; | ||
27 | |||
28 | button@191 { | ||
29 | label = "Volume Up"; | ||
30 | linux,code = <KEY_VOLUMEUP>; | ||
31 | channel = <0>; | ||
32 | voltage = <191274>; | ||
33 | }; | ||
34 | |||
35 | button@392 { | ||
36 | label = "Volume Down"; | ||
37 | linux,code = <KEY_VOLUMEDOWN>; | ||
38 | channel = <0>; | ||
39 | voltage = <392644>; | ||
40 | }; | ||
41 | |||
42 | button@601 { | ||
43 | label = "Menu"; | ||
44 | linux,code = <KEY_MENU>; | ||
45 | channel = <0>; | ||
46 | voltage = <601151>; | ||
47 | }; | ||
48 | |||
49 | button@795 { | ||
50 | label = "Enter"; | ||
51 | linux,code = <KEY_ENTER>; | ||
52 | channel = <0>; | ||
53 | voltage = <795090>; | ||
54 | }; | ||
55 | |||
56 | button@987 { | ||
57 | label = "Home"; | ||
58 | linux,code = <KEY_HOMEPAGE>; | ||
59 | channel = <0>; | ||
60 | voltage = <987387>; | ||
61 | }; | ||
62 | }; | ||
diff --git a/Documentation/devicetree/bindings/input/touchscreen/sun4i.txt b/Documentation/devicetree/bindings/input/touchscreen/sun4i.txt index aef57791f40b..433332d3b2ba 100644 --- a/Documentation/devicetree/bindings/input/touchscreen/sun4i.txt +++ b/Documentation/devicetree/bindings/input/touchscreen/sun4i.txt | |||
@@ -2,9 +2,10 @@ sun4i resistive touchscreen controller | |||
2 | -------------------------------------- | 2 | -------------------------------------- |
3 | 3 | ||
4 | Required properties: | 4 | Required properties: |
5 | - compatible: "allwinner,sun4i-a10-ts" | 5 | - compatible: "allwinner,sun4i-a10-ts" or "allwinner,sun6i-a31-ts" |
6 | - reg: mmio address range of the chip | 6 | - reg: mmio address range of the chip |
7 | - interrupts: interrupt to which the chip is connected | 7 | - interrupts: interrupt to which the chip is connected |
8 | - #thermal-sensor-cells: shall be 0 | ||
8 | 9 | ||
9 | Optional properties: | 10 | Optional properties: |
10 | - allwinner,ts-attached: boolean indicating that an actual touchscreen is | 11 | - allwinner,ts-attached: boolean indicating that an actual touchscreen is |
@@ -17,4 +18,5 @@ Example: | |||
17 | reg = <0x01c25000 0x100>; | 18 | reg = <0x01c25000 0x100>; |
18 | interrupts = <29>; | 19 | interrupts = <29>; |
19 | allwinner,ts-attached; | 20 | allwinner,ts-attached; |
21 | #thermal-sensor-cells = <0>; | ||
20 | }; | 22 | }; |
diff --git a/Documentation/devicetree/bindings/input/touchscreen/ti-tsc-adc.txt b/Documentation/devicetree/bindings/input/touchscreen/ti-tsc-adc.txt index 878549ba814d..6c4fb34823d3 100644 --- a/Documentation/devicetree/bindings/input/touchscreen/ti-tsc-adc.txt +++ b/Documentation/devicetree/bindings/input/touchscreen/ti-tsc-adc.txt | |||
@@ -28,6 +28,20 @@ Required properties: | |||
28 | ti,adc-channels: List of analog inputs available for ADC. | 28 | ti,adc-channels: List of analog inputs available for ADC. |
29 | AIN0 = 0, AIN1 = 1 and so on till AIN7 = 7. | 29 | AIN0 = 0, AIN1 = 1 and so on till AIN7 = 7. |
30 | 30 | ||
31 | Optional properties: | ||
32 | - child "tsc" | ||
33 | ti,charge-delay: Length of touch screen charge delay step in terms of | ||
34 | ADC clock cycles. Charge delay value should be large | ||
35 | in order to avoid false pen-up events. This value | ||
36 | effects the overall sampling speed, hence need to be | ||
37 | kept as low as possible, while avoiding false pen-up | ||
38 | event. Start from a lower value, say 0x400, and | ||
39 | increase value until false pen-up events are avoided. | ||
40 | The pen-up detection happens immediately after the | ||
41 | charge step, so this does in fact function as a | ||
42 | hardware knob for adjusting the amount of "settling | ||
43 | time". | ||
44 | |||
31 | Example: | 45 | Example: |
32 | tscadc: tscadc@44e0d000 { | 46 | tscadc: tscadc@44e0d000 { |
33 | compatible = "ti,am3359-tscadc"; | 47 | compatible = "ti,am3359-tscadc"; |
@@ -36,6 +50,7 @@ Example: | |||
36 | ti,x-plate-resistance = <200>; | 50 | ti,x-plate-resistance = <200>; |
37 | ti,coordiante-readouts = <5>; | 51 | ti,coordiante-readouts = <5>; |
38 | ti,wire-config = <0x00 0x11 0x22 0x33>; | 52 | ti,wire-config = <0x00 0x11 0x22 0x33>; |
53 | ti,charge-delay = <0x400>; | ||
39 | }; | 54 | }; |
40 | 55 | ||
41 | adc { | 56 | adc { |
diff --git a/Documentation/devicetree/bindings/input/tps65218-pwrbutton.txt b/Documentation/devicetree/bindings/input/tps65218-pwrbutton.txt new file mode 100644 index 000000000000..e30e0b93f2b3 --- /dev/null +++ b/Documentation/devicetree/bindings/input/tps65218-pwrbutton.txt | |||
@@ -0,0 +1,17 @@ | |||
1 | Texas Instruments TPS65218 power button | ||
2 | |||
3 | This driver provides a simple power button event via an Interrupt. | ||
4 | |||
5 | Required properties: | ||
6 | - compatible: should be "ti,tps65218-pwrbutton" | ||
7 | - interrupts: should be one of the following | ||
8 | - <3 IRQ_TYPE_EDGE_BOTH>: For controllers compatible with tps65218 | ||
9 | |||
10 | Example: | ||
11 | |||
12 | &tps { | ||
13 | power-button { | ||
14 | compatible = "ti,tps65218-pwrbutton"; | ||
15 | interrupts = <3 IRQ_TYPE_EDGE_BOTH>; | ||
16 | }; | ||
17 | }; | ||
diff --git a/Documentation/devicetree/bindings/serio/allwinner,sun4i-ps2.txt b/Documentation/devicetree/bindings/serio/allwinner,sun4i-ps2.txt new file mode 100644 index 000000000000..362a76925bcd --- /dev/null +++ b/Documentation/devicetree/bindings/serio/allwinner,sun4i-ps2.txt | |||
@@ -0,0 +1,23 @@ | |||
1 | * Device tree bindings for Allwinner A10, A20 PS2 host controller | ||
2 | |||
3 | A20 PS2 is dual role controller (PS2 host and PS2 device). These bindings are | ||
4 | for PS2 A10/A20 host controller. IBM compliant IBM PS2 and AT-compatible keyboard | ||
5 | and mouse can be connected. | ||
6 | |||
7 | Required properties: | ||
8 | |||
9 | - reg : Offset and length of the register set for the device. | ||
10 | - compatible : Should be as of the following: | ||
11 | - "allwinner,sun4i-a10-ps2" | ||
12 | - interrupts : The interrupt line connected to the PS2. | ||
13 | - clocks : The gate clk connected to the PS2. | ||
14 | |||
15 | |||
16 | Example: | ||
17 | ps20: ps2@0x01c2a000 { | ||
18 | compatible = "allwinner,sun4i-a10-ps2"; | ||
19 | reg = <0x01c2a000 0x400>; | ||
20 | interrupts = <0 62 4>; | ||
21 | clocks = <&apb1_gates 6>; | ||
22 | status = "disabled"; | ||
23 | }; | ||
diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt index d443279c95dc..96a17541391e 100644 --- a/Documentation/devicetree/bindings/vendor-prefixes.txt +++ b/Documentation/devicetree/bindings/vendor-prefixes.txt | |||
@@ -54,6 +54,7 @@ epcos EPCOS AG | |||
54 | epfl Ecole Polytechnique Fédérale de Lausanne | 54 | epfl Ecole Polytechnique Fédérale de Lausanne |
55 | epson Seiko Epson Corp. | 55 | epson Seiko Epson Corp. |
56 | est ESTeem Wireless Modems | 56 | est ESTeem Wireless Modems |
57 | ettus NI Ettus Research | ||
57 | eukrea Eukréa Electromatique | 58 | eukrea Eukréa Electromatique |
58 | everest Everest Semiconductor Co. Ltd. | 59 | everest Everest Semiconductor Co. Ltd. |
59 | excito Excito | 60 | excito Excito |
diff --git a/MAINTAINERS b/MAINTAINERS index 249498844a43..9c632548d3bd 100644 --- a/MAINTAINERS +++ b/MAINTAINERS | |||
@@ -3479,6 +3479,14 @@ M: "Maciej W. Rozycki" <macro@linux-mips.org> | |||
3479 | S: Maintained | 3479 | S: Maintained |
3480 | F: drivers/tty/serial/dz.* | 3480 | F: drivers/tty/serial/dz.* |
3481 | 3481 | ||
3482 | E3X0 POWER BUTTON DRIVER | ||
3483 | M: Moritz Fischer <moritz.fischer@ettus.com> | ||
3484 | L: usrp-users@lists.ettus.com | ||
3485 | W: http://www.ettus.com | ||
3486 | S: Supported | ||
3487 | F: drivers/input/misc/e3x0-button.c | ||
3488 | F: Documentation/devicetree/bindings/input/e3x0-button.txt | ||
3489 | |||
3482 | E4000 MEDIA DRIVER | 3490 | E4000 MEDIA DRIVER |
3483 | M: Antti Palosaari <crope@iki.fi> | 3491 | M: Antti Palosaari <crope@iki.fi> |
3484 | L: linux-media@vger.kernel.org | 3492 | L: linux-media@vger.kernel.org |
@@ -9281,6 +9289,13 @@ F: arch/m68k/sun3*/ | |||
9281 | F: arch/m68k/include/asm/sun3* | 9289 | F: arch/m68k/include/asm/sun3* |
9282 | F: drivers/net/ethernet/i825xx/sun3* | 9290 | F: drivers/net/ethernet/i825xx/sun3* |
9283 | 9291 | ||
9292 | SUN4I LOW RES ADC ATTACHED TABLET KEYS DRIVER | ||
9293 | M: Hans de Goede <hdegoede@redhat.com> | ||
9294 | L: linux-input@vger.kernel.org | ||
9295 | S: Maintained | ||
9296 | F: Documentation/devicetree/bindings/input/sun4i-lradc-keys.txt | ||
9297 | F: drivers/input/keyboard/sun4i-lradc-keys.c | ||
9298 | |||
9284 | SUNDANCE NETWORK DRIVER | 9299 | SUNDANCE NETWORK DRIVER |
9285 | M: Denis Kirjanov <kda@linux-powerpc.org> | 9300 | M: Denis Kirjanov <kda@linux-powerpc.org> |
9286 | L: netdev@vger.kernel.org | 9301 | L: netdev@vger.kernel.org |
diff --git a/arch/arm/boot/dts/am335x-evm.dts b/arch/arm/boot/dts/am335x-evm.dts index 54f118c08db8..66342515df20 100644 --- a/arch/arm/boot/dts/am335x-evm.dts +++ b/arch/arm/boot/dts/am335x-evm.dts | |||
@@ -648,6 +648,7 @@ | |||
648 | ti,x-plate-resistance = <200>; | 648 | ti,x-plate-resistance = <200>; |
649 | ti,coordinate-readouts = <5>; | 649 | ti,coordinate-readouts = <5>; |
650 | ti,wire-config = <0x00 0x11 0x22 0x33>; | 650 | ti,wire-config = <0x00 0x11 0x22 0x33>; |
651 | ti,charge-delay = <0x400>; | ||
651 | }; | 652 | }; |
652 | 653 | ||
653 | adc { | 654 | adc { |
diff --git a/drivers/iio/adc/ti_am335x_adc.c b/drivers/iio/adc/ti_am335x_adc.c index b730864731e8..adba23246474 100644 --- a/drivers/iio/adc/ti_am335x_adc.c +++ b/drivers/iio/adc/ti_am335x_adc.c | |||
@@ -86,19 +86,18 @@ static void tiadc_step_config(struct iio_dev *indio_dev) | |||
86 | { | 86 | { |
87 | struct tiadc_device *adc_dev = iio_priv(indio_dev); | 87 | struct tiadc_device *adc_dev = iio_priv(indio_dev); |
88 | unsigned int stepconfig; | 88 | unsigned int stepconfig; |
89 | int i, steps; | 89 | int i, steps = 0; |
90 | 90 | ||
91 | /* | 91 | /* |
92 | * There are 16 configurable steps and 8 analog input | 92 | * There are 16 configurable steps and 8 analog input |
93 | * lines available which are shared between Touchscreen and ADC. | 93 | * lines available which are shared between Touchscreen and ADC. |
94 | * | 94 | * |
95 | * Steps backwards i.e. from 16 towards 0 are used by ADC | 95 | * Steps forwards i.e. from 0 towards 16 are used by ADC |
96 | * depending on number of input lines needed. | 96 | * depending on number of input lines needed. |
97 | * Channel would represent which analog input | 97 | * Channel would represent which analog input |
98 | * needs to be given to ADC to digitalize data. | 98 | * needs to be given to ADC to digitalize data. |
99 | */ | 99 | */ |
100 | 100 | ||
101 | steps = TOTAL_STEPS - adc_dev->channels; | ||
102 | if (iio_buffer_enabled(indio_dev)) | 101 | if (iio_buffer_enabled(indio_dev)) |
103 | stepconfig = STEPCONFIG_AVG_16 | STEPCONFIG_FIFO1 | 102 | stepconfig = STEPCONFIG_AVG_16 | STEPCONFIG_FIFO1 |
104 | | STEPCONFIG_MODE_SWCNT; | 103 | | STEPCONFIG_MODE_SWCNT; |
diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c index 18d4b2c8fe55..a18f41b89b6a 100644 --- a/drivers/input/evdev.c +++ b/drivers/input/evdev.c | |||
@@ -62,26 +62,6 @@ struct evdev_client { | |||
62 | struct input_event buffer[]; | 62 | struct input_event buffer[]; |
63 | }; | 63 | }; |
64 | 64 | ||
65 | static int evdev_set_clk_type(struct evdev_client *client, unsigned int clkid) | ||
66 | { | ||
67 | switch (clkid) { | ||
68 | |||
69 | case CLOCK_REALTIME: | ||
70 | client->clk_type = EV_CLK_REAL; | ||
71 | break; | ||
72 | case CLOCK_MONOTONIC: | ||
73 | client->clk_type = EV_CLK_MONO; | ||
74 | break; | ||
75 | case CLOCK_BOOTTIME: | ||
76 | client->clk_type = EV_CLK_BOOT; | ||
77 | break; | ||
78 | default: | ||
79 | return -EINVAL; | ||
80 | } | ||
81 | |||
82 | return 0; | ||
83 | } | ||
84 | |||
85 | /* flush queued events of type @type, caller must hold client->buffer_lock */ | 65 | /* flush queued events of type @type, caller must hold client->buffer_lock */ |
86 | static void __evdev_flush_queue(struct evdev_client *client, unsigned int type) | 66 | static void __evdev_flush_queue(struct evdev_client *client, unsigned int type) |
87 | { | 67 | { |
@@ -128,10 +108,8 @@ static void __evdev_flush_queue(struct evdev_client *client, unsigned int type) | |||
128 | client->head = head; | 108 | client->head = head; |
129 | } | 109 | } |
130 | 110 | ||
131 | /* queue SYN_DROPPED event */ | 111 | static void __evdev_queue_syn_dropped(struct evdev_client *client) |
132 | static void evdev_queue_syn_dropped(struct evdev_client *client) | ||
133 | { | 112 | { |
134 | unsigned long flags; | ||
135 | struct input_event ev; | 113 | struct input_event ev; |
136 | ktime_t time; | 114 | ktime_t time; |
137 | 115 | ||
@@ -146,8 +124,6 @@ static void evdev_queue_syn_dropped(struct evdev_client *client) | |||
146 | ev.code = SYN_DROPPED; | 124 | ev.code = SYN_DROPPED; |
147 | ev.value = 0; | 125 | ev.value = 0; |
148 | 126 | ||
149 | spin_lock_irqsave(&client->buffer_lock, flags); | ||
150 | |||
151 | client->buffer[client->head++] = ev; | 127 | client->buffer[client->head++] = ev; |
152 | client->head &= client->bufsize - 1; | 128 | client->head &= client->bufsize - 1; |
153 | 129 | ||
@@ -156,8 +132,53 @@ static void evdev_queue_syn_dropped(struct evdev_client *client) | |||
156 | client->tail = (client->head - 1) & (client->bufsize - 1); | 132 | client->tail = (client->head - 1) & (client->bufsize - 1); |
157 | client->packet_head = client->tail; | 133 | client->packet_head = client->tail; |
158 | } | 134 | } |
135 | } | ||
136 | |||
137 | static void evdev_queue_syn_dropped(struct evdev_client *client) | ||
138 | { | ||
139 | unsigned long flags; | ||
140 | |||
141 | spin_lock_irqsave(&client->buffer_lock, flags); | ||
142 | __evdev_queue_syn_dropped(client); | ||
143 | spin_unlock_irqrestore(&client->buffer_lock, flags); | ||
144 | } | ||
145 | |||
146 | static int evdev_set_clk_type(struct evdev_client *client, unsigned int clkid) | ||
147 | { | ||
148 | unsigned long flags; | ||
149 | |||
150 | if (client->clk_type == clkid) | ||
151 | return 0; | ||
152 | |||
153 | switch (clkid) { | ||
154 | |||
155 | case CLOCK_REALTIME: | ||
156 | client->clk_type = EV_CLK_REAL; | ||
157 | break; | ||
158 | case CLOCK_MONOTONIC: | ||
159 | client->clk_type = EV_CLK_MONO; | ||
160 | break; | ||
161 | case CLOCK_BOOTTIME: | ||
162 | client->clk_type = EV_CLK_BOOT; | ||
163 | break; | ||
164 | default: | ||
165 | return -EINVAL; | ||
166 | } | ||
167 | |||
168 | /* | ||
169 | * Flush pending events and queue SYN_DROPPED event, | ||
170 | * but only if the queue is not empty. | ||
171 | */ | ||
172 | spin_lock_irqsave(&client->buffer_lock, flags); | ||
173 | |||
174 | if (client->head != client->tail) { | ||
175 | client->packet_head = client->head = client->tail; | ||
176 | __evdev_queue_syn_dropped(client); | ||
177 | } | ||
159 | 178 | ||
160 | spin_unlock_irqrestore(&client->buffer_lock, flags); | 179 | spin_unlock_irqrestore(&client->buffer_lock, flags); |
180 | |||
181 | return 0; | ||
161 | } | 182 | } |
162 | 183 | ||
163 | static void __pass_event(struct evdev_client *client, | 184 | static void __pass_event(struct evdev_client *client, |
diff --git a/drivers/input/input-mt.c b/drivers/input/input-mt.c index fbe29fcb15c5..cb150a1dbaff 100644 --- a/drivers/input/input-mt.c +++ b/drivers/input/input-mt.c | |||
@@ -293,7 +293,7 @@ void input_mt_sync_frame(struct input_dev *dev) | |||
293 | } | 293 | } |
294 | EXPORT_SYMBOL(input_mt_sync_frame); | 294 | EXPORT_SYMBOL(input_mt_sync_frame); |
295 | 295 | ||
296 | static int adjust_dual(int *begin, int step, int *end, int eq) | 296 | static int adjust_dual(int *begin, int step, int *end, int eq, int mu) |
297 | { | 297 | { |
298 | int f, *p, s, c; | 298 | int f, *p, s, c; |
299 | 299 | ||
@@ -311,9 +311,10 @@ static int adjust_dual(int *begin, int step, int *end, int eq) | |||
311 | s = *p; | 311 | s = *p; |
312 | 312 | ||
313 | c = (f + s + 1) / 2; | 313 | c = (f + s + 1) / 2; |
314 | if (c == 0 || (c > 0 && !eq)) | 314 | if (c == 0 || (c > mu && (!eq || mu > 0))) |
315 | return 0; | 315 | return 0; |
316 | if (s < 0) | 316 | /* Improve convergence for positive matrices by penalizing overcovers */ |
317 | if (s < 0 && mu <= 0) | ||
317 | c *= 2; | 318 | c *= 2; |
318 | 319 | ||
319 | for (p = begin; p != end; p += step) | 320 | for (p = begin; p != end; p += step) |
@@ -322,23 +323,24 @@ static int adjust_dual(int *begin, int step, int *end, int eq) | |||
322 | return (c < s && s <= 0) || (f >= 0 && f < c); | 323 | return (c < s && s <= 0) || (f >= 0 && f < c); |
323 | } | 324 | } |
324 | 325 | ||
325 | static void find_reduced_matrix(int *w, int nr, int nc, int nrc) | 326 | static void find_reduced_matrix(int *w, int nr, int nc, int nrc, int mu) |
326 | { | 327 | { |
327 | int i, k, sum; | 328 | int i, k, sum; |
328 | 329 | ||
329 | for (k = 0; k < nrc; k++) { | 330 | for (k = 0; k < nrc; k++) { |
330 | for (i = 0; i < nr; i++) | 331 | for (i = 0; i < nr; i++) |
331 | adjust_dual(w + i, nr, w + i + nrc, nr <= nc); | 332 | adjust_dual(w + i, nr, w + i + nrc, nr <= nc, mu); |
332 | sum = 0; | 333 | sum = 0; |
333 | for (i = 0; i < nrc; i += nr) | 334 | for (i = 0; i < nrc; i += nr) |
334 | sum += adjust_dual(w + i, 1, w + i + nr, nc <= nr); | 335 | sum += adjust_dual(w + i, 1, w + i + nr, nc <= nr, mu); |
335 | if (!sum) | 336 | if (!sum) |
336 | break; | 337 | break; |
337 | } | 338 | } |
338 | } | 339 | } |
339 | 340 | ||
340 | static int input_mt_set_matrix(struct input_mt *mt, | 341 | static int input_mt_set_matrix(struct input_mt *mt, |
341 | const struct input_mt_pos *pos, int num_pos) | 342 | const struct input_mt_pos *pos, int num_pos, |
343 | int mu) | ||
342 | { | 344 | { |
343 | const struct input_mt_pos *p; | 345 | const struct input_mt_pos *p; |
344 | struct input_mt_slot *s; | 346 | struct input_mt_slot *s; |
@@ -352,7 +354,7 @@ static int input_mt_set_matrix(struct input_mt *mt, | |||
352 | y = input_mt_get_value(s, ABS_MT_POSITION_Y); | 354 | y = input_mt_get_value(s, ABS_MT_POSITION_Y); |
353 | for (p = pos; p != pos + num_pos; p++) { | 355 | for (p = pos; p != pos + num_pos; p++) { |
354 | int dx = x - p->x, dy = y - p->y; | 356 | int dx = x - p->x, dy = y - p->y; |
355 | *w++ = dx * dx + dy * dy; | 357 | *w++ = dx * dx + dy * dy - mu; |
356 | } | 358 | } |
357 | } | 359 | } |
358 | 360 | ||
@@ -393,17 +395,24 @@ static void input_mt_set_slots(struct input_mt *mt, | |||
393 | * @slots: the slot assignment to be filled | 395 | * @slots: the slot assignment to be filled |
394 | * @pos: the position array to match | 396 | * @pos: the position array to match |
395 | * @num_pos: number of positions | 397 | * @num_pos: number of positions |
398 | * @dmax: maximum ABS_MT_POSITION displacement (zero for infinite) | ||
396 | * | 399 | * |
397 | * Performs a best match against the current contacts and returns | 400 | * Performs a best match against the current contacts and returns |
398 | * the slot assignment list. New contacts are assigned to unused | 401 | * the slot assignment list. New contacts are assigned to unused |
399 | * slots. | 402 | * slots. |
400 | * | 403 | * |
404 | * The assignments are balanced so that all coordinate displacements are | ||
405 | * below the euclidian distance dmax. If no such assignment can be found, | ||
406 | * some contacts are assigned to unused slots. | ||
407 | * | ||
401 | * Returns zero on success, or negative error in case of failure. | 408 | * Returns zero on success, or negative error in case of failure. |
402 | */ | 409 | */ |
403 | int input_mt_assign_slots(struct input_dev *dev, int *slots, | 410 | int input_mt_assign_slots(struct input_dev *dev, int *slots, |
404 | const struct input_mt_pos *pos, int num_pos) | 411 | const struct input_mt_pos *pos, int num_pos, |
412 | int dmax) | ||
405 | { | 413 | { |
406 | struct input_mt *mt = dev->mt; | 414 | struct input_mt *mt = dev->mt; |
415 | int mu = 2 * dmax * dmax; | ||
407 | int nrc; | 416 | int nrc; |
408 | 417 | ||
409 | if (!mt || !mt->red) | 418 | if (!mt || !mt->red) |
@@ -413,8 +422,8 @@ int input_mt_assign_slots(struct input_dev *dev, int *slots, | |||
413 | if (num_pos < 1) | 422 | if (num_pos < 1) |
414 | return 0; | 423 | return 0; |
415 | 424 | ||
416 | nrc = input_mt_set_matrix(mt, pos, num_pos); | 425 | nrc = input_mt_set_matrix(mt, pos, num_pos, mu); |
417 | find_reduced_matrix(mt->red, num_pos, nrc / num_pos, nrc); | 426 | find_reduced_matrix(mt->red, num_pos, nrc / num_pos, nrc, mu); |
418 | input_mt_set_slots(mt, slots, num_pos); | 427 | input_mt_set_slots(mt, slots, num_pos); |
419 | 428 | ||
420 | return 0; | 429 | return 0; |
diff --git a/drivers/input/input.c b/drivers/input/input.c index 213e3a1903ee..cc357f1516a7 100644 --- a/drivers/input/input.c +++ b/drivers/input/input.c | |||
@@ -100,23 +100,24 @@ static unsigned int input_to_handler(struct input_handle *handle, | |||
100 | struct input_value *end = vals; | 100 | struct input_value *end = vals; |
101 | struct input_value *v; | 101 | struct input_value *v; |
102 | 102 | ||
103 | for (v = vals; v != vals + count; v++) { | 103 | if (handler->filter) { |
104 | if (handler->filter && | 104 | for (v = vals; v != vals + count; v++) { |
105 | handler->filter(handle, v->type, v->code, v->value)) | 105 | if (handler->filter(handle, v->type, v->code, v->value)) |
106 | continue; | 106 | continue; |
107 | if (end != v) | 107 | if (end != v) |
108 | *end = *v; | 108 | *end = *v; |
109 | end++; | 109 | end++; |
110 | } | ||
111 | count = end - vals; | ||
110 | } | 112 | } |
111 | 113 | ||
112 | count = end - vals; | ||
113 | if (!count) | 114 | if (!count) |
114 | return 0; | 115 | return 0; |
115 | 116 | ||
116 | if (handler->events) | 117 | if (handler->events) |
117 | handler->events(handle, vals, count); | 118 | handler->events(handle, vals, count); |
118 | else if (handler->event) | 119 | else if (handler->event) |
119 | for (v = vals; v != end; v++) | 120 | for (v = vals; v != vals + count; v++) |
120 | handler->event(handle, v->type, v->code, v->value); | 121 | handler->event(handle, v->type, v->code, v->value); |
121 | 122 | ||
122 | return count; | 123 | return count; |
@@ -143,8 +144,11 @@ static void input_pass_values(struct input_dev *dev, | |||
143 | count = input_to_handler(handle, vals, count); | 144 | count = input_to_handler(handle, vals, count); |
144 | } else { | 145 | } else { |
145 | list_for_each_entry_rcu(handle, &dev->h_list, d_node) | 146 | list_for_each_entry_rcu(handle, &dev->h_list, d_node) |
146 | if (handle->open) | 147 | if (handle->open) { |
147 | count = input_to_handler(handle, vals, count); | 148 | count = input_to_handler(handle, vals, count); |
149 | if (!count) | ||
150 | break; | ||
151 | } | ||
148 | } | 152 | } |
149 | 153 | ||
150 | rcu_read_unlock(); | 154 | rcu_read_unlock(); |
@@ -152,12 +156,14 @@ static void input_pass_values(struct input_dev *dev, | |||
152 | add_input_randomness(vals->type, vals->code, vals->value); | 156 | add_input_randomness(vals->type, vals->code, vals->value); |
153 | 157 | ||
154 | /* trigger auto repeat for key events */ | 158 | /* trigger auto repeat for key events */ |
155 | for (v = vals; v != vals + count; v++) { | 159 | if (test_bit(EV_REP, dev->evbit) && test_bit(EV_KEY, dev->evbit)) { |
156 | if (v->type == EV_KEY && v->value != 2) { | 160 | for (v = vals; v != vals + count; v++) { |
157 | if (v->value) | 161 | if (v->type == EV_KEY && v->value != 2) { |
158 | input_start_autorepeat(dev, v->code); | 162 | if (v->value) |
159 | else | 163 | input_start_autorepeat(dev, v->code); |
160 | input_stop_autorepeat(dev); | 164 | else |
165 | input_stop_autorepeat(dev); | ||
166 | } | ||
161 | } | 167 | } |
162 | } | 168 | } |
163 | } | 169 | } |
diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig index a5d9b3f3c871..a89ba7cb96f1 100644 --- a/drivers/input/keyboard/Kconfig +++ b/drivers/input/keyboard/Kconfig | |||
@@ -568,6 +568,16 @@ config KEYBOARD_STMPE | |||
568 | To compile this driver as a module, choose M here: the module will be | 568 | To compile this driver as a module, choose M here: the module will be |
569 | called stmpe-keypad. | 569 | called stmpe-keypad. |
570 | 570 | ||
571 | config KEYBOARD_SUN4I_LRADC | ||
572 | tristate "Allwinner sun4i low res adc attached tablet keys support" | ||
573 | depends on ARCH_SUNXI | ||
574 | help | ||
575 | This selects support for the Allwinner low res adc attached tablet | ||
576 | keys found on Allwinner sunxi SoCs. | ||
577 | |||
578 | To compile this driver as a module, choose M here: the | ||
579 | module will be called sun4i-lradc-keys. | ||
580 | |||
571 | config KEYBOARD_DAVINCI | 581 | config KEYBOARD_DAVINCI |
572 | tristate "TI DaVinci Key Scan" | 582 | tristate "TI DaVinci Key Scan" |
573 | depends on ARCH_DAVINCI_DM365 | 583 | depends on ARCH_DAVINCI_DM365 |
diff --git a/drivers/input/keyboard/Makefile b/drivers/input/keyboard/Makefile index febafa527eb6..470767884bd8 100644 --- a/drivers/input/keyboard/Makefile +++ b/drivers/input/keyboard/Makefile | |||
@@ -53,6 +53,7 @@ obj-$(CONFIG_KEYBOARD_SPEAR) += spear-keyboard.o | |||
53 | obj-$(CONFIG_KEYBOARD_STMPE) += stmpe-keypad.o | 53 | obj-$(CONFIG_KEYBOARD_STMPE) += stmpe-keypad.o |
54 | obj-$(CONFIG_KEYBOARD_STOWAWAY) += stowaway.o | 54 | obj-$(CONFIG_KEYBOARD_STOWAWAY) += stowaway.o |
55 | obj-$(CONFIG_KEYBOARD_ST_KEYSCAN) += st-keyscan.o | 55 | obj-$(CONFIG_KEYBOARD_ST_KEYSCAN) += st-keyscan.o |
56 | obj-$(CONFIG_KEYBOARD_SUN4I_LRADC) += sun4i-lradc-keys.o | ||
56 | obj-$(CONFIG_KEYBOARD_SUNKBD) += sunkbd.o | 57 | obj-$(CONFIG_KEYBOARD_SUNKBD) += sunkbd.o |
57 | obj-$(CONFIG_KEYBOARD_TC3589X) += tc3589x-keypad.o | 58 | obj-$(CONFIG_KEYBOARD_TC3589X) += tc3589x-keypad.o |
58 | obj-$(CONFIG_KEYBOARD_TEGRA) += tegra-kbc.o | 59 | obj-$(CONFIG_KEYBOARD_TEGRA) += tegra-kbc.o |
diff --git a/drivers/input/keyboard/atakbd.c b/drivers/input/keyboard/atakbd.c index 10bcd4ae5402..f1235831283d 100644 --- a/drivers/input/keyboard/atakbd.c +++ b/drivers/input/keyboard/atakbd.c | |||
@@ -170,7 +170,7 @@ static unsigned char atakbd_keycode[0x72] = { /* American layout */ | |||
170 | [93] = KEY_KPASTERISK, | 170 | [93] = KEY_KPASTERISK, |
171 | [94] = KEY_KPPLUS, | 171 | [94] = KEY_KPPLUS, |
172 | [95] = KEY_HELP, | 172 | [95] = KEY_HELP, |
173 | [96] = KEY_BACKSLASH, /* FIXME: '<' */ | 173 | [96] = KEY_102ND, |
174 | [97] = KEY_KPASTERISK, /* FIXME */ | 174 | [97] = KEY_KPASTERISK, /* FIXME */ |
175 | [98] = KEY_KPSLASH, | 175 | [98] = KEY_KPSLASH, |
176 | [99] = KEY_KPLEFTPAREN, | 176 | [99] = KEY_KPLEFTPAREN, |
diff --git a/drivers/input/keyboard/cap11xx.c b/drivers/input/keyboard/cap11xx.c index 4f59f0bab28f..f07461a64d85 100644 --- a/drivers/input/keyboard/cap11xx.c +++ b/drivers/input/keyboard/cap11xx.c | |||
@@ -370,7 +370,6 @@ static struct i2c_driver cap11xx_i2c_driver = { | |||
370 | 370 | ||
371 | module_i2c_driver(cap11xx_i2c_driver); | 371 | module_i2c_driver(cap11xx_i2c_driver); |
372 | 372 | ||
373 | MODULE_ALIAS("platform:cap11xx"); | ||
374 | MODULE_DESCRIPTION("Microchip CAP11XX driver"); | 373 | MODULE_DESCRIPTION("Microchip CAP11XX driver"); |
375 | MODULE_AUTHOR("Daniel Mack <linux@zonque.org>"); | 374 | MODULE_AUTHOR("Daniel Mack <linux@zonque.org>"); |
376 | MODULE_LICENSE("GPL v2"); | 375 | MODULE_LICENSE("GPL v2"); |
diff --git a/drivers/input/keyboard/imx_keypad.c b/drivers/input/keyboard/imx_keypad.c index e53f232eda0e..2e855e6f3565 100644 --- a/drivers/input/keyboard/imx_keypad.c +++ b/drivers/input/keyboard/imx_keypad.c | |||
@@ -448,8 +448,7 @@ static int imx_keypad_probe(struct platform_device *pdev) | |||
448 | return -ENOMEM; | 448 | return -ENOMEM; |
449 | } | 449 | } |
450 | 450 | ||
451 | keypad = devm_kzalloc(&pdev->dev, sizeof(struct imx_keypad), | 451 | keypad = devm_kzalloc(&pdev->dev, sizeof(*keypad), GFP_KERNEL); |
452 | GFP_KERNEL); | ||
453 | if (!keypad) { | 452 | if (!keypad) { |
454 | dev_err(&pdev->dev, "not enough memory for driver data\n"); | 453 | dev_err(&pdev->dev, "not enough memory for driver data\n"); |
455 | return -ENOMEM; | 454 | return -ENOMEM; |
diff --git a/drivers/input/keyboard/pxa27x_keypad.c b/drivers/input/keyboard/pxa27x_keypad.c index a90d6bdc499e..a89488aa1aa4 100644 --- a/drivers/input/keyboard/pxa27x_keypad.c +++ b/drivers/input/keyboard/pxa27x_keypad.c | |||
@@ -20,6 +20,7 @@ | |||
20 | #include <linux/module.h> | 20 | #include <linux/module.h> |
21 | #include <linux/interrupt.h> | 21 | #include <linux/interrupt.h> |
22 | #include <linux/input.h> | 22 | #include <linux/input.h> |
23 | #include <linux/io.h> | ||
23 | #include <linux/device.h> | 24 | #include <linux/device.h> |
24 | #include <linux/platform_device.h> | 25 | #include <linux/platform_device.h> |
25 | #include <linux/clk.h> | 26 | #include <linux/clk.h> |
@@ -28,10 +29,6 @@ | |||
28 | #include <linux/slab.h> | 29 | #include <linux/slab.h> |
29 | #include <linux/of.h> | 30 | #include <linux/of.h> |
30 | 31 | ||
31 | #include <asm/mach/arch.h> | ||
32 | #include <asm/mach/map.h> | ||
33 | |||
34 | #include <mach/hardware.h> | ||
35 | #include <linux/platform_data/keypad-pxa27x.h> | 32 | #include <linux/platform_data/keypad-pxa27x.h> |
36 | /* | 33 | /* |
37 | * Keypad Controller registers | 34 | * Keypad Controller registers |
diff --git a/drivers/input/keyboard/sun4i-lradc-keys.c b/drivers/input/keyboard/sun4i-lradc-keys.c new file mode 100644 index 000000000000..cc8f7ddcee53 --- /dev/null +++ b/drivers/input/keyboard/sun4i-lradc-keys.c | |||
@@ -0,0 +1,286 @@ | |||
1 | /* | ||
2 | * Allwinner sun4i low res adc attached tablet keys driver | ||
3 | * | ||
4 | * Copyright (C) 2014 Hans de Goede <hdegoede@redhat.com> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
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 | /* | ||
18 | * Allwinnner sunxi SoCs have a lradc which is specifically designed to have | ||
19 | * various (tablet) keys (ie home, back, search, etc). attached to it using | ||
20 | * a resistor network. This driver is for the keys on such boards. | ||
21 | * | ||
22 | * There are 2 channels, currently this driver only supports channel 0 since | ||
23 | * there are no boards known to use channel 1. | ||
24 | */ | ||
25 | |||
26 | #include <linux/err.h> | ||
27 | #include <linux/init.h> | ||
28 | #include <linux/input.h> | ||
29 | #include <linux/interrupt.h> | ||
30 | #include <linux/io.h> | ||
31 | #include <linux/module.h> | ||
32 | #include <linux/of_platform.h> | ||
33 | #include <linux/platform_device.h> | ||
34 | #include <linux/regulator/consumer.h> | ||
35 | #include <linux/slab.h> | ||
36 | |||
37 | #define LRADC_CTRL 0x00 | ||
38 | #define LRADC_INTC 0x04 | ||
39 | #define LRADC_INTS 0x08 | ||
40 | #define LRADC_DATA0 0x0c | ||
41 | #define LRADC_DATA1 0x10 | ||
42 | |||
43 | /* LRADC_CTRL bits */ | ||
44 | #define FIRST_CONVERT_DLY(x) ((x) << 24) /* 8 bits */ | ||
45 | #define CHAN_SELECT(x) ((x) << 22) /* 2 bits */ | ||
46 | #define CONTINUE_TIME_SEL(x) ((x) << 16) /* 4 bits */ | ||
47 | #define KEY_MODE_SEL(x) ((x) << 12) /* 2 bits */ | ||
48 | #define LEVELA_B_CNT(x) ((x) << 8) /* 4 bits */ | ||
49 | #define HOLD_EN(x) ((x) << 6) | ||
50 | #define LEVELB_VOL(x) ((x) << 4) /* 2 bits */ | ||
51 | #define SAMPLE_RATE(x) ((x) << 2) /* 2 bits */ | ||
52 | #define ENABLE(x) ((x) << 0) | ||
53 | |||
54 | /* LRADC_INTC and LRADC_INTS bits */ | ||
55 | #define CHAN1_KEYUP_IRQ BIT(12) | ||
56 | #define CHAN1_ALRDY_HOLD_IRQ BIT(11) | ||
57 | #define CHAN1_HOLD_IRQ BIT(10) | ||
58 | #define CHAN1_KEYDOWN_IRQ BIT(9) | ||
59 | #define CHAN1_DATA_IRQ BIT(8) | ||
60 | #define CHAN0_KEYUP_IRQ BIT(4) | ||
61 | #define CHAN0_ALRDY_HOLD_IRQ BIT(3) | ||
62 | #define CHAN0_HOLD_IRQ BIT(2) | ||
63 | #define CHAN0_KEYDOWN_IRQ BIT(1) | ||
64 | #define CHAN0_DATA_IRQ BIT(0) | ||
65 | |||
66 | struct sun4i_lradc_keymap { | ||
67 | u32 voltage; | ||
68 | u32 keycode; | ||
69 | }; | ||
70 | |||
71 | struct sun4i_lradc_data { | ||
72 | struct device *dev; | ||
73 | struct input_dev *input; | ||
74 | void __iomem *base; | ||
75 | struct regulator *vref_supply; | ||
76 | struct sun4i_lradc_keymap *chan0_map; | ||
77 | u32 chan0_map_count; | ||
78 | u32 chan0_keycode; | ||
79 | u32 vref; | ||
80 | }; | ||
81 | |||
82 | static irqreturn_t sun4i_lradc_irq(int irq, void *dev_id) | ||
83 | { | ||
84 | struct sun4i_lradc_data *lradc = dev_id; | ||
85 | u32 i, ints, val, voltage, diff, keycode = 0, closest = 0xffffffff; | ||
86 | |||
87 | ints = readl(lradc->base + LRADC_INTS); | ||
88 | |||
89 | /* | ||
90 | * lradc supports only one keypress at a time, release does not give | ||
91 | * any info as to which key was released, so we cache the keycode. | ||
92 | */ | ||
93 | |||
94 | if (ints & CHAN0_KEYUP_IRQ) { | ||
95 | input_report_key(lradc->input, lradc->chan0_keycode, 0); | ||
96 | lradc->chan0_keycode = 0; | ||
97 | } | ||
98 | |||
99 | if ((ints & CHAN0_KEYDOWN_IRQ) && lradc->chan0_keycode == 0) { | ||
100 | val = readl(lradc->base + LRADC_DATA0) & 0x3f; | ||
101 | voltage = val * lradc->vref / 63; | ||
102 | |||
103 | for (i = 0; i < lradc->chan0_map_count; i++) { | ||
104 | diff = abs(lradc->chan0_map[i].voltage - voltage); | ||
105 | if (diff < closest) { | ||
106 | closest = diff; | ||
107 | keycode = lradc->chan0_map[i].keycode; | ||
108 | } | ||
109 | } | ||
110 | |||
111 | lradc->chan0_keycode = keycode; | ||
112 | input_report_key(lradc->input, lradc->chan0_keycode, 1); | ||
113 | } | ||
114 | |||
115 | input_sync(lradc->input); | ||
116 | |||
117 | writel(ints, lradc->base + LRADC_INTS); | ||
118 | |||
119 | return IRQ_HANDLED; | ||
120 | } | ||
121 | |||
122 | static int sun4i_lradc_open(struct input_dev *dev) | ||
123 | { | ||
124 | struct sun4i_lradc_data *lradc = input_get_drvdata(dev); | ||
125 | int error; | ||
126 | |||
127 | error = regulator_enable(lradc->vref_supply); | ||
128 | if (error) | ||
129 | return error; | ||
130 | |||
131 | /* lradc Vref internally is divided by 2/3 */ | ||
132 | lradc->vref = regulator_get_voltage(lradc->vref_supply) * 2 / 3; | ||
133 | |||
134 | /* | ||
135 | * Set sample time to 4 ms / 250 Hz. Wait 2 * 4 ms for key to | ||
136 | * stabilize on press, wait (1 + 1) * 4 ms for key release | ||
137 | */ | ||
138 | writel(FIRST_CONVERT_DLY(2) | LEVELA_B_CNT(1) | HOLD_EN(1) | | ||
139 | SAMPLE_RATE(0) | ENABLE(1), lradc->base + LRADC_CTRL); | ||
140 | |||
141 | writel(CHAN0_KEYUP_IRQ | CHAN0_KEYDOWN_IRQ, lradc->base + LRADC_INTC); | ||
142 | |||
143 | return 0; | ||
144 | } | ||
145 | |||
146 | static void sun4i_lradc_close(struct input_dev *dev) | ||
147 | { | ||
148 | struct sun4i_lradc_data *lradc = input_get_drvdata(dev); | ||
149 | |||
150 | /* Disable lradc, leave other settings unchanged */ | ||
151 | writel(FIRST_CONVERT_DLY(2) | LEVELA_B_CNT(1) | HOLD_EN(1) | | ||
152 | SAMPLE_RATE(2), lradc->base + LRADC_CTRL); | ||
153 | writel(0, lradc->base + LRADC_INTC); | ||
154 | |||
155 | regulator_disable(lradc->vref_supply); | ||
156 | } | ||
157 | |||
158 | static int sun4i_lradc_load_dt_keymap(struct device *dev, | ||
159 | struct sun4i_lradc_data *lradc) | ||
160 | { | ||
161 | struct device_node *np, *pp; | ||
162 | int i; | ||
163 | int error; | ||
164 | |||
165 | np = dev->of_node; | ||
166 | if (!np) | ||
167 | return -EINVAL; | ||
168 | |||
169 | lradc->chan0_map_count = of_get_child_count(np); | ||
170 | if (lradc->chan0_map_count == 0) { | ||
171 | dev_err(dev, "keymap is missing in device tree\n"); | ||
172 | return -EINVAL; | ||
173 | } | ||
174 | |||
175 | lradc->chan0_map = devm_kmalloc_array(dev, lradc->chan0_map_count, | ||
176 | sizeof(struct sun4i_lradc_keymap), | ||
177 | GFP_KERNEL); | ||
178 | if (!lradc->chan0_map) | ||
179 | return -ENOMEM; | ||
180 | |||
181 | i = 0; | ||
182 | for_each_child_of_node(np, pp) { | ||
183 | struct sun4i_lradc_keymap *map = &lradc->chan0_map[i]; | ||
184 | u32 channel; | ||
185 | |||
186 | error = of_property_read_u32(pp, "channel", &channel); | ||
187 | if (error || channel != 0) { | ||
188 | dev_err(dev, "%s: Inval channel prop\n", pp->name); | ||
189 | return -EINVAL; | ||
190 | } | ||
191 | |||
192 | error = of_property_read_u32(pp, "voltage", &map->voltage); | ||
193 | if (error) { | ||
194 | dev_err(dev, "%s: Inval voltage prop\n", pp->name); | ||
195 | return -EINVAL; | ||
196 | } | ||
197 | |||
198 | error = of_property_read_u32(pp, "linux,code", &map->keycode); | ||
199 | if (error) { | ||
200 | dev_err(dev, "%s: Inval linux,code prop\n", pp->name); | ||
201 | return -EINVAL; | ||
202 | } | ||
203 | |||
204 | i++; | ||
205 | } | ||
206 | |||
207 | return 0; | ||
208 | } | ||
209 | |||
210 | static int sun4i_lradc_probe(struct platform_device *pdev) | ||
211 | { | ||
212 | struct sun4i_lradc_data *lradc; | ||
213 | struct device *dev = &pdev->dev; | ||
214 | int i; | ||
215 | int error; | ||
216 | |||
217 | lradc = devm_kzalloc(dev, sizeof(struct sun4i_lradc_data), GFP_KERNEL); | ||
218 | if (!lradc) | ||
219 | return -ENOMEM; | ||
220 | |||
221 | error = sun4i_lradc_load_dt_keymap(dev, lradc); | ||
222 | if (error) | ||
223 | return error; | ||
224 | |||
225 | lradc->vref_supply = devm_regulator_get(dev, "vref"); | ||
226 | if (IS_ERR(lradc->vref_supply)) | ||
227 | return PTR_ERR(lradc->vref_supply); | ||
228 | |||
229 | lradc->dev = dev; | ||
230 | lradc->input = devm_input_allocate_device(dev); | ||
231 | if (!lradc->input) | ||
232 | return -ENOMEM; | ||
233 | |||
234 | lradc->input->name = pdev->name; | ||
235 | lradc->input->phys = "sun4i_lradc/input0"; | ||
236 | lradc->input->open = sun4i_lradc_open; | ||
237 | lradc->input->close = sun4i_lradc_close; | ||
238 | lradc->input->id.bustype = BUS_HOST; | ||
239 | lradc->input->id.vendor = 0x0001; | ||
240 | lradc->input->id.product = 0x0001; | ||
241 | lradc->input->id.version = 0x0100; | ||
242 | |||
243 | __set_bit(EV_KEY, lradc->input->evbit); | ||
244 | for (i = 0; i < lradc->chan0_map_count; i++) | ||
245 | __set_bit(lradc->chan0_map[i].keycode, lradc->input->keybit); | ||
246 | |||
247 | input_set_drvdata(lradc->input, lradc); | ||
248 | |||
249 | lradc->base = devm_ioremap_resource(dev, | ||
250 | platform_get_resource(pdev, IORESOURCE_MEM, 0)); | ||
251 | if (IS_ERR(lradc->base)) | ||
252 | return PTR_ERR(lradc->base); | ||
253 | |||
254 | error = devm_request_irq(dev, platform_get_irq(pdev, 0), | ||
255 | sun4i_lradc_irq, 0, | ||
256 | "sun4i-a10-lradc-keys", lradc); | ||
257 | if (error) | ||
258 | return error; | ||
259 | |||
260 | error = input_register_device(lradc->input); | ||
261 | if (error) | ||
262 | return error; | ||
263 | |||
264 | platform_set_drvdata(pdev, lradc); | ||
265 | return 0; | ||
266 | } | ||
267 | |||
268 | static const struct of_device_id sun4i_lradc_of_match[] = { | ||
269 | { .compatible = "allwinner,sun4i-a10-lradc-keys", }, | ||
270 | { /* sentinel */ } | ||
271 | }; | ||
272 | MODULE_DEVICE_TABLE(of, sun4i_lradc_of_match); | ||
273 | |||
274 | static struct platform_driver sun4i_lradc_driver = { | ||
275 | .driver = { | ||
276 | .name = "sun4i-a10-lradc-keys", | ||
277 | .of_match_table = of_match_ptr(sun4i_lradc_of_match), | ||
278 | }, | ||
279 | .probe = sun4i_lradc_probe, | ||
280 | }; | ||
281 | |||
282 | module_platform_driver(sun4i_lradc_driver); | ||
283 | |||
284 | MODULE_DESCRIPTION("Allwinner sun4i low res adc attached tablet keys driver"); | ||
285 | MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>"); | ||
286 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig index 23297ab6163f..6deb8dae3205 100644 --- a/drivers/input/misc/Kconfig +++ b/drivers/input/misc/Kconfig | |||
@@ -93,6 +93,16 @@ config INPUT_BMA150 | |||
93 | To compile this driver as a module, choose M here: the | 93 | To compile this driver as a module, choose M here: the |
94 | module will be called bma150. | 94 | module will be called bma150. |
95 | 95 | ||
96 | config INPUT_E3X0_BUTTON | ||
97 | tristate "NI Ettus Research USRP E3x0 Button support." | ||
98 | default n | ||
99 | help | ||
100 | Say Y here to enable support for the NI Ettus Research | ||
101 | USRP E3x0 Button. | ||
102 | |||
103 | To compile this driver as a module, choose M here: the | ||
104 | module will be called e3x0_button. | ||
105 | |||
96 | config INPUT_PCSPKR | 106 | config INPUT_PCSPKR |
97 | tristate "PC Speaker support" | 107 | tristate "PC Speaker support" |
98 | depends on PCSPKR_PLATFORM | 108 | depends on PCSPKR_PLATFORM |
@@ -394,6 +404,18 @@ config INPUT_CM109 | |||
394 | To compile this driver as a module, choose M here: the module will be | 404 | To compile this driver as a module, choose M here: the module will be |
395 | called cm109. | 405 | called cm109. |
396 | 406 | ||
407 | config INPUT_REGULATOR_HAPTIC | ||
408 | tristate "Regulator haptics support" | ||
409 | depends on REGULATOR | ||
410 | select INPUT_FF_MEMLESS | ||
411 | help | ||
412 | This option enables device driver support for the haptic controlled | ||
413 | by a regulator. This driver supports ff-memless interface | ||
414 | from input framework. | ||
415 | |||
416 | To compile this driver as a module, choose M here: the | ||
417 | module will be called regulator-haptic. | ||
418 | |||
397 | config INPUT_RETU_PWRBUTTON | 419 | config INPUT_RETU_PWRBUTTON |
398 | tristate "Retu Power button Driver" | 420 | tristate "Retu Power button Driver" |
399 | depends on MFD_RETU | 421 | depends on MFD_RETU |
@@ -404,6 +426,27 @@ config INPUT_RETU_PWRBUTTON | |||
404 | To compile this driver as a module, choose M here. The module will | 426 | To compile this driver as a module, choose M here. The module will |
405 | be called retu-pwrbutton. | 427 | be called retu-pwrbutton. |
406 | 428 | ||
429 | config INPUT_TPS65218_PWRBUTTON | ||
430 | tristate "TPS65218 Power button driver" | ||
431 | depends on MFD_TPS65218 | ||
432 | help | ||
433 | Say Y here if you want to enable power buttong reporting for | ||
434 | the TPS65218 Power Management IC device. | ||
435 | |||
436 | To compile this driver as a module, choose M here. The module will | ||
437 | be called tps65218-pwrbutton. | ||
438 | |||
439 | config INPUT_AXP20X_PEK | ||
440 | tristate "X-Powers AXP20X power button driver" | ||
441 | depends on MFD_AXP20X | ||
442 | help | ||
443 | Say Y here if you want to enable power key reporting via the | ||
444 | AXP20X PMIC. | ||
445 | |||
446 | To compile this driver as a module, choose M here. The module will | ||
447 | be called axp20x-pek. | ||
448 | |||
449 | |||
407 | config INPUT_TWL4030_PWRBUTTON | 450 | config INPUT_TWL4030_PWRBUTTON |
408 | tristate "TWL4030 Power button Driver" | 451 | tristate "TWL4030 Power button Driver" |
409 | depends on TWL4030_CORE | 452 | depends on TWL4030_CORE |
diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile index 19c760361f80..403a1a54a76c 100644 --- a/drivers/input/misc/Makefile +++ b/drivers/input/misc/Makefile | |||
@@ -26,6 +26,7 @@ obj-$(CONFIG_INPUT_COBALT_BTNS) += cobalt_btns.o | |||
26 | obj-$(CONFIG_INPUT_DA9052_ONKEY) += da9052_onkey.o | 26 | obj-$(CONFIG_INPUT_DA9052_ONKEY) += da9052_onkey.o |
27 | obj-$(CONFIG_INPUT_DA9055_ONKEY) += da9055_onkey.o | 27 | obj-$(CONFIG_INPUT_DA9055_ONKEY) += da9055_onkey.o |
28 | obj-$(CONFIG_INPUT_DM355EVM) += dm355evm_keys.o | 28 | obj-$(CONFIG_INPUT_DM355EVM) += dm355evm_keys.o |
29 | obj-$(CONFIG_INPUT_E3X0_BUTTON) += e3x0-button.o | ||
29 | obj-$(CONFIG_INPUT_DRV260X_HAPTICS) += drv260x.o | 30 | obj-$(CONFIG_INPUT_DRV260X_HAPTICS) += drv260x.o |
30 | obj-$(CONFIG_INPUT_DRV2667_HAPTICS) += drv2667.o | 31 | obj-$(CONFIG_INPUT_DRV2667_HAPTICS) += drv2667.o |
31 | obj-$(CONFIG_INPUT_GP2A) += gp2ap002a00f.o | 32 | obj-$(CONFIG_INPUT_GP2A) += gp2ap002a00f.o |
@@ -53,12 +54,15 @@ obj-$(CONFIG_INPUT_PMIC8XXX_PWRKEY) += pmic8xxx-pwrkey.o | |||
53 | obj-$(CONFIG_INPUT_POWERMATE) += powermate.o | 54 | obj-$(CONFIG_INPUT_POWERMATE) += powermate.o |
54 | obj-$(CONFIG_INPUT_PWM_BEEPER) += pwm-beeper.o | 55 | obj-$(CONFIG_INPUT_PWM_BEEPER) += pwm-beeper.o |
55 | obj-$(CONFIG_INPUT_RB532_BUTTON) += rb532_button.o | 56 | obj-$(CONFIG_INPUT_RB532_BUTTON) += rb532_button.o |
57 | obj-$(CONFIG_INPUT_REGULATOR_HAPTIC) += regulator-haptic.o | ||
56 | obj-$(CONFIG_INPUT_RETU_PWRBUTTON) += retu-pwrbutton.o | 58 | obj-$(CONFIG_INPUT_RETU_PWRBUTTON) += retu-pwrbutton.o |
59 | obj-$(CONFIG_INPUT_AXP20X_PEK) += axp20x-pek.o | ||
57 | obj-$(CONFIG_INPUT_GPIO_ROTARY_ENCODER) += rotary_encoder.o | 60 | obj-$(CONFIG_INPUT_GPIO_ROTARY_ENCODER) += rotary_encoder.o |
58 | obj-$(CONFIG_INPUT_SGI_BTNS) += sgi_btns.o | 61 | obj-$(CONFIG_INPUT_SGI_BTNS) += sgi_btns.o |
59 | obj-$(CONFIG_INPUT_SIRFSOC_ONKEY) += sirfsoc-onkey.o | 62 | obj-$(CONFIG_INPUT_SIRFSOC_ONKEY) += sirfsoc-onkey.o |
60 | obj-$(CONFIG_INPUT_SOC_BUTTON_ARRAY) += soc_button_array.o | 63 | obj-$(CONFIG_INPUT_SOC_BUTTON_ARRAY) += soc_button_array.o |
61 | obj-$(CONFIG_INPUT_SPARCSPKR) += sparcspkr.o | 64 | obj-$(CONFIG_INPUT_SPARCSPKR) += sparcspkr.o |
65 | obj-$(CONFIG_INPUT_TPS65218_PWRBUTTON) += tps65218-pwrbutton.o | ||
62 | obj-$(CONFIG_INPUT_TWL4030_PWRBUTTON) += twl4030-pwrbutton.o | 66 | obj-$(CONFIG_INPUT_TWL4030_PWRBUTTON) += twl4030-pwrbutton.o |
63 | obj-$(CONFIG_INPUT_TWL4030_VIBRA) += twl4030-vibra.o | 67 | obj-$(CONFIG_INPUT_TWL4030_VIBRA) += twl4030-vibra.o |
64 | obj-$(CONFIG_INPUT_TWL6040_VIBRA) += twl6040-vibra.o | 68 | obj-$(CONFIG_INPUT_TWL6040_VIBRA) += twl6040-vibra.o |
diff --git a/drivers/input/misc/axp20x-pek.c b/drivers/input/misc/axp20x-pek.c new file mode 100644 index 000000000000..f1c844739cd7 --- /dev/null +++ b/drivers/input/misc/axp20x-pek.c | |||
@@ -0,0 +1,290 @@ | |||
1 | /* | ||
2 | * axp20x power button driver. | ||
3 | * | ||
4 | * Copyright (C) 2013 Carlo Caione <carlo@caione.org> | ||
5 | * | ||
6 | * This file is subject to the terms and conditions of the GNU General | ||
7 | * Public License. See the file "COPYING" in the main directory of this | ||
8 | * archive for more details. | ||
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 | #include <linux/errno.h> | ||
17 | #include <linux/irq.h> | ||
18 | #include <linux/init.h> | ||
19 | #include <linux/input.h> | ||
20 | #include <linux/interrupt.h> | ||
21 | #include <linux/kernel.h> | ||
22 | #include <linux/mfd/axp20x.h> | ||
23 | #include <linux/module.h> | ||
24 | #include <linux/platform_device.h> | ||
25 | #include <linux/regmap.h> | ||
26 | #include <linux/slab.h> | ||
27 | |||
28 | #define AXP20X_PEK_STARTUP_MASK (0xc0) | ||
29 | #define AXP20X_PEK_SHUTDOWN_MASK (0x03) | ||
30 | |||
31 | struct axp20x_pek { | ||
32 | struct axp20x_dev *axp20x; | ||
33 | struct input_dev *input; | ||
34 | int irq_dbr; | ||
35 | int irq_dbf; | ||
36 | }; | ||
37 | |||
38 | struct axp20x_time { | ||
39 | unsigned int time; | ||
40 | unsigned int idx; | ||
41 | }; | ||
42 | |||
43 | static const struct axp20x_time startup_time[] = { | ||
44 | { .time = 128, .idx = 0 }, | ||
45 | { .time = 1000, .idx = 2 }, | ||
46 | { .time = 3000, .idx = 1 }, | ||
47 | { .time = 2000, .idx = 3 }, | ||
48 | }; | ||
49 | |||
50 | static const struct axp20x_time shutdown_time[] = { | ||
51 | { .time = 4000, .idx = 0 }, | ||
52 | { .time = 6000, .idx = 1 }, | ||
53 | { .time = 8000, .idx = 2 }, | ||
54 | { .time = 10000, .idx = 3 }, | ||
55 | }; | ||
56 | |||
57 | struct axp20x_pek_ext_attr { | ||
58 | const struct axp20x_time *p_time; | ||
59 | unsigned int mask; | ||
60 | }; | ||
61 | |||
62 | static struct axp20x_pek_ext_attr axp20x_pek_startup_ext_attr = { | ||
63 | .p_time = startup_time, | ||
64 | .mask = AXP20X_PEK_STARTUP_MASK, | ||
65 | }; | ||
66 | |||
67 | static struct axp20x_pek_ext_attr axp20x_pek_shutdown_ext_attr = { | ||
68 | .p_time = shutdown_time, | ||
69 | .mask = AXP20X_PEK_SHUTDOWN_MASK, | ||
70 | }; | ||
71 | |||
72 | static struct axp20x_pek_ext_attr *get_axp_ext_attr(struct device_attribute *attr) | ||
73 | { | ||
74 | return container_of(attr, struct dev_ext_attribute, attr)->var; | ||
75 | } | ||
76 | |||
77 | static ssize_t axp20x_show_ext_attr(struct device *dev, | ||
78 | struct device_attribute *attr, char *buf) | ||
79 | { | ||
80 | struct axp20x_pek *axp20x_pek = dev_get_drvdata(dev); | ||
81 | struct axp20x_pek_ext_attr *axp20x_ea = get_axp_ext_attr(attr); | ||
82 | unsigned int val; | ||
83 | int ret, i; | ||
84 | |||
85 | ret = regmap_read(axp20x_pek->axp20x->regmap, AXP20X_PEK_KEY, &val); | ||
86 | if (ret != 0) | ||
87 | return ret; | ||
88 | |||
89 | val &= axp20x_ea->mask; | ||
90 | val >>= ffs(axp20x_ea->mask) - 1; | ||
91 | |||
92 | for (i = 0; i < 4; i++) | ||
93 | if (val == axp20x_ea->p_time[i].idx) | ||
94 | val = axp20x_ea->p_time[i].time; | ||
95 | |||
96 | return sprintf(buf, "%u\n", val); | ||
97 | } | ||
98 | |||
99 | static ssize_t axp20x_store_ext_attr(struct device *dev, | ||
100 | struct device_attribute *attr, | ||
101 | const char *buf, size_t count) | ||
102 | { | ||
103 | struct axp20x_pek *axp20x_pek = dev_get_drvdata(dev); | ||
104 | struct axp20x_pek_ext_attr *axp20x_ea = get_axp_ext_attr(attr); | ||
105 | char val_str[20]; | ||
106 | size_t len; | ||
107 | int ret, i; | ||
108 | unsigned int val, idx = 0; | ||
109 | unsigned int best_err = UINT_MAX; | ||
110 | |||
111 | val_str[sizeof(val_str) - 1] = '\0'; | ||
112 | strncpy(val_str, buf, sizeof(val_str) - 1); | ||
113 | len = strlen(val_str); | ||
114 | |||
115 | if (len && val_str[len - 1] == '\n') | ||
116 | val_str[len - 1] = '\0'; | ||
117 | |||
118 | ret = kstrtouint(val_str, 10, &val); | ||
119 | if (ret) | ||
120 | return ret; | ||
121 | |||
122 | for (i = 3; i >= 0; i--) { | ||
123 | unsigned int err; | ||
124 | |||
125 | err = abs(axp20x_ea->p_time[i].time - val); | ||
126 | if (err < best_err) { | ||
127 | best_err = err; | ||
128 | idx = axp20x_ea->p_time[i].idx; | ||
129 | } | ||
130 | |||
131 | if (!err) | ||
132 | break; | ||
133 | } | ||
134 | |||
135 | idx <<= ffs(axp20x_ea->mask) - 1; | ||
136 | ret = regmap_update_bits(axp20x_pek->axp20x->regmap, | ||
137 | AXP20X_PEK_KEY, | ||
138 | axp20x_ea->mask, idx); | ||
139 | if (ret != 0) | ||
140 | return -EINVAL; | ||
141 | |||
142 | return count; | ||
143 | } | ||
144 | |||
145 | static struct dev_ext_attribute axp20x_dev_attr_startup = { | ||
146 | .attr = __ATTR(startup, 0644, axp20x_show_ext_attr, axp20x_store_ext_attr), | ||
147 | .var = &axp20x_pek_startup_ext_attr, | ||
148 | }; | ||
149 | |||
150 | static struct dev_ext_attribute axp20x_dev_attr_shutdown = { | ||
151 | .attr = __ATTR(shutdown, 0644, axp20x_show_ext_attr, axp20x_store_ext_attr), | ||
152 | .var = &axp20x_pek_shutdown_ext_attr, | ||
153 | }; | ||
154 | |||
155 | static struct attribute *axp20x_attributes[] = { | ||
156 | &axp20x_dev_attr_startup.attr.attr, | ||
157 | &axp20x_dev_attr_shutdown.attr.attr, | ||
158 | NULL, | ||
159 | }; | ||
160 | |||
161 | static const struct attribute_group axp20x_attribute_group = { | ||
162 | .attrs = axp20x_attributes, | ||
163 | }; | ||
164 | |||
165 | static irqreturn_t axp20x_pek_irq(int irq, void *pwr) | ||
166 | { | ||
167 | struct input_dev *idev = pwr; | ||
168 | struct axp20x_pek *axp20x_pek = input_get_drvdata(idev); | ||
169 | |||
170 | if (irq == axp20x_pek->irq_dbr) | ||
171 | input_report_key(idev, KEY_POWER, true); | ||
172 | else if (irq == axp20x_pek->irq_dbf) | ||
173 | input_report_key(idev, KEY_POWER, false); | ||
174 | |||
175 | input_sync(idev); | ||
176 | |||
177 | return IRQ_HANDLED; | ||
178 | } | ||
179 | |||
180 | static void axp20x_remove_sysfs_group(void *_data) | ||
181 | { | ||
182 | struct device *dev = _data; | ||
183 | |||
184 | sysfs_remove_group(&dev->kobj, &axp20x_attribute_group); | ||
185 | } | ||
186 | |||
187 | static int axp20x_pek_probe(struct platform_device *pdev) | ||
188 | { | ||
189 | struct axp20x_pek *axp20x_pek; | ||
190 | struct axp20x_dev *axp20x; | ||
191 | struct input_dev *idev; | ||
192 | int error; | ||
193 | |||
194 | axp20x_pek = devm_kzalloc(&pdev->dev, sizeof(struct axp20x_pek), | ||
195 | GFP_KERNEL); | ||
196 | if (!axp20x_pek) | ||
197 | return -ENOMEM; | ||
198 | |||
199 | axp20x_pek->axp20x = dev_get_drvdata(pdev->dev.parent); | ||
200 | axp20x = axp20x_pek->axp20x; | ||
201 | |||
202 | axp20x_pek->irq_dbr = platform_get_irq_byname(pdev, "PEK_DBR"); | ||
203 | if (axp20x_pek->irq_dbr < 0) { | ||
204 | dev_err(&pdev->dev, "No IRQ for PEK_DBR, error=%d\n", | ||
205 | axp20x_pek->irq_dbr); | ||
206 | return axp20x_pek->irq_dbr; | ||
207 | } | ||
208 | axp20x_pek->irq_dbr = regmap_irq_get_virq(axp20x->regmap_irqc, | ||
209 | axp20x_pek->irq_dbr); | ||
210 | |||
211 | axp20x_pek->irq_dbf = platform_get_irq_byname(pdev, "PEK_DBF"); | ||
212 | if (axp20x_pek->irq_dbf < 0) { | ||
213 | dev_err(&pdev->dev, "No IRQ for PEK_DBF, error=%d\n", | ||
214 | axp20x_pek->irq_dbf); | ||
215 | return axp20x_pek->irq_dbf; | ||
216 | } | ||
217 | axp20x_pek->irq_dbf = regmap_irq_get_virq(axp20x->regmap_irqc, | ||
218 | axp20x_pek->irq_dbf); | ||
219 | |||
220 | axp20x_pek->input = devm_input_allocate_device(&pdev->dev); | ||
221 | if (!axp20x_pek->input) | ||
222 | return -ENOMEM; | ||
223 | |||
224 | idev = axp20x_pek->input; | ||
225 | |||
226 | idev->name = "axp20x-pek"; | ||
227 | idev->phys = "m1kbd/input2"; | ||
228 | idev->dev.parent = &pdev->dev; | ||
229 | |||
230 | input_set_capability(idev, EV_KEY, KEY_POWER); | ||
231 | |||
232 | input_set_drvdata(idev, axp20x_pek); | ||
233 | |||
234 | error = devm_request_any_context_irq(&pdev->dev, axp20x_pek->irq_dbr, | ||
235 | axp20x_pek_irq, 0, | ||
236 | "axp20x-pek-dbr", idev); | ||
237 | if (error < 0) { | ||
238 | dev_err(axp20x->dev, "Failed to request dbr IRQ#%d: %d\n", | ||
239 | axp20x_pek->irq_dbr, error); | ||
240 | return error; | ||
241 | } | ||
242 | |||
243 | error = devm_request_any_context_irq(&pdev->dev, axp20x_pek->irq_dbf, | ||
244 | axp20x_pek_irq, 0, | ||
245 | "axp20x-pek-dbf", idev); | ||
246 | if (error < 0) { | ||
247 | dev_err(axp20x->dev, "Failed to request dbf IRQ#%d: %d\n", | ||
248 | axp20x_pek->irq_dbf, error); | ||
249 | return error; | ||
250 | } | ||
251 | |||
252 | error = sysfs_create_group(&pdev->dev.kobj, &axp20x_attribute_group); | ||
253 | if (error) { | ||
254 | dev_err(axp20x->dev, "Failed to create sysfs attributes: %d\n", | ||
255 | error); | ||
256 | return error; | ||
257 | } | ||
258 | |||
259 | error = devm_add_action(&pdev->dev, | ||
260 | axp20x_remove_sysfs_group, &pdev->dev); | ||
261 | if (error) { | ||
262 | axp20x_remove_sysfs_group(&pdev->dev); | ||
263 | dev_err(&pdev->dev, "Failed to add sysfs cleanup action: %d\n", | ||
264 | error); | ||
265 | return error; | ||
266 | } | ||
267 | |||
268 | error = input_register_device(idev); | ||
269 | if (error) { | ||
270 | dev_err(axp20x->dev, "Can't register input device: %d\n", | ||
271 | error); | ||
272 | return error; | ||
273 | } | ||
274 | |||
275 | platform_set_drvdata(pdev, axp20x_pek); | ||
276 | |||
277 | return 0; | ||
278 | } | ||
279 | |||
280 | static struct platform_driver axp20x_pek_driver = { | ||
281 | .probe = axp20x_pek_probe, | ||
282 | .driver = { | ||
283 | .name = "axp20x-pek", | ||
284 | }, | ||
285 | }; | ||
286 | module_platform_driver(axp20x_pek_driver); | ||
287 | |||
288 | MODULE_DESCRIPTION("axp20x Power Button"); | ||
289 | MODULE_AUTHOR("Carlo Caione <carlo@caione.org>"); | ||
290 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/input/misc/drv260x.c b/drivers/input/misc/drv260x.c index a364e109ca7c..599578042ea0 100644 --- a/drivers/input/misc/drv260x.c +++ b/drivers/input/misc/drv260x.c | |||
@@ -733,7 +733,6 @@ static struct i2c_driver drv260x_driver = { | |||
733 | }; | 733 | }; |
734 | module_i2c_driver(drv260x_driver); | 734 | module_i2c_driver(drv260x_driver); |
735 | 735 | ||
736 | MODULE_ALIAS("platform:drv260x-haptics"); | ||
737 | MODULE_DESCRIPTION("TI DRV260x haptics driver"); | 736 | MODULE_DESCRIPTION("TI DRV260x haptics driver"); |
738 | MODULE_LICENSE("GPL"); | 737 | MODULE_LICENSE("GPL"); |
739 | MODULE_AUTHOR("Dan Murphy <dmurphy@ti.com>"); | 738 | MODULE_AUTHOR("Dan Murphy <dmurphy@ti.com>"); |
diff --git a/drivers/input/misc/drv2667.c b/drivers/input/misc/drv2667.c index a021744e608c..fc0fddf0896a 100644 --- a/drivers/input/misc/drv2667.c +++ b/drivers/input/misc/drv2667.c | |||
@@ -492,7 +492,6 @@ static struct i2c_driver drv2667_driver = { | |||
492 | }; | 492 | }; |
493 | module_i2c_driver(drv2667_driver); | 493 | module_i2c_driver(drv2667_driver); |
494 | 494 | ||
495 | MODULE_ALIAS("platform:drv2667-haptics"); | ||
496 | MODULE_DESCRIPTION("TI DRV2667 haptics driver"); | 495 | MODULE_DESCRIPTION("TI DRV2667 haptics driver"); |
497 | MODULE_LICENSE("GPL"); | 496 | MODULE_LICENSE("GPL"); |
498 | MODULE_AUTHOR("Dan Murphy <dmurphy@ti.com>"); | 497 | MODULE_AUTHOR("Dan Murphy <dmurphy@ti.com>"); |
diff --git a/drivers/input/misc/e3x0-button.c b/drivers/input/misc/e3x0-button.c new file mode 100644 index 000000000000..13bfca8a7b16 --- /dev/null +++ b/drivers/input/misc/e3x0-button.c | |||
@@ -0,0 +1,157 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2014, National Instruments Corp. All rights reserved. | ||
3 | * | ||
4 | * Driver for NI Ettus Research USRP E3x0 Button Driver | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; version 2 of the License. | ||
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 | #include <linux/device.h> | ||
17 | #include <linux/kernel.h> | ||
18 | #include <linux/module.h> | ||
19 | #include <linux/platform_device.h> | ||
20 | #include <linux/input.h> | ||
21 | #include <linux/interrupt.h> | ||
22 | #include <linux/of.h> | ||
23 | #include <linux/slab.h> | ||
24 | |||
25 | static irqreturn_t e3x0_button_release_handler(int irq, void *data) | ||
26 | { | ||
27 | struct input_dev *idev = data; | ||
28 | |||
29 | input_report_key(idev, KEY_POWER, 0); | ||
30 | input_sync(idev); | ||
31 | |||
32 | return IRQ_HANDLED; | ||
33 | } | ||
34 | |||
35 | static irqreturn_t e3x0_button_press_handler(int irq, void *data) | ||
36 | { | ||
37 | struct input_dev *idev = data; | ||
38 | |||
39 | input_report_key(idev, KEY_POWER, 1); | ||
40 | pm_wakeup_event(idev->dev.parent, 0); | ||
41 | input_sync(idev); | ||
42 | |||
43 | return IRQ_HANDLED; | ||
44 | } | ||
45 | |||
46 | static int __maybe_unused e3x0_button_suspend(struct device *dev) | ||
47 | { | ||
48 | struct platform_device *pdev = to_platform_device(dev); | ||
49 | |||
50 | if (device_may_wakeup(dev)) | ||
51 | enable_irq_wake(platform_get_irq_byname(pdev, "press")); | ||
52 | |||
53 | return 0; | ||
54 | } | ||
55 | |||
56 | static int __maybe_unused e3x0_button_resume(struct device *dev) | ||
57 | { | ||
58 | struct platform_device *pdev = to_platform_device(dev); | ||
59 | |||
60 | if (device_may_wakeup(dev)) | ||
61 | disable_irq_wake(platform_get_irq_byname(pdev, "press")); | ||
62 | |||
63 | return 0; | ||
64 | } | ||
65 | |||
66 | static SIMPLE_DEV_PM_OPS(e3x0_button_pm_ops, | ||
67 | e3x0_button_suspend, e3x0_button_resume); | ||
68 | |||
69 | static int e3x0_button_probe(struct platform_device *pdev) | ||
70 | { | ||
71 | struct input_dev *input; | ||
72 | int irq_press, irq_release; | ||
73 | int error; | ||
74 | |||
75 | irq_press = platform_get_irq_byname(pdev, "press"); | ||
76 | if (irq_press < 0) { | ||
77 | dev_err(&pdev->dev, "No IRQ for 'press', error=%d\n", | ||
78 | irq_press); | ||
79 | return irq_press; | ||
80 | } | ||
81 | |||
82 | irq_release = platform_get_irq_byname(pdev, "release"); | ||
83 | if (irq_release < 0) { | ||
84 | dev_err(&pdev->dev, "No IRQ for 'release', error=%d\n", | ||
85 | irq_release); | ||
86 | return irq_release; | ||
87 | } | ||
88 | |||
89 | input = devm_input_allocate_device(&pdev->dev); | ||
90 | if (!input) | ||
91 | return -ENOMEM; | ||
92 | |||
93 | input->name = "NI Ettus Research USRP E3x0 Button Driver"; | ||
94 | input->phys = "e3x0_button/input0"; | ||
95 | input->dev.parent = &pdev->dev; | ||
96 | |||
97 | input_set_capability(input, EV_KEY, KEY_POWER); | ||
98 | |||
99 | error = devm_request_irq(&pdev->dev, irq_press, | ||
100 | e3x0_button_press_handler, 0, | ||
101 | "e3x0-button", input); | ||
102 | if (error) { | ||
103 | dev_err(&pdev->dev, "Failed to request 'press' IRQ#%d: %d\n", | ||
104 | irq_press, error); | ||
105 | return error; | ||
106 | } | ||
107 | |||
108 | error = devm_request_irq(&pdev->dev, irq_release, | ||
109 | e3x0_button_release_handler, 0, | ||
110 | "e3x0-button", input); | ||
111 | if (error) { | ||
112 | dev_err(&pdev->dev, "Failed to request 'release' IRQ#%d: %d\n", | ||
113 | irq_release, error); | ||
114 | return error; | ||
115 | } | ||
116 | |||
117 | error = input_register_device(input); | ||
118 | if (error) { | ||
119 | dev_err(&pdev->dev, "Can't register input device: %d\n", error); | ||
120 | return error; | ||
121 | } | ||
122 | |||
123 | platform_set_drvdata(pdev, input); | ||
124 | device_init_wakeup(&pdev->dev, 1); | ||
125 | return 0; | ||
126 | } | ||
127 | |||
128 | static int e3x0_button_remove(struct platform_device *pdev) | ||
129 | { | ||
130 | device_init_wakeup(&pdev->dev, 0); | ||
131 | return 0; | ||
132 | } | ||
133 | |||
134 | #ifdef CONFIG_OF | ||
135 | static const struct of_device_id e3x0_button_match[] = { | ||
136 | { .compatible = "ettus,e3x0-button", }, | ||
137 | { } | ||
138 | }; | ||
139 | MODULE_DEVICE_TABLE(of, e3x0_button_match); | ||
140 | #endif | ||
141 | |||
142 | static struct platform_driver e3x0_button_driver = { | ||
143 | .driver = { | ||
144 | .name = "e3x0-button", | ||
145 | .of_match_table = of_match_ptr(e3x0_button_match), | ||
146 | .pm = &e3x0_button_pm_ops, | ||
147 | }, | ||
148 | .probe = e3x0_button_probe, | ||
149 | .remove = e3x0_button_remove, | ||
150 | }; | ||
151 | |||
152 | module_platform_driver(e3x0_button_driver); | ||
153 | |||
154 | MODULE_LICENSE("GPL v2"); | ||
155 | MODULE_AUTHOR("Moritz Fischer <moritz.fischer@ettus.com>"); | ||
156 | MODULE_DESCRIPTION("NI Ettus Research USRP E3x0 Button driver"); | ||
157 | MODULE_ALIAS("platform:e3x0-button"); | ||
diff --git a/drivers/input/misc/regulator-haptic.c b/drivers/input/misc/regulator-haptic.c new file mode 100644 index 000000000000..132eb914ea3e --- /dev/null +++ b/drivers/input/misc/regulator-haptic.c | |||
@@ -0,0 +1,266 @@ | |||
1 | /* | ||
2 | * Regulator haptic driver | ||
3 | * | ||
4 | * Copyright (c) 2014 Samsung Electronics Co., Ltd. | ||
5 | * Author: Jaewon Kim <jaewon02.kim@samsung.com> | ||
6 | * Author: Hyunhee Kim <hyunhee.kim@samsung.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License version 2 as | ||
10 | * published by the Free Software Foundation. | ||
11 | */ | ||
12 | |||
13 | #include <linux/input.h> | ||
14 | #include <linux/module.h> | ||
15 | #include <linux/of.h> | ||
16 | #include <linux/platform_data/regulator-haptic.h> | ||
17 | #include <linux/platform_device.h> | ||
18 | #include <linux/regulator/consumer.h> | ||
19 | #include <linux/slab.h> | ||
20 | |||
21 | #define MAX_MAGNITUDE_SHIFT 16 | ||
22 | |||
23 | struct regulator_haptic { | ||
24 | struct device *dev; | ||
25 | struct input_dev *input_dev; | ||
26 | struct regulator *regulator; | ||
27 | |||
28 | struct work_struct work; | ||
29 | struct mutex mutex; | ||
30 | |||
31 | bool active; | ||
32 | bool suspended; | ||
33 | |||
34 | unsigned int max_volt; | ||
35 | unsigned int min_volt; | ||
36 | unsigned int magnitude; | ||
37 | }; | ||
38 | |||
39 | static int regulator_haptic_toggle(struct regulator_haptic *haptic, bool on) | ||
40 | { | ||
41 | int error; | ||
42 | |||
43 | if (haptic->active != on) { | ||
44 | |||
45 | error = on ? regulator_enable(haptic->regulator) : | ||
46 | regulator_disable(haptic->regulator); | ||
47 | if (error) { | ||
48 | dev_err(haptic->dev, | ||
49 | "failed to switch regulator %s: %d\n", | ||
50 | on ? "on" : "off", error); | ||
51 | return error; | ||
52 | } | ||
53 | |||
54 | haptic->active = on; | ||
55 | } | ||
56 | |||
57 | return 0; | ||
58 | } | ||
59 | |||
60 | static int regulator_haptic_set_voltage(struct regulator_haptic *haptic, | ||
61 | unsigned int magnitude) | ||
62 | { | ||
63 | u64 volt_mag_multi; | ||
64 | unsigned int intensity; | ||
65 | int error; | ||
66 | |||
67 | volt_mag_multi = (u64)(haptic->max_volt - haptic->min_volt) * magnitude; | ||
68 | intensity = (unsigned int)(volt_mag_multi >> MAX_MAGNITUDE_SHIFT); | ||
69 | |||
70 | error = regulator_set_voltage(haptic->regulator, | ||
71 | intensity + haptic->min_volt, | ||
72 | haptic->max_volt); | ||
73 | if (error) { | ||
74 | dev_err(haptic->dev, "cannot set regulator voltage to %d: %d\n", | ||
75 | intensity + haptic->min_volt, error); | ||
76 | return error; | ||
77 | } | ||
78 | |||
79 | regulator_haptic_toggle(haptic, !!magnitude); | ||
80 | |||
81 | return 0; | ||
82 | } | ||
83 | |||
84 | static void regulator_haptic_work(struct work_struct *work) | ||
85 | { | ||
86 | struct regulator_haptic *haptic = container_of(work, | ||
87 | struct regulator_haptic, work); | ||
88 | |||
89 | mutex_lock(&haptic->mutex); | ||
90 | |||
91 | if (!haptic->suspended) | ||
92 | regulator_haptic_set_voltage(haptic, haptic->magnitude); | ||
93 | |||
94 | mutex_unlock(&haptic->mutex); | ||
95 | } | ||
96 | |||
97 | static int regulator_haptic_play_effect(struct input_dev *input, void *data, | ||
98 | struct ff_effect *effect) | ||
99 | { | ||
100 | struct regulator_haptic *haptic = input_get_drvdata(input); | ||
101 | |||
102 | haptic->magnitude = effect->u.rumble.strong_magnitude; | ||
103 | if (!haptic->magnitude) | ||
104 | haptic->magnitude = effect->u.rumble.weak_magnitude; | ||
105 | |||
106 | schedule_work(&haptic->work); | ||
107 | |||
108 | return 0; | ||
109 | } | ||
110 | |||
111 | static void regulator_haptic_close(struct input_dev *input) | ||
112 | { | ||
113 | struct regulator_haptic *haptic = input_get_drvdata(input); | ||
114 | |||
115 | cancel_work_sync(&haptic->work); | ||
116 | regulator_haptic_set_voltage(haptic, 0); | ||
117 | } | ||
118 | |||
119 | static int __maybe_unused | ||
120 | regulator_haptic_parse_dt(struct device *dev, struct regulator_haptic *haptic) | ||
121 | { | ||
122 | struct device_node *node; | ||
123 | int error; | ||
124 | |||
125 | node = dev->of_node; | ||
126 | if(!node) { | ||
127 | dev_err(dev, "Missing dveice tree data\n"); | ||
128 | return -EINVAL; | ||
129 | } | ||
130 | |||
131 | error = of_property_read_u32(node, "max-microvolt", &haptic->max_volt); | ||
132 | if (error) { | ||
133 | dev_err(dev, "cannot parse max-microvolt\n"); | ||
134 | return error; | ||
135 | } | ||
136 | |||
137 | error = of_property_read_u32(node, "min-microvolt", &haptic->min_volt); | ||
138 | if (error) { | ||
139 | dev_err(dev, "cannot parse min-microvolt\n"); | ||
140 | return error; | ||
141 | } | ||
142 | |||
143 | return 0; | ||
144 | } | ||
145 | |||
146 | static int regulator_haptic_probe(struct platform_device *pdev) | ||
147 | { | ||
148 | const struct regulator_haptic_data *pdata = dev_get_platdata(&pdev->dev); | ||
149 | struct regulator_haptic *haptic; | ||
150 | struct input_dev *input_dev; | ||
151 | int error; | ||
152 | |||
153 | haptic = devm_kzalloc(&pdev->dev, sizeof(*haptic), GFP_KERNEL); | ||
154 | if (!haptic) | ||
155 | return -ENOMEM; | ||
156 | |||
157 | platform_set_drvdata(pdev, haptic); | ||
158 | haptic->dev = &pdev->dev; | ||
159 | mutex_init(&haptic->mutex); | ||
160 | INIT_WORK(&haptic->work, regulator_haptic_work); | ||
161 | |||
162 | if (pdata) { | ||
163 | haptic->max_volt = pdata->max_volt; | ||
164 | haptic->min_volt = pdata->min_volt; | ||
165 | } else if (IS_ENABLED(CONFIG_OF)) { | ||
166 | error = regulator_haptic_parse_dt(&pdev->dev, haptic); | ||
167 | if (error) | ||
168 | return error; | ||
169 | } else { | ||
170 | dev_err(&pdev->dev, "Missing platform data\n"); | ||
171 | return -EINVAL; | ||
172 | } | ||
173 | |||
174 | haptic->regulator = devm_regulator_get_exclusive(&pdev->dev, "haptic"); | ||
175 | if (IS_ERR(haptic->regulator)) { | ||
176 | dev_err(&pdev->dev, "failed to get regulator\n"); | ||
177 | return PTR_ERR(haptic->regulator); | ||
178 | } | ||
179 | |||
180 | input_dev = devm_input_allocate_device(&pdev->dev); | ||
181 | if (!input_dev) | ||
182 | return -ENOMEM; | ||
183 | |||
184 | haptic->input_dev = input_dev; | ||
185 | haptic->input_dev->name = "regulator-haptic"; | ||
186 | haptic->input_dev->dev.parent = &pdev->dev; | ||
187 | haptic->input_dev->close = regulator_haptic_close; | ||
188 | input_set_drvdata(haptic->input_dev, haptic); | ||
189 | input_set_capability(haptic->input_dev, EV_FF, FF_RUMBLE); | ||
190 | |||
191 | error = input_ff_create_memless(input_dev, NULL, | ||
192 | regulator_haptic_play_effect); | ||
193 | if (error) { | ||
194 | dev_err(&pdev->dev, "failed to create force-feedback\n"); | ||
195 | return error; | ||
196 | } | ||
197 | |||
198 | error = input_register_device(haptic->input_dev); | ||
199 | if (error) { | ||
200 | dev_err(&pdev->dev, "failed to register input device\n"); | ||
201 | return error; | ||
202 | } | ||
203 | |||
204 | return 0; | ||
205 | } | ||
206 | |||
207 | static int __maybe_unused regulator_haptic_suspend(struct device *dev) | ||
208 | { | ||
209 | struct platform_device *pdev = to_platform_device(dev); | ||
210 | struct regulator_haptic *haptic = platform_get_drvdata(pdev); | ||
211 | int error; | ||
212 | |||
213 | error = mutex_lock_interruptible(&haptic->mutex); | ||
214 | if (error) | ||
215 | return error; | ||
216 | |||
217 | regulator_haptic_set_voltage(haptic, 0); | ||
218 | |||
219 | haptic->suspended = true; | ||
220 | |||
221 | mutex_unlock(&haptic->mutex); | ||
222 | |||
223 | return 0; | ||
224 | } | ||
225 | |||
226 | static int __maybe_unused regulator_haptic_resume(struct device *dev) | ||
227 | { | ||
228 | struct platform_device *pdev = to_platform_device(dev); | ||
229 | struct regulator_haptic *haptic = platform_get_drvdata(pdev); | ||
230 | unsigned int magnitude; | ||
231 | |||
232 | mutex_lock(&haptic->mutex); | ||
233 | |||
234 | haptic->suspended = false; | ||
235 | |||
236 | magnitude = ACCESS_ONCE(haptic->magnitude); | ||
237 | if (magnitude) | ||
238 | regulator_haptic_set_voltage(haptic, magnitude); | ||
239 | |||
240 | mutex_unlock(&haptic->mutex); | ||
241 | |||
242 | return 0; | ||
243 | } | ||
244 | |||
245 | static SIMPLE_DEV_PM_OPS(regulator_haptic_pm_ops, | ||
246 | regulator_haptic_suspend, regulator_haptic_resume); | ||
247 | |||
248 | static struct of_device_id regulator_haptic_dt_match[] = { | ||
249 | { .compatible = "regulator-haptic" }, | ||
250 | { /* sentinel */ }, | ||
251 | }; | ||
252 | |||
253 | static struct platform_driver regulator_haptic_driver = { | ||
254 | .probe = regulator_haptic_probe, | ||
255 | .driver = { | ||
256 | .name = "regulator-haptic", | ||
257 | .of_match_table = regulator_haptic_dt_match, | ||
258 | .pm = ®ulator_haptic_pm_ops, | ||
259 | }, | ||
260 | }; | ||
261 | module_platform_driver(regulator_haptic_driver); | ||
262 | |||
263 | MODULE_AUTHOR("Jaewon Kim <jaewon02.kim@samsung.com>"); | ||
264 | MODULE_AUTHOR("Hyunhee Kim <hyunhee.kim@samsung.com>"); | ||
265 | MODULE_DESCRIPTION("Regulator haptic driver"); | ||
266 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/input/misc/tps65218-pwrbutton.c b/drivers/input/misc/tps65218-pwrbutton.c new file mode 100644 index 000000000000..54508dec4eb3 --- /dev/null +++ b/drivers/input/misc/tps65218-pwrbutton.c | |||
@@ -0,0 +1,126 @@ | |||
1 | /* | ||
2 | * Texas Instruments' TPS65218 Power Button Input Driver | ||
3 | * | ||
4 | * Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com/ | ||
5 | * Author: Felipe Balbi <balbi@ti.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License version 2 as | ||
9 | * published by the Free Software Foundation. | ||
10 | * | ||
11 | * This program is distributed "as is" WITHOUT ANY WARRANTY of any | ||
12 | * kind, whether express or implied; without even the implied warranty | ||
13 | * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | */ | ||
16 | |||
17 | #include <linux/init.h> | ||
18 | #include <linux/input.h> | ||
19 | #include <linux/interrupt.h> | ||
20 | #include <linux/kernel.h> | ||
21 | #include <linux/mfd/tps65218.h> | ||
22 | #include <linux/module.h> | ||
23 | #include <linux/of.h> | ||
24 | #include <linux/platform_device.h> | ||
25 | #include <linux/slab.h> | ||
26 | |||
27 | struct tps65218_pwrbutton { | ||
28 | struct device *dev; | ||
29 | struct tps65218 *tps; | ||
30 | struct input_dev *idev; | ||
31 | }; | ||
32 | |||
33 | static irqreturn_t tps65218_pwr_irq(int irq, void *_pwr) | ||
34 | { | ||
35 | struct tps65218_pwrbutton *pwr = _pwr; | ||
36 | unsigned int reg; | ||
37 | int error; | ||
38 | |||
39 | error = tps65218_reg_read(pwr->tps, TPS65218_REG_STATUS, ®); | ||
40 | if (error) { | ||
41 | dev_err(pwr->dev, "can't read register: %d\n", error); | ||
42 | goto out; | ||
43 | } | ||
44 | |||
45 | if (reg & TPS65218_STATUS_PB_STATE) { | ||
46 | input_report_key(pwr->idev, KEY_POWER, 1); | ||
47 | pm_wakeup_event(pwr->dev, 0); | ||
48 | } else { | ||
49 | input_report_key(pwr->idev, KEY_POWER, 0); | ||
50 | } | ||
51 | |||
52 | input_sync(pwr->idev); | ||
53 | |||
54 | out: | ||
55 | return IRQ_HANDLED; | ||
56 | } | ||
57 | |||
58 | static int tps65218_pwron_probe(struct platform_device *pdev) | ||
59 | { | ||
60 | struct tps65218 *tps = dev_get_drvdata(pdev->dev.parent); | ||
61 | struct device *dev = &pdev->dev; | ||
62 | struct tps65218_pwrbutton *pwr; | ||
63 | struct input_dev *idev; | ||
64 | int error; | ||
65 | int irq; | ||
66 | |||
67 | pwr = devm_kzalloc(dev, sizeof(*pwr), GFP_KERNEL); | ||
68 | if (!pwr) | ||
69 | return -ENOMEM; | ||
70 | |||
71 | idev = devm_input_allocate_device(dev); | ||
72 | if (!idev) | ||
73 | return -ENOMEM; | ||
74 | |||
75 | idev->name = "tps65218_pwrbutton"; | ||
76 | idev->phys = "tps65218_pwrbutton/input0"; | ||
77 | idev->dev.parent = dev; | ||
78 | idev->id.bustype = BUS_I2C; | ||
79 | |||
80 | input_set_capability(idev, EV_KEY, KEY_POWER); | ||
81 | |||
82 | pwr->tps = tps; | ||
83 | pwr->dev = dev; | ||
84 | pwr->idev = idev; | ||
85 | platform_set_drvdata(pdev, pwr); | ||
86 | device_init_wakeup(dev, true); | ||
87 | |||
88 | irq = platform_get_irq(pdev, 0); | ||
89 | error = devm_request_threaded_irq(dev, irq, NULL, tps65218_pwr_irq, | ||
90 | IRQF_TRIGGER_RISING | | ||
91 | IRQF_TRIGGER_FALLING | | ||
92 | IRQF_ONESHOT, | ||
93 | "tps65218-pwrbutton", pwr); | ||
94 | if (error) { | ||
95 | dev_err(dev, "failed to request IRQ #%d: %d\n", | ||
96 | irq, error); | ||
97 | return error; | ||
98 | } | ||
99 | |||
100 | error= input_register_device(idev); | ||
101 | if (error) { | ||
102 | dev_err(dev, "Can't register power button: %d\n", error); | ||
103 | return error; | ||
104 | } | ||
105 | |||
106 | return 0; | ||
107 | } | ||
108 | |||
109 | static struct of_device_id of_tps65218_pwr_match[] = { | ||
110 | { .compatible = "ti,tps65218-pwrbutton" }, | ||
111 | { }, | ||
112 | }; | ||
113 | MODULE_DEVICE_TABLE(of, of_tps65218_pwr_match); | ||
114 | |||
115 | static struct platform_driver tps65218_pwron_driver = { | ||
116 | .probe = tps65218_pwron_probe, | ||
117 | .driver = { | ||
118 | .name = "tps65218_pwrbutton", | ||
119 | .of_match_table = of_tps65218_pwr_match, | ||
120 | }, | ||
121 | }; | ||
122 | module_platform_driver(tps65218_pwron_driver); | ||
123 | |||
124 | MODULE_DESCRIPTION("TPS65218 Power Button"); | ||
125 | MODULE_LICENSE("GPL v2"); | ||
126 | MODULE_AUTHOR("Felipe Balbi <balbi@ti.com>"); | ||
diff --git a/drivers/input/mouse/Kconfig b/drivers/input/mouse/Kconfig index d8b46b0f2dbe..4658b5d41dd7 100644 --- a/drivers/input/mouse/Kconfig +++ b/drivers/input/mouse/Kconfig | |||
@@ -105,19 +105,12 @@ config MOUSE_PS2_ELANTECH | |||
105 | Say Y here if you have an Elantech PS/2 touchpad connected | 105 | Say Y here if you have an Elantech PS/2 touchpad connected |
106 | to your system. | 106 | to your system. |
107 | 107 | ||
108 | Note that if you enable this driver you will need an updated | ||
109 | X.org Synaptics driver that does not require ABS_PRESSURE | ||
110 | reports from the touchpad (i.e. post 1.5.0 version). You can | ||
111 | grab a patch for the driver here: | ||
112 | |||
113 | http://userweb.kernel.org/~dtor/synaptics-no-abspressure.patch | ||
114 | |||
115 | If unsure, say N. | ||
116 | |||
117 | This driver exposes some configuration registers via sysfs | 108 | This driver exposes some configuration registers via sysfs |
118 | entries. For further information, | 109 | entries. For further information, |
119 | see <file:Documentation/input/elantech.txt>. | 110 | see <file:Documentation/input/elantech.txt>. |
120 | 111 | ||
112 | If unsure, say N. | ||
113 | |||
121 | config MOUSE_PS2_SENTELIC | 114 | config MOUSE_PS2_SENTELIC |
122 | bool "Sentelic Finger Sensing Pad PS/2 protocol extension" | 115 | bool "Sentelic Finger Sensing Pad PS/2 protocol extension" |
123 | depends on MOUSE_PS2 | 116 | depends on MOUSE_PS2 |
@@ -146,6 +139,16 @@ config MOUSE_PS2_OLPC | |||
146 | 139 | ||
147 | If unsure, say N. | 140 | If unsure, say N. |
148 | 141 | ||
142 | config MOUSE_PS2_FOCALTECH | ||
143 | bool "FocalTech PS/2 mouse protocol extension" if EXPERT | ||
144 | default y | ||
145 | depends on MOUSE_PS2 | ||
146 | help | ||
147 | Say Y here if you have a FocalTech PS/2 TouchPad connected to | ||
148 | your system. | ||
149 | |||
150 | If unsure, say Y. | ||
151 | |||
149 | config MOUSE_SERIAL | 152 | config MOUSE_SERIAL |
150 | tristate "Serial mouse" | 153 | tristate "Serial mouse" |
151 | select SERIO | 154 | select SERIO |
@@ -206,6 +209,7 @@ config MOUSE_BCM5974 | |||
206 | config MOUSE_CYAPA | 209 | config MOUSE_CYAPA |
207 | tristate "Cypress APA I2C Trackpad support" | 210 | tristate "Cypress APA I2C Trackpad support" |
208 | depends on I2C | 211 | depends on I2C |
212 | select CRC_ITU_T | ||
209 | help | 213 | help |
210 | This driver adds support for Cypress All Points Addressable (APA) | 214 | This driver adds support for Cypress All Points Addressable (APA) |
211 | I2C Trackpads, including the ones used in 2012 Samsung Chromebooks. | 215 | I2C Trackpads, including the ones used in 2012 Samsung Chromebooks. |
diff --git a/drivers/input/mouse/Makefile b/drivers/input/mouse/Makefile index 560003dcac37..8a9c98e76d9c 100644 --- a/drivers/input/mouse/Makefile +++ b/drivers/input/mouse/Makefile | |||
@@ -8,7 +8,7 @@ obj-$(CONFIG_MOUSE_AMIGA) += amimouse.o | |||
8 | obj-$(CONFIG_MOUSE_APPLETOUCH) += appletouch.o | 8 | obj-$(CONFIG_MOUSE_APPLETOUCH) += appletouch.o |
9 | obj-$(CONFIG_MOUSE_ATARI) += atarimouse.o | 9 | obj-$(CONFIG_MOUSE_ATARI) += atarimouse.o |
10 | obj-$(CONFIG_MOUSE_BCM5974) += bcm5974.o | 10 | obj-$(CONFIG_MOUSE_BCM5974) += bcm5974.o |
11 | obj-$(CONFIG_MOUSE_CYAPA) += cyapa.o | 11 | obj-$(CONFIG_MOUSE_CYAPA) += cyapatp.o |
12 | obj-$(CONFIG_MOUSE_ELAN_I2C) += elan_i2c.o | 12 | obj-$(CONFIG_MOUSE_ELAN_I2C) += elan_i2c.o |
13 | obj-$(CONFIG_MOUSE_GPIO) += gpio_mouse.o | 13 | obj-$(CONFIG_MOUSE_GPIO) += gpio_mouse.o |
14 | obj-$(CONFIG_MOUSE_INPORT) += inport.o | 14 | obj-$(CONFIG_MOUSE_INPORT) += inport.o |
@@ -24,6 +24,7 @@ obj-$(CONFIG_MOUSE_SYNAPTICS_I2C) += synaptics_i2c.o | |||
24 | obj-$(CONFIG_MOUSE_SYNAPTICS_USB) += synaptics_usb.o | 24 | obj-$(CONFIG_MOUSE_SYNAPTICS_USB) += synaptics_usb.o |
25 | obj-$(CONFIG_MOUSE_VSXXXAA) += vsxxxaa.o | 25 | obj-$(CONFIG_MOUSE_VSXXXAA) += vsxxxaa.o |
26 | 26 | ||
27 | cyapatp-objs := cyapa.o cyapa_gen3.o cyapa_gen5.o | ||
27 | psmouse-objs := psmouse-base.o synaptics.o focaltech.o | 28 | psmouse-objs := psmouse-base.o synaptics.o focaltech.o |
28 | 29 | ||
29 | psmouse-$(CONFIG_MOUSE_PS2_ALPS) += alps.o | 30 | psmouse-$(CONFIG_MOUSE_PS2_ALPS) += alps.o |
diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c index d88d73d83552..f205b8be2ce4 100644 --- a/drivers/input/mouse/alps.c +++ b/drivers/input/mouse/alps.c | |||
@@ -435,7 +435,7 @@ static void alps_report_mt_data(struct psmouse *psmouse, int n) | |||
435 | struct alps_fields *f = &priv->f; | 435 | struct alps_fields *f = &priv->f; |
436 | int i, slot[MAX_TOUCHES]; | 436 | int i, slot[MAX_TOUCHES]; |
437 | 437 | ||
438 | input_mt_assign_slots(dev, slot, f->mt, n); | 438 | input_mt_assign_slots(dev, slot, f->mt, n, 0); |
439 | for (i = 0; i < n; i++) | 439 | for (i = 0; i < n; i++) |
440 | alps_set_slot(dev, slot[i], f->mt[i].x, f->mt[i].y); | 440 | alps_set_slot(dev, slot[i], f->mt[i].x, f->mt[i].y); |
441 | 441 | ||
@@ -475,6 +475,13 @@ static void alps_process_trackstick_packet_v3(struct psmouse *psmouse) | |||
475 | struct input_dev *dev = priv->dev2; | 475 | struct input_dev *dev = priv->dev2; |
476 | int x, y, z, left, right, middle; | 476 | int x, y, z, left, right, middle; |
477 | 477 | ||
478 | /* It should be a DualPoint when received trackstick packet */ | ||
479 | if (!(priv->flags & ALPS_DUALPOINT)) { | ||
480 | psmouse_warn(psmouse, | ||
481 | "Rejected trackstick packet from non DualPoint device"); | ||
482 | return; | ||
483 | } | ||
484 | |||
478 | /* Sanity check packet */ | 485 | /* Sanity check packet */ |
479 | if (!(packet[0] & 0x40)) { | 486 | if (!(packet[0] & 0x40)) { |
480 | psmouse_dbg(psmouse, "Bad trackstick packet, discarding\n"); | 487 | psmouse_dbg(psmouse, "Bad trackstick packet, discarding\n"); |
@@ -699,7 +706,8 @@ static void alps_process_touchpad_packet_v3_v5(struct psmouse *psmouse) | |||
699 | 706 | ||
700 | alps_report_semi_mt_data(psmouse, fingers); | 707 | alps_report_semi_mt_data(psmouse, fingers); |
701 | 708 | ||
702 | if (!(priv->quirks & ALPS_QUIRK_TRACKSTICK_BUTTONS)) { | 709 | if ((priv->flags & ALPS_DUALPOINT) && |
710 | !(priv->quirks & ALPS_QUIRK_TRACKSTICK_BUTTONS)) { | ||
703 | input_report_key(dev2, BTN_LEFT, f->ts_left); | 711 | input_report_key(dev2, BTN_LEFT, f->ts_left); |
704 | input_report_key(dev2, BTN_RIGHT, f->ts_right); | 712 | input_report_key(dev2, BTN_RIGHT, f->ts_right); |
705 | input_report_key(dev2, BTN_MIDDLE, f->ts_middle); | 713 | input_report_key(dev2, BTN_MIDDLE, f->ts_middle); |
@@ -743,8 +751,11 @@ static void alps_process_packet_v6(struct psmouse *psmouse) | |||
743 | */ | 751 | */ |
744 | if (packet[5] == 0x7F) { | 752 | if (packet[5] == 0x7F) { |
745 | /* It should be a DualPoint when received Trackpoint packet */ | 753 | /* It should be a DualPoint when received Trackpoint packet */ |
746 | if (!(priv->flags & ALPS_DUALPOINT)) | 754 | if (!(priv->flags & ALPS_DUALPOINT)) { |
755 | psmouse_warn(psmouse, | ||
756 | "Rejected trackstick packet from non DualPoint device"); | ||
747 | return; | 757 | return; |
758 | } | ||
748 | 759 | ||
749 | /* Trackpoint packet */ | 760 | /* Trackpoint packet */ |
750 | x = packet[1] | ((packet[3] & 0x20) << 2); | 761 | x = packet[1] | ((packet[3] & 0x20) << 2); |
@@ -1026,6 +1037,13 @@ static void alps_process_trackstick_packet_v7(struct psmouse *psmouse) | |||
1026 | struct input_dev *dev2 = priv->dev2; | 1037 | struct input_dev *dev2 = priv->dev2; |
1027 | int x, y, z, left, right, middle; | 1038 | int x, y, z, left, right, middle; |
1028 | 1039 | ||
1040 | /* It should be a DualPoint when received trackstick packet */ | ||
1041 | if (!(priv->flags & ALPS_DUALPOINT)) { | ||
1042 | psmouse_warn(psmouse, | ||
1043 | "Rejected trackstick packet from non DualPoint device"); | ||
1044 | return; | ||
1045 | } | ||
1046 | |||
1029 | /* | 1047 | /* |
1030 | * b7 b6 b5 b4 b3 b2 b1 b0 | 1048 | * b7 b6 b5 b4 b3 b2 b1 b0 |
1031 | * Byte0 0 1 0 0 1 0 0 0 | 1049 | * Byte0 0 1 0 0 1 0 0 0 |
@@ -2443,14 +2461,24 @@ int alps_init(struct psmouse *psmouse) | |||
2443 | dev1->keybit[BIT_WORD(BTN_MIDDLE)] |= BIT_MASK(BTN_MIDDLE); | 2461 | dev1->keybit[BIT_WORD(BTN_MIDDLE)] |= BIT_MASK(BTN_MIDDLE); |
2444 | } | 2462 | } |
2445 | 2463 | ||
2464 | if (priv->flags & ALPS_DUALPOINT) { | ||
2465 | /* | ||
2466 | * format of input device name is: "protocol vendor name" | ||
2467 | * see function psmouse_switch_protocol() in psmouse-base.c | ||
2468 | */ | ||
2469 | dev2->name = "AlpsPS/2 ALPS DualPoint Stick"; | ||
2470 | dev2->id.product = PSMOUSE_ALPS; | ||
2471 | dev2->id.version = priv->proto_version; | ||
2472 | } else { | ||
2473 | dev2->name = "PS/2 ALPS Mouse"; | ||
2474 | dev2->id.product = PSMOUSE_PS2; | ||
2475 | dev2->id.version = 0x0000; | ||
2476 | } | ||
2477 | |||
2446 | snprintf(priv->phys, sizeof(priv->phys), "%s/input1", psmouse->ps2dev.serio->phys); | 2478 | snprintf(priv->phys, sizeof(priv->phys), "%s/input1", psmouse->ps2dev.serio->phys); |
2447 | dev2->phys = priv->phys; | 2479 | dev2->phys = priv->phys; |
2448 | dev2->name = (priv->flags & ALPS_DUALPOINT) ? | ||
2449 | "DualPoint Stick" : "ALPS PS/2 Device"; | ||
2450 | dev2->id.bustype = BUS_I8042; | 2480 | dev2->id.bustype = BUS_I8042; |
2451 | dev2->id.vendor = 0x0002; | 2481 | dev2->id.vendor = 0x0002; |
2452 | dev2->id.product = PSMOUSE_ALPS; | ||
2453 | dev2->id.version = 0x0000; | ||
2454 | dev2->dev.parent = &psmouse->ps2dev.serio->dev; | 2482 | dev2->dev.parent = &psmouse->ps2dev.serio->dev; |
2455 | 2483 | ||
2456 | dev2->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REL); | 2484 | dev2->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REL); |
diff --git a/drivers/input/mouse/bcm5974.c b/drivers/input/mouse/bcm5974.c index c329cdb0b91a..b10709f04615 100644 --- a/drivers/input/mouse/bcm5974.c +++ b/drivers/input/mouse/bcm5974.c | |||
@@ -564,7 +564,7 @@ static int report_tp_state(struct bcm5974 *dev, int size) | |||
564 | dev->index[n++] = &f[i]; | 564 | dev->index[n++] = &f[i]; |
565 | } | 565 | } |
566 | 566 | ||
567 | input_mt_assign_slots(input, dev->slots, dev->pos, n); | 567 | input_mt_assign_slots(input, dev->slots, dev->pos, n, 0); |
568 | 568 | ||
569 | for (i = 0; i < n; i++) | 569 | for (i = 0; i < n; i++) |
570 | report_finger_data(input, dev->slots[i], | 570 | report_finger_data(input, dev->slots[i], |
diff --git a/drivers/input/mouse/cyapa.c b/drivers/input/mouse/cyapa.c index 1bece8cad46f..58f4f6fa4857 100644 --- a/drivers/input/mouse/cyapa.c +++ b/drivers/input/mouse/cyapa.c | |||
@@ -20,408 +20,131 @@ | |||
20 | #include <linux/input/mt.h> | 20 | #include <linux/input/mt.h> |
21 | #include <linux/interrupt.h> | 21 | #include <linux/interrupt.h> |
22 | #include <linux/module.h> | 22 | #include <linux/module.h> |
23 | #include <linux/mutex.h> | ||
23 | #include <linux/slab.h> | 24 | #include <linux/slab.h> |
25 | #include <linux/uaccess.h> | ||
26 | #include <linux/pm_runtime.h> | ||
27 | #include <linux/acpi.h> | ||
28 | #include "cyapa.h" | ||
24 | 29 | ||
25 | /* APA trackpad firmware generation */ | ||
26 | #define CYAPA_GEN3 0x03 /* support MT-protocol B with tracking ID. */ | ||
27 | |||
28 | #define CYAPA_NAME "Cypress APA Trackpad (cyapa)" | ||
29 | |||
30 | /* commands for read/write registers of Cypress trackpad */ | ||
31 | #define CYAPA_CMD_SOFT_RESET 0x00 | ||
32 | #define CYAPA_CMD_POWER_MODE 0x01 | ||
33 | #define CYAPA_CMD_DEV_STATUS 0x02 | ||
34 | #define CYAPA_CMD_GROUP_DATA 0x03 | ||
35 | #define CYAPA_CMD_GROUP_CMD 0x04 | ||
36 | #define CYAPA_CMD_GROUP_QUERY 0x05 | ||
37 | #define CYAPA_CMD_BL_STATUS 0x06 | ||
38 | #define CYAPA_CMD_BL_HEAD 0x07 | ||
39 | #define CYAPA_CMD_BL_CMD 0x08 | ||
40 | #define CYAPA_CMD_BL_DATA 0x09 | ||
41 | #define CYAPA_CMD_BL_ALL 0x0a | ||
42 | #define CYAPA_CMD_BLK_PRODUCT_ID 0x0b | ||
43 | #define CYAPA_CMD_BLK_HEAD 0x0c | ||
44 | |||
45 | /* report data start reg offset address. */ | ||
46 | #define DATA_REG_START_OFFSET 0x0000 | ||
47 | |||
48 | #define BL_HEAD_OFFSET 0x00 | ||
49 | #define BL_DATA_OFFSET 0x10 | ||
50 | |||
51 | /* | ||
52 | * Operational Device Status Register | ||
53 | * | ||
54 | * bit 7: Valid interrupt source | ||
55 | * bit 6 - 4: Reserved | ||
56 | * bit 3 - 2: Power status | ||
57 | * bit 1 - 0: Device status | ||
58 | */ | ||
59 | #define REG_OP_STATUS 0x00 | ||
60 | #define OP_STATUS_SRC 0x80 | ||
61 | #define OP_STATUS_POWER 0x0c | ||
62 | #define OP_STATUS_DEV 0x03 | ||
63 | #define OP_STATUS_MASK (OP_STATUS_SRC | OP_STATUS_POWER | OP_STATUS_DEV) | ||
64 | |||
65 | /* | ||
66 | * Operational Finger Count/Button Flags Register | ||
67 | * | ||
68 | * bit 7 - 4: Number of touched finger | ||
69 | * bit 3: Valid data | ||
70 | * bit 2: Middle Physical Button | ||
71 | * bit 1: Right Physical Button | ||
72 | * bit 0: Left physical Button | ||
73 | */ | ||
74 | #define REG_OP_DATA1 0x01 | ||
75 | #define OP_DATA_VALID 0x08 | ||
76 | #define OP_DATA_MIDDLE_BTN 0x04 | ||
77 | #define OP_DATA_RIGHT_BTN 0x02 | ||
78 | #define OP_DATA_LEFT_BTN 0x01 | ||
79 | #define OP_DATA_BTN_MASK (OP_DATA_MIDDLE_BTN | OP_DATA_RIGHT_BTN | \ | ||
80 | OP_DATA_LEFT_BTN) | ||
81 | |||
82 | /* | ||
83 | * Bootloader Status Register | ||
84 | * | ||
85 | * bit 7: Busy | ||
86 | * bit 6 - 5: Reserved | ||
87 | * bit 4: Bootloader running | ||
88 | * bit 3 - 1: Reserved | ||
89 | * bit 0: Checksum valid | ||
90 | */ | ||
91 | #define REG_BL_STATUS 0x01 | ||
92 | #define BL_STATUS_BUSY 0x80 | ||
93 | #define BL_STATUS_RUNNING 0x10 | ||
94 | #define BL_STATUS_DATA_VALID 0x08 | ||
95 | #define BL_STATUS_CSUM_VALID 0x01 | ||
96 | |||
97 | /* | ||
98 | * Bootloader Error Register | ||
99 | * | ||
100 | * bit 7: Invalid | ||
101 | * bit 6: Invalid security key | ||
102 | * bit 5: Bootloading | ||
103 | * bit 4: Command checksum | ||
104 | * bit 3: Flash protection error | ||
105 | * bit 2: Flash checksum error | ||
106 | * bit 1 - 0: Reserved | ||
107 | */ | ||
108 | #define REG_BL_ERROR 0x02 | ||
109 | #define BL_ERROR_INVALID 0x80 | ||
110 | #define BL_ERROR_INVALID_KEY 0x40 | ||
111 | #define BL_ERROR_BOOTLOADING 0x20 | ||
112 | #define BL_ERROR_CMD_CSUM 0x10 | ||
113 | #define BL_ERROR_FLASH_PROT 0x08 | ||
114 | #define BL_ERROR_FLASH_CSUM 0x04 | ||
115 | |||
116 | #define BL_STATUS_SIZE 3 /* length of bootloader status registers */ | ||
117 | #define BLK_HEAD_BYTES 32 | ||
118 | |||
119 | #define PRODUCT_ID_SIZE 16 | ||
120 | #define QUERY_DATA_SIZE 27 | ||
121 | #define REG_PROTOCOL_GEN_QUERY_OFFSET 20 | ||
122 | |||
123 | #define REG_OFFSET_DATA_BASE 0x0000 | ||
124 | #define REG_OFFSET_COMMAND_BASE 0x0028 | ||
125 | #define REG_OFFSET_QUERY_BASE 0x002a | ||
126 | |||
127 | #define CAPABILITY_LEFT_BTN_MASK (0x01 << 3) | ||
128 | #define CAPABILITY_RIGHT_BTN_MASK (0x01 << 4) | ||
129 | #define CAPABILITY_MIDDLE_BTN_MASK (0x01 << 5) | ||
130 | #define CAPABILITY_BTN_MASK (CAPABILITY_LEFT_BTN_MASK | \ | ||
131 | CAPABILITY_RIGHT_BTN_MASK | \ | ||
132 | CAPABILITY_MIDDLE_BTN_MASK) | ||
133 | |||
134 | #define CYAPA_OFFSET_SOFT_RESET REG_OFFSET_COMMAND_BASE | ||
135 | |||
136 | #define REG_OFFSET_POWER_MODE (REG_OFFSET_COMMAND_BASE + 1) | ||
137 | |||
138 | #define PWR_MODE_MASK 0xfc | ||
139 | #define PWR_MODE_FULL_ACTIVE (0x3f << 2) | ||
140 | #define PWR_MODE_IDLE (0x05 << 2) /* default sleep time is 50 ms. */ | ||
141 | #define PWR_MODE_OFF (0x00 << 2) | ||
142 | |||
143 | #define PWR_STATUS_MASK 0x0c | ||
144 | #define PWR_STATUS_ACTIVE (0x03 << 2) | ||
145 | #define PWR_STATUS_IDLE (0x02 << 2) | ||
146 | #define PWR_STATUS_OFF (0x00 << 2) | ||
147 | |||
148 | /* | ||
149 | * CYAPA trackpad device states. | ||
150 | * Used in register 0x00, bit1-0, DeviceStatus field. | ||
151 | * Other values indicate device is in an abnormal state and must be reset. | ||
152 | */ | ||
153 | #define CYAPA_DEV_NORMAL 0x03 | ||
154 | #define CYAPA_DEV_BUSY 0x01 | ||
155 | |||
156 | enum cyapa_state { | ||
157 | CYAPA_STATE_OP, | ||
158 | CYAPA_STATE_BL_IDLE, | ||
159 | CYAPA_STATE_BL_ACTIVE, | ||
160 | CYAPA_STATE_BL_BUSY, | ||
161 | CYAPA_STATE_NO_DEVICE, | ||
162 | }; | ||
163 | |||
164 | |||
165 | struct cyapa_touch { | ||
166 | /* | ||
167 | * high bits or x/y position value | ||
168 | * bit 7 - 4: high 4 bits of x position value | ||
169 | * bit 3 - 0: high 4 bits of y position value | ||
170 | */ | ||
171 | u8 xy_hi; | ||
172 | u8 x_lo; /* low 8 bits of x position value. */ | ||
173 | u8 y_lo; /* low 8 bits of y position value. */ | ||
174 | u8 pressure; | ||
175 | /* id range is 1 - 15. It is incremented with every new touch. */ | ||
176 | u8 id; | ||
177 | } __packed; | ||
178 | |||
179 | /* The touch.id is used as the MT slot id, thus max MT slot is 15 */ | ||
180 | #define CYAPA_MAX_MT_SLOTS 15 | ||
181 | |||
182 | struct cyapa_reg_data { | ||
183 | /* | ||
184 | * bit 0 - 1: device status | ||
185 | * bit 3 - 2: power mode | ||
186 | * bit 6 - 4: reserved | ||
187 | * bit 7: interrupt valid bit | ||
188 | */ | ||
189 | u8 device_status; | ||
190 | /* | ||
191 | * bit 7 - 4: number of fingers currently touching pad | ||
192 | * bit 3: valid data check bit | ||
193 | * bit 2: middle mechanism button state if exists | ||
194 | * bit 1: right mechanism button state if exists | ||
195 | * bit 0: left mechanism button state if exists | ||
196 | */ | ||
197 | u8 finger_btn; | ||
198 | /* CYAPA reports up to 5 touches per packet. */ | ||
199 | struct cyapa_touch touches[5]; | ||
200 | } __packed; | ||
201 | |||
202 | /* The main device structure */ | ||
203 | struct cyapa { | ||
204 | enum cyapa_state state; | ||
205 | |||
206 | struct i2c_client *client; | ||
207 | struct input_dev *input; | ||
208 | char phys[32]; /* device physical location */ | ||
209 | bool irq_wake; /* irq wake is enabled */ | ||
210 | bool smbus; | ||
211 | |||
212 | /* read from query data region. */ | ||
213 | char product_id[16]; | ||
214 | u8 btn_capability; | ||
215 | u8 gen; | ||
216 | int max_abs_x; | ||
217 | int max_abs_y; | ||
218 | int physical_size_x; | ||
219 | int physical_size_y; | ||
220 | }; | ||
221 | |||
222 | static const u8 bl_deactivate[] = { 0x00, 0xff, 0x3b, 0x00, 0x01, 0x02, 0x03, | ||
223 | 0x04, 0x05, 0x06, 0x07 }; | ||
224 | static const u8 bl_exit[] = { 0x00, 0xff, 0xa5, 0x00, 0x01, 0x02, 0x03, 0x04, | ||
225 | 0x05, 0x06, 0x07 }; | ||
226 | |||
227 | struct cyapa_cmd_len { | ||
228 | u8 cmd; | ||
229 | u8 len; | ||
230 | }; | ||
231 | 30 | ||
232 | #define CYAPA_ADAPTER_FUNC_NONE 0 | 31 | #define CYAPA_ADAPTER_FUNC_NONE 0 |
233 | #define CYAPA_ADAPTER_FUNC_I2C 1 | 32 | #define CYAPA_ADAPTER_FUNC_I2C 1 |
234 | #define CYAPA_ADAPTER_FUNC_SMBUS 2 | 33 | #define CYAPA_ADAPTER_FUNC_SMBUS 2 |
235 | #define CYAPA_ADAPTER_FUNC_BOTH 3 | 34 | #define CYAPA_ADAPTER_FUNC_BOTH 3 |
236 | 35 | ||
237 | /* | 36 | #define CYAPA_FW_NAME "cyapa.bin" |
238 | * macros for SMBus communication | ||
239 | */ | ||
240 | #define SMBUS_READ 0x01 | ||
241 | #define SMBUS_WRITE 0x00 | ||
242 | #define SMBUS_ENCODE_IDX(cmd, idx) ((cmd) | (((idx) & 0x03) << 1)) | ||
243 | #define SMBUS_ENCODE_RW(cmd, rw) ((cmd) | ((rw) & 0x01)) | ||
244 | #define SMBUS_BYTE_BLOCK_CMD_MASK 0x80 | ||
245 | #define SMBUS_GROUP_BLOCK_CMD_MASK 0x40 | ||
246 | |||
247 | /* for byte read/write command */ | ||
248 | #define CMD_RESET 0 | ||
249 | #define CMD_POWER_MODE 1 | ||
250 | #define CMD_DEV_STATUS 2 | ||
251 | #define SMBUS_BYTE_CMD(cmd) (((cmd) & 0x3f) << 1) | ||
252 | #define CYAPA_SMBUS_RESET SMBUS_BYTE_CMD(CMD_RESET) | ||
253 | #define CYAPA_SMBUS_POWER_MODE SMBUS_BYTE_CMD(CMD_POWER_MODE) | ||
254 | #define CYAPA_SMBUS_DEV_STATUS SMBUS_BYTE_CMD(CMD_DEV_STATUS) | ||
255 | |||
256 | /* for group registers read/write command */ | ||
257 | #define REG_GROUP_DATA 0 | ||
258 | #define REG_GROUP_CMD 2 | ||
259 | #define REG_GROUP_QUERY 3 | ||
260 | #define SMBUS_GROUP_CMD(grp) (0x80 | (((grp) & 0x07) << 3)) | ||
261 | #define CYAPA_SMBUS_GROUP_DATA SMBUS_GROUP_CMD(REG_GROUP_DATA) | ||
262 | #define CYAPA_SMBUS_GROUP_CMD SMBUS_GROUP_CMD(REG_GROUP_CMD) | ||
263 | #define CYAPA_SMBUS_GROUP_QUERY SMBUS_GROUP_CMD(REG_GROUP_QUERY) | ||
264 | |||
265 | /* for register block read/write command */ | ||
266 | #define CMD_BL_STATUS 0 | ||
267 | #define CMD_BL_HEAD 1 | ||
268 | #define CMD_BL_CMD 2 | ||
269 | #define CMD_BL_DATA 3 | ||
270 | #define CMD_BL_ALL 4 | ||
271 | #define CMD_BLK_PRODUCT_ID 5 | ||
272 | #define CMD_BLK_HEAD 6 | ||
273 | #define SMBUS_BLOCK_CMD(cmd) (0xc0 | (((cmd) & 0x1f) << 1)) | ||
274 | |||
275 | /* register block read/write command in bootloader mode */ | ||
276 | #define CYAPA_SMBUS_BL_STATUS SMBUS_BLOCK_CMD(CMD_BL_STATUS) | ||
277 | #define CYAPA_SMBUS_BL_HEAD SMBUS_BLOCK_CMD(CMD_BL_HEAD) | ||
278 | #define CYAPA_SMBUS_BL_CMD SMBUS_BLOCK_CMD(CMD_BL_CMD) | ||
279 | #define CYAPA_SMBUS_BL_DATA SMBUS_BLOCK_CMD(CMD_BL_DATA) | ||
280 | #define CYAPA_SMBUS_BL_ALL SMBUS_BLOCK_CMD(CMD_BL_ALL) | ||
281 | |||
282 | /* register block read/write command in operational mode */ | ||
283 | #define CYAPA_SMBUS_BLK_PRODUCT_ID SMBUS_BLOCK_CMD(CMD_BLK_PRODUCT_ID) | ||
284 | #define CYAPA_SMBUS_BLK_HEAD SMBUS_BLOCK_CMD(CMD_BLK_HEAD) | ||
285 | |||
286 | static const struct cyapa_cmd_len cyapa_i2c_cmds[] = { | ||
287 | { CYAPA_OFFSET_SOFT_RESET, 1 }, | ||
288 | { REG_OFFSET_COMMAND_BASE + 1, 1 }, | ||
289 | { REG_OFFSET_DATA_BASE, 1 }, | ||
290 | { REG_OFFSET_DATA_BASE, sizeof(struct cyapa_reg_data) }, | ||
291 | { REG_OFFSET_COMMAND_BASE, 0 }, | ||
292 | { REG_OFFSET_QUERY_BASE, QUERY_DATA_SIZE }, | ||
293 | { BL_HEAD_OFFSET, 3 }, | ||
294 | { BL_HEAD_OFFSET, 16 }, | ||
295 | { BL_HEAD_OFFSET, 16 }, | ||
296 | { BL_DATA_OFFSET, 16 }, | ||
297 | { BL_HEAD_OFFSET, 32 }, | ||
298 | { REG_OFFSET_QUERY_BASE, PRODUCT_ID_SIZE }, | ||
299 | { REG_OFFSET_DATA_BASE, 32 } | ||
300 | }; | ||
301 | 37 | ||
302 | static const struct cyapa_cmd_len cyapa_smbus_cmds[] = { | 38 | const char product_id[] = "CYTRA"; |
303 | { CYAPA_SMBUS_RESET, 1 }, | ||
304 | { CYAPA_SMBUS_POWER_MODE, 1 }, | ||
305 | { CYAPA_SMBUS_DEV_STATUS, 1 }, | ||
306 | { CYAPA_SMBUS_GROUP_DATA, sizeof(struct cyapa_reg_data) }, | ||
307 | { CYAPA_SMBUS_GROUP_CMD, 2 }, | ||
308 | { CYAPA_SMBUS_GROUP_QUERY, QUERY_DATA_SIZE }, | ||
309 | { CYAPA_SMBUS_BL_STATUS, 3 }, | ||
310 | { CYAPA_SMBUS_BL_HEAD, 16 }, | ||
311 | { CYAPA_SMBUS_BL_CMD, 16 }, | ||
312 | { CYAPA_SMBUS_BL_DATA, 16 }, | ||
313 | { CYAPA_SMBUS_BL_ALL, 32 }, | ||
314 | { CYAPA_SMBUS_BLK_PRODUCT_ID, PRODUCT_ID_SIZE }, | ||
315 | { CYAPA_SMBUS_BLK_HEAD, 16 }, | ||
316 | }; | ||
317 | 39 | ||
318 | static ssize_t cyapa_i2c_reg_read_block(struct cyapa *cyapa, u8 reg, size_t len, | 40 | static int cyapa_reinitialize(struct cyapa *cyapa); |
319 | u8 *values) | 41 | |
42 | static inline bool cyapa_is_bootloader_mode(struct cyapa *cyapa) | ||
320 | { | 43 | { |
321 | return i2c_smbus_read_i2c_block_data(cyapa->client, reg, len, values); | 44 | if (cyapa->gen == CYAPA_GEN5 && cyapa->state == CYAPA_STATE_GEN5_BL) |
45 | return true; | ||
46 | |||
47 | if (cyapa->gen == CYAPA_GEN3 && | ||
48 | cyapa->state >= CYAPA_STATE_BL_BUSY && | ||
49 | cyapa->state <= CYAPA_STATE_BL_ACTIVE) | ||
50 | return true; | ||
51 | |||
52 | return false; | ||
322 | } | 53 | } |
323 | 54 | ||
324 | static ssize_t cyapa_i2c_reg_write_block(struct cyapa *cyapa, u8 reg, | 55 | static inline bool cyapa_is_operational_mode(struct cyapa *cyapa) |
325 | size_t len, const u8 *values) | ||
326 | { | 56 | { |
327 | return i2c_smbus_write_i2c_block_data(cyapa->client, reg, len, values); | 57 | if (cyapa->gen == CYAPA_GEN5 && cyapa->state == CYAPA_STATE_GEN5_APP) |
58 | return true; | ||
59 | |||
60 | if (cyapa->gen == CYAPA_GEN3 && cyapa->state == CYAPA_STATE_OP) | ||
61 | return true; | ||
62 | |||
63 | return false; | ||
328 | } | 64 | } |
329 | 65 | ||
330 | /* | 66 | /* Returns 0 on success, else negative errno on failure. */ |
331 | * cyapa_smbus_read_block - perform smbus block read command | 67 | static ssize_t cyapa_i2c_read(struct cyapa *cyapa, u8 reg, size_t len, |
332 | * @cyapa - private data structure of the driver | 68 | u8 *values) |
333 | * @cmd - the properly encoded smbus command | ||
334 | * @len - expected length of smbus command result | ||
335 | * @values - buffer to store smbus command result | ||
336 | * | ||
337 | * Returns negative errno, else the number of bytes written. | ||
338 | * | ||
339 | * Note: | ||
340 | * In trackpad device, the memory block allocated for I2C register map | ||
341 | * is 256 bytes, so the max read block for I2C bus is 256 bytes. | ||
342 | */ | ||
343 | static ssize_t cyapa_smbus_read_block(struct cyapa *cyapa, u8 cmd, size_t len, | ||
344 | u8 *values) | ||
345 | { | 69 | { |
346 | ssize_t ret; | ||
347 | u8 index; | ||
348 | u8 smbus_cmd; | ||
349 | u8 *buf; | ||
350 | struct i2c_client *client = cyapa->client; | 70 | struct i2c_client *client = cyapa->client; |
71 | struct i2c_msg msgs[] = { | ||
72 | { | ||
73 | .addr = client->addr, | ||
74 | .flags = 0, | ||
75 | .len = 1, | ||
76 | .buf = ®, | ||
77 | }, | ||
78 | { | ||
79 | .addr = client->addr, | ||
80 | .flags = I2C_M_RD, | ||
81 | .len = len, | ||
82 | .buf = values, | ||
83 | }, | ||
84 | }; | ||
85 | int ret; | ||
351 | 86 | ||
352 | if (!(SMBUS_BYTE_BLOCK_CMD_MASK & cmd)) | 87 | ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); |
353 | return -EINVAL; | ||
354 | |||
355 | if (SMBUS_GROUP_BLOCK_CMD_MASK & cmd) { | ||
356 | /* read specific block registers command. */ | ||
357 | smbus_cmd = SMBUS_ENCODE_RW(cmd, SMBUS_READ); | ||
358 | ret = i2c_smbus_read_block_data(client, smbus_cmd, values); | ||
359 | goto out; | ||
360 | } | ||
361 | 88 | ||
362 | ret = 0; | 89 | if (ret != ARRAY_SIZE(msgs)) |
363 | for (index = 0; index * I2C_SMBUS_BLOCK_MAX < len; index++) { | 90 | return ret < 0 ? ret : -EIO; |
364 | smbus_cmd = SMBUS_ENCODE_IDX(cmd, index); | ||
365 | smbus_cmd = SMBUS_ENCODE_RW(smbus_cmd, SMBUS_READ); | ||
366 | buf = values + I2C_SMBUS_BLOCK_MAX * index; | ||
367 | ret = i2c_smbus_read_block_data(client, smbus_cmd, buf); | ||
368 | if (ret < 0) | ||
369 | goto out; | ||
370 | } | ||
371 | 91 | ||
372 | out: | 92 | return 0; |
373 | return ret > 0 ? len : ret; | ||
374 | } | 93 | } |
375 | 94 | ||
376 | static s32 cyapa_read_byte(struct cyapa *cyapa, u8 cmd_idx) | 95 | /** |
96 | * cyapa_i2c_write - Execute i2c block data write operation | ||
97 | * @cyapa: Handle to this driver | ||
98 | * @ret: Offset of the data to written in the register map | ||
99 | * @len: number of bytes to write | ||
100 | * @values: Data to be written | ||
101 | * | ||
102 | * Return negative errno code on error; return zero when success. | ||
103 | */ | ||
104 | static int cyapa_i2c_write(struct cyapa *cyapa, u8 reg, | ||
105 | size_t len, const void *values) | ||
377 | { | 106 | { |
378 | u8 cmd; | 107 | struct i2c_client *client = cyapa->client; |
108 | char buf[32]; | ||
109 | int ret; | ||
379 | 110 | ||
380 | if (cyapa->smbus) { | 111 | if (len > sizeof(buf) - 1) |
381 | cmd = cyapa_smbus_cmds[cmd_idx].cmd; | 112 | return -ENOMEM; |
382 | cmd = SMBUS_ENCODE_RW(cmd, SMBUS_READ); | ||
383 | } else { | ||
384 | cmd = cyapa_i2c_cmds[cmd_idx].cmd; | ||
385 | } | ||
386 | return i2c_smbus_read_byte_data(cyapa->client, cmd); | ||
387 | } | ||
388 | 113 | ||
389 | static s32 cyapa_write_byte(struct cyapa *cyapa, u8 cmd_idx, u8 value) | 114 | buf[0] = reg; |
390 | { | 115 | memcpy(&buf[1], values, len); |
391 | u8 cmd; | ||
392 | 116 | ||
393 | if (cyapa->smbus) { | 117 | ret = i2c_master_send(client, buf, len + 1); |
394 | cmd = cyapa_smbus_cmds[cmd_idx].cmd; | 118 | if (ret != len + 1) |
395 | cmd = SMBUS_ENCODE_RW(cmd, SMBUS_WRITE); | 119 | return ret < 0 ? ret : -EIO; |
396 | } else { | 120 | |
397 | cmd = cyapa_i2c_cmds[cmd_idx].cmd; | 121 | return 0; |
398 | } | ||
399 | return i2c_smbus_write_byte_data(cyapa->client, cmd, value); | ||
400 | } | 122 | } |
401 | 123 | ||
402 | static ssize_t cyapa_read_block(struct cyapa *cyapa, u8 cmd_idx, u8 *values) | 124 | static u8 cyapa_check_adapter_functionality(struct i2c_client *client) |
403 | { | 125 | { |
404 | u8 cmd; | 126 | u8 ret = CYAPA_ADAPTER_FUNC_NONE; |
405 | size_t len; | ||
406 | 127 | ||
407 | if (cyapa->smbus) { | 128 | if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) |
408 | cmd = cyapa_smbus_cmds[cmd_idx].cmd; | 129 | ret |= CYAPA_ADAPTER_FUNC_I2C; |
409 | len = cyapa_smbus_cmds[cmd_idx].len; | 130 | if (i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA | |
410 | return cyapa_smbus_read_block(cyapa, cmd, len, values); | 131 | I2C_FUNC_SMBUS_BLOCK_DATA | |
411 | } else { | 132 | I2C_FUNC_SMBUS_I2C_BLOCK)) |
412 | cmd = cyapa_i2c_cmds[cmd_idx].cmd; | 133 | ret |= CYAPA_ADAPTER_FUNC_SMBUS; |
413 | len = cyapa_i2c_cmds[cmd_idx].len; | 134 | return ret; |
414 | return cyapa_i2c_reg_read_block(cyapa, cmd, len, values); | ||
415 | } | ||
416 | } | 135 | } |
417 | 136 | ||
418 | /* | 137 | /* |
419 | * Query device for its current operating state. | 138 | * Query device for its current operating state. |
420 | * | ||
421 | */ | 139 | */ |
422 | static int cyapa_get_state(struct cyapa *cyapa) | 140 | static int cyapa_get_state(struct cyapa *cyapa) |
423 | { | 141 | { |
424 | u8 status[BL_STATUS_SIZE]; | 142 | u8 status[BL_STATUS_SIZE]; |
143 | u8 cmd[32]; | ||
144 | /* The i2c address of gen4 and gen5 trackpad device must be even. */ | ||
145 | bool even_addr = ((cyapa->client->addr & 0x0001) == 0); | ||
146 | bool smbus = false; | ||
147 | int retries = 2; | ||
425 | int error; | 148 | int error; |
426 | 149 | ||
427 | cyapa->state = CYAPA_STATE_NO_DEVICE; | 150 | cyapa->state = CYAPA_STATE_NO_DEVICE; |
@@ -433,39 +156,74 @@ static int cyapa_get_state(struct cyapa *cyapa) | |||
433 | * | 156 | * |
434 | */ | 157 | */ |
435 | error = cyapa_i2c_reg_read_block(cyapa, BL_HEAD_OFFSET, BL_STATUS_SIZE, | 158 | error = cyapa_i2c_reg_read_block(cyapa, BL_HEAD_OFFSET, BL_STATUS_SIZE, |
436 | status); | 159 | status); |
437 | 160 | ||
438 | /* | 161 | /* |
439 | * On smbus systems in OP mode, the i2c_reg_read will fail with | 162 | * On smbus systems in OP mode, the i2c_reg_read will fail with |
440 | * -ETIMEDOUT. In this case, try again using the smbus equivalent | 163 | * -ETIMEDOUT. In this case, try again using the smbus equivalent |
441 | * command. This should return a BL_HEAD indicating CYAPA_STATE_OP. | 164 | * command. This should return a BL_HEAD indicating CYAPA_STATE_OP. |
442 | */ | 165 | */ |
443 | if (cyapa->smbus && (error == -ETIMEDOUT || error == -ENXIO)) | 166 | if (cyapa->smbus && (error == -ETIMEDOUT || error == -ENXIO)) { |
444 | error = cyapa_read_block(cyapa, CYAPA_CMD_BL_STATUS, status); | 167 | if (!even_addr) |
168 | error = cyapa_read_block(cyapa, | ||
169 | CYAPA_CMD_BL_STATUS, status); | ||
170 | smbus = true; | ||
171 | } | ||
445 | 172 | ||
446 | if (error != BL_STATUS_SIZE) | 173 | if (error != BL_STATUS_SIZE) |
447 | goto error; | 174 | goto error; |
448 | 175 | ||
449 | if ((status[REG_OP_STATUS] & OP_STATUS_SRC) == OP_STATUS_SRC) { | 176 | /* |
450 | switch (status[REG_OP_STATUS] & OP_STATUS_DEV) { | 177 | * Detect trackpad protocol based on characteristic registers and bits. |
451 | case CYAPA_DEV_NORMAL: | 178 | */ |
452 | case CYAPA_DEV_BUSY: | 179 | do { |
453 | cyapa->state = CYAPA_STATE_OP; | 180 | cyapa->status[REG_OP_STATUS] = status[REG_OP_STATUS]; |
454 | break; | 181 | cyapa->status[REG_BL_STATUS] = status[REG_BL_STATUS]; |
455 | default: | 182 | cyapa->status[REG_BL_ERROR] = status[REG_BL_ERROR]; |
456 | error = -EAGAIN; | 183 | |
457 | goto error; | 184 | if (cyapa->gen == CYAPA_GEN_UNKNOWN || |
185 | cyapa->gen == CYAPA_GEN3) { | ||
186 | error = cyapa_gen3_ops.state_parse(cyapa, | ||
187 | status, BL_STATUS_SIZE); | ||
188 | if (!error) | ||
189 | goto out_detected; | ||
458 | } | 190 | } |
459 | } else { | 191 | if ((cyapa->gen == CYAPA_GEN_UNKNOWN || |
460 | if (status[REG_BL_STATUS] & BL_STATUS_BUSY) | 192 | cyapa->gen == CYAPA_GEN5) && |
461 | cyapa->state = CYAPA_STATE_BL_BUSY; | 193 | !smbus && even_addr) { |
462 | else if (status[REG_BL_ERROR] & BL_ERROR_BOOTLOADING) | 194 | error = cyapa_gen5_ops.state_parse(cyapa, |
463 | cyapa->state = CYAPA_STATE_BL_ACTIVE; | 195 | status, BL_STATUS_SIZE); |
464 | else | 196 | if (!error) |
465 | cyapa->state = CYAPA_STATE_BL_IDLE; | 197 | goto out_detected; |
466 | } | 198 | } |
199 | |||
200 | /* | ||
201 | * Write 0x00 0x00 to trackpad device to force update its | ||
202 | * status, then redo the detection again. | ||
203 | */ | ||
204 | if (!smbus) { | ||
205 | cmd[0] = 0x00; | ||
206 | cmd[1] = 0x00; | ||
207 | error = cyapa_i2c_write(cyapa, 0, 2, cmd); | ||
208 | if (error) | ||
209 | goto error; | ||
210 | |||
211 | msleep(50); | ||
212 | |||
213 | error = cyapa_i2c_read(cyapa, BL_HEAD_OFFSET, | ||
214 | BL_STATUS_SIZE, status); | ||
215 | if (error) | ||
216 | goto error; | ||
217 | } | ||
218 | } while (--retries > 0 && !smbus); | ||
219 | |||
220 | goto error; | ||
467 | 221 | ||
222 | out_detected: | ||
223 | if (cyapa->state <= CYAPA_STATE_BL_BUSY) | ||
224 | return -EAGAIN; | ||
468 | return 0; | 225 | return 0; |
226 | |||
469 | error: | 227 | error: |
470 | return (error < 0) ? error : -EAGAIN; | 228 | return (error < 0) ? error : -EAGAIN; |
471 | } | 229 | } |
@@ -482,364 +240,939 @@ error: | |||
482 | * Returns: | 240 | * Returns: |
483 | * 0 when the device eventually responds with a valid non-busy state. | 241 | * 0 when the device eventually responds with a valid non-busy state. |
484 | * -ETIMEDOUT if device never responds (too many -EAGAIN) | 242 | * -ETIMEDOUT if device never responds (too many -EAGAIN) |
485 | * < 0 other errors | 243 | * -EAGAIN if bootload is busy, or unknown state. |
244 | * < 0 other errors | ||
486 | */ | 245 | */ |
487 | static int cyapa_poll_state(struct cyapa *cyapa, unsigned int timeout) | 246 | int cyapa_poll_state(struct cyapa *cyapa, unsigned int timeout) |
488 | { | 247 | { |
489 | int error; | 248 | int error; |
490 | int tries = timeout / 100; | 249 | int tries = timeout / 100; |
491 | 250 | ||
492 | error = cyapa_get_state(cyapa); | 251 | do { |
493 | while ((error || cyapa->state >= CYAPA_STATE_BL_BUSY) && tries--) { | ||
494 | msleep(100); | ||
495 | error = cyapa_get_state(cyapa); | 252 | error = cyapa_get_state(cyapa); |
496 | } | 253 | if (!error && cyapa->state > CYAPA_STATE_BL_BUSY) |
497 | return (error == -EAGAIN || error == -ETIMEDOUT) ? -ETIMEDOUT : error; | 254 | return 0; |
498 | } | ||
499 | 255 | ||
500 | static int cyapa_bl_deactivate(struct cyapa *cyapa) | 256 | msleep(100); |
501 | { | 257 | } while (tries--); |
502 | int error; | ||
503 | |||
504 | error = cyapa_i2c_reg_write_block(cyapa, 0, sizeof(bl_deactivate), | ||
505 | bl_deactivate); | ||
506 | if (error) | ||
507 | return error; | ||
508 | 258 | ||
509 | /* wait for bootloader to switch to idle state; should take < 100ms */ | 259 | return (error == -EAGAIN || error == -ETIMEDOUT) ? -ETIMEDOUT : error; |
510 | msleep(100); | ||
511 | error = cyapa_poll_state(cyapa, 500); | ||
512 | if (error) | ||
513 | return error; | ||
514 | if (cyapa->state != CYAPA_STATE_BL_IDLE) | ||
515 | return -EAGAIN; | ||
516 | return 0; | ||
517 | } | 260 | } |
518 | 261 | ||
519 | /* | 262 | /* |
520 | * Exit bootloader | 263 | * Check if device is operational. |
521 | * | 264 | * |
522 | * Send bl_exit command, then wait 50 - 100 ms to let device transition to | 265 | * An operational device is responding, has exited bootloader, and has |
523 | * operational mode. If this is the first time the device's firmware is | 266 | * firmware supported by this driver. |
524 | * running, it can take up to 2 seconds to calibrate its sensors. So, poll | ||
525 | * the device's new state for up to 2 seconds. | ||
526 | * | 267 | * |
527 | * Returns: | 268 | * Returns: |
269 | * -ENODEV no device | ||
270 | * -EBUSY no device or in bootloader | ||
528 | * -EIO failure while reading from device | 271 | * -EIO failure while reading from device |
529 | * -EAGAIN device is stuck in bootloader, b/c it has invalid firmware | 272 | * -ETIMEDOUT timeout failure for bus idle or bus no response |
530 | * 0 device is supported and in operational mode | 273 | * -EAGAIN device is still in bootloader |
274 | * if ->state = CYAPA_STATE_BL_IDLE, device has invalid firmware | ||
275 | * -EINVAL device is in operational mode, but not supported by this driver | ||
276 | * 0 device is supported | ||
531 | */ | 277 | */ |
532 | static int cyapa_bl_exit(struct cyapa *cyapa) | 278 | static int cyapa_check_is_operational(struct cyapa *cyapa) |
533 | { | 279 | { |
534 | int error; | 280 | int error; |
535 | 281 | ||
536 | error = cyapa_i2c_reg_write_block(cyapa, 0, sizeof(bl_exit), bl_exit); | 282 | error = cyapa_poll_state(cyapa, 4000); |
537 | if (error) | 283 | if (error) |
538 | return error; | 284 | return error; |
539 | 285 | ||
540 | /* | 286 | switch (cyapa->gen) { |
541 | * Wait for bootloader to exit, and operation mode to start. | 287 | case CYAPA_GEN5: |
542 | * Normally, this takes at least 50 ms. | 288 | cyapa->ops = &cyapa_gen5_ops; |
543 | */ | 289 | break; |
544 | usleep_range(50000, 100000); | 290 | case CYAPA_GEN3: |
545 | /* | 291 | cyapa->ops = &cyapa_gen3_ops; |
546 | * In addition, when a device boots for the first time after being | 292 | break; |
547 | * updated to new firmware, it must first calibrate its sensors, which | 293 | default: |
548 | * can take up to an additional 2 seconds. | 294 | return -ENODEV; |
549 | */ | 295 | } |
550 | error = cyapa_poll_state(cyapa, 2000); | ||
551 | if (error < 0) | ||
552 | return error; | ||
553 | if (cyapa->state != CYAPA_STATE_OP) | ||
554 | return -EAGAIN; | ||
555 | 296 | ||
556 | return 0; | 297 | error = cyapa->ops->operational_check(cyapa); |
298 | if (!error && cyapa_is_operational_mode(cyapa)) | ||
299 | cyapa->operational = true; | ||
300 | else | ||
301 | cyapa->operational = false; | ||
302 | |||
303 | return error; | ||
557 | } | 304 | } |
558 | 305 | ||
306 | |||
559 | /* | 307 | /* |
560 | * Set device power mode | 308 | * Returns 0 on device detected, negative errno on no device detected. |
561 | * | 309 | * And when the device is detected and opertaional, it will be reset to |
310 | * full power active mode automatically. | ||
562 | */ | 311 | */ |
563 | static int cyapa_set_power_mode(struct cyapa *cyapa, u8 power_mode) | 312 | static int cyapa_detect(struct cyapa *cyapa) |
564 | { | 313 | { |
565 | struct device *dev = &cyapa->client->dev; | 314 | struct device *dev = &cyapa->client->dev; |
566 | int ret; | 315 | int error; |
567 | u8 power; | ||
568 | |||
569 | if (cyapa->state != CYAPA_STATE_OP) | ||
570 | return 0; | ||
571 | 316 | ||
572 | ret = cyapa_read_byte(cyapa, CYAPA_CMD_POWER_MODE); | 317 | error = cyapa_check_is_operational(cyapa); |
573 | if (ret < 0) | 318 | if (error) { |
574 | return ret; | 319 | if (error != -ETIMEDOUT && error != -ENODEV && |
320 | cyapa_is_bootloader_mode(cyapa)) { | ||
321 | dev_warn(dev, "device detected but not operational\n"); | ||
322 | return 0; | ||
323 | } | ||
575 | 324 | ||
576 | power = ret & ~PWR_MODE_MASK; | 325 | dev_err(dev, "no device detected: %d\n", error); |
577 | power |= power_mode & PWR_MODE_MASK; | 326 | return error; |
578 | ret = cyapa_write_byte(cyapa, CYAPA_CMD_POWER_MODE, power); | ||
579 | if (ret < 0) { | ||
580 | dev_err(dev, "failed to set power_mode 0x%02x err = %d\n", | ||
581 | power_mode, ret); | ||
582 | return ret; | ||
583 | } | 327 | } |
584 | 328 | ||
585 | return 0; | 329 | return 0; |
586 | } | 330 | } |
587 | 331 | ||
588 | static int cyapa_get_query_data(struct cyapa *cyapa) | 332 | static int cyapa_open(struct input_dev *input) |
589 | { | 333 | { |
590 | u8 query_data[QUERY_DATA_SIZE]; | 334 | struct cyapa *cyapa = input_get_drvdata(input); |
591 | int ret; | 335 | struct i2c_client *client = cyapa->client; |
336 | int error; | ||
592 | 337 | ||
593 | if (cyapa->state != CYAPA_STATE_OP) | 338 | error = mutex_lock_interruptible(&cyapa->state_sync_lock); |
594 | return -EBUSY; | 339 | if (error) |
340 | return error; | ||
595 | 341 | ||
596 | ret = cyapa_read_block(cyapa, CYAPA_CMD_GROUP_QUERY, query_data); | 342 | if (cyapa->operational) { |
597 | if (ret < 0) | 343 | /* |
598 | return ret; | 344 | * though failed to set active power mode, |
599 | if (ret != QUERY_DATA_SIZE) | 345 | * but still may be able to work in lower scan rate |
600 | return -EIO; | 346 | * when in operational mode. |
347 | */ | ||
348 | error = cyapa->ops->set_power_mode(cyapa, | ||
349 | PWR_MODE_FULL_ACTIVE, 0); | ||
350 | if (error) { | ||
351 | dev_warn(&client->dev, | ||
352 | "set active power failed: %d\n", error); | ||
353 | goto out; | ||
354 | } | ||
355 | } else { | ||
356 | error = cyapa_reinitialize(cyapa); | ||
357 | if (error || !cyapa->operational) { | ||
358 | error = error ? error : -EAGAIN; | ||
359 | goto out; | ||
360 | } | ||
361 | } | ||
362 | |||
363 | enable_irq(client->irq); | ||
364 | if (!pm_runtime_enabled(&client->dev)) { | ||
365 | pm_runtime_set_active(&client->dev); | ||
366 | pm_runtime_enable(&client->dev); | ||
367 | } | ||
368 | out: | ||
369 | mutex_unlock(&cyapa->state_sync_lock); | ||
370 | return error; | ||
371 | } | ||
372 | |||
373 | static void cyapa_close(struct input_dev *input) | ||
374 | { | ||
375 | struct cyapa *cyapa = input_get_drvdata(input); | ||
376 | struct i2c_client *client = cyapa->client; | ||
377 | |||
378 | mutex_lock(&cyapa->state_sync_lock); | ||
379 | |||
380 | disable_irq(client->irq); | ||
381 | if (pm_runtime_enabled(&client->dev)) | ||
382 | pm_runtime_disable(&client->dev); | ||
383 | pm_runtime_set_suspended(&client->dev); | ||
384 | |||
385 | if (cyapa->operational) | ||
386 | cyapa->ops->set_power_mode(cyapa, PWR_MODE_OFF, 0); | ||
601 | 387 | ||
602 | memcpy(&cyapa->product_id[0], &query_data[0], 5); | 388 | mutex_unlock(&cyapa->state_sync_lock); |
603 | cyapa->product_id[5] = '-'; | 389 | } |
604 | memcpy(&cyapa->product_id[6], &query_data[5], 6); | ||
605 | cyapa->product_id[12] = '-'; | ||
606 | memcpy(&cyapa->product_id[13], &query_data[11], 2); | ||
607 | cyapa->product_id[15] = '\0'; | ||
608 | 390 | ||
609 | cyapa->btn_capability = query_data[19] & CAPABILITY_BTN_MASK; | 391 | static int cyapa_create_input_dev(struct cyapa *cyapa) |
392 | { | ||
393 | struct device *dev = &cyapa->client->dev; | ||
394 | struct input_dev *input; | ||
395 | int error; | ||
610 | 396 | ||
611 | cyapa->gen = query_data[20] & 0x0f; | 397 | if (!cyapa->physical_size_x || !cyapa->physical_size_y) |
398 | return -EINVAL; | ||
612 | 399 | ||
613 | cyapa->max_abs_x = ((query_data[21] & 0xf0) << 4) | query_data[22]; | 400 | input = devm_input_allocate_device(dev); |
614 | cyapa->max_abs_y = ((query_data[21] & 0x0f) << 8) | query_data[23]; | 401 | if (!input) { |
402 | dev_err(dev, "failed to allocate memory for input device.\n"); | ||
403 | return -ENOMEM; | ||
404 | } | ||
405 | |||
406 | input->name = CYAPA_NAME; | ||
407 | input->phys = cyapa->phys; | ||
408 | input->id.bustype = BUS_I2C; | ||
409 | input->id.version = 1; | ||
410 | input->id.product = 0; /* Means any product in eventcomm. */ | ||
411 | input->dev.parent = &cyapa->client->dev; | ||
412 | |||
413 | input->open = cyapa_open; | ||
414 | input->close = cyapa_close; | ||
415 | |||
416 | input_set_drvdata(input, cyapa); | ||
417 | |||
418 | __set_bit(EV_ABS, input->evbit); | ||
419 | |||
420 | /* Finger position */ | ||
421 | input_set_abs_params(input, ABS_MT_POSITION_X, 0, cyapa->max_abs_x, 0, | ||
422 | 0); | ||
423 | input_set_abs_params(input, ABS_MT_POSITION_Y, 0, cyapa->max_abs_y, 0, | ||
424 | 0); | ||
425 | input_set_abs_params(input, ABS_MT_PRESSURE, 0, cyapa->max_z, 0, 0); | ||
426 | if (cyapa->gen > CYAPA_GEN3) { | ||
427 | input_set_abs_params(input, ABS_MT_TOUCH_MAJOR, 0, 255, 0, 0); | ||
428 | input_set_abs_params(input, ABS_MT_TOUCH_MINOR, 0, 255, 0, 0); | ||
429 | /* | ||
430 | * Orientation is the angle between the vertical axis and | ||
431 | * the major axis of the contact ellipse. | ||
432 | * The range is -127 to 127. | ||
433 | * the positive direction is clockwise form the vertical axis. | ||
434 | * If the ellipse of contact degenerates into a circle, | ||
435 | * orientation is reported as 0. | ||
436 | * | ||
437 | * Also, for Gen5 trackpad the accurate of this orientation | ||
438 | * value is value + (-30 ~ 30). | ||
439 | */ | ||
440 | input_set_abs_params(input, ABS_MT_ORIENTATION, | ||
441 | -127, 127, 0, 0); | ||
442 | } | ||
443 | if (cyapa->gen >= CYAPA_GEN5) { | ||
444 | input_set_abs_params(input, ABS_MT_WIDTH_MAJOR, 0, 255, 0, 0); | ||
445 | input_set_abs_params(input, ABS_MT_WIDTH_MINOR, 0, 255, 0, 0); | ||
446 | } | ||
447 | |||
448 | input_abs_set_res(input, ABS_MT_POSITION_X, | ||
449 | cyapa->max_abs_x / cyapa->physical_size_x); | ||
450 | input_abs_set_res(input, ABS_MT_POSITION_Y, | ||
451 | cyapa->max_abs_y / cyapa->physical_size_y); | ||
452 | |||
453 | if (cyapa->btn_capability & CAPABILITY_LEFT_BTN_MASK) | ||
454 | __set_bit(BTN_LEFT, input->keybit); | ||
455 | if (cyapa->btn_capability & CAPABILITY_MIDDLE_BTN_MASK) | ||
456 | __set_bit(BTN_MIDDLE, input->keybit); | ||
457 | if (cyapa->btn_capability & CAPABILITY_RIGHT_BTN_MASK) | ||
458 | __set_bit(BTN_RIGHT, input->keybit); | ||
459 | |||
460 | if (cyapa->btn_capability == CAPABILITY_LEFT_BTN_MASK) | ||
461 | __set_bit(INPUT_PROP_BUTTONPAD, input->propbit); | ||
462 | |||
463 | /* Handle pointer emulation and unused slots in core */ | ||
464 | error = input_mt_init_slots(input, CYAPA_MAX_MT_SLOTS, | ||
465 | INPUT_MT_POINTER | INPUT_MT_DROP_UNUSED); | ||
466 | if (error) { | ||
467 | dev_err(dev, "failed to initialize MT slots: %d\n", error); | ||
468 | return error; | ||
469 | } | ||
615 | 470 | ||
616 | cyapa->physical_size_x = | 471 | /* Register the device in input subsystem */ |
617 | ((query_data[24] & 0xf0) << 4) | query_data[25]; | 472 | error = input_register_device(input); |
618 | cyapa->physical_size_y = | 473 | if (error) { |
619 | ((query_data[24] & 0x0f) << 8) | query_data[26]; | 474 | dev_err(dev, "failed to register input device: %d\n", error); |
475 | return error; | ||
476 | } | ||
620 | 477 | ||
478 | cyapa->input = input; | ||
621 | return 0; | 479 | return 0; |
622 | } | 480 | } |
623 | 481 | ||
482 | static void cyapa_enable_irq_for_cmd(struct cyapa *cyapa) | ||
483 | { | ||
484 | struct input_dev *input = cyapa->input; | ||
485 | |||
486 | if (!input || !input->users) { | ||
487 | /* | ||
488 | * When input is NULL, TP must be in deep sleep mode. | ||
489 | * In this mode, later non-power I2C command will always failed | ||
490 | * if not bring it out of deep sleep mode firstly, | ||
491 | * so must command TP to active mode here. | ||
492 | */ | ||
493 | if (!input || cyapa->operational) | ||
494 | cyapa->ops->set_power_mode(cyapa, | ||
495 | PWR_MODE_FULL_ACTIVE, 0); | ||
496 | /* Gen3 always using polling mode for command. */ | ||
497 | if (cyapa->gen >= CYAPA_GEN5) | ||
498 | enable_irq(cyapa->client->irq); | ||
499 | } | ||
500 | } | ||
501 | |||
502 | static void cyapa_disable_irq_for_cmd(struct cyapa *cyapa) | ||
503 | { | ||
504 | struct input_dev *input = cyapa->input; | ||
505 | |||
506 | if (!input || !input->users) { | ||
507 | if (cyapa->gen >= CYAPA_GEN5) | ||
508 | disable_irq(cyapa->client->irq); | ||
509 | if (!input || cyapa->operational) | ||
510 | cyapa->ops->set_power_mode(cyapa, PWR_MODE_OFF, 0); | ||
511 | } | ||
512 | } | ||
513 | |||
624 | /* | 514 | /* |
625 | * Check if device is operational. | 515 | * cyapa_sleep_time_to_pwr_cmd and cyapa_pwr_cmd_to_sleep_time |
626 | * | 516 | * |
627 | * An operational device is responding, has exited bootloader, and has | 517 | * These are helper functions that convert to and from integer idle |
628 | * firmware supported by this driver. | 518 | * times and register settings to write to the PowerMode register. |
519 | * The trackpad supports between 20ms to 1000ms scan intervals. | ||
520 | * The time will be increased in increments of 10ms from 20ms to 100ms. | ||
521 | * From 100ms to 1000ms, time will be increased in increments of 20ms. | ||
629 | * | 522 | * |
630 | * Returns: | 523 | * When Idle_Time < 100, the format to convert Idle_Time to Idle_Command is: |
631 | * -EBUSY no device or in bootloader | 524 | * Idle_Command = Idle Time / 10; |
632 | * -EIO failure while reading from device | 525 | * When Idle_Time >= 100, the format to convert Idle_Time to Idle_Command is: |
633 | * -EAGAIN device is still in bootloader | 526 | * Idle_Command = Idle Time / 20 + 5; |
634 | * if ->state = CYAPA_STATE_BL_IDLE, device has invalid firmware | ||
635 | * -EINVAL device is in operational mode, but not supported by this driver | ||
636 | * 0 device is supported | ||
637 | */ | 527 | */ |
638 | static int cyapa_check_is_operational(struct cyapa *cyapa) | 528 | u8 cyapa_sleep_time_to_pwr_cmd(u16 sleep_time) |
639 | { | 529 | { |
640 | struct device *dev = &cyapa->client->dev; | 530 | u16 encoded_time; |
641 | static const char unique_str[] = "CYTRA"; | ||
642 | int error; | ||
643 | 531 | ||
644 | error = cyapa_poll_state(cyapa, 2000); | 532 | sleep_time = clamp_val(sleep_time, 20, 1000); |
533 | encoded_time = sleep_time < 100 ? sleep_time / 10 : sleep_time / 20 + 5; | ||
534 | return (encoded_time << 2) & PWR_MODE_MASK; | ||
535 | } | ||
536 | |||
537 | u16 cyapa_pwr_cmd_to_sleep_time(u8 pwr_mode) | ||
538 | { | ||
539 | u8 encoded_time = pwr_mode >> 2; | ||
540 | |||
541 | return (encoded_time < 10) ? encoded_time * 10 | ||
542 | : (encoded_time - 5) * 20; | ||
543 | } | ||
544 | |||
545 | /* 0 on driver initialize and detected successfully, negative on failure. */ | ||
546 | static int cyapa_initialize(struct cyapa *cyapa) | ||
547 | { | ||
548 | int error = 0; | ||
549 | |||
550 | cyapa->state = CYAPA_STATE_NO_DEVICE; | ||
551 | cyapa->gen = CYAPA_GEN_UNKNOWN; | ||
552 | mutex_init(&cyapa->state_sync_lock); | ||
553 | |||
554 | /* | ||
555 | * Set to hard code default, they will be updated with trackpad set | ||
556 | * default values after probe and initialized. | ||
557 | */ | ||
558 | cyapa->suspend_power_mode = PWR_MODE_SLEEP; | ||
559 | cyapa->suspend_sleep_time = | ||
560 | cyapa_pwr_cmd_to_sleep_time(cyapa->suspend_power_mode); | ||
561 | |||
562 | /* ops.initialize() is aimed to prepare for module communications. */ | ||
563 | error = cyapa_gen3_ops.initialize(cyapa); | ||
564 | if (!error) | ||
565 | error = cyapa_gen5_ops.initialize(cyapa); | ||
645 | if (error) | 566 | if (error) |
646 | return error; | 567 | return error; |
647 | switch (cyapa->state) { | ||
648 | case CYAPA_STATE_BL_ACTIVE: | ||
649 | error = cyapa_bl_deactivate(cyapa); | ||
650 | if (error) | ||
651 | return error; | ||
652 | 568 | ||
653 | /* Fallthrough state */ | 569 | error = cyapa_detect(cyapa); |
654 | case CYAPA_STATE_BL_IDLE: | 570 | if (error) |
655 | error = cyapa_bl_exit(cyapa); | 571 | return error; |
656 | if (error) | ||
657 | return error; | ||
658 | 572 | ||
659 | /* Fallthrough state */ | 573 | /* Power down the device until we need it. */ |
660 | case CYAPA_STATE_OP: | 574 | if (cyapa->operational) |
661 | error = cyapa_get_query_data(cyapa); | 575 | cyapa->ops->set_power_mode(cyapa, PWR_MODE_OFF, 0); |
662 | if (error) | ||
663 | return error; | ||
664 | 576 | ||
665 | /* only support firmware protocol gen3 */ | 577 | return 0; |
666 | if (cyapa->gen != CYAPA_GEN3) { | 578 | } |
667 | dev_err(dev, "unsupported protocol version (%d)", | 579 | |
668 | cyapa->gen); | 580 | static int cyapa_reinitialize(struct cyapa *cyapa) |
669 | return -EINVAL; | 581 | { |
670 | } | 582 | struct device *dev = &cyapa->client->dev; |
583 | struct input_dev *input = cyapa->input; | ||
584 | int error; | ||
585 | |||
586 | if (pm_runtime_enabled(dev)) | ||
587 | pm_runtime_disable(dev); | ||
671 | 588 | ||
672 | /* only support product ID starting with CYTRA */ | 589 | /* Avoid command failures when TP was in OFF state. */ |
673 | if (memcmp(cyapa->product_id, unique_str, | 590 | if (cyapa->operational) |
674 | sizeof(unique_str) - 1) != 0) { | 591 | cyapa->ops->set_power_mode(cyapa, PWR_MODE_FULL_ACTIVE, 0); |
675 | dev_err(dev, "unsupported product ID (%s)\n", | 592 | |
676 | cyapa->product_id); | 593 | error = cyapa_detect(cyapa); |
677 | return -EINVAL; | 594 | if (error) |
595 | goto out; | ||
596 | |||
597 | if (!input && cyapa->operational) { | ||
598 | error = cyapa_create_input_dev(cyapa); | ||
599 | if (error) { | ||
600 | dev_err(dev, "create input_dev instance failed: %d\n", | ||
601 | error); | ||
602 | goto out; | ||
678 | } | 603 | } |
679 | return 0; | 604 | } |
680 | 605 | ||
681 | default: | 606 | out: |
682 | return -EIO; | 607 | if (!input || !input->users) { |
608 | /* Reset to power OFF state to save power when no user open. */ | ||
609 | if (cyapa->operational) | ||
610 | cyapa->ops->set_power_mode(cyapa, PWR_MODE_OFF, 0); | ||
611 | } else if (!error && cyapa->operational) { | ||
612 | /* | ||
613 | * Make sure only enable runtime PM when device is | ||
614 | * in operational mode and input->users > 0. | ||
615 | */ | ||
616 | pm_runtime_set_active(dev); | ||
617 | pm_runtime_enable(dev); | ||
683 | } | 618 | } |
684 | return 0; | 619 | |
620 | return error; | ||
685 | } | 621 | } |
686 | 622 | ||
687 | static irqreturn_t cyapa_irq(int irq, void *dev_id) | 623 | static irqreturn_t cyapa_irq(int irq, void *dev_id) |
688 | { | 624 | { |
689 | struct cyapa *cyapa = dev_id; | 625 | struct cyapa *cyapa = dev_id; |
690 | struct device *dev = &cyapa->client->dev; | 626 | struct device *dev = &cyapa->client->dev; |
691 | struct input_dev *input = cyapa->input; | ||
692 | struct cyapa_reg_data data; | ||
693 | int i; | ||
694 | int ret; | ||
695 | int num_fingers; | ||
696 | 627 | ||
628 | pm_runtime_get_sync(dev); | ||
697 | if (device_may_wakeup(dev)) | 629 | if (device_may_wakeup(dev)) |
698 | pm_wakeup_event(dev, 0); | 630 | pm_wakeup_event(dev, 0); |
699 | 631 | ||
700 | ret = cyapa_read_block(cyapa, CYAPA_CMD_GROUP_DATA, (u8 *)&data); | 632 | /* Interrupt event maybe cuased by host command to trackpad device. */ |
701 | if (ret != sizeof(data)) | 633 | if (cyapa->ops->irq_cmd_handler(cyapa)) { |
702 | goto out; | 634 | /* |
635 | * Interrupt event maybe from trackpad device input reporting. | ||
636 | */ | ||
637 | if (!cyapa->input) { | ||
638 | /* | ||
639 | * Still in probling or in firware image | ||
640 | * udpating or reading. | ||
641 | */ | ||
642 | cyapa->ops->sort_empty_output_data(cyapa, | ||
643 | NULL, NULL, NULL); | ||
644 | goto out; | ||
645 | } | ||
703 | 646 | ||
704 | if ((data.device_status & OP_STATUS_SRC) != OP_STATUS_SRC || | 647 | if (!cyapa->operational || cyapa->ops->irq_handler(cyapa)) { |
705 | (data.device_status & OP_STATUS_DEV) != CYAPA_DEV_NORMAL || | 648 | if (!mutex_trylock(&cyapa->state_sync_lock)) { |
706 | (data.finger_btn & OP_DATA_VALID) != OP_DATA_VALID) { | 649 | cyapa->ops->sort_empty_output_data(cyapa, |
707 | goto out; | 650 | NULL, NULL, NULL); |
651 | goto out; | ||
652 | } | ||
653 | cyapa_reinitialize(cyapa); | ||
654 | mutex_unlock(&cyapa->state_sync_lock); | ||
655 | } | ||
708 | } | 656 | } |
709 | 657 | ||
710 | num_fingers = (data.finger_btn >> 4) & 0x0f; | 658 | out: |
711 | for (i = 0; i < num_fingers; i++) { | 659 | pm_runtime_mark_last_busy(dev); |
712 | const struct cyapa_touch *touch = &data.touches[i]; | 660 | pm_runtime_put_sync_autosuspend(dev); |
713 | /* Note: touch->id range is 1 to 15; slots are 0 to 14. */ | 661 | return IRQ_HANDLED; |
714 | int slot = touch->id - 1; | 662 | } |
663 | |||
664 | /* | ||
665 | ************************************************************** | ||
666 | * sysfs interface | ||
667 | ************************************************************** | ||
668 | */ | ||
669 | #ifdef CONFIG_PM_SLEEP | ||
670 | static ssize_t cyapa_show_suspend_scanrate(struct device *dev, | ||
671 | struct device_attribute *attr, | ||
672 | char *buf) | ||
673 | { | ||
674 | struct cyapa *cyapa = dev_get_drvdata(dev); | ||
675 | u8 pwr_cmd = cyapa->suspend_power_mode; | ||
676 | u16 sleep_time; | ||
677 | int len; | ||
678 | int error; | ||
679 | |||
680 | error = mutex_lock_interruptible(&cyapa->state_sync_lock); | ||
681 | if (error) | ||
682 | return error; | ||
683 | |||
684 | pwr_cmd = cyapa->suspend_power_mode; | ||
685 | sleep_time = cyapa->suspend_sleep_time; | ||
686 | |||
687 | mutex_unlock(&cyapa->state_sync_lock); | ||
688 | |||
689 | switch (pwr_cmd) { | ||
690 | case PWR_MODE_BTN_ONLY: | ||
691 | len = scnprintf(buf, PAGE_SIZE, "%s\n", BTN_ONLY_MODE_NAME); | ||
692 | break; | ||
715 | 693 | ||
716 | input_mt_slot(input, slot); | 694 | case PWR_MODE_OFF: |
717 | input_mt_report_slot_state(input, MT_TOOL_FINGER, true); | 695 | len = scnprintf(buf, PAGE_SIZE, "%s\n", OFF_MODE_NAME); |
718 | input_report_abs(input, ABS_MT_POSITION_X, | 696 | break; |
719 | ((touch->xy_hi & 0xf0) << 4) | touch->x_lo); | 697 | |
720 | input_report_abs(input, ABS_MT_POSITION_Y, | 698 | default: |
721 | ((touch->xy_hi & 0x0f) << 8) | touch->y_lo); | 699 | len = scnprintf(buf, PAGE_SIZE, "%u\n", |
722 | input_report_abs(input, ABS_MT_PRESSURE, touch->pressure); | 700 | cyapa->gen == CYAPA_GEN3 ? |
701 | cyapa_pwr_cmd_to_sleep_time(pwr_cmd) : | ||
702 | sleep_time); | ||
703 | break; | ||
723 | } | 704 | } |
724 | 705 | ||
725 | input_mt_sync_frame(input); | 706 | return len; |
707 | } | ||
726 | 708 | ||
727 | if (cyapa->btn_capability & CAPABILITY_LEFT_BTN_MASK) | 709 | static ssize_t cyapa_update_suspend_scanrate(struct device *dev, |
728 | input_report_key(input, BTN_LEFT, | 710 | struct device_attribute *attr, |
729 | data.finger_btn & OP_DATA_LEFT_BTN); | 711 | const char *buf, size_t count) |
712 | { | ||
713 | struct cyapa *cyapa = dev_get_drvdata(dev); | ||
714 | u16 sleep_time; | ||
715 | int error; | ||
730 | 716 | ||
731 | if (cyapa->btn_capability & CAPABILITY_MIDDLE_BTN_MASK) | 717 | error = mutex_lock_interruptible(&cyapa->state_sync_lock); |
732 | input_report_key(input, BTN_MIDDLE, | 718 | if (error) |
733 | data.finger_btn & OP_DATA_MIDDLE_BTN); | 719 | return error; |
734 | 720 | ||
735 | if (cyapa->btn_capability & CAPABILITY_RIGHT_BTN_MASK) | 721 | if (sysfs_streq(buf, BTN_ONLY_MODE_NAME)) { |
736 | input_report_key(input, BTN_RIGHT, | 722 | cyapa->suspend_power_mode = PWR_MODE_BTN_ONLY; |
737 | data.finger_btn & OP_DATA_RIGHT_BTN); | 723 | } else if (sysfs_streq(buf, OFF_MODE_NAME)) { |
724 | cyapa->suspend_power_mode = PWR_MODE_OFF; | ||
725 | } else if (!kstrtou16(buf, 10, &sleep_time)) { | ||
726 | cyapa->suspend_sleep_time = max_t(u16, sleep_time, 1000); | ||
727 | cyapa->suspend_power_mode = | ||
728 | cyapa_sleep_time_to_pwr_cmd(cyapa->suspend_sleep_time); | ||
729 | } else { | ||
730 | count = -EINVAL; | ||
731 | } | ||
738 | 732 | ||
739 | input_sync(input); | 733 | mutex_unlock(&cyapa->state_sync_lock); |
740 | 734 | ||
741 | out: | 735 | return count; |
742 | return IRQ_HANDLED; | ||
743 | } | 736 | } |
744 | 737 | ||
745 | static u8 cyapa_check_adapter_functionality(struct i2c_client *client) | 738 | static DEVICE_ATTR(suspend_scanrate_ms, S_IRUGO|S_IWUSR, |
739 | cyapa_show_suspend_scanrate, | ||
740 | cyapa_update_suspend_scanrate); | ||
741 | |||
742 | static struct attribute *cyapa_power_wakeup_entries[] = { | ||
743 | &dev_attr_suspend_scanrate_ms.attr, | ||
744 | NULL, | ||
745 | }; | ||
746 | |||
747 | static const struct attribute_group cyapa_power_wakeup_group = { | ||
748 | .name = power_group_name, | ||
749 | .attrs = cyapa_power_wakeup_entries, | ||
750 | }; | ||
751 | |||
752 | static void cyapa_remove_power_wakeup_group(void *data) | ||
746 | { | 753 | { |
747 | u8 ret = CYAPA_ADAPTER_FUNC_NONE; | 754 | struct cyapa *cyapa = data; |
748 | 755 | ||
749 | if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) | 756 | sysfs_unmerge_group(&cyapa->client->dev.kobj, |
750 | ret |= CYAPA_ADAPTER_FUNC_I2C; | 757 | &cyapa_power_wakeup_group); |
751 | if (i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA | | ||
752 | I2C_FUNC_SMBUS_BLOCK_DATA | | ||
753 | I2C_FUNC_SMBUS_I2C_BLOCK)) | ||
754 | ret |= CYAPA_ADAPTER_FUNC_SMBUS; | ||
755 | return ret; | ||
756 | } | 758 | } |
757 | 759 | ||
758 | static int cyapa_open(struct input_dev *input) | 760 | static int cyapa_prepare_wakeup_controls(struct cyapa *cyapa) |
759 | { | 761 | { |
760 | struct cyapa *cyapa = input_get_drvdata(input); | ||
761 | struct i2c_client *client = cyapa->client; | 762 | struct i2c_client *client = cyapa->client; |
763 | struct device *dev = &client->dev; | ||
764 | int error; | ||
765 | |||
766 | if (device_can_wakeup(dev)) { | ||
767 | error = sysfs_merge_group(&client->dev.kobj, | ||
768 | &cyapa_power_wakeup_group); | ||
769 | if (error) { | ||
770 | dev_err(dev, "failed to add power wakeup group: %d\n", | ||
771 | error); | ||
772 | return error; | ||
773 | } | ||
774 | |||
775 | error = devm_add_action(dev, | ||
776 | cyapa_remove_power_wakeup_group, cyapa); | ||
777 | if (error) { | ||
778 | cyapa_remove_power_wakeup_group(cyapa); | ||
779 | dev_err(dev, "failed to add power cleanup action: %d\n", | ||
780 | error); | ||
781 | return error; | ||
782 | } | ||
783 | } | ||
784 | |||
785 | return 0; | ||
786 | } | ||
787 | #else | ||
788 | static inline int cyapa_prepare_wakeup_controls(struct cyapa *cyapa) | ||
789 | { | ||
790 | return 0; | ||
791 | } | ||
792 | #endif /* CONFIG_PM_SLEEP */ | ||
793 | |||
794 | #ifdef CONFIG_PM | ||
795 | static ssize_t cyapa_show_rt_suspend_scanrate(struct device *dev, | ||
796 | struct device_attribute *attr, | ||
797 | char *buf) | ||
798 | { | ||
799 | struct cyapa *cyapa = dev_get_drvdata(dev); | ||
800 | u8 pwr_cmd; | ||
801 | u16 sleep_time; | ||
802 | int error; | ||
803 | |||
804 | error = mutex_lock_interruptible(&cyapa->state_sync_lock); | ||
805 | if (error) | ||
806 | return error; | ||
807 | |||
808 | pwr_cmd = cyapa->runtime_suspend_power_mode; | ||
809 | sleep_time = cyapa->runtime_suspend_sleep_time; | ||
810 | |||
811 | mutex_unlock(&cyapa->state_sync_lock); | ||
812 | |||
813 | return scnprintf(buf, PAGE_SIZE, "%u\n", | ||
814 | cyapa->gen == CYAPA_GEN3 ? | ||
815 | cyapa_pwr_cmd_to_sleep_time(pwr_cmd) : | ||
816 | sleep_time); | ||
817 | } | ||
818 | |||
819 | static ssize_t cyapa_update_rt_suspend_scanrate(struct device *dev, | ||
820 | struct device_attribute *attr, | ||
821 | const char *buf, size_t count) | ||
822 | { | ||
823 | struct cyapa *cyapa = dev_get_drvdata(dev); | ||
824 | u16 time; | ||
825 | int error; | ||
826 | |||
827 | if (buf == NULL || count == 0 || kstrtou16(buf, 10, &time)) { | ||
828 | dev_err(dev, "invalid runtime suspend scanrate ms parameter\n"); | ||
829 | return -EINVAL; | ||
830 | } | ||
831 | |||
832 | /* | ||
833 | * When the suspend scanrate is changed, pm_runtime_get to resume | ||
834 | * a potentially suspended device, update to the new pwr_cmd | ||
835 | * and then pm_runtime_put to suspend into the new power mode. | ||
836 | */ | ||
837 | pm_runtime_get_sync(dev); | ||
838 | |||
839 | error = mutex_lock_interruptible(&cyapa->state_sync_lock); | ||
840 | if (error) | ||
841 | return error; | ||
842 | |||
843 | cyapa->runtime_suspend_sleep_time = max_t(u16, time, 1000); | ||
844 | cyapa->runtime_suspend_power_mode = | ||
845 | cyapa_sleep_time_to_pwr_cmd(cyapa->runtime_suspend_sleep_time); | ||
846 | |||
847 | mutex_unlock(&cyapa->state_sync_lock); | ||
848 | |||
849 | pm_runtime_put_sync_autosuspend(dev); | ||
850 | |||
851 | return count; | ||
852 | } | ||
853 | |||
854 | static DEVICE_ATTR(runtime_suspend_scanrate_ms, S_IRUGO|S_IWUSR, | ||
855 | cyapa_show_rt_suspend_scanrate, | ||
856 | cyapa_update_rt_suspend_scanrate); | ||
857 | |||
858 | static struct attribute *cyapa_power_runtime_entries[] = { | ||
859 | &dev_attr_runtime_suspend_scanrate_ms.attr, | ||
860 | NULL, | ||
861 | }; | ||
862 | |||
863 | static const struct attribute_group cyapa_power_runtime_group = { | ||
864 | .name = power_group_name, | ||
865 | .attrs = cyapa_power_runtime_entries, | ||
866 | }; | ||
867 | |||
868 | static void cyapa_remove_power_runtime_group(void *data) | ||
869 | { | ||
870 | struct cyapa *cyapa = data; | ||
871 | |||
872 | sysfs_unmerge_group(&cyapa->client->dev.kobj, | ||
873 | &cyapa_power_runtime_group); | ||
874 | } | ||
875 | |||
876 | static int cyapa_start_runtime(struct cyapa *cyapa) | ||
877 | { | ||
878 | struct device *dev = &cyapa->client->dev; | ||
762 | int error; | 879 | int error; |
763 | 880 | ||
764 | error = cyapa_set_power_mode(cyapa, PWR_MODE_FULL_ACTIVE); | 881 | cyapa->runtime_suspend_power_mode = PWR_MODE_IDLE; |
882 | cyapa->runtime_suspend_sleep_time = | ||
883 | cyapa_pwr_cmd_to_sleep_time(cyapa->runtime_suspend_power_mode); | ||
884 | |||
885 | error = sysfs_merge_group(&dev->kobj, &cyapa_power_runtime_group); | ||
765 | if (error) { | 886 | if (error) { |
766 | dev_err(&client->dev, "set active power failed: %d\n", error); | 887 | dev_err(dev, |
888 | "failed to create power runtime group: %d\n", error); | ||
767 | return error; | 889 | return error; |
768 | } | 890 | } |
769 | 891 | ||
770 | enable_irq(client->irq); | 892 | error = devm_add_action(dev, cyapa_remove_power_runtime_group, cyapa); |
893 | if (error) { | ||
894 | cyapa_remove_power_runtime_group(cyapa); | ||
895 | dev_err(dev, | ||
896 | "failed to add power runtime cleanup action: %d\n", | ||
897 | error); | ||
898 | return error; | ||
899 | } | ||
900 | |||
901 | /* runtime is enabled until device is operational and opened. */ | ||
902 | pm_runtime_set_suspended(dev); | ||
903 | pm_runtime_use_autosuspend(dev); | ||
904 | pm_runtime_set_autosuspend_delay(dev, AUTOSUSPEND_DELAY); | ||
905 | |||
771 | return 0; | 906 | return 0; |
772 | } | 907 | } |
908 | #else | ||
909 | static inline int cyapa_start_runtime(struct cyapa *cyapa) | ||
910 | { | ||
911 | return 0; | ||
912 | } | ||
913 | #endif /* CONFIG_PM */ | ||
773 | 914 | ||
774 | static void cyapa_close(struct input_dev *input) | 915 | static ssize_t cyapa_show_fm_ver(struct device *dev, |
916 | struct device_attribute *attr, char *buf) | ||
775 | { | 917 | { |
776 | struct cyapa *cyapa = input_get_drvdata(input); | 918 | int error; |
919 | struct cyapa *cyapa = dev_get_drvdata(dev); | ||
777 | 920 | ||
778 | disable_irq(cyapa->client->irq); | 921 | error = mutex_lock_interruptible(&cyapa->state_sync_lock); |
779 | cyapa_set_power_mode(cyapa, PWR_MODE_OFF); | 922 | if (error) |
923 | return error; | ||
924 | error = scnprintf(buf, PAGE_SIZE, "%d.%d\n", cyapa->fw_maj_ver, | ||
925 | cyapa->fw_min_ver); | ||
926 | mutex_unlock(&cyapa->state_sync_lock); | ||
927 | return error; | ||
780 | } | 928 | } |
781 | 929 | ||
782 | static int cyapa_create_input_dev(struct cyapa *cyapa) | 930 | static ssize_t cyapa_show_product_id(struct device *dev, |
931 | struct device_attribute *attr, char *buf) | ||
932 | { | ||
933 | struct cyapa *cyapa = dev_get_drvdata(dev); | ||
934 | int size; | ||
935 | int error; | ||
936 | |||
937 | error = mutex_lock_interruptible(&cyapa->state_sync_lock); | ||
938 | if (error) | ||
939 | return error; | ||
940 | size = scnprintf(buf, PAGE_SIZE, "%s\n", cyapa->product_id); | ||
941 | mutex_unlock(&cyapa->state_sync_lock); | ||
942 | return size; | ||
943 | } | ||
944 | |||
945 | static int cyapa_firmware(struct cyapa *cyapa, const char *fw_name) | ||
783 | { | 946 | { |
784 | struct device *dev = &cyapa->client->dev; | 947 | struct device *dev = &cyapa->client->dev; |
785 | struct input_dev *input; | 948 | const struct firmware *fw; |
786 | int error; | 949 | int error; |
787 | 950 | ||
788 | if (!cyapa->physical_size_x || !cyapa->physical_size_y) | 951 | error = request_firmware(&fw, fw_name, dev); |
789 | return -EINVAL; | 952 | if (error) { |
953 | dev_err(dev, "Could not load firmware from %s: %d\n", | ||
954 | fw_name, error); | ||
955 | return error; | ||
956 | } | ||
790 | 957 | ||
791 | input = devm_input_allocate_device(dev); | 958 | error = cyapa->ops->check_fw(cyapa, fw); |
792 | if (!input) { | 959 | if (error) { |
793 | dev_err(dev, "failed to allocate memory for input device.\n"); | 960 | dev_err(dev, "Invalid CYAPA firmware image: %s\n", |
794 | return -ENOMEM; | 961 | fw_name); |
962 | goto done; | ||
795 | } | 963 | } |
796 | 964 | ||
797 | input->name = CYAPA_NAME; | 965 | /* |
798 | input->phys = cyapa->phys; | 966 | * Resume the potentially suspended device because doing FW |
799 | input->id.bustype = BUS_I2C; | 967 | * update on a device not in the FULL mode has a chance to |
800 | input->id.version = 1; | 968 | * fail. |
801 | input->id.product = 0; /* Means any product in eventcomm. */ | 969 | */ |
802 | input->dev.parent = &cyapa->client->dev; | 970 | pm_runtime_get_sync(dev); |
803 | 971 | ||
804 | input->open = cyapa_open; | 972 | /* Require IRQ support for firmware update commands. */ |
805 | input->close = cyapa_close; | 973 | cyapa_enable_irq_for_cmd(cyapa); |
806 | 974 | ||
807 | input_set_drvdata(input, cyapa); | 975 | error = cyapa->ops->bl_enter(cyapa); |
976 | if (error) { | ||
977 | dev_err(dev, "bl_enter failed, %d\n", error); | ||
978 | goto err_detect; | ||
979 | } | ||
808 | 980 | ||
809 | __set_bit(EV_ABS, input->evbit); | 981 | error = cyapa->ops->bl_activate(cyapa); |
982 | if (error) { | ||
983 | dev_err(dev, "bl_activate failed, %d\n", error); | ||
984 | goto err_detect; | ||
985 | } | ||
810 | 986 | ||
811 | /* Finger position */ | 987 | error = cyapa->ops->bl_initiate(cyapa, fw); |
812 | input_set_abs_params(input, ABS_MT_POSITION_X, 0, cyapa->max_abs_x, 0, | 988 | if (error) { |
813 | 0); | 989 | dev_err(dev, "bl_initiate failed, %d\n", error); |
814 | input_set_abs_params(input, ABS_MT_POSITION_Y, 0, cyapa->max_abs_y, 0, | 990 | goto err_detect; |
815 | 0); | 991 | } |
816 | input_set_abs_params(input, ABS_MT_PRESSURE, 0, 255, 0, 0); | ||
817 | 992 | ||
818 | input_abs_set_res(input, ABS_MT_POSITION_X, | 993 | error = cyapa->ops->update_fw(cyapa, fw); |
819 | cyapa->max_abs_x / cyapa->physical_size_x); | 994 | if (error) { |
820 | input_abs_set_res(input, ABS_MT_POSITION_Y, | 995 | dev_err(dev, "update_fw failed, %d\n", error); |
821 | cyapa->max_abs_y / cyapa->physical_size_y); | 996 | goto err_detect; |
997 | } | ||
822 | 998 | ||
823 | if (cyapa->btn_capability & CAPABILITY_LEFT_BTN_MASK) | 999 | err_detect: |
824 | __set_bit(BTN_LEFT, input->keybit); | 1000 | cyapa_disable_irq_for_cmd(cyapa); |
825 | if (cyapa->btn_capability & CAPABILITY_MIDDLE_BTN_MASK) | 1001 | pm_runtime_put_noidle(dev); |
826 | __set_bit(BTN_MIDDLE, input->keybit); | ||
827 | if (cyapa->btn_capability & CAPABILITY_RIGHT_BTN_MASK) | ||
828 | __set_bit(BTN_RIGHT, input->keybit); | ||
829 | 1002 | ||
830 | if (cyapa->btn_capability == CAPABILITY_LEFT_BTN_MASK) | 1003 | done: |
831 | __set_bit(INPUT_PROP_BUTTONPAD, input->propbit); | 1004 | release_firmware(fw); |
1005 | return error; | ||
1006 | } | ||
832 | 1007 | ||
833 | /* Handle pointer emulation and unused slots in core */ | 1008 | static ssize_t cyapa_update_fw_store(struct device *dev, |
834 | error = input_mt_init_slots(input, CYAPA_MAX_MT_SLOTS, | 1009 | struct device_attribute *attr, |
835 | INPUT_MT_POINTER | INPUT_MT_DROP_UNUSED); | 1010 | const char *buf, size_t count) |
1011 | { | ||
1012 | struct cyapa *cyapa = dev_get_drvdata(dev); | ||
1013 | char fw_name[NAME_MAX]; | ||
1014 | int ret, error; | ||
1015 | |||
1016 | if (count >= NAME_MAX) { | ||
1017 | dev_err(dev, "File name too long\n"); | ||
1018 | return -EINVAL; | ||
1019 | } | ||
1020 | |||
1021 | memcpy(fw_name, buf, count); | ||
1022 | if (fw_name[count - 1] == '\n') | ||
1023 | fw_name[count - 1] = '\0'; | ||
1024 | else | ||
1025 | fw_name[count] = '\0'; | ||
1026 | |||
1027 | if (cyapa->input) { | ||
1028 | /* | ||
1029 | * Force the input device to be registered after the firmware | ||
1030 | * image is updated, so if the corresponding parameters updated | ||
1031 | * in the new firmware image can taken effect immediately. | ||
1032 | */ | ||
1033 | input_unregister_device(cyapa->input); | ||
1034 | cyapa->input = NULL; | ||
1035 | } | ||
1036 | |||
1037 | error = mutex_lock_interruptible(&cyapa->state_sync_lock); | ||
836 | if (error) { | 1038 | if (error) { |
837 | dev_err(dev, "failed to initialize MT slots: %d\n", error); | 1039 | /* |
1040 | * Whatever, do reinitialize to try to recover TP state to | ||
1041 | * previous state just as it entered fw update entrance. | ||
1042 | */ | ||
1043 | cyapa_reinitialize(cyapa); | ||
838 | return error; | 1044 | return error; |
839 | } | 1045 | } |
840 | 1046 | ||
841 | cyapa->input = input; | 1047 | error = cyapa_firmware(cyapa, fw_name); |
842 | return 0; | 1048 | if (error) |
1049 | dev_err(dev, "firmware update failed: %d\n", error); | ||
1050 | else | ||
1051 | dev_dbg(dev, "firmware update successfully done.\n"); | ||
1052 | |||
1053 | /* | ||
1054 | * Redetect trackpad device states because firmware update process | ||
1055 | * will reset trackpad device into bootloader mode. | ||
1056 | */ | ||
1057 | ret = cyapa_reinitialize(cyapa); | ||
1058 | if (ret) { | ||
1059 | dev_err(dev, "failed to redetect after updated: %d\n", ret); | ||
1060 | error = error ? error : ret; | ||
1061 | } | ||
1062 | |||
1063 | mutex_unlock(&cyapa->state_sync_lock); | ||
1064 | |||
1065 | return error ? error : count; | ||
1066 | } | ||
1067 | |||
1068 | static ssize_t cyapa_calibrate_store(struct device *dev, | ||
1069 | struct device_attribute *attr, | ||
1070 | const char *buf, size_t count) | ||
1071 | { | ||
1072 | struct cyapa *cyapa = dev_get_drvdata(dev); | ||
1073 | int error; | ||
1074 | |||
1075 | error = mutex_lock_interruptible(&cyapa->state_sync_lock); | ||
1076 | if (error) | ||
1077 | return error; | ||
1078 | |||
1079 | if (cyapa->operational) { | ||
1080 | cyapa_enable_irq_for_cmd(cyapa); | ||
1081 | error = cyapa->ops->calibrate_store(dev, attr, buf, count); | ||
1082 | cyapa_disable_irq_for_cmd(cyapa); | ||
1083 | } else { | ||
1084 | error = -EBUSY; /* Still running in bootloader mode. */ | ||
1085 | } | ||
1086 | |||
1087 | mutex_unlock(&cyapa->state_sync_lock); | ||
1088 | return error < 0 ? error : count; | ||
1089 | } | ||
1090 | |||
1091 | static ssize_t cyapa_show_baseline(struct device *dev, | ||
1092 | struct device_attribute *attr, char *buf) | ||
1093 | { | ||
1094 | struct cyapa *cyapa = dev_get_drvdata(dev); | ||
1095 | ssize_t error; | ||
1096 | |||
1097 | error = mutex_lock_interruptible(&cyapa->state_sync_lock); | ||
1098 | if (error) | ||
1099 | return error; | ||
1100 | |||
1101 | if (cyapa->operational) { | ||
1102 | cyapa_enable_irq_for_cmd(cyapa); | ||
1103 | error = cyapa->ops->show_baseline(dev, attr, buf); | ||
1104 | cyapa_disable_irq_for_cmd(cyapa); | ||
1105 | } else { | ||
1106 | error = -EBUSY; /* Still running in bootloader mode. */ | ||
1107 | } | ||
1108 | |||
1109 | mutex_unlock(&cyapa->state_sync_lock); | ||
1110 | return error; | ||
1111 | } | ||
1112 | |||
1113 | static char *cyapa_state_to_string(struct cyapa *cyapa) | ||
1114 | { | ||
1115 | switch (cyapa->state) { | ||
1116 | case CYAPA_STATE_BL_BUSY: | ||
1117 | return "bootloader busy"; | ||
1118 | case CYAPA_STATE_BL_IDLE: | ||
1119 | return "bootloader idle"; | ||
1120 | case CYAPA_STATE_BL_ACTIVE: | ||
1121 | return "bootloader active"; | ||
1122 | case CYAPA_STATE_GEN5_BL: | ||
1123 | return "bootloader"; | ||
1124 | case CYAPA_STATE_OP: | ||
1125 | case CYAPA_STATE_GEN5_APP: | ||
1126 | return "operational"; /* Normal valid state. */ | ||
1127 | default: | ||
1128 | return "invalid mode"; | ||
1129 | } | ||
1130 | } | ||
1131 | |||
1132 | static ssize_t cyapa_show_mode(struct device *dev, | ||
1133 | struct device_attribute *attr, char *buf) | ||
1134 | { | ||
1135 | struct cyapa *cyapa = dev_get_drvdata(dev); | ||
1136 | int size; | ||
1137 | int error; | ||
1138 | |||
1139 | error = mutex_lock_interruptible(&cyapa->state_sync_lock); | ||
1140 | if (error) | ||
1141 | return error; | ||
1142 | |||
1143 | size = scnprintf(buf, PAGE_SIZE, "gen%d %s\n", | ||
1144 | cyapa->gen, cyapa_state_to_string(cyapa)); | ||
1145 | |||
1146 | mutex_unlock(&cyapa->state_sync_lock); | ||
1147 | return size; | ||
1148 | } | ||
1149 | |||
1150 | static DEVICE_ATTR(firmware_version, S_IRUGO, cyapa_show_fm_ver, NULL); | ||
1151 | static DEVICE_ATTR(product_id, S_IRUGO, cyapa_show_product_id, NULL); | ||
1152 | static DEVICE_ATTR(update_fw, S_IWUSR, NULL, cyapa_update_fw_store); | ||
1153 | static DEVICE_ATTR(baseline, S_IRUGO, cyapa_show_baseline, NULL); | ||
1154 | static DEVICE_ATTR(calibrate, S_IWUSR, NULL, cyapa_calibrate_store); | ||
1155 | static DEVICE_ATTR(mode, S_IRUGO, cyapa_show_mode, NULL); | ||
1156 | |||
1157 | static struct attribute *cyapa_sysfs_entries[] = { | ||
1158 | &dev_attr_firmware_version.attr, | ||
1159 | &dev_attr_product_id.attr, | ||
1160 | &dev_attr_update_fw.attr, | ||
1161 | &dev_attr_baseline.attr, | ||
1162 | &dev_attr_calibrate.attr, | ||
1163 | &dev_attr_mode.attr, | ||
1164 | NULL, | ||
1165 | }; | ||
1166 | |||
1167 | static const struct attribute_group cyapa_sysfs_group = { | ||
1168 | .attrs = cyapa_sysfs_entries, | ||
1169 | }; | ||
1170 | |||
1171 | static void cyapa_remove_sysfs_group(void *data) | ||
1172 | { | ||
1173 | struct cyapa *cyapa = data; | ||
1174 | |||
1175 | sysfs_remove_group(&cyapa->client->dev.kobj, &cyapa_sysfs_group); | ||
843 | } | 1176 | } |
844 | 1177 | ||
845 | static int cyapa_probe(struct i2c_client *client, | 1178 | static int cyapa_probe(struct i2c_client *client, |
@@ -848,6 +1181,7 @@ static int cyapa_probe(struct i2c_client *client, | |||
848 | struct device *dev = &client->dev; | 1181 | struct device *dev = &client->dev; |
849 | struct cyapa *cyapa; | 1182 | struct cyapa *cyapa; |
850 | u8 adapter_func; | 1183 | u8 adapter_func; |
1184 | union i2c_smbus_data dummy; | ||
851 | int error; | 1185 | int error; |
852 | 1186 | ||
853 | adapter_func = cyapa_check_adapter_functionality(client); | 1187 | adapter_func = cyapa_check_adapter_functionality(client); |
@@ -856,38 +1190,54 @@ static int cyapa_probe(struct i2c_client *client, | |||
856 | return -EIO; | 1190 | return -EIO; |
857 | } | 1191 | } |
858 | 1192 | ||
1193 | /* Make sure there is something at this address */ | ||
1194 | if (i2c_smbus_xfer(client->adapter, client->addr, 0, | ||
1195 | I2C_SMBUS_READ, 0, I2C_SMBUS_BYTE, &dummy) < 0) | ||
1196 | return -ENODEV; | ||
1197 | |||
859 | cyapa = devm_kzalloc(dev, sizeof(struct cyapa), GFP_KERNEL); | 1198 | cyapa = devm_kzalloc(dev, sizeof(struct cyapa), GFP_KERNEL); |
860 | if (!cyapa) | 1199 | if (!cyapa) |
861 | return -ENOMEM; | 1200 | return -ENOMEM; |
862 | 1201 | ||
863 | cyapa->gen = CYAPA_GEN3; | 1202 | /* i2c isn't supported, use smbus */ |
1203 | if (adapter_func == CYAPA_ADAPTER_FUNC_SMBUS) | ||
1204 | cyapa->smbus = true; | ||
1205 | |||
864 | cyapa->client = client; | 1206 | cyapa->client = client; |
865 | i2c_set_clientdata(client, cyapa); | 1207 | i2c_set_clientdata(client, cyapa); |
866 | sprintf(cyapa->phys, "i2c-%d-%04x/input0", client->adapter->nr, | 1208 | sprintf(cyapa->phys, "i2c-%d-%04x/input0", client->adapter->nr, |
867 | client->addr); | 1209 | client->addr); |
868 | 1210 | ||
869 | /* i2c isn't supported, use smbus */ | 1211 | error = cyapa_initialize(cyapa); |
870 | if (adapter_func == CYAPA_ADAPTER_FUNC_SMBUS) | 1212 | if (error) { |
871 | cyapa->smbus = true; | 1213 | dev_err(dev, "failed to detect and initialize tp device.\n"); |
1214 | return error; | ||
1215 | } | ||
872 | 1216 | ||
873 | cyapa->state = CYAPA_STATE_NO_DEVICE; | 1217 | error = sysfs_create_group(&client->dev.kobj, &cyapa_sysfs_group); |
1218 | if (error) { | ||
1219 | dev_err(dev, "failed to create sysfs entries: %d\n", error); | ||
1220 | return error; | ||
1221 | } | ||
874 | 1222 | ||
875 | error = cyapa_check_is_operational(cyapa); | 1223 | error = devm_add_action(dev, cyapa_remove_sysfs_group, cyapa); |
876 | if (error) { | 1224 | if (error) { |
877 | dev_err(dev, "device not operational, %d\n", error); | 1225 | cyapa_remove_sysfs_group(cyapa); |
1226 | dev_err(dev, "failed to add sysfs cleanup action: %d\n", error); | ||
878 | return error; | 1227 | return error; |
879 | } | 1228 | } |
880 | 1229 | ||
881 | /* Power down the device until we need it */ | 1230 | error = cyapa_prepare_wakeup_controls(cyapa); |
882 | error = cyapa_set_power_mode(cyapa, PWR_MODE_OFF); | ||
883 | if (error) { | 1231 | if (error) { |
884 | dev_err(dev, "failed to quiesce the device: %d\n", error); | 1232 | dev_err(dev, "failed to prepare wakeup controls: %d\n", error); |
885 | return error; | 1233 | return error; |
886 | } | 1234 | } |
887 | 1235 | ||
888 | error = cyapa_create_input_dev(cyapa); | 1236 | error = cyapa_start_runtime(cyapa); |
889 | if (error) | 1237 | if (error) { |
1238 | dev_err(dev, "failed to start pm_runtime: %d\n", error); | ||
890 | return error; | 1239 | return error; |
1240 | } | ||
891 | 1241 | ||
892 | error = devm_request_threaded_irq(dev, client->irq, | 1242 | error = devm_request_threaded_irq(dev, client->irq, |
893 | NULL, cyapa_irq, | 1243 | NULL, cyapa_irq, |
@@ -901,11 +1251,18 @@ static int cyapa_probe(struct i2c_client *client, | |||
901 | /* Disable IRQ until the device is opened */ | 1251 | /* Disable IRQ until the device is opened */ |
902 | disable_irq(client->irq); | 1252 | disable_irq(client->irq); |
903 | 1253 | ||
904 | /* Register the device in input subsystem */ | 1254 | /* |
905 | error = input_register_device(cyapa->input); | 1255 | * Register the device in the input subsystem when it's operational. |
906 | if (error) { | 1256 | * Otherwise, keep in this driver, so it can be be recovered or updated |
907 | dev_err(dev, "failed to register input device: %d\n", error); | 1257 | * through the sysfs mode and update_fw interfaces by user or apps. |
908 | return error; | 1258 | */ |
1259 | if (cyapa->operational) { | ||
1260 | error = cyapa_create_input_dev(cyapa); | ||
1261 | if (error) { | ||
1262 | dev_err(dev, "create input_dev instance failed: %d\n", | ||
1263 | error); | ||
1264 | return error; | ||
1265 | } | ||
909 | } | 1266 | } |
910 | 1267 | ||
911 | return 0; | 1268 | return 0; |
@@ -915,32 +1272,40 @@ static int __maybe_unused cyapa_suspend(struct device *dev) | |||
915 | { | 1272 | { |
916 | struct i2c_client *client = to_i2c_client(dev); | 1273 | struct i2c_client *client = to_i2c_client(dev); |
917 | struct cyapa *cyapa = i2c_get_clientdata(client); | 1274 | struct cyapa *cyapa = i2c_get_clientdata(client); |
918 | struct input_dev *input = cyapa->input; | ||
919 | u8 power_mode; | 1275 | u8 power_mode; |
920 | int error; | 1276 | int error; |
921 | 1277 | ||
922 | error = mutex_lock_interruptible(&input->mutex); | 1278 | error = mutex_lock_interruptible(&cyapa->state_sync_lock); |
923 | if (error) | 1279 | if (error) |
924 | return error; | 1280 | return error; |
925 | 1281 | ||
1282 | /* | ||
1283 | * Runtime PM is enable only when device is in operational mode and | ||
1284 | * users in use, so need check it before disable it to | ||
1285 | * avoid unbalance warning. | ||
1286 | */ | ||
1287 | if (pm_runtime_enabled(dev)) | ||
1288 | pm_runtime_disable(dev); | ||
926 | disable_irq(client->irq); | 1289 | disable_irq(client->irq); |
927 | 1290 | ||
928 | /* | 1291 | /* |
929 | * Set trackpad device to idle mode if wakeup is allowed, | 1292 | * Set trackpad device to idle mode if wakeup is allowed, |
930 | * otherwise turn off. | 1293 | * otherwise turn off. |
931 | */ | 1294 | */ |
932 | power_mode = device_may_wakeup(dev) ? PWR_MODE_IDLE | 1295 | if (cyapa->operational) { |
933 | : PWR_MODE_OFF; | 1296 | power_mode = device_may_wakeup(dev) ? cyapa->suspend_power_mode |
934 | error = cyapa_set_power_mode(cyapa, power_mode); | 1297 | : PWR_MODE_OFF; |
935 | if (error) | 1298 | error = cyapa->ops->set_power_mode(cyapa, power_mode, |
936 | dev_err(dev, "resume: set power mode to %d failed: %d\n", | 1299 | cyapa->suspend_sleep_time); |
937 | power_mode, error); | 1300 | if (error) |
1301 | dev_err(dev, "suspend set power mode failed: %d\n", | ||
1302 | error); | ||
1303 | } | ||
938 | 1304 | ||
939 | if (device_may_wakeup(dev)) | 1305 | if (device_may_wakeup(dev)) |
940 | cyapa->irq_wake = (enable_irq_wake(client->irq) == 0); | 1306 | cyapa->irq_wake = (enable_irq_wake(client->irq) == 0); |
941 | 1307 | ||
942 | mutex_unlock(&input->mutex); | 1308 | mutex_unlock(&cyapa->state_sync_lock); |
943 | |||
944 | return 0; | 1309 | return 0; |
945 | } | 1310 | } |
946 | 1311 | ||
@@ -948,29 +1313,56 @@ static int __maybe_unused cyapa_resume(struct device *dev) | |||
948 | { | 1313 | { |
949 | struct i2c_client *client = to_i2c_client(dev); | 1314 | struct i2c_client *client = to_i2c_client(dev); |
950 | struct cyapa *cyapa = i2c_get_clientdata(client); | 1315 | struct cyapa *cyapa = i2c_get_clientdata(client); |
951 | struct input_dev *input = cyapa->input; | ||
952 | u8 power_mode; | ||
953 | int error; | 1316 | int error; |
954 | 1317 | ||
955 | mutex_lock(&input->mutex); | 1318 | mutex_lock(&cyapa->state_sync_lock); |
956 | 1319 | ||
957 | if (device_may_wakeup(dev) && cyapa->irq_wake) | 1320 | if (device_may_wakeup(dev) && cyapa->irq_wake) { |
958 | disable_irq_wake(client->irq); | 1321 | disable_irq_wake(client->irq); |
1322 | cyapa->irq_wake = false; | ||
1323 | } | ||
959 | 1324 | ||
960 | power_mode = input->users ? PWR_MODE_FULL_ACTIVE : PWR_MODE_OFF; | 1325 | /* Update device states and runtime PM states. */ |
961 | error = cyapa_set_power_mode(cyapa, PWR_MODE_FULL_ACTIVE); | 1326 | error = cyapa_reinitialize(cyapa); |
962 | if (error) | 1327 | if (error) |
963 | dev_warn(dev, "resume: set power mode to %d failed: %d\n", | 1328 | dev_warn(dev, "failed to reinitialize TP device: %d\n", error); |
964 | power_mode, error); | ||
965 | 1329 | ||
966 | enable_irq(client->irq); | 1330 | enable_irq(client->irq); |
967 | 1331 | ||
968 | mutex_unlock(&input->mutex); | 1332 | mutex_unlock(&cyapa->state_sync_lock); |
1333 | return 0; | ||
1334 | } | ||
1335 | |||
1336 | static int __maybe_unused cyapa_runtime_suspend(struct device *dev) | ||
1337 | { | ||
1338 | struct cyapa *cyapa = dev_get_drvdata(dev); | ||
1339 | int error; | ||
1340 | |||
1341 | error = cyapa->ops->set_power_mode(cyapa, | ||
1342 | cyapa->runtime_suspend_power_mode, | ||
1343 | cyapa->runtime_suspend_sleep_time); | ||
1344 | if (error) | ||
1345 | dev_warn(dev, "runtime suspend failed: %d\n", error); | ||
1346 | |||
1347 | return 0; | ||
1348 | } | ||
1349 | |||
1350 | static int __maybe_unused cyapa_runtime_resume(struct device *dev) | ||
1351 | { | ||
1352 | struct cyapa *cyapa = dev_get_drvdata(dev); | ||
1353 | int error; | ||
1354 | |||
1355 | error = cyapa->ops->set_power_mode(cyapa, PWR_MODE_FULL_ACTIVE, 0); | ||
1356 | if (error) | ||
1357 | dev_warn(dev, "runtime resume failed: %d\n", error); | ||
969 | 1358 | ||
970 | return 0; | 1359 | return 0; |
971 | } | 1360 | } |
972 | 1361 | ||
973 | static SIMPLE_DEV_PM_OPS(cyapa_pm_ops, cyapa_suspend, cyapa_resume); | 1362 | static const struct dev_pm_ops cyapa_pm_ops = { |
1363 | SET_SYSTEM_SLEEP_PM_OPS(cyapa_suspend, cyapa_resume) | ||
1364 | SET_RUNTIME_PM_OPS(cyapa_runtime_suspend, cyapa_runtime_resume, NULL) | ||
1365 | }; | ||
974 | 1366 | ||
975 | static const struct i2c_device_id cyapa_id_table[] = { | 1367 | static const struct i2c_device_id cyapa_id_table[] = { |
976 | { "cyapa", 0 }, | 1368 | { "cyapa", 0 }, |
@@ -978,11 +1370,21 @@ static const struct i2c_device_id cyapa_id_table[] = { | |||
978 | }; | 1370 | }; |
979 | MODULE_DEVICE_TABLE(i2c, cyapa_id_table); | 1371 | MODULE_DEVICE_TABLE(i2c, cyapa_id_table); |
980 | 1372 | ||
1373 | #ifdef CONFIG_ACPI | ||
1374 | static const struct acpi_device_id cyapa_acpi_id[] = { | ||
1375 | { "CYAP0000", 0 }, /* Gen3 trackpad with 0x67 I2C address. */ | ||
1376 | { "CYAP0001", 0 }, /* Gen5 trackpad with 0x24 I2C address. */ | ||
1377 | { } | ||
1378 | }; | ||
1379 | MODULE_DEVICE_TABLE(acpi, cyapa_acpi_id); | ||
1380 | #endif | ||
1381 | |||
981 | static struct i2c_driver cyapa_driver = { | 1382 | static struct i2c_driver cyapa_driver = { |
982 | .driver = { | 1383 | .driver = { |
983 | .name = "cyapa", | 1384 | .name = "cyapa", |
984 | .owner = THIS_MODULE, | 1385 | .owner = THIS_MODULE, |
985 | .pm = &cyapa_pm_ops, | 1386 | .pm = &cyapa_pm_ops, |
1387 | .acpi_match_table = ACPI_PTR(cyapa_acpi_id), | ||
986 | }, | 1388 | }, |
987 | 1389 | ||
988 | .probe = cyapa_probe, | 1390 | .probe = cyapa_probe, |
diff --git a/drivers/input/mouse/cyapa.h b/drivers/input/mouse/cyapa.h new file mode 100644 index 000000000000..adc9ed5dcb0e --- /dev/null +++ b/drivers/input/mouse/cyapa.h | |||
@@ -0,0 +1,301 @@ | |||
1 | /* | ||
2 | * Cypress APA trackpad with I2C interface | ||
3 | * | ||
4 | * Author: Dudley Du <dudl@cypress.com> | ||
5 | * | ||
6 | * Copyright (C) 2014 Cypress Semiconductor, Inc. | ||
7 | * | ||
8 | * This file is subject to the terms and conditions of the GNU General Public | ||
9 | * License. See the file COPYING in the main directory of this archive for | ||
10 | * more details. | ||
11 | */ | ||
12 | |||
13 | #ifndef _CYAPA_H | ||
14 | #define _CYAPA_H | ||
15 | |||
16 | #include <linux/firmware.h> | ||
17 | |||
18 | /* APA trackpad firmware generation number. */ | ||
19 | #define CYAPA_GEN_UNKNOWN 0x00 /* unknown protocol. */ | ||
20 | #define CYAPA_GEN3 0x03 /* support MT-protocol B with tracking ID. */ | ||
21 | #define CYAPA_GEN5 0x05 /* support TrueTouch GEN5 trackpad device. */ | ||
22 | |||
23 | #define CYAPA_NAME "Cypress APA Trackpad (cyapa)" | ||
24 | |||
25 | /* | ||
26 | * Macros for SMBus communication | ||
27 | */ | ||
28 | #define SMBUS_READ 0x01 | ||
29 | #define SMBUS_WRITE 0x00 | ||
30 | #define SMBUS_ENCODE_IDX(cmd, idx) ((cmd) | (((idx) & 0x03) << 1)) | ||
31 | #define SMBUS_ENCODE_RW(cmd, rw) ((cmd) | ((rw) & 0x01)) | ||
32 | #define SMBUS_BYTE_BLOCK_CMD_MASK 0x80 | ||
33 | #define SMBUS_GROUP_BLOCK_CMD_MASK 0x40 | ||
34 | |||
35 | /* Commands for read/write registers of Cypress trackpad */ | ||
36 | #define CYAPA_CMD_SOFT_RESET 0x00 | ||
37 | #define CYAPA_CMD_POWER_MODE 0x01 | ||
38 | #define CYAPA_CMD_DEV_STATUS 0x02 | ||
39 | #define CYAPA_CMD_GROUP_DATA 0x03 | ||
40 | #define CYAPA_CMD_GROUP_CMD 0x04 | ||
41 | #define CYAPA_CMD_GROUP_QUERY 0x05 | ||
42 | #define CYAPA_CMD_BL_STATUS 0x06 | ||
43 | #define CYAPA_CMD_BL_HEAD 0x07 | ||
44 | #define CYAPA_CMD_BL_CMD 0x08 | ||
45 | #define CYAPA_CMD_BL_DATA 0x09 | ||
46 | #define CYAPA_CMD_BL_ALL 0x0a | ||
47 | #define CYAPA_CMD_BLK_PRODUCT_ID 0x0b | ||
48 | #define CYAPA_CMD_BLK_HEAD 0x0c | ||
49 | #define CYAPA_CMD_MAX_BASELINE 0x0d | ||
50 | #define CYAPA_CMD_MIN_BASELINE 0x0e | ||
51 | |||
52 | #define BL_HEAD_OFFSET 0x00 | ||
53 | #define BL_DATA_OFFSET 0x10 | ||
54 | |||
55 | #define BL_STATUS_SIZE 3 /* Length of gen3 bootloader status registers */ | ||
56 | #define CYAPA_REG_MAP_SIZE 256 | ||
57 | |||
58 | /* | ||
59 | * Gen3 Operational Device Status Register | ||
60 | * | ||
61 | * bit 7: Valid interrupt source | ||
62 | * bit 6 - 4: Reserved | ||
63 | * bit 3 - 2: Power status | ||
64 | * bit 1 - 0: Device status | ||
65 | */ | ||
66 | #define REG_OP_STATUS 0x00 | ||
67 | #define OP_STATUS_SRC 0x80 | ||
68 | #define OP_STATUS_POWER 0x0c | ||
69 | #define OP_STATUS_DEV 0x03 | ||
70 | #define OP_STATUS_MASK (OP_STATUS_SRC | OP_STATUS_POWER | OP_STATUS_DEV) | ||
71 | |||
72 | /* | ||
73 | * Operational Finger Count/Button Flags Register | ||
74 | * | ||
75 | * bit 7 - 4: Number of touched finger | ||
76 | * bit 3: Valid data | ||
77 | * bit 2: Middle Physical Button | ||
78 | * bit 1: Right Physical Button | ||
79 | * bit 0: Left physical Button | ||
80 | */ | ||
81 | #define REG_OP_DATA1 0x01 | ||
82 | #define OP_DATA_VALID 0x08 | ||
83 | #define OP_DATA_MIDDLE_BTN 0x04 | ||
84 | #define OP_DATA_RIGHT_BTN 0x02 | ||
85 | #define OP_DATA_LEFT_BTN 0x01 | ||
86 | #define OP_DATA_BTN_MASK (OP_DATA_MIDDLE_BTN | OP_DATA_RIGHT_BTN | \ | ||
87 | OP_DATA_LEFT_BTN) | ||
88 | |||
89 | /* | ||
90 | * Write-only command file register used to issue commands and | ||
91 | * parameters to the bootloader. | ||
92 | * The default value read from it is always 0x00. | ||
93 | */ | ||
94 | #define REG_BL_FILE 0x00 | ||
95 | #define BL_FILE 0x00 | ||
96 | |||
97 | /* | ||
98 | * Bootloader Status Register | ||
99 | * | ||
100 | * bit 7: Busy | ||
101 | * bit 6 - 5: Reserved | ||
102 | * bit 4: Bootloader running | ||
103 | * bit 3 - 2: Reserved | ||
104 | * bit 1: Watchdog Reset | ||
105 | * bit 0: Checksum valid | ||
106 | */ | ||
107 | #define REG_BL_STATUS 0x01 | ||
108 | #define BL_STATUS_REV_6_5 0x60 | ||
109 | #define BL_STATUS_BUSY 0x80 | ||
110 | #define BL_STATUS_RUNNING 0x10 | ||
111 | #define BL_STATUS_REV_3_2 0x0c | ||
112 | #define BL_STATUS_WATCHDOG 0x02 | ||
113 | #define BL_STATUS_CSUM_VALID 0x01 | ||
114 | #define BL_STATUS_REV_MASK (BL_STATUS_WATCHDOG | BL_STATUS_REV_3_2 | \ | ||
115 | BL_STATUS_REV_6_5) | ||
116 | |||
117 | /* | ||
118 | * Bootloader Error Register | ||
119 | * | ||
120 | * bit 7: Invalid | ||
121 | * bit 6: Invalid security key | ||
122 | * bit 5: Bootloading | ||
123 | * bit 4: Command checksum | ||
124 | * bit 3: Flash protection error | ||
125 | * bit 2: Flash checksum error | ||
126 | * bit 1 - 0: Reserved | ||
127 | */ | ||
128 | #define REG_BL_ERROR 0x02 | ||
129 | #define BL_ERROR_INVALID 0x80 | ||
130 | #define BL_ERROR_INVALID_KEY 0x40 | ||
131 | #define BL_ERROR_BOOTLOADING 0x20 | ||
132 | #define BL_ERROR_CMD_CSUM 0x10 | ||
133 | #define BL_ERROR_FLASH_PROT 0x08 | ||
134 | #define BL_ERROR_FLASH_CSUM 0x04 | ||
135 | #define BL_ERROR_RESERVED 0x03 | ||
136 | #define BL_ERROR_NO_ERR_IDLE 0x00 | ||
137 | #define BL_ERROR_NO_ERR_ACTIVE (BL_ERROR_BOOTLOADING) | ||
138 | |||
139 | #define CAPABILITY_BTN_SHIFT 3 | ||
140 | #define CAPABILITY_LEFT_BTN_MASK (0x01 << 3) | ||
141 | #define CAPABILITY_RIGHT_BTN_MASK (0x01 << 4) | ||
142 | #define CAPABILITY_MIDDLE_BTN_MASK (0x01 << 5) | ||
143 | #define CAPABILITY_BTN_MASK (CAPABILITY_LEFT_BTN_MASK | \ | ||
144 | CAPABILITY_RIGHT_BTN_MASK | \ | ||
145 | CAPABILITY_MIDDLE_BTN_MASK) | ||
146 | |||
147 | #define PWR_MODE_MASK 0xfc | ||
148 | #define PWR_MODE_FULL_ACTIVE (0x3f << 2) | ||
149 | #define PWR_MODE_IDLE (0x03 << 2) /* Default rt suspend scanrate: 30ms */ | ||
150 | #define PWR_MODE_SLEEP (0x05 << 2) /* Default suspend scanrate: 50ms */ | ||
151 | #define PWR_MODE_BTN_ONLY (0x01 << 2) | ||
152 | #define PWR_MODE_OFF (0x00 << 2) | ||
153 | |||
154 | #define PWR_STATUS_MASK 0x0c | ||
155 | #define PWR_STATUS_ACTIVE (0x03 << 2) | ||
156 | #define PWR_STATUS_IDLE (0x02 << 2) | ||
157 | #define PWR_STATUS_BTN_ONLY (0x01 << 2) | ||
158 | #define PWR_STATUS_OFF (0x00 << 2) | ||
159 | |||
160 | #define AUTOSUSPEND_DELAY 2000 /* unit : ms */ | ||
161 | |||
162 | #define UNINIT_SLEEP_TIME 0xFFFF | ||
163 | #define UNINIT_PWR_MODE 0xFF | ||
164 | |||
165 | #define BTN_ONLY_MODE_NAME "buttononly" | ||
166 | #define OFF_MODE_NAME "off" | ||
167 | |||
168 | /* The touch.id is used as the MT slot id, thus max MT slot is 15 */ | ||
169 | #define CYAPA_MAX_MT_SLOTS 15 | ||
170 | |||
171 | struct cyapa; | ||
172 | |||
173 | typedef bool (*cb_sort)(struct cyapa *, u8 *, int); | ||
174 | |||
175 | struct cyapa_dev_ops { | ||
176 | int (*check_fw)(struct cyapa *, const struct firmware *); | ||
177 | int (*bl_enter)(struct cyapa *); | ||
178 | int (*bl_activate)(struct cyapa *); | ||
179 | int (*bl_initiate)(struct cyapa *, const struct firmware *); | ||
180 | int (*update_fw)(struct cyapa *, const struct firmware *); | ||
181 | int (*bl_deactivate)(struct cyapa *); | ||
182 | |||
183 | ssize_t (*show_baseline)(struct device *, | ||
184 | struct device_attribute *, char *); | ||
185 | ssize_t (*calibrate_store)(struct device *, | ||
186 | struct device_attribute *, const char *, size_t); | ||
187 | |||
188 | int (*initialize)(struct cyapa *cyapa); | ||
189 | |||
190 | int (*state_parse)(struct cyapa *cyapa, u8 *reg_status, int len); | ||
191 | int (*operational_check)(struct cyapa *cyapa); | ||
192 | |||
193 | int (*irq_handler)(struct cyapa *); | ||
194 | bool (*irq_cmd_handler)(struct cyapa *); | ||
195 | int (*sort_empty_output_data)(struct cyapa *, | ||
196 | u8 *, int *, cb_sort); | ||
197 | |||
198 | int (*set_power_mode)(struct cyapa *, u8, u16); | ||
199 | }; | ||
200 | |||
201 | struct cyapa_gen5_cmd_states { | ||
202 | struct mutex cmd_lock; | ||
203 | struct completion cmd_ready; | ||
204 | atomic_t cmd_issued; | ||
205 | u8 in_progress_cmd; | ||
206 | bool is_irq_mode; | ||
207 | |||
208 | cb_sort resp_sort_func; | ||
209 | u8 *resp_data; | ||
210 | int *resp_len; | ||
211 | |||
212 | u8 irq_cmd_buf[CYAPA_REG_MAP_SIZE]; | ||
213 | u8 empty_buf[CYAPA_REG_MAP_SIZE]; | ||
214 | }; | ||
215 | |||
216 | union cyapa_cmd_states { | ||
217 | struct cyapa_gen5_cmd_states gen5; | ||
218 | }; | ||
219 | |||
220 | enum cyapa_state { | ||
221 | CYAPA_STATE_NO_DEVICE, | ||
222 | CYAPA_STATE_BL_BUSY, | ||
223 | CYAPA_STATE_BL_IDLE, | ||
224 | CYAPA_STATE_BL_ACTIVE, | ||
225 | CYAPA_STATE_OP, | ||
226 | CYAPA_STATE_GEN5_BL, | ||
227 | CYAPA_STATE_GEN5_APP, | ||
228 | }; | ||
229 | |||
230 | /* The main device structure */ | ||
231 | struct cyapa { | ||
232 | enum cyapa_state state; | ||
233 | u8 status[BL_STATUS_SIZE]; | ||
234 | bool operational; /* true: ready for data reporting; false: not. */ | ||
235 | |||
236 | struct i2c_client *client; | ||
237 | struct input_dev *input; | ||
238 | char phys[32]; /* Device physical location */ | ||
239 | bool irq_wake; /* Irq wake is enabled */ | ||
240 | bool smbus; | ||
241 | |||
242 | /* power mode settings */ | ||
243 | u8 suspend_power_mode; | ||
244 | u16 suspend_sleep_time; | ||
245 | u8 runtime_suspend_power_mode; | ||
246 | u16 runtime_suspend_sleep_time; | ||
247 | u8 dev_pwr_mode; | ||
248 | u16 dev_sleep_time; | ||
249 | |||
250 | /* Read from query data region. */ | ||
251 | char product_id[16]; | ||
252 | u8 fw_maj_ver; /* Firmware major version. */ | ||
253 | u8 fw_min_ver; /* Firmware minor version. */ | ||
254 | u8 btn_capability; | ||
255 | u8 gen; | ||
256 | int max_abs_x; | ||
257 | int max_abs_y; | ||
258 | int physical_size_x; | ||
259 | int physical_size_y; | ||
260 | |||
261 | /* Used in ttsp and truetouch based trackpad devices. */ | ||
262 | u8 x_origin; /* X Axis Origin: 0 = left side; 1 = rigth side. */ | ||
263 | u8 y_origin; /* Y Axis Origin: 0 = top; 1 = bottom. */ | ||
264 | int electrodes_x; /* Number of electrodes on the X Axis*/ | ||
265 | int electrodes_y; /* Number of electrodes on the Y Axis*/ | ||
266 | int electrodes_rx; /* Number of Rx electrodes */ | ||
267 | int aligned_electrodes_rx; /* 4 aligned */ | ||
268 | int max_z; | ||
269 | |||
270 | /* | ||
271 | * Used to synchronize the access or update the device state. | ||
272 | * And since update firmware and read firmware image process will take | ||
273 | * quite long time, maybe more than 10 seconds, so use mutex_lock | ||
274 | * to sync and wait other interface and detecting are done or ready. | ||
275 | */ | ||
276 | struct mutex state_sync_lock; | ||
277 | |||
278 | const struct cyapa_dev_ops *ops; | ||
279 | |||
280 | union cyapa_cmd_states cmd_states; | ||
281 | }; | ||
282 | |||
283 | |||
284 | ssize_t cyapa_i2c_reg_read_block(struct cyapa *cyapa, u8 reg, size_t len, | ||
285 | u8 *values); | ||
286 | ssize_t cyapa_smbus_read_block(struct cyapa *cyapa, u8 cmd, size_t len, | ||
287 | u8 *values); | ||
288 | |||
289 | ssize_t cyapa_read_block(struct cyapa *cyapa, u8 cmd_idx, u8 *values); | ||
290 | |||
291 | int cyapa_poll_state(struct cyapa *cyapa, unsigned int timeout); | ||
292 | |||
293 | u8 cyapa_sleep_time_to_pwr_cmd(u16 sleep_time); | ||
294 | u16 cyapa_pwr_cmd_to_sleep_time(u8 pwr_mode); | ||
295 | |||
296 | |||
297 | extern const char product_id[]; | ||
298 | extern const struct cyapa_dev_ops cyapa_gen3_ops; | ||
299 | extern const struct cyapa_dev_ops cyapa_gen5_ops; | ||
300 | |||
301 | #endif | ||
diff --git a/drivers/input/mouse/cyapa_gen3.c b/drivers/input/mouse/cyapa_gen3.c new file mode 100644 index 000000000000..77e9d70a986b --- /dev/null +++ b/drivers/input/mouse/cyapa_gen3.c | |||
@@ -0,0 +1,1247 @@ | |||
1 | /* | ||
2 | * Cypress APA trackpad with I2C interface | ||
3 | * | ||
4 | * Author: Dudley Du <dudl@cypress.com> | ||
5 | * Further cleanup and restructuring by: | ||
6 | * Daniel Kurtz <djkurtz@chromium.org> | ||
7 | * Benson Leung <bleung@chromium.org> | ||
8 | * | ||
9 | * Copyright (C) 2011-2014 Cypress Semiconductor, Inc. | ||
10 | * Copyright (C) 2011-2012 Google, Inc. | ||
11 | * | ||
12 | * This file is subject to the terms and conditions of the GNU General Public | ||
13 | * License. See the file COPYING in the main directory of this archive for | ||
14 | * more details. | ||
15 | */ | ||
16 | |||
17 | #include <linux/delay.h> | ||
18 | #include <linux/i2c.h> | ||
19 | #include <linux/input.h> | ||
20 | #include <linux/input/mt.h> | ||
21 | #include <linux/module.h> | ||
22 | #include <linux/slab.h> | ||
23 | #include <linux/unaligned/access_ok.h> | ||
24 | #include "cyapa.h" | ||
25 | |||
26 | |||
27 | #define GEN3_MAX_FINGERS 5 | ||
28 | #define GEN3_FINGER_NUM(x) (((x) >> 4) & 0x07) | ||
29 | |||
30 | #define BLK_HEAD_BYTES 32 | ||
31 | |||
32 | /* Macro for register map group offset. */ | ||
33 | #define PRODUCT_ID_SIZE 16 | ||
34 | #define QUERY_DATA_SIZE 27 | ||
35 | #define REG_PROTOCOL_GEN_QUERY_OFFSET 20 | ||
36 | |||
37 | #define REG_OFFSET_DATA_BASE 0x0000 | ||
38 | #define REG_OFFSET_COMMAND_BASE 0x0028 | ||
39 | #define REG_OFFSET_QUERY_BASE 0x002a | ||
40 | |||
41 | #define CYAPA_OFFSET_SOFT_RESET REG_OFFSET_COMMAND_BASE | ||
42 | #define OP_RECALIBRATION_MASK 0x80 | ||
43 | #define OP_REPORT_BASELINE_MASK 0x40 | ||
44 | #define REG_OFFSET_MAX_BASELINE 0x0026 | ||
45 | #define REG_OFFSET_MIN_BASELINE 0x0027 | ||
46 | |||
47 | #define REG_OFFSET_POWER_MODE (REG_OFFSET_COMMAND_BASE + 1) | ||
48 | #define SET_POWER_MODE_DELAY 10000 /* Unit: us */ | ||
49 | #define SET_POWER_MODE_TRIES 5 | ||
50 | |||
51 | #define GEN3_BL_CMD_CHECKSUM_SEED 0xff | ||
52 | #define GEN3_BL_CMD_INITIATE_BL 0x38 | ||
53 | #define GEN3_BL_CMD_WRITE_BLOCK 0x39 | ||
54 | #define GEN3_BL_CMD_VERIFY_BLOCK 0x3a | ||
55 | #define GEN3_BL_CMD_TERMINATE_BL 0x3b | ||
56 | #define GEN3_BL_CMD_LAUNCH_APP 0xa5 | ||
57 | |||
58 | /* | ||
59 | * CYAPA trackpad device states. | ||
60 | * Used in register 0x00, bit1-0, DeviceStatus field. | ||
61 | * Other values indicate device is in an abnormal state and must be reset. | ||
62 | */ | ||
63 | #define CYAPA_DEV_NORMAL 0x03 | ||
64 | #define CYAPA_DEV_BUSY 0x01 | ||
65 | |||
66 | #define CYAPA_FW_BLOCK_SIZE 64 | ||
67 | #define CYAPA_FW_READ_SIZE 16 | ||
68 | #define CYAPA_FW_HDR_START 0x0780 | ||
69 | #define CYAPA_FW_HDR_BLOCK_COUNT 2 | ||
70 | #define CYAPA_FW_HDR_BLOCK_START (CYAPA_FW_HDR_START / CYAPA_FW_BLOCK_SIZE) | ||
71 | #define CYAPA_FW_HDR_SIZE (CYAPA_FW_HDR_BLOCK_COUNT * \ | ||
72 | CYAPA_FW_BLOCK_SIZE) | ||
73 | #define CYAPA_FW_DATA_START 0x0800 | ||
74 | #define CYAPA_FW_DATA_BLOCK_COUNT 480 | ||
75 | #define CYAPA_FW_DATA_BLOCK_START (CYAPA_FW_DATA_START / CYAPA_FW_BLOCK_SIZE) | ||
76 | #define CYAPA_FW_DATA_SIZE (CYAPA_FW_DATA_BLOCK_COUNT * \ | ||
77 | CYAPA_FW_BLOCK_SIZE) | ||
78 | #define CYAPA_FW_SIZE (CYAPA_FW_HDR_SIZE + CYAPA_FW_DATA_SIZE) | ||
79 | #define CYAPA_CMD_LEN 16 | ||
80 | |||
81 | #define GEN3_BL_IDLE_FW_MAJ_VER_OFFSET 0x0b | ||
82 | #define GEN3_BL_IDLE_FW_MIN_VER_OFFSET (GEN3_BL_IDLE_FW_MAJ_VER_OFFSET + 1) | ||
83 | |||
84 | |||
85 | struct cyapa_touch { | ||
86 | /* | ||
87 | * high bits or x/y position value | ||
88 | * bit 7 - 4: high 4 bits of x position value | ||
89 | * bit 3 - 0: high 4 bits of y position value | ||
90 | */ | ||
91 | u8 xy_hi; | ||
92 | u8 x_lo; /* low 8 bits of x position value. */ | ||
93 | u8 y_lo; /* low 8 bits of y position value. */ | ||
94 | u8 pressure; | ||
95 | /* id range is 1 - 15. It is incremented with every new touch. */ | ||
96 | u8 id; | ||
97 | } __packed; | ||
98 | |||
99 | struct cyapa_reg_data { | ||
100 | /* | ||
101 | * bit 0 - 1: device status | ||
102 | * bit 3 - 2: power mode | ||
103 | * bit 6 - 4: reserved | ||
104 | * bit 7: interrupt valid bit | ||
105 | */ | ||
106 | u8 device_status; | ||
107 | /* | ||
108 | * bit 7 - 4: number of fingers currently touching pad | ||
109 | * bit 3: valid data check bit | ||
110 | * bit 2: middle mechanism button state if exists | ||
111 | * bit 1: right mechanism button state if exists | ||
112 | * bit 0: left mechanism button state if exists | ||
113 | */ | ||
114 | u8 finger_btn; | ||
115 | /* CYAPA reports up to 5 touches per packet. */ | ||
116 | struct cyapa_touch touches[5]; | ||
117 | } __packed; | ||
118 | |||
119 | struct gen3_write_block_cmd { | ||
120 | u8 checksum_seed; /* Always be 0xff */ | ||
121 | u8 cmd_code; /* command code: 0x39 */ | ||
122 | u8 key[8]; /* 8-byte security key */ | ||
123 | __be16 block_num; | ||
124 | u8 block_data[CYAPA_FW_BLOCK_SIZE]; | ||
125 | u8 block_checksum; /* Calculated using bytes 12 - 75 */ | ||
126 | u8 cmd_checksum; /* Calculated using bytes 0-76 */ | ||
127 | } __packed; | ||
128 | |||
129 | static const u8 security_key[] = { | ||
130 | 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 }; | ||
131 | static const u8 bl_activate[] = { 0x00, 0xff, 0x38, 0x00, 0x01, 0x02, 0x03, | ||
132 | 0x04, 0x05, 0x06, 0x07 }; | ||
133 | static const u8 bl_deactivate[] = { 0x00, 0xff, 0x3b, 0x00, 0x01, 0x02, 0x03, | ||
134 | 0x04, 0x05, 0x06, 0x07 }; | ||
135 | static const u8 bl_exit[] = { 0x00, 0xff, 0xa5, 0x00, 0x01, 0x02, 0x03, 0x04, | ||
136 | 0x05, 0x06, 0x07 }; | ||
137 | |||
138 | |||
139 | /* for byte read/write command */ | ||
140 | #define CMD_RESET 0 | ||
141 | #define CMD_POWER_MODE 1 | ||
142 | #define CMD_DEV_STATUS 2 | ||
143 | #define CMD_REPORT_MAX_BASELINE 3 | ||
144 | #define CMD_REPORT_MIN_BASELINE 4 | ||
145 | #define SMBUS_BYTE_CMD(cmd) (((cmd) & 0x3f) << 1) | ||
146 | #define CYAPA_SMBUS_RESET SMBUS_BYTE_CMD(CMD_RESET) | ||
147 | #define CYAPA_SMBUS_POWER_MODE SMBUS_BYTE_CMD(CMD_POWER_MODE) | ||
148 | #define CYAPA_SMBUS_DEV_STATUS SMBUS_BYTE_CMD(CMD_DEV_STATUS) | ||
149 | #define CYAPA_SMBUS_MAX_BASELINE SMBUS_BYTE_CMD(CMD_REPORT_MAX_BASELINE) | ||
150 | #define CYAPA_SMBUS_MIN_BASELINE SMBUS_BYTE_CMD(CMD_REPORT_MIN_BASELINE) | ||
151 | |||
152 | /* for group registers read/write command */ | ||
153 | #define REG_GROUP_DATA 0 | ||
154 | #define REG_GROUP_CMD 2 | ||
155 | #define REG_GROUP_QUERY 3 | ||
156 | #define SMBUS_GROUP_CMD(grp) (0x80 | (((grp) & 0x07) << 3)) | ||
157 | #define CYAPA_SMBUS_GROUP_DATA SMBUS_GROUP_CMD(REG_GROUP_DATA) | ||
158 | #define CYAPA_SMBUS_GROUP_CMD SMBUS_GROUP_CMD(REG_GROUP_CMD) | ||
159 | #define CYAPA_SMBUS_GROUP_QUERY SMBUS_GROUP_CMD(REG_GROUP_QUERY) | ||
160 | |||
161 | /* for register block read/write command */ | ||
162 | #define CMD_BL_STATUS 0 | ||
163 | #define CMD_BL_HEAD 1 | ||
164 | #define CMD_BL_CMD 2 | ||
165 | #define CMD_BL_DATA 3 | ||
166 | #define CMD_BL_ALL 4 | ||
167 | #define CMD_BLK_PRODUCT_ID 5 | ||
168 | #define CMD_BLK_HEAD 6 | ||
169 | #define SMBUS_BLOCK_CMD(cmd) (0xc0 | (((cmd) & 0x1f) << 1)) | ||
170 | |||
171 | /* register block read/write command in bootloader mode */ | ||
172 | #define CYAPA_SMBUS_BL_STATUS SMBUS_BLOCK_CMD(CMD_BL_STATUS) | ||
173 | #define CYAPA_SMBUS_BL_HEAD SMBUS_BLOCK_CMD(CMD_BL_HEAD) | ||
174 | #define CYAPA_SMBUS_BL_CMD SMBUS_BLOCK_CMD(CMD_BL_CMD) | ||
175 | #define CYAPA_SMBUS_BL_DATA SMBUS_BLOCK_CMD(CMD_BL_DATA) | ||
176 | #define CYAPA_SMBUS_BL_ALL SMBUS_BLOCK_CMD(CMD_BL_ALL) | ||
177 | |||
178 | /* register block read/write command in operational mode */ | ||
179 | #define CYAPA_SMBUS_BLK_PRODUCT_ID SMBUS_BLOCK_CMD(CMD_BLK_PRODUCT_ID) | ||
180 | #define CYAPA_SMBUS_BLK_HEAD SMBUS_BLOCK_CMD(CMD_BLK_HEAD) | ||
181 | |||
182 | /* for byte read/write command */ | ||
183 | #define CMD_RESET 0 | ||
184 | #define CMD_POWER_MODE 1 | ||
185 | #define CMD_DEV_STATUS 2 | ||
186 | #define CMD_REPORT_MAX_BASELINE 3 | ||
187 | #define CMD_REPORT_MIN_BASELINE 4 | ||
188 | #define SMBUS_BYTE_CMD(cmd) (((cmd) & 0x3f) << 1) | ||
189 | #define CYAPA_SMBUS_RESET SMBUS_BYTE_CMD(CMD_RESET) | ||
190 | #define CYAPA_SMBUS_POWER_MODE SMBUS_BYTE_CMD(CMD_POWER_MODE) | ||
191 | #define CYAPA_SMBUS_DEV_STATUS SMBUS_BYTE_CMD(CMD_DEV_STATUS) | ||
192 | #define CYAPA_SMBUS_MAX_BASELINE SMBUS_BYTE_CMD(CMD_REPORT_MAX_BASELINE) | ||
193 | #define CYAPA_SMBUS_MIN_BASELINE SMBUS_BYTE_CMD(CMD_REPORT_MIN_BASELINE) | ||
194 | |||
195 | /* for group registers read/write command */ | ||
196 | #define REG_GROUP_DATA 0 | ||
197 | #define REG_GROUP_CMD 2 | ||
198 | #define REG_GROUP_QUERY 3 | ||
199 | #define SMBUS_GROUP_CMD(grp) (0x80 | (((grp) & 0x07) << 3)) | ||
200 | #define CYAPA_SMBUS_GROUP_DATA SMBUS_GROUP_CMD(REG_GROUP_DATA) | ||
201 | #define CYAPA_SMBUS_GROUP_CMD SMBUS_GROUP_CMD(REG_GROUP_CMD) | ||
202 | #define CYAPA_SMBUS_GROUP_QUERY SMBUS_GROUP_CMD(REG_GROUP_QUERY) | ||
203 | |||
204 | /* for register block read/write command */ | ||
205 | #define CMD_BL_STATUS 0 | ||
206 | #define CMD_BL_HEAD 1 | ||
207 | #define CMD_BL_CMD 2 | ||
208 | #define CMD_BL_DATA 3 | ||
209 | #define CMD_BL_ALL 4 | ||
210 | #define CMD_BLK_PRODUCT_ID 5 | ||
211 | #define CMD_BLK_HEAD 6 | ||
212 | #define SMBUS_BLOCK_CMD(cmd) (0xc0 | (((cmd) & 0x1f) << 1)) | ||
213 | |||
214 | /* register block read/write command in bootloader mode */ | ||
215 | #define CYAPA_SMBUS_BL_STATUS SMBUS_BLOCK_CMD(CMD_BL_STATUS) | ||
216 | #define CYAPA_SMBUS_BL_HEAD SMBUS_BLOCK_CMD(CMD_BL_HEAD) | ||
217 | #define CYAPA_SMBUS_BL_CMD SMBUS_BLOCK_CMD(CMD_BL_CMD) | ||
218 | #define CYAPA_SMBUS_BL_DATA SMBUS_BLOCK_CMD(CMD_BL_DATA) | ||
219 | #define CYAPA_SMBUS_BL_ALL SMBUS_BLOCK_CMD(CMD_BL_ALL) | ||
220 | |||
221 | /* register block read/write command in operational mode */ | ||
222 | #define CYAPA_SMBUS_BLK_PRODUCT_ID SMBUS_BLOCK_CMD(CMD_BLK_PRODUCT_ID) | ||
223 | #define CYAPA_SMBUS_BLK_HEAD SMBUS_BLOCK_CMD(CMD_BLK_HEAD) | ||
224 | |||
225 | struct cyapa_cmd_len { | ||
226 | u8 cmd; | ||
227 | u8 len; | ||
228 | }; | ||
229 | |||
230 | /* maps generic CYAPA_CMD_* code to the I2C equivalent */ | ||
231 | static const struct cyapa_cmd_len cyapa_i2c_cmds[] = { | ||
232 | { CYAPA_OFFSET_SOFT_RESET, 1 }, /* CYAPA_CMD_SOFT_RESET */ | ||
233 | { REG_OFFSET_COMMAND_BASE + 1, 1 }, /* CYAPA_CMD_POWER_MODE */ | ||
234 | { REG_OFFSET_DATA_BASE, 1 }, /* CYAPA_CMD_DEV_STATUS */ | ||
235 | { REG_OFFSET_DATA_BASE, sizeof(struct cyapa_reg_data) }, | ||
236 | /* CYAPA_CMD_GROUP_DATA */ | ||
237 | { REG_OFFSET_COMMAND_BASE, 0 }, /* CYAPA_CMD_GROUP_CMD */ | ||
238 | { REG_OFFSET_QUERY_BASE, QUERY_DATA_SIZE }, /* CYAPA_CMD_GROUP_QUERY */ | ||
239 | { BL_HEAD_OFFSET, 3 }, /* CYAPA_CMD_BL_STATUS */ | ||
240 | { BL_HEAD_OFFSET, 16 }, /* CYAPA_CMD_BL_HEAD */ | ||
241 | { BL_HEAD_OFFSET, 16 }, /* CYAPA_CMD_BL_CMD */ | ||
242 | { BL_DATA_OFFSET, 16 }, /* CYAPA_CMD_BL_DATA */ | ||
243 | { BL_HEAD_OFFSET, 32 }, /* CYAPA_CMD_BL_ALL */ | ||
244 | { REG_OFFSET_QUERY_BASE, PRODUCT_ID_SIZE }, | ||
245 | /* CYAPA_CMD_BLK_PRODUCT_ID */ | ||
246 | { REG_OFFSET_DATA_BASE, 32 }, /* CYAPA_CMD_BLK_HEAD */ | ||
247 | { REG_OFFSET_MAX_BASELINE, 1 }, /* CYAPA_CMD_MAX_BASELINE */ | ||
248 | { REG_OFFSET_MIN_BASELINE, 1 }, /* CYAPA_CMD_MIN_BASELINE */ | ||
249 | }; | ||
250 | |||
251 | static const struct cyapa_cmd_len cyapa_smbus_cmds[] = { | ||
252 | { CYAPA_SMBUS_RESET, 1 }, /* CYAPA_CMD_SOFT_RESET */ | ||
253 | { CYAPA_SMBUS_POWER_MODE, 1 }, /* CYAPA_CMD_POWER_MODE */ | ||
254 | { CYAPA_SMBUS_DEV_STATUS, 1 }, /* CYAPA_CMD_DEV_STATUS */ | ||
255 | { CYAPA_SMBUS_GROUP_DATA, sizeof(struct cyapa_reg_data) }, | ||
256 | /* CYAPA_CMD_GROUP_DATA */ | ||
257 | { CYAPA_SMBUS_GROUP_CMD, 2 }, /* CYAPA_CMD_GROUP_CMD */ | ||
258 | { CYAPA_SMBUS_GROUP_QUERY, QUERY_DATA_SIZE }, | ||
259 | /* CYAPA_CMD_GROUP_QUERY */ | ||
260 | { CYAPA_SMBUS_BL_STATUS, 3 }, /* CYAPA_CMD_BL_STATUS */ | ||
261 | { CYAPA_SMBUS_BL_HEAD, 16 }, /* CYAPA_CMD_BL_HEAD */ | ||
262 | { CYAPA_SMBUS_BL_CMD, 16 }, /* CYAPA_CMD_BL_CMD */ | ||
263 | { CYAPA_SMBUS_BL_DATA, 16 }, /* CYAPA_CMD_BL_DATA */ | ||
264 | { CYAPA_SMBUS_BL_ALL, 32 }, /* CYAPA_CMD_BL_ALL */ | ||
265 | { CYAPA_SMBUS_BLK_PRODUCT_ID, PRODUCT_ID_SIZE }, | ||
266 | /* CYAPA_CMD_BLK_PRODUCT_ID */ | ||
267 | { CYAPA_SMBUS_BLK_HEAD, 16 }, /* CYAPA_CMD_BLK_HEAD */ | ||
268 | { CYAPA_SMBUS_MAX_BASELINE, 1 }, /* CYAPA_CMD_MAX_BASELINE */ | ||
269 | { CYAPA_SMBUS_MIN_BASELINE, 1 }, /* CYAPA_CMD_MIN_BASELINE */ | ||
270 | }; | ||
271 | |||
272 | |||
273 | /* | ||
274 | * cyapa_smbus_read_block - perform smbus block read command | ||
275 | * @cyapa - private data structure of the driver | ||
276 | * @cmd - the properly encoded smbus command | ||
277 | * @len - expected length of smbus command result | ||
278 | * @values - buffer to store smbus command result | ||
279 | * | ||
280 | * Returns negative errno, else the number of bytes written. | ||
281 | * | ||
282 | * Note: | ||
283 | * In trackpad device, the memory block allocated for I2C register map | ||
284 | * is 256 bytes, so the max read block for I2C bus is 256 bytes. | ||
285 | */ | ||
286 | ssize_t cyapa_smbus_read_block(struct cyapa *cyapa, u8 cmd, size_t len, | ||
287 | u8 *values) | ||
288 | { | ||
289 | ssize_t ret; | ||
290 | u8 index; | ||
291 | u8 smbus_cmd; | ||
292 | u8 *buf; | ||
293 | struct i2c_client *client = cyapa->client; | ||
294 | |||
295 | if (!(SMBUS_BYTE_BLOCK_CMD_MASK & cmd)) | ||
296 | return -EINVAL; | ||
297 | |||
298 | if (SMBUS_GROUP_BLOCK_CMD_MASK & cmd) { | ||
299 | /* read specific block registers command. */ | ||
300 | smbus_cmd = SMBUS_ENCODE_RW(cmd, SMBUS_READ); | ||
301 | ret = i2c_smbus_read_block_data(client, smbus_cmd, values); | ||
302 | goto out; | ||
303 | } | ||
304 | |||
305 | ret = 0; | ||
306 | for (index = 0; index * I2C_SMBUS_BLOCK_MAX < len; index++) { | ||
307 | smbus_cmd = SMBUS_ENCODE_IDX(cmd, index); | ||
308 | smbus_cmd = SMBUS_ENCODE_RW(smbus_cmd, SMBUS_READ); | ||
309 | buf = values + I2C_SMBUS_BLOCK_MAX * index; | ||
310 | ret = i2c_smbus_read_block_data(client, smbus_cmd, buf); | ||
311 | if (ret < 0) | ||
312 | goto out; | ||
313 | } | ||
314 | |||
315 | out: | ||
316 | return ret > 0 ? len : ret; | ||
317 | } | ||
318 | |||
319 | static s32 cyapa_read_byte(struct cyapa *cyapa, u8 cmd_idx) | ||
320 | { | ||
321 | u8 cmd; | ||
322 | |||
323 | if (cyapa->smbus) { | ||
324 | cmd = cyapa_smbus_cmds[cmd_idx].cmd; | ||
325 | cmd = SMBUS_ENCODE_RW(cmd, SMBUS_READ); | ||
326 | } else { | ||
327 | cmd = cyapa_i2c_cmds[cmd_idx].cmd; | ||
328 | } | ||
329 | return i2c_smbus_read_byte_data(cyapa->client, cmd); | ||
330 | } | ||
331 | |||
332 | static s32 cyapa_write_byte(struct cyapa *cyapa, u8 cmd_idx, u8 value) | ||
333 | { | ||
334 | u8 cmd; | ||
335 | |||
336 | if (cyapa->smbus) { | ||
337 | cmd = cyapa_smbus_cmds[cmd_idx].cmd; | ||
338 | cmd = SMBUS_ENCODE_RW(cmd, SMBUS_WRITE); | ||
339 | } else { | ||
340 | cmd = cyapa_i2c_cmds[cmd_idx].cmd; | ||
341 | } | ||
342 | return i2c_smbus_write_byte_data(cyapa->client, cmd, value); | ||
343 | } | ||
344 | |||
345 | ssize_t cyapa_i2c_reg_read_block(struct cyapa *cyapa, u8 reg, size_t len, | ||
346 | u8 *values) | ||
347 | { | ||
348 | return i2c_smbus_read_i2c_block_data(cyapa->client, reg, len, values); | ||
349 | } | ||
350 | |||
351 | static ssize_t cyapa_i2c_reg_write_block(struct cyapa *cyapa, u8 reg, | ||
352 | size_t len, const u8 *values) | ||
353 | { | ||
354 | return i2c_smbus_write_i2c_block_data(cyapa->client, reg, len, values); | ||
355 | } | ||
356 | |||
357 | ssize_t cyapa_read_block(struct cyapa *cyapa, u8 cmd_idx, u8 *values) | ||
358 | { | ||
359 | u8 cmd; | ||
360 | size_t len; | ||
361 | |||
362 | if (cyapa->smbus) { | ||
363 | cmd = cyapa_smbus_cmds[cmd_idx].cmd; | ||
364 | len = cyapa_smbus_cmds[cmd_idx].len; | ||
365 | return cyapa_smbus_read_block(cyapa, cmd, len, values); | ||
366 | } | ||
367 | cmd = cyapa_i2c_cmds[cmd_idx].cmd; | ||
368 | len = cyapa_i2c_cmds[cmd_idx].len; | ||
369 | return cyapa_i2c_reg_read_block(cyapa, cmd, len, values); | ||
370 | } | ||
371 | |||
372 | /* | ||
373 | * Determine the Gen3 trackpad device's current operating state. | ||
374 | * | ||
375 | */ | ||
376 | static int cyapa_gen3_state_parse(struct cyapa *cyapa, u8 *reg_data, int len) | ||
377 | { | ||
378 | cyapa->state = CYAPA_STATE_NO_DEVICE; | ||
379 | |||
380 | /* Parse based on Gen3 characteristic registers and bits */ | ||
381 | if (reg_data[REG_BL_FILE] == BL_FILE && | ||
382 | reg_data[REG_BL_ERROR] == BL_ERROR_NO_ERR_IDLE && | ||
383 | (reg_data[REG_BL_STATUS] == | ||
384 | (BL_STATUS_RUNNING | BL_STATUS_CSUM_VALID) || | ||
385 | reg_data[REG_BL_STATUS] == BL_STATUS_RUNNING)) { | ||
386 | /* | ||
387 | * Normal state after power on or reset, | ||
388 | * REG_BL_STATUS == 0x11, firmware image checksum is valid. | ||
389 | * REG_BL_STATUS == 0x10, firmware image checksum is invalid. | ||
390 | */ | ||
391 | cyapa->gen = CYAPA_GEN3; | ||
392 | cyapa->state = CYAPA_STATE_BL_IDLE; | ||
393 | } else if (reg_data[REG_BL_FILE] == BL_FILE && | ||
394 | (reg_data[REG_BL_STATUS] & BL_STATUS_RUNNING) == | ||
395 | BL_STATUS_RUNNING) { | ||
396 | cyapa->gen = CYAPA_GEN3; | ||
397 | if (reg_data[REG_BL_STATUS] & BL_STATUS_BUSY) { | ||
398 | cyapa->state = CYAPA_STATE_BL_BUSY; | ||
399 | } else { | ||
400 | if ((reg_data[REG_BL_ERROR] & BL_ERROR_BOOTLOADING) == | ||
401 | BL_ERROR_BOOTLOADING) | ||
402 | cyapa->state = CYAPA_STATE_BL_ACTIVE; | ||
403 | else | ||
404 | cyapa->state = CYAPA_STATE_BL_IDLE; | ||
405 | } | ||
406 | } else if ((reg_data[REG_OP_STATUS] & OP_STATUS_SRC) && | ||
407 | (reg_data[REG_OP_DATA1] & OP_DATA_VALID)) { | ||
408 | /* | ||
409 | * Normal state when running in operational mode, | ||
410 | * may also not in full power state or | ||
411 | * busying in command process. | ||
412 | */ | ||
413 | if (GEN3_FINGER_NUM(reg_data[REG_OP_DATA1]) <= | ||
414 | GEN3_MAX_FINGERS) { | ||
415 | /* Finger number data is valid. */ | ||
416 | cyapa->gen = CYAPA_GEN3; | ||
417 | cyapa->state = CYAPA_STATE_OP; | ||
418 | } | ||
419 | } else if (reg_data[REG_OP_STATUS] == 0x0C && | ||
420 | reg_data[REG_OP_DATA1] == 0x08) { | ||
421 | /* Op state when first two registers overwritten with 0x00 */ | ||
422 | cyapa->gen = CYAPA_GEN3; | ||
423 | cyapa->state = CYAPA_STATE_OP; | ||
424 | } else if (reg_data[REG_BL_STATUS] & | ||
425 | (BL_STATUS_RUNNING | BL_STATUS_BUSY)) { | ||
426 | cyapa->gen = CYAPA_GEN3; | ||
427 | cyapa->state = CYAPA_STATE_BL_BUSY; | ||
428 | } | ||
429 | |||
430 | if (cyapa->gen == CYAPA_GEN3 && (cyapa->state == CYAPA_STATE_OP || | ||
431 | cyapa->state == CYAPA_STATE_BL_IDLE || | ||
432 | cyapa->state == CYAPA_STATE_BL_ACTIVE || | ||
433 | cyapa->state == CYAPA_STATE_BL_BUSY)) | ||
434 | return 0; | ||
435 | |||
436 | return -EAGAIN; | ||
437 | } | ||
438 | |||
439 | /* | ||
440 | * Enter bootloader by soft resetting the device. | ||
441 | * | ||
442 | * If device is already in the bootloader, the function just returns. | ||
443 | * Otherwise, reset the device; after reset, device enters bootloader idle | ||
444 | * state immediately. | ||
445 | * | ||
446 | * Returns: | ||
447 | * 0 on success | ||
448 | * -EAGAIN device was reset, but is not now in bootloader idle state | ||
449 | * < 0 if the device never responds within the timeout | ||
450 | */ | ||
451 | static int cyapa_gen3_bl_enter(struct cyapa *cyapa) | ||
452 | { | ||
453 | int error; | ||
454 | int waiting_time; | ||
455 | |||
456 | error = cyapa_poll_state(cyapa, 500); | ||
457 | if (error) | ||
458 | return error; | ||
459 | if (cyapa->state == CYAPA_STATE_BL_IDLE) { | ||
460 | /* Already in BL_IDLE. Skipping reset. */ | ||
461 | return 0; | ||
462 | } | ||
463 | |||
464 | if (cyapa->state != CYAPA_STATE_OP) | ||
465 | return -EAGAIN; | ||
466 | |||
467 | cyapa->operational = false; | ||
468 | cyapa->state = CYAPA_STATE_NO_DEVICE; | ||
469 | error = cyapa_write_byte(cyapa, CYAPA_CMD_SOFT_RESET, 0x01); | ||
470 | if (error) | ||
471 | return -EIO; | ||
472 | |||
473 | usleep_range(25000, 50000); | ||
474 | waiting_time = 2000; /* For some shipset, max waiting time is 1~2s. */ | ||
475 | do { | ||
476 | error = cyapa_poll_state(cyapa, 500); | ||
477 | if (error) { | ||
478 | if (error == -ETIMEDOUT) { | ||
479 | waiting_time -= 500; | ||
480 | continue; | ||
481 | } | ||
482 | return error; | ||
483 | } | ||
484 | |||
485 | if ((cyapa->state == CYAPA_STATE_BL_IDLE) && | ||
486 | !(cyapa->status[REG_BL_STATUS] & BL_STATUS_WATCHDOG)) | ||
487 | break; | ||
488 | |||
489 | msleep(100); | ||
490 | waiting_time -= 100; | ||
491 | } while (waiting_time > 0); | ||
492 | |||
493 | if ((cyapa->state != CYAPA_STATE_BL_IDLE) || | ||
494 | (cyapa->status[REG_BL_STATUS] & BL_STATUS_WATCHDOG)) | ||
495 | return -EAGAIN; | ||
496 | |||
497 | return 0; | ||
498 | } | ||
499 | |||
500 | static int cyapa_gen3_bl_activate(struct cyapa *cyapa) | ||
501 | { | ||
502 | int error; | ||
503 | |||
504 | error = cyapa_i2c_reg_write_block(cyapa, 0, sizeof(bl_activate), | ||
505 | bl_activate); | ||
506 | if (error) | ||
507 | return error; | ||
508 | |||
509 | /* Wait for bootloader to activate; takes between 2 and 12 seconds */ | ||
510 | msleep(2000); | ||
511 | error = cyapa_poll_state(cyapa, 11000); | ||
512 | if (error) | ||
513 | return error; | ||
514 | if (cyapa->state != CYAPA_STATE_BL_ACTIVE) | ||
515 | return -EAGAIN; | ||
516 | |||
517 | return 0; | ||
518 | } | ||
519 | |||
520 | static int cyapa_gen3_bl_deactivate(struct cyapa *cyapa) | ||
521 | { | ||
522 | int error; | ||
523 | |||
524 | error = cyapa_i2c_reg_write_block(cyapa, 0, sizeof(bl_deactivate), | ||
525 | bl_deactivate); | ||
526 | if (error) | ||
527 | return error; | ||
528 | |||
529 | /* Wait for bootloader to switch to idle state; should take < 100ms */ | ||
530 | msleep(100); | ||
531 | error = cyapa_poll_state(cyapa, 500); | ||
532 | if (error) | ||
533 | return error; | ||
534 | if (cyapa->state != CYAPA_STATE_BL_IDLE) | ||
535 | return -EAGAIN; | ||
536 | return 0; | ||
537 | } | ||
538 | |||
539 | /* | ||
540 | * Exit bootloader | ||
541 | * | ||
542 | * Send bl_exit command, then wait 50 - 100 ms to let device transition to | ||
543 | * operational mode. If this is the first time the device's firmware is | ||
544 | * running, it can take up to 2 seconds to calibrate its sensors. So, poll | ||
545 | * the device's new state for up to 2 seconds. | ||
546 | * | ||
547 | * Returns: | ||
548 | * -EIO failure while reading from device | ||
549 | * -EAGAIN device is stuck in bootloader, b/c it has invalid firmware | ||
550 | * 0 device is supported and in operational mode | ||
551 | */ | ||
552 | static int cyapa_gen3_bl_exit(struct cyapa *cyapa) | ||
553 | { | ||
554 | int error; | ||
555 | |||
556 | error = cyapa_i2c_reg_write_block(cyapa, 0, sizeof(bl_exit), bl_exit); | ||
557 | if (error) | ||
558 | return error; | ||
559 | |||
560 | /* | ||
561 | * Wait for bootloader to exit, and operation mode to start. | ||
562 | * Normally, this takes at least 50 ms. | ||
563 | */ | ||
564 | usleep_range(50000, 100000); | ||
565 | /* | ||
566 | * In addition, when a device boots for the first time after being | ||
567 | * updated to new firmware, it must first calibrate its sensors, which | ||
568 | * can take up to an additional 2 seconds. If the device power is | ||
569 | * running low, this may take even longer. | ||
570 | */ | ||
571 | error = cyapa_poll_state(cyapa, 4000); | ||
572 | if (error < 0) | ||
573 | return error; | ||
574 | if (cyapa->state != CYAPA_STATE_OP) | ||
575 | return -EAGAIN; | ||
576 | |||
577 | return 0; | ||
578 | } | ||
579 | |||
580 | static u16 cyapa_gen3_csum(const u8 *buf, size_t count) | ||
581 | { | ||
582 | int i; | ||
583 | u16 csum = 0; | ||
584 | |||
585 | for (i = 0; i < count; i++) | ||
586 | csum += buf[i]; | ||
587 | |||
588 | return csum; | ||
589 | } | ||
590 | |||
591 | /* | ||
592 | * Verify the integrity of a CYAPA firmware image file. | ||
593 | * | ||
594 | * The firmware image file is 30848 bytes, composed of 482 64-byte blocks. | ||
595 | * | ||
596 | * The first 2 blocks are the firmware header. | ||
597 | * The next 480 blocks are the firmware image. | ||
598 | * | ||
599 | * The first two bytes of the header hold the header checksum, computed by | ||
600 | * summing the other 126 bytes of the header. | ||
601 | * The last two bytes of the header hold the firmware image checksum, computed | ||
602 | * by summing the 30720 bytes of the image modulo 0xffff. | ||
603 | * | ||
604 | * Both checksums are stored little-endian. | ||
605 | */ | ||
606 | static int cyapa_gen3_check_fw(struct cyapa *cyapa, const struct firmware *fw) | ||
607 | { | ||
608 | struct device *dev = &cyapa->client->dev; | ||
609 | u16 csum; | ||
610 | u16 csum_expected; | ||
611 | |||
612 | /* Firmware must match exact 30848 bytes = 482 64-byte blocks. */ | ||
613 | if (fw->size != CYAPA_FW_SIZE) { | ||
614 | dev_err(dev, "invalid firmware size = %zu, expected %u.\n", | ||
615 | fw->size, CYAPA_FW_SIZE); | ||
616 | return -EINVAL; | ||
617 | } | ||
618 | |||
619 | /* Verify header block */ | ||
620 | csum_expected = (fw->data[0] << 8) | fw->data[1]; | ||
621 | csum = cyapa_gen3_csum(&fw->data[2], CYAPA_FW_HDR_SIZE - 2); | ||
622 | if (csum != csum_expected) { | ||
623 | dev_err(dev, "%s %04x, expected: %04x\n", | ||
624 | "invalid firmware header checksum = ", | ||
625 | csum, csum_expected); | ||
626 | return -EINVAL; | ||
627 | } | ||
628 | |||
629 | /* Verify firmware image */ | ||
630 | csum_expected = (fw->data[CYAPA_FW_HDR_SIZE - 2] << 8) | | ||
631 | fw->data[CYAPA_FW_HDR_SIZE - 1]; | ||
632 | csum = cyapa_gen3_csum(&fw->data[CYAPA_FW_HDR_SIZE], | ||
633 | CYAPA_FW_DATA_SIZE); | ||
634 | if (csum != csum_expected) { | ||
635 | dev_err(dev, "%s %04x, expected: %04x\n", | ||
636 | "invalid firmware header checksum = ", | ||
637 | csum, csum_expected); | ||
638 | return -EINVAL; | ||
639 | } | ||
640 | return 0; | ||
641 | } | ||
642 | |||
643 | /* | ||
644 | * Write a |len| byte long buffer |buf| to the device, by chopping it up into a | ||
645 | * sequence of smaller |CYAPA_CMD_LEN|-length write commands. | ||
646 | * | ||
647 | * The data bytes for a write command are prepended with the 1-byte offset | ||
648 | * of the data relative to the start of |buf|. | ||
649 | */ | ||
650 | static int cyapa_gen3_write_buffer(struct cyapa *cyapa, | ||
651 | const u8 *buf, size_t len) | ||
652 | { | ||
653 | int error; | ||
654 | size_t i; | ||
655 | unsigned char cmd[CYAPA_CMD_LEN + 1]; | ||
656 | size_t cmd_len; | ||
657 | |||
658 | for (i = 0; i < len; i += CYAPA_CMD_LEN) { | ||
659 | const u8 *payload = &buf[i]; | ||
660 | |||
661 | cmd_len = (len - i >= CYAPA_CMD_LEN) ? CYAPA_CMD_LEN : len - i; | ||
662 | cmd[0] = i; | ||
663 | memcpy(&cmd[1], payload, cmd_len); | ||
664 | |||
665 | error = cyapa_i2c_reg_write_block(cyapa, 0, cmd_len + 1, cmd); | ||
666 | if (error) | ||
667 | return error; | ||
668 | } | ||
669 | return 0; | ||
670 | } | ||
671 | |||
672 | /* | ||
673 | * A firmware block write command writes 64 bytes of data to a single flash | ||
674 | * page in the device. The 78-byte block write command has the format: | ||
675 | * <0xff> <CMD> <Key> <Start> <Data> <Data-Checksum> <CMD Checksum> | ||
676 | * | ||
677 | * <0xff> - every command starts with 0xff | ||
678 | * <CMD> - the write command value is 0x39 | ||
679 | * <Key> - write commands include an 8-byte key: { 00 01 02 03 04 05 06 07 } | ||
680 | * <Block> - Memory Block number (address / 64) (16-bit, big-endian) | ||
681 | * <Data> - 64 bytes of firmware image data | ||
682 | * <Data Checksum> - sum of 64 <Data> bytes, modulo 0xff | ||
683 | * <CMD Checksum> - sum of 77 bytes, from 0xff to <Data Checksum> | ||
684 | * | ||
685 | * Each write command is split into 5 i2c write transactions of up to 16 bytes. | ||
686 | * Each transaction starts with an i2c register offset: (00, 10, 20, 30, 40). | ||
687 | */ | ||
688 | static int cyapa_gen3_write_fw_block(struct cyapa *cyapa, | ||
689 | u16 block, const u8 *data) | ||
690 | { | ||
691 | int ret; | ||
692 | struct gen3_write_block_cmd write_block_cmd; | ||
693 | u8 status[BL_STATUS_SIZE]; | ||
694 | int tries; | ||
695 | u8 bl_status, bl_error; | ||
696 | |||
697 | /* Set write command and security key bytes. */ | ||
698 | write_block_cmd.checksum_seed = GEN3_BL_CMD_CHECKSUM_SEED; | ||
699 | write_block_cmd.cmd_code = GEN3_BL_CMD_WRITE_BLOCK; | ||
700 | memcpy(write_block_cmd.key, security_key, sizeof(security_key)); | ||
701 | put_unaligned_be16(block, &write_block_cmd.block_num); | ||
702 | memcpy(write_block_cmd.block_data, data, CYAPA_FW_BLOCK_SIZE); | ||
703 | write_block_cmd.block_checksum = cyapa_gen3_csum( | ||
704 | write_block_cmd.block_data, CYAPA_FW_BLOCK_SIZE); | ||
705 | write_block_cmd.cmd_checksum = cyapa_gen3_csum((u8 *)&write_block_cmd, | ||
706 | sizeof(write_block_cmd) - 1); | ||
707 | |||
708 | ret = cyapa_gen3_write_buffer(cyapa, (u8 *)&write_block_cmd, | ||
709 | sizeof(write_block_cmd)); | ||
710 | if (ret) | ||
711 | return ret; | ||
712 | |||
713 | /* Wait for write to finish */ | ||
714 | tries = 11; /* Programming for one block can take about 100ms. */ | ||
715 | do { | ||
716 | usleep_range(10000, 20000); | ||
717 | |||
718 | /* Check block write command result status. */ | ||
719 | ret = cyapa_i2c_reg_read_block(cyapa, BL_HEAD_OFFSET, | ||
720 | BL_STATUS_SIZE, status); | ||
721 | if (ret != BL_STATUS_SIZE) | ||
722 | return (ret < 0) ? ret : -EIO; | ||
723 | } while ((status[REG_BL_STATUS] & BL_STATUS_BUSY) && --tries); | ||
724 | |||
725 | /* Ignore WATCHDOG bit and reserved bits. */ | ||
726 | bl_status = status[REG_BL_STATUS] & ~BL_STATUS_REV_MASK; | ||
727 | bl_error = status[REG_BL_ERROR] & ~BL_ERROR_RESERVED; | ||
728 | |||
729 | if (bl_status & BL_STATUS_BUSY) | ||
730 | ret = -ETIMEDOUT; | ||
731 | else if (bl_status != BL_STATUS_RUNNING || | ||
732 | bl_error != BL_ERROR_BOOTLOADING) | ||
733 | ret = -EIO; | ||
734 | else | ||
735 | ret = 0; | ||
736 | |||
737 | return ret; | ||
738 | } | ||
739 | |||
740 | static int cyapa_gen3_write_blocks(struct cyapa *cyapa, | ||
741 | size_t start_block, size_t block_count, | ||
742 | const u8 *image_data) | ||
743 | { | ||
744 | int error; | ||
745 | int i; | ||
746 | |||
747 | for (i = 0; i < block_count; i++) { | ||
748 | size_t block = start_block + i; | ||
749 | size_t addr = i * CYAPA_FW_BLOCK_SIZE; | ||
750 | const u8 *data = &image_data[addr]; | ||
751 | |||
752 | error = cyapa_gen3_write_fw_block(cyapa, block, data); | ||
753 | if (error) | ||
754 | return error; | ||
755 | } | ||
756 | return 0; | ||
757 | } | ||
758 | |||
759 | static int cyapa_gen3_do_fw_update(struct cyapa *cyapa, | ||
760 | const struct firmware *fw) | ||
761 | { | ||
762 | struct device *dev = &cyapa->client->dev; | ||
763 | int error; | ||
764 | |||
765 | /* First write data, starting at byte 128 of fw->data */ | ||
766 | error = cyapa_gen3_write_blocks(cyapa, | ||
767 | CYAPA_FW_DATA_BLOCK_START, CYAPA_FW_DATA_BLOCK_COUNT, | ||
768 | &fw->data[CYAPA_FW_HDR_BLOCK_COUNT * CYAPA_FW_BLOCK_SIZE]); | ||
769 | if (error) { | ||
770 | dev_err(dev, "FW update aborted, write image: %d\n", error); | ||
771 | return error; | ||
772 | } | ||
773 | |||
774 | /* Then write checksum */ | ||
775 | error = cyapa_gen3_write_blocks(cyapa, | ||
776 | CYAPA_FW_HDR_BLOCK_START, CYAPA_FW_HDR_BLOCK_COUNT, | ||
777 | &fw->data[0]); | ||
778 | if (error) { | ||
779 | dev_err(dev, "FW update aborted, write checksum: %d\n", error); | ||
780 | return error; | ||
781 | } | ||
782 | |||
783 | return 0; | ||
784 | } | ||
785 | |||
786 | static ssize_t cyapa_gen3_do_calibrate(struct device *dev, | ||
787 | struct device_attribute *attr, | ||
788 | const char *buf, size_t count) | ||
789 | { | ||
790 | struct cyapa *cyapa = dev_get_drvdata(dev); | ||
791 | int tries; | ||
792 | int ret; | ||
793 | |||
794 | ret = cyapa_read_byte(cyapa, CYAPA_CMD_DEV_STATUS); | ||
795 | if (ret < 0) { | ||
796 | dev_err(dev, "Error reading dev status: %d\n", ret); | ||
797 | goto out; | ||
798 | } | ||
799 | if ((ret & CYAPA_DEV_NORMAL) != CYAPA_DEV_NORMAL) { | ||
800 | dev_warn(dev, "Trackpad device is busy, device state: 0x%02x\n", | ||
801 | ret); | ||
802 | ret = -EAGAIN; | ||
803 | goto out; | ||
804 | } | ||
805 | |||
806 | ret = cyapa_write_byte(cyapa, CYAPA_CMD_SOFT_RESET, | ||
807 | OP_RECALIBRATION_MASK); | ||
808 | if (ret < 0) { | ||
809 | dev_err(dev, "Failed to send calibrate command: %d\n", | ||
810 | ret); | ||
811 | goto out; | ||
812 | } | ||
813 | |||
814 | tries = 20; /* max recalibration timeout 2s. */ | ||
815 | do { | ||
816 | /* | ||
817 | * For this recalibration, the max time will not exceed 2s. | ||
818 | * The average time is approximately 500 - 700 ms, and we | ||
819 | * will check the status every 100 - 200ms. | ||
820 | */ | ||
821 | usleep_range(100000, 200000); | ||
822 | |||
823 | ret = cyapa_read_byte(cyapa, CYAPA_CMD_DEV_STATUS); | ||
824 | if (ret < 0) { | ||
825 | dev_err(dev, "Error reading dev status: %d\n", | ||
826 | ret); | ||
827 | goto out; | ||
828 | } | ||
829 | if ((ret & CYAPA_DEV_NORMAL) == CYAPA_DEV_NORMAL) | ||
830 | break; | ||
831 | } while (--tries); | ||
832 | |||
833 | if (tries == 0) { | ||
834 | dev_err(dev, "Failed to calibrate. Timeout.\n"); | ||
835 | ret = -ETIMEDOUT; | ||
836 | goto out; | ||
837 | } | ||
838 | dev_dbg(dev, "Calibration successful.\n"); | ||
839 | |||
840 | out: | ||
841 | return ret < 0 ? ret : count; | ||
842 | } | ||
843 | |||
844 | static ssize_t cyapa_gen3_show_baseline(struct device *dev, | ||
845 | struct device_attribute *attr, char *buf) | ||
846 | { | ||
847 | struct cyapa *cyapa = dev_get_drvdata(dev); | ||
848 | int max_baseline, min_baseline; | ||
849 | int tries; | ||
850 | int ret; | ||
851 | |||
852 | ret = cyapa_read_byte(cyapa, CYAPA_CMD_DEV_STATUS); | ||
853 | if (ret < 0) { | ||
854 | dev_err(dev, "Error reading dev status. err = %d\n", ret); | ||
855 | goto out; | ||
856 | } | ||
857 | if ((ret & CYAPA_DEV_NORMAL) != CYAPA_DEV_NORMAL) { | ||
858 | dev_warn(dev, "Trackpad device is busy. device state = 0x%x\n", | ||
859 | ret); | ||
860 | ret = -EAGAIN; | ||
861 | goto out; | ||
862 | } | ||
863 | |||
864 | ret = cyapa_write_byte(cyapa, CYAPA_CMD_SOFT_RESET, | ||
865 | OP_REPORT_BASELINE_MASK); | ||
866 | if (ret < 0) { | ||
867 | dev_err(dev, "Failed to send report baseline command. %d\n", | ||
868 | ret); | ||
869 | goto out; | ||
870 | } | ||
871 | |||
872 | tries = 3; /* Try for 30 to 60 ms */ | ||
873 | do { | ||
874 | usleep_range(10000, 20000); | ||
875 | |||
876 | ret = cyapa_read_byte(cyapa, CYAPA_CMD_DEV_STATUS); | ||
877 | if (ret < 0) { | ||
878 | dev_err(dev, "Error reading dev status. err = %d\n", | ||
879 | ret); | ||
880 | goto out; | ||
881 | } | ||
882 | if ((ret & CYAPA_DEV_NORMAL) == CYAPA_DEV_NORMAL) | ||
883 | break; | ||
884 | } while (--tries); | ||
885 | |||
886 | if (tries == 0) { | ||
887 | dev_err(dev, "Device timed out going to Normal state.\n"); | ||
888 | ret = -ETIMEDOUT; | ||
889 | goto out; | ||
890 | } | ||
891 | |||
892 | ret = cyapa_read_byte(cyapa, CYAPA_CMD_MAX_BASELINE); | ||
893 | if (ret < 0) { | ||
894 | dev_err(dev, "Failed to read max baseline. err = %d\n", ret); | ||
895 | goto out; | ||
896 | } | ||
897 | max_baseline = ret; | ||
898 | |||
899 | ret = cyapa_read_byte(cyapa, CYAPA_CMD_MIN_BASELINE); | ||
900 | if (ret < 0) { | ||
901 | dev_err(dev, "Failed to read min baseline. err = %d\n", ret); | ||
902 | goto out; | ||
903 | } | ||
904 | min_baseline = ret; | ||
905 | |||
906 | dev_dbg(dev, "Baseline report successful. Max: %d Min: %d\n", | ||
907 | max_baseline, min_baseline); | ||
908 | ret = scnprintf(buf, PAGE_SIZE, "%d %d\n", max_baseline, min_baseline); | ||
909 | |||
910 | out: | ||
911 | return ret; | ||
912 | } | ||
913 | |||
914 | /* | ||
915 | * cyapa_get_wait_time_for_pwr_cmd | ||
916 | * | ||
917 | * Compute the amount of time we need to wait after updating the touchpad | ||
918 | * power mode. The touchpad needs to consume the incoming power mode set | ||
919 | * command at the current clock rate. | ||
920 | */ | ||
921 | |||
922 | static u16 cyapa_get_wait_time_for_pwr_cmd(u8 pwr_mode) | ||
923 | { | ||
924 | switch (pwr_mode) { | ||
925 | case PWR_MODE_FULL_ACTIVE: return 20; | ||
926 | case PWR_MODE_BTN_ONLY: return 20; | ||
927 | case PWR_MODE_OFF: return 20; | ||
928 | default: return cyapa_pwr_cmd_to_sleep_time(pwr_mode) + 50; | ||
929 | } | ||
930 | } | ||
931 | |||
932 | /* | ||
933 | * Set device power mode | ||
934 | * | ||
935 | * Write to the field to configure power state. Power states include : | ||
936 | * Full : Max scans and report rate. | ||
937 | * Idle : Report rate set by user specified time. | ||
938 | * ButtonOnly : No scans for fingers. When the button is triggered, | ||
939 | * a slave interrupt is asserted to notify host to wake up. | ||
940 | * Off : Only awake for i2c commands from host. No function for button | ||
941 | * or touch sensors. | ||
942 | * | ||
943 | * The power_mode command should conform to the following : | ||
944 | * Full : 0x3f | ||
945 | * Idle : Configurable from 20 to 1000ms. See note below for | ||
946 | * cyapa_sleep_time_to_pwr_cmd and cyapa_pwr_cmd_to_sleep_time | ||
947 | * ButtonOnly : 0x01 | ||
948 | * Off : 0x00 | ||
949 | * | ||
950 | * Device power mode can only be set when device is in operational mode. | ||
951 | */ | ||
952 | static int cyapa_gen3_set_power_mode(struct cyapa *cyapa, u8 power_mode, | ||
953 | u16 always_unused) | ||
954 | { | ||
955 | int ret; | ||
956 | u8 power; | ||
957 | int tries; | ||
958 | u16 sleep_time; | ||
959 | |||
960 | always_unused = 0; | ||
961 | if (cyapa->state != CYAPA_STATE_OP) | ||
962 | return 0; | ||
963 | |||
964 | tries = SET_POWER_MODE_TRIES; | ||
965 | while (tries--) { | ||
966 | ret = cyapa_read_byte(cyapa, CYAPA_CMD_POWER_MODE); | ||
967 | if (ret >= 0) | ||
968 | break; | ||
969 | usleep_range(SET_POWER_MODE_DELAY, 2 * SET_POWER_MODE_DELAY); | ||
970 | } | ||
971 | if (ret < 0) | ||
972 | return ret; | ||
973 | |||
974 | /* | ||
975 | * Return early if the power mode to set is the same as the current | ||
976 | * one. | ||
977 | */ | ||
978 | if ((ret & PWR_MODE_MASK) == power_mode) | ||
979 | return 0; | ||
980 | |||
981 | sleep_time = cyapa_get_wait_time_for_pwr_cmd(ret & PWR_MODE_MASK); | ||
982 | power = ret; | ||
983 | power &= ~PWR_MODE_MASK; | ||
984 | power |= power_mode & PWR_MODE_MASK; | ||
985 | tries = SET_POWER_MODE_TRIES; | ||
986 | while (tries--) { | ||
987 | ret = cyapa_write_byte(cyapa, CYAPA_CMD_POWER_MODE, power); | ||
988 | if (!ret) | ||
989 | break; | ||
990 | usleep_range(SET_POWER_MODE_DELAY, 2 * SET_POWER_MODE_DELAY); | ||
991 | } | ||
992 | |||
993 | /* | ||
994 | * Wait for the newly set power command to go in at the previous | ||
995 | * clock speed (scanrate) used by the touchpad firmware. Not | ||
996 | * doing so before issuing the next command may result in errors | ||
997 | * depending on the command's content. | ||
998 | */ | ||
999 | msleep(sleep_time); | ||
1000 | return ret; | ||
1001 | } | ||
1002 | |||
1003 | static int cyapa_gen3_get_query_data(struct cyapa *cyapa) | ||
1004 | { | ||
1005 | u8 query_data[QUERY_DATA_SIZE]; | ||
1006 | int ret; | ||
1007 | |||
1008 | if (cyapa->state != CYAPA_STATE_OP) | ||
1009 | return -EBUSY; | ||
1010 | |||
1011 | ret = cyapa_read_block(cyapa, CYAPA_CMD_GROUP_QUERY, query_data); | ||
1012 | if (ret != QUERY_DATA_SIZE) | ||
1013 | return (ret < 0) ? ret : -EIO; | ||
1014 | |||
1015 | memcpy(&cyapa->product_id[0], &query_data[0], 5); | ||
1016 | cyapa->product_id[5] = '-'; | ||
1017 | memcpy(&cyapa->product_id[6], &query_data[5], 6); | ||
1018 | cyapa->product_id[12] = '-'; | ||
1019 | memcpy(&cyapa->product_id[13], &query_data[11], 2); | ||
1020 | cyapa->product_id[15] = '\0'; | ||
1021 | |||
1022 | cyapa->fw_maj_ver = query_data[15]; | ||
1023 | cyapa->fw_min_ver = query_data[16]; | ||
1024 | |||
1025 | cyapa->btn_capability = query_data[19] & CAPABILITY_BTN_MASK; | ||
1026 | |||
1027 | cyapa->gen = query_data[20] & 0x0f; | ||
1028 | |||
1029 | cyapa->max_abs_x = ((query_data[21] & 0xf0) << 4) | query_data[22]; | ||
1030 | cyapa->max_abs_y = ((query_data[21] & 0x0f) << 8) | query_data[23]; | ||
1031 | |||
1032 | cyapa->physical_size_x = | ||
1033 | ((query_data[24] & 0xf0) << 4) | query_data[25]; | ||
1034 | cyapa->physical_size_y = | ||
1035 | ((query_data[24] & 0x0f) << 8) | query_data[26]; | ||
1036 | |||
1037 | cyapa->max_z = 255; | ||
1038 | |||
1039 | return 0; | ||
1040 | } | ||
1041 | |||
1042 | static int cyapa_gen3_bl_query_data(struct cyapa *cyapa) | ||
1043 | { | ||
1044 | u8 bl_data[CYAPA_CMD_LEN]; | ||
1045 | int ret; | ||
1046 | |||
1047 | ret = cyapa_i2c_reg_read_block(cyapa, 0, CYAPA_CMD_LEN, bl_data); | ||
1048 | if (ret != CYAPA_CMD_LEN) | ||
1049 | return (ret < 0) ? ret : -EIO; | ||
1050 | |||
1051 | /* | ||
1052 | * This value will be updated again when entered application mode. | ||
1053 | * If TP failed to enter application mode, this fw version values | ||
1054 | * can be used as a reference. | ||
1055 | * This firmware version valid when fw image checksum is valid. | ||
1056 | */ | ||
1057 | if (bl_data[REG_BL_STATUS] == | ||
1058 | (BL_STATUS_RUNNING | BL_STATUS_CSUM_VALID)) { | ||
1059 | cyapa->fw_maj_ver = bl_data[GEN3_BL_IDLE_FW_MAJ_VER_OFFSET]; | ||
1060 | cyapa->fw_min_ver = bl_data[GEN3_BL_IDLE_FW_MIN_VER_OFFSET]; | ||
1061 | } | ||
1062 | |||
1063 | return 0; | ||
1064 | } | ||
1065 | |||
1066 | /* | ||
1067 | * Check if device is operational. | ||
1068 | * | ||
1069 | * An operational device is responding, has exited bootloader, and has | ||
1070 | * firmware supported by this driver. | ||
1071 | * | ||
1072 | * Returns: | ||
1073 | * -EBUSY no device or in bootloader | ||
1074 | * -EIO failure while reading from device | ||
1075 | * -EAGAIN device is still in bootloader | ||
1076 | * if ->state = CYAPA_STATE_BL_IDLE, device has invalid firmware | ||
1077 | * -EINVAL device is in operational mode, but not supported by this driver | ||
1078 | * 0 device is supported | ||
1079 | */ | ||
1080 | static int cyapa_gen3_do_operational_check(struct cyapa *cyapa) | ||
1081 | { | ||
1082 | struct device *dev = &cyapa->client->dev; | ||
1083 | int error; | ||
1084 | |||
1085 | switch (cyapa->state) { | ||
1086 | case CYAPA_STATE_BL_ACTIVE: | ||
1087 | error = cyapa_gen3_bl_deactivate(cyapa); | ||
1088 | if (error) { | ||
1089 | dev_err(dev, "failed to bl_deactivate: %d\n", error); | ||
1090 | return error; | ||
1091 | } | ||
1092 | |||
1093 | /* Fallthrough state */ | ||
1094 | case CYAPA_STATE_BL_IDLE: | ||
1095 | /* Try to get firmware version in bootloader mode. */ | ||
1096 | cyapa_gen3_bl_query_data(cyapa); | ||
1097 | |||
1098 | error = cyapa_gen3_bl_exit(cyapa); | ||
1099 | if (error) { | ||
1100 | dev_err(dev, "failed to bl_exit: %d\n", error); | ||
1101 | return error; | ||
1102 | } | ||
1103 | |||
1104 | /* Fallthrough state */ | ||
1105 | case CYAPA_STATE_OP: | ||
1106 | /* | ||
1107 | * Reading query data before going back to the full mode | ||
1108 | * may cause problems, so we set the power mode first here. | ||
1109 | */ | ||
1110 | error = cyapa_gen3_set_power_mode(cyapa, | ||
1111 | PWR_MODE_FULL_ACTIVE, 0); | ||
1112 | if (error) | ||
1113 | dev_err(dev, "%s: set full power mode failed: %d\n", | ||
1114 | __func__, error); | ||
1115 | error = cyapa_gen3_get_query_data(cyapa); | ||
1116 | if (error < 0) | ||
1117 | return error; | ||
1118 | |||
1119 | /* Only support firmware protocol gen3 */ | ||
1120 | if (cyapa->gen != CYAPA_GEN3) { | ||
1121 | dev_err(dev, "unsupported protocol version (%d)", | ||
1122 | cyapa->gen); | ||
1123 | return -EINVAL; | ||
1124 | } | ||
1125 | |||
1126 | /* Only support product ID starting with CYTRA */ | ||
1127 | if (memcmp(cyapa->product_id, product_id, | ||
1128 | strlen(product_id)) != 0) { | ||
1129 | dev_err(dev, "unsupported product ID (%s)\n", | ||
1130 | cyapa->product_id); | ||
1131 | return -EINVAL; | ||
1132 | } | ||
1133 | |||
1134 | return 0; | ||
1135 | |||
1136 | default: | ||
1137 | return -EIO; | ||
1138 | } | ||
1139 | return 0; | ||
1140 | } | ||
1141 | |||
1142 | /* | ||
1143 | * Return false, do not continue process | ||
1144 | * Return true, continue process. | ||
1145 | */ | ||
1146 | static bool cyapa_gen3_irq_cmd_handler(struct cyapa *cyapa) | ||
1147 | { | ||
1148 | /* Not gen3 irq command response, skip for continue. */ | ||
1149 | if (cyapa->gen != CYAPA_GEN3) | ||
1150 | return true; | ||
1151 | |||
1152 | if (cyapa->operational) | ||
1153 | return true; | ||
1154 | |||
1155 | /* | ||
1156 | * Driver in detecting or other interface function processing, | ||
1157 | * so, stop cyapa_gen3_irq_handler to continue process to | ||
1158 | * avoid unwanted to error detecting and processing. | ||
1159 | * | ||
1160 | * And also, avoid the periodicly accerted interrupts to be processed | ||
1161 | * as touch inputs when gen3 failed to launch into application mode, | ||
1162 | * which will cause gen3 stays in bootloader mode. | ||
1163 | */ | ||
1164 | return false; | ||
1165 | } | ||
1166 | |||
1167 | static int cyapa_gen3_irq_handler(struct cyapa *cyapa) | ||
1168 | { | ||
1169 | struct input_dev *input = cyapa->input; | ||
1170 | struct device *dev = &cyapa->client->dev; | ||
1171 | struct cyapa_reg_data data; | ||
1172 | int num_fingers; | ||
1173 | int ret; | ||
1174 | int i; | ||
1175 | |||
1176 | ret = cyapa_read_block(cyapa, CYAPA_CMD_GROUP_DATA, (u8 *)&data); | ||
1177 | if (ret != sizeof(data)) { | ||
1178 | dev_err(dev, "failed to read report data, (%d)\n", ret); | ||
1179 | return -EINVAL; | ||
1180 | } | ||
1181 | |||
1182 | if ((data.device_status & OP_STATUS_SRC) != OP_STATUS_SRC || | ||
1183 | (data.device_status & OP_STATUS_DEV) != CYAPA_DEV_NORMAL || | ||
1184 | (data.finger_btn & OP_DATA_VALID) != OP_DATA_VALID) { | ||
1185 | dev_err(dev, "invalid device state bytes, %02x %02x\n", | ||
1186 | data.device_status, data.finger_btn); | ||
1187 | return -EINVAL; | ||
1188 | } | ||
1189 | |||
1190 | num_fingers = (data.finger_btn >> 4) & 0x0f; | ||
1191 | for (i = 0; i < num_fingers; i++) { | ||
1192 | const struct cyapa_touch *touch = &data.touches[i]; | ||
1193 | /* Note: touch->id range is 1 to 15; slots are 0 to 14. */ | ||
1194 | int slot = touch->id - 1; | ||
1195 | |||
1196 | input_mt_slot(input, slot); | ||
1197 | input_mt_report_slot_state(input, MT_TOOL_FINGER, true); | ||
1198 | input_report_abs(input, ABS_MT_POSITION_X, | ||
1199 | ((touch->xy_hi & 0xf0) << 4) | touch->x_lo); | ||
1200 | input_report_abs(input, ABS_MT_POSITION_Y, | ||
1201 | ((touch->xy_hi & 0x0f) << 8) | touch->y_lo); | ||
1202 | input_report_abs(input, ABS_MT_PRESSURE, touch->pressure); | ||
1203 | } | ||
1204 | |||
1205 | input_mt_sync_frame(input); | ||
1206 | |||
1207 | if (cyapa->btn_capability & CAPABILITY_LEFT_BTN_MASK) | ||
1208 | input_report_key(input, BTN_LEFT, | ||
1209 | !!(data.finger_btn & OP_DATA_LEFT_BTN)); | ||
1210 | if (cyapa->btn_capability & CAPABILITY_MIDDLE_BTN_MASK) | ||
1211 | input_report_key(input, BTN_MIDDLE, | ||
1212 | !!(data.finger_btn & OP_DATA_MIDDLE_BTN)); | ||
1213 | if (cyapa->btn_capability & CAPABILITY_RIGHT_BTN_MASK) | ||
1214 | input_report_key(input, BTN_RIGHT, | ||
1215 | !!(data.finger_btn & OP_DATA_RIGHT_BTN)); | ||
1216 | input_sync(input); | ||
1217 | |||
1218 | return 0; | ||
1219 | } | ||
1220 | |||
1221 | static int cyapa_gen3_initialize(struct cyapa *cyapa) { return 0; } | ||
1222 | static int cyapa_gen3_bl_initiate(struct cyapa *cyapa, | ||
1223 | const struct firmware *fw) { return 0; } | ||
1224 | static int cyapa_gen3_empty_output_data(struct cyapa *cyapa, | ||
1225 | u8 *buf, int *len, cb_sort func) { return 0; } | ||
1226 | |||
1227 | const struct cyapa_dev_ops cyapa_gen3_ops = { | ||
1228 | .check_fw = cyapa_gen3_check_fw, | ||
1229 | .bl_enter = cyapa_gen3_bl_enter, | ||
1230 | .bl_activate = cyapa_gen3_bl_activate, | ||
1231 | .update_fw = cyapa_gen3_do_fw_update, | ||
1232 | .bl_deactivate = cyapa_gen3_bl_deactivate, | ||
1233 | .bl_initiate = cyapa_gen3_bl_initiate, | ||
1234 | |||
1235 | .show_baseline = cyapa_gen3_show_baseline, | ||
1236 | .calibrate_store = cyapa_gen3_do_calibrate, | ||
1237 | |||
1238 | .initialize = cyapa_gen3_initialize, | ||
1239 | |||
1240 | .state_parse = cyapa_gen3_state_parse, | ||
1241 | .operational_check = cyapa_gen3_do_operational_check, | ||
1242 | |||
1243 | .irq_handler = cyapa_gen3_irq_handler, | ||
1244 | .irq_cmd_handler = cyapa_gen3_irq_cmd_handler, | ||
1245 | .sort_empty_output_data = cyapa_gen3_empty_output_data, | ||
1246 | .set_power_mode = cyapa_gen3_set_power_mode, | ||
1247 | }; | ||
diff --git a/drivers/input/mouse/cyapa_gen5.c b/drivers/input/mouse/cyapa_gen5.c new file mode 100644 index 000000000000..ddf5393a1180 --- /dev/null +++ b/drivers/input/mouse/cyapa_gen5.c | |||
@@ -0,0 +1,2777 @@ | |||
1 | /* | ||
2 | * Cypress APA trackpad with I2C interface | ||
3 | * | ||
4 | * Author: Dudley Du <dudl@cypress.com> | ||
5 | * | ||
6 | * Copyright (C) 2014 Cypress Semiconductor, Inc. | ||
7 | * | ||
8 | * This file is subject to the terms and conditions of the GNU General Public | ||
9 | * License. See the file COPYING in the main directory of this archive for | ||
10 | * more details. | ||
11 | */ | ||
12 | |||
13 | #include <linux/delay.h> | ||
14 | #include <linux/i2c.h> | ||
15 | #include <linux/input.h> | ||
16 | #include <linux/input/mt.h> | ||
17 | #include <linux/mutex.h> | ||
18 | #include <linux/completion.h> | ||
19 | #include <linux/slab.h> | ||
20 | #include <linux/unaligned/access_ok.h> | ||
21 | #include <linux/crc-itu-t.h> | ||
22 | #include "cyapa.h" | ||
23 | |||
24 | |||
25 | /* Macro of Gen5 */ | ||
26 | #define RECORD_EVENT_NONE 0 | ||
27 | #define RECORD_EVENT_TOUCHDOWN 1 | ||
28 | #define RECORD_EVENT_DISPLACE 2 | ||
29 | #define RECORD_EVENT_LIFTOFF 3 | ||
30 | |||
31 | #define CYAPA_TSG_FLASH_MAP_BLOCK_SIZE 0x80 | ||
32 | #define CYAPA_TSG_IMG_FW_HDR_SIZE 13 | ||
33 | #define CYAPA_TSG_FW_ROW_SIZE (CYAPA_TSG_FLASH_MAP_BLOCK_SIZE) | ||
34 | #define CYAPA_TSG_IMG_START_ROW_NUM 0x002e | ||
35 | #define CYAPA_TSG_IMG_END_ROW_NUM 0x01fe | ||
36 | #define CYAPA_TSG_IMG_APP_INTEGRITY_ROW_NUM 0x01ff | ||
37 | #define CYAPA_TSG_IMG_MAX_RECORDS (CYAPA_TSG_IMG_END_ROW_NUM - \ | ||
38 | CYAPA_TSG_IMG_START_ROW_NUM + 1 + 1) | ||
39 | #define CYAPA_TSG_IMG_READ_SIZE (CYAPA_TSG_FLASH_MAP_BLOCK_SIZE / 2) | ||
40 | #define CYAPA_TSG_START_OF_APPLICATION 0x1700 | ||
41 | #define CYAPA_TSG_APP_INTEGRITY_SIZE 60 | ||
42 | #define CYAPA_TSG_FLASH_MAP_METADATA_SIZE 60 | ||
43 | #define CYAPA_TSG_BL_KEY_SIZE 8 | ||
44 | |||
45 | #define CYAPA_TSG_MAX_CMD_SIZE 256 | ||
46 | |||
47 | #define GEN5_BL_CMD_VERIFY_APP_INTEGRITY 0x31 | ||
48 | #define GEN5_BL_CMD_GET_BL_INFO 0x38 | ||
49 | #define GEN5_BL_CMD_PROGRAM_VERIFY_ROW 0x39 | ||
50 | #define GEN5_BL_CMD_LAUNCH_APP 0x3b | ||
51 | #define GEN5_BL_CMD_INITIATE_BL 0x48 | ||
52 | |||
53 | #define GEN5_HID_DESCRIPTOR_ADDR 0x0001 | ||
54 | #define GEN5_REPORT_DESCRIPTOR_ADDR 0x0002 | ||
55 | #define GEN5_INPUT_REPORT_ADDR 0x0003 | ||
56 | #define GEN5_OUTPUT_REPORT_ADDR 0x0004 | ||
57 | #define GEN5_CMD_DATA_ADDR 0x0006 | ||
58 | |||
59 | #define GEN5_TOUCH_REPORT_HEAD_SIZE 7 | ||
60 | #define GEN5_TOUCH_REPORT_MAX_SIZE 127 | ||
61 | #define GEN5_BTN_REPORT_HEAD_SIZE 6 | ||
62 | #define GEN5_BTN_REPORT_MAX_SIZE 14 | ||
63 | #define GEN5_WAKEUP_EVENT_SIZE 4 | ||
64 | #define GEN5_RAW_DATA_HEAD_SIZE 24 | ||
65 | |||
66 | #define GEN5_BL_CMD_REPORT_ID 0x40 | ||
67 | #define GEN5_BL_RESP_REPORT_ID 0x30 | ||
68 | #define GEN5_APP_CMD_REPORT_ID 0x2f | ||
69 | #define GEN5_APP_RESP_REPORT_ID 0x1f | ||
70 | |||
71 | #define GEN5_APP_DEEP_SLEEP_REPORT_ID 0xf0 | ||
72 | #define GEN5_DEEP_SLEEP_RESP_LENGTH 5 | ||
73 | |||
74 | #define GEN5_CMD_GET_PARAMETER 0x05 | ||
75 | #define GEN5_CMD_SET_PARAMETER 0x06 | ||
76 | #define GEN5_PARAMETER_ACT_INTERVL_ID 0x4d | ||
77 | #define GEN5_PARAMETER_ACT_INTERVL_SIZE 1 | ||
78 | #define GEN5_PARAMETER_ACT_LFT_INTERVL_ID 0x4f | ||
79 | #define GEN5_PARAMETER_ACT_LFT_INTERVL_SIZE 2 | ||
80 | #define GEN5_PARAMETER_LP_INTRVL_ID 0x4c | ||
81 | #define GEN5_PARAMETER_LP_INTRVL_SIZE 2 | ||
82 | |||
83 | #define GEN5_PARAMETER_DISABLE_PIP_REPORT 0x08 | ||
84 | |||
85 | #define GEN5_POWER_STATE_ACTIVE 0x01 | ||
86 | #define GEN5_POWER_STATE_LOOK_FOR_TOUCH 0x02 | ||
87 | #define GEN5_POWER_STATE_READY 0x03 | ||
88 | #define GEN5_POWER_STATE_IDLE 0x04 | ||
89 | #define GEN5_POWER_STATE_BTN_ONLY 0x05 | ||
90 | #define GEN5_POWER_STATE_OFF 0x06 | ||
91 | |||
92 | #define GEN5_DEEP_SLEEP_STATE_MASK 0x03 | ||
93 | #define GEN5_DEEP_SLEEP_STATE_ON 0x00 | ||
94 | #define GEN5_DEEP_SLEEP_STATE_OFF 0x01 | ||
95 | |||
96 | #define GEN5_DEEP_SLEEP_OPCODE 0x08 | ||
97 | #define GEN5_DEEP_SLEEP_OPCODE_MASK 0x0f | ||
98 | |||
99 | #define GEN5_POWER_READY_MAX_INTRVL_TIME 50 /* Unit: ms */ | ||
100 | #define GEN5_POWER_IDLE_MAX_INTRVL_TIME 250 /* Unit: ms */ | ||
101 | |||
102 | #define GEN5_CMD_REPORT_ID_OFFSET 4 | ||
103 | |||
104 | #define GEN5_RESP_REPORT_ID_OFFSET 2 | ||
105 | #define GEN5_RESP_RSVD_OFFSET 3 | ||
106 | #define GEN5_RESP_RSVD_KEY 0x00 | ||
107 | #define GEN5_RESP_BL_SOP_OFFSET 4 | ||
108 | #define GEN5_SOP_KEY 0x01 /* Start of Packet */ | ||
109 | #define GEN5_EOP_KEY 0x17 /* End of Packet */ | ||
110 | #define GEN5_RESP_APP_CMD_OFFSET 4 | ||
111 | #define GET_GEN5_CMD_CODE(reg) ((reg) & 0x7f) | ||
112 | |||
113 | #define VALID_CMD_RESP_HEADER(resp, cmd) \ | ||
114 | (((resp)[GEN5_RESP_REPORT_ID_OFFSET] == GEN5_APP_RESP_REPORT_ID) && \ | ||
115 | ((resp)[GEN5_RESP_RSVD_OFFSET] == GEN5_RESP_RSVD_KEY) && \ | ||
116 | (GET_GEN5_CMD_CODE((resp)[GEN5_RESP_APP_CMD_OFFSET]) == (cmd))) | ||
117 | |||
118 | #define GEN5_MIN_BL_CMD_LENGTH 13 | ||
119 | #define GEN5_MIN_BL_RESP_LENGTH 11 | ||
120 | #define GEN5_MIN_APP_CMD_LENGTH 7 | ||
121 | #define GEN5_MIN_APP_RESP_LENGTH 5 | ||
122 | #define GEN5_UNSUPPORTED_CMD_RESP_LENGTH 6 | ||
123 | |||
124 | #define GEN5_RESP_LENGTH_OFFSET 0x00 | ||
125 | #define GEN5_RESP_LENGTH_SIZE 2 | ||
126 | |||
127 | #define GEN5_HID_DESCRIPTOR_SIZE 32 | ||
128 | #define GEN5_BL_HID_REPORT_ID 0xff | ||
129 | #define GEN5_APP_HID_REPORT_ID 0xf7 | ||
130 | #define GEN5_BL_MAX_OUTPUT_LENGTH 0x0100 | ||
131 | #define GEN5_APP_MAX_OUTPUT_LENGTH 0x00fe | ||
132 | |||
133 | #define GEN5_BL_REPORT_DESCRIPTOR_SIZE 0x1d | ||
134 | #define GEN5_BL_REPORT_DESCRIPTOR_ID 0xfe | ||
135 | #define GEN5_APP_REPORT_DESCRIPTOR_SIZE 0xee | ||
136 | #define GEN5_APP_CONTRACT_REPORT_DESCRIPTOR_SIZE 0xfa | ||
137 | #define GEN5_APP_REPORT_DESCRIPTOR_ID 0xf6 | ||
138 | |||
139 | #define GEN5_TOUCH_REPORT_ID 0x01 | ||
140 | #define GEN5_BTN_REPORT_ID 0x03 | ||
141 | #define GEN5_WAKEUP_EVENT_REPORT_ID 0x04 | ||
142 | #define GEN5_OLD_PUSH_BTN_REPORT_ID 0x05 | ||
143 | #define GEN5_PUSH_BTN_REPORT_ID 0x06 | ||
144 | |||
145 | #define GEN5_CMD_COMPLETE_SUCCESS(status) ((status) == 0x00) | ||
146 | |||
147 | #define GEN5_BL_INITIATE_RESP_LEN 11 | ||
148 | #define GEN5_BL_FAIL_EXIT_RESP_LEN 11 | ||
149 | #define GEN5_BL_FAIL_EXIT_STATUS_CODE 0x0c | ||
150 | #define GEN5_BL_VERIFY_INTEGRITY_RESP_LEN 12 | ||
151 | #define GEN5_BL_INTEGRITY_CHEKC_PASS 0x00 | ||
152 | #define GEN5_BL_BLOCK_WRITE_RESP_LEN 11 | ||
153 | #define GEN5_BL_READ_APP_INFO_RESP_LEN 31 | ||
154 | #define GEN5_CMD_CALIBRATE 0x28 | ||
155 | #define CYAPA_SENSING_MODE_MUTUAL_CAP_FINE 0x00 | ||
156 | #define CYAPA_SENSING_MODE_SELF_CAP 0x02 | ||
157 | |||
158 | #define GEN5_CMD_RETRIEVE_DATA_STRUCTURE 0x24 | ||
159 | #define GEN5_RETRIEVE_MUTUAL_PWC_DATA 0x00 | ||
160 | #define GEN5_RETRIEVE_SELF_CAP_PWC_DATA 0x01 | ||
161 | |||
162 | #define GEN5_RETRIEVE_DATA_ELEMENT_SIZE_MASK 0x07 | ||
163 | |||
164 | #define GEN5_CMD_EXECUTE_PANEL_SCAN 0x2a | ||
165 | #define GEN5_CMD_RETRIEVE_PANEL_SCAN 0x2b | ||
166 | #define GEN5_PANEL_SCAN_MUTUAL_RAW_DATA 0x00 | ||
167 | #define GEN5_PANEL_SCAN_MUTUAL_BASELINE 0x01 | ||
168 | #define GEN5_PANEL_SCAN_MUTUAL_DIFFCOUNT 0x02 | ||
169 | #define GEN5_PANEL_SCAN_SELF_RAW_DATA 0x03 | ||
170 | #define GEN5_PANEL_SCAN_SELF_BASELINE 0x04 | ||
171 | #define GEN5_PANEL_SCAN_SELF_DIFFCOUNT 0x05 | ||
172 | |||
173 | /* The offset only valid for reterive PWC and panel scan commands */ | ||
174 | #define GEN5_RESP_DATA_STRUCTURE_OFFSET 10 | ||
175 | #define GEN5_PWC_DATA_ELEMENT_SIZE_MASK 0x07 | ||
176 | |||
177 | #define GEN5_NUMBER_OF_TOUCH_OFFSET 5 | ||
178 | #define GEN5_NUMBER_OF_TOUCH_MASK 0x1f | ||
179 | #define GEN5_BUTTONS_OFFSET 5 | ||
180 | #define GEN5_BUTTONS_MASK 0x0f | ||
181 | #define GEN5_GET_EVENT_ID(reg) (((reg) >> 5) & 0x03) | ||
182 | #define GEN5_GET_TOUCH_ID(reg) ((reg) & 0x1f) | ||
183 | |||
184 | #define GEN5_PRODUCT_FAMILY_MASK 0xf000 | ||
185 | #define GEN5_PRODUCT_FAMILY_TRACKPAD 0x1000 | ||
186 | |||
187 | #define TSG_INVALID_CMD 0xff | ||
188 | |||
189 | struct cyapa_gen5_touch_record { | ||
190 | /* | ||
191 | * Bit 7 - 3: reserved | ||
192 | * Bit 2 - 0: touch type; | ||
193 | * 0 : standard finger; | ||
194 | * 1 - 15 : reserved. | ||
195 | */ | ||
196 | u8 touch_type; | ||
197 | |||
198 | /* | ||
199 | * Bit 7: indicates touch liftoff status. | ||
200 | * 0 : touch is currently on the panel. | ||
201 | * 1 : touch record indicates a liftoff. | ||
202 | * Bit 6 - 5: indicates an event associated with this touch instance | ||
203 | * 0 : no event | ||
204 | * 1 : touchdown | ||
205 | * 2 : significant displacement (> active distance) | ||
206 | * 3 : liftoff (record reports last known coordinates) | ||
207 | * Bit 4 - 0: An arbitrary ID tag associated with a finger | ||
208 | * to allow tracking a touch as it moves around the panel. | ||
209 | */ | ||
210 | u8 touch_tip_event_id; | ||
211 | |||
212 | /* Bit 7 - 0 of X-axis coordinate of the touch in pixel. */ | ||
213 | u8 x_lo; | ||
214 | |||
215 | /* Bit 15 - 8 of X-axis coordinate of the touch in pixel. */ | ||
216 | u8 x_hi; | ||
217 | |||
218 | /* Bit 7 - 0 of Y-axis coordinate of the touch in pixel. */ | ||
219 | u8 y_lo; | ||
220 | |||
221 | /* Bit 15 - 8 of Y-axis coordinate of the touch in pixel. */ | ||
222 | u8 y_hi; | ||
223 | |||
224 | /* Touch intensity in counts, pressure value. */ | ||
225 | u8 z; | ||
226 | |||
227 | /* | ||
228 | * The length of the major axis of the ellipse of contact between | ||
229 | * the finger and the panel (ABS_MT_TOUCH_MAJOR). | ||
230 | */ | ||
231 | u8 major_axis_len; | ||
232 | |||
233 | /* | ||
234 | * The length of the minor axis of the ellipse of contact between | ||
235 | * the finger and the panel (ABS_MT_TOUCH_MINOR). | ||
236 | */ | ||
237 | u8 minor_axis_len; | ||
238 | |||
239 | /* | ||
240 | * The length of the major axis of the approaching tool. | ||
241 | * (ABS_MT_WIDTH_MAJOR) | ||
242 | */ | ||
243 | u8 major_tool_len; | ||
244 | |||
245 | /* | ||
246 | * The length of the minor axis of the approaching tool. | ||
247 | * (ABS_MT_WIDTH_MINOR) | ||
248 | */ | ||
249 | u8 minor_tool_len; | ||
250 | |||
251 | /* | ||
252 | * The angle between the panel vertical axis and | ||
253 | * the major axis of the contact ellipse. This value is an 8-bit | ||
254 | * signed integer. The range is -127 to +127 (corresponding to | ||
255 | * -90 degree and +90 degree respectively). | ||
256 | * The positive direction is clockwise from the vertical axis. | ||
257 | * If the ellipse of contact degenerates into a circle, | ||
258 | * orientation is reported as 0. | ||
259 | */ | ||
260 | u8 orientation; | ||
261 | } __packed; | ||
262 | |||
263 | struct cyapa_gen5_report_data { | ||
264 | u8 report_head[GEN5_TOUCH_REPORT_HEAD_SIZE]; | ||
265 | struct cyapa_gen5_touch_record touch_records[10]; | ||
266 | } __packed; | ||
267 | |||
268 | struct cyapa_tsg_bin_image_head { | ||
269 | u8 head_size; /* Unit: bytes, including itself. */ | ||
270 | u8 ttda_driver_major_version; /* Reserved as 0. */ | ||
271 | u8 ttda_driver_minor_version; /* Reserved as 0. */ | ||
272 | u8 fw_major_version; | ||
273 | u8 fw_minor_version; | ||
274 | u8 fw_revision_control_number[8]; | ||
275 | } __packed; | ||
276 | |||
277 | struct cyapa_tsg_bin_image_data_record { | ||
278 | u8 flash_array_id; | ||
279 | __be16 row_number; | ||
280 | /* The number of bytes of flash data contained in this record. */ | ||
281 | __be16 record_len; | ||
282 | /* The flash program data. */ | ||
283 | u8 record_data[CYAPA_TSG_FW_ROW_SIZE]; | ||
284 | } __packed; | ||
285 | |||
286 | struct cyapa_tsg_bin_image { | ||
287 | struct cyapa_tsg_bin_image_head image_head; | ||
288 | struct cyapa_tsg_bin_image_data_record records[0]; | ||
289 | } __packed; | ||
290 | |||
291 | struct gen5_bl_packet_start { | ||
292 | u8 sop; /* Start of packet, must be 01h */ | ||
293 | u8 cmd_code; | ||
294 | __le16 data_length; /* Size of data parameter start from data[0] */ | ||
295 | } __packed; | ||
296 | |||
297 | struct gen5_bl_packet_end { | ||
298 | __le16 crc; | ||
299 | u8 eop; /* End of packet, must be 17h */ | ||
300 | } __packed; | ||
301 | |||
302 | struct gen5_bl_cmd_head { | ||
303 | __le16 addr; /* Output report register address, must be 0004h */ | ||
304 | /* Size of packet not including output report register address */ | ||
305 | __le16 length; | ||
306 | u8 report_id; /* Bootloader output report id, must be 40h */ | ||
307 | u8 rsvd; /* Reserved, must be 0 */ | ||
308 | struct gen5_bl_packet_start packet_start; | ||
309 | u8 data[0]; /* Command data variable based on commands */ | ||
310 | } __packed; | ||
311 | |||
312 | /* Initiate bootload command data structure. */ | ||
313 | struct gen5_bl_initiate_cmd_data { | ||
314 | /* Key must be "A5h 01h 02h 03h FFh FEh FDh 5Ah" */ | ||
315 | u8 key[CYAPA_TSG_BL_KEY_SIZE]; | ||
316 | u8 metadata_raw_parameter[CYAPA_TSG_FLASH_MAP_METADATA_SIZE]; | ||
317 | __le16 metadata_crc; | ||
318 | } __packed; | ||
319 | |||
320 | struct gen5_bl_metadata_row_params { | ||
321 | __le16 size; | ||
322 | __le16 maximum_size; | ||
323 | __le32 app_start; | ||
324 | __le16 app_len; | ||
325 | __le16 app_crc; | ||
326 | __le32 app_entry; | ||
327 | __le32 upgrade_start; | ||
328 | __le16 upgrade_len; | ||
329 | __le16 entry_row_crc; | ||
330 | u8 padding[36]; /* Padding data must be 0 */ | ||
331 | __le16 metadata_crc; /* CRC starts at offset of 60 */ | ||
332 | } __packed; | ||
333 | |||
334 | /* Bootload program and verify row command data structure */ | ||
335 | struct gen5_bl_flash_row_head { | ||
336 | u8 flash_array_id; | ||
337 | __le16 flash_row_id; | ||
338 | u8 flash_data[0]; | ||
339 | } __packed; | ||
340 | |||
341 | struct gen5_app_cmd_head { | ||
342 | __le16 addr; /* Output report register address, must be 0004h */ | ||
343 | /* Size of packet not including output report register address */ | ||
344 | __le16 length; | ||
345 | u8 report_id; /* Application output report id, must be 2Fh */ | ||
346 | u8 rsvd; /* Reserved, must be 0 */ | ||
347 | /* | ||
348 | * Bit 7: reserved, must be 0. | ||
349 | * Bit 6-0: command code. | ||
350 | */ | ||
351 | u8 cmd_code; | ||
352 | u8 parameter_data[0]; /* Parameter data variable based on cmd_code */ | ||
353 | } __packed; | ||
354 | |||
355 | /* Applicaton get/set parameter command data structure */ | ||
356 | struct gen5_app_set_parameter_data { | ||
357 | u8 parameter_id; | ||
358 | u8 parameter_size; | ||
359 | __le32 value; | ||
360 | } __packed; | ||
361 | |||
362 | struct gen5_app_get_parameter_data { | ||
363 | u8 parameter_id; | ||
364 | } __packed; | ||
365 | |||
366 | struct gen5_retrieve_panel_scan_data { | ||
367 | __le16 read_offset; | ||
368 | __le16 read_elements; | ||
369 | u8 data_id; | ||
370 | } __packed; | ||
371 | |||
372 | /* Variables to record latest gen5 trackpad power states. */ | ||
373 | #define GEN5_DEV_SET_PWR_STATE(cyapa, s) ((cyapa)->dev_pwr_mode = (s)) | ||
374 | #define GEN5_DEV_GET_PWR_STATE(cyapa) ((cyapa)->dev_pwr_mode) | ||
375 | #define GEN5_DEV_SET_SLEEP_TIME(cyapa, t) ((cyapa)->dev_sleep_time = (t)) | ||
376 | #define GEN5_DEV_GET_SLEEP_TIME(cyapa) ((cyapa)->dev_sleep_time) | ||
377 | #define GEN5_DEV_UNINIT_SLEEP_TIME(cyapa) \ | ||
378 | (((cyapa)->dev_sleep_time) == UNINIT_SLEEP_TIME) | ||
379 | |||
380 | |||
381 | static u8 cyapa_gen5_bl_cmd_key[] = { 0xa5, 0x01, 0x02, 0x03, | ||
382 | 0xff, 0xfe, 0xfd, 0x5a }; | ||
383 | |||
384 | static int cyapa_gen5_initialize(struct cyapa *cyapa) | ||
385 | { | ||
386 | struct cyapa_gen5_cmd_states *gen5_pip = &cyapa->cmd_states.gen5; | ||
387 | |||
388 | init_completion(&gen5_pip->cmd_ready); | ||
389 | atomic_set(&gen5_pip->cmd_issued, 0); | ||
390 | mutex_init(&gen5_pip->cmd_lock); | ||
391 | |||
392 | gen5_pip->resp_sort_func = NULL; | ||
393 | gen5_pip->in_progress_cmd = TSG_INVALID_CMD; | ||
394 | gen5_pip->resp_data = NULL; | ||
395 | gen5_pip->resp_len = NULL; | ||
396 | |||
397 | cyapa->dev_pwr_mode = UNINIT_PWR_MODE; | ||
398 | cyapa->dev_sleep_time = UNINIT_SLEEP_TIME; | ||
399 | |||
400 | return 0; | ||
401 | } | ||
402 | |||
403 | /* Return negative errno, or else the number of bytes read. */ | ||
404 | static ssize_t cyapa_i2c_pip_read(struct cyapa *cyapa, u8 *buf, size_t size) | ||
405 | { | ||
406 | int ret; | ||
407 | |||
408 | if (size == 0) | ||
409 | return 0; | ||
410 | |||
411 | if (!buf || size > CYAPA_REG_MAP_SIZE) | ||
412 | return -EINVAL; | ||
413 | |||
414 | ret = i2c_master_recv(cyapa->client, buf, size); | ||
415 | |||
416 | if (ret != size) | ||
417 | return (ret < 0) ? ret : -EIO; | ||
418 | |||
419 | return size; | ||
420 | } | ||
421 | |||
422 | /** | ||
423 | * Return a negative errno code else zero on success. | ||
424 | */ | ||
425 | static ssize_t cyapa_i2c_pip_write(struct cyapa *cyapa, u8 *buf, size_t size) | ||
426 | { | ||
427 | int ret; | ||
428 | |||
429 | if (!buf || !size) | ||
430 | return -EINVAL; | ||
431 | |||
432 | ret = i2c_master_send(cyapa->client, buf, size); | ||
433 | |||
434 | if (ret != size) | ||
435 | return (ret < 0) ? ret : -EIO; | ||
436 | |||
437 | return 0; | ||
438 | } | ||
439 | |||
440 | /** | ||
441 | * This function is aimed to dump all not read data in Gen5 trackpad | ||
442 | * before send any command, otherwise, the interrupt line will be blocked. | ||
443 | */ | ||
444 | static int cyapa_empty_pip_output_data(struct cyapa *cyapa, | ||
445 | u8 *buf, int *len, cb_sort func) | ||
446 | { | ||
447 | struct cyapa_gen5_cmd_states *gen5_pip = &cyapa->cmd_states.gen5; | ||
448 | int length; | ||
449 | int report_count; | ||
450 | int empty_count; | ||
451 | int buf_len; | ||
452 | int error; | ||
453 | |||
454 | buf_len = 0; | ||
455 | if (len) { | ||
456 | buf_len = (*len < CYAPA_REG_MAP_SIZE) ? | ||
457 | *len : CYAPA_REG_MAP_SIZE; | ||
458 | *len = 0; | ||
459 | } | ||
460 | |||
461 | report_count = 8; /* max 7 pending data before command response data */ | ||
462 | empty_count = 0; | ||
463 | do { | ||
464 | /* | ||
465 | * Depending on testing in cyapa driver, there are max 5 "02 00" | ||
466 | * packets between two valid buffered data report in firmware. | ||
467 | * So in order to dump all buffered data out and | ||
468 | * make interrupt line release for reassert again, | ||
469 | * we must set the empty_count check value bigger than 5 to | ||
470 | * make it work. Otherwise, in some situation, | ||
471 | * the interrupt line may unable to reactive again, | ||
472 | * which will cause trackpad device unable to | ||
473 | * report data any more. | ||
474 | * for example, it may happen in EFT and ESD testing. | ||
475 | */ | ||
476 | if (empty_count > 5) | ||
477 | return 0; | ||
478 | |||
479 | error = cyapa_i2c_pip_read(cyapa, gen5_pip->empty_buf, | ||
480 | GEN5_RESP_LENGTH_SIZE); | ||
481 | if (error < 0) | ||
482 | return error; | ||
483 | |||
484 | length = get_unaligned_le16(gen5_pip->empty_buf); | ||
485 | if (length == GEN5_RESP_LENGTH_SIZE) { | ||
486 | empty_count++; | ||
487 | continue; | ||
488 | } else if (length > CYAPA_REG_MAP_SIZE) { | ||
489 | /* Should not happen */ | ||
490 | return -EINVAL; | ||
491 | } else if (length == 0) { | ||
492 | /* Application or bootloader launch data polled out. */ | ||
493 | length = GEN5_RESP_LENGTH_SIZE; | ||
494 | if (buf && buf_len && func && | ||
495 | func(cyapa, gen5_pip->empty_buf, length)) { | ||
496 | length = min(buf_len, length); | ||
497 | memcpy(buf, gen5_pip->empty_buf, length); | ||
498 | *len = length; | ||
499 | /* Response found, success. */ | ||
500 | return 0; | ||
501 | } | ||
502 | continue; | ||
503 | } | ||
504 | |||
505 | error = cyapa_i2c_pip_read(cyapa, gen5_pip->empty_buf, length); | ||
506 | if (error < 0) | ||
507 | return error; | ||
508 | |||
509 | report_count--; | ||
510 | empty_count = 0; | ||
511 | length = get_unaligned_le16(gen5_pip->empty_buf); | ||
512 | if (length <= GEN5_RESP_LENGTH_SIZE) { | ||
513 | empty_count++; | ||
514 | } else if (buf && buf_len && func && | ||
515 | func(cyapa, gen5_pip->empty_buf, length)) { | ||
516 | length = min(buf_len, length); | ||
517 | memcpy(buf, gen5_pip->empty_buf, length); | ||
518 | *len = length; | ||
519 | /* Response found, success. */ | ||
520 | return 0; | ||
521 | } | ||
522 | |||
523 | error = -EINVAL; | ||
524 | } while (report_count); | ||
525 | |||
526 | return error; | ||
527 | } | ||
528 | |||
529 | static int cyapa_do_i2c_pip_cmd_irq_sync( | ||
530 | struct cyapa *cyapa, | ||
531 | u8 *cmd, size_t cmd_len, | ||
532 | unsigned long timeout) | ||
533 | { | ||
534 | struct cyapa_gen5_cmd_states *gen5_pip = &cyapa->cmd_states.gen5; | ||
535 | int error; | ||
536 | |||
537 | /* Wait for interrupt to set ready completion */ | ||
538 | init_completion(&gen5_pip->cmd_ready); | ||
539 | |||
540 | atomic_inc(&gen5_pip->cmd_issued); | ||
541 | error = cyapa_i2c_pip_write(cyapa, cmd, cmd_len); | ||
542 | if (error) { | ||
543 | atomic_dec(&gen5_pip->cmd_issued); | ||
544 | return (error < 0) ? error : -EIO; | ||
545 | } | ||
546 | |||
547 | /* Wait for interrupt to indicate command is completed. */ | ||
548 | timeout = wait_for_completion_timeout(&gen5_pip->cmd_ready, | ||
549 | msecs_to_jiffies(timeout)); | ||
550 | if (timeout == 0) { | ||
551 | atomic_dec(&gen5_pip->cmd_issued); | ||
552 | return -ETIMEDOUT; | ||
553 | } | ||
554 | |||
555 | return 0; | ||
556 | } | ||
557 | |||
558 | static int cyapa_do_i2c_pip_cmd_polling( | ||
559 | struct cyapa *cyapa, | ||
560 | u8 *cmd, size_t cmd_len, | ||
561 | u8 *resp_data, int *resp_len, | ||
562 | unsigned long timeout, | ||
563 | cb_sort func) | ||
564 | { | ||
565 | struct cyapa_gen5_cmd_states *gen5_pip = &cyapa->cmd_states.gen5; | ||
566 | int tries; | ||
567 | int length; | ||
568 | int error; | ||
569 | |||
570 | atomic_inc(&gen5_pip->cmd_issued); | ||
571 | error = cyapa_i2c_pip_write(cyapa, cmd, cmd_len); | ||
572 | if (error) { | ||
573 | atomic_dec(&gen5_pip->cmd_issued); | ||
574 | return error < 0 ? error : -EIO; | ||
575 | } | ||
576 | |||
577 | length = resp_len ? *resp_len : 0; | ||
578 | if (resp_data && resp_len && length != 0 && func) { | ||
579 | tries = timeout / 5; | ||
580 | do { | ||
581 | usleep_range(3000, 5000); | ||
582 | *resp_len = length; | ||
583 | error = cyapa_empty_pip_output_data(cyapa, | ||
584 | resp_data, resp_len, func); | ||
585 | if (error || *resp_len == 0) | ||
586 | continue; | ||
587 | else | ||
588 | break; | ||
589 | } while (--tries > 0); | ||
590 | if ((error || *resp_len == 0) || tries <= 0) | ||
591 | error = error ? error : -ETIMEDOUT; | ||
592 | } | ||
593 | |||
594 | atomic_dec(&gen5_pip->cmd_issued); | ||
595 | return error; | ||
596 | } | ||
597 | |||
598 | static int cyapa_i2c_pip_cmd_irq_sync( | ||
599 | struct cyapa *cyapa, | ||
600 | u8 *cmd, int cmd_len, | ||
601 | u8 *resp_data, int *resp_len, | ||
602 | unsigned long timeout, | ||
603 | cb_sort func, | ||
604 | bool irq_mode) | ||
605 | { | ||
606 | struct cyapa_gen5_cmd_states *gen5_pip = &cyapa->cmd_states.gen5; | ||
607 | int error; | ||
608 | |||
609 | if (!cmd || !cmd_len) | ||
610 | return -EINVAL; | ||
611 | |||
612 | /* Commands must be serialized. */ | ||
613 | error = mutex_lock_interruptible(&gen5_pip->cmd_lock); | ||
614 | if (error) | ||
615 | return error; | ||
616 | |||
617 | gen5_pip->resp_sort_func = func; | ||
618 | gen5_pip->resp_data = resp_data; | ||
619 | gen5_pip->resp_len = resp_len; | ||
620 | |||
621 | if (cmd_len >= GEN5_MIN_APP_CMD_LENGTH && | ||
622 | cmd[4] == GEN5_APP_CMD_REPORT_ID) { | ||
623 | /* Application command */ | ||
624 | gen5_pip->in_progress_cmd = cmd[6] & 0x7f; | ||
625 | } else if (cmd_len >= GEN5_MIN_BL_CMD_LENGTH && | ||
626 | cmd[4] == GEN5_BL_CMD_REPORT_ID) { | ||
627 | /* Bootloader command */ | ||
628 | gen5_pip->in_progress_cmd = cmd[7]; | ||
629 | } | ||
630 | |||
631 | /* Send command data, wait and read output response data's length. */ | ||
632 | if (irq_mode) { | ||
633 | gen5_pip->is_irq_mode = true; | ||
634 | error = cyapa_do_i2c_pip_cmd_irq_sync(cyapa, cmd, cmd_len, | ||
635 | timeout); | ||
636 | if (error == -ETIMEDOUT && resp_data && | ||
637 | resp_len && *resp_len != 0 && func) { | ||
638 | /* | ||
639 | * For some old version, there was no interrupt for | ||
640 | * the command response data, so need to poll here | ||
641 | * to try to get the response data. | ||
642 | */ | ||
643 | error = cyapa_empty_pip_output_data(cyapa, | ||
644 | resp_data, resp_len, func); | ||
645 | if (error || *resp_len == 0) | ||
646 | error = error ? error : -ETIMEDOUT; | ||
647 | } | ||
648 | } else { | ||
649 | gen5_pip->is_irq_mode = false; | ||
650 | error = cyapa_do_i2c_pip_cmd_polling(cyapa, cmd, cmd_len, | ||
651 | resp_data, resp_len, timeout, func); | ||
652 | } | ||
653 | |||
654 | gen5_pip->resp_sort_func = NULL; | ||
655 | gen5_pip->resp_data = NULL; | ||
656 | gen5_pip->resp_len = NULL; | ||
657 | gen5_pip->in_progress_cmd = TSG_INVALID_CMD; | ||
658 | |||
659 | mutex_unlock(&gen5_pip->cmd_lock); | ||
660 | return error; | ||
661 | } | ||
662 | |||
663 | static bool cyapa_gen5_sort_tsg_pip_bl_resp_data(struct cyapa *cyapa, | ||
664 | u8 *data, int len) | ||
665 | { | ||
666 | if (!data || len < GEN5_MIN_BL_RESP_LENGTH) | ||
667 | return false; | ||
668 | |||
669 | /* Bootloader input report id 30h */ | ||
670 | if (data[GEN5_RESP_REPORT_ID_OFFSET] == GEN5_BL_RESP_REPORT_ID && | ||
671 | data[GEN5_RESP_RSVD_OFFSET] == GEN5_RESP_RSVD_KEY && | ||
672 | data[GEN5_RESP_BL_SOP_OFFSET] == GEN5_SOP_KEY) | ||
673 | return true; | ||
674 | |||
675 | return false; | ||
676 | } | ||
677 | |||
678 | static bool cyapa_gen5_sort_tsg_pip_app_resp_data(struct cyapa *cyapa, | ||
679 | u8 *data, int len) | ||
680 | { | ||
681 | struct cyapa_gen5_cmd_states *gen5_pip = &cyapa->cmd_states.gen5; | ||
682 | int resp_len; | ||
683 | |||
684 | if (!data || len < GEN5_MIN_APP_RESP_LENGTH) | ||
685 | return false; | ||
686 | |||
687 | if (data[GEN5_RESP_REPORT_ID_OFFSET] == GEN5_APP_RESP_REPORT_ID && | ||
688 | data[GEN5_RESP_RSVD_OFFSET] == GEN5_RESP_RSVD_KEY) { | ||
689 | resp_len = get_unaligned_le16(&data[GEN5_RESP_LENGTH_OFFSET]); | ||
690 | if (GET_GEN5_CMD_CODE(data[GEN5_RESP_APP_CMD_OFFSET]) == 0x00 && | ||
691 | resp_len == GEN5_UNSUPPORTED_CMD_RESP_LENGTH && | ||
692 | data[5] == gen5_pip->in_progress_cmd) { | ||
693 | /* Unsupported command code */ | ||
694 | return false; | ||
695 | } else if (GET_GEN5_CMD_CODE(data[GEN5_RESP_APP_CMD_OFFSET]) == | ||
696 | gen5_pip->in_progress_cmd) { | ||
697 | /* Correct command response received */ | ||
698 | return true; | ||
699 | } | ||
700 | } | ||
701 | |||
702 | return false; | ||
703 | } | ||
704 | |||
705 | static bool cyapa_gen5_sort_application_launch_data(struct cyapa *cyapa, | ||
706 | u8 *buf, int len) | ||
707 | { | ||
708 | if (buf == NULL || len < GEN5_RESP_LENGTH_SIZE) | ||
709 | return false; | ||
710 | |||
711 | /* | ||
712 | * After reset or power on, trackpad device always sets to 0x00 0x00 | ||
713 | * to indicate a reset or power on event. | ||
714 | */ | ||
715 | if (buf[0] == 0 && buf[1] == 0) | ||
716 | return true; | ||
717 | |||
718 | return false; | ||
719 | } | ||
720 | |||
721 | static bool cyapa_gen5_sort_hid_descriptor_data(struct cyapa *cyapa, | ||
722 | u8 *buf, int len) | ||
723 | { | ||
724 | int resp_len; | ||
725 | int max_output_len; | ||
726 | |||
727 | /* Check hid descriptor. */ | ||
728 | if (len != GEN5_HID_DESCRIPTOR_SIZE) | ||
729 | return false; | ||
730 | |||
731 | resp_len = get_unaligned_le16(&buf[GEN5_RESP_LENGTH_OFFSET]); | ||
732 | max_output_len = get_unaligned_le16(&buf[16]); | ||
733 | if (resp_len == GEN5_HID_DESCRIPTOR_SIZE) { | ||
734 | if (buf[GEN5_RESP_REPORT_ID_OFFSET] == GEN5_BL_HID_REPORT_ID && | ||
735 | max_output_len == GEN5_BL_MAX_OUTPUT_LENGTH) { | ||
736 | /* BL mode HID Descriptor */ | ||
737 | return true; | ||
738 | } else if ((buf[GEN5_RESP_REPORT_ID_OFFSET] == | ||
739 | GEN5_APP_HID_REPORT_ID) && | ||
740 | max_output_len == GEN5_APP_MAX_OUTPUT_LENGTH) { | ||
741 | /* APP mode HID Descriptor */ | ||
742 | return true; | ||
743 | } | ||
744 | } | ||
745 | |||
746 | return false; | ||
747 | } | ||
748 | |||
749 | static bool cyapa_gen5_sort_deep_sleep_data(struct cyapa *cyapa, | ||
750 | u8 *buf, int len) | ||
751 | { | ||
752 | if (len == GEN5_DEEP_SLEEP_RESP_LENGTH && | ||
753 | buf[GEN5_RESP_REPORT_ID_OFFSET] == | ||
754 | GEN5_APP_DEEP_SLEEP_REPORT_ID && | ||
755 | (buf[4] & GEN5_DEEP_SLEEP_OPCODE_MASK) == | ||
756 | GEN5_DEEP_SLEEP_OPCODE) | ||
757 | return true; | ||
758 | return false; | ||
759 | } | ||
760 | |||
761 | static int gen5_idle_state_parse(struct cyapa *cyapa) | ||
762 | { | ||
763 | u8 resp_data[GEN5_HID_DESCRIPTOR_SIZE]; | ||
764 | int max_output_len; | ||
765 | int length; | ||
766 | u8 cmd[2]; | ||
767 | int ret; | ||
768 | int error; | ||
769 | |||
770 | /* | ||
771 | * Dump all buffered data firstly for the situation | ||
772 | * when the trackpad is just power on the cyapa go here. | ||
773 | */ | ||
774 | cyapa_empty_pip_output_data(cyapa, NULL, NULL, NULL); | ||
775 | |||
776 | memset(resp_data, 0, sizeof(resp_data)); | ||
777 | ret = cyapa_i2c_pip_read(cyapa, resp_data, 3); | ||
778 | if (ret != 3) | ||
779 | return ret < 0 ? ret : -EIO; | ||
780 | |||
781 | length = get_unaligned_le16(&resp_data[GEN5_RESP_LENGTH_OFFSET]); | ||
782 | if (length == GEN5_RESP_LENGTH_SIZE) { | ||
783 | /* Normal state of Gen5 with no data to respose */ | ||
784 | cyapa->gen = CYAPA_GEN5; | ||
785 | |||
786 | cyapa_empty_pip_output_data(cyapa, NULL, NULL, NULL); | ||
787 | |||
788 | /* Read description from trackpad device */ | ||
789 | cmd[0] = 0x01; | ||
790 | cmd[1] = 0x00; | ||
791 | length = GEN5_HID_DESCRIPTOR_SIZE; | ||
792 | error = cyapa_i2c_pip_cmd_irq_sync(cyapa, | ||
793 | cmd, GEN5_RESP_LENGTH_SIZE, | ||
794 | resp_data, &length, | ||
795 | 300, | ||
796 | cyapa_gen5_sort_hid_descriptor_data, | ||
797 | false); | ||
798 | if (error) | ||
799 | return error; | ||
800 | |||
801 | length = get_unaligned_le16( | ||
802 | &resp_data[GEN5_RESP_LENGTH_OFFSET]); | ||
803 | max_output_len = get_unaligned_le16(&resp_data[16]); | ||
804 | if ((length == GEN5_HID_DESCRIPTOR_SIZE || | ||
805 | length == GEN5_RESP_LENGTH_SIZE) && | ||
806 | (resp_data[GEN5_RESP_REPORT_ID_OFFSET] == | ||
807 | GEN5_BL_HID_REPORT_ID) && | ||
808 | max_output_len == GEN5_BL_MAX_OUTPUT_LENGTH) { | ||
809 | /* BL mode HID Description read */ | ||
810 | cyapa->state = CYAPA_STATE_GEN5_BL; | ||
811 | } else if ((length == GEN5_HID_DESCRIPTOR_SIZE || | ||
812 | length == GEN5_RESP_LENGTH_SIZE) && | ||
813 | (resp_data[GEN5_RESP_REPORT_ID_OFFSET] == | ||
814 | GEN5_APP_HID_REPORT_ID) && | ||
815 | max_output_len == GEN5_APP_MAX_OUTPUT_LENGTH) { | ||
816 | /* APP mode HID Description read */ | ||
817 | cyapa->state = CYAPA_STATE_GEN5_APP; | ||
818 | } else { | ||
819 | /* Should not happen!!! */ | ||
820 | cyapa->state = CYAPA_STATE_NO_DEVICE; | ||
821 | } | ||
822 | } | ||
823 | |||
824 | return 0; | ||
825 | } | ||
826 | |||
827 | static int gen5_hid_description_header_parse(struct cyapa *cyapa, u8 *reg_data) | ||
828 | { | ||
829 | int length; | ||
830 | u8 resp_data[32]; | ||
831 | int max_output_len; | ||
832 | int ret; | ||
833 | |||
834 | /* 0x20 0x00 0xF7 is Gen5 Application HID Description Header; | ||
835 | * 0x20 0x00 0xFF is Gen5 Booloader HID Description Header. | ||
836 | * | ||
837 | * Must read HID Description content through out, | ||
838 | * otherwise Gen5 trackpad cannot response next command | ||
839 | * or report any touch or button data. | ||
840 | */ | ||
841 | ret = cyapa_i2c_pip_read(cyapa, resp_data, | ||
842 | GEN5_HID_DESCRIPTOR_SIZE); | ||
843 | if (ret != GEN5_HID_DESCRIPTOR_SIZE) | ||
844 | return ret < 0 ? ret : -EIO; | ||
845 | length = get_unaligned_le16(&resp_data[GEN5_RESP_LENGTH_OFFSET]); | ||
846 | max_output_len = get_unaligned_le16(&resp_data[16]); | ||
847 | if (length == GEN5_RESP_LENGTH_SIZE) { | ||
848 | if (reg_data[GEN5_RESP_REPORT_ID_OFFSET] == | ||
849 | GEN5_BL_HID_REPORT_ID) { | ||
850 | /* | ||
851 | * BL mode HID Description has been previously | ||
852 | * read out. | ||
853 | */ | ||
854 | cyapa->gen = CYAPA_GEN5; | ||
855 | cyapa->state = CYAPA_STATE_GEN5_BL; | ||
856 | } else { | ||
857 | /* | ||
858 | * APP mode HID Description has been previously | ||
859 | * read out. | ||
860 | */ | ||
861 | cyapa->gen = CYAPA_GEN5; | ||
862 | cyapa->state = CYAPA_STATE_GEN5_APP; | ||
863 | } | ||
864 | } else if (length == GEN5_HID_DESCRIPTOR_SIZE && | ||
865 | resp_data[2] == GEN5_BL_HID_REPORT_ID && | ||
866 | max_output_len == GEN5_BL_MAX_OUTPUT_LENGTH) { | ||
867 | /* BL mode HID Description read. */ | ||
868 | cyapa->gen = CYAPA_GEN5; | ||
869 | cyapa->state = CYAPA_STATE_GEN5_BL; | ||
870 | } else if (length == GEN5_HID_DESCRIPTOR_SIZE && | ||
871 | (resp_data[GEN5_RESP_REPORT_ID_OFFSET] == | ||
872 | GEN5_APP_HID_REPORT_ID) && | ||
873 | max_output_len == GEN5_APP_MAX_OUTPUT_LENGTH) { | ||
874 | /* APP mode HID Description read. */ | ||
875 | cyapa->gen = CYAPA_GEN5; | ||
876 | cyapa->state = CYAPA_STATE_GEN5_APP; | ||
877 | } else { | ||
878 | /* Should not happen!!! */ | ||
879 | cyapa->state = CYAPA_STATE_NO_DEVICE; | ||
880 | } | ||
881 | |||
882 | return 0; | ||
883 | } | ||
884 | |||
885 | static int gen5_report_data_header_parse(struct cyapa *cyapa, u8 *reg_data) | ||
886 | { | ||
887 | int length; | ||
888 | |||
889 | length = get_unaligned_le16(®_data[GEN5_RESP_LENGTH_OFFSET]); | ||
890 | switch (reg_data[GEN5_RESP_REPORT_ID_OFFSET]) { | ||
891 | case GEN5_TOUCH_REPORT_ID: | ||
892 | if (length < GEN5_TOUCH_REPORT_HEAD_SIZE || | ||
893 | length > GEN5_TOUCH_REPORT_MAX_SIZE) | ||
894 | return -EINVAL; | ||
895 | break; | ||
896 | case GEN5_BTN_REPORT_ID: | ||
897 | case GEN5_OLD_PUSH_BTN_REPORT_ID: | ||
898 | case GEN5_PUSH_BTN_REPORT_ID: | ||
899 | if (length < GEN5_BTN_REPORT_HEAD_SIZE || | ||
900 | length > GEN5_BTN_REPORT_MAX_SIZE) | ||
901 | return -EINVAL; | ||
902 | break; | ||
903 | case GEN5_WAKEUP_EVENT_REPORT_ID: | ||
904 | if (length != GEN5_WAKEUP_EVENT_SIZE) | ||
905 | return -EINVAL; | ||
906 | break; | ||
907 | default: | ||
908 | return -EINVAL; | ||
909 | } | ||
910 | |||
911 | cyapa->gen = CYAPA_GEN5; | ||
912 | cyapa->state = CYAPA_STATE_GEN5_APP; | ||
913 | return 0; | ||
914 | } | ||
915 | |||
916 | static int gen5_cmd_resp_header_parse(struct cyapa *cyapa, u8 *reg_data) | ||
917 | { | ||
918 | struct cyapa_gen5_cmd_states *gen5_pip = &cyapa->cmd_states.gen5; | ||
919 | int length; | ||
920 | int ret; | ||
921 | |||
922 | /* | ||
923 | * Must read report data through out, | ||
924 | * otherwise Gen5 trackpad cannot response next command | ||
925 | * or report any touch or button data. | ||
926 | */ | ||
927 | length = get_unaligned_le16(®_data[GEN5_RESP_LENGTH_OFFSET]); | ||
928 | ret = cyapa_i2c_pip_read(cyapa, gen5_pip->empty_buf, length); | ||
929 | if (ret != length) | ||
930 | return ret < 0 ? ret : -EIO; | ||
931 | |||
932 | if (length == GEN5_RESP_LENGTH_SIZE) { | ||
933 | /* Previous command has read the data through out. */ | ||
934 | if (reg_data[GEN5_RESP_REPORT_ID_OFFSET] == | ||
935 | GEN5_BL_RESP_REPORT_ID) { | ||
936 | /* Gen5 BL command response data detected */ | ||
937 | cyapa->gen = CYAPA_GEN5; | ||
938 | cyapa->state = CYAPA_STATE_GEN5_BL; | ||
939 | } else { | ||
940 | /* Gen5 APP command response data detected */ | ||
941 | cyapa->gen = CYAPA_GEN5; | ||
942 | cyapa->state = CYAPA_STATE_GEN5_APP; | ||
943 | } | ||
944 | } else if ((gen5_pip->empty_buf[GEN5_RESP_REPORT_ID_OFFSET] == | ||
945 | GEN5_BL_RESP_REPORT_ID) && | ||
946 | (gen5_pip->empty_buf[GEN5_RESP_RSVD_OFFSET] == | ||
947 | GEN5_RESP_RSVD_KEY) && | ||
948 | (gen5_pip->empty_buf[GEN5_RESP_BL_SOP_OFFSET] == | ||
949 | GEN5_SOP_KEY) && | ||
950 | (gen5_pip->empty_buf[length - 1] == | ||
951 | GEN5_EOP_KEY)) { | ||
952 | /* Gen5 BL command response data detected */ | ||
953 | cyapa->gen = CYAPA_GEN5; | ||
954 | cyapa->state = CYAPA_STATE_GEN5_BL; | ||
955 | } else if (gen5_pip->empty_buf[GEN5_RESP_REPORT_ID_OFFSET] == | ||
956 | GEN5_APP_RESP_REPORT_ID && | ||
957 | gen5_pip->empty_buf[GEN5_RESP_RSVD_OFFSET] == | ||
958 | GEN5_RESP_RSVD_KEY) { | ||
959 | /* Gen5 APP command response data detected */ | ||
960 | cyapa->gen = CYAPA_GEN5; | ||
961 | cyapa->state = CYAPA_STATE_GEN5_APP; | ||
962 | } else { | ||
963 | /* Should not happen!!! */ | ||
964 | cyapa->state = CYAPA_STATE_NO_DEVICE; | ||
965 | } | ||
966 | |||
967 | return 0; | ||
968 | } | ||
969 | |||
970 | static int cyapa_gen5_state_parse(struct cyapa *cyapa, u8 *reg_data, int len) | ||
971 | { | ||
972 | int length; | ||
973 | |||
974 | if (!reg_data || len < 3) | ||
975 | return -EINVAL; | ||
976 | |||
977 | cyapa->state = CYAPA_STATE_NO_DEVICE; | ||
978 | |||
979 | /* Parse based on Gen5 characteristic registers and bits */ | ||
980 | length = get_unaligned_le16(®_data[GEN5_RESP_LENGTH_OFFSET]); | ||
981 | if (length == 0 || length == GEN5_RESP_LENGTH_SIZE) { | ||
982 | gen5_idle_state_parse(cyapa); | ||
983 | } else if (length == GEN5_HID_DESCRIPTOR_SIZE && | ||
984 | (reg_data[2] == GEN5_BL_HID_REPORT_ID || | ||
985 | reg_data[2] == GEN5_APP_HID_REPORT_ID)) { | ||
986 | gen5_hid_description_header_parse(cyapa, reg_data); | ||
987 | } else if ((length == GEN5_APP_REPORT_DESCRIPTOR_SIZE || | ||
988 | length == GEN5_APP_CONTRACT_REPORT_DESCRIPTOR_SIZE) && | ||
989 | reg_data[2] == GEN5_APP_REPORT_DESCRIPTOR_ID) { | ||
990 | /* 0xEE 0x00 0xF6 is Gen5 APP report description header. */ | ||
991 | cyapa->gen = CYAPA_GEN5; | ||
992 | cyapa->state = CYAPA_STATE_GEN5_APP; | ||
993 | } else if (length == GEN5_BL_REPORT_DESCRIPTOR_SIZE && | ||
994 | reg_data[2] == GEN5_BL_REPORT_DESCRIPTOR_ID) { | ||
995 | /* 0x1D 0x00 0xFE is Gen5 BL report descriptior header. */ | ||
996 | cyapa->gen = CYAPA_GEN5; | ||
997 | cyapa->state = CYAPA_STATE_GEN5_BL; | ||
998 | } else if (reg_data[2] == GEN5_TOUCH_REPORT_ID || | ||
999 | reg_data[2] == GEN5_BTN_REPORT_ID || | ||
1000 | reg_data[2] == GEN5_OLD_PUSH_BTN_REPORT_ID || | ||
1001 | reg_data[2] == GEN5_PUSH_BTN_REPORT_ID || | ||
1002 | reg_data[2] == GEN5_WAKEUP_EVENT_REPORT_ID) { | ||
1003 | gen5_report_data_header_parse(cyapa, reg_data); | ||
1004 | } else if (reg_data[2] == GEN5_BL_RESP_REPORT_ID || | ||
1005 | reg_data[2] == GEN5_APP_RESP_REPORT_ID) { | ||
1006 | gen5_cmd_resp_header_parse(cyapa, reg_data); | ||
1007 | } | ||
1008 | |||
1009 | if (cyapa->gen == CYAPA_GEN5) { | ||
1010 | /* | ||
1011 | * Must read the content (e.g.: report description and so on) | ||
1012 | * from trackpad device throughout. Otherwise, | ||
1013 | * Gen5 trackpad cannot response to next command or | ||
1014 | * report any touch or button data later. | ||
1015 | */ | ||
1016 | cyapa_empty_pip_output_data(cyapa, NULL, NULL, NULL); | ||
1017 | |||
1018 | if (cyapa->state == CYAPA_STATE_GEN5_APP || | ||
1019 | cyapa->state == CYAPA_STATE_GEN5_BL) | ||
1020 | return 0; | ||
1021 | } | ||
1022 | |||
1023 | return -EAGAIN; | ||
1024 | } | ||
1025 | |||
1026 | static int cyapa_gen5_bl_initiate(struct cyapa *cyapa, | ||
1027 | const struct firmware *fw) | ||
1028 | { | ||
1029 | struct cyapa_tsg_bin_image *image; | ||
1030 | struct gen5_bl_cmd_head *bl_cmd_head; | ||
1031 | struct gen5_bl_packet_start *bl_packet_start; | ||
1032 | struct gen5_bl_initiate_cmd_data *cmd_data; | ||
1033 | struct gen5_bl_packet_end *bl_packet_end; | ||
1034 | u8 cmd[CYAPA_TSG_MAX_CMD_SIZE]; | ||
1035 | int cmd_len; | ||
1036 | u16 cmd_data_len; | ||
1037 | u16 cmd_crc = 0; | ||
1038 | u16 meta_data_crc = 0; | ||
1039 | u8 resp_data[11]; | ||
1040 | int resp_len; | ||
1041 | int records_num; | ||
1042 | u8 *data; | ||
1043 | int error; | ||
1044 | |||
1045 | /* Try to dump all buffered report data before any send command. */ | ||
1046 | cyapa_empty_pip_output_data(cyapa, NULL, NULL, NULL); | ||
1047 | |||
1048 | memset(cmd, 0, CYAPA_TSG_MAX_CMD_SIZE); | ||
1049 | bl_cmd_head = (struct gen5_bl_cmd_head *)cmd; | ||
1050 | cmd_data_len = CYAPA_TSG_BL_KEY_SIZE + CYAPA_TSG_FLASH_MAP_BLOCK_SIZE; | ||
1051 | cmd_len = sizeof(struct gen5_bl_cmd_head) + cmd_data_len + | ||
1052 | sizeof(struct gen5_bl_packet_end); | ||
1053 | |||
1054 | put_unaligned_le16(GEN5_OUTPUT_REPORT_ADDR, &bl_cmd_head->addr); | ||
1055 | put_unaligned_le16(cmd_len - 2, &bl_cmd_head->length); | ||
1056 | bl_cmd_head->report_id = GEN5_BL_CMD_REPORT_ID; | ||
1057 | |||
1058 | bl_packet_start = &bl_cmd_head->packet_start; | ||
1059 | bl_packet_start->sop = GEN5_SOP_KEY; | ||
1060 | bl_packet_start->cmd_code = GEN5_BL_CMD_INITIATE_BL; | ||
1061 | /* 8 key bytes and 128 bytes block size */ | ||
1062 | put_unaligned_le16(cmd_data_len, &bl_packet_start->data_length); | ||
1063 | |||
1064 | cmd_data = (struct gen5_bl_initiate_cmd_data *)bl_cmd_head->data; | ||
1065 | memcpy(cmd_data->key, cyapa_gen5_bl_cmd_key, CYAPA_TSG_BL_KEY_SIZE); | ||
1066 | |||
1067 | /* Copy 60 bytes Meta Data Row Parameters */ | ||
1068 | image = (struct cyapa_tsg_bin_image *)fw->data; | ||
1069 | records_num = (fw->size - sizeof(struct cyapa_tsg_bin_image_head)) / | ||
1070 | sizeof(struct cyapa_tsg_bin_image_data_record); | ||
1071 | /* APP_INTEGRITY row is always the last row block */ | ||
1072 | data = image->records[records_num - 1].record_data; | ||
1073 | memcpy(cmd_data->metadata_raw_parameter, data, | ||
1074 | CYAPA_TSG_FLASH_MAP_METADATA_SIZE); | ||
1075 | |||
1076 | meta_data_crc = crc_itu_t(0xffff, cmd_data->metadata_raw_parameter, | ||
1077 | CYAPA_TSG_FLASH_MAP_METADATA_SIZE); | ||
1078 | put_unaligned_le16(meta_data_crc, &cmd_data->metadata_crc); | ||
1079 | |||
1080 | bl_packet_end = (struct gen5_bl_packet_end *)(bl_cmd_head->data + | ||
1081 | cmd_data_len); | ||
1082 | cmd_crc = crc_itu_t(0xffff, (u8 *)bl_packet_start, | ||
1083 | sizeof(struct gen5_bl_packet_start) + cmd_data_len); | ||
1084 | put_unaligned_le16(cmd_crc, &bl_packet_end->crc); | ||
1085 | bl_packet_end->eop = GEN5_EOP_KEY; | ||
1086 | |||
1087 | resp_len = sizeof(resp_data); | ||
1088 | error = cyapa_i2c_pip_cmd_irq_sync(cyapa, | ||
1089 | cmd, cmd_len, | ||
1090 | resp_data, &resp_len, 12000, | ||
1091 | cyapa_gen5_sort_tsg_pip_bl_resp_data, true); | ||
1092 | if (error || resp_len != GEN5_BL_INITIATE_RESP_LEN || | ||
1093 | resp_data[2] != GEN5_BL_RESP_REPORT_ID || | ||
1094 | !GEN5_CMD_COMPLETE_SUCCESS(resp_data[5])) | ||
1095 | return error ? error : -EAGAIN; | ||
1096 | |||
1097 | return 0; | ||
1098 | } | ||
1099 | |||
1100 | static bool cyapa_gen5_sort_bl_exit_data(struct cyapa *cyapa, u8 *buf, int len) | ||
1101 | { | ||
1102 | if (buf == NULL || len < GEN5_RESP_LENGTH_SIZE) | ||
1103 | return false; | ||
1104 | |||
1105 | if (buf[0] == 0 && buf[1] == 0) | ||
1106 | return true; | ||
1107 | |||
1108 | /* Exit bootloader failed for some reason. */ | ||
1109 | if (len == GEN5_BL_FAIL_EXIT_RESP_LEN && | ||
1110 | buf[GEN5_RESP_REPORT_ID_OFFSET] == | ||
1111 | GEN5_BL_RESP_REPORT_ID && | ||
1112 | buf[GEN5_RESP_RSVD_OFFSET] == GEN5_RESP_RSVD_KEY && | ||
1113 | buf[GEN5_RESP_BL_SOP_OFFSET] == GEN5_SOP_KEY && | ||
1114 | buf[10] == GEN5_EOP_KEY) | ||
1115 | return true; | ||
1116 | |||
1117 | return false; | ||
1118 | } | ||
1119 | |||
1120 | static int cyapa_gen5_bl_exit(struct cyapa *cyapa) | ||
1121 | { | ||
1122 | |||
1123 | u8 bl_gen5_bl_exit[] = { 0x04, 0x00, | ||
1124 | 0x0B, 0x00, 0x40, 0x00, 0x01, 0x3b, 0x00, 0x00, | ||
1125 | 0x20, 0xc7, 0x17 | ||
1126 | }; | ||
1127 | u8 resp_data[11]; | ||
1128 | int resp_len; | ||
1129 | int error; | ||
1130 | |||
1131 | resp_len = sizeof(resp_data); | ||
1132 | error = cyapa_i2c_pip_cmd_irq_sync(cyapa, | ||
1133 | bl_gen5_bl_exit, sizeof(bl_gen5_bl_exit), | ||
1134 | resp_data, &resp_len, | ||
1135 | 5000, cyapa_gen5_sort_bl_exit_data, false); | ||
1136 | if (error) | ||
1137 | return error; | ||
1138 | |||
1139 | if (resp_len == GEN5_BL_FAIL_EXIT_RESP_LEN || | ||
1140 | resp_data[GEN5_RESP_REPORT_ID_OFFSET] == | ||
1141 | GEN5_BL_RESP_REPORT_ID) | ||
1142 | return -EAGAIN; | ||
1143 | |||
1144 | if (resp_data[0] == 0x00 && resp_data[1] == 0x00) | ||
1145 | return 0; | ||
1146 | |||
1147 | return -ENODEV; | ||
1148 | } | ||
1149 | |||
1150 | static int cyapa_gen5_bl_enter(struct cyapa *cyapa) | ||
1151 | { | ||
1152 | u8 cmd[] = { 0x04, 0x00, 0x05, 0x00, 0x2F, 0x00, 0x01 }; | ||
1153 | u8 resp_data[2]; | ||
1154 | int resp_len; | ||
1155 | int error; | ||
1156 | |||
1157 | error = cyapa_poll_state(cyapa, 500); | ||
1158 | if (error < 0) | ||
1159 | return error; | ||
1160 | if (cyapa->gen != CYAPA_GEN5) | ||
1161 | return -EINVAL; | ||
1162 | |||
1163 | /* Already in Gen5 BL. Skipping exit. */ | ||
1164 | if (cyapa->state == CYAPA_STATE_GEN5_BL) | ||
1165 | return 0; | ||
1166 | |||
1167 | if (cyapa->state != CYAPA_STATE_GEN5_APP) | ||
1168 | return -EAGAIN; | ||
1169 | |||
1170 | /* Try to dump all buffered report data before any send command. */ | ||
1171 | cyapa_empty_pip_output_data(cyapa, NULL, NULL, NULL); | ||
1172 | |||
1173 | /* | ||
1174 | * Send bootloader enter command to trackpad device, | ||
1175 | * after enter bootloader, the response data is two bytes of 0x00 0x00. | ||
1176 | */ | ||
1177 | resp_len = sizeof(resp_data); | ||
1178 | memset(resp_data, 0, resp_len); | ||
1179 | error = cyapa_i2c_pip_cmd_irq_sync(cyapa, | ||
1180 | cmd, sizeof(cmd), | ||
1181 | resp_data, &resp_len, | ||
1182 | 5000, cyapa_gen5_sort_application_launch_data, | ||
1183 | true); | ||
1184 | if (error || resp_data[0] != 0x00 || resp_data[1] != 0x00) | ||
1185 | return error < 0 ? error : -EAGAIN; | ||
1186 | |||
1187 | cyapa->operational = false; | ||
1188 | cyapa->state = CYAPA_STATE_GEN5_BL; | ||
1189 | return 0; | ||
1190 | } | ||
1191 | |||
1192 | static int cyapa_gen5_check_fw(struct cyapa *cyapa, const struct firmware *fw) | ||
1193 | { | ||
1194 | struct device *dev = &cyapa->client->dev; | ||
1195 | const struct cyapa_tsg_bin_image *image = (const void *)fw->data; | ||
1196 | const struct cyapa_tsg_bin_image_data_record *app_integrity; | ||
1197 | const struct gen5_bl_metadata_row_params *metadata; | ||
1198 | size_t flash_records_count; | ||
1199 | u32 fw_app_start, fw_upgrade_start; | ||
1200 | u16 fw_app_len, fw_upgrade_len; | ||
1201 | u16 app_crc; | ||
1202 | u16 app_integrity_crc; | ||
1203 | int record_index; | ||
1204 | int i; | ||
1205 | |||
1206 | flash_records_count = (fw->size - | ||
1207 | sizeof(struct cyapa_tsg_bin_image_head)) / | ||
1208 | sizeof(struct cyapa_tsg_bin_image_data_record); | ||
1209 | |||
1210 | /* | ||
1211 | * APP_INTEGRITY row is always the last row block, | ||
1212 | * and the row id must be 0x01ff. | ||
1213 | */ | ||
1214 | app_integrity = &image->records[flash_records_count - 1]; | ||
1215 | |||
1216 | if (app_integrity->flash_array_id != 0x00 || | ||
1217 | get_unaligned_be16(&app_integrity->row_number) != 0x01ff) { | ||
1218 | dev_err(dev, "%s: invalid app_integrity data.\n", __func__); | ||
1219 | return -EINVAL; | ||
1220 | } | ||
1221 | |||
1222 | metadata = (const void *)app_integrity->record_data; | ||
1223 | |||
1224 | /* Verify app_integrity crc */ | ||
1225 | app_integrity_crc = crc_itu_t(0xffff, app_integrity->record_data, | ||
1226 | CYAPA_TSG_APP_INTEGRITY_SIZE); | ||
1227 | if (app_integrity_crc != get_unaligned_le16(&metadata->metadata_crc)) { | ||
1228 | dev_err(dev, "%s: invalid app_integrity crc.\n", __func__); | ||
1229 | return -EINVAL; | ||
1230 | } | ||
1231 | |||
1232 | fw_app_start = get_unaligned_le32(&metadata->app_start); | ||
1233 | fw_app_len = get_unaligned_le16(&metadata->app_len); | ||
1234 | fw_upgrade_start = get_unaligned_le32(&metadata->upgrade_start); | ||
1235 | fw_upgrade_len = get_unaligned_le16(&metadata->upgrade_len); | ||
1236 | |||
1237 | if (fw_app_start % CYAPA_TSG_FW_ROW_SIZE || | ||
1238 | fw_app_len % CYAPA_TSG_FW_ROW_SIZE || | ||
1239 | fw_upgrade_start % CYAPA_TSG_FW_ROW_SIZE || | ||
1240 | fw_upgrade_len % CYAPA_TSG_FW_ROW_SIZE) { | ||
1241 | dev_err(dev, "%s: invalid image alignment.\n", __func__); | ||
1242 | return -EINVAL; | ||
1243 | } | ||
1244 | |||
1245 | /* | ||
1246 | * Verify application image CRC | ||
1247 | */ | ||
1248 | record_index = fw_app_start / CYAPA_TSG_FW_ROW_SIZE - | ||
1249 | CYAPA_TSG_IMG_START_ROW_NUM; | ||
1250 | app_crc = 0xffffU; | ||
1251 | for (i = 0; i < fw_app_len / CYAPA_TSG_FW_ROW_SIZE; i++) { | ||
1252 | const u8 *data = image->records[record_index + i].record_data; | ||
1253 | app_crc = crc_itu_t(app_crc, data, CYAPA_TSG_FW_ROW_SIZE); | ||
1254 | } | ||
1255 | |||
1256 | if (app_crc != get_unaligned_le16(&metadata->app_crc)) { | ||
1257 | dev_err(dev, "%s: invalid firmware app crc check.\n", __func__); | ||
1258 | return -EINVAL; | ||
1259 | } | ||
1260 | |||
1261 | return 0; | ||
1262 | } | ||
1263 | |||
1264 | static int cyapa_gen5_write_fw_block(struct cyapa *cyapa, | ||
1265 | struct cyapa_tsg_bin_image_data_record *flash_record) | ||
1266 | { | ||
1267 | struct gen5_bl_cmd_head *bl_cmd_head; | ||
1268 | struct gen5_bl_packet_start *bl_packet_start; | ||
1269 | struct gen5_bl_flash_row_head *flash_row_head; | ||
1270 | struct gen5_bl_packet_end *bl_packet_end; | ||
1271 | u8 cmd[CYAPA_TSG_MAX_CMD_SIZE]; | ||
1272 | u16 cmd_len; | ||
1273 | u8 flash_array_id; | ||
1274 | u16 flash_row_id; | ||
1275 | u16 record_len; | ||
1276 | u8 *record_data; | ||
1277 | u16 data_len; | ||
1278 | u16 crc; | ||
1279 | u8 resp_data[11]; | ||
1280 | int resp_len; | ||
1281 | int error; | ||
1282 | |||
1283 | flash_array_id = flash_record->flash_array_id; | ||
1284 | flash_row_id = get_unaligned_be16(&flash_record->row_number); | ||
1285 | record_len = get_unaligned_be16(&flash_record->record_len); | ||
1286 | record_data = flash_record->record_data; | ||
1287 | |||
1288 | memset(cmd, 0, CYAPA_TSG_MAX_CMD_SIZE); | ||
1289 | bl_cmd_head = (struct gen5_bl_cmd_head *)cmd; | ||
1290 | bl_packet_start = &bl_cmd_head->packet_start; | ||
1291 | cmd_len = sizeof(struct gen5_bl_cmd_head) + | ||
1292 | sizeof(struct gen5_bl_flash_row_head) + | ||
1293 | CYAPA_TSG_FLASH_MAP_BLOCK_SIZE + | ||
1294 | sizeof(struct gen5_bl_packet_end); | ||
1295 | |||
1296 | put_unaligned_le16(GEN5_OUTPUT_REPORT_ADDR, &bl_cmd_head->addr); | ||
1297 | /* Don't include 2 bytes register address */ | ||
1298 | put_unaligned_le16(cmd_len - 2, &bl_cmd_head->length); | ||
1299 | bl_cmd_head->report_id = GEN5_BL_CMD_REPORT_ID; | ||
1300 | bl_packet_start->sop = GEN5_SOP_KEY; | ||
1301 | bl_packet_start->cmd_code = GEN5_BL_CMD_PROGRAM_VERIFY_ROW; | ||
1302 | |||
1303 | /* 1 (Flash Array ID) + 2 (Flash Row ID) + 128 (flash data) */ | ||
1304 | data_len = sizeof(struct gen5_bl_flash_row_head) + record_len; | ||
1305 | put_unaligned_le16(data_len, &bl_packet_start->data_length); | ||
1306 | |||
1307 | flash_row_head = (struct gen5_bl_flash_row_head *)bl_cmd_head->data; | ||
1308 | flash_row_head->flash_array_id = flash_array_id; | ||
1309 | put_unaligned_le16(flash_row_id, &flash_row_head->flash_row_id); | ||
1310 | memcpy(flash_row_head->flash_data, record_data, record_len); | ||
1311 | |||
1312 | bl_packet_end = (struct gen5_bl_packet_end *)(bl_cmd_head->data + | ||
1313 | data_len); | ||
1314 | crc = crc_itu_t(0xffff, (u8 *)bl_packet_start, | ||
1315 | sizeof(struct gen5_bl_packet_start) + data_len); | ||
1316 | put_unaligned_le16(crc, &bl_packet_end->crc); | ||
1317 | bl_packet_end->eop = GEN5_EOP_KEY; | ||
1318 | |||
1319 | resp_len = sizeof(resp_data); | ||
1320 | error = cyapa_i2c_pip_cmd_irq_sync(cyapa, cmd, cmd_len, | ||
1321 | resp_data, &resp_len, | ||
1322 | 500, cyapa_gen5_sort_tsg_pip_bl_resp_data, true); | ||
1323 | if (error || resp_len != GEN5_BL_BLOCK_WRITE_RESP_LEN || | ||
1324 | resp_data[2] != GEN5_BL_RESP_REPORT_ID || | ||
1325 | !GEN5_CMD_COMPLETE_SUCCESS(resp_data[5])) | ||
1326 | return error < 0 ? error : -EAGAIN; | ||
1327 | |||
1328 | return 0; | ||
1329 | } | ||
1330 | |||
1331 | static int cyapa_gen5_do_fw_update(struct cyapa *cyapa, | ||
1332 | const struct firmware *fw) | ||
1333 | { | ||
1334 | struct device *dev = &cyapa->client->dev; | ||
1335 | struct cyapa_tsg_bin_image_data_record *flash_record; | ||
1336 | struct cyapa_tsg_bin_image *image = | ||
1337 | (struct cyapa_tsg_bin_image *)fw->data; | ||
1338 | int flash_records_count; | ||
1339 | int i; | ||
1340 | int error; | ||
1341 | |||
1342 | cyapa_empty_pip_output_data(cyapa, NULL, NULL, NULL); | ||
1343 | |||
1344 | flash_records_count = | ||
1345 | (fw->size - sizeof(struct cyapa_tsg_bin_image_head)) / | ||
1346 | sizeof(struct cyapa_tsg_bin_image_data_record); | ||
1347 | /* | ||
1348 | * The last flash row 0x01ff has been written through bl_initiate | ||
1349 | * command, so DO NOT write flash 0x01ff to trackpad device. | ||
1350 | */ | ||
1351 | for (i = 0; i < (flash_records_count - 1); i++) { | ||
1352 | flash_record = &image->records[i]; | ||
1353 | error = cyapa_gen5_write_fw_block(cyapa, flash_record); | ||
1354 | if (error) { | ||
1355 | dev_err(dev, "%s: Gen5 FW update aborted: %d\n", | ||
1356 | __func__, error); | ||
1357 | return error; | ||
1358 | } | ||
1359 | } | ||
1360 | |||
1361 | return 0; | ||
1362 | } | ||
1363 | |||
1364 | static int cyapa_gen5_change_power_state(struct cyapa *cyapa, u8 power_state) | ||
1365 | { | ||
1366 | u8 cmd[8] = { 0x04, 0x00, 0x06, 0x00, 0x2f, 0x00, 0x08, 0x01 }; | ||
1367 | u8 resp_data[6]; | ||
1368 | int resp_len; | ||
1369 | int error; | ||
1370 | |||
1371 | cmd[7] = power_state; | ||
1372 | resp_len = sizeof(resp_data); | ||
1373 | error = cyapa_i2c_pip_cmd_irq_sync(cyapa, cmd, sizeof(cmd), | ||
1374 | resp_data, &resp_len, | ||
1375 | 500, cyapa_gen5_sort_tsg_pip_app_resp_data, false); | ||
1376 | if (error || !VALID_CMD_RESP_HEADER(resp_data, 0x08) || | ||
1377 | !GEN5_CMD_COMPLETE_SUCCESS(resp_data[5])) | ||
1378 | return error < 0 ? error : -EINVAL; | ||
1379 | |||
1380 | return 0; | ||
1381 | } | ||
1382 | |||
1383 | static int cyapa_gen5_set_interval_time(struct cyapa *cyapa, | ||
1384 | u8 parameter_id, u16 interval_time) | ||
1385 | { | ||
1386 | struct gen5_app_cmd_head *app_cmd_head; | ||
1387 | struct gen5_app_set_parameter_data *parameter_data; | ||
1388 | u8 cmd[CYAPA_TSG_MAX_CMD_SIZE]; | ||
1389 | int cmd_len; | ||
1390 | u8 resp_data[7]; | ||
1391 | int resp_len; | ||
1392 | u8 parameter_size; | ||
1393 | int error; | ||
1394 | |||
1395 | memset(cmd, 0, CYAPA_TSG_MAX_CMD_SIZE); | ||
1396 | app_cmd_head = (struct gen5_app_cmd_head *)cmd; | ||
1397 | parameter_data = (struct gen5_app_set_parameter_data *) | ||
1398 | app_cmd_head->parameter_data; | ||
1399 | cmd_len = sizeof(struct gen5_app_cmd_head) + | ||
1400 | sizeof(struct gen5_app_set_parameter_data); | ||
1401 | |||
1402 | switch (parameter_id) { | ||
1403 | case GEN5_PARAMETER_ACT_INTERVL_ID: | ||
1404 | parameter_size = GEN5_PARAMETER_ACT_INTERVL_SIZE; | ||
1405 | break; | ||
1406 | case GEN5_PARAMETER_ACT_LFT_INTERVL_ID: | ||
1407 | parameter_size = GEN5_PARAMETER_ACT_LFT_INTERVL_SIZE; | ||
1408 | break; | ||
1409 | case GEN5_PARAMETER_LP_INTRVL_ID: | ||
1410 | parameter_size = GEN5_PARAMETER_LP_INTRVL_SIZE; | ||
1411 | break; | ||
1412 | default: | ||
1413 | return -EINVAL; | ||
1414 | } | ||
1415 | |||
1416 | put_unaligned_le16(GEN5_OUTPUT_REPORT_ADDR, &app_cmd_head->addr); | ||
1417 | /* | ||
1418 | * Don't include unused parameter value bytes and | ||
1419 | * 2 bytes register address. | ||
1420 | */ | ||
1421 | put_unaligned_le16(cmd_len - (4 - parameter_size) - 2, | ||
1422 | &app_cmd_head->length); | ||
1423 | app_cmd_head->report_id = GEN5_APP_CMD_REPORT_ID; | ||
1424 | app_cmd_head->cmd_code = GEN5_CMD_SET_PARAMETER; | ||
1425 | parameter_data->parameter_id = parameter_id; | ||
1426 | parameter_data->parameter_size = parameter_size; | ||
1427 | put_unaligned_le32((u32)interval_time, ¶meter_data->value); | ||
1428 | resp_len = sizeof(resp_data); | ||
1429 | error = cyapa_i2c_pip_cmd_irq_sync(cyapa, cmd, cmd_len, | ||
1430 | resp_data, &resp_len, | ||
1431 | 500, cyapa_gen5_sort_tsg_pip_app_resp_data, false); | ||
1432 | if (error || resp_data[5] != parameter_id || | ||
1433 | resp_data[6] != parameter_size || | ||
1434 | !VALID_CMD_RESP_HEADER(resp_data, GEN5_CMD_SET_PARAMETER)) | ||
1435 | return error < 0 ? error : -EINVAL; | ||
1436 | |||
1437 | return 0; | ||
1438 | } | ||
1439 | |||
1440 | static int cyapa_gen5_get_interval_time(struct cyapa *cyapa, | ||
1441 | u8 parameter_id, u16 *interval_time) | ||
1442 | { | ||
1443 | struct gen5_app_cmd_head *app_cmd_head; | ||
1444 | struct gen5_app_get_parameter_data *parameter_data; | ||
1445 | u8 cmd[CYAPA_TSG_MAX_CMD_SIZE]; | ||
1446 | int cmd_len; | ||
1447 | u8 resp_data[11]; | ||
1448 | int resp_len; | ||
1449 | u8 parameter_size; | ||
1450 | u16 mask, i; | ||
1451 | int error; | ||
1452 | |||
1453 | memset(cmd, 0, CYAPA_TSG_MAX_CMD_SIZE); | ||
1454 | app_cmd_head = (struct gen5_app_cmd_head *)cmd; | ||
1455 | parameter_data = (struct gen5_app_get_parameter_data *) | ||
1456 | app_cmd_head->parameter_data; | ||
1457 | cmd_len = sizeof(struct gen5_app_cmd_head) + | ||
1458 | sizeof(struct gen5_app_get_parameter_data); | ||
1459 | |||
1460 | *interval_time = 0; | ||
1461 | switch (parameter_id) { | ||
1462 | case GEN5_PARAMETER_ACT_INTERVL_ID: | ||
1463 | parameter_size = GEN5_PARAMETER_ACT_INTERVL_SIZE; | ||
1464 | break; | ||
1465 | case GEN5_PARAMETER_ACT_LFT_INTERVL_ID: | ||
1466 | parameter_size = GEN5_PARAMETER_ACT_LFT_INTERVL_SIZE; | ||
1467 | break; | ||
1468 | case GEN5_PARAMETER_LP_INTRVL_ID: | ||
1469 | parameter_size = GEN5_PARAMETER_LP_INTRVL_SIZE; | ||
1470 | break; | ||
1471 | default: | ||
1472 | return -EINVAL; | ||
1473 | } | ||
1474 | |||
1475 | put_unaligned_le16(GEN5_HID_DESCRIPTOR_ADDR, &app_cmd_head->addr); | ||
1476 | /* Don't include 2 bytes register address */ | ||
1477 | put_unaligned_le16(cmd_len - 2, &app_cmd_head->length); | ||
1478 | app_cmd_head->report_id = GEN5_APP_CMD_REPORT_ID; | ||
1479 | app_cmd_head->cmd_code = GEN5_CMD_GET_PARAMETER; | ||
1480 | parameter_data->parameter_id = parameter_id; | ||
1481 | |||
1482 | resp_len = sizeof(resp_data); | ||
1483 | error = cyapa_i2c_pip_cmd_irq_sync(cyapa, cmd, cmd_len, | ||
1484 | resp_data, &resp_len, | ||
1485 | 500, cyapa_gen5_sort_tsg_pip_app_resp_data, false); | ||
1486 | if (error || resp_data[5] != parameter_id || resp_data[6] == 0 || | ||
1487 | !VALID_CMD_RESP_HEADER(resp_data, GEN5_CMD_GET_PARAMETER)) | ||
1488 | return error < 0 ? error : -EINVAL; | ||
1489 | |||
1490 | mask = 0; | ||
1491 | for (i = 0; i < parameter_size; i++) | ||
1492 | mask |= (0xff << (i * 8)); | ||
1493 | *interval_time = get_unaligned_le16(&resp_data[7]) & mask; | ||
1494 | |||
1495 | return 0; | ||
1496 | } | ||
1497 | |||
1498 | static int cyapa_gen5_disable_pip_report(struct cyapa *cyapa) | ||
1499 | { | ||
1500 | struct gen5_app_cmd_head *app_cmd_head; | ||
1501 | u8 cmd[10]; | ||
1502 | u8 resp_data[7]; | ||
1503 | int resp_len; | ||
1504 | int error; | ||
1505 | |||
1506 | memset(cmd, 0, sizeof(cmd)); | ||
1507 | app_cmd_head = (struct gen5_app_cmd_head *)cmd; | ||
1508 | |||
1509 | put_unaligned_le16(GEN5_HID_DESCRIPTOR_ADDR, &app_cmd_head->addr); | ||
1510 | put_unaligned_le16(sizeof(cmd) - 2, &app_cmd_head->length); | ||
1511 | app_cmd_head->report_id = GEN5_APP_CMD_REPORT_ID; | ||
1512 | app_cmd_head->cmd_code = GEN5_CMD_SET_PARAMETER; | ||
1513 | app_cmd_head->parameter_data[0] = GEN5_PARAMETER_DISABLE_PIP_REPORT; | ||
1514 | app_cmd_head->parameter_data[1] = 0x01; | ||
1515 | app_cmd_head->parameter_data[2] = 0x01; | ||
1516 | resp_len = sizeof(resp_data); | ||
1517 | error = cyapa_i2c_pip_cmd_irq_sync(cyapa, cmd, sizeof(cmd), | ||
1518 | resp_data, &resp_len, | ||
1519 | 500, cyapa_gen5_sort_tsg_pip_app_resp_data, false); | ||
1520 | if (error || resp_data[5] != GEN5_PARAMETER_DISABLE_PIP_REPORT || | ||
1521 | !VALID_CMD_RESP_HEADER(resp_data, GEN5_CMD_SET_PARAMETER) || | ||
1522 | resp_data[6] != 0x01) | ||
1523 | return error < 0 ? error : -EINVAL; | ||
1524 | |||
1525 | return 0; | ||
1526 | } | ||
1527 | |||
1528 | static int cyapa_gen5_deep_sleep(struct cyapa *cyapa, u8 state) | ||
1529 | { | ||
1530 | u8 cmd[] = { 0x05, 0x00, 0x00, 0x08}; | ||
1531 | u8 resp_data[5]; | ||
1532 | int resp_len; | ||
1533 | int error; | ||
1534 | |||
1535 | cmd[2] = state & GEN5_DEEP_SLEEP_STATE_MASK; | ||
1536 | resp_len = sizeof(resp_data); | ||
1537 | error = cyapa_i2c_pip_cmd_irq_sync(cyapa, cmd, sizeof(cmd), | ||
1538 | resp_data, &resp_len, | ||
1539 | 500, cyapa_gen5_sort_deep_sleep_data, false); | ||
1540 | if (error || ((resp_data[3] & GEN5_DEEP_SLEEP_STATE_MASK) != state)) | ||
1541 | return -EINVAL; | ||
1542 | |||
1543 | return 0; | ||
1544 | } | ||
1545 | |||
1546 | static int cyapa_gen5_set_power_mode(struct cyapa *cyapa, | ||
1547 | u8 power_mode, u16 sleep_time) | ||
1548 | { | ||
1549 | struct device *dev = &cyapa->client->dev; | ||
1550 | u8 power_state; | ||
1551 | int error; | ||
1552 | |||
1553 | if (cyapa->state != CYAPA_STATE_GEN5_APP) | ||
1554 | return 0; | ||
1555 | |||
1556 | /* Dump all the report data before do power mode commmands. */ | ||
1557 | cyapa_empty_pip_output_data(cyapa, NULL, NULL, NULL); | ||
1558 | |||
1559 | if (GEN5_DEV_GET_PWR_STATE(cyapa) == UNINIT_PWR_MODE) { | ||
1560 | /* | ||
1561 | * Assume TP in deep sleep mode when driver is loaded, | ||
1562 | * avoid driver unload and reload command IO issue caused by TP | ||
1563 | * has been set into deep sleep mode when unloading. | ||
1564 | */ | ||
1565 | GEN5_DEV_SET_PWR_STATE(cyapa, PWR_MODE_OFF); | ||
1566 | } | ||
1567 | |||
1568 | if (GEN5_DEV_UNINIT_SLEEP_TIME(cyapa) && | ||
1569 | GEN5_DEV_GET_PWR_STATE(cyapa) != PWR_MODE_OFF) | ||
1570 | if (cyapa_gen5_get_interval_time(cyapa, | ||
1571 | GEN5_PARAMETER_LP_INTRVL_ID, | ||
1572 | &cyapa->dev_sleep_time) != 0) | ||
1573 | GEN5_DEV_SET_SLEEP_TIME(cyapa, UNINIT_SLEEP_TIME); | ||
1574 | |||
1575 | if (GEN5_DEV_GET_PWR_STATE(cyapa) == power_mode) { | ||
1576 | if (power_mode == PWR_MODE_OFF || | ||
1577 | power_mode == PWR_MODE_FULL_ACTIVE || | ||
1578 | power_mode == PWR_MODE_BTN_ONLY || | ||
1579 | GEN5_DEV_GET_SLEEP_TIME(cyapa) == sleep_time) { | ||
1580 | /* Has in correct power mode state, early return. */ | ||
1581 | return 0; | ||
1582 | } | ||
1583 | } | ||
1584 | |||
1585 | if (power_mode == PWR_MODE_OFF) { | ||
1586 | error = cyapa_gen5_deep_sleep(cyapa, GEN5_DEEP_SLEEP_STATE_OFF); | ||
1587 | if (error) { | ||
1588 | dev_err(dev, "enter deep sleep fail: %d\n", error); | ||
1589 | return error; | ||
1590 | } | ||
1591 | |||
1592 | GEN5_DEV_SET_PWR_STATE(cyapa, PWR_MODE_OFF); | ||
1593 | return 0; | ||
1594 | } | ||
1595 | |||
1596 | /* | ||
1597 | * When trackpad in power off mode, it cannot change to other power | ||
1598 | * state directly, must be wake up from sleep firstly, then | ||
1599 | * continue to do next power sate change. | ||
1600 | */ | ||
1601 | if (GEN5_DEV_GET_PWR_STATE(cyapa) == PWR_MODE_OFF) { | ||
1602 | error = cyapa_gen5_deep_sleep(cyapa, GEN5_DEEP_SLEEP_STATE_ON); | ||
1603 | if (error) { | ||
1604 | dev_err(dev, "deep sleep wake fail: %d\n", error); | ||
1605 | return error; | ||
1606 | } | ||
1607 | } | ||
1608 | |||
1609 | if (power_mode == PWR_MODE_FULL_ACTIVE) { | ||
1610 | error = cyapa_gen5_change_power_state(cyapa, | ||
1611 | GEN5_POWER_STATE_ACTIVE); | ||
1612 | if (error) { | ||
1613 | dev_err(dev, "change to active fail: %d\n", error); | ||
1614 | return error; | ||
1615 | } | ||
1616 | |||
1617 | GEN5_DEV_SET_PWR_STATE(cyapa, PWR_MODE_FULL_ACTIVE); | ||
1618 | } else if (power_mode == PWR_MODE_BTN_ONLY) { | ||
1619 | error = cyapa_gen5_change_power_state(cyapa, | ||
1620 | GEN5_POWER_STATE_BTN_ONLY); | ||
1621 | if (error) { | ||
1622 | dev_err(dev, "fail to button only mode: %d\n", error); | ||
1623 | return error; | ||
1624 | } | ||
1625 | |||
1626 | GEN5_DEV_SET_PWR_STATE(cyapa, PWR_MODE_BTN_ONLY); | ||
1627 | } else { | ||
1628 | /* | ||
1629 | * Continue to change power mode even failed to set | ||
1630 | * interval time, it won't affect the power mode change. | ||
1631 | * except the sleep interval time is not correct. | ||
1632 | */ | ||
1633 | if (GEN5_DEV_UNINIT_SLEEP_TIME(cyapa) || | ||
1634 | sleep_time != GEN5_DEV_GET_SLEEP_TIME(cyapa)) | ||
1635 | if (cyapa_gen5_set_interval_time(cyapa, | ||
1636 | GEN5_PARAMETER_LP_INTRVL_ID, | ||
1637 | sleep_time) == 0) | ||
1638 | GEN5_DEV_SET_SLEEP_TIME(cyapa, sleep_time); | ||
1639 | |||
1640 | if (sleep_time <= GEN5_POWER_READY_MAX_INTRVL_TIME) | ||
1641 | power_state = GEN5_POWER_STATE_READY; | ||
1642 | else | ||
1643 | power_state = GEN5_POWER_STATE_IDLE; | ||
1644 | error = cyapa_gen5_change_power_state(cyapa, power_state); | ||
1645 | if (error) { | ||
1646 | dev_err(dev, "set power state to 0x%02x failed: %d\n", | ||
1647 | power_state, error); | ||
1648 | return error; | ||
1649 | } | ||
1650 | |||
1651 | /* | ||
1652 | * Disable pip report for a little time, firmware will | ||
1653 | * re-enable it automatically. It's used to fix the issue | ||
1654 | * that trackpad unable to report signal to wake system up | ||
1655 | * in the special situation that system is in suspending, and | ||
1656 | * at the same time, user touch trackpad to wake system up. | ||
1657 | * This function can avoid the data to be buffured when system | ||
1658 | * is suspending which may cause interrput line unable to be | ||
1659 | * asserted again. | ||
1660 | */ | ||
1661 | cyapa_empty_pip_output_data(cyapa, NULL, NULL, NULL); | ||
1662 | cyapa_gen5_disable_pip_report(cyapa); | ||
1663 | |||
1664 | GEN5_DEV_SET_PWR_STATE(cyapa, | ||
1665 | cyapa_sleep_time_to_pwr_cmd(sleep_time)); | ||
1666 | } | ||
1667 | |||
1668 | return 0; | ||
1669 | } | ||
1670 | |||
1671 | static int cyapa_gen5_resume_scanning(struct cyapa *cyapa) | ||
1672 | { | ||
1673 | u8 cmd[] = { 0x04, 0x00, 0x05, 0x00, 0x2f, 0x00, 0x04 }; | ||
1674 | u8 resp_data[6]; | ||
1675 | int resp_len; | ||
1676 | int error; | ||
1677 | |||
1678 | /* Try to dump all buffered data before doing command. */ | ||
1679 | cyapa_empty_pip_output_data(cyapa, NULL, NULL, NULL); | ||
1680 | |||
1681 | resp_len = sizeof(resp_data); | ||
1682 | error = cyapa_i2c_pip_cmd_irq_sync(cyapa, | ||
1683 | cmd, sizeof(cmd), | ||
1684 | resp_data, &resp_len, | ||
1685 | 500, cyapa_gen5_sort_tsg_pip_app_resp_data, true); | ||
1686 | if (error || !VALID_CMD_RESP_HEADER(resp_data, 0x04)) | ||
1687 | return -EINVAL; | ||
1688 | |||
1689 | /* Try to dump all buffered data when resuming scanning. */ | ||
1690 | cyapa_empty_pip_output_data(cyapa, NULL, NULL, NULL); | ||
1691 | |||
1692 | return 0; | ||
1693 | } | ||
1694 | |||
1695 | static int cyapa_gen5_suspend_scanning(struct cyapa *cyapa) | ||
1696 | { | ||
1697 | u8 cmd[] = { 0x04, 0x00, 0x05, 0x00, 0x2f, 0x00, 0x03 }; | ||
1698 | u8 resp_data[6]; | ||
1699 | int resp_len; | ||
1700 | int error; | ||
1701 | |||
1702 | /* Try to dump all buffered data before doing command. */ | ||
1703 | cyapa_empty_pip_output_data(cyapa, NULL, NULL, NULL); | ||
1704 | |||
1705 | resp_len = sizeof(resp_data); | ||
1706 | error = cyapa_i2c_pip_cmd_irq_sync(cyapa, | ||
1707 | cmd, sizeof(cmd), | ||
1708 | resp_data, &resp_len, | ||
1709 | 500, cyapa_gen5_sort_tsg_pip_app_resp_data, true); | ||
1710 | if (error || !VALID_CMD_RESP_HEADER(resp_data, 0x03)) | ||
1711 | return -EINVAL; | ||
1712 | |||
1713 | /* Try to dump all buffered data when suspending scanning. */ | ||
1714 | cyapa_empty_pip_output_data(cyapa, NULL, NULL, NULL); | ||
1715 | |||
1716 | return 0; | ||
1717 | } | ||
1718 | |||
1719 | static int cyapa_gen5_calibrate_pwcs(struct cyapa *cyapa, | ||
1720 | u8 calibrate_sensing_mode_type) | ||
1721 | { | ||
1722 | struct gen5_app_cmd_head *app_cmd_head; | ||
1723 | u8 cmd[8]; | ||
1724 | u8 resp_data[6]; | ||
1725 | int resp_len; | ||
1726 | int error; | ||
1727 | |||
1728 | /* Try to dump all buffered data before doing command. */ | ||
1729 | cyapa_empty_pip_output_data(cyapa, NULL, NULL, NULL); | ||
1730 | |||
1731 | memset(cmd, 0, sizeof(cmd)); | ||
1732 | app_cmd_head = (struct gen5_app_cmd_head *)cmd; | ||
1733 | put_unaligned_le16(GEN5_OUTPUT_REPORT_ADDR, &app_cmd_head->addr); | ||
1734 | put_unaligned_le16(sizeof(cmd) - 2, &app_cmd_head->length); | ||
1735 | app_cmd_head->report_id = GEN5_APP_CMD_REPORT_ID; | ||
1736 | app_cmd_head->cmd_code = GEN5_CMD_CALIBRATE; | ||
1737 | app_cmd_head->parameter_data[0] = calibrate_sensing_mode_type; | ||
1738 | resp_len = sizeof(resp_data); | ||
1739 | error = cyapa_i2c_pip_cmd_irq_sync(cyapa, | ||
1740 | cmd, sizeof(cmd), | ||
1741 | resp_data, &resp_len, | ||
1742 | 5000, cyapa_gen5_sort_tsg_pip_app_resp_data, true); | ||
1743 | if (error || !VALID_CMD_RESP_HEADER(resp_data, GEN5_CMD_CALIBRATE) || | ||
1744 | !GEN5_CMD_COMPLETE_SUCCESS(resp_data[5])) | ||
1745 | return error < 0 ? error : -EAGAIN; | ||
1746 | |||
1747 | return 0; | ||
1748 | } | ||
1749 | |||
1750 | static ssize_t cyapa_gen5_do_calibrate(struct device *dev, | ||
1751 | struct device_attribute *attr, | ||
1752 | const char *buf, size_t count) | ||
1753 | { | ||
1754 | struct cyapa *cyapa = dev_get_drvdata(dev); | ||
1755 | int error, calibrate_error; | ||
1756 | |||
1757 | /* 1. Suspend Scanning*/ | ||
1758 | error = cyapa_gen5_suspend_scanning(cyapa); | ||
1759 | if (error) | ||
1760 | return error; | ||
1761 | |||
1762 | /* 2. Do mutual capacitance fine calibrate. */ | ||
1763 | calibrate_error = cyapa_gen5_calibrate_pwcs(cyapa, | ||
1764 | CYAPA_SENSING_MODE_MUTUAL_CAP_FINE); | ||
1765 | if (calibrate_error) | ||
1766 | goto resume_scanning; | ||
1767 | |||
1768 | /* 3. Do self capacitance calibrate. */ | ||
1769 | calibrate_error = cyapa_gen5_calibrate_pwcs(cyapa, | ||
1770 | CYAPA_SENSING_MODE_SELF_CAP); | ||
1771 | if (calibrate_error) | ||
1772 | goto resume_scanning; | ||
1773 | |||
1774 | resume_scanning: | ||
1775 | /* 4. Resume Scanning*/ | ||
1776 | error = cyapa_gen5_resume_scanning(cyapa); | ||
1777 | if (error || calibrate_error) | ||
1778 | return error ? error : calibrate_error; | ||
1779 | |||
1780 | return count; | ||
1781 | } | ||
1782 | |||
1783 | static s32 twos_complement_to_s32(s32 value, int num_bits) | ||
1784 | { | ||
1785 | if (value >> (num_bits - 1)) | ||
1786 | value |= -1 << num_bits; | ||
1787 | return value; | ||
1788 | } | ||
1789 | |||
1790 | static s32 cyapa_parse_structure_data(u8 data_format, u8 *buf, int buf_len) | ||
1791 | { | ||
1792 | int data_size; | ||
1793 | bool big_endian; | ||
1794 | bool unsigned_type; | ||
1795 | s32 value; | ||
1796 | |||
1797 | data_size = (data_format & 0x07); | ||
1798 | big_endian = ((data_format & 0x10) == 0x00); | ||
1799 | unsigned_type = ((data_format & 0x20) == 0x00); | ||
1800 | |||
1801 | if (buf_len < data_size) | ||
1802 | return 0; | ||
1803 | |||
1804 | switch (data_size) { | ||
1805 | case 1: | ||
1806 | value = buf[0]; | ||
1807 | break; | ||
1808 | case 2: | ||
1809 | if (big_endian) | ||
1810 | value = get_unaligned_be16(buf); | ||
1811 | else | ||
1812 | value = get_unaligned_le16(buf); | ||
1813 | break; | ||
1814 | case 4: | ||
1815 | if (big_endian) | ||
1816 | value = get_unaligned_be32(buf); | ||
1817 | else | ||
1818 | value = get_unaligned_le32(buf); | ||
1819 | break; | ||
1820 | default: | ||
1821 | /* Should not happen, just as default case here. */ | ||
1822 | value = 0; | ||
1823 | break; | ||
1824 | } | ||
1825 | |||
1826 | if (!unsigned_type) | ||
1827 | value = twos_complement_to_s32(value, data_size * 8); | ||
1828 | |||
1829 | return value; | ||
1830 | } | ||
1831 | |||
1832 | static void cyapa_gen5_guess_electrodes(struct cyapa *cyapa, | ||
1833 | int *electrodes_rx, int *electrodes_tx) | ||
1834 | { | ||
1835 | if (cyapa->electrodes_rx != 0) { | ||
1836 | *electrodes_rx = cyapa->electrodes_rx; | ||
1837 | *electrodes_tx = (cyapa->electrodes_x == *electrodes_rx) ? | ||
1838 | cyapa->electrodes_y : cyapa->electrodes_x; | ||
1839 | } else { | ||
1840 | *electrodes_tx = min(cyapa->electrodes_x, cyapa->electrodes_y); | ||
1841 | *electrodes_rx = max(cyapa->electrodes_x, cyapa->electrodes_y); | ||
1842 | } | ||
1843 | } | ||
1844 | |||
1845 | /* | ||
1846 | * Read all the global mutual or self idac data or mutual or self local PWC | ||
1847 | * data based on the @idac_data_type. | ||
1848 | * If the input value of @data_size is 0, then means read global mutual or | ||
1849 | * self idac data. For read global mutual idac data, @idac_max, @idac_min and | ||
1850 | * @idac_ave are in order used to return the max value of global mutual idac | ||
1851 | * data, the min value of global mutual idac and the average value of the | ||
1852 | * global mutual idac data. For read global self idac data, @idac_max is used | ||
1853 | * to return the global self cap idac data in Rx direction, @idac_min is used | ||
1854 | * to return the global self cap idac data in Tx direction. @idac_ave is not | ||
1855 | * used. | ||
1856 | * If the input value of @data_size is not 0, than means read the mutual or | ||
1857 | * self local PWC data. The @idac_max, @idac_min and @idac_ave are used to | ||
1858 | * return the max, min and average value of the mutual or self local PWC data. | ||
1859 | * Note, in order to raed mutual local PWC data, must read invoke this function | ||
1860 | * to read the mutual global idac data firstly to set the correct Rx number | ||
1861 | * value, otherwise, the read mutual idac and PWC data may not correct. | ||
1862 | */ | ||
1863 | static int cyapa_gen5_read_idac_data(struct cyapa *cyapa, | ||
1864 | u8 cmd_code, u8 idac_data_type, int *data_size, | ||
1865 | int *idac_max, int *idac_min, int *idac_ave) | ||
1866 | { | ||
1867 | struct gen5_app_cmd_head *cmd_head; | ||
1868 | u8 cmd[12]; | ||
1869 | u8 resp_data[256]; | ||
1870 | int resp_len; | ||
1871 | int read_len; | ||
1872 | int value; | ||
1873 | u16 offset; | ||
1874 | int read_elements; | ||
1875 | bool read_global_idac; | ||
1876 | int sum, count, max_element_cnt; | ||
1877 | int tmp_max, tmp_min, tmp_ave, tmp_sum, tmp_count; | ||
1878 | int electrodes_rx, electrodes_tx; | ||
1879 | int i; | ||
1880 | int error; | ||
1881 | |||
1882 | if (cmd_code != GEN5_CMD_RETRIEVE_DATA_STRUCTURE || | ||
1883 | (idac_data_type != GEN5_RETRIEVE_MUTUAL_PWC_DATA && | ||
1884 | idac_data_type != GEN5_RETRIEVE_SELF_CAP_PWC_DATA) || | ||
1885 | !data_size || !idac_max || !idac_min || !idac_ave) | ||
1886 | return -EINVAL; | ||
1887 | |||
1888 | *idac_max = INT_MIN; | ||
1889 | *idac_min = INT_MAX; | ||
1890 | sum = count = tmp_count = 0; | ||
1891 | electrodes_rx = electrodes_tx = 0; | ||
1892 | if (*data_size == 0) { | ||
1893 | /* | ||
1894 | * Read global idac values firstly. | ||
1895 | * Currently, no idac data exceed 4 bytes. | ||
1896 | */ | ||
1897 | read_global_idac = true; | ||
1898 | offset = 0; | ||
1899 | *data_size = 4; | ||
1900 | tmp_max = INT_MIN; | ||
1901 | tmp_min = INT_MAX; | ||
1902 | tmp_ave = tmp_sum = tmp_count = 0; | ||
1903 | |||
1904 | if (idac_data_type == GEN5_RETRIEVE_MUTUAL_PWC_DATA) { | ||
1905 | if (cyapa->aligned_electrodes_rx == 0) { | ||
1906 | cyapa_gen5_guess_electrodes(cyapa, | ||
1907 | &electrodes_rx, &electrodes_tx); | ||
1908 | cyapa->aligned_electrodes_rx = | ||
1909 | (electrodes_rx + 3) & ~3u; | ||
1910 | } | ||
1911 | max_element_cnt = | ||
1912 | (cyapa->aligned_electrodes_rx + 7) & ~7u; | ||
1913 | } else { | ||
1914 | max_element_cnt = 2; | ||
1915 | } | ||
1916 | } else { | ||
1917 | read_global_idac = false; | ||
1918 | if (*data_size > 4) | ||
1919 | *data_size = 4; | ||
1920 | /* Calculate the start offset in bytes of local PWC data. */ | ||
1921 | if (idac_data_type == GEN5_RETRIEVE_MUTUAL_PWC_DATA) { | ||
1922 | offset = cyapa->aligned_electrodes_rx * (*data_size); | ||
1923 | if (cyapa->electrodes_rx == cyapa->electrodes_x) | ||
1924 | electrodes_tx = cyapa->electrodes_y; | ||
1925 | else | ||
1926 | electrodes_tx = cyapa->electrodes_x; | ||
1927 | max_element_cnt = ((cyapa->aligned_electrodes_rx + 7) & | ||
1928 | ~7u) * electrodes_tx; | ||
1929 | } else if (idac_data_type == GEN5_RETRIEVE_SELF_CAP_PWC_DATA) { | ||
1930 | offset = 2; | ||
1931 | max_element_cnt = cyapa->electrodes_x + | ||
1932 | cyapa->electrodes_y; | ||
1933 | max_element_cnt = (max_element_cnt + 3) & ~3u; | ||
1934 | } | ||
1935 | } | ||
1936 | |||
1937 | memset(cmd, 0, sizeof(cmd)); | ||
1938 | cmd_head = (struct gen5_app_cmd_head *)cmd; | ||
1939 | put_unaligned_le16(GEN5_OUTPUT_REPORT_ADDR, &cmd_head->addr); | ||
1940 | put_unaligned_le16(sizeof(cmd) - 2, &cmd_head->length); | ||
1941 | cmd_head->report_id = GEN5_APP_CMD_REPORT_ID; | ||
1942 | cmd_head->cmd_code = cmd_code; | ||
1943 | do { | ||
1944 | read_elements = (256 - GEN5_RESP_DATA_STRUCTURE_OFFSET) / | ||
1945 | (*data_size); | ||
1946 | read_elements = min(read_elements, max_element_cnt - count); | ||
1947 | read_len = read_elements * (*data_size); | ||
1948 | |||
1949 | put_unaligned_le16(offset, &cmd_head->parameter_data[0]); | ||
1950 | put_unaligned_le16(read_len, &cmd_head->parameter_data[2]); | ||
1951 | cmd_head->parameter_data[4] = idac_data_type; | ||
1952 | resp_len = GEN5_RESP_DATA_STRUCTURE_OFFSET + read_len; | ||
1953 | error = cyapa_i2c_pip_cmd_irq_sync(cyapa, | ||
1954 | cmd, sizeof(cmd), | ||
1955 | resp_data, &resp_len, | ||
1956 | 500, cyapa_gen5_sort_tsg_pip_app_resp_data, | ||
1957 | true); | ||
1958 | if (error || resp_len < GEN5_RESP_DATA_STRUCTURE_OFFSET || | ||
1959 | !VALID_CMD_RESP_HEADER(resp_data, cmd_code) || | ||
1960 | !GEN5_CMD_COMPLETE_SUCCESS(resp_data[5]) || | ||
1961 | resp_data[6] != idac_data_type) | ||
1962 | return (error < 0) ? error : -EAGAIN; | ||
1963 | read_len = get_unaligned_le16(&resp_data[7]); | ||
1964 | if (read_len == 0) | ||
1965 | break; | ||
1966 | |||
1967 | *data_size = (resp_data[9] & GEN5_PWC_DATA_ELEMENT_SIZE_MASK); | ||
1968 | if (read_len < *data_size) | ||
1969 | return -EINVAL; | ||
1970 | |||
1971 | if (read_global_idac && | ||
1972 | idac_data_type == GEN5_RETRIEVE_SELF_CAP_PWC_DATA) { | ||
1973 | /* Rx's self global idac data. */ | ||
1974 | *idac_max = cyapa_parse_structure_data( | ||
1975 | resp_data[9], | ||
1976 | &resp_data[GEN5_RESP_DATA_STRUCTURE_OFFSET], | ||
1977 | *data_size); | ||
1978 | /* Tx's self global idac data. */ | ||
1979 | *idac_min = cyapa_parse_structure_data( | ||
1980 | resp_data[9], | ||
1981 | &resp_data[GEN5_RESP_DATA_STRUCTURE_OFFSET + | ||
1982 | *data_size], | ||
1983 | *data_size); | ||
1984 | break; | ||
1985 | } | ||
1986 | |||
1987 | /* Read mutual global idac or local mutual/self PWC data. */ | ||
1988 | offset += read_len; | ||
1989 | for (i = 10; i < (read_len + GEN5_RESP_DATA_STRUCTURE_OFFSET); | ||
1990 | i += *data_size) { | ||
1991 | value = cyapa_parse_structure_data(resp_data[9], | ||
1992 | &resp_data[i], *data_size); | ||
1993 | *idac_min = min(value, *idac_min); | ||
1994 | *idac_max = max(value, *idac_max); | ||
1995 | |||
1996 | if (idac_data_type == GEN5_RETRIEVE_MUTUAL_PWC_DATA && | ||
1997 | tmp_count < cyapa->aligned_electrodes_rx && | ||
1998 | read_global_idac) { | ||
1999 | /* | ||
2000 | * The value gap betwen global and local mutual | ||
2001 | * idac data must bigger than 50%. | ||
2002 | * Normally, global value bigger than 50, | ||
2003 | * local values less than 10. | ||
2004 | */ | ||
2005 | if (!tmp_ave || value > tmp_ave / 2) { | ||
2006 | tmp_min = min(value, tmp_min); | ||
2007 | tmp_max = max(value, tmp_max); | ||
2008 | tmp_sum += value; | ||
2009 | tmp_count++; | ||
2010 | |||
2011 | tmp_ave = tmp_sum / tmp_count; | ||
2012 | } | ||
2013 | } | ||
2014 | |||
2015 | sum += value; | ||
2016 | count++; | ||
2017 | |||
2018 | if (count >= max_element_cnt) | ||
2019 | goto out; | ||
2020 | } | ||
2021 | } while (true); | ||
2022 | |||
2023 | out: | ||
2024 | *idac_ave = count ? (sum / count) : 0; | ||
2025 | |||
2026 | if (read_global_idac && | ||
2027 | idac_data_type == GEN5_RETRIEVE_MUTUAL_PWC_DATA) { | ||
2028 | if (tmp_count == 0) | ||
2029 | return 0; | ||
2030 | |||
2031 | if (tmp_count == cyapa->aligned_electrodes_rx) { | ||
2032 | cyapa->electrodes_rx = cyapa->electrodes_rx ? | ||
2033 | cyapa->electrodes_rx : electrodes_rx; | ||
2034 | } else if (tmp_count == electrodes_rx) { | ||
2035 | cyapa->electrodes_rx = cyapa->electrodes_rx ? | ||
2036 | cyapa->electrodes_rx : electrodes_rx; | ||
2037 | cyapa->aligned_electrodes_rx = electrodes_rx; | ||
2038 | } else { | ||
2039 | cyapa->electrodes_rx = cyapa->electrodes_rx ? | ||
2040 | cyapa->electrodes_rx : electrodes_tx; | ||
2041 | cyapa->aligned_electrodes_rx = tmp_count; | ||
2042 | } | ||
2043 | |||
2044 | *idac_min = tmp_min; | ||
2045 | *idac_max = tmp_max; | ||
2046 | *idac_ave = tmp_ave; | ||
2047 | } | ||
2048 | |||
2049 | return 0; | ||
2050 | } | ||
2051 | |||
2052 | static int cyapa_gen5_read_mutual_idac_data(struct cyapa *cyapa, | ||
2053 | int *gidac_mutual_max, int *gidac_mutual_min, int *gidac_mutual_ave, | ||
2054 | int *lidac_mutual_max, int *lidac_mutual_min, int *lidac_mutual_ave) | ||
2055 | { | ||
2056 | int data_size; | ||
2057 | int error; | ||
2058 | |||
2059 | *gidac_mutual_max = *gidac_mutual_min = *gidac_mutual_ave = 0; | ||
2060 | *lidac_mutual_max = *lidac_mutual_min = *lidac_mutual_ave = 0; | ||
2061 | |||
2062 | data_size = 0; | ||
2063 | error = cyapa_gen5_read_idac_data(cyapa, | ||
2064 | GEN5_CMD_RETRIEVE_DATA_STRUCTURE, | ||
2065 | GEN5_RETRIEVE_MUTUAL_PWC_DATA, | ||
2066 | &data_size, | ||
2067 | gidac_mutual_max, gidac_mutual_min, gidac_mutual_ave); | ||
2068 | if (error) | ||
2069 | return error; | ||
2070 | |||
2071 | error = cyapa_gen5_read_idac_data(cyapa, | ||
2072 | GEN5_CMD_RETRIEVE_DATA_STRUCTURE, | ||
2073 | GEN5_RETRIEVE_MUTUAL_PWC_DATA, | ||
2074 | &data_size, | ||
2075 | lidac_mutual_max, lidac_mutual_min, lidac_mutual_ave); | ||
2076 | return error; | ||
2077 | } | ||
2078 | |||
2079 | static int cyapa_gen5_read_self_idac_data(struct cyapa *cyapa, | ||
2080 | int *gidac_self_rx, int *gidac_self_tx, | ||
2081 | int *lidac_self_max, int *lidac_self_min, int *lidac_self_ave) | ||
2082 | { | ||
2083 | int data_size; | ||
2084 | int error; | ||
2085 | |||
2086 | *gidac_self_rx = *gidac_self_tx = 0; | ||
2087 | *lidac_self_max = *lidac_self_min = *lidac_self_ave = 0; | ||
2088 | |||
2089 | data_size = 0; | ||
2090 | error = cyapa_gen5_read_idac_data(cyapa, | ||
2091 | GEN5_CMD_RETRIEVE_DATA_STRUCTURE, | ||
2092 | GEN5_RETRIEVE_SELF_CAP_PWC_DATA, | ||
2093 | &data_size, | ||
2094 | lidac_self_max, lidac_self_min, lidac_self_ave); | ||
2095 | if (error) | ||
2096 | return error; | ||
2097 | *gidac_self_rx = *lidac_self_max; | ||
2098 | *gidac_self_tx = *lidac_self_min; | ||
2099 | |||
2100 | error = cyapa_gen5_read_idac_data(cyapa, | ||
2101 | GEN5_CMD_RETRIEVE_DATA_STRUCTURE, | ||
2102 | GEN5_RETRIEVE_SELF_CAP_PWC_DATA, | ||
2103 | &data_size, | ||
2104 | lidac_self_max, lidac_self_min, lidac_self_ave); | ||
2105 | return error; | ||
2106 | } | ||
2107 | |||
2108 | static ssize_t cyapa_gen5_execute_panel_scan(struct cyapa *cyapa) | ||
2109 | { | ||
2110 | struct gen5_app_cmd_head *app_cmd_head; | ||
2111 | u8 cmd[7]; | ||
2112 | u8 resp_data[6]; | ||
2113 | int resp_len; | ||
2114 | int error; | ||
2115 | |||
2116 | memset(cmd, 0, sizeof(cmd)); | ||
2117 | app_cmd_head = (struct gen5_app_cmd_head *)cmd; | ||
2118 | put_unaligned_le16(GEN5_OUTPUT_REPORT_ADDR, &app_cmd_head->addr); | ||
2119 | put_unaligned_le16(sizeof(cmd) - 2, &app_cmd_head->length); | ||
2120 | app_cmd_head->report_id = GEN5_APP_CMD_REPORT_ID; | ||
2121 | app_cmd_head->cmd_code = GEN5_CMD_EXECUTE_PANEL_SCAN; | ||
2122 | resp_len = sizeof(resp_data); | ||
2123 | error = cyapa_i2c_pip_cmd_irq_sync(cyapa, | ||
2124 | cmd, sizeof(cmd), | ||
2125 | resp_data, &resp_len, | ||
2126 | 500, cyapa_gen5_sort_tsg_pip_app_resp_data, true); | ||
2127 | if (error || resp_len != sizeof(resp_data) || | ||
2128 | !VALID_CMD_RESP_HEADER(resp_data, | ||
2129 | GEN5_CMD_EXECUTE_PANEL_SCAN) || | ||
2130 | !GEN5_CMD_COMPLETE_SUCCESS(resp_data[5])) | ||
2131 | return error ? error : -EAGAIN; | ||
2132 | |||
2133 | return 0; | ||
2134 | } | ||
2135 | |||
2136 | static int cyapa_gen5_read_panel_scan_raw_data(struct cyapa *cyapa, | ||
2137 | u8 cmd_code, u8 raw_data_type, int raw_data_max_num, | ||
2138 | int *raw_data_max, int *raw_data_min, int *raw_data_ave, | ||
2139 | u8 *buffer) | ||
2140 | { | ||
2141 | struct gen5_app_cmd_head *app_cmd_head; | ||
2142 | struct gen5_retrieve_panel_scan_data *panel_sacn_data; | ||
2143 | u8 cmd[12]; | ||
2144 | u8 resp_data[256]; /* Max bytes can transfer one time. */ | ||
2145 | int resp_len; | ||
2146 | int read_elements; | ||
2147 | int read_len; | ||
2148 | u16 offset; | ||
2149 | s32 value; | ||
2150 | int sum, count; | ||
2151 | int data_size; | ||
2152 | s32 *intp; | ||
2153 | int i; | ||
2154 | int error; | ||
2155 | |||
2156 | if (cmd_code != GEN5_CMD_RETRIEVE_PANEL_SCAN || | ||
2157 | (raw_data_type > GEN5_PANEL_SCAN_SELF_DIFFCOUNT) || | ||
2158 | !raw_data_max || !raw_data_min || !raw_data_ave) | ||
2159 | return -EINVAL; | ||
2160 | |||
2161 | intp = (s32 *)buffer; | ||
2162 | *raw_data_max = INT_MIN; | ||
2163 | *raw_data_min = INT_MAX; | ||
2164 | sum = count = 0; | ||
2165 | offset = 0; | ||
2166 | /* Assume max element size is 4 currently. */ | ||
2167 | read_elements = (256 - GEN5_RESP_DATA_STRUCTURE_OFFSET) / 4; | ||
2168 | read_len = read_elements * 4; | ||
2169 | app_cmd_head = (struct gen5_app_cmd_head *)cmd; | ||
2170 | put_unaligned_le16(GEN5_OUTPUT_REPORT_ADDR, &app_cmd_head->addr); | ||
2171 | put_unaligned_le16(sizeof(cmd) - 2, &app_cmd_head->length); | ||
2172 | app_cmd_head->report_id = GEN5_APP_CMD_REPORT_ID; | ||
2173 | app_cmd_head->cmd_code = cmd_code; | ||
2174 | panel_sacn_data = (struct gen5_retrieve_panel_scan_data *) | ||
2175 | app_cmd_head->parameter_data; | ||
2176 | do { | ||
2177 | put_unaligned_le16(offset, &panel_sacn_data->read_offset); | ||
2178 | put_unaligned_le16(read_elements, | ||
2179 | &panel_sacn_data->read_elements); | ||
2180 | panel_sacn_data->data_id = raw_data_type; | ||
2181 | |||
2182 | resp_len = GEN5_RESP_DATA_STRUCTURE_OFFSET + read_len; | ||
2183 | error = cyapa_i2c_pip_cmd_irq_sync(cyapa, | ||
2184 | cmd, sizeof(cmd), | ||
2185 | resp_data, &resp_len, | ||
2186 | 500, cyapa_gen5_sort_tsg_pip_app_resp_data, true); | ||
2187 | if (error || resp_len < GEN5_RESP_DATA_STRUCTURE_OFFSET || | ||
2188 | !VALID_CMD_RESP_HEADER(resp_data, cmd_code) || | ||
2189 | !GEN5_CMD_COMPLETE_SUCCESS(resp_data[5]) || | ||
2190 | resp_data[6] != raw_data_type) | ||
2191 | return error ? error : -EAGAIN; | ||
2192 | |||
2193 | read_elements = get_unaligned_le16(&resp_data[7]); | ||
2194 | if (read_elements == 0) | ||
2195 | break; | ||
2196 | |||
2197 | data_size = (resp_data[9] & GEN5_PWC_DATA_ELEMENT_SIZE_MASK); | ||
2198 | offset += read_elements; | ||
2199 | if (read_elements) { | ||
2200 | for (i = GEN5_RESP_DATA_STRUCTURE_OFFSET; | ||
2201 | i < (read_elements * data_size + | ||
2202 | GEN5_RESP_DATA_STRUCTURE_OFFSET); | ||
2203 | i += data_size) { | ||
2204 | value = cyapa_parse_structure_data(resp_data[9], | ||
2205 | &resp_data[i], data_size); | ||
2206 | *raw_data_min = min(value, *raw_data_min); | ||
2207 | *raw_data_max = max(value, *raw_data_max); | ||
2208 | |||
2209 | if (intp) | ||
2210 | put_unaligned_le32(value, &intp[count]); | ||
2211 | |||
2212 | sum += value; | ||
2213 | count++; | ||
2214 | |||
2215 | } | ||
2216 | } | ||
2217 | |||
2218 | if (count >= raw_data_max_num) | ||
2219 | break; | ||
2220 | |||
2221 | read_elements = (sizeof(resp_data) - | ||
2222 | GEN5_RESP_DATA_STRUCTURE_OFFSET) / data_size; | ||
2223 | read_len = read_elements * data_size; | ||
2224 | } while (true); | ||
2225 | |||
2226 | *raw_data_ave = count ? (sum / count) : 0; | ||
2227 | |||
2228 | return 0; | ||
2229 | } | ||
2230 | |||
2231 | static ssize_t cyapa_gen5_show_baseline(struct device *dev, | ||
2232 | struct device_attribute *attr, char *buf) | ||
2233 | { | ||
2234 | struct cyapa *cyapa = dev_get_drvdata(dev); | ||
2235 | int gidac_mutual_max, gidac_mutual_min, gidac_mutual_ave; | ||
2236 | int lidac_mutual_max, lidac_mutual_min, lidac_mutual_ave; | ||
2237 | int gidac_self_rx, gidac_self_tx; | ||
2238 | int lidac_self_max, lidac_self_min, lidac_self_ave; | ||
2239 | int raw_cap_mutual_max, raw_cap_mutual_min, raw_cap_mutual_ave; | ||
2240 | int raw_cap_self_max, raw_cap_self_min, raw_cap_self_ave; | ||
2241 | int mutual_diffdata_max, mutual_diffdata_min, mutual_diffdata_ave; | ||
2242 | int self_diffdata_max, self_diffdata_min, self_diffdata_ave; | ||
2243 | int mutual_baseline_max, mutual_baseline_min, mutual_baseline_ave; | ||
2244 | int self_baseline_max, self_baseline_min, self_baseline_ave; | ||
2245 | int error, resume_error; | ||
2246 | int size; | ||
2247 | |||
2248 | if (cyapa->state != CYAPA_STATE_GEN5_APP) | ||
2249 | return -EBUSY; | ||
2250 | |||
2251 | /* 1. Suspend Scanning*/ | ||
2252 | error = cyapa_gen5_suspend_scanning(cyapa); | ||
2253 | if (error) | ||
2254 | return error; | ||
2255 | |||
2256 | /* 2. Read global and local mutual IDAC data. */ | ||
2257 | gidac_self_rx = gidac_self_tx = 0; | ||
2258 | error = cyapa_gen5_read_mutual_idac_data(cyapa, | ||
2259 | &gidac_mutual_max, &gidac_mutual_min, | ||
2260 | &gidac_mutual_ave, &lidac_mutual_max, | ||
2261 | &lidac_mutual_min, &lidac_mutual_ave); | ||
2262 | if (error) | ||
2263 | goto resume_scanning; | ||
2264 | |||
2265 | /* 3. Read global and local self IDAC data. */ | ||
2266 | error = cyapa_gen5_read_self_idac_data(cyapa, | ||
2267 | &gidac_self_rx, &gidac_self_tx, | ||
2268 | &lidac_self_max, &lidac_self_min, | ||
2269 | &lidac_self_ave); | ||
2270 | if (error) | ||
2271 | goto resume_scanning; | ||
2272 | |||
2273 | /* 4. Execuate panel scan. It must be executed before read data. */ | ||
2274 | error = cyapa_gen5_execute_panel_scan(cyapa); | ||
2275 | if (error) | ||
2276 | goto resume_scanning; | ||
2277 | |||
2278 | /* 5. Retrieve panel scan, mutual cap raw data. */ | ||
2279 | error = cyapa_gen5_read_panel_scan_raw_data(cyapa, | ||
2280 | GEN5_CMD_RETRIEVE_PANEL_SCAN, | ||
2281 | GEN5_PANEL_SCAN_MUTUAL_RAW_DATA, | ||
2282 | cyapa->electrodes_x * cyapa->electrodes_y, | ||
2283 | &raw_cap_mutual_max, &raw_cap_mutual_min, | ||
2284 | &raw_cap_mutual_ave, | ||
2285 | NULL); | ||
2286 | if (error) | ||
2287 | goto resume_scanning; | ||
2288 | |||
2289 | /* 6. Retrieve panel scan, self cap raw data. */ | ||
2290 | error = cyapa_gen5_read_panel_scan_raw_data(cyapa, | ||
2291 | GEN5_CMD_RETRIEVE_PANEL_SCAN, | ||
2292 | GEN5_PANEL_SCAN_SELF_RAW_DATA, | ||
2293 | cyapa->electrodes_x + cyapa->electrodes_y, | ||
2294 | &raw_cap_self_max, &raw_cap_self_min, | ||
2295 | &raw_cap_self_ave, | ||
2296 | NULL); | ||
2297 | if (error) | ||
2298 | goto resume_scanning; | ||
2299 | |||
2300 | /* 7. Retrieve panel scan, mutual cap diffcount raw data. */ | ||
2301 | error = cyapa_gen5_read_panel_scan_raw_data(cyapa, | ||
2302 | GEN5_CMD_RETRIEVE_PANEL_SCAN, | ||
2303 | GEN5_PANEL_SCAN_MUTUAL_DIFFCOUNT, | ||
2304 | cyapa->electrodes_x * cyapa->electrodes_y, | ||
2305 | &mutual_diffdata_max, &mutual_diffdata_min, | ||
2306 | &mutual_diffdata_ave, | ||
2307 | NULL); | ||
2308 | if (error) | ||
2309 | goto resume_scanning; | ||
2310 | |||
2311 | /* 8. Retrieve panel scan, self cap diffcount raw data. */ | ||
2312 | error = cyapa_gen5_read_panel_scan_raw_data(cyapa, | ||
2313 | GEN5_CMD_RETRIEVE_PANEL_SCAN, | ||
2314 | GEN5_PANEL_SCAN_SELF_DIFFCOUNT, | ||
2315 | cyapa->electrodes_x + cyapa->electrodes_y, | ||
2316 | &self_diffdata_max, &self_diffdata_min, | ||
2317 | &self_diffdata_ave, | ||
2318 | NULL); | ||
2319 | if (error) | ||
2320 | goto resume_scanning; | ||
2321 | |||
2322 | /* 9. Retrieve panel scan, mutual cap baseline raw data. */ | ||
2323 | error = cyapa_gen5_read_panel_scan_raw_data(cyapa, | ||
2324 | GEN5_CMD_RETRIEVE_PANEL_SCAN, | ||
2325 | GEN5_PANEL_SCAN_MUTUAL_BASELINE, | ||
2326 | cyapa->electrodes_x * cyapa->electrodes_y, | ||
2327 | &mutual_baseline_max, &mutual_baseline_min, | ||
2328 | &mutual_baseline_ave, | ||
2329 | NULL); | ||
2330 | if (error) | ||
2331 | goto resume_scanning; | ||
2332 | |||
2333 | /* 10. Retrieve panel scan, self cap baseline raw data. */ | ||
2334 | error = cyapa_gen5_read_panel_scan_raw_data(cyapa, | ||
2335 | GEN5_CMD_RETRIEVE_PANEL_SCAN, | ||
2336 | GEN5_PANEL_SCAN_SELF_BASELINE, | ||
2337 | cyapa->electrodes_x + cyapa->electrodes_y, | ||
2338 | &self_baseline_max, &self_baseline_min, | ||
2339 | &self_baseline_ave, | ||
2340 | NULL); | ||
2341 | if (error) | ||
2342 | goto resume_scanning; | ||
2343 | |||
2344 | resume_scanning: | ||
2345 | /* 11. Resume Scanning*/ | ||
2346 | resume_error = cyapa_gen5_resume_scanning(cyapa); | ||
2347 | if (resume_error || error) | ||
2348 | return resume_error ? resume_error : error; | ||
2349 | |||
2350 | /* 12. Output data strings */ | ||
2351 | size = scnprintf(buf, PAGE_SIZE, "%d %d %d %d %d %d %d %d %d %d %d ", | ||
2352 | gidac_mutual_min, gidac_mutual_max, gidac_mutual_ave, | ||
2353 | lidac_mutual_min, lidac_mutual_max, lidac_mutual_ave, | ||
2354 | gidac_self_rx, gidac_self_tx, | ||
2355 | lidac_self_min, lidac_self_max, lidac_self_ave); | ||
2356 | size += scnprintf(buf + size, PAGE_SIZE - size, | ||
2357 | "%d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d\n", | ||
2358 | raw_cap_mutual_min, raw_cap_mutual_max, raw_cap_mutual_ave, | ||
2359 | raw_cap_self_min, raw_cap_self_max, raw_cap_self_ave, | ||
2360 | mutual_diffdata_min, mutual_diffdata_max, mutual_diffdata_ave, | ||
2361 | self_diffdata_min, self_diffdata_max, self_diffdata_ave, | ||
2362 | mutual_baseline_min, mutual_baseline_max, mutual_baseline_ave, | ||
2363 | self_baseline_min, self_baseline_max, self_baseline_ave); | ||
2364 | return size; | ||
2365 | } | ||
2366 | |||
2367 | static bool cyapa_gen5_sort_system_info_data(struct cyapa *cyapa, | ||
2368 | u8 *buf, int len) | ||
2369 | { | ||
2370 | /* Check the report id and command code */ | ||
2371 | if (VALID_CMD_RESP_HEADER(buf, 0x02)) | ||
2372 | return true; | ||
2373 | |||
2374 | return false; | ||
2375 | } | ||
2376 | |||
2377 | static int cyapa_gen5_bl_query_data(struct cyapa *cyapa) | ||
2378 | { | ||
2379 | u8 bl_query_data_cmd[] = { 0x04, 0x00, 0x0b, 0x00, 0x40, 0x00, | ||
2380 | 0x01, 0x3c, 0x00, 0x00, 0xb0, 0x42, 0x17 | ||
2381 | }; | ||
2382 | u8 resp_data[GEN5_BL_READ_APP_INFO_RESP_LEN]; | ||
2383 | int resp_len; | ||
2384 | int error; | ||
2385 | |||
2386 | resp_len = GEN5_BL_READ_APP_INFO_RESP_LEN; | ||
2387 | error = cyapa_i2c_pip_cmd_irq_sync(cyapa, | ||
2388 | bl_query_data_cmd, sizeof(bl_query_data_cmd), | ||
2389 | resp_data, &resp_len, | ||
2390 | 500, cyapa_gen5_sort_tsg_pip_bl_resp_data, false); | ||
2391 | if (error || resp_len != GEN5_BL_READ_APP_INFO_RESP_LEN || | ||
2392 | !GEN5_CMD_COMPLETE_SUCCESS(resp_data[5])) | ||
2393 | return error ? error : -EIO; | ||
2394 | |||
2395 | memcpy(&cyapa->product_id[0], &resp_data[8], 5); | ||
2396 | cyapa->product_id[5] = '-'; | ||
2397 | memcpy(&cyapa->product_id[6], &resp_data[13], 6); | ||
2398 | cyapa->product_id[12] = '-'; | ||
2399 | memcpy(&cyapa->product_id[13], &resp_data[19], 2); | ||
2400 | cyapa->product_id[15] = '\0'; | ||
2401 | |||
2402 | cyapa->fw_maj_ver = resp_data[22]; | ||
2403 | cyapa->fw_min_ver = resp_data[23]; | ||
2404 | |||
2405 | return 0; | ||
2406 | } | ||
2407 | |||
2408 | static int cyapa_gen5_get_query_data(struct cyapa *cyapa) | ||
2409 | { | ||
2410 | u8 get_system_information[] = { | ||
2411 | 0x04, 0x00, 0x05, 0x00, 0x2f, 0x00, 0x02 | ||
2412 | }; | ||
2413 | u8 resp_data[71]; | ||
2414 | int resp_len; | ||
2415 | u16 product_family; | ||
2416 | int error; | ||
2417 | |||
2418 | resp_len = sizeof(resp_data); | ||
2419 | error = cyapa_i2c_pip_cmd_irq_sync(cyapa, | ||
2420 | get_system_information, sizeof(get_system_information), | ||
2421 | resp_data, &resp_len, | ||
2422 | 2000, cyapa_gen5_sort_system_info_data, false); | ||
2423 | if (error || resp_len < sizeof(resp_data)) | ||
2424 | return error ? error : -EIO; | ||
2425 | |||
2426 | product_family = get_unaligned_le16(&resp_data[7]); | ||
2427 | if ((product_family & GEN5_PRODUCT_FAMILY_MASK) != | ||
2428 | GEN5_PRODUCT_FAMILY_TRACKPAD) | ||
2429 | return -EINVAL; | ||
2430 | |||
2431 | cyapa->fw_maj_ver = resp_data[15]; | ||
2432 | cyapa->fw_min_ver = resp_data[16]; | ||
2433 | |||
2434 | cyapa->electrodes_x = resp_data[52]; | ||
2435 | cyapa->electrodes_y = resp_data[53]; | ||
2436 | |||
2437 | cyapa->physical_size_x = get_unaligned_le16(&resp_data[54]) / 100; | ||
2438 | cyapa->physical_size_y = get_unaligned_le16(&resp_data[56]) / 100; | ||
2439 | |||
2440 | cyapa->max_abs_x = get_unaligned_le16(&resp_data[58]); | ||
2441 | cyapa->max_abs_y = get_unaligned_le16(&resp_data[60]); | ||
2442 | |||
2443 | cyapa->max_z = get_unaligned_le16(&resp_data[62]); | ||
2444 | |||
2445 | cyapa->x_origin = resp_data[64] & 0x01; | ||
2446 | cyapa->y_origin = resp_data[65] & 0x01; | ||
2447 | |||
2448 | cyapa->btn_capability = (resp_data[70] << 3) & CAPABILITY_BTN_MASK; | ||
2449 | |||
2450 | memcpy(&cyapa->product_id[0], &resp_data[33], 5); | ||
2451 | cyapa->product_id[5] = '-'; | ||
2452 | memcpy(&cyapa->product_id[6], &resp_data[38], 6); | ||
2453 | cyapa->product_id[12] = '-'; | ||
2454 | memcpy(&cyapa->product_id[13], &resp_data[44], 2); | ||
2455 | cyapa->product_id[15] = '\0'; | ||
2456 | |||
2457 | if (!cyapa->electrodes_x || !cyapa->electrodes_y || | ||
2458 | !cyapa->physical_size_x || !cyapa->physical_size_y || | ||
2459 | !cyapa->max_abs_x || !cyapa->max_abs_y || !cyapa->max_z) | ||
2460 | return -EINVAL; | ||
2461 | |||
2462 | return 0; | ||
2463 | } | ||
2464 | |||
2465 | static int cyapa_gen5_do_operational_check(struct cyapa *cyapa) | ||
2466 | { | ||
2467 | struct device *dev = &cyapa->client->dev; | ||
2468 | int error; | ||
2469 | |||
2470 | if (cyapa->gen != CYAPA_GEN5) | ||
2471 | return -ENODEV; | ||
2472 | |||
2473 | switch (cyapa->state) { | ||
2474 | case CYAPA_STATE_GEN5_BL: | ||
2475 | error = cyapa_gen5_bl_exit(cyapa); | ||
2476 | if (error) { | ||
2477 | /* Rry to update trackpad product information. */ | ||
2478 | cyapa_gen5_bl_query_data(cyapa); | ||
2479 | goto out; | ||
2480 | } | ||
2481 | |||
2482 | cyapa->state = CYAPA_STATE_GEN5_APP; | ||
2483 | |||
2484 | case CYAPA_STATE_GEN5_APP: | ||
2485 | /* | ||
2486 | * If trackpad device in deep sleep mode, | ||
2487 | * the app command will fail. | ||
2488 | * So always try to reset trackpad device to full active when | ||
2489 | * the device state is requeried. | ||
2490 | */ | ||
2491 | error = cyapa_gen5_set_power_mode(cyapa, | ||
2492 | PWR_MODE_FULL_ACTIVE, 0); | ||
2493 | if (error) | ||
2494 | dev_warn(dev, "%s: failed to set power active mode.\n", | ||
2495 | __func__); | ||
2496 | |||
2497 | /* Get trackpad product information. */ | ||
2498 | error = cyapa_gen5_get_query_data(cyapa); | ||
2499 | if (error) | ||
2500 | goto out; | ||
2501 | /* Only support product ID starting with CYTRA */ | ||
2502 | if (memcmp(cyapa->product_id, product_id, | ||
2503 | strlen(product_id)) != 0) { | ||
2504 | dev_err(dev, "%s: unknown product ID (%s)\n", | ||
2505 | __func__, cyapa->product_id); | ||
2506 | error = -EINVAL; | ||
2507 | } | ||
2508 | break; | ||
2509 | default: | ||
2510 | error = -EINVAL; | ||
2511 | } | ||
2512 | |||
2513 | out: | ||
2514 | return error; | ||
2515 | } | ||
2516 | |||
2517 | /* | ||
2518 | * Return false, do not continue process | ||
2519 | * Return true, continue process. | ||
2520 | */ | ||
2521 | static bool cyapa_gen5_irq_cmd_handler(struct cyapa *cyapa) | ||
2522 | { | ||
2523 | struct cyapa_gen5_cmd_states *gen5_pip = &cyapa->cmd_states.gen5; | ||
2524 | int length; | ||
2525 | |||
2526 | if (atomic_read(&gen5_pip->cmd_issued)) { | ||
2527 | /* Polling command response data. */ | ||
2528 | if (gen5_pip->is_irq_mode == false) | ||
2529 | return false; | ||
2530 | |||
2531 | /* | ||
2532 | * Read out all none command response data. | ||
2533 | * these output data may caused by user put finger on | ||
2534 | * trackpad when host waiting the command response. | ||
2535 | */ | ||
2536 | cyapa_i2c_pip_read(cyapa, gen5_pip->irq_cmd_buf, | ||
2537 | GEN5_RESP_LENGTH_SIZE); | ||
2538 | length = get_unaligned_le16(gen5_pip->irq_cmd_buf); | ||
2539 | length = (length <= GEN5_RESP_LENGTH_SIZE) ? | ||
2540 | GEN5_RESP_LENGTH_SIZE : length; | ||
2541 | if (length > GEN5_RESP_LENGTH_SIZE) | ||
2542 | cyapa_i2c_pip_read(cyapa, | ||
2543 | gen5_pip->irq_cmd_buf, length); | ||
2544 | |||
2545 | if (!(gen5_pip->resp_sort_func && | ||
2546 | gen5_pip->resp_sort_func(cyapa, | ||
2547 | gen5_pip->irq_cmd_buf, length))) { | ||
2548 | /* | ||
2549 | * Cover the Gen5 V1 firmware issue. | ||
2550 | * The issue is there is no interrut will be | ||
2551 | * asserted to notityf host to read a command | ||
2552 | * data out when always has finger touch on | ||
2553 | * trackpad during the command is issued to | ||
2554 | * trackad device. | ||
2555 | * This issue has the scenario is that, | ||
2556 | * user always has his fingers touched on | ||
2557 | * trackpad device when booting/rebooting | ||
2558 | * their chrome book. | ||
2559 | */ | ||
2560 | length = 0; | ||
2561 | if (gen5_pip->resp_len) | ||
2562 | length = *gen5_pip->resp_len; | ||
2563 | cyapa_empty_pip_output_data(cyapa, | ||
2564 | gen5_pip->resp_data, | ||
2565 | &length, | ||
2566 | gen5_pip->resp_sort_func); | ||
2567 | if (gen5_pip->resp_len && length != 0) { | ||
2568 | *gen5_pip->resp_len = length; | ||
2569 | atomic_dec(&gen5_pip->cmd_issued); | ||
2570 | complete(&gen5_pip->cmd_ready); | ||
2571 | } | ||
2572 | return false; | ||
2573 | } | ||
2574 | |||
2575 | if (gen5_pip->resp_data && gen5_pip->resp_len) { | ||
2576 | *gen5_pip->resp_len = (*gen5_pip->resp_len < length) ? | ||
2577 | *gen5_pip->resp_len : length; | ||
2578 | memcpy(gen5_pip->resp_data, gen5_pip->irq_cmd_buf, | ||
2579 | *gen5_pip->resp_len); | ||
2580 | } | ||
2581 | atomic_dec(&gen5_pip->cmd_issued); | ||
2582 | complete(&gen5_pip->cmd_ready); | ||
2583 | return false; | ||
2584 | } | ||
2585 | |||
2586 | return true; | ||
2587 | } | ||
2588 | |||
2589 | static void cyapa_gen5_report_buttons(struct cyapa *cyapa, | ||
2590 | const struct cyapa_gen5_report_data *report_data) | ||
2591 | { | ||
2592 | struct input_dev *input = cyapa->input; | ||
2593 | u8 buttons = report_data->report_head[GEN5_BUTTONS_OFFSET]; | ||
2594 | |||
2595 | buttons = (buttons << CAPABILITY_BTN_SHIFT) & CAPABILITY_BTN_MASK; | ||
2596 | |||
2597 | if (cyapa->btn_capability & CAPABILITY_LEFT_BTN_MASK) { | ||
2598 | input_report_key(input, BTN_LEFT, | ||
2599 | !!(buttons & CAPABILITY_LEFT_BTN_MASK)); | ||
2600 | } | ||
2601 | if (cyapa->btn_capability & CAPABILITY_MIDDLE_BTN_MASK) { | ||
2602 | input_report_key(input, BTN_MIDDLE, | ||
2603 | !!(buttons & CAPABILITY_MIDDLE_BTN_MASK)); | ||
2604 | } | ||
2605 | if (cyapa->btn_capability & CAPABILITY_RIGHT_BTN_MASK) { | ||
2606 | input_report_key(input, BTN_RIGHT, | ||
2607 | !!(buttons & CAPABILITY_RIGHT_BTN_MASK)); | ||
2608 | } | ||
2609 | |||
2610 | input_sync(input); | ||
2611 | } | ||
2612 | |||
2613 | static void cyapa_gen5_report_slot_data(struct cyapa *cyapa, | ||
2614 | const struct cyapa_gen5_touch_record *touch) | ||
2615 | { | ||
2616 | struct input_dev *input = cyapa->input; | ||
2617 | u8 event_id = GEN5_GET_EVENT_ID(touch->touch_tip_event_id); | ||
2618 | int slot = GEN5_GET_TOUCH_ID(touch->touch_tip_event_id); | ||
2619 | int x, y; | ||
2620 | |||
2621 | if (event_id == RECORD_EVENT_LIFTOFF) | ||
2622 | return; | ||
2623 | |||
2624 | input_mt_slot(input, slot); | ||
2625 | input_mt_report_slot_state(input, MT_TOOL_FINGER, true); | ||
2626 | x = (touch->x_hi << 8) | touch->x_lo; | ||
2627 | if (cyapa->x_origin) | ||
2628 | x = cyapa->max_abs_x - x; | ||
2629 | input_report_abs(input, ABS_MT_POSITION_X, x); | ||
2630 | y = (touch->y_hi << 8) | touch->y_lo; | ||
2631 | if (cyapa->y_origin) | ||
2632 | y = cyapa->max_abs_y - y; | ||
2633 | input_report_abs(input, ABS_MT_POSITION_Y, y); | ||
2634 | input_report_abs(input, ABS_MT_PRESSURE, | ||
2635 | touch->z); | ||
2636 | input_report_abs(input, ABS_MT_TOUCH_MAJOR, | ||
2637 | touch->major_axis_len); | ||
2638 | input_report_abs(input, ABS_MT_TOUCH_MINOR, | ||
2639 | touch->minor_axis_len); | ||
2640 | |||
2641 | input_report_abs(input, ABS_MT_WIDTH_MAJOR, | ||
2642 | touch->major_tool_len); | ||
2643 | input_report_abs(input, ABS_MT_WIDTH_MINOR, | ||
2644 | touch->minor_tool_len); | ||
2645 | |||
2646 | input_report_abs(input, ABS_MT_ORIENTATION, | ||
2647 | touch->orientation); | ||
2648 | } | ||
2649 | |||
2650 | static void cyapa_gen5_report_touches(struct cyapa *cyapa, | ||
2651 | const struct cyapa_gen5_report_data *report_data) | ||
2652 | { | ||
2653 | struct input_dev *input = cyapa->input; | ||
2654 | unsigned int touch_num; | ||
2655 | int i; | ||
2656 | |||
2657 | touch_num = report_data->report_head[GEN5_NUMBER_OF_TOUCH_OFFSET] & | ||
2658 | GEN5_NUMBER_OF_TOUCH_MASK; | ||
2659 | |||
2660 | for (i = 0; i < touch_num; i++) | ||
2661 | cyapa_gen5_report_slot_data(cyapa, | ||
2662 | &report_data->touch_records[i]); | ||
2663 | |||
2664 | input_mt_sync_frame(input); | ||
2665 | input_sync(input); | ||
2666 | } | ||
2667 | |||
2668 | static int cyapa_gen5_irq_handler(struct cyapa *cyapa) | ||
2669 | { | ||
2670 | struct device *dev = &cyapa->client->dev; | ||
2671 | struct cyapa_gen5_report_data report_data; | ||
2672 | int ret; | ||
2673 | u8 report_id; | ||
2674 | unsigned int report_len; | ||
2675 | |||
2676 | if (cyapa->gen != CYAPA_GEN5 || | ||
2677 | cyapa->state != CYAPA_STATE_GEN5_APP) { | ||
2678 | dev_err(dev, "invalid device state, gen=%d, state=0x%02x\n", | ||
2679 | cyapa->gen, cyapa->state); | ||
2680 | return -EINVAL; | ||
2681 | } | ||
2682 | |||
2683 | ret = cyapa_i2c_pip_read(cyapa, (u8 *)&report_data, | ||
2684 | GEN5_RESP_LENGTH_SIZE); | ||
2685 | if (ret != GEN5_RESP_LENGTH_SIZE) { | ||
2686 | dev_err(dev, "failed to read length bytes, (%d)\n", ret); | ||
2687 | return -EINVAL; | ||
2688 | } | ||
2689 | |||
2690 | report_len = get_unaligned_le16( | ||
2691 | &report_data.report_head[GEN5_RESP_LENGTH_OFFSET]); | ||
2692 | if (report_len < GEN5_RESP_LENGTH_SIZE) { | ||
2693 | /* Invliad length or internal reset happened. */ | ||
2694 | dev_err(dev, "invalid report_len=%d. bytes: %02x %02x\n", | ||
2695 | report_len, report_data.report_head[0], | ||
2696 | report_data.report_head[1]); | ||
2697 | return -EINVAL; | ||
2698 | } | ||
2699 | |||
2700 | /* Idle, no data for report. */ | ||
2701 | if (report_len == GEN5_RESP_LENGTH_SIZE) | ||
2702 | return 0; | ||
2703 | |||
2704 | ret = cyapa_i2c_pip_read(cyapa, (u8 *)&report_data, report_len); | ||
2705 | if (ret != report_len) { | ||
2706 | dev_err(dev, "failed to read %d bytes report data, (%d)\n", | ||
2707 | report_len, ret); | ||
2708 | return -EINVAL; | ||
2709 | } | ||
2710 | |||
2711 | report_id = report_data.report_head[GEN5_RESP_REPORT_ID_OFFSET]; | ||
2712 | if (report_id == GEN5_WAKEUP_EVENT_REPORT_ID && | ||
2713 | report_len == GEN5_WAKEUP_EVENT_SIZE) { | ||
2714 | /* | ||
2715 | * Device wake event from deep sleep mode for touch. | ||
2716 | * This interrupt event is used to wake system up. | ||
2717 | */ | ||
2718 | return 0; | ||
2719 | } else if (report_id != GEN5_TOUCH_REPORT_ID && | ||
2720 | report_id != GEN5_BTN_REPORT_ID && | ||
2721 | report_id != GEN5_OLD_PUSH_BTN_REPORT_ID && | ||
2722 | report_id != GEN5_PUSH_BTN_REPORT_ID) { | ||
2723 | /* Running in BL mode or unknown response data read. */ | ||
2724 | dev_err(dev, "invalid report_id=0x%02x\n", report_id); | ||
2725 | return -EINVAL; | ||
2726 | } | ||
2727 | |||
2728 | if (report_id == GEN5_TOUCH_REPORT_ID && | ||
2729 | (report_len < GEN5_TOUCH_REPORT_HEAD_SIZE || | ||
2730 | report_len > GEN5_TOUCH_REPORT_MAX_SIZE)) { | ||
2731 | /* Invalid report data length for finger packet. */ | ||
2732 | dev_err(dev, "invalid touch packet length=%d\n", report_len); | ||
2733 | return 0; | ||
2734 | } | ||
2735 | |||
2736 | if ((report_id == GEN5_BTN_REPORT_ID || | ||
2737 | report_id == GEN5_OLD_PUSH_BTN_REPORT_ID || | ||
2738 | report_id == GEN5_PUSH_BTN_REPORT_ID) && | ||
2739 | (report_len < GEN5_BTN_REPORT_HEAD_SIZE || | ||
2740 | report_len > GEN5_BTN_REPORT_MAX_SIZE)) { | ||
2741 | /* Invalid report data length of button packet. */ | ||
2742 | dev_err(dev, "invalid button packet length=%d\n", report_len); | ||
2743 | return 0; | ||
2744 | } | ||
2745 | |||
2746 | if (report_id == GEN5_TOUCH_REPORT_ID) | ||
2747 | cyapa_gen5_report_touches(cyapa, &report_data); | ||
2748 | else | ||
2749 | cyapa_gen5_report_buttons(cyapa, &report_data); | ||
2750 | |||
2751 | return 0; | ||
2752 | } | ||
2753 | |||
2754 | static int cyapa_gen5_bl_activate(struct cyapa *cyapa) { return 0; } | ||
2755 | static int cyapa_gen5_bl_deactivate(struct cyapa *cyapa) { return 0; } | ||
2756 | |||
2757 | const struct cyapa_dev_ops cyapa_gen5_ops = { | ||
2758 | .check_fw = cyapa_gen5_check_fw, | ||
2759 | .bl_enter = cyapa_gen5_bl_enter, | ||
2760 | .bl_initiate = cyapa_gen5_bl_initiate, | ||
2761 | .update_fw = cyapa_gen5_do_fw_update, | ||
2762 | .bl_activate = cyapa_gen5_bl_activate, | ||
2763 | .bl_deactivate = cyapa_gen5_bl_deactivate, | ||
2764 | |||
2765 | .show_baseline = cyapa_gen5_show_baseline, | ||
2766 | .calibrate_store = cyapa_gen5_do_calibrate, | ||
2767 | |||
2768 | .initialize = cyapa_gen5_initialize, | ||
2769 | |||
2770 | .state_parse = cyapa_gen5_state_parse, | ||
2771 | .operational_check = cyapa_gen5_do_operational_check, | ||
2772 | |||
2773 | .irq_handler = cyapa_gen5_irq_handler, | ||
2774 | .irq_cmd_handler = cyapa_gen5_irq_cmd_handler, | ||
2775 | .sort_empty_output_data = cyapa_empty_pip_output_data, | ||
2776 | .set_power_mode = cyapa_gen5_set_power_mode, | ||
2777 | }; | ||
diff --git a/drivers/input/mouse/cypress_ps2.c b/drivers/input/mouse/cypress_ps2.c index 8af34ffe208b..9118a1861a45 100644 --- a/drivers/input/mouse/cypress_ps2.c +++ b/drivers/input/mouse/cypress_ps2.c | |||
@@ -538,7 +538,7 @@ static void cypress_process_packet(struct psmouse *psmouse, bool zero_pkt) | |||
538 | pos[i].y = contact->y; | 538 | pos[i].y = contact->y; |
539 | } | 539 | } |
540 | 540 | ||
541 | input_mt_assign_slots(input, slots, pos, n); | 541 | input_mt_assign_slots(input, slots, pos, n, 0); |
542 | 542 | ||
543 | for (i = 0; i < n; i++) { | 543 | for (i = 0; i < n; i++) { |
544 | contact = &report_data.contacts[i]; | 544 | contact = &report_data.contacts[i]; |
diff --git a/drivers/input/mouse/elan_i2c.h b/drivers/input/mouse/elan_i2c.h index 2e838626205f..e100c1b31597 100644 --- a/drivers/input/mouse/elan_i2c.h +++ b/drivers/input/mouse/elan_i2c.h | |||
@@ -4,7 +4,6 @@ | |||
4 | * Copyright (c) 2013 ELAN Microelectronics Corp. | 4 | * Copyright (c) 2013 ELAN Microelectronics Corp. |
5 | * | 5 | * |
6 | * Author: 林政維 (Duson Lin) <dusonlin@emc.com.tw> | 6 | * Author: 林政維 (Duson Lin) <dusonlin@emc.com.tw> |
7 | * Version: 1.5.5 | ||
8 | * | 7 | * |
9 | * Based on cyapa driver: | 8 | * Based on cyapa driver: |
10 | * copyright (c) 2011-2012 Cypress Semiconductor, Inc. | 9 | * copyright (c) 2011-2012 Cypress Semiconductor, Inc. |
@@ -33,8 +32,9 @@ | |||
33 | #define ETP_FW_IAP_PAGE_ERR (1 << 5) | 32 | #define ETP_FW_IAP_PAGE_ERR (1 << 5) |
34 | #define ETP_FW_IAP_INTF_ERR (1 << 4) | 33 | #define ETP_FW_IAP_INTF_ERR (1 << 4) |
35 | #define ETP_FW_PAGE_SIZE 64 | 34 | #define ETP_FW_PAGE_SIZE 64 |
36 | #define ETP_FW_PAGE_COUNT 768 | 35 | #define ETP_FW_VAILDPAGE_COUNT 768 |
37 | #define ETP_FW_SIZE (ETP_FW_PAGE_SIZE * ETP_FW_PAGE_COUNT) | 36 | #define ETP_FW_SIGNATURE_SIZE 6 |
37 | #define ETP_FW_SIGNATURE_ADDRESS 0xBFFA | ||
38 | 38 | ||
39 | struct i2c_client; | 39 | struct i2c_client; |
40 | struct completion; | 40 | struct completion; |
diff --git a/drivers/input/mouse/elan_i2c_core.c b/drivers/input/mouse/elan_i2c_core.c index 0cb2be48d537..7ce8bfe22d7e 100644 --- a/drivers/input/mouse/elan_i2c_core.c +++ b/drivers/input/mouse/elan_i2c_core.c | |||
@@ -4,7 +4,7 @@ | |||
4 | * Copyright (c) 2013 ELAN Microelectronics Corp. | 4 | * Copyright (c) 2013 ELAN Microelectronics Corp. |
5 | * | 5 | * |
6 | * Author: 林政維 (Duson Lin) <dusonlin@emc.com.tw> | 6 | * Author: 林政維 (Duson Lin) <dusonlin@emc.com.tw> |
7 | * Version: 1.5.5 | 7 | * Version: 1.5.6 |
8 | * | 8 | * |
9 | * Based on cyapa driver: | 9 | * Based on cyapa driver: |
10 | * copyright (c) 2011-2012 Cypress Semiconductor, Inc. | 10 | * copyright (c) 2011-2012 Cypress Semiconductor, Inc. |
@@ -40,7 +40,7 @@ | |||
40 | #include "elan_i2c.h" | 40 | #include "elan_i2c.h" |
41 | 41 | ||
42 | #define DRIVER_NAME "elan_i2c" | 42 | #define DRIVER_NAME "elan_i2c" |
43 | #define ELAN_DRIVER_VERSION "1.5.5" | 43 | #define ELAN_DRIVER_VERSION "1.5.6" |
44 | #define ETP_PRESSURE_OFFSET 25 | 44 | #define ETP_PRESSURE_OFFSET 25 |
45 | #define ETP_MAX_PRESSURE 255 | 45 | #define ETP_MAX_PRESSURE 255 |
46 | #define ETP_FWIDTH_REDUCE 90 | 46 | #define ETP_FWIDTH_REDUCE 90 |
@@ -312,7 +312,7 @@ static int __elan_update_firmware(struct elan_tp_data *data, | |||
312 | iap_start_addr = get_unaligned_le16(&fw->data[ETP_IAP_START_ADDR * 2]); | 312 | iap_start_addr = get_unaligned_le16(&fw->data[ETP_IAP_START_ADDR * 2]); |
313 | 313 | ||
314 | boot_page_count = (iap_start_addr * 2) / ETP_FW_PAGE_SIZE; | 314 | boot_page_count = (iap_start_addr * 2) / ETP_FW_PAGE_SIZE; |
315 | for (i = boot_page_count; i < ETP_FW_PAGE_COUNT; i++) { | 315 | for (i = boot_page_count; i < ETP_FW_VAILDPAGE_COUNT; i++) { |
316 | u16 checksum = 0; | 316 | u16 checksum = 0; |
317 | const u8 *page = &fw->data[i * ETP_FW_PAGE_SIZE]; | 317 | const u8 *page = &fw->data[i * ETP_FW_PAGE_SIZE]; |
318 | 318 | ||
@@ -434,10 +434,11 @@ static ssize_t elan_sysfs_update_fw(struct device *dev, | |||
434 | struct device_attribute *attr, | 434 | struct device_attribute *attr, |
435 | const char *buf, size_t count) | 435 | const char *buf, size_t count) |
436 | { | 436 | { |
437 | struct i2c_client *client = to_i2c_client(dev); | 437 | struct elan_tp_data *data = dev_get_drvdata(dev); |
438 | struct elan_tp_data *data = i2c_get_clientdata(client); | ||
439 | const struct firmware *fw; | 438 | const struct firmware *fw; |
440 | int error; | 439 | int error; |
440 | const u8 *fw_signature; | ||
441 | static const u8 signature[] = {0xAA, 0x55, 0xCC, 0x33, 0xFF, 0xFF}; | ||
441 | 442 | ||
442 | error = request_firmware(&fw, ETP_FW_NAME, dev); | 443 | error = request_firmware(&fw, ETP_FW_NAME, dev); |
443 | if (error) { | 444 | if (error) { |
@@ -446,10 +447,12 @@ static ssize_t elan_sysfs_update_fw(struct device *dev, | |||
446 | return error; | 447 | return error; |
447 | } | 448 | } |
448 | 449 | ||
449 | /* Firmware must be exactly PAGE_NUM * PAGE_SIZE bytes */ | 450 | /* Firmware file must match signature data */ |
450 | if (fw->size != ETP_FW_SIZE) { | 451 | fw_signature = &fw->data[ETP_FW_SIGNATURE_ADDRESS]; |
451 | dev_err(dev, "invalid firmware size = %zu, expected %d.\n", | 452 | if (memcmp(fw_signature, signature, sizeof(signature)) != 0) { |
452 | fw->size, ETP_FW_SIZE); | 453 | dev_err(dev, "signature mismatch (expected %*ph, got %*ph)\n", |
454 | (int)sizeof(signature), signature, | ||
455 | (int)sizeof(signature), fw_signature); | ||
453 | error = -EBADF; | 456 | error = -EBADF; |
454 | goto out_release_fw; | 457 | goto out_release_fw; |
455 | } | 458 | } |
diff --git a/drivers/input/mouse/elan_i2c_i2c.c b/drivers/input/mouse/elan_i2c_i2c.c index 97d4937fc244..029941f861af 100644 --- a/drivers/input/mouse/elan_i2c_i2c.c +++ b/drivers/input/mouse/elan_i2c_i2c.c | |||
@@ -4,7 +4,6 @@ | |||
4 | * Copyright (c) 2013 ELAN Microelectronics Corp. | 4 | * Copyright (c) 2013 ELAN Microelectronics Corp. |
5 | * | 5 | * |
6 | * Author: 林政維 (Duson Lin) <dusonlin@emc.com.tw> | 6 | * Author: 林政維 (Duson Lin) <dusonlin@emc.com.tw> |
7 | * Version: 1.5.5 | ||
8 | * | 7 | * |
9 | * Based on cyapa driver: | 8 | * Based on cyapa driver: |
10 | * copyright (c) 2011-2012 Cypress Semiconductor, Inc. | 9 | * copyright (c) 2011-2012 Cypress Semiconductor, Inc. |
diff --git a/drivers/input/mouse/elan_i2c_smbus.c b/drivers/input/mouse/elan_i2c_smbus.c index 359bf8583d54..06a2bcd1cda2 100644 --- a/drivers/input/mouse/elan_i2c_smbus.c +++ b/drivers/input/mouse/elan_i2c_smbus.c | |||
@@ -4,7 +4,6 @@ | |||
4 | * Copyright (c) 2013 ELAN Microelectronics Corp. | 4 | * Copyright (c) 2013 ELAN Microelectronics Corp. |
5 | * | 5 | * |
6 | * Author: 林政維 (Duson Lin) <dusonlin@emc.com.tw> | 6 | * Author: 林政維 (Duson Lin) <dusonlin@emc.com.tw> |
7 | * Version: 1.5.5 | ||
8 | * | 7 | * |
9 | * Based on cyapa driver: | 8 | * Based on cyapa driver: |
10 | * copyright (c) 2011-2012 Cypress Semiconductor, Inc. | 9 | * copyright (c) 2011-2012 Cypress Semiconductor, Inc. |
@@ -71,7 +70,7 @@ static int elan_smbus_initialize(struct i2c_client *client) | |||
71 | 70 | ||
72 | /* compare hello packet */ | 71 | /* compare hello packet */ |
73 | if (memcmp(values, check, ETP_SMBUS_HELLOPACKET_LEN)) { | 72 | if (memcmp(values, check, ETP_SMBUS_HELLOPACKET_LEN)) { |
74 | dev_err(&client->dev, "hello packet fail [%*px]\n", | 73 | dev_err(&client->dev, "hello packet fail [%*ph]\n", |
75 | ETP_SMBUS_HELLOPACKET_LEN, values); | 74 | ETP_SMBUS_HELLOPACKET_LEN, values); |
76 | return -ENXIO; | 75 | return -ENXIO; |
77 | } | 76 | } |
diff --git a/drivers/input/mouse/focaltech.c b/drivers/input/mouse/focaltech.c index f4d657ee1cc0..fca38ba63bbe 100644 --- a/drivers/input/mouse/focaltech.c +++ b/drivers/input/mouse/focaltech.c | |||
@@ -2,6 +2,7 @@ | |||
2 | * Focaltech TouchPad PS/2 mouse driver | 2 | * Focaltech TouchPad PS/2 mouse driver |
3 | * | 3 | * |
4 | * Copyright (c) 2014 Red Hat Inc. | 4 | * Copyright (c) 2014 Red Hat Inc. |
5 | * Copyright (c) 2014 Mathias Gottschlag <mgottschlag@gmail.com> | ||
5 | * | 6 | * |
6 | * This program is free software; you can redistribute it and/or modify | 7 | * This program is free software; you can redistribute it and/or modify |
7 | * it under the terms of the GNU General Public License as published by | 8 | * it under the terms of the GNU General Public License as published by |
@@ -13,15 +14,14 @@ | |||
13 | * Hans de Goede <hdegoede@redhat.com> | 14 | * Hans de Goede <hdegoede@redhat.com> |
14 | */ | 15 | */ |
15 | 16 | ||
16 | /* | ||
17 | * The Focaltech PS/2 touchpad protocol is unknown. This drivers deals with | ||
18 | * detection only, to avoid further detection attempts confusing the touchpad | ||
19 | * this way it at least works in PS/2 mouse compatibility mode. | ||
20 | */ | ||
21 | 17 | ||
22 | #include <linux/device.h> | 18 | #include <linux/device.h> |
23 | #include <linux/libps2.h> | 19 | #include <linux/libps2.h> |
20 | #include <linux/input/mt.h> | ||
21 | #include <linux/serio.h> | ||
22 | #include <linux/slab.h> | ||
24 | #include "psmouse.h" | 23 | #include "psmouse.h" |
24 | #include "focaltech.h" | ||
25 | 25 | ||
26 | static const char * const focaltech_pnp_ids[] = { | 26 | static const char * const focaltech_pnp_ids[] = { |
27 | "FLT0101", | 27 | "FLT0101", |
@@ -30,6 +30,12 @@ static const char * const focaltech_pnp_ids[] = { | |||
30 | NULL | 30 | NULL |
31 | }; | 31 | }; |
32 | 32 | ||
33 | /* | ||
34 | * Even if the kernel is built without support for Focaltech PS/2 touchpads (or | ||
35 | * when the real driver fails to recognize the device), we still have to detect | ||
36 | * them in order to avoid further detection attempts confusing the touchpad. | ||
37 | * This way it at least works in PS/2 mouse compatibility mode. | ||
38 | */ | ||
33 | int focaltech_detect(struct psmouse *psmouse, bool set_properties) | 39 | int focaltech_detect(struct psmouse *psmouse, bool set_properties) |
34 | { | 40 | { |
35 | if (!psmouse_matches_pnp_id(psmouse, focaltech_pnp_ids)) | 41 | if (!psmouse_matches_pnp_id(psmouse, focaltech_pnp_ids)) |
@@ -37,16 +43,404 @@ int focaltech_detect(struct psmouse *psmouse, bool set_properties) | |||
37 | 43 | ||
38 | if (set_properties) { | 44 | if (set_properties) { |
39 | psmouse->vendor = "FocalTech"; | 45 | psmouse->vendor = "FocalTech"; |
40 | psmouse->name = "FocalTech Touchpad in mouse emulation mode"; | 46 | psmouse->name = "FocalTech Touchpad"; |
41 | } | 47 | } |
42 | 48 | ||
43 | return 0; | 49 | return 0; |
44 | } | 50 | } |
45 | 51 | ||
46 | int focaltech_init(struct psmouse *psmouse) | 52 | static void focaltech_reset(struct psmouse *psmouse) |
47 | { | 53 | { |
48 | ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_RESET_DIS); | 54 | ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_RESET_DIS); |
49 | psmouse_reset(psmouse); | 55 | psmouse_reset(psmouse); |
56 | } | ||
57 | |||
58 | #ifdef CONFIG_MOUSE_PS2_FOCALTECH | ||
59 | |||
60 | /* | ||
61 | * Packet types - the numbers are not consecutive, so we might be missing | ||
62 | * something here. | ||
63 | */ | ||
64 | #define FOC_TOUCH 0x3 /* bitmap of active fingers */ | ||
65 | #define FOC_ABS 0x6 /* absolute position of one finger */ | ||
66 | #define FOC_REL 0x9 /* relative position of 1-2 fingers */ | ||
67 | |||
68 | #define FOC_MAX_FINGERS 5 | ||
69 | |||
70 | #define FOC_MAX_X 2431 | ||
71 | #define FOC_MAX_Y 1663 | ||
72 | |||
73 | /* | ||
74 | * Current state of a single finger on the touchpad. | ||
75 | */ | ||
76 | struct focaltech_finger_state { | ||
77 | /* The touchpad has generated a touch event for the finger */ | ||
78 | bool active; | ||
79 | |||
80 | /* | ||
81 | * The touchpad has sent position data for the finger. The | ||
82 | * flag is 0 when the finger is not active, and there is a | ||
83 | * time between the first touch event for the finger and the | ||
84 | * following absolute position packet for the finger where the | ||
85 | * touchpad has declared the finger to be valid, but we do not | ||
86 | * have any valid position yet. | ||
87 | */ | ||
88 | bool valid; | ||
89 | |||
90 | /* | ||
91 | * Absolute position (from the bottom left corner) of the | ||
92 | * finger. | ||
93 | */ | ||
94 | unsigned int x; | ||
95 | unsigned int y; | ||
96 | }; | ||
97 | |||
98 | /* | ||
99 | * Description of the current state of the touchpad hardware. | ||
100 | */ | ||
101 | struct focaltech_hw_state { | ||
102 | /* | ||
103 | * The touchpad tracks the positions of the fingers for us, | ||
104 | * the array indices correspond to the finger indices returned | ||
105 | * in the report packages. | ||
106 | */ | ||
107 | struct focaltech_finger_state fingers[FOC_MAX_FINGERS]; | ||
108 | |||
109 | /* True if the clickpad has been pressed. */ | ||
110 | bool pressed; | ||
111 | }; | ||
112 | |||
113 | struct focaltech_data { | ||
114 | unsigned int x_max, y_max; | ||
115 | struct focaltech_hw_state state; | ||
116 | }; | ||
117 | |||
118 | static void focaltech_report_state(struct psmouse *psmouse) | ||
119 | { | ||
120 | struct focaltech_data *priv = psmouse->private; | ||
121 | struct focaltech_hw_state *state = &priv->state; | ||
122 | struct input_dev *dev = psmouse->dev; | ||
123 | int i; | ||
124 | |||
125 | for (i = 0; i < FOC_MAX_FINGERS; i++) { | ||
126 | struct focaltech_finger_state *finger = &state->fingers[i]; | ||
127 | bool active = finger->active && finger->valid; | ||
128 | |||
129 | input_mt_slot(dev, i); | ||
130 | input_mt_report_slot_state(dev, MT_TOOL_FINGER, active); | ||
131 | if (active) { | ||
132 | input_report_abs(dev, ABS_MT_POSITION_X, finger->x); | ||
133 | input_report_abs(dev, ABS_MT_POSITION_Y, | ||
134 | FOC_MAX_Y - finger->y); | ||
135 | } | ||
136 | } | ||
137 | input_mt_report_pointer_emulation(dev, true); | ||
138 | |||
139 | input_report_key(psmouse->dev, BTN_LEFT, state->pressed); | ||
140 | input_sync(psmouse->dev); | ||
141 | } | ||
142 | |||
143 | static void focaltech_process_touch_packet(struct psmouse *psmouse, | ||
144 | unsigned char *packet) | ||
145 | { | ||
146 | struct focaltech_data *priv = psmouse->private; | ||
147 | struct focaltech_hw_state *state = &priv->state; | ||
148 | unsigned char fingers = packet[1]; | ||
149 | int i; | ||
150 | |||
151 | state->pressed = (packet[0] >> 4) & 1; | ||
152 | |||
153 | /* the second byte contains a bitmap of all fingers touching the pad */ | ||
154 | for (i = 0; i < FOC_MAX_FINGERS; i++) { | ||
155 | state->fingers[i].active = fingers & 0x1; | ||
156 | if (!state->fingers[i].active) { | ||
157 | /* | ||
158 | * Even when the finger becomes active again, we still | ||
159 | * will have to wait for the first valid position. | ||
160 | */ | ||
161 | state->fingers[i].valid = false; | ||
162 | } | ||
163 | fingers >>= 1; | ||
164 | } | ||
165 | } | ||
166 | |||
167 | static void focaltech_process_abs_packet(struct psmouse *psmouse, | ||
168 | unsigned char *packet) | ||
169 | { | ||
170 | struct focaltech_data *priv = psmouse->private; | ||
171 | struct focaltech_hw_state *state = &priv->state; | ||
172 | unsigned int finger; | ||
173 | |||
174 | finger = (packet[1] >> 4) - 1; | ||
175 | if (finger >= FOC_MAX_FINGERS) { | ||
176 | psmouse_err(psmouse, "Invalid finger in abs packet: %d\n", | ||
177 | finger); | ||
178 | return; | ||
179 | } | ||
180 | |||
181 | state->pressed = (packet[0] >> 4) & 1; | ||
182 | |||
183 | /* | ||
184 | * packet[5] contains some kind of tool size in the most | ||
185 | * significant nibble. 0xff is a special value (latching) that | ||
186 | * signals a large contact area. | ||
187 | */ | ||
188 | if (packet[5] == 0xff) { | ||
189 | state->fingers[finger].valid = false; | ||
190 | return; | ||
191 | } | ||
192 | |||
193 | state->fingers[finger].x = ((packet[1] & 0xf) << 8) | packet[2]; | ||
194 | state->fingers[finger].y = (packet[3] << 8) | packet[4]; | ||
195 | state->fingers[finger].valid = true; | ||
196 | } | ||
197 | |||
198 | static void focaltech_process_rel_packet(struct psmouse *psmouse, | ||
199 | unsigned char *packet) | ||
200 | { | ||
201 | struct focaltech_data *priv = psmouse->private; | ||
202 | struct focaltech_hw_state *state = &priv->state; | ||
203 | int finger1, finger2; | ||
204 | |||
205 | state->pressed = packet[0] >> 7; | ||
206 | finger1 = ((packet[0] >> 4) & 0x7) - 1; | ||
207 | if (finger1 < FOC_MAX_FINGERS) { | ||
208 | state->fingers[finger1].x += (char)packet[1]; | ||
209 | state->fingers[finger1].y += (char)packet[2]; | ||
210 | } else { | ||
211 | psmouse_err(psmouse, "First finger in rel packet invalid: %d\n", | ||
212 | finger1); | ||
213 | } | ||
214 | |||
215 | /* | ||
216 | * If there is an odd number of fingers, the last relative | ||
217 | * packet only contains one finger. In this case, the second | ||
218 | * finger index in the packet is 0 (we subtract 1 in the lines | ||
219 | * above to create array indices, so the finger will overflow | ||
220 | * and be above FOC_MAX_FINGERS). | ||
221 | */ | ||
222 | finger2 = ((packet[3] >> 4) & 0x7) - 1; | ||
223 | if (finger2 < FOC_MAX_FINGERS) { | ||
224 | state->fingers[finger2].x += (char)packet[4]; | ||
225 | state->fingers[finger2].y += (char)packet[5]; | ||
226 | } | ||
227 | } | ||
228 | |||
229 | static void focaltech_process_packet(struct psmouse *psmouse) | ||
230 | { | ||
231 | unsigned char *packet = psmouse->packet; | ||
232 | |||
233 | switch (packet[0] & 0xf) { | ||
234 | case FOC_TOUCH: | ||
235 | focaltech_process_touch_packet(psmouse, packet); | ||
236 | break; | ||
237 | |||
238 | case FOC_ABS: | ||
239 | focaltech_process_abs_packet(psmouse, packet); | ||
240 | break; | ||
241 | |||
242 | case FOC_REL: | ||
243 | focaltech_process_rel_packet(psmouse, packet); | ||
244 | break; | ||
245 | |||
246 | default: | ||
247 | psmouse_err(psmouse, "Unknown packet type: %02x\n", packet[0]); | ||
248 | break; | ||
249 | } | ||
250 | |||
251 | focaltech_report_state(psmouse); | ||
252 | } | ||
253 | |||
254 | static psmouse_ret_t focaltech_process_byte(struct psmouse *psmouse) | ||
255 | { | ||
256 | if (psmouse->pktcnt >= 6) { /* Full packet received */ | ||
257 | focaltech_process_packet(psmouse); | ||
258 | return PSMOUSE_FULL_PACKET; | ||
259 | } | ||
260 | |||
261 | /* | ||
262 | * We might want to do some validation of the data here, but | ||
263 | * we do not know the protocol well enough | ||
264 | */ | ||
265 | return PSMOUSE_GOOD_DATA; | ||
266 | } | ||
267 | |||
268 | static int focaltech_switch_protocol(struct psmouse *psmouse) | ||
269 | { | ||
270 | struct ps2dev *ps2dev = &psmouse->ps2dev; | ||
271 | unsigned char param[3]; | ||
272 | |||
273 | param[0] = 0; | ||
274 | if (ps2_command(ps2dev, param, 0x10f8)) | ||
275 | return -EIO; | ||
276 | |||
277 | if (ps2_command(ps2dev, param, 0x10f8)) | ||
278 | return -EIO; | ||
279 | |||
280 | if (ps2_command(ps2dev, param, 0x10f8)) | ||
281 | return -EIO; | ||
282 | |||
283 | param[0] = 1; | ||
284 | if (ps2_command(ps2dev, param, 0x10f8)) | ||
285 | return -EIO; | ||
286 | |||
287 | if (ps2_command(ps2dev, param, PSMOUSE_CMD_SETSCALE11)) | ||
288 | return -EIO; | ||
289 | |||
290 | if (ps2_command(ps2dev, param, PSMOUSE_CMD_ENABLE)) | ||
291 | return -EIO; | ||
292 | |||
293 | return 0; | ||
294 | } | ||
295 | |||
296 | static void focaltech_disconnect(struct psmouse *psmouse) | ||
297 | { | ||
298 | focaltech_reset(psmouse); | ||
299 | kfree(psmouse->private); | ||
300 | psmouse->private = NULL; | ||
301 | } | ||
302 | |||
303 | static int focaltech_reconnect(struct psmouse *psmouse) | ||
304 | { | ||
305 | int error; | ||
306 | |||
307 | focaltech_reset(psmouse); | ||
308 | |||
309 | error = focaltech_switch_protocol(psmouse); | ||
310 | if (error) { | ||
311 | psmouse_err(psmouse, "Unable to initialize the device\n"); | ||
312 | return error; | ||
313 | } | ||
314 | |||
315 | return 0; | ||
316 | } | ||
317 | |||
318 | static void focaltech_set_input_params(struct psmouse *psmouse) | ||
319 | { | ||
320 | struct input_dev *dev = psmouse->dev; | ||
321 | struct focaltech_data *priv = psmouse->private; | ||
322 | |||
323 | /* | ||
324 | * Undo part of setup done for us by psmouse core since touchpad | ||
325 | * is not a relative device. | ||
326 | */ | ||
327 | __clear_bit(EV_REL, dev->evbit); | ||
328 | __clear_bit(REL_X, dev->relbit); | ||
329 | __clear_bit(REL_Y, dev->relbit); | ||
330 | __clear_bit(BTN_RIGHT, dev->keybit); | ||
331 | __clear_bit(BTN_MIDDLE, dev->keybit); | ||
332 | |||
333 | /* | ||
334 | * Now set up our capabilities. | ||
335 | */ | ||
336 | __set_bit(EV_ABS, dev->evbit); | ||
337 | input_set_abs_params(dev, ABS_MT_POSITION_X, 0, priv->x_max, 0, 0); | ||
338 | input_set_abs_params(dev, ABS_MT_POSITION_Y, 0, priv->y_max, 0, 0); | ||
339 | input_mt_init_slots(dev, 5, INPUT_MT_POINTER); | ||
340 | __set_bit(INPUT_PROP_BUTTONPAD, dev->propbit); | ||
341 | } | ||
342 | |||
343 | static int focaltech_read_register(struct ps2dev *ps2dev, int reg, | ||
344 | unsigned char *param) | ||
345 | { | ||
346 | if (ps2_command(ps2dev, param, PSMOUSE_CMD_SETSCALE11)) | ||
347 | return -EIO; | ||
348 | |||
349 | param[0] = 0; | ||
350 | if (ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES)) | ||
351 | return -EIO; | ||
352 | |||
353 | if (ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES)) | ||
354 | return -EIO; | ||
355 | |||
356 | if (ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES)) | ||
357 | return -EIO; | ||
358 | |||
359 | param[0] = reg; | ||
360 | if (ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES)) | ||
361 | return -EIO; | ||
362 | |||
363 | if (ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO)) | ||
364 | return -EIO; | ||
365 | |||
366 | return 0; | ||
367 | } | ||
368 | |||
369 | static int focaltech_read_size(struct psmouse *psmouse) | ||
370 | { | ||
371 | struct ps2dev *ps2dev = &psmouse->ps2dev; | ||
372 | struct focaltech_data *priv = psmouse->private; | ||
373 | char param[3]; | ||
374 | |||
375 | if (focaltech_read_register(ps2dev, 2, param)) | ||
376 | return -EIO; | ||
377 | |||
378 | /* not sure whether this is 100% correct */ | ||
379 | priv->x_max = (unsigned char)param[1] * 128; | ||
380 | priv->y_max = (unsigned char)param[2] * 128; | ||
381 | |||
382 | return 0; | ||
383 | } | ||
384 | int focaltech_init(struct psmouse *psmouse) | ||
385 | { | ||
386 | struct focaltech_data *priv; | ||
387 | int error; | ||
388 | |||
389 | psmouse->private = priv = kzalloc(sizeof(struct focaltech_data), | ||
390 | GFP_KERNEL); | ||
391 | if (!priv) | ||
392 | return -ENOMEM; | ||
393 | |||
394 | focaltech_reset(psmouse); | ||
395 | |||
396 | error = focaltech_read_size(psmouse); | ||
397 | if (error) { | ||
398 | psmouse_err(psmouse, | ||
399 | "Unable to read the size of the touchpad\n"); | ||
400 | goto fail; | ||
401 | } | ||
402 | |||
403 | error = focaltech_switch_protocol(psmouse); | ||
404 | if (error) { | ||
405 | psmouse_err(psmouse, "Unable to initialize the device\n"); | ||
406 | goto fail; | ||
407 | } | ||
408 | |||
409 | focaltech_set_input_params(psmouse); | ||
410 | |||
411 | psmouse->protocol_handler = focaltech_process_byte; | ||
412 | psmouse->pktsize = 6; | ||
413 | psmouse->disconnect = focaltech_disconnect; | ||
414 | psmouse->reconnect = focaltech_reconnect; | ||
415 | psmouse->cleanup = focaltech_reset; | ||
416 | /* resync is not supported yet */ | ||
417 | psmouse->resync_time = 0; | ||
50 | 418 | ||
51 | return 0; | 419 | return 0; |
420 | |||
421 | fail: | ||
422 | focaltech_reset(psmouse); | ||
423 | kfree(priv); | ||
424 | return error; | ||
52 | } | 425 | } |
426 | |||
427 | bool focaltech_supported(void) | ||
428 | { | ||
429 | return true; | ||
430 | } | ||
431 | |||
432 | #else /* CONFIG_MOUSE_PS2_FOCALTECH */ | ||
433 | |||
434 | int focaltech_init(struct psmouse *psmouse) | ||
435 | { | ||
436 | focaltech_reset(psmouse); | ||
437 | |||
438 | return 0; | ||
439 | } | ||
440 | |||
441 | bool focaltech_supported(void) | ||
442 | { | ||
443 | return false; | ||
444 | } | ||
445 | |||
446 | #endif /* CONFIG_MOUSE_PS2_FOCALTECH */ | ||
diff --git a/drivers/input/mouse/focaltech.h b/drivers/input/mouse/focaltech.h index 498650c61e28..71870a9b548a 100644 --- a/drivers/input/mouse/focaltech.h +++ b/drivers/input/mouse/focaltech.h | |||
@@ -2,6 +2,7 @@ | |||
2 | * Focaltech TouchPad PS/2 mouse driver | 2 | * Focaltech TouchPad PS/2 mouse driver |
3 | * | 3 | * |
4 | * Copyright (c) 2014 Red Hat Inc. | 4 | * Copyright (c) 2014 Red Hat Inc. |
5 | * Copyright (c) 2014 Mathias Gottschlag <mgottschlag@gmail.com> | ||
5 | * | 6 | * |
6 | * This program is free software; you can redistribute it and/or modify | 7 | * This program is free software; you can redistribute it and/or modify |
7 | * it under the terms of the GNU General Public License as published by | 8 | * it under the terms of the GNU General Public License as published by |
@@ -18,5 +19,6 @@ | |||
18 | 19 | ||
19 | int focaltech_detect(struct psmouse *psmouse, bool set_properties); | 20 | int focaltech_detect(struct psmouse *psmouse, bool set_properties); |
20 | int focaltech_init(struct psmouse *psmouse); | 21 | int focaltech_init(struct psmouse *psmouse); |
22 | bool focaltech_supported(void); | ||
21 | 23 | ||
22 | #endif | 24 | #endif |
diff --git a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c index 95a3a6e2faf6..68469feda470 100644 --- a/drivers/input/mouse/psmouse-base.c +++ b/drivers/input/mouse/psmouse-base.c | |||
@@ -725,16 +725,19 @@ static int psmouse_extensions(struct psmouse *psmouse, | |||
725 | 725 | ||
726 | /* Always check for focaltech, this is safe as it uses pnp-id matching */ | 726 | /* Always check for focaltech, this is safe as it uses pnp-id matching */ |
727 | if (psmouse_do_detect(focaltech_detect, psmouse, set_properties) == 0) { | 727 | if (psmouse_do_detect(focaltech_detect, psmouse, set_properties) == 0) { |
728 | if (!set_properties || focaltech_init(psmouse) == 0) { | 728 | if (max_proto > PSMOUSE_IMEX) { |
729 | /* | 729 | if (!set_properties || focaltech_init(psmouse) == 0) { |
730 | * Not supported yet, use bare protocol. | 730 | if (focaltech_supported()) |
731 | * Note that we need to also restrict | 731 | return PSMOUSE_FOCALTECH; |
732 | * psmouse_max_proto so that psmouse_initialize() | 732 | /* |
733 | * does not try to reset rate and resolution, | 733 | * Note that we need to also restrict |
734 | * because even that upsets the device. | 734 | * psmouse_max_proto so that psmouse_initialize() |
735 | */ | 735 | * does not try to reset rate and resolution, |
736 | psmouse_max_proto = PSMOUSE_PS2; | 736 | * because even that upsets the device. |
737 | return PSMOUSE_PS2; | 737 | */ |
738 | psmouse_max_proto = PSMOUSE_PS2; | ||
739 | return PSMOUSE_PS2; | ||
740 | } | ||
738 | } | 741 | } |
739 | } | 742 | } |
740 | 743 | ||
@@ -1063,6 +1066,15 @@ static const struct psmouse_protocol psmouse_protocols[] = { | |||
1063 | .alias = "cortps", | 1066 | .alias = "cortps", |
1064 | .detect = cortron_detect, | 1067 | .detect = cortron_detect, |
1065 | }, | 1068 | }, |
1069 | #ifdef CONFIG_MOUSE_PS2_FOCALTECH | ||
1070 | { | ||
1071 | .type = PSMOUSE_FOCALTECH, | ||
1072 | .name = "FocalTechPS/2", | ||
1073 | .alias = "focaltech", | ||
1074 | .detect = focaltech_detect, | ||
1075 | .init = focaltech_init, | ||
1076 | }, | ||
1077 | #endif | ||
1066 | { | 1078 | { |
1067 | .type = PSMOUSE_AUTO, | 1079 | .type = PSMOUSE_AUTO, |
1068 | .name = "auto", | 1080 | .name = "auto", |
diff --git a/drivers/input/mouse/psmouse.h b/drivers/input/mouse/psmouse.h index f4cf664c7db3..c2ff137ecbdb 100644 --- a/drivers/input/mouse/psmouse.h +++ b/drivers/input/mouse/psmouse.h | |||
@@ -96,6 +96,7 @@ enum psmouse_type { | |||
96 | PSMOUSE_FSP, | 96 | PSMOUSE_FSP, |
97 | PSMOUSE_SYNAPTICS_RELATIVE, | 97 | PSMOUSE_SYNAPTICS_RELATIVE, |
98 | PSMOUSE_CYPRESS, | 98 | PSMOUSE_CYPRESS, |
99 | PSMOUSE_FOCALTECH, | ||
99 | PSMOUSE_AUTO /* This one should always be last */ | 100 | PSMOUSE_AUTO /* This one should always be last */ |
100 | }; | 101 | }; |
101 | 102 | ||
diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c index 23e26e0768b5..7e705ee90b86 100644 --- a/drivers/input/mouse/synaptics.c +++ b/drivers/input/mouse/synaptics.c | |||
@@ -67,6 +67,9 @@ | |||
67 | #define X_MAX_POSITIVE 8176 | 67 | #define X_MAX_POSITIVE 8176 |
68 | #define Y_MAX_POSITIVE 8176 | 68 | #define Y_MAX_POSITIVE 8176 |
69 | 69 | ||
70 | /* maximum ABS_MT_POSITION displacement (in mm) */ | ||
71 | #define DMAX 10 | ||
72 | |||
70 | /***************************************************************************** | 73 | /***************************************************************************** |
71 | * Stuff we need even when we do not want native Synaptics support | 74 | * Stuff we need even when we do not want native Synaptics support |
72 | ****************************************************************************/ | 75 | ****************************************************************************/ |
@@ -575,14 +578,6 @@ static void synaptics_pt_create(struct psmouse *psmouse) | |||
575 | * Functions to interpret the absolute mode packets | 578 | * Functions to interpret the absolute mode packets |
576 | ****************************************************************************/ | 579 | ****************************************************************************/ |
577 | 580 | ||
578 | static void synaptics_mt_state_set(struct synaptics_mt_state *state, int count, | ||
579 | int sgm, int agm) | ||
580 | { | ||
581 | state->count = count; | ||
582 | state->sgm = sgm; | ||
583 | state->agm = agm; | ||
584 | } | ||
585 | |||
586 | static void synaptics_parse_agm(const unsigned char buf[], | 581 | static void synaptics_parse_agm(const unsigned char buf[], |
587 | struct synaptics_data *priv, | 582 | struct synaptics_data *priv, |
588 | struct synaptics_hw_state *hw) | 583 | struct synaptics_hw_state *hw) |
@@ -601,16 +596,13 @@ static void synaptics_parse_agm(const unsigned char buf[], | |||
601 | break; | 596 | break; |
602 | 597 | ||
603 | case 2: | 598 | case 2: |
604 | /* AGM-CONTACT packet: (count, sgm, agm) */ | 599 | /* AGM-CONTACT packet: we are only interested in the count */ |
605 | synaptics_mt_state_set(&agm->mt_state, buf[1], buf[2], buf[4]); | 600 | priv->agm_count = buf[1]; |
606 | break; | 601 | break; |
607 | 602 | ||
608 | default: | 603 | default: |
609 | break; | 604 | break; |
610 | } | 605 | } |
611 | |||
612 | /* Record that at least one AGM has been received since last SGM */ | ||
613 | priv->agm_pending = true; | ||
614 | } | 606 | } |
615 | 607 | ||
616 | static bool is_forcepad; | 608 | static bool is_forcepad; |
@@ -804,424 +796,68 @@ static void synaptics_report_buttons(struct psmouse *psmouse, | |||
804 | input_report_key(dev, BTN_0 + i, hw->ext_buttons & (1 << i)); | 796 | input_report_key(dev, BTN_0 + i, hw->ext_buttons & (1 << i)); |
805 | } | 797 | } |
806 | 798 | ||
807 | static void synaptics_report_slot(struct input_dev *dev, int slot, | ||
808 | const struct synaptics_hw_state *hw) | ||
809 | { | ||
810 | input_mt_slot(dev, slot); | ||
811 | input_mt_report_slot_state(dev, MT_TOOL_FINGER, (hw != NULL)); | ||
812 | if (!hw) | ||
813 | return; | ||
814 | |||
815 | input_report_abs(dev, ABS_MT_POSITION_X, hw->x); | ||
816 | input_report_abs(dev, ABS_MT_POSITION_Y, synaptics_invert_y(hw->y)); | ||
817 | input_report_abs(dev, ABS_MT_PRESSURE, hw->z); | ||
818 | } | ||
819 | |||
820 | static void synaptics_report_mt_data(struct psmouse *psmouse, | 799 | static void synaptics_report_mt_data(struct psmouse *psmouse, |
821 | struct synaptics_mt_state *mt_state, | 800 | const struct synaptics_hw_state *sgm, |
822 | const struct synaptics_hw_state *sgm) | 801 | int num_fingers) |
823 | { | 802 | { |
824 | struct input_dev *dev = psmouse->dev; | 803 | struct input_dev *dev = psmouse->dev; |
825 | struct synaptics_data *priv = psmouse->private; | 804 | struct synaptics_data *priv = psmouse->private; |
826 | struct synaptics_hw_state *agm = &priv->agm; | 805 | const struct synaptics_hw_state *hw[2] = { sgm, &priv->agm }; |
827 | struct synaptics_mt_state *old = &priv->mt_state; | 806 | struct input_mt_pos pos[2]; |
807 | int slot[2], nsemi, i; | ||
828 | 808 | ||
829 | switch (mt_state->count) { | 809 | nsemi = clamp_val(num_fingers, 0, 2); |
830 | case 0: | ||
831 | synaptics_report_slot(dev, 0, NULL); | ||
832 | synaptics_report_slot(dev, 1, NULL); | ||
833 | break; | ||
834 | case 1: | ||
835 | if (mt_state->sgm == -1) { | ||
836 | synaptics_report_slot(dev, 0, NULL); | ||
837 | synaptics_report_slot(dev, 1, NULL); | ||
838 | } else if (mt_state->sgm == 0) { | ||
839 | synaptics_report_slot(dev, 0, sgm); | ||
840 | synaptics_report_slot(dev, 1, NULL); | ||
841 | } else { | ||
842 | synaptics_report_slot(dev, 0, NULL); | ||
843 | synaptics_report_slot(dev, 1, sgm); | ||
844 | } | ||
845 | break; | ||
846 | default: | ||
847 | /* | ||
848 | * If the finger slot contained in SGM is valid, and either | ||
849 | * hasn't changed, or is new, or the old SGM has now moved to | ||
850 | * AGM, then report SGM in MTB slot 0. | ||
851 | * Otherwise, empty MTB slot 0. | ||
852 | */ | ||
853 | if (mt_state->sgm != -1 && | ||
854 | (mt_state->sgm == old->sgm || | ||
855 | old->sgm == -1 || mt_state->agm == old->sgm)) | ||
856 | synaptics_report_slot(dev, 0, sgm); | ||
857 | else | ||
858 | synaptics_report_slot(dev, 0, NULL); | ||
859 | 810 | ||
860 | /* | 811 | for (i = 0; i < nsemi; i++) { |
861 | * If the finger slot contained in AGM is valid, and either | 812 | pos[i].x = hw[i]->x; |
862 | * hasn't changed, or is new, then report AGM in MTB slot 1. | 813 | pos[i].y = synaptics_invert_y(hw[i]->y); |
863 | * Otherwise, empty MTB slot 1. | ||
864 | * | ||
865 | * However, in the case where the AGM is new, make sure that | ||
866 | * that it is either the same as the old SGM, or there was no | ||
867 | * SGM. | ||
868 | * | ||
869 | * Otherwise, if the SGM was just 1, and the new AGM is 2, then | ||
870 | * the new AGM will keep the old SGM's tracking ID, which can | ||
871 | * cause apparent drumroll. This happens if in the following | ||
872 | * valid finger sequence: | ||
873 | * | ||
874 | * Action SGM AGM (MTB slot:Contact) | ||
875 | * 1. Touch contact 0 (0:0) | ||
876 | * 2. Touch contact 1 (0:0, 1:1) | ||
877 | * 3. Lift contact 0 (1:1) | ||
878 | * 4. Touch contacts 2,3 (0:2, 1:3) | ||
879 | * | ||
880 | * In step 4, contact 3, in AGM must not be given the same | ||
881 | * tracking ID as contact 1 had in step 3. To avoid this, | ||
882 | * the first agm with contact 3 is dropped and slot 1 is | ||
883 | * invalidated (tracking ID = -1). | ||
884 | */ | ||
885 | if (mt_state->agm != -1 && | ||
886 | (mt_state->agm == old->agm || | ||
887 | (old->agm == -1 && | ||
888 | (old->sgm == -1 || mt_state->agm == old->sgm)))) | ||
889 | synaptics_report_slot(dev, 1, agm); | ||
890 | else | ||
891 | synaptics_report_slot(dev, 1, NULL); | ||
892 | break; | ||
893 | } | 814 | } |
894 | 815 | ||
816 | input_mt_assign_slots(dev, slot, pos, nsemi, DMAX * priv->x_res); | ||
817 | |||
818 | for (i = 0; i < nsemi; i++) { | ||
819 | input_mt_slot(dev, slot[i]); | ||
820 | input_mt_report_slot_state(dev, MT_TOOL_FINGER, true); | ||
821 | input_report_abs(dev, ABS_MT_POSITION_X, pos[i].x); | ||
822 | input_report_abs(dev, ABS_MT_POSITION_Y, pos[i].y); | ||
823 | input_report_abs(dev, ABS_MT_PRESSURE, hw[i]->z); | ||
824 | } | ||
825 | |||
826 | input_mt_drop_unused(dev); | ||
827 | |||
895 | /* Don't use active slot count to generate BTN_TOOL events. */ | 828 | /* Don't use active slot count to generate BTN_TOOL events. */ |
896 | input_mt_report_pointer_emulation(dev, false); | 829 | input_mt_report_pointer_emulation(dev, false); |
897 | 830 | ||
898 | /* Send the number of fingers reported by touchpad itself. */ | 831 | /* Send the number of fingers reported by touchpad itself. */ |
899 | input_mt_report_finger_count(dev, mt_state->count); | 832 | input_mt_report_finger_count(dev, num_fingers); |
900 | 833 | ||
901 | synaptics_report_buttons(psmouse, sgm); | 834 | synaptics_report_buttons(psmouse, sgm); |
902 | 835 | ||
903 | input_sync(dev); | 836 | input_sync(dev); |
904 | } | 837 | } |
905 | 838 | ||
906 | /* Handle case where mt_state->count = 0 */ | ||
907 | static void synaptics_image_sensor_0f(struct synaptics_data *priv, | ||
908 | struct synaptics_mt_state *mt_state) | ||
909 | { | ||
910 | synaptics_mt_state_set(mt_state, 0, -1, -1); | ||
911 | priv->mt_state_lost = false; | ||
912 | } | ||
913 | |||
914 | /* Handle case where mt_state->count = 1 */ | ||
915 | static void synaptics_image_sensor_1f(struct synaptics_data *priv, | ||
916 | struct synaptics_mt_state *mt_state) | ||
917 | { | ||
918 | struct synaptics_hw_state *agm = &priv->agm; | ||
919 | struct synaptics_mt_state *old = &priv->mt_state; | ||
920 | |||
921 | /* | ||
922 | * If the last AGM was (0,0,0), and there is only one finger left, | ||
923 | * then we absolutely know that SGM contains slot 0, and all other | ||
924 | * fingers have been removed. | ||
925 | */ | ||
926 | if (priv->agm_pending && agm->z == 0) { | ||
927 | synaptics_mt_state_set(mt_state, 1, 0, -1); | ||
928 | priv->mt_state_lost = false; | ||
929 | return; | ||
930 | } | ||
931 | |||
932 | switch (old->count) { | ||
933 | case 0: | ||
934 | synaptics_mt_state_set(mt_state, 1, 0, -1); | ||
935 | break; | ||
936 | case 1: | ||
937 | /* | ||
938 | * If mt_state_lost, then the previous transition was 3->1, | ||
939 | * and SGM now contains either slot 0 or 1, but we don't know | ||
940 | * which. So, we just assume that the SGM now contains slot 1. | ||
941 | * | ||
942 | * If pending AGM and either: | ||
943 | * (a) the previous SGM slot contains slot 0, or | ||
944 | * (b) there was no SGM slot | ||
945 | * then, the SGM now contains slot 1 | ||
946 | * | ||
947 | * Case (a) happens with very rapid "drum roll" gestures, where | ||
948 | * slot 0 finger is lifted and a new slot 1 finger touches | ||
949 | * within one reporting interval. | ||
950 | * | ||
951 | * Case (b) happens if initially two or more fingers tap | ||
952 | * briefly, and all but one lift before the end of the first | ||
953 | * reporting interval. | ||
954 | * | ||
955 | * (In both these cases, slot 0 will becomes empty, so SGM | ||
956 | * contains slot 1 with the new finger) | ||
957 | * | ||
958 | * Else, if there was no previous SGM, it now contains slot 0. | ||
959 | * | ||
960 | * Otherwise, SGM still contains the same slot. | ||
961 | */ | ||
962 | if (priv->mt_state_lost || | ||
963 | (priv->agm_pending && old->sgm <= 0)) | ||
964 | synaptics_mt_state_set(mt_state, 1, 1, -1); | ||
965 | else if (old->sgm == -1) | ||
966 | synaptics_mt_state_set(mt_state, 1, 0, -1); | ||
967 | break; | ||
968 | case 2: | ||
969 | /* | ||
970 | * If mt_state_lost, we don't know which finger SGM contains. | ||
971 | * | ||
972 | * So, report 1 finger, but with both slots empty. | ||
973 | * We will use slot 1 on subsequent 1->1 | ||
974 | */ | ||
975 | if (priv->mt_state_lost) { | ||
976 | synaptics_mt_state_set(mt_state, 1, -1, -1); | ||
977 | break; | ||
978 | } | ||
979 | /* | ||
980 | * Since the last AGM was NOT (0,0,0), it was the finger in | ||
981 | * slot 0 that has been removed. | ||
982 | * So, SGM now contains previous AGM's slot, and AGM is now | ||
983 | * empty. | ||
984 | */ | ||
985 | synaptics_mt_state_set(mt_state, 1, old->agm, -1); | ||
986 | break; | ||
987 | case 3: | ||
988 | /* | ||
989 | * Since last AGM was not (0,0,0), we don't know which finger | ||
990 | * is left. | ||
991 | * | ||
992 | * So, report 1 finger, but with both slots empty. | ||
993 | * We will use slot 1 on subsequent 1->1 | ||
994 | */ | ||
995 | synaptics_mt_state_set(mt_state, 1, -1, -1); | ||
996 | priv->mt_state_lost = true; | ||
997 | break; | ||
998 | case 4: | ||
999 | case 5: | ||
1000 | /* mt_state was updated by AGM-CONTACT packet */ | ||
1001 | break; | ||
1002 | } | ||
1003 | } | ||
1004 | |||
1005 | /* Handle case where mt_state->count = 2 */ | ||
1006 | static void synaptics_image_sensor_2f(struct synaptics_data *priv, | ||
1007 | struct synaptics_mt_state *mt_state) | ||
1008 | { | ||
1009 | struct synaptics_mt_state *old = &priv->mt_state; | ||
1010 | |||
1011 | switch (old->count) { | ||
1012 | case 0: | ||
1013 | synaptics_mt_state_set(mt_state, 2, 0, 1); | ||
1014 | break; | ||
1015 | case 1: | ||
1016 | /* | ||
1017 | * If previous SGM contained slot 1 or higher, SGM now contains | ||
1018 | * slot 0 (the newly touching finger) and AGM contains SGM's | ||
1019 | * previous slot. | ||
1020 | * | ||
1021 | * Otherwise, SGM still contains slot 0 and AGM now contains | ||
1022 | * slot 1. | ||
1023 | */ | ||
1024 | if (old->sgm >= 1) | ||
1025 | synaptics_mt_state_set(mt_state, 2, 0, old->sgm); | ||
1026 | else | ||
1027 | synaptics_mt_state_set(mt_state, 2, 0, 1); | ||
1028 | break; | ||
1029 | case 2: | ||
1030 | /* | ||
1031 | * If mt_state_lost, SGM now contains either finger 1 or 2, but | ||
1032 | * we don't know which. | ||
1033 | * So, we just assume that the SGM contains slot 0 and AGM 1. | ||
1034 | */ | ||
1035 | if (priv->mt_state_lost) | ||
1036 | synaptics_mt_state_set(mt_state, 2, 0, 1); | ||
1037 | /* | ||
1038 | * Otherwise, use the same mt_state, since it either hasn't | ||
1039 | * changed, or was updated by a recently received AGM-CONTACT | ||
1040 | * packet. | ||
1041 | */ | ||
1042 | break; | ||
1043 | case 3: | ||
1044 | /* | ||
1045 | * 3->2 transitions have two unsolvable problems: | ||
1046 | * 1) no indication is given which finger was removed | ||
1047 | * 2) no way to tell if agm packet was for finger 3 | ||
1048 | * before 3->2, or finger 2 after 3->2. | ||
1049 | * | ||
1050 | * So, report 2 fingers, but empty all slots. | ||
1051 | * We will guess slots [0,1] on subsequent 2->2. | ||
1052 | */ | ||
1053 | synaptics_mt_state_set(mt_state, 2, -1, -1); | ||
1054 | priv->mt_state_lost = true; | ||
1055 | break; | ||
1056 | case 4: | ||
1057 | case 5: | ||
1058 | /* mt_state was updated by AGM-CONTACT packet */ | ||
1059 | break; | ||
1060 | } | ||
1061 | } | ||
1062 | |||
1063 | /* Handle case where mt_state->count = 3 */ | ||
1064 | static void synaptics_image_sensor_3f(struct synaptics_data *priv, | ||
1065 | struct synaptics_mt_state *mt_state) | ||
1066 | { | ||
1067 | struct synaptics_mt_state *old = &priv->mt_state; | ||
1068 | |||
1069 | switch (old->count) { | ||
1070 | case 0: | ||
1071 | synaptics_mt_state_set(mt_state, 3, 0, 2); | ||
1072 | break; | ||
1073 | case 1: | ||
1074 | /* | ||
1075 | * If previous SGM contained slot 2 or higher, SGM now contains | ||
1076 | * slot 0 (one of the newly touching fingers) and AGM contains | ||
1077 | * SGM's previous slot. | ||
1078 | * | ||
1079 | * Otherwise, SGM now contains slot 0 and AGM contains slot 2. | ||
1080 | */ | ||
1081 | if (old->sgm >= 2) | ||
1082 | synaptics_mt_state_set(mt_state, 3, 0, old->sgm); | ||
1083 | else | ||
1084 | synaptics_mt_state_set(mt_state, 3, 0, 2); | ||
1085 | break; | ||
1086 | case 2: | ||
1087 | /* | ||
1088 | * If the AGM previously contained slot 3 or higher, then the | ||
1089 | * newly touching finger is in the lowest available slot. | ||
1090 | * | ||
1091 | * If SGM was previously 1 or higher, then the new SGM is | ||
1092 | * now slot 0 (with a new finger), otherwise, the new finger | ||
1093 | * is now in a hidden slot between 0 and AGM's slot. | ||
1094 | * | ||
1095 | * In all such cases, the SGM now contains slot 0, and the AGM | ||
1096 | * continues to contain the same slot as before. | ||
1097 | */ | ||
1098 | if (old->agm >= 3) { | ||
1099 | synaptics_mt_state_set(mt_state, 3, 0, old->agm); | ||
1100 | break; | ||
1101 | } | ||
1102 | |||
1103 | /* | ||
1104 | * After some 3->1 and all 3->2 transitions, we lose track | ||
1105 | * of which slot is reported by SGM and AGM. | ||
1106 | * | ||
1107 | * For 2->3 in this state, report 3 fingers, but empty all | ||
1108 | * slots, and we will guess (0,2) on a subsequent 0->3. | ||
1109 | * | ||
1110 | * To userspace, the resulting transition will look like: | ||
1111 | * 2:[0,1] -> 3:[-1,-1] -> 3:[0,2] | ||
1112 | */ | ||
1113 | if (priv->mt_state_lost) { | ||
1114 | synaptics_mt_state_set(mt_state, 3, -1, -1); | ||
1115 | break; | ||
1116 | } | ||
1117 | |||
1118 | /* | ||
1119 | * If the (SGM,AGM) really previously contained slots (0, 1), | ||
1120 | * then we cannot know what slot was just reported by the AGM, | ||
1121 | * because the 2->3 transition can occur either before or after | ||
1122 | * the AGM packet. Thus, this most recent AGM could contain | ||
1123 | * either the same old slot 1 or the new slot 2. | ||
1124 | * Subsequent AGMs will be reporting slot 2. | ||
1125 | * | ||
1126 | * To userspace, the resulting transition will look like: | ||
1127 | * 2:[0,1] -> 3:[0,-1] -> 3:[0,2] | ||
1128 | */ | ||
1129 | synaptics_mt_state_set(mt_state, 3, 0, -1); | ||
1130 | break; | ||
1131 | case 3: | ||
1132 | /* | ||
1133 | * If, for whatever reason, the previous agm was invalid, | ||
1134 | * Assume SGM now contains slot 0, AGM now contains slot 2. | ||
1135 | */ | ||
1136 | if (old->agm <= 2) | ||
1137 | synaptics_mt_state_set(mt_state, 3, 0, 2); | ||
1138 | /* | ||
1139 | * mt_state either hasn't changed, or was updated by a recently | ||
1140 | * received AGM-CONTACT packet. | ||
1141 | */ | ||
1142 | break; | ||
1143 | |||
1144 | case 4: | ||
1145 | case 5: | ||
1146 | /* mt_state was updated by AGM-CONTACT packet */ | ||
1147 | break; | ||
1148 | } | ||
1149 | } | ||
1150 | |||
1151 | /* Handle case where mt_state->count = 4, or = 5 */ | ||
1152 | static void synaptics_image_sensor_45f(struct synaptics_data *priv, | ||
1153 | struct synaptics_mt_state *mt_state) | ||
1154 | { | ||
1155 | /* mt_state was updated correctly by AGM-CONTACT packet */ | ||
1156 | priv->mt_state_lost = false; | ||
1157 | } | ||
1158 | |||
1159 | static void synaptics_image_sensor_process(struct psmouse *psmouse, | 839 | static void synaptics_image_sensor_process(struct psmouse *psmouse, |
1160 | struct synaptics_hw_state *sgm) | 840 | struct synaptics_hw_state *sgm) |
1161 | { | 841 | { |
1162 | struct synaptics_data *priv = psmouse->private; | 842 | struct synaptics_data *priv = psmouse->private; |
1163 | struct synaptics_hw_state *agm = &priv->agm; | 843 | int num_fingers; |
1164 | struct synaptics_mt_state mt_state; | ||
1165 | |||
1166 | /* Initialize using current mt_state (as updated by last agm) */ | ||
1167 | mt_state = agm->mt_state; | ||
1168 | 844 | ||
1169 | /* | 845 | /* |
1170 | * Update mt_state using the new finger count and current mt_state. | 846 | * Update mt_state using the new finger count and current mt_state. |
1171 | */ | 847 | */ |
1172 | if (sgm->z == 0) | 848 | if (sgm->z == 0) |
1173 | synaptics_image_sensor_0f(priv, &mt_state); | 849 | num_fingers = 0; |
1174 | else if (sgm->w >= 4) | 850 | else if (sgm->w >= 4) |
1175 | synaptics_image_sensor_1f(priv, &mt_state); | 851 | num_fingers = 1; |
1176 | else if (sgm->w == 0) | 852 | else if (sgm->w == 0) |
1177 | synaptics_image_sensor_2f(priv, &mt_state); | 853 | num_fingers = 2; |
1178 | else if (sgm->w == 1 && mt_state.count <= 3) | 854 | else if (sgm->w == 1) |
1179 | synaptics_image_sensor_3f(priv, &mt_state); | 855 | num_fingers = priv->agm_count ? priv->agm_count : 3; |
1180 | else | 856 | else |
1181 | synaptics_image_sensor_45f(priv, &mt_state); | 857 | num_fingers = 4; |
1182 | 858 | ||
1183 | /* Send resulting input events to user space */ | 859 | /* Send resulting input events to user space */ |
1184 | synaptics_report_mt_data(psmouse, &mt_state, sgm); | 860 | synaptics_report_mt_data(psmouse, sgm, num_fingers); |
1185 | |||
1186 | /* Store updated mt_state */ | ||
1187 | priv->mt_state = agm->mt_state = mt_state; | ||
1188 | priv->agm_pending = false; | ||
1189 | } | ||
1190 | |||
1191 | static void synaptics_profile_sensor_process(struct psmouse *psmouse, | ||
1192 | struct synaptics_hw_state *sgm, | ||
1193 | int num_fingers) | ||
1194 | { | ||
1195 | struct input_dev *dev = psmouse->dev; | ||
1196 | struct synaptics_data *priv = psmouse->private; | ||
1197 | struct synaptics_hw_state *hw[2] = { sgm, &priv->agm }; | ||
1198 | struct input_mt_pos pos[2]; | ||
1199 | int slot[2], nsemi, i; | ||
1200 | |||
1201 | nsemi = clamp_val(num_fingers, 0, 2); | ||
1202 | |||
1203 | for (i = 0; i < nsemi; i++) { | ||
1204 | pos[i].x = hw[i]->x; | ||
1205 | pos[i].y = synaptics_invert_y(hw[i]->y); | ||
1206 | } | ||
1207 | |||
1208 | input_mt_assign_slots(dev, slot, pos, nsemi); | ||
1209 | |||
1210 | for (i = 0; i < nsemi; i++) { | ||
1211 | input_mt_slot(dev, slot[i]); | ||
1212 | input_mt_report_slot_state(dev, MT_TOOL_FINGER, true); | ||
1213 | input_report_abs(dev, ABS_MT_POSITION_X, pos[i].x); | ||
1214 | input_report_abs(dev, ABS_MT_POSITION_Y, pos[i].y); | ||
1215 | input_report_abs(dev, ABS_MT_PRESSURE, hw[i]->z); | ||
1216 | } | ||
1217 | |||
1218 | input_mt_drop_unused(dev); | ||
1219 | input_mt_report_pointer_emulation(dev, false); | ||
1220 | input_mt_report_finger_count(dev, num_fingers); | ||
1221 | |||
1222 | synaptics_report_buttons(psmouse, sgm); | ||
1223 | |||
1224 | input_sync(dev); | ||
1225 | } | 861 | } |
1226 | 862 | ||
1227 | /* | 863 | /* |
@@ -1288,7 +924,7 @@ static void synaptics_process_packet(struct psmouse *psmouse) | |||
1288 | } | 924 | } |
1289 | 925 | ||
1290 | if (cr48_profile_sensor) { | 926 | if (cr48_profile_sensor) { |
1291 | synaptics_profile_sensor_process(psmouse, &hw, num_fingers); | 927 | synaptics_report_mt_data(psmouse, &hw, num_fingers); |
1292 | return; | 928 | return; |
1293 | } | 929 | } |
1294 | 930 | ||
@@ -1445,7 +1081,7 @@ static void set_input_params(struct psmouse *psmouse, | |||
1445 | ABS_MT_POSITION_Y); | 1081 | ABS_MT_POSITION_Y); |
1446 | /* Image sensors can report per-contact pressure */ | 1082 | /* Image sensors can report per-contact pressure */ |
1447 | input_set_abs_params(dev, ABS_MT_PRESSURE, 0, 255, 0, 0); | 1083 | input_set_abs_params(dev, ABS_MT_PRESSURE, 0, 255, 0, 0); |
1448 | input_mt_init_slots(dev, 2, INPUT_MT_POINTER); | 1084 | input_mt_init_slots(dev, 2, INPUT_MT_POINTER | INPUT_MT_TRACK); |
1449 | 1085 | ||
1450 | /* Image sensors can signal 4 and 5 finger clicks */ | 1086 | /* Image sensors can signal 4 and 5 finger clicks */ |
1451 | __set_bit(BTN_TOOL_QUADTAP, dev->keybit); | 1087 | __set_bit(BTN_TOOL_QUADTAP, dev->keybit); |
diff --git a/drivers/input/mouse/synaptics.h b/drivers/input/mouse/synaptics.h index 1bd01f21783b..6faf9bb7c117 100644 --- a/drivers/input/mouse/synaptics.h +++ b/drivers/input/mouse/synaptics.h | |||
@@ -119,16 +119,6 @@ | |||
119 | #define SYN_REDUCED_FILTER_FUZZ 8 | 119 | #define SYN_REDUCED_FILTER_FUZZ 8 |
120 | 120 | ||
121 | /* | 121 | /* |
122 | * A structure to describe which internal touchpad finger slots are being | ||
123 | * reported in raw packets. | ||
124 | */ | ||
125 | struct synaptics_mt_state { | ||
126 | int count; /* num fingers being tracked */ | ||
127 | int sgm; /* which slot is reported by sgm pkt */ | ||
128 | int agm; /* which slot is reported by agm pkt*/ | ||
129 | }; | ||
130 | |||
131 | /* | ||
132 | * A structure to describe the state of the touchpad hardware (buttons and pad) | 122 | * A structure to describe the state of the touchpad hardware (buttons and pad) |
133 | */ | 123 | */ |
134 | struct synaptics_hw_state { | 124 | struct synaptics_hw_state { |
@@ -143,9 +133,6 @@ struct synaptics_hw_state { | |||
143 | unsigned int down:1; | 133 | unsigned int down:1; |
144 | unsigned char ext_buttons; | 134 | unsigned char ext_buttons; |
145 | signed char scroll; | 135 | signed char scroll; |
146 | |||
147 | /* As reported in last AGM-CONTACT packets */ | ||
148 | struct synaptics_mt_state mt_state; | ||
149 | }; | 136 | }; |
150 | 137 | ||
151 | struct synaptics_data { | 138 | struct synaptics_data { |
@@ -170,15 +157,12 @@ struct synaptics_data { | |||
170 | 157 | ||
171 | struct serio *pt_port; /* Pass-through serio port */ | 158 | struct serio *pt_port; /* Pass-through serio port */ |
172 | 159 | ||
173 | struct synaptics_mt_state mt_state; /* Current mt finger state */ | ||
174 | bool mt_state_lost; /* mt_state may be incorrect */ | ||
175 | |||
176 | /* | 160 | /* |
177 | * Last received Advanced Gesture Mode (AGM) packet. An AGM packet | 161 | * Last received Advanced Gesture Mode (AGM) packet. An AGM packet |
178 | * contains position data for a second contact, at half resolution. | 162 | * contains position data for a second contact, at half resolution. |
179 | */ | 163 | */ |
180 | struct synaptics_hw_state agm; | 164 | struct synaptics_hw_state agm; |
181 | bool agm_pending; /* new AGM packet received */ | 165 | unsigned int agm_count; /* finger count reported by agm */ |
182 | 166 | ||
183 | /* ForcePad handling */ | 167 | /* ForcePad handling */ |
184 | unsigned long press_start; | 168 | unsigned long press_start; |
diff --git a/drivers/input/serio/Kconfig b/drivers/input/serio/Kconfig index bc2d47431bdc..77833d7a004b 100644 --- a/drivers/input/serio/Kconfig +++ b/drivers/input/serio/Kconfig | |||
@@ -281,4 +281,14 @@ config HYPERV_KEYBOARD | |||
281 | To compile this driver as a module, choose M here: the module will | 281 | To compile this driver as a module, choose M here: the module will |
282 | be called hyperv_keyboard. | 282 | be called hyperv_keyboard. |
283 | 283 | ||
284 | config SERIO_SUN4I_PS2 | ||
285 | tristate "Allwinner A10 PS/2 controller support" | ||
286 | depends on ARCH_SUNXI || COMPILE_TEST | ||
287 | help | ||
288 | This selects support for the PS/2 Host Controller on | ||
289 | Allwinner A10. | ||
290 | |||
291 | To compile this driver as a module, choose M here: the | ||
292 | module will be called sun4i-ps2. | ||
293 | |||
284 | endif | 294 | endif |
diff --git a/drivers/input/serio/Makefile b/drivers/input/serio/Makefile index 815d874fe724..c600089b7a34 100644 --- a/drivers/input/serio/Makefile +++ b/drivers/input/serio/Makefile | |||
@@ -29,3 +29,4 @@ obj-$(CONFIG_SERIO_ARC_PS2) += arc_ps2.o | |||
29 | obj-$(CONFIG_SERIO_APBPS2) += apbps2.o | 29 | obj-$(CONFIG_SERIO_APBPS2) += apbps2.o |
30 | obj-$(CONFIG_SERIO_OLPC_APSP) += olpc_apsp.o | 30 | obj-$(CONFIG_SERIO_OLPC_APSP) += olpc_apsp.o |
31 | obj-$(CONFIG_HYPERV_KEYBOARD) += hyperv-keyboard.o | 31 | obj-$(CONFIG_HYPERV_KEYBOARD) += hyperv-keyboard.o |
32 | obj-$(CONFIG_SERIO_SUN4I_PS2) += sun4i-ps2.o | ||
diff --git a/drivers/input/serio/gscps2.c b/drivers/input/serio/gscps2.c index 8d9ba0c3827c..94ab494a6ade 100644 --- a/drivers/input/serio/gscps2.c +++ b/drivers/input/serio/gscps2.c | |||
@@ -40,7 +40,6 @@ | |||
40 | MODULE_AUTHOR("Laurent Canet <canetl@esiee.fr>, Thibaut Varene <varenet@parisc-linux.org>, Helge Deller <deller@gmx.de>"); | 40 | MODULE_AUTHOR("Laurent Canet <canetl@esiee.fr>, Thibaut Varene <varenet@parisc-linux.org>, Helge Deller <deller@gmx.de>"); |
41 | MODULE_DESCRIPTION("HP GSC PS2 port driver"); | 41 | MODULE_DESCRIPTION("HP GSC PS2 port driver"); |
42 | MODULE_LICENSE("GPL"); | 42 | MODULE_LICENSE("GPL"); |
43 | MODULE_DEVICE_TABLE(parisc, gscps2_device_tbl); | ||
44 | 43 | ||
45 | #define PFX "gscps2.c: " | 44 | #define PFX "gscps2.c: " |
46 | 45 | ||
@@ -439,6 +438,7 @@ static struct parisc_device_id gscps2_device_tbl[] = { | |||
439 | #endif | 438 | #endif |
440 | { 0, } /* 0 terminated list */ | 439 | { 0, } /* 0 terminated list */ |
441 | }; | 440 | }; |
441 | MODULE_DEVICE_TABLE(parisc, gscps2_device_tbl); | ||
442 | 442 | ||
443 | static struct parisc_driver parisc_ps2_driver = { | 443 | static struct parisc_driver parisc_ps2_driver = { |
444 | .name = "gsc_ps2", | 444 | .name = "gsc_ps2", |
diff --git a/drivers/input/serio/sun4i-ps2.c b/drivers/input/serio/sun4i-ps2.c new file mode 100644 index 000000000000..04b96fe39339 --- /dev/null +++ b/drivers/input/serio/sun4i-ps2.c | |||
@@ -0,0 +1,340 @@ | |||
1 | /* | ||
2 | * Driver for Allwinner A10 PS2 host controller | ||
3 | * | ||
4 | * Author: Vishnu Patekar <vishnupatekar0510@gmail.com> | ||
5 | * Aaron.maoye <leafy.myeh@newbietech.com> | ||
6 | */ | ||
7 | |||
8 | #include <linux/module.h> | ||
9 | #include <linux/serio.h> | ||
10 | #include <linux/interrupt.h> | ||
11 | #include <linux/errno.h> | ||
12 | #include <linux/slab.h> | ||
13 | #include <linux/io.h> | ||
14 | #include <linux/clk.h> | ||
15 | #include <linux/mod_devicetable.h> | ||
16 | #include <linux/platform_device.h> | ||
17 | |||
18 | #define DRIVER_NAME "sun4i-ps2" | ||
19 | |||
20 | /* register offset definitions */ | ||
21 | #define PS2_REG_GCTL 0x00 /* PS2 Module Global Control Reg */ | ||
22 | #define PS2_REG_DATA 0x04 /* PS2 Module Data Reg */ | ||
23 | #define PS2_REG_LCTL 0x08 /* PS2 Module Line Control Reg */ | ||
24 | #define PS2_REG_LSTS 0x0C /* PS2 Module Line Status Reg */ | ||
25 | #define PS2_REG_FCTL 0x10 /* PS2 Module FIFO Control Reg */ | ||
26 | #define PS2_REG_FSTS 0x14 /* PS2 Module FIFO Status Reg */ | ||
27 | #define PS2_REG_CLKDR 0x18 /* PS2 Module Clock Divider Reg*/ | ||
28 | |||
29 | /* PS2 GLOBAL CONTROL REGISTER PS2_GCTL */ | ||
30 | #define PS2_GCTL_INTFLAG BIT(4) | ||
31 | #define PS2_GCTL_INTEN BIT(3) | ||
32 | #define PS2_GCTL_RESET BIT(2) | ||
33 | #define PS2_GCTL_MASTER BIT(1) | ||
34 | #define PS2_GCTL_BUSEN BIT(0) | ||
35 | |||
36 | /* PS2 LINE CONTROL REGISTER */ | ||
37 | #define PS2_LCTL_NOACK BIT(18) | ||
38 | #define PS2_LCTL_TXDTOEN BIT(8) | ||
39 | #define PS2_LCTL_STOPERREN BIT(3) | ||
40 | #define PS2_LCTL_ACKERREN BIT(2) | ||
41 | #define PS2_LCTL_PARERREN BIT(1) | ||
42 | #define PS2_LCTL_RXDTOEN BIT(0) | ||
43 | |||
44 | /* PS2 LINE STATUS REGISTER */ | ||
45 | #define PS2_LSTS_TXTDO BIT(8) | ||
46 | #define PS2_LSTS_STOPERR BIT(3) | ||
47 | #define PS2_LSTS_ACKERR BIT(2) | ||
48 | #define PS2_LSTS_PARERR BIT(1) | ||
49 | #define PS2_LSTS_RXTDO BIT(0) | ||
50 | |||
51 | #define PS2_LINE_ERROR_BIT \ | ||
52 | (PS2_LSTS_TXTDO | PS2_LSTS_STOPERR | PS2_LSTS_ACKERR | \ | ||
53 | PS2_LSTS_PARERR | PS2_LSTS_RXTDO) | ||
54 | |||
55 | /* PS2 FIFO CONTROL REGISTER */ | ||
56 | #define PS2_FCTL_TXRST BIT(17) | ||
57 | #define PS2_FCTL_RXRST BIT(16) | ||
58 | #define PS2_FCTL_TXUFIEN BIT(10) | ||
59 | #define PS2_FCTL_TXOFIEN BIT(9) | ||
60 | #define PS2_FCTL_TXRDYIEN BIT(8) | ||
61 | #define PS2_FCTL_RXUFIEN BIT(2) | ||
62 | #define PS2_FCTL_RXOFIEN BIT(1) | ||
63 | #define PS2_FCTL_RXRDYIEN BIT(0) | ||
64 | |||
65 | /* PS2 FIFO STATUS REGISTER */ | ||
66 | #define PS2_FSTS_TXUF BIT(10) | ||
67 | #define PS2_FSTS_TXOF BIT(9) | ||
68 | #define PS2_FSTS_TXRDY BIT(8) | ||
69 | #define PS2_FSTS_RXUF BIT(2) | ||
70 | #define PS2_FSTS_RXOF BIT(1) | ||
71 | #define PS2_FSTS_RXRDY BIT(0) | ||
72 | |||
73 | #define PS2_FIFO_ERROR_BIT \ | ||
74 | (PS2_FSTS_TXUF | PS2_FSTS_TXOF | PS2_FSTS_RXUF | PS2_FSTS_RXOF) | ||
75 | |||
76 | #define PS2_SAMPLE_CLK 1000000 | ||
77 | #define PS2_SCLK 125000 | ||
78 | |||
79 | struct sun4i_ps2data { | ||
80 | struct serio *serio; | ||
81 | struct device *dev; | ||
82 | |||
83 | /* IO mapping base */ | ||
84 | void __iomem *reg_base; | ||
85 | |||
86 | /* clock management */ | ||
87 | struct clk *clk; | ||
88 | |||
89 | /* irq */ | ||
90 | spinlock_t lock; | ||
91 | int irq; | ||
92 | }; | ||
93 | |||
94 | static irqreturn_t sun4i_ps2_interrupt(int irq, void *dev_id) | ||
95 | { | ||
96 | struct sun4i_ps2data *drvdata = dev_id; | ||
97 | u32 intr_status; | ||
98 | u32 fifo_status; | ||
99 | unsigned char byte; | ||
100 | unsigned int rxflags = 0; | ||
101 | u32 rval; | ||
102 | |||
103 | spin_lock(&drvdata->lock); | ||
104 | |||
105 | /* Get the PS/2 interrupts and clear them */ | ||
106 | intr_status = readl(drvdata->reg_base + PS2_REG_LSTS); | ||
107 | fifo_status = readl(drvdata->reg_base + PS2_REG_FSTS); | ||
108 | |||
109 | /* Check line status register */ | ||
110 | if (intr_status & PS2_LINE_ERROR_BIT) { | ||
111 | rxflags = (intr_status & PS2_LINE_ERROR_BIT) ? SERIO_FRAME : 0; | ||
112 | rxflags |= (intr_status & PS2_LSTS_PARERR) ? SERIO_PARITY : 0; | ||
113 | rxflags |= (intr_status & PS2_LSTS_PARERR) ? SERIO_TIMEOUT : 0; | ||
114 | |||
115 | rval = PS2_LSTS_TXTDO | PS2_LSTS_STOPERR | PS2_LSTS_ACKERR | | ||
116 | PS2_LSTS_PARERR | PS2_LSTS_RXTDO; | ||
117 | writel(rval, drvdata->reg_base + PS2_REG_LSTS); | ||
118 | } | ||
119 | |||
120 | /* Check FIFO status register */ | ||
121 | if (fifo_status & PS2_FIFO_ERROR_BIT) { | ||
122 | rval = PS2_FSTS_TXUF | PS2_FSTS_TXOF | PS2_FSTS_TXRDY | | ||
123 | PS2_FSTS_RXUF | PS2_FSTS_RXOF | PS2_FSTS_RXRDY; | ||
124 | writel(rval, drvdata->reg_base + PS2_REG_FSTS); | ||
125 | } | ||
126 | |||
127 | rval = (fifo_status >> 16) & 0x3; | ||
128 | while (rval--) { | ||
129 | byte = readl(drvdata->reg_base + PS2_REG_DATA) & 0xff; | ||
130 | serio_interrupt(drvdata->serio, byte, rxflags); | ||
131 | } | ||
132 | |||
133 | writel(intr_status, drvdata->reg_base + PS2_REG_LSTS); | ||
134 | writel(fifo_status, drvdata->reg_base + PS2_REG_FSTS); | ||
135 | |||
136 | spin_unlock(&drvdata->lock); | ||
137 | |||
138 | return IRQ_HANDLED; | ||
139 | } | ||
140 | |||
141 | static int sun4i_ps2_open(struct serio *serio) | ||
142 | { | ||
143 | struct sun4i_ps2data *drvdata = serio->port_data; | ||
144 | u32 src_clk = 0; | ||
145 | u32 clk_scdf; | ||
146 | u32 clk_pcdf; | ||
147 | u32 rval; | ||
148 | unsigned long flags; | ||
149 | |||
150 | /* Set line control and enable interrupt */ | ||
151 | rval = PS2_LCTL_STOPERREN | PS2_LCTL_ACKERREN | ||
152 | | PS2_LCTL_PARERREN | PS2_LCTL_RXDTOEN; | ||
153 | writel(rval, drvdata->reg_base + PS2_REG_LCTL); | ||
154 | |||
155 | /* Reset FIFO */ | ||
156 | rval = PS2_FCTL_TXRST | PS2_FCTL_RXRST | PS2_FCTL_TXUFIEN | ||
157 | | PS2_FCTL_TXOFIEN | PS2_FCTL_RXUFIEN | ||
158 | | PS2_FCTL_RXOFIEN | PS2_FCTL_RXRDYIEN; | ||
159 | |||
160 | writel(rval, drvdata->reg_base + PS2_REG_FCTL); | ||
161 | |||
162 | src_clk = clk_get_rate(drvdata->clk); | ||
163 | /* Set clock divider register */ | ||
164 | clk_scdf = src_clk / PS2_SAMPLE_CLK - 1; | ||
165 | clk_pcdf = PS2_SAMPLE_CLK / PS2_SCLK - 1; | ||
166 | rval = (clk_scdf << 8) | clk_pcdf; | ||
167 | writel(rval, drvdata->reg_base + PS2_REG_CLKDR); | ||
168 | |||
169 | /* Set global control register */ | ||
170 | rval = PS2_GCTL_RESET | PS2_GCTL_INTEN | PS2_GCTL_MASTER | ||
171 | | PS2_GCTL_BUSEN; | ||
172 | |||
173 | spin_lock_irqsave(&drvdata->lock, flags); | ||
174 | writel(rval, drvdata->reg_base + PS2_REG_GCTL); | ||
175 | spin_unlock_irqrestore(&drvdata->lock, flags); | ||
176 | |||
177 | return 0; | ||
178 | } | ||
179 | |||
180 | static void sun4i_ps2_close(struct serio *serio) | ||
181 | { | ||
182 | struct sun4i_ps2data *drvdata = serio->port_data; | ||
183 | u32 rval; | ||
184 | |||
185 | /* Shut off the interrupt */ | ||
186 | rval = readl(drvdata->reg_base + PS2_REG_GCTL); | ||
187 | writel(rval & ~(PS2_GCTL_INTEN), drvdata->reg_base + PS2_REG_GCTL); | ||
188 | |||
189 | synchronize_irq(drvdata->irq); | ||
190 | } | ||
191 | |||
192 | static int sun4i_ps2_write(struct serio *serio, unsigned char val) | ||
193 | { | ||
194 | unsigned long expire = jiffies + msecs_to_jiffies(10000); | ||
195 | struct sun4i_ps2data *drvdata = serio->port_data; | ||
196 | |||
197 | do { | ||
198 | if (readl(drvdata->reg_base + PS2_REG_FSTS) & PS2_FSTS_TXRDY) { | ||
199 | writel(val, drvdata->reg_base + PS2_REG_DATA); | ||
200 | return 0; | ||
201 | } | ||
202 | } while (time_before(jiffies, expire)); | ||
203 | |||
204 | return SERIO_TIMEOUT; | ||
205 | } | ||
206 | |||
207 | static int sun4i_ps2_probe(struct platform_device *pdev) | ||
208 | { | ||
209 | struct resource *res; /* IO mem resources */ | ||
210 | struct sun4i_ps2data *drvdata; | ||
211 | struct serio *serio; | ||
212 | struct device *dev = &pdev->dev; | ||
213 | unsigned int irq; | ||
214 | int error; | ||
215 | |||
216 | drvdata = kzalloc(sizeof(struct sun4i_ps2data), GFP_KERNEL); | ||
217 | serio = kzalloc(sizeof(struct serio), GFP_KERNEL); | ||
218 | if (!drvdata || !serio) { | ||
219 | error = -ENOMEM; | ||
220 | goto err_free_mem; | ||
221 | } | ||
222 | |||
223 | spin_lock_init(&drvdata->lock); | ||
224 | |||
225 | /* IO */ | ||
226 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
227 | if (!res) { | ||
228 | dev_err(dev, "failed to locate registers\n"); | ||
229 | error = -ENXIO; | ||
230 | goto err_free_mem; | ||
231 | } | ||
232 | |||
233 | drvdata->reg_base = ioremap(res->start, resource_size(res)); | ||
234 | if (!drvdata->reg_base) { | ||
235 | dev_err(dev, "failed to map registers\n"); | ||
236 | error = -ENOMEM; | ||
237 | goto err_free_mem; | ||
238 | } | ||
239 | |||
240 | drvdata->clk = clk_get(dev, NULL); | ||
241 | if (IS_ERR(drvdata->clk)) { | ||
242 | error = PTR_ERR(drvdata->clk); | ||
243 | dev_err(dev, "couldn't get clock %d\n", error); | ||
244 | goto err_ioremap; | ||
245 | } | ||
246 | |||
247 | error = clk_prepare_enable(drvdata->clk); | ||
248 | if (error) { | ||
249 | dev_err(dev, "failed to enable clock %d\n", error); | ||
250 | goto err_clk; | ||
251 | } | ||
252 | |||
253 | serio->id.type = SERIO_8042; | ||
254 | serio->write = sun4i_ps2_write; | ||
255 | serio->open = sun4i_ps2_open; | ||
256 | serio->close = sun4i_ps2_close; | ||
257 | serio->port_data = drvdata; | ||
258 | serio->dev.parent = dev; | ||
259 | strlcpy(serio->name, dev_name(dev), sizeof(serio->name)); | ||
260 | strlcpy(serio->phys, dev_name(dev), sizeof(serio->phys)); | ||
261 | |||
262 | /* shutoff interrupt */ | ||
263 | writel(0, drvdata->reg_base + PS2_REG_GCTL); | ||
264 | |||
265 | /* Get IRQ for the device */ | ||
266 | irq = platform_get_irq(pdev, 0); | ||
267 | if (!irq) { | ||
268 | dev_err(dev, "no IRQ found\n"); | ||
269 | error = -ENXIO; | ||
270 | goto err_disable_clk; | ||
271 | } | ||
272 | |||
273 | drvdata->irq = irq; | ||
274 | drvdata->serio = serio; | ||
275 | drvdata->dev = dev; | ||
276 | |||
277 | error = request_irq(drvdata->irq, sun4i_ps2_interrupt, 0, | ||
278 | DRIVER_NAME, drvdata); | ||
279 | if (error) { | ||
280 | dev_err(drvdata->dev, "failed to allocate interrupt %d: %d\n", | ||
281 | drvdata->irq, error); | ||
282 | goto err_disable_clk; | ||
283 | } | ||
284 | |||
285 | serio_register_port(serio); | ||
286 | platform_set_drvdata(pdev, drvdata); | ||
287 | |||
288 | return 0; /* success */ | ||
289 | |||
290 | err_disable_clk: | ||
291 | clk_disable_unprepare(drvdata->clk); | ||
292 | err_clk: | ||
293 | clk_put(drvdata->clk); | ||
294 | err_ioremap: | ||
295 | iounmap(drvdata->reg_base); | ||
296 | err_free_mem: | ||
297 | kfree(serio); | ||
298 | kfree(drvdata); | ||
299 | return error; | ||
300 | } | ||
301 | |||
302 | static int sun4i_ps2_remove(struct platform_device *pdev) | ||
303 | { | ||
304 | struct sun4i_ps2data *drvdata = platform_get_drvdata(pdev); | ||
305 | |||
306 | serio_unregister_port(drvdata->serio); | ||
307 | |||
308 | free_irq(drvdata->irq, drvdata); | ||
309 | |||
310 | clk_disable_unprepare(drvdata->clk); | ||
311 | clk_put(drvdata->clk); | ||
312 | |||
313 | iounmap(drvdata->reg_base); | ||
314 | |||
315 | kfree(drvdata); | ||
316 | |||
317 | return 0; | ||
318 | } | ||
319 | |||
320 | static const struct of_device_id sun4i_ps2_match[] = { | ||
321 | { .compatible = "allwinner,sun4i-a10-ps2", }, | ||
322 | { }, | ||
323 | }; | ||
324 | |||
325 | MODULE_DEVICE_TABLE(of, sun4i_ps2_match); | ||
326 | |||
327 | static struct platform_driver sun4i_ps2_driver = { | ||
328 | .probe = sun4i_ps2_probe, | ||
329 | .remove = sun4i_ps2_remove, | ||
330 | .driver = { | ||
331 | .name = DRIVER_NAME, | ||
332 | .of_match_table = sun4i_ps2_match, | ||
333 | }, | ||
334 | }; | ||
335 | module_platform_driver(sun4i_ps2_driver); | ||
336 | |||
337 | MODULE_AUTHOR("Vishnu Patekar <vishnupatekar0510@gmail.com>"); | ||
338 | MODULE_AUTHOR("Aaron.maoye <leafy.myeh@newbietech.com>"); | ||
339 | MODULE_DESCRIPTION("Allwinner A10/Sun4i PS/2 driver"); | ||
340 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/input/tablet/gtco.c b/drivers/input/tablet/gtco.c index 858045694e9d..3a7f3a4a4396 100644 --- a/drivers/input/tablet/gtco.c +++ b/drivers/input/tablet/gtco.c | |||
@@ -59,7 +59,7 @@ Scott Hill shill@gtcocalcomp.com | |||
59 | #include <asm/uaccess.h> | 59 | #include <asm/uaccess.h> |
60 | #include <asm/unaligned.h> | 60 | #include <asm/unaligned.h> |
61 | #include <asm/byteorder.h> | 61 | #include <asm/byteorder.h> |
62 | 62 | #include <linux/bitops.h> | |
63 | 63 | ||
64 | #include <linux/usb/input.h> | 64 | #include <linux/usb/input.h> |
65 | 65 | ||
@@ -614,7 +614,6 @@ static void gtco_urb_callback(struct urb *urbinfo) | |||
614 | struct input_dev *inputdev; | 614 | struct input_dev *inputdev; |
615 | int rc; | 615 | int rc; |
616 | u32 val = 0; | 616 | u32 val = 0; |
617 | s8 valsigned = 0; | ||
618 | char le_buffer[2]; | 617 | char le_buffer[2]; |
619 | 618 | ||
620 | inputdev = device->inputdevice; | 619 | inputdev = device->inputdevice; |
@@ -665,20 +664,11 @@ static void gtco_urb_callback(struct urb *urbinfo) | |||
665 | /* Fall thru */ | 664 | /* Fall thru */ |
666 | case 4: | 665 | case 4: |
667 | /* Tilt */ | 666 | /* Tilt */ |
667 | input_report_abs(inputdev, ABS_TILT_X, | ||
668 | sign_extend32(device->buffer[6], 6)); | ||
668 | 669 | ||
669 | /* Sign extend these 7 bit numbers. */ | 670 | input_report_abs(inputdev, ABS_TILT_Y, |
670 | if (device->buffer[6] & 0x40) | 671 | sign_extend32(device->buffer[7], 6)); |
671 | device->buffer[6] |= 0x80; | ||
672 | |||
673 | if (device->buffer[7] & 0x40) | ||
674 | device->buffer[7] |= 0x80; | ||
675 | |||
676 | |||
677 | valsigned = (device->buffer[6]); | ||
678 | input_report_abs(inputdev, ABS_TILT_X, (s32)valsigned); | ||
679 | |||
680 | valsigned = (device->buffer[7]); | ||
681 | input_report_abs(inputdev, ABS_TILT_Y, (s32)valsigned); | ||
682 | 672 | ||
683 | /* Fall thru */ | 673 | /* Fall thru */ |
684 | case 2: | 674 | case 2: |
diff --git a/drivers/input/touchscreen/elants_i2c.c b/drivers/input/touchscreen/elants_i2c.c index a510f7ef9b66..926c58e540c0 100644 --- a/drivers/input/touchscreen/elants_i2c.c +++ b/drivers/input/touchscreen/elants_i2c.c | |||
@@ -33,10 +33,8 @@ | |||
33 | #include <linux/delay.h> | 33 | #include <linux/delay.h> |
34 | #include <linux/uaccess.h> | 34 | #include <linux/uaccess.h> |
35 | #include <linux/buffer_head.h> | 35 | #include <linux/buffer_head.h> |
36 | #include <linux/version.h> | ||
37 | #include <linux/slab.h> | 36 | #include <linux/slab.h> |
38 | #include <linux/firmware.h> | 37 | #include <linux/firmware.h> |
39 | #include <linux/version.h> | ||
40 | #include <linux/input/mt.h> | 38 | #include <linux/input/mt.h> |
41 | #include <linux/acpi.h> | 39 | #include <linux/acpi.h> |
42 | #include <linux/of.h> | 40 | #include <linux/of.h> |
diff --git a/drivers/input/touchscreen/pixcir_i2c_ts.c b/drivers/input/touchscreen/pixcir_i2c_ts.c index 4fb5537fdd42..2c2107147319 100644 --- a/drivers/input/touchscreen/pixcir_i2c_ts.c +++ b/drivers/input/touchscreen/pixcir_i2c_ts.c | |||
@@ -126,7 +126,7 @@ static void pixcir_ts_report(struct pixcir_i2c_ts_data *ts, | |||
126 | pos[i].y = touch->y; | 126 | pos[i].y = touch->y; |
127 | } | 127 | } |
128 | 128 | ||
129 | input_mt_assign_slots(ts->input, slots, pos, n); | 129 | input_mt_assign_slots(ts->input, slots, pos, n, 0); |
130 | } | 130 | } |
131 | 131 | ||
132 | for (i = 0; i < n; i++) { | 132 | for (i = 0; i < n; i++) { |
diff --git a/drivers/input/touchscreen/sun4i-ts.c b/drivers/input/touchscreen/sun4i-ts.c index 28a06749ae42..b93a28b955fd 100644 --- a/drivers/input/touchscreen/sun4i-ts.c +++ b/drivers/input/touchscreen/sun4i-ts.c | |||
@@ -34,6 +34,7 @@ | |||
34 | 34 | ||
35 | #include <linux/err.h> | 35 | #include <linux/err.h> |
36 | #include <linux/hwmon.h> | 36 | #include <linux/hwmon.h> |
37 | #include <linux/thermal.h> | ||
37 | #include <linux/init.h> | 38 | #include <linux/init.h> |
38 | #include <linux/input.h> | 39 | #include <linux/input.h> |
39 | #include <linux/interrupt.h> | 40 | #include <linux/interrupt.h> |
@@ -71,6 +72,9 @@ | |||
71 | #define TP_ADC_SELECT(x) ((x) << 3) | 72 | #define TP_ADC_SELECT(x) ((x) << 3) |
72 | #define ADC_CHAN_SELECT(x) ((x) << 0) /* 3 bits */ | 73 | #define ADC_CHAN_SELECT(x) ((x) << 0) /* 3 bits */ |
73 | 74 | ||
75 | /* on sun6i, bits 3~6 are left shifted by 1 to 4~7 */ | ||
76 | #define SUN6I_TP_MODE_EN(x) ((x) << 5) | ||
77 | |||
74 | /* TP_CTRL2 bits */ | 78 | /* TP_CTRL2 bits */ |
75 | #define TP_SENSITIVE_ADJUST(x) ((x) << 28) /* 4 bits */ | 79 | #define TP_SENSITIVE_ADJUST(x) ((x) << 28) /* 4 bits */ |
76 | #define TP_MODE_SELECT(x) ((x) << 26) /* 2 bits */ | 80 | #define TP_MODE_SELECT(x) ((x) << 26) /* 2 bits */ |
@@ -107,10 +111,13 @@ | |||
107 | struct sun4i_ts_data { | 111 | struct sun4i_ts_data { |
108 | struct device *dev; | 112 | struct device *dev; |
109 | struct input_dev *input; | 113 | struct input_dev *input; |
114 | struct thermal_zone_device *tz; | ||
110 | void __iomem *base; | 115 | void __iomem *base; |
111 | unsigned int irq; | 116 | unsigned int irq; |
112 | bool ignore_fifo_data; | 117 | bool ignore_fifo_data; |
113 | int temp_data; | 118 | int temp_data; |
119 | int temp_offset; | ||
120 | int temp_step; | ||
114 | }; | 121 | }; |
115 | 122 | ||
116 | static void sun4i_ts_irq_handle_input(struct sun4i_ts_data *ts, u32 reg_val) | 123 | static void sun4i_ts_irq_handle_input(struct sun4i_ts_data *ts, u32 reg_val) |
@@ -180,16 +187,38 @@ static void sun4i_ts_close(struct input_dev *dev) | |||
180 | writel(TEMP_IRQ_EN(1), ts->base + TP_INT_FIFOC); | 187 | writel(TEMP_IRQ_EN(1), ts->base + TP_INT_FIFOC); |
181 | } | 188 | } |
182 | 189 | ||
190 | static int sun4i_get_temp(const struct sun4i_ts_data *ts, long *temp) | ||
191 | { | ||
192 | /* No temp_data until the first irq */ | ||
193 | if (ts->temp_data == -1) | ||
194 | return -EAGAIN; | ||
195 | |||
196 | *temp = (ts->temp_data - ts->temp_offset) * ts->temp_step; | ||
197 | |||
198 | return 0; | ||
199 | } | ||
200 | |||
201 | static int sun4i_get_tz_temp(void *data, long *temp) | ||
202 | { | ||
203 | return sun4i_get_temp(data, temp); | ||
204 | } | ||
205 | |||
206 | static struct thermal_zone_of_device_ops sun4i_ts_tz_ops = { | ||
207 | .get_temp = sun4i_get_tz_temp, | ||
208 | }; | ||
209 | |||
183 | static ssize_t show_temp(struct device *dev, struct device_attribute *devattr, | 210 | static ssize_t show_temp(struct device *dev, struct device_attribute *devattr, |
184 | char *buf) | 211 | char *buf) |
185 | { | 212 | { |
186 | struct sun4i_ts_data *ts = dev_get_drvdata(dev); | 213 | struct sun4i_ts_data *ts = dev_get_drvdata(dev); |
214 | long temp; | ||
215 | int error; | ||
187 | 216 | ||
188 | /* No temp_data until the first irq */ | 217 | error = sun4i_get_temp(ts, &temp); |
189 | if (ts->temp_data == -1) | 218 | if (error) |
190 | return -EAGAIN; | 219 | return error; |
191 | 220 | ||
192 | return sprintf(buf, "%d\n", (ts->temp_data - 1447) * 100); | 221 | return sprintf(buf, "%ld\n", temp); |
193 | } | 222 | } |
194 | 223 | ||
195 | static ssize_t show_temp_label(struct device *dev, | 224 | static ssize_t show_temp_label(struct device *dev, |
@@ -215,6 +244,7 @@ static int sun4i_ts_probe(struct platform_device *pdev) | |||
215 | struct device_node *np = dev->of_node; | 244 | struct device_node *np = dev->of_node; |
216 | struct device *hwmon; | 245 | struct device *hwmon; |
217 | int error; | 246 | int error; |
247 | u32 reg; | ||
218 | bool ts_attached; | 248 | bool ts_attached; |
219 | 249 | ||
220 | ts = devm_kzalloc(dev, sizeof(struct sun4i_ts_data), GFP_KERNEL); | 250 | ts = devm_kzalloc(dev, sizeof(struct sun4i_ts_data), GFP_KERNEL); |
@@ -224,6 +254,25 @@ static int sun4i_ts_probe(struct platform_device *pdev) | |||
224 | ts->dev = dev; | 254 | ts->dev = dev; |
225 | ts->ignore_fifo_data = true; | 255 | ts->ignore_fifo_data = true; |
226 | ts->temp_data = -1; | 256 | ts->temp_data = -1; |
257 | if (of_device_is_compatible(np, "allwinner,sun6i-a31-ts")) { | ||
258 | /* Allwinner SDK has temperature = -271 + (value / 6) (C) */ | ||
259 | ts->temp_offset = 1626; | ||
260 | ts->temp_step = 167; | ||
261 | } else { | ||
262 | /* | ||
263 | * The user manuals do not contain the formula for calculating | ||
264 | * the temperature. The formula used here is from the AXP209, | ||
265 | * which is designed by X-Powers, an affiliate of Allwinner: | ||
266 | * | ||
267 | * temperature = -144.7 + (value * 0.1) | ||
268 | * | ||
269 | * Allwinner does not have any documentation whatsoever for | ||
270 | * this hardware. Moreover, it is claimed that the sensor | ||
271 | * is inaccurate and cannot work properly. | ||
272 | */ | ||
273 | ts->temp_offset = 1447; | ||
274 | ts->temp_step = 100; | ||
275 | } | ||
227 | 276 | ||
228 | ts_attached = of_property_read_bool(np, "allwinner,ts-attached"); | 277 | ts_attached = of_property_read_bool(np, "allwinner,ts-attached"); |
229 | if (ts_attached) { | 278 | if (ts_attached) { |
@@ -280,20 +329,34 @@ static int sun4i_ts_probe(struct platform_device *pdev) | |||
280 | * Set stylus up debounce to aprox 10 ms, enable debounce, and | 329 | * Set stylus up debounce to aprox 10 ms, enable debounce, and |
281 | * finally enable tp mode. | 330 | * finally enable tp mode. |
282 | */ | 331 | */ |
283 | writel(STYLUS_UP_DEBOUN(5) | STYLUS_UP_DEBOUN_EN(1) | TP_MODE_EN(1), | 332 | reg = STYLUS_UP_DEBOUN(5) | STYLUS_UP_DEBOUN_EN(1); |
284 | ts->base + TP_CTRL1); | 333 | if (of_device_is_compatible(np, "allwinner,sun4i-a10-ts")) |
334 | reg |= TP_MODE_EN(1); | ||
335 | else | ||
336 | reg |= SUN6I_TP_MODE_EN(1); | ||
337 | writel(reg, ts->base + TP_CTRL1); | ||
285 | 338 | ||
339 | /* | ||
340 | * The thermal core does not register hwmon devices for DT-based | ||
341 | * thermal zone sensors, such as this one. | ||
342 | */ | ||
286 | hwmon = devm_hwmon_device_register_with_groups(ts->dev, "sun4i_ts", | 343 | hwmon = devm_hwmon_device_register_with_groups(ts->dev, "sun4i_ts", |
287 | ts, sun4i_ts_groups); | 344 | ts, sun4i_ts_groups); |
288 | if (IS_ERR(hwmon)) | 345 | if (IS_ERR(hwmon)) |
289 | return PTR_ERR(hwmon); | 346 | return PTR_ERR(hwmon); |
290 | 347 | ||
348 | ts->tz = thermal_zone_of_sensor_register(ts->dev, 0, ts, | ||
349 | &sun4i_ts_tz_ops); | ||
350 | if (IS_ERR(ts->tz)) | ||
351 | ts->tz = NULL; | ||
352 | |||
291 | writel(TEMP_IRQ_EN(1), ts->base + TP_INT_FIFOC); | 353 | writel(TEMP_IRQ_EN(1), ts->base + TP_INT_FIFOC); |
292 | 354 | ||
293 | if (ts_attached) { | 355 | if (ts_attached) { |
294 | error = input_register_device(ts->input); | 356 | error = input_register_device(ts->input); |
295 | if (error) { | 357 | if (error) { |
296 | writel(0, ts->base + TP_INT_FIFOC); | 358 | writel(0, ts->base + TP_INT_FIFOC); |
359 | thermal_zone_of_sensor_unregister(ts->dev, ts->tz); | ||
297 | return error; | 360 | return error; |
298 | } | 361 | } |
299 | } | 362 | } |
@@ -310,6 +373,8 @@ static int sun4i_ts_remove(struct platform_device *pdev) | |||
310 | if (ts->input) | 373 | if (ts->input) |
311 | input_unregister_device(ts->input); | 374 | input_unregister_device(ts->input); |
312 | 375 | ||
376 | thermal_zone_of_sensor_unregister(ts->dev, ts->tz); | ||
377 | |||
313 | /* Deactivate all IRQs */ | 378 | /* Deactivate all IRQs */ |
314 | writel(0, ts->base + TP_INT_FIFOC); | 379 | writel(0, ts->base + TP_INT_FIFOC); |
315 | 380 | ||
@@ -318,6 +383,7 @@ static int sun4i_ts_remove(struct platform_device *pdev) | |||
318 | 383 | ||
319 | static const struct of_device_id sun4i_ts_of_match[] = { | 384 | static const struct of_device_id sun4i_ts_of_match[] = { |
320 | { .compatible = "allwinner,sun4i-a10-ts", }, | 385 | { .compatible = "allwinner,sun4i-a10-ts", }, |
386 | { .compatible = "allwinner,sun6i-a31-ts", }, | ||
321 | { /* sentinel */ } | 387 | { /* sentinel */ } |
322 | }; | 388 | }; |
323 | MODULE_DEVICE_TABLE(of, sun4i_ts_of_match); | 389 | MODULE_DEVICE_TABLE(of, sun4i_ts_of_match); |
diff --git a/drivers/input/touchscreen/ti_am335x_tsc.c b/drivers/input/touchscreen/ti_am335x_tsc.c index 004f1346a957..191a1b87895f 100644 --- a/drivers/input/touchscreen/ti_am335x_tsc.c +++ b/drivers/input/touchscreen/ti_am335x_tsc.c | |||
@@ -26,6 +26,7 @@ | |||
26 | #include <linux/delay.h> | 26 | #include <linux/delay.h> |
27 | #include <linux/of.h> | 27 | #include <linux/of.h> |
28 | #include <linux/of_device.h> | 28 | #include <linux/of_device.h> |
29 | #include <linux/sort.h> | ||
29 | 30 | ||
30 | #include <linux/mfd/ti_am335x_tscadc.h> | 31 | #include <linux/mfd/ti_am335x_tscadc.h> |
31 | 32 | ||
@@ -52,6 +53,7 @@ struct titsc { | |||
52 | u32 bit_xp, bit_xn, bit_yp, bit_yn; | 53 | u32 bit_xp, bit_xn, bit_yp, bit_yn; |
53 | u32 inp_xp, inp_xn, inp_yp, inp_yn; | 54 | u32 inp_xp, inp_xn, inp_yp, inp_yn; |
54 | u32 step_mask; | 55 | u32 step_mask; |
56 | u32 charge_delay; | ||
55 | }; | 57 | }; |
56 | 58 | ||
57 | static unsigned int titsc_readl(struct titsc *ts, unsigned int reg) | 59 | static unsigned int titsc_readl(struct titsc *ts, unsigned int reg) |
@@ -121,7 +123,7 @@ static void titsc_step_config(struct titsc *ts_dev) | |||
121 | { | 123 | { |
122 | unsigned int config; | 124 | unsigned int config; |
123 | int i; | 125 | int i; |
124 | int end_step; | 126 | int end_step, first_step, tsc_steps; |
125 | u32 stepenable; | 127 | u32 stepenable; |
126 | 128 | ||
127 | config = STEPCONFIG_MODE_HWSYNC | | 129 | config = STEPCONFIG_MODE_HWSYNC | |
@@ -140,9 +142,11 @@ static void titsc_step_config(struct titsc *ts_dev) | |||
140 | break; | 142 | break; |
141 | } | 143 | } |
142 | 144 | ||
143 | /* 1 … coordinate_readouts is for X */ | 145 | tsc_steps = ts_dev->coordinate_readouts * 2 + 2; |
144 | end_step = ts_dev->coordinate_readouts; | 146 | first_step = TOTAL_STEPS - tsc_steps; |
145 | for (i = 0; i < end_step; i++) { | 147 | /* Steps 16 to 16-coordinate_readouts is for X */ |
148 | end_step = first_step + tsc_steps; | ||
149 | for (i = end_step - ts_dev->coordinate_readouts; i < end_step; i++) { | ||
146 | titsc_writel(ts_dev, REG_STEPCONFIG(i), config); | 150 | titsc_writel(ts_dev, REG_STEPCONFIG(i), config); |
147 | titsc_writel(ts_dev, REG_STEPDELAY(i), STEPCONFIG_OPENDLY); | 151 | titsc_writel(ts_dev, REG_STEPDELAY(i), STEPCONFIG_OPENDLY); |
148 | } | 152 | } |
@@ -164,22 +168,20 @@ static void titsc_step_config(struct titsc *ts_dev) | |||
164 | break; | 168 | break; |
165 | } | 169 | } |
166 | 170 | ||
167 | /* coordinate_readouts … coordinate_readouts * 2 is for Y */ | 171 | /* 1 ... coordinate_readouts is for Y */ |
168 | end_step = ts_dev->coordinate_readouts * 2; | 172 | end_step = first_step + ts_dev->coordinate_readouts; |
169 | for (i = ts_dev->coordinate_readouts; i < end_step; i++) { | 173 | for (i = first_step; i < end_step; i++) { |
170 | titsc_writel(ts_dev, REG_STEPCONFIG(i), config); | 174 | titsc_writel(ts_dev, REG_STEPCONFIG(i), config); |
171 | titsc_writel(ts_dev, REG_STEPDELAY(i), STEPCONFIG_OPENDLY); | 175 | titsc_writel(ts_dev, REG_STEPDELAY(i), STEPCONFIG_OPENDLY); |
172 | } | 176 | } |
173 | 177 | ||
174 | /* Charge step configuration */ | 178 | /* Make CHARGECONFIG same as IDLECONFIG */ |
175 | config = ts_dev->bit_xp | ts_dev->bit_yn | | ||
176 | STEPCHARGE_RFP_XPUL | STEPCHARGE_RFM_XNUR | | ||
177 | STEPCHARGE_INM_AN1 | STEPCHARGE_INP(ts_dev->inp_yp); | ||
178 | 179 | ||
180 | config = titsc_readl(ts_dev, REG_IDLECONFIG); | ||
179 | titsc_writel(ts_dev, REG_CHARGECONFIG, config); | 181 | titsc_writel(ts_dev, REG_CHARGECONFIG, config); |
180 | titsc_writel(ts_dev, REG_CHARGEDELAY, CHARGEDLY_OPENDLY); | 182 | titsc_writel(ts_dev, REG_CHARGEDELAY, ts_dev->charge_delay); |
181 | 183 | ||
182 | /* coordinate_readouts * 2 … coordinate_readouts * 2 + 2 is for Z */ | 184 | /* coordinate_readouts + 1 ... coordinate_readouts + 2 is for Z */ |
183 | config = STEPCONFIG_MODE_HWSYNC | | 185 | config = STEPCONFIG_MODE_HWSYNC | |
184 | STEPCONFIG_AVG_16 | ts_dev->bit_yp | | 186 | STEPCONFIG_AVG_16 | ts_dev->bit_yp | |
185 | ts_dev->bit_xn | STEPCONFIG_INM_ADCREFM | | 187 | ts_dev->bit_xn | STEPCONFIG_INM_ADCREFM | |
@@ -194,73 +196,104 @@ static void titsc_step_config(struct titsc *ts_dev) | |||
194 | titsc_writel(ts_dev, REG_STEPDELAY(end_step), | 196 | titsc_writel(ts_dev, REG_STEPDELAY(end_step), |
195 | STEPCONFIG_OPENDLY); | 197 | STEPCONFIG_OPENDLY); |
196 | 198 | ||
197 | /* The steps1 … end and bit 0 for TS_Charge */ | 199 | /* The steps end ... end - readouts * 2 + 2 and bit 0 for TS_Charge */ |
198 | stepenable = (1 << (end_step + 2)) - 1; | 200 | stepenable = 1; |
201 | for (i = 0; i < tsc_steps; i++) | ||
202 | stepenable |= 1 << (first_step + i + 1); | ||
203 | |||
199 | ts_dev->step_mask = stepenable; | 204 | ts_dev->step_mask = stepenable; |
200 | am335x_tsc_se_set_cache(ts_dev->mfd_tscadc, ts_dev->step_mask); | 205 | am335x_tsc_se_set_cache(ts_dev->mfd_tscadc, ts_dev->step_mask); |
201 | } | 206 | } |
202 | 207 | ||
208 | static int titsc_cmp_coord(const void *a, const void *b) | ||
209 | { | ||
210 | return *(int *)a - *(int *)b; | ||
211 | } | ||
212 | |||
203 | static void titsc_read_coordinates(struct titsc *ts_dev, | 213 | static void titsc_read_coordinates(struct titsc *ts_dev, |
204 | u32 *x, u32 *y, u32 *z1, u32 *z2) | 214 | u32 *x, u32 *y, u32 *z1, u32 *z2) |
205 | { | 215 | { |
206 | unsigned int fifocount = titsc_readl(ts_dev, REG_FIFO0CNT); | 216 | unsigned int yvals[7], xvals[7]; |
207 | unsigned int prev_val_x = ~0, prev_val_y = ~0; | 217 | unsigned int i, xsum = 0, ysum = 0; |
208 | unsigned int prev_diff_x = ~0, prev_diff_y = ~0; | ||
209 | unsigned int read, diff; | ||
210 | unsigned int i, channel; | ||
211 | unsigned int creads = ts_dev->coordinate_readouts; | 218 | unsigned int creads = ts_dev->coordinate_readouts; |
212 | 219 | ||
213 | *z1 = *z2 = 0; | 220 | for (i = 0; i < creads; i++) { |
214 | if (fifocount % (creads * 2 + 2)) | 221 | yvals[i] = titsc_readl(ts_dev, REG_FIFO0); |
215 | fifocount -= fifocount % (creads * 2 + 2); | 222 | yvals[i] &= 0xfff; |
216 | /* | 223 | } |
217 | * Delta filter is used to remove large variations in sampled | ||
218 | * values from ADC. The filter tries to predict where the next | ||
219 | * coordinate could be. This is done by taking a previous | ||
220 | * coordinate and subtracting it form current one. Further the | ||
221 | * algorithm compares the difference with that of a present value, | ||
222 | * if true the value is reported to the sub system. | ||
223 | */ | ||
224 | for (i = 0; i < fifocount; i++) { | ||
225 | read = titsc_readl(ts_dev, REG_FIFO0); | ||
226 | |||
227 | channel = (read & 0xf0000) >> 16; | ||
228 | read &= 0xfff; | ||
229 | if (channel < creads) { | ||
230 | diff = abs(read - prev_val_x); | ||
231 | if (diff < prev_diff_x) { | ||
232 | prev_diff_x = diff; | ||
233 | *x = read; | ||
234 | } | ||
235 | prev_val_x = read; | ||
236 | 224 | ||
237 | } else if (channel < creads * 2) { | 225 | *z1 = titsc_readl(ts_dev, REG_FIFO0); |
238 | diff = abs(read - prev_val_y); | 226 | *z1 &= 0xfff; |
239 | if (diff < prev_diff_y) { | 227 | *z2 = titsc_readl(ts_dev, REG_FIFO0); |
240 | prev_diff_y = diff; | 228 | *z2 &= 0xfff; |
241 | *y = read; | ||
242 | } | ||
243 | prev_val_y = read; | ||
244 | 229 | ||
245 | } else if (channel < creads * 2 + 1) { | 230 | for (i = 0; i < creads; i++) { |
246 | *z1 = read; | 231 | xvals[i] = titsc_readl(ts_dev, REG_FIFO0); |
232 | xvals[i] &= 0xfff; | ||
233 | } | ||
247 | 234 | ||
248 | } else if (channel < creads * 2 + 2) { | 235 | /* |
249 | *z2 = read; | 236 | * If co-ordinates readouts is less than 4 then |
237 | * report the average. In case of 4 or more | ||
238 | * readouts, sort the co-ordinate samples, drop | ||
239 | * min and max values and report the average of | ||
240 | * remaining values. | ||
241 | */ | ||
242 | if (creads <= 3) { | ||
243 | for (i = 0; i < creads; i++) { | ||
244 | ysum += yvals[i]; | ||
245 | xsum += xvals[i]; | ||
250 | } | 246 | } |
247 | ysum /= creads; | ||
248 | xsum /= creads; | ||
249 | } else { | ||
250 | sort(yvals, creads, sizeof(unsigned int), | ||
251 | titsc_cmp_coord, NULL); | ||
252 | sort(xvals, creads, sizeof(unsigned int), | ||
253 | titsc_cmp_coord, NULL); | ||
254 | for (i = 1; i < creads - 1; i++) { | ||
255 | ysum += yvals[i]; | ||
256 | xsum += xvals[i]; | ||
257 | } | ||
258 | ysum /= creads - 2; | ||
259 | xsum /= creads - 2; | ||
251 | } | 260 | } |
261 | *y = ysum; | ||
262 | *x = xsum; | ||
252 | } | 263 | } |
253 | 264 | ||
254 | static irqreturn_t titsc_irq(int irq, void *dev) | 265 | static irqreturn_t titsc_irq(int irq, void *dev) |
255 | { | 266 | { |
256 | struct titsc *ts_dev = dev; | 267 | struct titsc *ts_dev = dev; |
257 | struct input_dev *input_dev = ts_dev->input; | 268 | struct input_dev *input_dev = ts_dev->input; |
258 | unsigned int status, irqclr = 0; | 269 | unsigned int fsm, status, irqclr = 0; |
259 | unsigned int x = 0, y = 0; | 270 | unsigned int x = 0, y = 0; |
260 | unsigned int z1, z2, z; | 271 | unsigned int z1, z2, z; |
261 | unsigned int fsm; | ||
262 | 272 | ||
263 | status = titsc_readl(ts_dev, REG_IRQSTATUS); | 273 | status = titsc_readl(ts_dev, REG_RAWIRQSTATUS); |
274 | if (status & IRQENB_HW_PEN) { | ||
275 | ts_dev->pen_down = true; | ||
276 | titsc_writel(ts_dev, REG_IRQWAKEUP, 0x00); | ||
277 | titsc_writel(ts_dev, REG_IRQCLR, IRQENB_HW_PEN); | ||
278 | irqclr |= IRQENB_HW_PEN; | ||
279 | } | ||
280 | |||
281 | if (status & IRQENB_PENUP) { | ||
282 | fsm = titsc_readl(ts_dev, REG_ADCFSM); | ||
283 | if (fsm == ADCFSM_STEPID) { | ||
284 | ts_dev->pen_down = false; | ||
285 | input_report_key(input_dev, BTN_TOUCH, 0); | ||
286 | input_report_abs(input_dev, ABS_PRESSURE, 0); | ||
287 | input_sync(input_dev); | ||
288 | } else { | ||
289 | ts_dev->pen_down = true; | ||
290 | } | ||
291 | irqclr |= IRQENB_PENUP; | ||
292 | } | ||
293 | |||
294 | if (status & IRQENB_EOS) | ||
295 | irqclr |= IRQENB_EOS; | ||
296 | |||
264 | /* | 297 | /* |
265 | * ADC and touchscreen share the IRQ line. | 298 | * ADC and touchscreen share the IRQ line. |
266 | * FIFO1 interrupts are used by ADC. Handle FIFO0 IRQs here only | 299 | * FIFO1 interrupts are used by ADC. Handle FIFO0 IRQs here only |
@@ -291,37 +324,11 @@ static irqreturn_t titsc_irq(int irq, void *dev) | |||
291 | } | 324 | } |
292 | irqclr |= IRQENB_FIFO0THRES; | 325 | irqclr |= IRQENB_FIFO0THRES; |
293 | } | 326 | } |
294 | |||
295 | /* | ||
296 | * Time for sequencer to settle, to read | ||
297 | * correct state of the sequencer. | ||
298 | */ | ||
299 | udelay(SEQ_SETTLE); | ||
300 | |||
301 | status = titsc_readl(ts_dev, REG_RAWIRQSTATUS); | ||
302 | if (status & IRQENB_PENUP) { | ||
303 | /* Pen up event */ | ||
304 | fsm = titsc_readl(ts_dev, REG_ADCFSM); | ||
305 | if (fsm == ADCFSM_STEPID) { | ||
306 | ts_dev->pen_down = false; | ||
307 | input_report_key(input_dev, BTN_TOUCH, 0); | ||
308 | input_report_abs(input_dev, ABS_PRESSURE, 0); | ||
309 | input_sync(input_dev); | ||
310 | } else { | ||
311 | ts_dev->pen_down = true; | ||
312 | } | ||
313 | irqclr |= IRQENB_PENUP; | ||
314 | } | ||
315 | |||
316 | if (status & IRQENB_HW_PEN) { | ||
317 | |||
318 | titsc_writel(ts_dev, REG_IRQWAKEUP, 0x00); | ||
319 | titsc_writel(ts_dev, REG_IRQCLR, IRQENB_HW_PEN); | ||
320 | } | ||
321 | |||
322 | if (irqclr) { | 327 | if (irqclr) { |
323 | titsc_writel(ts_dev, REG_IRQSTATUS, irqclr); | 328 | titsc_writel(ts_dev, REG_IRQSTATUS, irqclr); |
324 | am335x_tsc_se_set_cache(ts_dev->mfd_tscadc, ts_dev->step_mask); | 329 | if (status & IRQENB_EOS) |
330 | am335x_tsc_se_set_cache(ts_dev->mfd_tscadc, | ||
331 | ts_dev->step_mask); | ||
325 | return IRQ_HANDLED; | 332 | return IRQ_HANDLED; |
326 | } | 333 | } |
327 | return IRQ_NONE; | 334 | return IRQ_NONE; |
@@ -368,6 +375,23 @@ static int titsc_parse_dt(struct platform_device *pdev, | |||
368 | if (err < 0) | 375 | if (err < 0) |
369 | return err; | 376 | return err; |
370 | 377 | ||
378 | if (ts_dev->coordinate_readouts <= 0) { | ||
379 | dev_warn(&pdev->dev, | ||
380 | "invalid co-ordinate readouts, resetting it to 5\n"); | ||
381 | ts_dev->coordinate_readouts = 5; | ||
382 | } | ||
383 | |||
384 | err = of_property_read_u32(node, "ti,charge-delay", | ||
385 | &ts_dev->charge_delay); | ||
386 | /* | ||
387 | * If ti,charge-delay value is not specified, then use | ||
388 | * CHARGEDLY_OPENDLY as the default value. | ||
389 | */ | ||
390 | if (err < 0) { | ||
391 | ts_dev->charge_delay = CHARGEDLY_OPENDLY; | ||
392 | dev_warn(&pdev->dev, "ti,charge-delay not specified\n"); | ||
393 | } | ||
394 | |||
371 | return of_property_read_u32_array(node, "ti,wire-config", | 395 | return of_property_read_u32_array(node, "ti,wire-config", |
372 | ts_dev->config_inp, ARRAY_SIZE(ts_dev->config_inp)); | 396 | ts_dev->config_inp, ARRAY_SIZE(ts_dev->config_inp)); |
373 | } | 397 | } |
@@ -411,6 +435,7 @@ static int titsc_probe(struct platform_device *pdev) | |||
411 | } | 435 | } |
412 | 436 | ||
413 | titsc_writel(ts_dev, REG_IRQENABLE, IRQENB_FIFO0THRES); | 437 | titsc_writel(ts_dev, REG_IRQENABLE, IRQENB_FIFO0THRES); |
438 | titsc_writel(ts_dev, REG_IRQENABLE, IRQENB_EOS); | ||
414 | err = titsc_config_wires(ts_dev); | 439 | err = titsc_config_wires(ts_dev); |
415 | if (err) { | 440 | if (err) { |
416 | dev_err(&pdev->dev, "wrong i/p wire configuration\n"); | 441 | dev_err(&pdev->dev, "wrong i/p wire configuration\n"); |
diff --git a/include/linux/input/mt.h b/include/linux/input/mt.h index f583ff639776..d7188de4db96 100644 --- a/include/linux/input/mt.h +++ b/include/linux/input/mt.h | |||
@@ -119,7 +119,8 @@ struct input_mt_pos { | |||
119 | }; | 119 | }; |
120 | 120 | ||
121 | int input_mt_assign_slots(struct input_dev *dev, int *slots, | 121 | int input_mt_assign_slots(struct input_dev *dev, int *slots, |
122 | const struct input_mt_pos *pos, int num_pos); | 122 | const struct input_mt_pos *pos, int num_pos, |
123 | int dmax); | ||
123 | 124 | ||
124 | int input_mt_get_slot_by_key(struct input_dev *dev, int key); | 125 | int input_mt_get_slot_by_key(struct input_dev *dev, int key); |
125 | 126 | ||
diff --git a/include/linux/mfd/ti_am335x_tscadc.h b/include/linux/mfd/ti_am335x_tscadc.h index e2e70053470e..3f4e994ace2b 100644 --- a/include/linux/mfd/ti_am335x_tscadc.h +++ b/include/linux/mfd/ti_am335x_tscadc.h | |||
@@ -52,6 +52,7 @@ | |||
52 | 52 | ||
53 | /* IRQ enable */ | 53 | /* IRQ enable */ |
54 | #define IRQENB_HW_PEN BIT(0) | 54 | #define IRQENB_HW_PEN BIT(0) |
55 | #define IRQENB_EOS BIT(1) | ||
55 | #define IRQENB_FIFO0THRES BIT(2) | 56 | #define IRQENB_FIFO0THRES BIT(2) |
56 | #define IRQENB_FIFO0OVRRUN BIT(3) | 57 | #define IRQENB_FIFO0OVRRUN BIT(3) |
57 | #define IRQENB_FIFO0UNDRFLW BIT(4) | 58 | #define IRQENB_FIFO0UNDRFLW BIT(4) |
@@ -107,7 +108,7 @@ | |||
107 | /* Charge delay */ | 108 | /* Charge delay */ |
108 | #define CHARGEDLY_OPEN_MASK (0x3FFFF << 0) | 109 | #define CHARGEDLY_OPEN_MASK (0x3FFFF << 0) |
109 | #define CHARGEDLY_OPEN(val) ((val) << 0) | 110 | #define CHARGEDLY_OPEN(val) ((val) << 0) |
110 | #define CHARGEDLY_OPENDLY CHARGEDLY_OPEN(1) | 111 | #define CHARGEDLY_OPENDLY CHARGEDLY_OPEN(0x400) |
111 | 112 | ||
112 | /* Control register */ | 113 | /* Control register */ |
113 | #define CNTRLREG_TSCSSENB BIT(0) | 114 | #define CNTRLREG_TSCSSENB BIT(0) |
diff --git a/include/linux/platform_data/regulator-haptic.h b/include/linux/platform_data/regulator-haptic.h new file mode 100644 index 000000000000..5658e58e0738 --- /dev/null +++ b/include/linux/platform_data/regulator-haptic.h | |||
@@ -0,0 +1,29 @@ | |||
1 | /* | ||
2 | * Regulator Haptic Platform Data | ||
3 | * | ||
4 | * Copyright (c) 2014 Samsung Electronics Co., Ltd. | ||
5 | * Author: Jaewon Kim <jaewon02.kim@samsung.com> | ||
6 | * Author: Hyunhee Kim <hyunhee.kim@samsung.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License version 2 as | ||
10 | * published by the Free Software Foundation. | ||
11 | */ | ||
12 | |||
13 | #ifndef _REGULATOR_HAPTIC_H | ||
14 | #define _REGULATOR_HAPTIC_H | ||
15 | |||
16 | /* | ||
17 | * struct regulator_haptic_data - Platform device data | ||
18 | * | ||
19 | * @max_volt: maximum voltage value supplied to the haptic motor. | ||
20 | * <The unit of the voltage is a micro> | ||
21 | * @min_volt: minimum voltage value supplied to the haptic motor. | ||
22 | * <The unit of the voltage is a micro> | ||
23 | */ | ||
24 | struct regulator_haptic_data { | ||
25 | unsigned int max_volt; | ||
26 | unsigned int min_volt; | ||
27 | }; | ||
28 | |||
29 | #endif /* _REGULATOR_HAPTIC_H */ | ||